Merge pull request #641 from KLayout/usability-enhancements

Usability enhancements
This commit is contained in:
Matthias Köfferlein 2020-11-14 20:54:30 +01:00 committed by GitHub
commit 7d677d8866
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
129 changed files with 12876 additions and 6238 deletions

View File

@ -50,6 +50,38 @@ PropertiesPage::PropertiesPage (ant::Service *rulers, db::Manager *manager, QWid
p2_to_layout->setEnabled (! readonly());
both_to_layout->setEnabled (! readonly());
if (! readonly ()) {
connect (fmt_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (fmt_x_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (fmt_y_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (x1, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (x2, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (y1, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (y2, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (style_cb, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (outline_cb, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (main_position, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (main_xalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (main_yalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (xlabel_xalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (xlabel_yalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (ylabel_xalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (ylabel_yalign, SIGNAL (activated (int)), this, SIGNAL (edited ()));
} else {
fmt_le->setReadOnly (true);
fmt_x_le->setReadOnly (true);
fmt_y_le->setReadOnly (true);
x1->setReadOnly (true);
x2->setReadOnly (true);
y1->setReadOnly (true);
y2->setReadOnly (true);
}
lay::activate_help_links (help_label);
mp_rulers->clear_highlights ();
@ -91,7 +123,53 @@ PropertiesPage::swap_points_clicked ()
y2->setText (ty2);
db::Transaction t (manager (), tl::to_string (QObject::tr ("Swap ruler points")));
apply ();
emit edited ();
}
void
PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2)
{
double dx1 = 0.0, dy1 = 0.0, dx2 = 0.0, dy2 = 0.0;
bool has_error = false;
try {
tl::from_string (tl::to_string (x1->text ()), dx1);
lay::indicate_error (x1, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x1, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (x2->text ()), dx2);
lay::indicate_error (x2, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x2, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (y1->text ()), dy1);
lay::indicate_error (y1, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y1, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (y2->text ()), dy2);
lay::indicate_error (y2, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y2, &ex);
has_error = true;
}
if (has_error) {
throw tl::Exception (tl::to_string (tr ("At least one value is invalid - see highlighted entry fields")));
}
p1 = db::DPoint (dx1, dy1);
p2 = db::DPoint (dx2, dy2);
}
void
@ -104,13 +182,8 @@ PropertiesPage::snap_to_layout_clicked ()
ant::Service *service = dynamic_cast<ant::Service *> (editable ());
tl_assert (service != 0);
double dx1 = 0.0, dy1 = 0.0, dx2 = 0.0, dy2 = 0.0;
tl::from_string (tl::to_string (x1->text ()), dx1);
tl::from_string (tl::to_string (x2->text ()), dx2);
tl::from_string (tl::to_string (y1->text ()), dy1);
tl::from_string (tl::to_string (y2->text ()), dy2);
db::DPoint p1 (dx1, dy1), p2 (dx2, dy2);
db::DPoint p1, p2;
get_points (p1, p2);
ant::Object r = current ();
@ -137,11 +210,11 @@ PropertiesPage::snap_to_layout_clicked ()
while (snap_range < max_range) {
std::pair<bool, db::DPoint> pp = lay::obj_snap (service->view (), snap_p1 ? p2 : p1, snap_p1 ? p1 : p2, g, ac, snap_range);
if (pp.first) {
lay::PointSnapToObjectResult pp = lay::obj_snap (service->view (), snap_p1 ? p2 : p1, snap_p1 ? p1 : p2, g, ac, snap_range);
if (pp.object_snap != lay::PointSnapToObjectResult::NoObject) {
QString xs = tl::to_qstring (tl::micron_to_string (pp.second.x ()));
QString ys = tl::to_qstring (tl::micron_to_string (pp.second.y ()));
QString xs = tl::to_qstring (tl::micron_to_string (pp.snapped_point.x ()));
QString ys = tl::to_qstring (tl::micron_to_string (pp.snapped_point.y ()));
if (sender () == p1_to_layout) {
x1->setText (xs);
@ -152,7 +225,7 @@ PropertiesPage::snap_to_layout_clicked ()
}
db::Transaction t (manager (), tl::to_string (snap_p1 ? QObject::tr ("Snap first ruler point") : QObject::tr ("Snap second ruler point")));
apply ();
emit edited ();
break;
@ -168,16 +241,16 @@ PropertiesPage::snap_to_layout_clicked ()
double snap_range = service->widget ()->mouse_event_trans ().inverted ().ctrans (service->snap_range ());
snap_range *= 0.5;
std::pair<bool, db::DEdge> ee = lay::obj_snap2 (service->view (), p1, p2, g, ac, snap_range, snap_range * 1000.0);
if (ee.first) {
lay::TwoPointSnapToObjectResult ee = lay::obj_snap2 (service->view (), p1, p2, g, ac, snap_range, snap_range * 1000.0);
if (ee.any) {
x1->setText (tl::to_qstring (tl::micron_to_string (ee.second.p1 ().x ())));
y1->setText (tl::to_qstring (tl::micron_to_string (ee.second.p1 ().y ())));
x2->setText (tl::to_qstring (tl::micron_to_string (ee.second.p2 ().x ())));
y2->setText (tl::to_qstring (tl::micron_to_string (ee.second.p2 ().y ())));
x1->setText (tl::to_qstring (tl::micron_to_string (ee.first.x ())));
y1->setText (tl::to_qstring (tl::micron_to_string (ee.first.y ())));
x2->setText (tl::to_qstring (tl::micron_to_string (ee.second.x ())));
y2->setText (tl::to_qstring (tl::micron_to_string (ee.second.y ())));
db::Transaction t (manager (), tl::to_string (QObject::tr ("Snap both ruler points")));
apply ();
emit edited ();
}
@ -268,22 +341,9 @@ PropertiesPage::readonly ()
void
PropertiesPage::apply ()
{
double dx1 = current ().p1 ().x (), dy1 = current ().p1 ().y ();
double dx2 = current ().p2 ().x (), dy2 = current ().p2 ().y ();
// only adjust the values if the text has changed
if (tl::to_qstring (tl::micron_to_string (dx1)) != x1->text ()) {
tl::from_string (tl::to_string (x1->text ()), dx1);
}
if (tl::to_qstring (tl::micron_to_string (dx2)) != x2->text ()) {
tl::from_string (tl::to_string (x2->text ()), dx2);
}
if (tl::to_qstring (tl::micron_to_string (dy1)) != y1->text ()) {
tl::from_string (tl::to_string (y1->text ()), dy1);
}
if (tl::to_qstring (tl::micron_to_string (dy2)) != y2->text ()) {
tl::from_string (tl::to_string (y2->text ()), dy2);
}
db::DPoint p1, p2;
get_points (p1, p2);
std::string fmt = tl::to_string (fmt_le->text ());
std::string fmt_x = tl::to_string (fmt_x_le->text ());
@ -291,7 +351,7 @@ PropertiesPage::apply ()
Object::style_type style = Object::style_type (style_cb->currentIndex ());
Object::outline_type outline = Object::outline_type (outline_cb->currentIndex ());
ant::Object ruler (db::DPoint (dx1, dy1), db::DPoint (dx2, dy2), current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ());
ant::Object ruler (p1, p2, current ().id (), fmt_x, fmt_y, fmt, style, outline, current ().snap (), current ().angle_constraint ());
ruler.set_main_position (Object::position_type (main_position->currentIndex ()));
ruler.set_main_xalign (Object::alignment_type (main_xalign->currentIndex ()));

View File

@ -64,6 +64,7 @@ private:
bool m_enable_cb_callback;
const ant::Object &current () const;
void get_points(db::DPoint &p1, db::DPoint &p2);
};
}

View File

@ -706,9 +706,7 @@ View::render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas)
// ant::Service implementation
Service::Service (db::Manager *manager, lay::LayoutView *view)
: lay::ViewService (view->view_object_widget ()),
lay::Editable (view),
lay::Plugin (view),
: lay::EditorServiceBase (view),
lay::Drawing (1/*number of planes*/, view->drawings ()),
db::Object (manager),
m_halo (true),
@ -801,7 +799,7 @@ Service::configure (const std::string &name, const std::string &value)
m_current_template = n;
} else {
taken = false;
lay::EditorServiceBase::configure (name, value);
}
return taken;
@ -1434,14 +1432,14 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
double snap_range = widget ()->mouse_event_trans ().inverted ().ctrans (m_snap_range);
snap_range *= 0.5;
std::pair<bool, db::DEdge> ee = lay::obj_snap2 (mp_view, p, g, ac, snap_range, snap_range * 1000.0);
if (ee.first) {
lay::TwoPointSnapToObjectResult ee = lay::obj_snap2 (mp_view, p, g, ac, snap_range, snap_range * 1000.0);
if (ee.any) {
// begin the transaction
tl_assert (! manager ()->transacting ());
manager ()->transaction (tl::to_string (QObject::tr ("Create ruler")));
m_current = ant::Object (ee.second.p1 (), ee.second.p2 (), 0, tpl);
m_current = ant::Object (ee.first, ee.second, 0, tpl);
show_message ();
insert_ruler (m_current, true);
@ -1505,17 +1503,31 @@ Service::create_measure_ruler (const db::DPoint &pt, lay::angle_constraint_type
ant::Template tpl;
std::pair<bool, db::DEdge> ee = lay::obj_snap2 (mp_view, pt, db::DVector (), ac, snap_range, snap_range * 1000.0);
if (ee.first) {
return ant::Object (ee.second.p1 (), ee.second.p2 (), 0, tpl);
lay::TwoPointSnapToObjectResult ee = lay::obj_snap2 (mp_view, pt, db::DVector (), ac, snap_range, snap_range * 1000.0);
if (ee.any) {
return ant::Object (ee.first, ee.second, 0, tpl);
} else {
return ant::Object (pt, pt, 0, tpl);
}
}
bool
bool
Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
if (prio) {
lay::PointSnapToObjectResult snap_details;
if (m_drawing) {
snap_details = snap2_details (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons));
} else {
const ant::Template &tpl = current_template ();
snap_details = snap1_details (p, m_obj_snap && tpl.snap ());
}
mouse_cursor_from_snap_details (snap_details);
}
if (m_drawing && prio) {
set_cursor (lay::Cursor::cross);
@ -1532,12 +1544,14 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
void
Service::deactivated ()
{
lay::EditorServiceBase::deactivated ();
drag_cancel ();
clear_transient_selection ();
}
std::pair<bool, db::DPoint>
Service::snap1 (const db::DPoint &p, bool obj_snap)
lay::PointSnapToObjectResult
Service::snap1_details (const db::DPoint &p, bool obj_snap)
{
db::DVector g;
if (m_grid_snap) {
@ -1548,9 +1562,16 @@ Service::snap1 (const db::DPoint &p, bool obj_snap)
return lay::obj_snap (obj_snap ? mp_view : 0, p, g, snap_range);
}
std::pair<bool, db::DPoint>
Service::snap1 (const db::DPoint &p, bool obj_snap)
{
lay::PointSnapToObjectResult res = snap1_details (p, obj_snap);
return std::make_pair (res.object_snap != lay::PointSnapToObjectResult::NoObject, res.snapped_point);
}
std::pair <bool, db::DPoint>
Service::snap2 (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac)
lay::PointSnapToObjectResult
Service::snap2_details (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac)
{
db::DVector g;
if (m_grid_snap) {
@ -1563,6 +1584,13 @@ Service::snap2 (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *o
return lay::obj_snap (m_obj_snap && obj->snap () ? mp_view : 0, p1, p2, g, snap_mode, snap_range);
}
std::pair <bool, db::DPoint>
Service::snap2 (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac)
{
lay::PointSnapToObjectResult res = snap2_details (p1, p2, obj, ac);
return std::make_pair (res.object_snap != lay::PointSnapToObjectResult::NoObject, res.snapped_point);
}
struct RulerIdComp
{

View File

@ -27,9 +27,7 @@
#include "antCommon.h"
#include "layViewObject.h"
#include "layEditable.h"
#include "layPlugin.h"
#include "layEditorServiceBase.h"
#include "layDrawing.h"
#include "laySnap.h"
#include "layAnnotationShapes.h"
@ -180,9 +178,7 @@ private:
// -------------------------------------------------------------
class ANT_PUBLIC Service
: public lay::ViewService,
public lay::Editable,
public lay::Plugin,
: public lay::EditorServiceBase,
public lay::Drawing,
public db::Object
{
@ -529,8 +525,10 @@ private:
unsigned int m_current_template;
std::pair<bool, db::DPoint> snap1 (const db::DPoint &p, bool obj_snap);
lay::PointSnapToObjectResult snap1_details (const db::DPoint &p, bool obj_snap);
std::pair<bool, db::DPoint> snap2 (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);
const ant::Template &current_template () const;
void show_message ();

View File

@ -1,7 +1,8 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AlignOptionsDialog</class>
<widget class="QDialog" name="AlignOptionsDialog" >
<property name="geometry" >
<widget class="QDialog" name="AlignOptionsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
@ -9,26 +10,26 @@
<height>392</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Alignment Options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Horizontal alignment</string>
</property>
<layout class="QGridLayout" name="gridLayout_3" >
<item row="0" column="0" >
<widget class="QRadioButton" name="h_none_rb" >
<property name="text" >
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QRadioButton" name="h_none_rb">
<property name="text">
<string/>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_none.png</normaloff>:/align_none.png</iconset>
</property>
<property name="iconSize" >
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
@ -36,16 +37,16 @@
</property>
</widget>
</item>
<item row="0" column="2" >
<widget class="QRadioButton" name="h_left_rb" >
<property name="text" >
<item row="0" column="2">
<widget class="QRadioButton" name="h_left_rb">
<property name="text">
<string/>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_left.png</normaloff>:/align_left.png</iconset>
</property>
<property name="iconSize" >
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
@ -53,16 +54,16 @@
</property>
</widget>
</item>
<item row="0" column="4" >
<widget class="QRadioButton" name="h_center_rb" >
<property name="text" >
<item row="0" column="4">
<widget class="QRadioButton" name="h_center_rb">
<property name="text">
<string/>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_hcenter.png</normaloff>:/align_hcenter.png</iconset>
</property>
<property name="iconSize" >
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
@ -70,16 +71,16 @@
</property>
</widget>
</item>
<item row="0" column="6" >
<widget class="QRadioButton" name="h_right_rb" >
<property name="text" >
<item row="0" column="6">
<widget class="QRadioButton" name="h_right_rb">
<property name="text">
<string/>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_right.png</normaloff>:/align_right.png</iconset>
</property>
<property name="iconSize" >
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
@ -87,12 +88,12 @@
</property>
</widget>
</item>
<item row="0" column="7" >
<spacer name="horizontalSpacer_3" >
<property name="orientation" >
<item row="0" column="7">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>243</width>
<height>20</height>
@ -100,55 +101,55 @@
</property>
</spacer>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>none</string>
</property>
<property name="alignment" >
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<item row="1" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>left</string>
</property>
<property name="alignment" >
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="4" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<item row="1" column="4">
<widget class="QLabel" name="label_7">
<property name="text">
<string>center</string>
</property>
<property name="alignment" >
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="6" >
<widget class="QLabel" name="label_8" >
<property name="text" >
<item row="1" column="6">
<widget class="QLabel" name="label_8">
<property name="text">
<string>right</string>
</property>
<property name="alignment" >
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1" >
<spacer name="horizontalSpacer" >
<property name="orientation" >
<item row="0" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
@ -156,15 +157,15 @@
</property>
</spacer>
</item>
<item row="0" column="3" >
<spacer name="horizontalSpacer_4" >
<property name="orientation" >
<item row="0" column="3">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
@ -172,15 +173,15 @@
</property>
</spacer>
</item>
<item row="0" column="5" >
<spacer name="horizontalSpacer_5" >
<property name="orientation" >
<item row="0" column="5">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
@ -192,21 +193,21 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Vertical alignment</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" >
<item row="0" column="0" >
<widget class="QRadioButton" name="v_none_rb" >
<property name="text" >
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QRadioButton" name="v_none_rb">
<property name="text">
<string/>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_none.png</normaloff>:/align_none.png</iconset>
</property>
<property name="iconSize" >
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
@ -214,16 +215,16 @@
</property>
</widget>
</item>
<item row="0" column="2" >
<widget class="QRadioButton" name="v_top_rb" >
<property name="text" >
<item row="0" column="2">
<widget class="QRadioButton" name="v_top_rb">
<property name="text">
<string/>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_top.png</normaloff>:/align_top.png</iconset>
</property>
<property name="iconSize" >
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
@ -231,16 +232,16 @@
</property>
</widget>
</item>
<item row="0" column="4" >
<widget class="QRadioButton" name="v_center_rb" >
<property name="text" >
<item row="0" column="4">
<widget class="QRadioButton" name="v_center_rb">
<property name="text">
<string/>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_vcenter.png</normaloff>:/align_vcenter.png</iconset>
</property>
<property name="iconSize" >
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
@ -248,12 +249,12 @@
</property>
</widget>
</item>
<item row="0" column="7" >
<spacer name="horizontalSpacer_2" >
<property name="orientation" >
<item row="0" column="7">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>243</width>
<height>34</height>
@ -261,56 +262,56 @@
</property>
</spacer>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>none</string>
</property>
<property name="alignment" >
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<item row="1" column="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>top</string>
</property>
<property name="alignment" >
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="4" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<item row="1" column="4">
<widget class="QLabel" name="label_3">
<property name="text">
<string>center</string>
</property>
<property name="alignment" >
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="6" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<item row="1" column="6">
<widget class="QLabel" name="label_4">
<property name="text">
<string>bottom</string>
</property>
<property name="alignment" >
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="6" >
<widget class="QRadioButton" name="v_bottom_rb" >
<property name="text" >
<item row="0" column="6">
<widget class="QRadioButton" name="v_bottom_rb">
<property name="text">
<string/>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_bottom.png</normaloff>:/align_bottom.png</iconset>
</property>
<property name="iconSize" >
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
@ -318,15 +319,15 @@
</property>
</widget>
</item>
<item row="0" column="1" >
<spacer name="horizontalSpacer_6" >
<property name="orientation" >
<item row="0" column="1">
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
@ -334,15 +335,15 @@
</property>
</spacer>
</item>
<item row="0" column="3" >
<spacer name="horizontalSpacer_7" >
<property name="orientation" >
<item row="0" column="3">
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
@ -350,15 +351,15 @@
</property>
</spacer>
</item>
<item row="0" column="5" >
<spacer name="horizontalSpacer_8" >
<property name="orientation" >
<item row="0" column="5">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
@ -370,21 +371,21 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3" >
<property name="title" >
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Layers for alignment of instances</string>
</property>
<layout class="QGridLayout" name="gridLayout" >
<item row="1" column="0" >
<widget class="QRadioButton" name="visible_layers_rb" >
<property name="text" >
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QRadioButton" name="visible_layers_rb">
<property name="text">
<string>Use visible layers only</string>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QRadioButton" name="all_layers_rb" >
<property name="text" >
<item row="0" column="0">
<widget class="QRadioButton" name="all_layers_rb">
<property name="text">
<string>Use all layers</string>
</property>
</widget>
@ -393,11 +394,11 @@
</widget>
</item>
<item>
<spacer name="verticalSpacer" >
<property name="orientation" >
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>488</width>
<height>16</height>
@ -406,11 +407,11 @@
</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" >
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
@ -431,7 +432,7 @@
<tabstop>buttonBox</tabstop>
</tabstops>
<resources>
<include location="layResources.qrc" />
<include location="../../lay/lay/layResources.qrc"/>
</resources>
<connections>
<connection>
@ -440,11 +441,11 @@
<receiver>AlignOptionsDialog</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>
@ -456,11 +457,11 @@
<receiver>AlignOptionsDialog</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

@ -0,0 +1,715 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DistributeOptionsDialog</class>
<widget class="QDialog" name="DistributeOptionsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>689</width>
<height>574</height>
</rect>
</property>
<property name="windowTitle">
<string>Distribution Options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="h_distribute">
<property name="title">
<string>Horizontal distribution</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_9">
<property name="text">
<string>The pitch specifies the offset at which the objects are placed relative to each other. The space is the minimum distance between the objects.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Pitch</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="h_pitch">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_12">
<property name="text">
<string>µm</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Space</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="h_space">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="text">
<string>µm</string>
</property>
</widget>
</item>
<item>
<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>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="v_distribute">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="title">
<string>Vertical distribution</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_18">
<property name="text">
<string>Pitch</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="v_pitch">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_19">
<property name="text">
<string>µm</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_12">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_20">
<property name="text">
<string>Space</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="v_space">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_21">
<property name="text">
<string>µm</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_13">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>The pitch specifies the offset at which the objects are placed relative to each other. The space is the minimum distance between the objects.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Horizonal alignment</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QRadioButton" name="h_none_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_none.png</normaloff>:/align_none.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer_14">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QRadioButton" name="h_left_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_left.png</normaloff>:/align_left.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="4">
<widget class="QRadioButton" name="h_center_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_hcenter.png</normaloff>:/align_hcenter.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="5">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="6">
<widget class="QRadioButton" name="h_right_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_right.png</normaloff>:/align_right.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="7">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>245</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>none</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>left</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_7">
<property name="text">
<string>center</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="label_8">
<property name="text">
<string>right</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Vertical alignment</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QRadioButton" name="v_none_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_none.png</normaloff>:/align_none.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer_15">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QRadioButton" name="v_top_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_top.png</normaloff>:/align_top.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="4">
<widget class="QRadioButton" name="v_center_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_vcenter.png</normaloff>:/align_vcenter.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="5">
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="6">
<widget class="QRadioButton" name="v_bottom_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_bottom.png</normaloff>:/align_bottom.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="7">
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>245</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>none</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_14">
<property name="text">
<string>top</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_15">
<property name="text">
<string>center</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="label_17">
<property name="text">
<string>bottom</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>For the computation of cell instance bounding boxes ...</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QRadioButton" name="visible_layers_rb">
<property name="text">
<string>Use visible layers only</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="all_layers_rb">
<property name="text">
<string>Use all layers</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>488</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>all_layers_rb</tabstop>
<tabstop>visible_layers_rb</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources>
<include location="../../lay/lay/layResources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DistributeOptionsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DistributeOptionsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,139 +0,0 @@
<ui version="4.0" >
<class>EditorOptionsDialog</class>
<widget class="QDialog" name="EditorOptionsDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>642</width>
<height>572</height>
</rect>
</property>
<property name="windowTitle" >
<string>Object Editor Options</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QTabWidget" name="pages" >
<property name="currentIndex" >
<number>0</number>
</property>
<widget class="QWidget" name="tab_2" >
<attribute name="title" >
<string>Tab 2</string>
</attribute>
</widget>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>8</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QFrame" name="frame" >
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="ok_pb" >
<property name="text" >
<string>Ok</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="apply_pb" >
<property name="text" >
<string>Apply</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancel_pb" >
<property name="text" >
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>cancel_pb</sender>
<signal>clicked()</signal>
<receiver>EditorOptionsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>506</x>
<y>388</y>
</hint>
<hint type="destinationlabel" >
<x>276</x>
<y>205</y>
</hint>
</hints>
</connection>
<connection>
<sender>ok_pb</sender>
<signal>clicked()</signal>
<receiver>EditorOptionsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>344</x>
<y>388</y>
</hint>
<hint type="destinationlabel" >
<x>276</x>
<y>205</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -6,10 +6,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>417</height>
<width>400</width>
<height>446</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
@ -18,387 +24,449 @@
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
<number>0</number>
</property>
<property name="topMargin">
<number>9</number>
<number>0</number>
</property>
<property name="rightMargin">
<number>9</number>
<number>0</number>
</property>
<property name="bottomMargin">
<number>9</number>
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Snapping</string>
<widget class="QScrollArea" name="scrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<layout class="QGridLayout">
<property name="leftMargin">
<number>9</number>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>446</height>
</rect>
</property>
<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">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>148</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>16</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<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 (&quot;gx,gy&quot;)</string>
</property>
</widget>
</item>
<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">
<string>Objects </string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="grid_cb">
<item>
<property name="text">
<string>No grid</string>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Snapping</string>
</property>
</item>
<item>
<property name="text">
<string>Global grid</string>
<layout class="QGridLayout" name="_5">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Grid</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="grid_cb">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>No grid</string>
</property>
</item>
<item>
<property name="text">
<string>Global grid</string>
</property>
</item>
<item>
<property name="text">
<string>Other grid ...</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QCheckBox" name="snap_objects_cbx">
<property name="text">
<string>Snap to other objects</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Objects </string>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>148</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<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 (&quot;gx,gy&quot;)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Angle Constraints</string>
</property>
</item>
<item>
<property name="text">
<string>Other grid ...</string>
<layout class="QGridLayout" name="_2">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Movements </string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="move_angle_cb">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>Any Direction</string>
</property>
</item>
<item>
<property name="text">
<string>Diagonal</string>
</property>
</item>
<item>
<property name="text">
<string>Manhattan</string>
</property>
</item>
</widget>
</item>
<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">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>Any Angle</string>
</property>
</item>
<item>
<property name="text">
<string>Diagonal</string>
</property>
</item>
<item>
<property name="text">
<string>Manhattan</string>
</property>
</item>
</widget>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Hierarchical Features</string>
</property>
</item>
</widget>
</item>
<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>
</item>
</layout>
<layout class="QGridLayout" name="_3">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<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="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</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="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>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Instance Display</string>
</property>
<layout class="QHBoxLayout" name="_4">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<item>
<widget class="QCheckBox" name="show_shapes_cbx">
<property name="text">
<string>Show shapes while moving (max.</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="max_shapes_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="text">
<string> shapes)</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="spacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>121</width>
<height>70</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Angle Constraints</string>
</property>
<layout class="QGridLayout">
<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>
<property name="spacing">
<number>6</number>
</property>
<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">
<string>Connections </string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="conn_angle_cb">
<item>
<property name="text">
<string>Any Angle</string>
</property>
</item>
<item>
<property name="text">
<string>Diagonal</string>
</property>
</item>
<item>
<property name="text">
<string>Manhattan</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="move_angle_cb">
<item>
<property name="text">
<string>Any Direction</string>
</property>
</item>
<item>
<property name="text">
<string>Diagonal</string>
</property>
</item>
<item>
<property name="text">
<string>Manhattan</string>
</property>
</item>
</widget>
</item>
<item row="0" column="2" rowspan="2">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>257</width>
<height>41</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Hierarchical Features</string>
</property>
<layout class="QGridLayout">
<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>
<property name="spacing">
<number>6</number>
</property>
<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="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="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>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Instance Display</string>
</property>
<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">
<string>Show shapes when moving (max.</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="max_shapes_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="text">
<string>shapes)</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>121</width>
<height>51</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<tabstops>
<tabstop>scrollArea</tabstop>
<tabstop>grid_cb</tabstop>
<tabstop>edit_grid_le</tabstop>
<tabstop>snap_objects_cbx</tabstop>
<tabstop>conn_angle_cb</tabstop>
<tabstop>move_angle_cb</tabstop>
<tabstop>hier_sel_cbx</tabstop>
<tabstop>hier_copy_mode_cbx</tabstop>
<tabstop>show_shapes_cbx</tabstop>
<tabstop>max_shapes_le</tabstop>
</tabstops>

View File

@ -6,10 +6,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>680</width>
<height>574</height>
<width>358</width>
<height>496</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
@ -18,163 +24,218 @@
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
<number>0</number>
</property>
<property name="topMargin">
<number>9</number>
<number>0</number>
</property>
<property name="rightMargin">
<number>9</number>
<number>0</number>
</property>
<property name="bottomMargin">
<number>9</number>
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame">
<widget class="QScrollArea" name="scrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
<enum>QFrame::Plain</enum>
</property>
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>358</width>
<height>496</height>
</rect>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Cell </string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="cell_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="browse_pb">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="text">
<string> Library </string>
</property>
</widget>
</item>
<item>
<widget class="lay::LibrarySelectionComboBox" name="lib_cbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>522</width>
<height>8</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QTabWidget" name="param_tab_widget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Geometry</string>
</attribute>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>9</number>
<number>4</number>
</property>
<property name="topMargin">
<number>9</number>
<number>4</number>
</property>
<property name="rightMargin">
<number>9</number>
<number>4</number>
</property>
<property name="bottomMargin">
<number>9</number>
<number>4</number>
</property>
<item>
<property name="spacing">
<number>2</number>
</property>
<item row="0" column="0">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Library</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="lay::LibrarySelectionComboBox" name="lib_cbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Cell </string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="browse_pb">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/find.png</normaloff>:/find.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="cell_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="clearButtonEnabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<spacer name="spacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="place_origin_cb">
<property name="text">
<string>Place origin of cell</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Rotation / Scaling</string>
</property>
<layout class="QGridLayout">
<layout class="QGridLayout" name="_2">
<property name="leftMargin">
<number>9</number>
<number>4</number>
</property>
<property name="topMargin">
<number>9</number>
<number>4</number>
</property>
<property name="rightMargin">
<number>9</number>
<number>4</number>
</property>
<property name="bottomMargin">
<number>9</number>
<number>4</number>
</property>
<property name="spacing">
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<item row="0" column="1">
<widget class="QLineEdit" name="scale_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -194,14 +255,14 @@
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Scaling factor (magnification)</string>
<string>Scaling factor</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="angle_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -229,10 +290,17 @@
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_17">
<property name="text">
<string>(magnification)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<item row="5" column="0">
<widget class="QGroupBox" name="array_grp">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -246,33 +314,36 @@
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QGridLayout">
<layout class="QGridLayout" name="_3">
<property name="leftMargin">
<number>9</number>
<number>4</number>
</property>
<property name="topMargin">
<number>9</number>
<number>4</number>
</property>
<property name="rightMargin">
<number>9</number>
<number>4</number>
</property>
<property name="bottomMargin">
<number>9</number>
<number>4</number>
</property>
<property name="spacing">
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<item row="2" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string> Column vector (x,y)</string>
<string> Column step</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="column_x_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -292,7 +363,7 @@
<item row="2" column="4">
<widget class="QLineEdit" name="column_y_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -312,7 +383,7 @@
<item row="1" column="4">
<widget class="QLineEdit" name="row_y_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -332,7 +403,7 @@
<item row="1" column="2">
<widget class="QLineEdit" name="row_x_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -352,14 +423,14 @@
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string> Row vector (x,y)</string>
<string> Row step</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string> Rows/Columns</string>
<string>Dimension</string>
</property>
</widget>
</item>
@ -368,12 +439,15 @@
<property name="text">
<string>columns =</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLineEdit" name="columns_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -385,74 +459,89 @@
<property name="text">
<string>rows = </string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="rows_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="3" column="0" colspan="5">
<item row="4" column="0" colspan="5">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Warning: although row and column vectors can be arbitrary combination,
some design systems only accept orthogonal (rectangular) arrays.</string>
<string>Warning: although row and column vectors can be arbitrary combination, some design systems only accept orthogonal (rectangular) arrays.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<item row="6" column="0">
<spacer name="spacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>120</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="pcell_tab">
<attribute name="title">
<string>PCell</string>
</attribute>
</widget>
</widget>
</item>
<item>
<widget class="QCheckBox" name="place_origin_cb">
<property name="text">
<string>Place origin of cell</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>50</width>
<height>8</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
@ -462,22 +551,8 @@ some design systems only accept orthogonal (rectangular) arrays.</string>
<header>layWidgets.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>cell_le</tabstop>
<tabstop>browse_pb</tabstop>
<tabstop>lib_cbx</tabstop>
<tabstop>param_tab_widget</tabstop>
<tabstop>scale_le</tabstop>
<tabstop>angle_le</tabstop>
<tabstop>mirror_cbx</tabstop>
<tabstop>rows_le</tabstop>
<tabstop>columns_le</tabstop>
<tabstop>row_x_le</tabstop>
<tabstop>row_y_le</tabstop>
<tabstop>column_x_le</tabstop>
<tabstop>column_y_le</tabstop>
<tabstop>place_origin_cb</tabstop>
</tabstops>
<resources/>
<resources>
<include location="../../lay/lay/layResources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditorOptionsInstPCellParam</class>
<widget class="QWidget" name="EditorOptionsInstPCellParam">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>358</width>
<height>481</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,7 +1,8 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditorOptionsPath</class>
<widget class="QWidget" name="EditorOptionsPath" >
<property name="geometry" >
<widget class="QWidget" name="EditorOptionsPath">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
@ -9,228 +10,264 @@
<height>289</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>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame_2" >
<property name="frameShape" >
<widget class="QScrollArea" name="scrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
<property name="widgetResizable">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>357</width>
<height>289</height>
</rect>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_2" >
<property name="text" >
<string> Width </string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="width_le" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>micron</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>21</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="_2">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Width</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="width_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>µm</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>21</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Extensions</string>
</property>
<layout class="QGridLayout" name="_3">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<item row="2" column="1">
<widget class="QLabel" name="label_8">
<property name="text">
<string> end =</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="start_ext_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="label_5">
<property name="text">
<string>µm</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="end_ext_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="type_cb">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Flush</string>
</property>
</item>
<item>
<property name="text">
<string>Square</string>
</property>
</item>
<item>
<property name="text">
<string>Variable</string>
</property>
</item>
<item>
<property name="text">
<string>Round</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Variable </string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_4">
<property name="text">
<string>µm</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>start =</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="1" column="4">
<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>
</layout>
</widget>
</item>
<item row="2" column="0">
<spacer name="spacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>271</width>
<height>123</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title" >
<string>Extensions</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item rowspan="3" row="0" column="4" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>21</width>
<height>81</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="3" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>micron</string>
</property>
</widget>
</item>
<item row="1" column="3" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>micron</string>
</property>
</widget>
</item>
<item row="2" column="2" >
<widget class="QLineEdit" name="end_ext_le" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLabel" name="label_8" >
<property name="text" >
<string> end =</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<string>start =</string>
</property>
</widget>
</item>
<item row="1" column="2" >
<widget class="QLineEdit" name="start_ext_le" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<string>Variable </string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2" >
<widget class="QComboBox" name="type_cb" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text" >
<string>Flush</string>
</property>
</item>
<item>
<property name="text" >
<string>Square</string>
</property>
</item>
<item>
<property name="text" >
<string>Variable</string>
</property>
</item>
<item>
<property name="text" >
<string>Round</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Type</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>271</width>
<height>63</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<tabstops>
<tabstop>width_le</tabstop>
<tabstop>type_cb</tabstop>
<tabstop>start_ext_le</tabstop>
<tabstop>end_ext_le</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -1,7 +1,8 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditorOptionsText</class>
<widget class="QWidget" name="EditorOptionsText" >
<property name="geometry" >
<widget class="QWidget" name="EditorOptionsText">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
@ -9,225 +10,288 @@
<height>243</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
<layout class="QVBoxLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="spacing" >
<number>6</number>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame" >
<property name="frameShape" >
<widget class="QScrollArea" name="scrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
<property name="widgetResizable">
<bool>true</bool>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>542</width>
<height>243</height>
</rect>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="2" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Alignment</string>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLabel" name="label_8" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>h =</string>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="Text size" >
<property name="text" >
<string>Text size</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="4" >
<widget class="QLineEdit" name="text_le" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_2" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>Text</string>
</property>
</widget>
</item>
<item row="4" column="1" colspan="4" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Hint: orientation, alignments and size cannot be saved to OASIS files
Enable a vector font and text scaling in the setup dialog
to show text objects scaled and rotated</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2" >
<widget class="QLineEdit" name="size_le" />
</item>
<item row="3" column="3" colspan="2" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>(Leave empty for default)</string>
</property>
</widget>
</item>
<item row="2" column="4" >
<widget class="QComboBox" name="valign_cbx" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text" >
<string>(Default)</string>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</item>
<item>
<property name="text" >
<string>Top</string>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</item>
<item>
<property name="text" >
<string>Center</string>
<layout class="QGridLayout" name="_2">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<item row="2" column="3">
<widget class="QLabel" name="label_9">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>v =</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="5">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="0">
<widget class="QLabel" name="Text size">
<property name="text">
<string>Text size</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Text</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QComboBox" name="valign_cbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>(Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Top</string>
</property>
</item>
<item>
<property name="text">
<string>Center</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom</string>
</property>
</item>
</widget>
</item>
<item row="2" column="2">
<widget class="QComboBox" name="halign_cbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>(Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Left</string>
</property>
</item>
<item>
<property name="text">
<string>Center</string>
</property>
</item>
<item>
<property name="text">
<string>Right</string>
</property>
</item>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>h =</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Alignment</string>
</property>
</widget>
</item>
<item row="2" column="5">
<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="5">
<widget class="QLineEdit" name="text_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="4" column="1" colspan="5">
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="size_le"/>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>(empty for default)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="5" column="1" colspan="5">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Hint: orientation, alignments and size cannot be saved to OASIS files. Enable a vector font and text scaling in the setup dialog to show text objects scaled and rotated.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<spacer name="spacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</item>
<item>
<property name="text" >
<string>Bottom</string>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>77</height>
</size>
</property>
</item>
</widget>
</item>
<item row="2" column="3" >
<widget class="QLabel" name="label_9" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>v =</string>
</property>
</widget>
</item>
<item row="2" column="2" >
<widget class="QComboBox" name="halign_cbx" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text" >
<string>(Default)</string>
</property>
</item>
<item>
<property name="text" >
<string>Left</string>
</property>
</item>
<item>
<property name="text" >
<string>Center</string>
</property>
</item>
<item>
<property name="text" >
<string>Right</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0" colspan="5" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
</layout>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<tabstops>
<tabstop>text_le</tabstop>
<tabstop>halign_cbx</tabstop>
<tabstop>valign_cbx</tabstop>
<tabstop>size_le</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -1,73 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PCellParametersDialog</class>
<widget class="QDialog" name="PCellParametersDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>469</width>
<height>429</height>
</rect>
</property>
<property name="windowTitle">
<string>PCell Parameters</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="edt::PCellParametersPage" name="parameters" native="true"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttons">
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>edt::PCellParametersPage</class>
<extends>QWidget</extends>
<header>edtPCellParametersPage.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttons</sender>
<signal>rejected()</signal>
<receiver>PCellParametersDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>321</x>
<y>405</y>
</hint>
<hint type="destinationlabel">
<x>337</x>
<y>423</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttons</sender>
<signal>accepted()</signal>
<receiver>PCellParametersDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>427</x>
<y>405</y>
</hint>
<hint type="destinationlabel">
<x>443</x>
<y>425</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -21,7 +21,8 @@ HEADERS = \
edtServiceImpl.h \
edtUtils.h \
edtCommon.h \
edtPCellParametersDialog.h
edtDistribute.h \
edtRecentConfigurationPage.h
FORMS = \
AlignOptionsDialog.ui \
@ -29,7 +30,6 @@ FORMS = \
CopyModeDialog.ui \
ChangeLayerOptionsDialog.ui \
EditablePathPropertiesPage.ui \
EditorOptionsDialog.ui \
EditorOptionsGeneric.ui \
EditorOptionsInst.ui \
EditorOptionsPath.ui \
@ -42,7 +42,8 @@ FORMS = \
PolygonPropertiesPage.ui \
RoundCornerOptionsDialog.ui \
TextPropertiesPage.ui \
PCellParametersDialog.ui
DistributeOptionsDialog.ui \
EditorOptionsInstPCellParam.ui
SOURCES = \
edtConfig.cc \
@ -59,7 +60,8 @@ SOURCES = \
edtServiceImpl.cc \
edtUtils.cc \
gsiDeclEdt.cc \
edtPCellParametersDialog.cc
edtDistribute.cc \
edtRecentConfigurationPage.cc
INCLUDEPATH += $$TL_INC $$GSI_INC $$LAYBASIC_INC $$DB_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$LAYBASIC_INC $$DB_INC

View File

@ -326,6 +326,93 @@ AlignOptionsDialog::exec_dialog (lay::LayoutView * /*view*/, int &hmode, int &vm
}
}
// --------------------------------------------------------------------------------
// DistributeOptionsDialog implementation
DistributeOptionsDialog::DistributeOptionsDialog (QWidget *parent)
: QDialog (parent)
{
setObjectName (QString::fromUtf8 ("change_layer_options_dialog"));
Ui::DistributeOptionsDialog::setupUi (this);
}
DistributeOptionsDialog::~DistributeOptionsDialog ()
{
// .. nothing yet ..
}
bool
DistributeOptionsDialog::exec_dialog (lay::LayoutView * /*view*/, bool &hdistribute, int &hmode, double &hpitch, double &hspace, bool &vdistribute, int &vmode, double &vpitch, double &vspace, bool &visible_layers)
{
QRadioButton *hmode_buttons [] = { this->h_none_rb, this->h_left_rb, this->h_center_rb, this->h_right_rb };
QRadioButton *vmode_buttons [] = { this->v_none_rb, this->v_top_rb, this->v_center_rb, this->v_bottom_rb };
QRadioButton *layers_buttons [] = { this->all_layers_rb, this->visible_layers_rb };
this->h_distribute->setChecked (hdistribute);
for (int i = 1; i < 4; ++i) {
hmode_buttons [i]->setChecked (hmode == i);
}
this->h_space->setText (tl::to_qstring (tl::micron_to_string (hspace)));
this->h_pitch->setText (tl::to_qstring (tl::micron_to_string (hpitch)));
this->v_distribute->setChecked (vdistribute);
for (int i = 1; i < 4; ++i) {
vmode_buttons [i]->setChecked (vmode == i);
}
this->v_space->setText (tl::to_qstring (tl::micron_to_string (vspace)));
this->v_pitch->setText (tl::to_qstring (tl::micron_to_string (vpitch)));
for (int i = 0; i < 2; ++i) {
layers_buttons [i]->setChecked (int (visible_layers) == i);
}
if (QDialog::exec ()) {
hdistribute = this->h_distribute->isChecked ();
hmode = -1;
for (int i = 1; i < 4; ++i) {
if (hmode_buttons [i]->isChecked ()) {
hmode = i;
}
}
hspace = 0.0;
tl::from_string (tl::to_string (this->h_space->text ()), hspace);
hpitch = 0.0;
tl::from_string (tl::to_string (this->h_pitch->text ()), hpitch);
vdistribute = this->v_distribute->isChecked ();
vmode = -1;
for (int i = 1; i < 4; ++i) {
if (vmode_buttons [i]->isChecked ()) {
vmode = i;
}
}
vspace = 0.0;
tl::from_string (tl::to_string (this->v_space->text ()), vspace);
vpitch = 0.0;
tl::from_string (tl::to_string (this->v_pitch->text ()), vpitch);
visible_layers = false;
for (int i = 0; i < 2; ++i) {
if (layers_buttons [i]->isChecked ()) {
visible_layers = (i != 0);
}
}
return true;
} else {
return false;
}
}
// --------------------------------------------------------------------------------
// MakeCellOptionsDialog implementation

View File

@ -37,6 +37,7 @@
#include "ui_InstantiationForm.h"
#include "ui_ChangeLayerOptionsDialog.h"
#include "ui_AlignOptionsDialog.h"
#include "ui_DistributeOptionsDialog.h"
#include "ui_CopyModeDialog.h"
#include "ui_MakeCellOptionsDialog.h"
#include "ui_MakeArrayOptionsDialog.h"
@ -127,6 +128,22 @@ public:
bool exec_dialog (lay::LayoutView *view, int &hmode, int &vmode, bool &visible_layers);
};
/**
* @brief Distribute function options dialog
*/
class DistributeOptionsDialog
: public QDialog,
public Ui::DistributeOptionsDialog
{
Q_OBJECT
public:
DistributeOptionsDialog (QWidget *parent);
virtual ~DistributeOptionsDialog ();
bool exec_dialog (lay::LayoutView *view, bool &hdistribute, int &hmode, double &hpitch, double &hspace, bool &vdistribute, int &vmode, double &vpitch, double &vspace, bool &visible_layers);
};
/**
* @brief Options dialog for the "make cell" function
*/

View File

@ -0,0 +1,27 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "edtDistribute.h"
// .. nothing yet (all in header) ..

476
src/edt/edt/edtDistribute.h Normal file
View File

@ -0,0 +1,476 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_edtDistribute
#define HDR_edtDistribute
#include "dbBox.h"
#include "dbTypes.h"
#include "tlIntervalMap.h"
namespace edt
{
/**
* @brief Gets the box position by reference position
*/
template <class Box, bool horizontally>
typename Box::coord_type box_position (const Box &box, int ref)
{
if (horizontally) {
if (ref < 0) {
return box.left ();
} else if (ref == 0) {
return box.center ().x ();
} else {
return box.right ();
}
} else {
if (ref < 0) {
return box.bottom ();
} else if (ref == 0) {
return box.center ().y ();
} else {
return box.top ();
}
}
}
/**
* @brief Compares boxes by their reference position
*/
template <class Box, class Value, bool horizontally>
class box_compare
{
public:
typedef typename Box::coord_type coord_type;
box_compare (int ref)
: m_ref (ref)
{
// .. nothing yet ..
}
bool operator() (const std::pair<Box, Value> &a, const std::pair<Box, Value> &b) const
{
coord_type ca = box_position<Box, horizontally> (a.first, m_ref);
coord_type cb = box_position<Box, horizontally> (b.first, m_ref);
if (! db::coord_traits<coord_type>::equal (ca, cb)) {
return db::coord_traits<coord_type>::less (ca, cb);
} else {
coord_type ca2 = box_position<Box, !horizontally> (a.first, m_ref);
coord_type cb2 = box_position<Box, !horizontally> (b.first, m_ref);
return db::coord_traits<coord_type>::less (ca2, cb2);
}
}
private:
int m_ref;
};
/**
* @brief Does some heuristic binning of coordinates
*/
template <class Box, bool horizontally>
void do_bin (typename std::vector<std::pair<Box, size_t> >::const_iterator b, typename std::vector<std::pair<Box, size_t> >::const_iterator e, int ref, std::vector<std::vector<size_t> > &bins)
{
typedef typename Box::coord_type coord_type;
// determine maximum distance between adjacent coordinates
coord_type max_dist = 0;
for (typename std::vector<std::pair<Box, size_t> >::const_iterator i = b + 1; i != e; ++i) {
max_dist = std::max (max_dist, box_position<Box, horizontally> (i->first, ref) - box_position<Box, horizontally> ((i - 1)->first, ref));
}
// heuristically, everything that has a distance of less than 1/3 of the maximum distance falls into one bin
coord_type bin_start = box_position<Box, horizontally> (b->first, ref);
bins.push_back (std::vector<size_t> ());
bins.back ().push_back (b->second);
coord_type thr = max_dist / 3;
for (typename std::vector<std::pair<Box, size_t> >::const_iterator i = b + 1; i != e; ++i) {
coord_type c = box_position<Box, horizontally> (i->first, ref);
if (c - bin_start > thr) {
// start a new bin
bins.push_back (std::vector<size_t> ());
bin_start = c;
}
bins.back ().push_back (i->second);
}
}
/**
* @brief Computes the effective box width (rounded to pitch, space added)
*/
template <class Box, bool horizontal>
inline typename Box::coord_type eff_dim (const Box &box, typename Box::coord_type pitch, typename Box::coord_type space)
{
typedef typename Box::coord_type coord_type;
coord_type d = (horizontal ? box.width () : box.height ()) + space;
if (pitch > 0) {
d = db::coord_traits<coord_type>::rounded (ceil (double (d) / double (pitch) - 1e-10) * double (pitch));
}
return d;
}
template <class Coord>
struct max_coord_join_op
{
void operator() (Coord &a, const Coord &b) const
{
a = std::max (a, b);
}
};
/**
* @brief Implements an algorithm for 2d-distributing rectangular objects
*/
template <class Box, class Value>
class distributed_placer
{
public:
typedef typename Box::coord_type coord_type;
typedef std::vector<std::pair<Box, Value> > objects;
typedef typename objects::const_iterator iterator;
/**
* @brief Constructor
*/
distributed_placer ()
{
// .. nothing yet ..
}
/**
* @brief Reserves space for n objects
*/
void reserve (size_t n)
{
m_objects.reserve (n);
}
/**
* @brief Inserts a new object
*/
void insert (const Box &box, const Value &value)
{
tl_assert (! box.empty ());
m_objects.push_back (std::make_pair (box, value));
}
/**
* @brief Stored objects iterator: begin
*/
iterator begin () const
{
return m_objects.begin ();
}
/**
* @brief Stored objects iterator: end
*/
iterator end () const
{
return m_objects.end ();
}
/**
* @brief Distributes the stored objects in vertical direction only
*
* @param ref The reference location (-1: bottom, 0: center, 1: top)
* @param refp The alignment in the other (horizontal) direction (-1: left, 0: center, 1: right, other: leave as is)
* @param pitch The distribution pitch (grid) or 0 for no pitch
* @param space The minimum space between the objects
*/
void distribute_v (int ref, int refp, coord_type pitch, coord_type space)
{
do_distribute_1d<false> (ref, refp, pitch, space);
}
/**
* @brief Distributes the stored objects in horizontal direction only
*
* @param ref The reference location (-1: left, 0: center, 1: right)
* @param refp The alignment in the other (vertical) direction (-1: bottom, 0: center, 1: top, other: leave as is)
* @param pitch The distribution pitch (grid) or 0 for no pitch
* @param space The minimum space between the objects
*/
void distribute_h (int ref, int refp, coord_type pitch, coord_type space)
{
do_distribute_1d<true> (ref, refp, pitch, space);
}
/**
* @brief Distributes the stored objects in horizontal and vertical direction
*
* @param href The horizontal reference location (-1: left, 0: center, 1: right)
* @param hpitch The horizontal distribution pitch (grid) or 0 for no pitch
* @param hspace The horizontal minimum space between the objects
* @param vref The vertical reference location (-1: bottom, 0: center, 1: top)
* @param vpitch The vertical distribution pitch (grid) or 0 for no pitch
* @param vspace The vertical minimum space between the objects
*/
void distribute_matrix (int href, coord_type hpitch, coord_type hspace, int vref, coord_type vpitch, coord_type vspace)
{
if (m_objects.size () < 2) {
return;
}
// The algorithm is this:
// 1.) Bin the boxes according to their positions in horizontal and vertical direction.
// This forms the potential columns and rows
// 2.) Compute the row and column widths and heights as the maximum of their content
// 3.) position the objects inside these cells
std::vector<std::pair<Box, size_t> > indexed_boxes;
indexed_boxes.reserve (m_objects.size ());
Box all;
for (typename objects::iterator i = m_objects.begin (); i != m_objects.end (); ++i) {
all += i->first;
}
size_t n = 0;
for (typename objects::iterator i = m_objects.begin (); i != m_objects.end (); ++i, ++n) {
indexed_boxes.push_back (std::make_pair (i->first, n));
}
std::vector<std::vector<size_t> > hbins, vbins;
std::sort (indexed_boxes.begin (), indexed_boxes.end (), box_compare<Box, size_t, true> (href));
do_bin<Box, true> (indexed_boxes.begin (), indexed_boxes.end (), href, hbins);
std::sort (indexed_boxes.begin (), indexed_boxes.end (), box_compare<Box, size_t, false> (vref));
do_bin<Box, false> (indexed_boxes.begin (), indexed_boxes.end (), vref, vbins);
// rewrite the bins to cell occupation lists
std::vector<std::vector<std::vector<size_t> > > cells;
cells.resize (hbins.size ());
for (size_t i = 0; i < hbins.size (); ++i) {
cells [i].resize (vbins.size ());
}
{
std::vector<size_t> hbin_for_index;
hbin_for_index.resize (indexed_boxes.size (), size_t (0));
for (std::vector<std::vector<size_t> >::const_iterator i = hbins.begin (); i != hbins.end (); ++i) {
for (std::vector<size_t>::const_iterator j = i->begin (); j != i->end (); ++j) {
hbin_for_index [*j] = i - hbins.begin ();
}
}
for (std::vector<std::vector<size_t> >::const_iterator i = vbins.begin (); i != vbins.end (); ++i) {
for (std::vector<size_t>::const_iterator j = i->begin (); j != i->end (); ++j) {
cells [hbin_for_index [*j]][i - vbins.begin ()].push_back (*j);
}
}
}
// initialize the cell widths
std::vector<coord_type> cell_widths, cell_heights;
cell_widths.resize (hbins.size (), 0);
cell_heights.resize (vbins.size (), 0);
// compute the cell widths as the maximum of the content
for (std::vector<std::vector<std::vector<size_t> > >::const_iterator i = cells.begin (); i != cells.end (); ++i) {
for (std::vector<std::vector<size_t> >::const_iterator j = i->begin (); j != i->end (); ++j) {
coord_type wcell = 0, hcell = 0;
for (std::vector<size_t>::const_iterator k = j->begin (); k != j->end (); ++k) {
// NOTE: intra-cell objects are distributed horizontally
wcell += eff_dim<Box, true> (m_objects [*k].first, hpitch, hspace);
hcell = std::max (hcell, eff_dim<Box, false> (m_objects [*k].first, vpitch, vspace));
}
cell_widths [i - cells.begin ()] = std::max (cell_widths [i - cells.begin ()], wcell);
cell_heights [j - i->begin ()] = std::max (cell_heights [j - i->begin ()], hcell);
}
}
// Compute the columns and row positions
std::vector<coord_type> cell_xpos, cell_ypos;
cell_xpos.reserve (cell_widths.size ());
cell_ypos.reserve (cell_heights.size ());
coord_type x = 0, y = 0;
for (typename std::vector<coord_type>::const_iterator i = cell_widths.begin (); i != cell_widths.end (); ++i) {
cell_xpos.push_back (x);
x += *i;
}
for (typename std::vector<coord_type>::const_iterator i = cell_heights.begin (); i != cell_heights.end (); ++i) {
cell_ypos.push_back (y);
y += *i;
}
// Compute the actual coordinates of the objects inside the cells
for (std::vector<std::vector<std::vector<size_t> > >::const_iterator i = cells.begin (); i != cells.end (); ++i) {
for (std::vector<std::vector<size_t> >::const_iterator j = i->begin (); j != i->end (); ++j) {
coord_type wcell = 0;
for (std::vector<size_t>::const_iterator k = j->begin (); k != j->end (); ++k) {
// NOTE: intra-cell objects are distributed horizontally
wcell += eff_dim<Box, true> (m_objects [*k].first, hpitch, hspace);
}
coord_type x = cell_xpos [i - cells.begin ()];
if (href == 0) {
x += (cell_widths [i - cells.begin ()] - wcell) / 2;
} else if (href > 0) {
x += (cell_widths [i - cells.begin ()] - wcell);
}
for (std::vector<size_t>::const_iterator k = j->begin (); k != j->end (); ++k) {
coord_type w = eff_dim<Box, true> (m_objects [*k].first, hpitch, hspace);
coord_type h = eff_dim<Box, false> (m_objects [*k].first, vpitch, vspace);
coord_type y = cell_ypos [j - i->begin ()];
if (vref == 0) {
y += (cell_heights [j - i->begin ()] - h) / 2;
} else if (href > 0) {
y += (cell_heights [j - i->begin ()] - h);
}
m_objects [*k].first.move (db::point<coord_type> (x, y) - m_objects [*k].first.p1 ());
// NOTE: intra-cell objects are distributed horizontally
x += w;
}
}
}
// Final adjustments - align the whole matrix with the original bounding box
Box new_all;
for (typename objects::iterator i = m_objects.begin (); i != m_objects.end (); ++i, ++n) {
new_all += i->first;
}
coord_type dh = box_position<Box, true> (all, href) - box_position<Box, true> (new_all, href);
coord_type dv = box_position<Box, false> (all, vref) - box_position<Box, false> (new_all, vref);
db::vector<coord_type> mv (dh, dv);
for (typename objects::iterator i = m_objects.begin (); i != m_objects.end (); ++i) {
i->first.move (mv);
}
}
private:
objects m_objects;
template <bool horizontally>
void do_distribute_1d (int ref, int refp, coord_type pitch, coord_type space)
{
if (m_objects.size () < 2) {
return;
}
Box all;
for (typename objects::const_iterator i = m_objects.begin () + 1; i != m_objects.end (); ++i) {
all += i->first;
}
std::sort (m_objects.begin (), m_objects.end (), box_compare<Box, Value, horizontally> (ref));
Box current = m_objects.front ().first;
coord_type p0 = box_position<Box, horizontally> (current, ref);
for (typename objects::iterator i = m_objects.begin () + 1; i != m_objects.end (); ++i) {
coord_type p = box_position<Box, horizontally> (i->first, -1);
coord_type offset = box_position<Box, horizontally> (i->first, ref) - p;
coord_type pnew = box_position<Box, horizontally> (current, 1) + space;
if (db::coord_traits<coord_type>::less (0, pitch)) {
pnew = coord_type (ceil (double (pnew + offset - p0) / double (pitch) - 1e-10)) * pitch - offset + p0;
}
db::vector<coord_type> mv;
if (horizontally) {
mv = db::vector<coord_type> (pnew - p, 0);
} else {
mv = db::vector<coord_type> (0, pnew - p);
}
i->first.move (mv);
current = i->first;
}
// final adjustment
Box new_all = m_objects.front ().first + m_objects.back ().first;
db::vector<coord_type> mv;
coord_type d = box_position<Box, horizontally> (all, ref) - box_position<Box, horizontally> (new_all, ref);
if (horizontally) {
mv = db::vector<coord_type> (d, 0);
} else {
mv = db::vector<coord_type> (0, d);
}
for (typename objects::iterator i = m_objects.begin (); i != m_objects.end (); ++i) {
i->first.move (mv);
if (refp >= -1 && refp <= 1) {
coord_type dp = box_position<Box, ! horizontally> (all, refp) - box_position<Box, ! horizontally> (i->first, refp);
db::vector<coord_type> mvp;
if (horizontally) {
mvp = db::vector<coord_type> (0, dp);
} else {
mvp = db::vector<coord_type> (dp, 0);
}
i->first.move (mvp);
}
}
}
};
}
#endif

View File

@ -25,209 +25,67 @@
#include "dbLibrary.h"
#include "dbLibraryManager.h"
#include "dbPCellHeader.h"
#include "edtEditorOptionsPages.h"
#include "edtPCellParametersPage.h"
#include "edtConfig.h"
#include "edtService.h"
#include "edtEditorOptionsPages.h"
#include "edtPropertiesPageUtils.h"
#include "tlExceptions.h"
#include "layPlugin.h"
#include "layLayoutView.h"
#include "layCellSelectionForm.h"
#include "ui_EditorOptionsDialog.h"
#include "layQtTools.h"
#include "ui_EditorOptionsGeneric.h"
#include "ui_EditorOptionsPath.h"
#include "ui_EditorOptionsText.h"
#include "ui_EditorOptionsInst.h"
#include "ui_EditorOptionsInstPCellParam.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QTabWidget>
#include <QToolButton>
#include <QCompleter>
namespace edt
{
// ------------------------------------------------------------------
// EditorOptionsPage implementation
// Configures a value from a line edit
EditorOptionsPage::EditorOptionsPage ()
: mp_owner (0), m_active (true), mp_plugin_declaration (0)
{
// nothing yet ..
}
EditorOptionsPage::~EditorOptionsPage ()
{
set_owner (0);
}
void
EditorOptionsPage::set_owner (EditorOptionsPages *owner)
{
if (mp_owner) {
mp_owner->unregister_page (this);
}
mp_owner = owner;
}
void
EditorOptionsPage::activate (bool active)
{
if (m_active != active) {
m_active = active;
if (mp_owner) {
mp_owner->activate_page (this);
}
}
}
// ------------------------------------------------------------------
// EditorOptionsPages implementation
struct EOPCompareOp
{
bool operator() (edt::EditorOptionsPage *a, edt::EditorOptionsPage *b) const
{
return a->order () < b->order ();
}
};
EditorOptionsPages::EditorOptionsPages (const std::vector<edt::EditorOptionsPage *> &pages, lay::Dispatcher *root)
: mp_root (root)
{
mp_ui = new Ui::EditorOptionsDialog ();
mp_ui->setupUi (this);
connect (mp_ui->apply_pb, SIGNAL (clicked ()), this, SLOT (apply ()));
m_pages = pages;
for (std::vector <edt::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
(*p)->set_owner (this);
}
update (0);
setup ();
}
EditorOptionsPages::~EditorOptionsPages ()
{
while (m_pages.size () > 0) {
delete m_pages [0];
}
delete mp_ui;
mp_ui = 0;
}
void
EditorOptionsPages::unregister_page (edt::EditorOptionsPage *page)
{
std::vector <edt::EditorOptionsPage *> pages;
for (std::vector <edt::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
if (*p != page) {
pages.push_back (*p);
}
}
m_pages = pages;
update (0);
}
void
EditorOptionsPages::activate_page (edt::EditorOptionsPage *page)
template <class Value>
static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le, const std::string &cfg_name)
{
try {
page->setup (mp_root);
} catch (...) {
// catch any errors related to configuration file errors etc.
Value value = Value (0);
tl::from_string (tl::to_string (le->text ()), value);
dispatcher->config_set (cfg_name, tl::to_string (value));
lay::indicate_error (le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
}
update (page);
if (isVisible ()) {
activateWindow ();
raise ();
}
}
void
EditorOptionsPages::update (edt::EditorOptionsPage *page)
{
std::sort (m_pages.begin (), m_pages.end (), EOPCompareOp ());
while (mp_ui->pages->count () > 0) {
mp_ui->pages->removeTab (0);
}
int index = -1;
for (std::vector <edt::EditorOptionsPage *>::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
if ((*p)->active ()) {
mp_ui->pages->addTab ((*p)->q_frame (), tl::to_qstring ((*p)->title ()));
if ((*p) == page) {
index = int (std::distance (m_pages.begin (), p));
}
} else {
(*p)->q_frame ()->setParent (0);
}
}
if (index < 0) {
index = mp_ui->pages->currentIndex ();
}
if (index >= int (mp_ui->pages->count ())) {
index = mp_ui->pages->count () - 1;
}
mp_ui->pages->setCurrentIndex (index);
}
void
EditorOptionsPages::setup ()
{
try {
for (std::vector <edt::EditorOptionsPage *>::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
if ((*p)->active ()) {
(*p)->setup (mp_root);
}
}
// make the display consistent with the status (this is important for
// PCell parameters where the PCell may be asked to modify the parameters)
do_apply ();
} catch (...) {
// catch any errors related to configuration file errors etc.
}
}
void
EditorOptionsPages::do_apply ()
{
for (std::vector <edt::EditorOptionsPage *>::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
if ((*p)->active ()) {
(*p)->apply (mp_root);
}
}
}
void
EditorOptionsPages::apply ()
{
BEGIN_PROTECTED
do_apply ();
END_PROTECTED_W (this)
}
void
EditorOptionsPages::accept ()
{
BEGIN_PROTECTED
do_apply ();
QDialog::accept ();
END_PROTECTED_W (this)
}
// ------------------------------------------------------------------
// EditorOptionsGeneric implementation
EditorOptionsGeneric::EditorOptionsGeneric ()
: QWidget (), EditorOptionsPage ()
EditorOptionsGeneric::EditorOptionsGeneric (lay::Dispatcher *dispatcher)
: EditorOptionsPage (dispatcher)
{
mp_ui = new Ui::EditorOptionsGeneric ();
mp_ui->setupUi (this);
connect (mp_ui->grid_cb, SIGNAL (activated (int)), this, SLOT (grid_changed (int)));
connect (mp_ui->edit_grid_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->grid_cb, SIGNAL (activated (int)), this, SLOT (edited ()));
connect (mp_ui->move_angle_cb, SIGNAL (activated (int)), this, SLOT (edited ()));
connect (mp_ui->conn_angle_cb, SIGNAL (activated (int)), this, SLOT (edited ()));
connect (mp_ui->hier_sel_cbx, SIGNAL (clicked ()), this, SLOT (edited ()));
connect (mp_ui->hier_copy_mode_cbx, SIGNAL (activated (int)), this, SLOT (edited ()));
connect (mp_ui->snap_objects_cbx, SIGNAL (clicked ()), this, SLOT (edited ()));
connect (mp_ui->max_shapes_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->show_shapes_cbx, SIGNAL (clicked ()), this, SLOT (edited ()));
}
EditorOptionsGeneric::~EditorOptionsGeneric ()
@ -236,27 +94,32 @@ EditorOptionsGeneric::~EditorOptionsGeneric ()
mp_ui = 0;
}
std::string
std::string
EditorOptionsGeneric::title () const
{
return tl::to_string (QObject::tr ("Basic Editing"));
}
void
EditorOptionsGeneric::apply (lay::Plugin *root)
void
EditorOptionsGeneric::apply (lay::Dispatcher *root)
{
// Edit grid
db::DVector eg;
EditGridConverter egc;
if (mp_ui->grid_cb->currentIndex () == 0) {
eg = db::DVector (-1.0, -1.0);
root->config_set (cfg_edit_grid, egc.to_string (db::DVector (-1.0, -1.0)));
} else if (mp_ui->grid_cb->currentIndex () == 1) {
eg = db::DVector ();
root->config_set (cfg_edit_grid, egc.to_string (db::DVector ()));
} else {
egc.from_string_picky (tl::to_string (mp_ui->edit_grid_le->text ()), eg);
try {
db::DVector eg;
egc.from_string_picky (tl::to_string (mp_ui->edit_grid_le->text ()), eg);
lay::indicate_error (mp_ui->edit_grid_le, 0);
root->config_set (cfg_edit_grid, egc.to_string (eg));
} catch (tl::Exception &ex) {
lay::indicate_error (mp_ui->edit_grid_le, &ex);
}
}
root->config_set (cfg_edit_grid, egc.to_string (eg));
// Edit & move angle
@ -269,9 +132,7 @@ EditorOptionsGeneric::apply (lay::Plugin *root)
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;
tl::from_string (tl::to_string (mp_ui->max_shapes_le->text ()), max_shapes);
root->config_set (cfg_edit_max_shapes_of_instances, tl::to_string (max_shapes));
configure_from_line_edit<unsigned int> (root, mp_ui->max_shapes_le, cfg_edit_max_shapes_of_instances);
root->config_set (cfg_edit_show_shapes_of_instances, tl::to_string (mp_ui->show_shapes_cbx->isChecked ()));
}
@ -287,8 +148,8 @@ EditorOptionsGeneric::show_shapes_changed ()
mp_ui->max_shapes_le->setEnabled (mp_ui->show_shapes_cbx->isChecked ());
}
void
EditorOptionsGeneric::setup (lay::Plugin *root)
void
EditorOptionsGeneric::setup (lay::Dispatcher *root)
{
// Edit grid
@ -305,12 +166,13 @@ EditorOptionsGeneric::setup (lay::Plugin *root)
mp_ui->edit_grid_le->setText (tl::to_qstring (egc.to_string (eg)));
}
grid_changed (mp_ui->grid_cb->currentIndex ());
lay::indicate_error (mp_ui->edit_grid_le, 0);
// edit & move angle
ACConverter acc;
lay::angle_constraint_type ac;
ac = lay::AC_Any;
root->config_get (cfg_edit_move_angle_mode, ac, acc);
mp_ui->move_angle_cb->setCurrentIndex (int (ac));
@ -334,6 +196,7 @@ EditorOptionsGeneric::setup (lay::Plugin *root)
unsigned int max_shapes = 1000;
root->config_get (cfg_edit_max_shapes_of_instances, max_shapes);
mp_ui->max_shapes_le->setText (tl::to_qstring (tl::to_string (max_shapes)));
lay::indicate_error (mp_ui->max_shapes_le, 0);
bool show_shapes = true;
root->config_get (cfg_edit_show_shapes_of_instances, show_shapes);
@ -343,11 +206,16 @@ EditorOptionsGeneric::setup (lay::Plugin *root)
// ------------------------------------------------------------------
// EditorOptionsText implementation
EditorOptionsText::EditorOptionsText ()
: QWidget (), EditorOptionsPage ()
EditorOptionsText::EditorOptionsText (lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher)
{
mp_ui = new Ui::EditorOptionsText ();
mp_ui->setupUi (this);
connect (mp_ui->text_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->halign_cbx, SIGNAL (activated (int)), this, SLOT (edited ()));
connect (mp_ui->valign_cbx, SIGNAL (activated (int)), this, SLOT (edited ()));
connect (mp_ui->size_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
}
EditorOptionsText::~EditorOptionsText ()
@ -363,7 +231,7 @@ EditorOptionsText::title () const
}
void
EditorOptionsText::apply (lay::Plugin *root)
EditorOptionsText::apply (lay::Dispatcher *root)
{
// Text string
root->config_set (cfg_edit_text_string, tl::unescape_string (tl::to_string (mp_ui->text_le->text ())));
@ -387,7 +255,7 @@ EditorOptionsText::apply (lay::Plugin *root)
}
void
EditorOptionsText::setup (lay::Plugin *root)
EditorOptionsText::setup (lay::Dispatcher *root)
{
// Text string
std::string s;
@ -416,13 +284,18 @@ EditorOptionsText::setup (lay::Plugin *root)
// ------------------------------------------------------------------
// EditorOptionsPath implementation
EditorOptionsPath::EditorOptionsPath ()
: QWidget (), EditorOptionsPage ()
EditorOptionsPath::EditorOptionsPath (lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher)
{
mp_ui = new Ui::EditorOptionsPath ();
mp_ui->setupUi (this);
connect (mp_ui->type_cb, SIGNAL (currentIndexChanged (int)), this, SLOT (type_changed (int)));
connect (mp_ui->width_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->type_cb, SIGNAL (activated (int)), this, SLOT (edited ()));
connect (mp_ui->start_ext_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->end_ext_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
}
EditorOptionsPath::~EditorOptionsPath ()
@ -445,13 +318,11 @@ EditorOptionsPath::type_changed (int type)
}
void
EditorOptionsPath::apply (lay::Plugin *root)
EditorOptionsPath::apply (lay::Dispatcher *root)
{
// width
double w = 0.0;
tl::from_string (tl::to_string (mp_ui->width_le->text ()), w);
root->config_set (cfg_edit_path_width, tl::to_string (w));
configure_from_line_edit<double> (root, mp_ui->width_le, cfg_edit_path_width);
// path type and extensions
@ -465,14 +336,10 @@ EditorOptionsPath::apply (lay::Plugin *root)
} else if (mp_ui->type_cb->currentIndex () == 2) {
double bgnext = 0.0, endext = 0.0;
root->config_set (cfg_edit_path_ext_type, "variable");
tl::from_string (tl::to_string (mp_ui->start_ext_le->text ()), bgnext);
root->config_set (cfg_edit_path_ext_var_begin, tl::to_string (bgnext));
tl::from_string (tl::to_string (mp_ui->end_ext_le->text ()), endext);
root->config_set (cfg_edit_path_ext_var_end, tl::to_string (endext));
configure_from_line_edit<double> (root, mp_ui->start_ext_le, cfg_edit_path_ext_var_begin);
configure_from_line_edit<double> (root, mp_ui->end_ext_le, cfg_edit_path_ext_var_end);
} else if (mp_ui->type_cb->currentIndex () == 3) {
@ -482,13 +349,14 @@ EditorOptionsPath::apply (lay::Plugin *root)
}
void
EditorOptionsPath::setup (lay::Plugin *root)
EditorOptionsPath::setup (lay::Dispatcher *root)
{
// width
double w = 0.0;
root->config_get (cfg_edit_path_width, w);
mp_ui->width_le->setText (tl::to_qstring (tl::to_string (w)));
lay::indicate_error (mp_ui->width_le, 0);
// path type and extensions
@ -509,26 +377,35 @@ EditorOptionsPath::setup (lay::Plugin *root)
root->config_get (cfg_edit_path_ext_var_begin, bgnext);
root->config_get (cfg_edit_path_ext_var_end, endext);
mp_ui->start_ext_le->setText (tl::to_qstring (tl::to_string (bgnext)));
lay::indicate_error (mp_ui->start_ext_le, 0);
mp_ui->end_ext_le->setText (tl::to_qstring (tl::to_string (endext)));
lay::indicate_error (mp_ui->end_ext_le, 0);
}
// ------------------------------------------------------------------
// EditorOptionsInst implementation
EditorOptionsInst::EditorOptionsInst (lay::Dispatcher *root)
: QWidget (), EditorOptionsPage (), mp_root (root), mp_pcell_parameters (0)
EditorOptionsInst::EditorOptionsInst (lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher)
{
mp_ui = new Ui::EditorOptionsInst ();
mp_ui->setupUi (this);
connect (mp_ui->array_grp, SIGNAL (clicked ()), this, SLOT (array_changed ()));
connect (mp_ui->browse_pb, SIGNAL (clicked ()), this, SLOT (browse_cell ()));
connect (mp_ui->lib_cbx, SIGNAL (currentIndexChanged (int)), this, SLOT (library_changed (int)));
connect (mp_ui->cell_le, SIGNAL (textChanged (const QString &)), this, SLOT (cell_name_changed (const QString &)));
QHBoxLayout *layout = new QHBoxLayout (mp_ui->pcell_tab);
layout->setMargin (0);
mp_ui->pcell_tab->setLayout (layout);
connect (mp_ui->lib_cbx, SIGNAL (currentIndexChanged (int)), this, SLOT (library_changed ()));
connect (mp_ui->cell_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->angle_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->scale_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->rows_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->row_x_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->row_y_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->columns_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->column_x_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->column_y_le, SIGNAL (editingFinished ()), this, SLOT (edited ()));
connect (mp_ui->mirror_cbx, SIGNAL (clicked ()), this, SLOT (edited ()));
connect (mp_ui->array_grp, SIGNAL (clicked ()), this, SLOT (edited ()));
connect (mp_ui->place_origin_cb, SIGNAL (clicked ()), this, SLOT (edited ()));
m_cv_index = -1;
}
@ -546,19 +423,61 @@ EditorOptionsInst::title () const
}
void
EditorOptionsInst::library_changed (int)
EditorOptionsInst::library_changed ()
{
BEGIN_PROTECTED
update_pcell_parameters ();
END_PROTECTED
update_cell_edits ();
edited ();
}
// Maximum number of cells for which to offer a cell name completer
const static size_t max_cells = 10000;
void
EditorOptionsInst::cell_name_changed (const QString &)
EditorOptionsInst::update_cell_edits ()
{
BEGIN_PROTECTED
update_pcell_parameters ();
END_PROTECTED
if (mp_ui->cell_le->completer ()) {
mp_ui->cell_le->completer ()->deleteLater ();
}
db::Layout *layout = 0;
lay::LayoutView *view = lay::LayoutView::current ();
// find the layout the cell has to be looked up: that is either the layout of the current instance or
// the library selected
if (mp_ui->lib_cbx->current_library ()) {
layout = &mp_ui->lib_cbx->current_library ()->layout ();
} else if (view && view->cellview (m_cv_index).is_valid ()) {
layout = &view->cellview (m_cv_index)->layout ();
}
if (! layout) {
return;
}
QStringList cellnames;
if (layout->cells () < max_cells) {
for (db::Layout::iterator c = layout->begin (); c != layout->end (); ++c) {
cellnames.push_back (tl::to_qstring (layout->cell_name (c->cell_index ())));
}
for (db::Layout::pcell_iterator pc = layout->begin_pcells (); pc != layout->end_pcells () && size_t (cellnames.size ()) < max_cells; ++pc) {
cellnames.push_back (tl::to_qstring (pc->first));
}
}
if (size_t (cellnames.size ()) < max_cells) {
QCompleter *completer = new QCompleter (cellnames, this);
completer->setCaseSensitivity (Qt::CaseSensitive);
mp_ui->cell_le->setCompleter (completer);
} else {
mp_ui->cell_le->setCompleter (0);
}
std::pair<bool, db::pcell_id_type> pc = layout->pcell_by_name (tl::to_string (mp_ui->cell_le->text ()).c_str ());
std::pair<bool, db::cell_index_type> cc = layout->cell_by_name (tl::to_string (mp_ui->cell_le->text ()).c_str ());
// by the way, update the foreground color of the cell edit box as well (red, if not valid)
tl::Exception ex ("No cell or PCell with this name");
lay::indicate_error (mp_ui->cell_le, (! pc.first && ! cc.first) ? &ex : 0);
}
void
@ -602,7 +521,7 @@ BEGIN_PROTECTED
} else if (layout->is_valid_cell_index (form.selected_cell_index ())) {
mp_ui->cell_le->setText (tl::to_qstring (layout->cell_name (form.selected_cell_index ())));
}
update_pcell_parameters ();
edited ();
}
}
@ -620,74 +539,40 @@ EditorOptionsInst::array_changed ()
mp_ui->columns_le->setEnabled (array);
mp_ui->column_x_le->setEnabled (array);
mp_ui->column_y_le->setEnabled (array);
edited ();
}
void
EditorOptionsInst::apply (lay::Plugin *root)
EditorOptionsInst::apply (lay::Dispatcher *root)
{
// cell name
root->config_set (cfg_edit_inst_cell_name, tl::to_string (mp_ui->cell_le->text ()));
// cell name
// lib name
if (mp_ui->lib_cbx->current_library ()) {
root->config_set (cfg_edit_inst_lib_name, mp_ui->lib_cbx->current_library ()->get_name ());
} else {
root->config_set (cfg_edit_inst_lib_name, std::string ());
}
// pcell parameters
std::string param;
db::Layout *layout = 0;
if (mp_ui->lib_cbx->current_library ()) {
layout = &mp_ui->lib_cbx->current_library ()->layout ();
} else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout ();
}
if (layout && mp_pcell_parameters) {
std::pair<bool, db::pcell_id_type> pc = layout->pcell_by_name (tl::to_string (mp_ui->cell_le->text ()).c_str ());
if (pc.first) {
const db::PCellDeclaration *pc_decl = layout->pcell_declaration (pc.second);
if (pc_decl) {
param = pcell_parameters_to_string (pc_decl->named_parameters (mp_pcell_parameters->get_parameters ()));
}
}
}
root->config_set (cfg_edit_inst_pcell_parameters, param);
// rotation, scaling
double angle = 0.0;
tl::from_string (tl::to_string (mp_ui->angle_le->text ()), angle);
root->config_set (cfg_edit_inst_angle, tl::to_string (angle));
configure_from_line_edit<double> (root, mp_ui->angle_le, cfg_edit_inst_angle);
bool mirror = mp_ui->mirror_cbx->isChecked ();
root->config_set (cfg_edit_inst_mirror, tl::to_string (mirror));
double scale = 1.0;
tl::from_string (tl::to_string (mp_ui->scale_le->text ()), scale);
root->config_set (cfg_edit_inst_scale, tl::to_string (scale));
configure_from_line_edit<double> (root, mp_ui->scale_le, cfg_edit_inst_scale);
// array
bool array = mp_ui->array_grp->isChecked ();
root->config_set (cfg_edit_inst_array, tl::to_string (array));
int rows = 1, columns = 1;
double row_x = 0.0, row_y = 0.0, column_x = 0.0, column_y = 0.0;
tl::from_string (tl::to_string (mp_ui->rows_le->text ()), rows);
tl::from_string (tl::to_string (mp_ui->row_x_le->text ()), row_x);
tl::from_string (tl::to_string (mp_ui->row_y_le->text ()), row_y);
tl::from_string (tl::to_string (mp_ui->columns_le->text ()), columns);
tl::from_string (tl::to_string (mp_ui->column_x_le->text ()), column_x);
tl::from_string (tl::to_string (mp_ui->column_y_le->text ()), column_y);
root->config_set (cfg_edit_inst_rows, tl::to_string (rows));
root->config_set (cfg_edit_inst_row_x, tl::to_string (row_x));
root->config_set (cfg_edit_inst_row_y, tl::to_string (row_y));
root->config_set (cfg_edit_inst_columns, tl::to_string (columns));
root->config_set (cfg_edit_inst_column_x, tl::to_string (column_x));
root->config_set (cfg_edit_inst_column_y, tl::to_string (column_y));
configure_from_line_edit<int> (root, mp_ui->rows_le, cfg_edit_inst_rows);
configure_from_line_edit<double> (root, mp_ui->row_x_le, cfg_edit_inst_row_x);
configure_from_line_edit<double> (root, mp_ui->row_y_le, cfg_edit_inst_row_y);
configure_from_line_edit<int> (root, mp_ui->columns_le, cfg_edit_inst_columns);
configure_from_line_edit<double> (root, mp_ui->column_x_le, cfg_edit_inst_column_x);
configure_from_line_edit<double> (root, mp_ui->column_y_le, cfg_edit_inst_column_y);
// place origin of cell flag
bool place_origin = mp_ui->place_origin_cb->isChecked ();
@ -695,45 +580,187 @@ EditorOptionsInst::apply (lay::Plugin *root)
}
void
EditorOptionsInst::setup (lay::Plugin *root)
EditorOptionsInst::setup (lay::Dispatcher *root)
{
m_cv_index = -1;
if (lay::LayoutView::current ()) {
m_cv_index = lay::LayoutView::current ()->active_cellview_index ();
}
mp_ui->lib_cbx->update_list ();
if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
mp_ui->lib_cbx->set_technology_filter (lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (), true);
} else {
mp_ui->lib_cbx->set_technology_filter (std::string (), false);
try {
mp_ui->lib_cbx->blockSignals (true);
mp_ui->lib_cbx->update_list ();
if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
mp_ui->lib_cbx->set_technology_filter (lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (), true);
} else {
mp_ui->lib_cbx->set_technology_filter (std::string (), false);
}
// cell name
std::string s;
root->config_get (cfg_edit_inst_cell_name, s);
mp_ui->cell_le->setText (tl::to_qstring (s));
// library
std::string l;
root->config_get (cfg_edit_inst_lib_name, l);
mp_ui->lib_cbx->set_current_library (db::LibraryManager::instance ().lib_ptr_by_name (l));
mp_ui->lib_cbx->blockSignals (false);
update_cell_edits ();
} catch (...) {
mp_ui->lib_cbx->blockSignals (false);
throw;
}
// rotation, scaling
double angle = 0.0;
root->config_get (cfg_edit_inst_angle, angle);
mp_ui->angle_le->setText (tl::to_qstring (tl::to_string (angle)));
lay::indicate_error (mp_ui->angle_le, 0);
bool mirror = false;
root->config_get (cfg_edit_inst_mirror, mirror);
mp_ui->mirror_cbx->setChecked (mirror);
double scale = 1.0;
root->config_get (cfg_edit_inst_scale, scale);
mp_ui->scale_le->setText (tl::to_qstring (tl::to_string (scale)));
lay::indicate_error (mp_ui->scale_le, 0);
// array
bool array = false;
root->config_get (cfg_edit_inst_array, array);
mp_ui->array_grp->setChecked (array);
int rows = 1, columns = 1;
double row_x = 0.0, row_y = 0.0, column_x = 0.0, column_y = 0.0;
root->config_get (cfg_edit_inst_rows, rows);
root->config_get (cfg_edit_inst_row_x, row_x);
root->config_get (cfg_edit_inst_row_y, row_y);
root->config_get (cfg_edit_inst_columns, columns);
root->config_get (cfg_edit_inst_column_x, column_x);
root->config_get (cfg_edit_inst_column_y, column_y);
mp_ui->rows_le->setText (tl::to_qstring (tl::to_string (rows)));
lay::indicate_error (mp_ui->rows_le, 0);
mp_ui->row_x_le->setText (tl::to_qstring (tl::to_string (row_x)));
lay::indicate_error (mp_ui->row_x_le, 0);
mp_ui->row_y_le->setText (tl::to_qstring (tl::to_string (row_y)));
lay::indicate_error (mp_ui->row_y_le, 0);
mp_ui->columns_le->setText (tl::to_qstring (tl::to_string (columns)));
lay::indicate_error (mp_ui->columns_le, 0);
mp_ui->column_x_le->setText (tl::to_qstring (tl::to_string (column_x)));
lay::indicate_error (mp_ui->column_x_le, 0);
mp_ui->column_y_le->setText (tl::to_qstring (tl::to_string (column_y)));
lay::indicate_error (mp_ui->column_y_le, 0);
// place origin of cell flag
bool place_origin = false;
root->config_get (cfg_edit_inst_place_origin, place_origin);
mp_ui->place_origin_cb->setChecked (place_origin);
}
// ------------------------------------------------------------------
// EditorOptionsInstPCellParam implementation
EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::Dispatcher *dispatcher)
: lay::EditorOptionsPage (dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0)
{
mp_ui = new Ui::EditorOptionsInstPCellParam ();
mp_ui->setupUi (this);
}
EditorOptionsInstPCellParam::~EditorOptionsInstPCellParam ()
{
delete mp_ui;
mp_ui = 0;
}
std::string
EditorOptionsInstPCellParam::title () const
{
return tl::to_string (QObject::tr ("PCell"));
}
void
EditorOptionsInstPCellParam::apply (lay::Dispatcher *root)
{
// pcell parameters
std::string param;
db::Layout *layout = 0;
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
if (lib) {
layout = &lib->layout ();
} else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout ();
}
bool ok = true;
if (layout && mp_pcell_parameters) {
std::pair<bool, db::pcell_id_type> pc = layout->pcell_by_name (tl::to_string (m_cell_name).c_str ());
if (pc.first) {
const db::PCellDeclaration *pc_decl = layout->pcell_declaration (pc.second);
if (pc_decl) {
param = pcell_parameters_to_string (pc_decl->named_parameters (mp_pcell_parameters->get_parameters (&ok)));
}
}
}
if (ok) {
root->config_set (cfg_edit_inst_pcell_parameters, param);
}
}
void
EditorOptionsInstPCellParam::setup (lay::Dispatcher *root)
{
m_cv_index = -1;
if (lay::LayoutView::current ()) {
m_cv_index = lay::LayoutView::current ()->active_cellview_index ();
}
bool needs_update = (mp_pcell_parameters == 0);
// cell name
std::string s;
root->config_get (cfg_edit_inst_cell_name, s);
mp_ui->cell_le->setText (tl::to_qstring (s));
std::string cn;
root->config_get (cfg_edit_inst_cell_name, cn);
if (cn != m_cell_name) {
m_cell_name = cn;
needs_update = true;
}
// library
std::string l;
root->config_get (cfg_edit_inst_lib_name, l);
mp_ui->lib_cbx->set_current_library (db::LibraryManager::instance ().lib_ptr_by_name (l));
std::string ln;
root->config_get (cfg_edit_inst_lib_name, ln);
if (ln != m_lib_name) {
m_lib_name = ln;
needs_update = true;
}
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
// pcell parameters
std::string param;
root->config_get (cfg_edit_inst_pcell_parameters, param);
db::Layout *layout = 0;
if (mp_ui->lib_cbx->current_library ()) {
layout = &mp_ui->lib_cbx->current_library ()->layout ();
if (lib) {
layout = &lib->layout ();
} else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout ();
}
std::vector<tl::Variant> pv;
if (layout && mp_pcell_parameters) {
if (layout) {
std::pair<bool, db::pcell_id_type> pc = layout->pcell_by_name (tl::to_string (mp_ui->cell_le->text ()).c_str ());
std::pair<bool, db::pcell_id_type> pc = layout->pcell_by_name (tl::to_string (m_cell_name).c_str ());
if (pc.first) {
@ -768,88 +795,49 @@ EditorOptionsInst::setup (lay::Plugin *root)
}
}
if (! needs_update) {
bool ok = false;
if (mp_pcell_parameters->get_parameters (&ok) != pv || ! ok) {
needs_update = true;
}
}
try {
update_pcell_parameters (pv);
if (needs_update) {
update_pcell_parameters (pv);
}
} catch (...) { }
// rotation, scaling
double angle = 0.0;
root->config_get (cfg_edit_inst_angle, angle);
mp_ui->angle_le->setText (tl::to_qstring (tl::to_string (angle)));
bool mirror = false;
root->config_get (cfg_edit_inst_mirror, mirror);
mp_ui->mirror_cbx->setChecked (mirror);
double scale = 1.0;
root->config_get (cfg_edit_inst_scale, scale);
mp_ui->scale_le->setText (tl::to_qstring (tl::to_string (scale)));
// array
bool array = false;
root->config_get (cfg_edit_inst_array, array);
mp_ui->array_grp->setChecked (array);
int rows = 1, columns = 1;
double row_x = 0.0, row_y = 0.0, column_x = 0.0, column_y = 0.0;
root->config_get (cfg_edit_inst_rows, rows);
root->config_get (cfg_edit_inst_row_x, row_x);
root->config_get (cfg_edit_inst_row_y, row_y);
root->config_get (cfg_edit_inst_columns, columns);
root->config_get (cfg_edit_inst_column_x, column_x);
root->config_get (cfg_edit_inst_column_y, column_y);
mp_ui->rows_le->setText (tl::to_qstring (tl::to_string (rows)));
mp_ui->row_x_le->setText (tl::to_qstring (tl::to_string (row_x)));
mp_ui->row_y_le->setText (tl::to_qstring (tl::to_string (row_y)));
mp_ui->columns_le->setText (tl::to_qstring (tl::to_string (columns)));
mp_ui->column_x_le->setText (tl::to_qstring (tl::to_string (column_x)));
mp_ui->column_y_le->setText (tl::to_qstring (tl::to_string (column_y)));
// place origin of cell flag
bool place_origin = false;
root->config_get (cfg_edit_inst_place_origin, place_origin);
mp_ui->place_origin_cb->setChecked (place_origin);
}
void
EditorOptionsInst::update_pcell_parameters ()
void
EditorOptionsInstPCellParam::update_pcell_parameters ()
{
update_pcell_parameters (std::vector <tl::Variant> ());
}
void
EditorOptionsInst::update_pcell_parameters (const std::vector <tl::Variant> &parameters)
void
EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Variant> &parameters)
{
db::Layout *layout = 0;
lay::LayoutView *view = lay::LayoutView::current ();
if (m_cv_index < 0 || !lay::LayoutView::current () || !lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) {
mp_ui->param_tab_widget->setTabEnabled (1, false);
return;
}
// find the layout the cell has to be looked up: that is either the layout of the current instance or
// find the layout the cell has to be looked up: that is either the layout of the current instance or
// the library selected
if (mp_ui->lib_cbx->current_library ()) {
layout = &mp_ui->lib_cbx->current_library ()->layout ();
} else {
layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout ();
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
if (lib) {
layout = &lib->layout ();
} else if (view) {
const lay::CellView &cv = view->cellview (m_cv_index);
if (cv.is_valid ()) {
layout = &cv->layout ();
}
}
std::pair<bool, db::pcell_id_type> pc = layout->pcell_by_name (tl::to_string (mp_ui->cell_le->text ()).c_str ());
std::pair<bool, db::cell_index_type> cc = layout->cell_by_name (tl::to_string (mp_ui->cell_le->text ()).c_str ());
// by the way, update the foreground color of the cell edit box as well (red, if not valid)
QPalette pl = mp_ui->cell_le->palette ();
if (! pc.first && ! cc.first) {
pl.setColor (QPalette::Text, Qt::red);
pl.setColor (QPalette::Base, QColor (Qt::red).lighter (180));
} else {
pl.setColor (QPalette::Text, palette ().color (QPalette::Text));
pl.setColor (QPalette::Base, palette ().color (QPalette::Base));
std::pair<bool, db::pcell_id_type> pc (false, 0);
if (layout) {
pc = layout->pcell_by_name (tl::to_string (m_cell_name).c_str ());
}
mp_ui->cell_le->setPalette (pl);
PCellParametersPage::State pcp_state;
@ -860,19 +848,30 @@ EditorOptionsInst::update_pcell_parameters (const std::vector <tl::Variant> &par
mp_pcell_parameters->deleteLater ();
}
if (mp_placeholder_label) {
mp_placeholder_label->hide ();
mp_placeholder_label->deleteLater ();
}
mp_pcell_parameters = 0;
mp_placeholder_label = 0;
if (pc.first && layout->pcell_declaration (pc.second)) {
if (pc.first && layout->pcell_declaration (pc.second) && view && view->cellview (m_cv_index).is_valid ()) {
mp_ui->param_tab_widget->setTabEnabled (1, true);
lay::LayoutView *view = lay::LayoutView::current ();
mp_pcell_parameters = new PCellParametersPage (mp_ui->pcell_tab, &view->cellview (m_cv_index)->layout (), view, m_cv_index, layout->pcell_declaration (pc.second), parameters);
mp_ui->pcell_tab->layout ()->addWidget (mp_pcell_parameters);
mp_pcell_parameters = new PCellParametersPage (this, true /*dense*/);
mp_pcell_parameters->setup (&view->cellview (m_cv_index)->layout (), view, m_cv_index, layout->pcell_declaration (pc.second), parameters);
this->layout ()->addWidget (mp_pcell_parameters);
mp_pcell_parameters->set_state (pcp_state);
connect (mp_pcell_parameters, SIGNAL (edited ()), this, SLOT (edited ()));
} else {
mp_ui->param_tab_widget->setTabEnabled (1, false);
mp_placeholder_label = new QLabel (this);
mp_placeholder_label->setText (tr ("Not a PCell"));
mp_placeholder_label->setAlignment (Qt::AlignHCenter | Qt::AlignVCenter);
this->layout ()->addWidget (mp_placeholder_label);
}
}

View File

@ -24,12 +24,17 @@
#ifndef HDR_edtEditorOptionsPages
#define HDR_edtEditorOptionsPages
#include "layEditorOptionsPage.h"
#include <tlVariant.h>
#include <QDialog>
#include <QFrame>
#include <vector>
#include <string>
class QTabWidget;
class QLabel;
namespace Ui
{
class EditorOptionsDialog;
@ -39,6 +44,7 @@ namespace Ui
class EditorOptionsPath;
class EditorOptionsText;
class EditorOptionsInst;
class EditorOptionsInstPCellParam;
}
namespace lay
@ -53,83 +59,22 @@ namespace edt
class PCellParametersPage;
class EditorOptionsPages;
/**
* @brief The base class for a object properties page
*/
class EditorOptionsPage
{
public:
EditorOptionsPage ();
virtual ~EditorOptionsPage ();
virtual QWidget *q_frame () = 0;
virtual std::string title () const = 0;
virtual int order () const = 0;
virtual void apply (lay::Plugin *root) = 0;
virtual void setup (lay::Plugin *root) = 0;
bool active () const { return m_active; }
void activate (bool active);
void set_owner (EditorOptionsPages *owner);
const lay::PluginDeclaration *plugin_declaration () const { return mp_plugin_declaration; }
void set_plugin_declaration (const lay::PluginDeclaration *pd) { mp_plugin_declaration = pd; }
private:
EditorOptionsPages *mp_owner;
bool m_active;
const lay::PluginDeclaration *mp_plugin_declaration;
};
/**
* @brief The object properties dialog
*/
class EditorOptionsPages
: public QDialog
{
Q_OBJECT
public:
EditorOptionsPages (const std::vector<edt::EditorOptionsPage *> &pages, lay::Dispatcher *root);
~EditorOptionsPages ();
void unregister_page (edt::EditorOptionsPage *page);
void activate_page (edt::EditorOptionsPage *page);
public slots:
void apply ();
void setup ();
void accept ();
private:
std::vector <edt::EditorOptionsPage *> m_pages;
Ui::EditorOptionsDialog *mp_ui;
lay::Dispatcher *mp_root;
void update (edt::EditorOptionsPage *page);
void do_apply ();
};
/**
* @brief The generic properties page
*/
class EditorOptionsGeneric
: public QWidget, public EditorOptionsPage
: public lay::EditorOptionsPage
{
Q_OBJECT
public:
EditorOptionsGeneric ();
EditorOptionsGeneric (lay::Dispatcher *dispatcher);
~EditorOptionsGeneric ();
virtual QWidget *q_frame () { return this; }
virtual std::string title () const;
virtual int order () const { return 0; }
void apply (lay::Plugin *root);
void setup (lay::Plugin *root);
void apply (lay::Dispatcher *root);
void setup (lay::Dispatcher *root);
public slots:
void grid_changed (int);
@ -143,18 +88,16 @@ private:
* @brief The text properties page
*/
class EditorOptionsText
: public QWidget, public EditorOptionsPage
: public lay::EditorOptionsPage
{
public:
EditorOptionsText ();
EditorOptionsText (lay::Dispatcher *dispatcher);
~EditorOptionsText ();
virtual QWidget *q_frame () { return this; }
virtual std::string title () const;
virtual int order () const { return 10; }
void apply (lay::Plugin *root);
void setup (lay::Plugin *root);
void apply (lay::Dispatcher *root);
void setup (lay::Dispatcher *root);
private:
Ui::EditorOptionsText *mp_ui;
@ -164,20 +107,18 @@ private:
* @brief The path properties page
*/
class EditorOptionsPath
: public QWidget, public EditorOptionsPage
: public lay::EditorOptionsPage
{
Q_OBJECT
public:
EditorOptionsPath ();
EditorOptionsPath (lay::Dispatcher *dispatcher);
~EditorOptionsPath ();
virtual QWidget *q_frame () { return this; }
virtual std::string title () const;
virtual int order () const { return 20; }
void apply (lay::Plugin *root);
void setup (lay::Plugin *root);
virtual int order () const { return 30; }
void apply (lay::Dispatcher *root);
void setup (lay::Dispatcher *root);
public slots:
void type_changed (int);
@ -190,7 +131,7 @@ private:
* @brief The instance properties page
*/
class EditorOptionsInst
: public QWidget, public EditorOptionsPage
: public lay::EditorOptionsPage
{
Q_OBJECT
@ -198,25 +139,49 @@ public:
EditorOptionsInst (lay::Dispatcher *root);
~EditorOptionsInst ();
virtual QWidget *q_frame () { return this; }
virtual std::string title () const;
virtual int order () const { return 20; }
void apply (lay::Plugin *root);
void setup (lay::Plugin *root);
void apply (lay::Dispatcher *root);
void setup (lay::Dispatcher *root);
public slots:
private slots:
void array_changed ();
void browse_cell ();
void update_pcell_parameters ();
void library_changed (int index);
void cell_name_changed (const QString &s);
void library_changed ();
void update_cell_edits ();
private:
Ui::EditorOptionsInst *mp_ui;
lay::Dispatcher *mp_root;
edt::PCellParametersPage *mp_pcell_parameters;
int m_cv_index;
};
/**
* @brief The instance properties page (PCell parameters)
*/
class EditorOptionsInstPCellParam
: public lay::EditorOptionsPage
{
Q_OBJECT
public:
EditorOptionsInstPCellParam (lay::Dispatcher *root);
~EditorOptionsInstPCellParam ();
virtual std::string title () const;
virtual int order () const { return 21; }
void apply (lay::Dispatcher *root);
void setup (lay::Dispatcher *root);
private slots:
void update_pcell_parameters ();
private:
Ui::EditorOptionsInstPCellParam *mp_ui;
edt::PCellParametersPage *mp_pcell_parameters;
QLabel *mp_placeholder_label;
int m_cv_index;
std::string m_lib_name, m_cell_name;
void update_pcell_parameters (const std::vector <tl::Variant> &parameters);
};

View File

@ -31,6 +31,7 @@
#include "layObjectInstPath.h"
#include "layLayoutView.h"
#include "layCellSelectionForm.h"
#include "layQtTools.h"
#include "tlExceptions.h"
#include "tlString.h"
@ -65,6 +66,43 @@ InstPropertiesPage::InstPropertiesPage (edt::Service *service, db::Manager *mana
connect (lib_cbx, SIGNAL (currentIndexChanged (int)), this, SLOT (library_changed (int)));
connect (cell_name_le, SIGNAL (textChanged (const QString &)), this, SLOT (cell_name_changed (const QString &)));
if (! readonly ()) {
connect (lib_cbx, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (cell_name_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (array_grp, SIGNAL (clicked ()), this, SIGNAL (edited ()));
connect (rows_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (columns_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (row_x_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (row_y_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (column_x_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (column_y_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (pos_x_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (pos_y_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (angle_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (mag_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (mirror_cbx, SIGNAL (clicked ()), this, SIGNAL (edited ()));
} else {
browse_pb->setEnabled (false);
cell_name_le->setReadOnly (true);
rows_le->setReadOnly (true);
columns_le->setReadOnly (true);
row_x_le->setReadOnly (true);
row_y_le->setReadOnly (true);
column_x_le->setReadOnly (true);
column_y_le->setReadOnly (true);
pos_x_le->setReadOnly (true);
pos_y_le->setReadOnly (true);
angle_le->setReadOnly (true);
mag_le->setReadOnly (true);
lib_cbx->setEnabled (false);
array_grp->setEnabled (false);
mirror_cbx->setEnabled (false);
}
QHBoxLayout *layout = new QHBoxLayout (pcell_tab);
layout->setMargin (0);
pcell_tab->setLayout (layout);
@ -125,12 +163,19 @@ BEGIN_PROTECTED
}
if (form.exec ()) {
cell_name_le->blockSignals (true);
if (form.selected_cell_is_pcell ()) {
cell_name_le->setText (tl::to_qstring (layout->pcell_header (form.selected_pcell_id ())->get_name ()));
} else if (layout->is_valid_cell_index (form.selected_cell_index ())) {
cell_name_le->setText (tl::to_qstring (layout->cell_name (form.selected_cell_index ())));
}
cell_name_le->blockSignals (false);
update_pcell_parameters ();
emit edited ();
}
END_PROTECTED
@ -140,7 +185,9 @@ void
InstPropertiesPage::show_props ()
{
lay::UserPropertiesForm props_form (this);
props_form.show (mp_service->view (), m_selection_ptrs [m_index]->cv_index (), m_prop_id);
if (props_form.show (mp_service->view (), m_selection_ptrs [m_index]->cv_index (), m_prop_id)) {
emit edited ();
}
}
void
@ -222,6 +269,7 @@ InstPropertiesPage::update ()
db::cell_index_type def_cell_index = pos->back ().inst_ptr.cell_index ();
const db::Cell &def_cell = def_layout->cell (def_cell_index);
lib_cbx->blockSignals (true);
std::pair<db::Library *, db::cell_index_type> dl = def_layout->defining_library (def_cell_index);
lib_cbx->set_technology_filter (cv->tech_name (), true);
lib_cbx->set_current_library (dl.first);
@ -229,13 +277,16 @@ InstPropertiesPage::update ()
def_layout = &dl.first->layout ();
def_cell_index = dl.second;
}
lib_cbx->blockSignals (false);
std::pair<bool, db::pcell_id_type> pci = def_layout->is_pcell_instance (def_cell_index);
cell_name_le->blockSignals (true);
if (pci.first && def_layout->pcell_declaration (pci.second)) {
cell_name_le->setText (tl::to_qstring (def_layout->pcell_header (pci.second)->get_name ()));
} else {
cell_name_le->setText (tl::to_qstring (def_layout->cell_name (def_cell_index)));
}
cell_name_le->blockSignals (false);
db::Vector rowv, columnv;
unsigned long rows, columns;
@ -325,6 +376,9 @@ InstPropertiesPage::readonly ()
ChangeApplicator *
InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & /*inst*/, double dbu)
{
bool has_error = false;
bool has_pcell_error = false;
std::auto_ptr<CombinedChangeApplicator> appl (new CombinedChangeApplicator ());
edt::Service::obj_iterator pos = m_selection_ptrs [m_index];
@ -343,34 +397,69 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
layout = &cv->layout ();
}
std::pair<bool, db::cell_index_type> ci = layout->cell_by_name (tl::to_string (cell_name_le->text ()).c_str ());
std::pair<bool, db::pcell_id_type> pci = layout->pcell_by_name (tl::to_string (cell_name_le->text ()).c_str ());
if (! ci.first && ! pci.first) {
throw tl::Exception (tl::to_string (QObject::tr ("Not a valid cell name: %s")).c_str (), tl::to_string (cell_name_le->text ()).c_str ());
try {
std::pair<bool, db::cell_index_type> ci = layout->cell_by_name (tl::to_string (cell_name_le->text ()).c_str ());
std::pair<bool, db::pcell_id_type> pci = layout->pcell_by_name (tl::to_string (cell_name_le->text ()).c_str ());
if (! ci.first && ! pci.first) {
throw tl::Exception (tl::to_string (QObject::tr ("Not a valid cell or PCell name: %s")).c_str (), tl::to_string (cell_name_le->text ()).c_str ());
}
lay::indicate_error (cell_name_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (cell_name_le, &ex);
has_error = true;
}
db::cell_index_type inst_cell_index = ci.second;
try {
// instantiate the PCell
if (pci.first) {
tl_assert (mp_pcell_parameters != 0);
tl_assert (layout->pcell_declaration (pci.second) == mp_pcell_parameters->pcell_decl ());
inst_cell_index = layout->get_pcell_variant (pci.second, mp_pcell_parameters->get_parameters ());
}
std::pair<bool, db::cell_index_type> ci = layout->cell_by_name (tl::to_string (cell_name_le->text ()).c_str ());
std::pair<bool, db::pcell_id_type> pci = layout->pcell_by_name (tl::to_string (cell_name_le->text ()).c_str ());
tl_assert (ci.first || pci.first);
// reference the library
if (lib) {
layout = & cv->layout ();
inst_cell_index = layout->get_lib_proxy (lib, inst_cell_index);
}
db::cell_index_type inst_cell_index = 0;
if (inst_cell_index != pos->back ().inst_ptr.cell_index ()) {
appl->add (new ChangeTargetCellApplicator (inst_cell_index));
// instantiate the PCell
if (pci.first) {
tl_assert (mp_pcell_parameters != 0);
tl_assert (layout->pcell_declaration (pci.second) == mp_pcell_parameters->pcell_decl ());
inst_cell_index = layout->get_pcell_variant (pci.second, mp_pcell_parameters->get_parameters ());
} else {
inst_cell_index = ci.second;
}
// reference the library
if (lib) {
layout = & cv->layout ();
inst_cell_index = layout->get_lib_proxy (lib, inst_cell_index);
}
if (inst_cell_index != pos->back ().inst_ptr.cell_index ()) {
appl->add (new ChangeTargetCellApplicator (inst_cell_index));
}
} catch (tl::Exception &ex) {
has_pcell_error = true;
}
double x = 0.0, y = 0.0;
tl::from_string (tl::to_string (pos_x_le->text ()), x);
tl::from_string (tl::to_string (pos_y_le->text ()), y);
try {
tl::from_string (tl::to_string (pos_x_le->text ()), x);
lay::indicate_error (pos_x_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (pos_x_le, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (pos_y_le->text ()), y);
lay::indicate_error (pos_y_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (pos_y_le, &ex);
has_error = true;
}
db::DCplxTrans t;
if (abs_cb->isChecked ()) {
@ -381,20 +470,32 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
bool mirror = mirror_cbx->isChecked ();
double angle = 0.0;
tl::from_string (tl::to_string (angle_le->text ()), angle);
try {
tl::from_string (tl::to_string (angle_le->text ()), angle);
lay::indicate_error (angle_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (angle_le, &ex);
has_error = true;
}
double mag = 0.0;
tl::from_string (tl::to_string (mag_le->text ()), mag);
try {
tl::from_string (tl::to_string (mag_le->text ()), mag);
lay::indicate_error (mag_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (mag_le, &ex);
has_error = true;
}
angle -= (floor (angle / 360.0) + 1.0) * 360.0;
while (angle < -1e-6) {
angle += 360.0;
}
db::CellInstArray::complex_trans_type tr = pos->back ().inst_ptr.complex_trans ();
db::CellInstArray::complex_trans_type trans = pos->back ().inst_ptr.complex_trans ();
if (fabs (angle - tr.angle ()) > 1e-6 || mirror != tr.is_mirror () || fabs (mag - tr.mag ()) > 1e-6 || ! disp.equal (tr.disp () * dbu)) {
appl->add (new ChangeInstanceTransApplicator (angle, tr.angle (), mirror, tr.is_mirror (), mag, tr.mag (), disp, tr.disp () * dbu));
if (fabs (angle - trans.angle ()) > 1e-6 || mirror != trans.is_mirror () || fabs (mag - trans.mag ()) > 1e-6 || ! disp.equal (trans.disp () * dbu)) {
appl->add (new ChangeInstanceTransApplicator (angle, trans.angle (), mirror, trans.is_mirror (), mag, trans.mag (), disp, trans.disp () * dbu));
}
db::CellInstArray::vector_type a_org, b_org;
@ -407,12 +508,53 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
double rx = 0.0, ry = 0.0;
unsigned long rows = 0, cols = 0;
tl::from_string (tl::to_string (column_x_le->text ()), cx);
tl::from_string (tl::to_string (column_y_le->text ()), cy);
tl::from_string (tl::to_string (row_x_le->text ()), rx);
tl::from_string (tl::to_string (row_y_le->text ()), ry);
tl::from_string (tl::to_string (rows_le->text ()), rows);
tl::from_string (tl::to_string (columns_le->text ()), cols);
try {
tl::from_string (tl::to_string (column_x_le->text ()), cx);
lay::indicate_error (column_x_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (column_x_le, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (column_y_le->text ()), cy);
lay::indicate_error (column_y_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (column_y_le, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (row_x_le->text ()), rx);
lay::indicate_error (row_x_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (row_x_le, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (row_y_le->text ()), ry);
lay::indicate_error (row_y_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (row_y_le, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (rows_le->text ()), rows);
lay::indicate_error (rows_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (rows_le, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (columns_le->text ()), cols);
lay::indicate_error (columns_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (columns_le, &ex);
has_error = true;
}
db::DVector rv = db::DVector (dpoint_from_dpoint (db::DPoint (rx, ry), dbu, du, t));
db::DVector cv = db::DVector (dpoint_from_dpoint (db::DPoint (cx, cy), dbu, du, t));
@ -432,6 +574,14 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
}
if (has_error || has_pcell_error) {
throw tl::Exception (tl::to_string (tr ("At least one value and PCell parameter is not correct - see hightlighted entry fields or the PCell error indicator")));
} else if (has_error) {
throw tl::Exception (tl::to_string (tr ("At least one value is not correct - see hightlighted entry fields")));
} else if (has_pcell_error) {
throw tl::Exception (tl::to_string (tr ("At least one PCell parameter is not correct - see hightlighted entry fields or the PCell error indicator")));
}
return appl.release ();
}
@ -453,7 +603,7 @@ InstPropertiesPage::recompute_selection_ptrs (const std::vector<lay::ObjectInstP
}
void
InstPropertiesPage::do_apply (bool current_only)
InstPropertiesPage::do_apply (bool current_only, bool relative)
{
lay::LayerState layer_state = mp_service->view ()->layer_snapshot ();
unsigned int cv_index = m_selection_ptrs [m_index]->cv_index ();
@ -482,32 +632,7 @@ InstPropertiesPage::do_apply (bool current_only)
bool relative_mode = false;
if (! current_only && applicator->supports_relative_mode ()) {
static bool s_relative_mode = true;
QMessageBox mb (QMessageBox::Question,
tr ("Apply Changes To All"),
tr ("For this operation absolute or relative mode is available which affects the way parameters of the selected objects are changed:\n\n"
"In absolute mode, they will be set to the given value. In relative mode, they will be adjusted by the same amount.\n"),
QMessageBox::NoButton, this);
mb.addButton (tr ("Cancel"), QMessageBox::RejectRole);
QPushButton *absolute = mb.addButton (tr ("Absolute"), QMessageBox::NoRole);
QPushButton *relative = mb.addButton (tr ("Relative"), QMessageBox::YesRole);
mb.setDefaultButton (s_relative_mode ? relative : absolute);
mb.exec ();
if (mb.clickedButton () == absolute) {
s_relative_mode = relative_mode = false;
} else if (mb.clickedButton () == relative) {
s_relative_mode = relative_mode = true;
} else {
// Cancel pressed
return;
}
relative_mode = relative;
}
// Note: using the apply-all scheme for applying a single change may look like overhead.
@ -599,7 +724,7 @@ InstPropertiesPage::do_apply (bool current_only)
void
InstPropertiesPage::apply ()
{
do_apply (true);
do_apply (true, false);
}
bool
@ -609,9 +734,9 @@ InstPropertiesPage::can_apply_to_all () const
}
void
InstPropertiesPage::apply_to_all ()
InstPropertiesPage::apply_to_all (bool relative)
{
do_apply (false);
do_apply (false, relative);
}
void
@ -636,16 +761,13 @@ InstPropertiesPage::update_pcell_parameters ()
std::pair<bool, db::pcell_id_type> pc = layout->pcell_by_name (tl::to_string (cell_name_le->text ()).c_str ());
std::pair<bool, db::cell_index_type> cc = layout->cell_by_name (tl::to_string (cell_name_le->text ()).c_str ());
// by the way, update the foreground color of the cell edit box as well (red, if not valid)
QPalette pl = cell_name_le->palette ();
// indicate an invalid cell name
if (! pc.first && ! cc.first) {
pl.setColor (QPalette::Text, Qt::red);
pl.setColor (QPalette::Base, QColor (Qt::red).lighter (180));
tl::Exception ex (tl::to_string (QObject::tr ("Not a valid cell or PCell name: %s")).c_str (), tl::to_string (cell_name_le->text ()).c_str ());
lay::indicate_error (cell_name_le, &ex);
} else {
pl.setColor (QPalette::Text, palette ().color (QPalette::Text));
pl.setColor (QPalette::Base, palette ().color (QPalette::Base));
lay::indicate_error (cell_name_le, 0);
}
cell_name_le->setPalette (pl);
if (pc.first && layout->pcell_declaration (pc.second)) {
@ -686,13 +808,14 @@ InstPropertiesPage::update_pcell_parameters ()
mp_pcell_parameters->deleteLater ();
}
mp_pcell_parameters = new PCellParametersPage (pcell_tab, &cv->layout (), mp_service->view (), pos->cv_index (), layout->pcell_declaration (pc.second), parameters);
mp_pcell_parameters = new PCellParametersPage (pcell_tab);
connect (mp_pcell_parameters, SIGNAL (edited ()), this, SIGNAL (edited ()));
mp_pcell_parameters->setup (&cv->layout (), mp_service->view (), pos->cv_index (), layout->pcell_declaration (pc.second), parameters);
pcell_tab->layout ()->addWidget (mp_pcell_parameters);
}
param_tab_widget->setTabEnabled (1, true);
param_tab_widget->setCurrentIndex (1);
} else {
@ -704,8 +827,11 @@ InstPropertiesPage::update_pcell_parameters ()
mp_pcell_parameters = 0;
param_tab_widget->setCurrentIndex (0);
if (param_tab_widget->currentIndex () == 1) {
param_tab_widget->setCurrentIndex (0);
}
param_tab_widget->setTabEnabled (1, false);
}
}

View File

@ -68,9 +68,9 @@ protected:
virtual bool readonly ();
virtual void apply ();
virtual void apply_to_all ();
virtual void apply_to_all (bool relative);
virtual bool can_apply_to_all () const;
void do_apply (bool current_only);
void do_apply (bool current_only, bool relative);
virtual ChangeApplicator *create_applicator (db::Cell &cell, const db::Instance &inst, double dbu);
protected slots:

View File

@ -30,7 +30,11 @@
#include "tlExceptions.h"
#include "layLayoutView.h"
#include "layDialogs.h"
#include "laySelector.h"
#include "layCellSelectionForm.h"
#include "layFinder.h"
#include "layLayerProperties.h"
#include "layLayerTreeModel.h"
#include "tlProgress.h"
#include "edtPlugin.h"
#include "edtMainService.h"
@ -39,8 +43,11 @@
#include "edtConfig.h"
#include "edtDialogs.h"
#include "edtEditorOptionsPages.h"
#include "edtDistribute.h"
#include <QMessageBox>
#include <QFontInfo>
#include <QWidgetAction>
namespace edt
{
@ -58,12 +65,18 @@ MainService::MainService (db::Manager *manager, lay::LayoutView *view, lay::Disp
m_flatten_insts_levels (std::numeric_limits<int>::max ()),
m_flatten_prune (false),
m_align_hmode (0), m_align_vmode (0), m_align_visible_layers (false),
m_hdistribute (true),
m_distribute_hmode (1), m_distribute_hpitch (0.0), m_distribute_hspace (0.0),
m_vdistribute (true),
m_distribute_vmode (1), m_distribute_vpitch (0.0), m_distribute_vspace (0.0),
m_distribute_visible_layers (false),
m_origin_mode_x (-1), m_origin_mode_y (-1), m_origin_visible_layers_for_bbox (false),
m_array_a (0.0, 1.0), m_array_b (1.0, 0.0),
m_array_na (1), m_array_nb (1),
m_router (0.0), m_rinner (0.0), m_npoints (64), m_undo_before_apply (true),
mp_round_corners_dialog (0),
mp_align_options_dialog (0),
mp_distribute_options_dialog (0),
mp_flatten_inst_options_dialog (0),
mp_make_cell_options_dialog (0),
mp_make_array_options_dialog (0)
@ -94,6 +107,15 @@ MainService::align_options_dialog ()
return mp_align_options_dialog;
}
edt::DistributeOptionsDialog *
MainService::distribute_options_dialog ()
{
if (! mp_distribute_options_dialog) {
mp_distribute_options_dialog = new edt::DistributeOptionsDialog (view ());
}
return mp_distribute_options_dialog;
}
lay::FlattenInstOptionsDialog *
MainService::flatten_inst_options_dialog ()
{
@ -128,10 +150,10 @@ MainService::menu_activated (const std::string &symbol)
cm_descend ();
} else if (symbol == "edt::ascend") {
cm_ascend ();
} else if (symbol == "edt::edit_options") {
cm_edit_options ();
} else if (symbol == "edt::sel_align") {
cm_align ();
} else if (symbol == "edt::sel_distribute") {
cm_distribute ();
} else if (symbol == "edt::sel_tap") {
cm_tap ();
} else if (symbol == "edt::sel_round_corners") {
@ -1835,7 +1857,115 @@ MainService::cm_align ()
}
}
void
void
MainService::cm_distribute ()
{
tl_assert (view ()->is_editable ());
check_no_guiding_shapes ();
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
if (! distribute_options_dialog ()->exec_dialog (view (), m_hdistribute, m_distribute_hmode, m_distribute_hpitch, m_distribute_hspace,
m_vdistribute, m_distribute_vmode, m_distribute_vpitch, m_distribute_vspace,
m_distribute_visible_layers)) {
return;
}
if (! m_hdistribute && ! m_vdistribute) {
return;
}
// count the items
size_t n = 0;
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) {
++n;
}
}
std::vector<std::pair<size_t, size_t> > objects_for_service;
std::vector<db::DCplxTrans> transformations;
{
std::vector<db::DBox> org_boxes;
org_boxes.reserve (n);
edt::distributed_placer<db::DBox, size_t> placer;
placer.reserve (n);
size_t i = 0;
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
objects_for_service.push_back (std::make_pair (i, i));
for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) {
const db::Layout &layout = view ()->cellview (s->cv_index ())->layout ();
db::CplxTrans tr = db::CplxTrans (layout.dbu ()) * s->trans ();
db::DBox box;
if (! s->is_cell_inst ()) {
box = tr * s->shape ().bbox ();
} else {
box = inst_bbox (tr, view (), s->cv_index (), s->back (), m_distribute_visible_layers);
}
org_boxes.push_back (box);
placer.insert (box, i);
++i;
}
objects_for_service.back ().second = i;
}
int href = int (m_distribute_hmode - 2);
int vref = 2 - int (m_distribute_vmode);
if (m_hdistribute && m_vdistribute) {
placer.distribute_matrix (href, m_distribute_hpitch, m_distribute_hspace,
vref, m_distribute_vpitch, m_distribute_vspace);
} else if (m_hdistribute) {
placer.distribute_h (href, vref, m_distribute_hpitch, m_distribute_hspace);
} else if (m_vdistribute) {
placer.distribute_v (vref, href, m_distribute_vpitch, m_distribute_vspace);
}
transformations.resize (org_boxes.size ());
for (edt::distributed_placer<db::DBox, size_t>::iterator i = placer.begin (); i != placer.end (); ++i) {
transformations[i->second] = db::DCplxTrans (i->first.p1 () - org_boxes[i->second].p1 ());
}
}
{
view ()->cancel_edits ();
manager ()->transaction (tl::to_string (QObject::tr ("Distribution")));
// do the distribution
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
size_t ie = es - edt_services.begin ();
// create a transformation vector that describes each shape's transformation
std::vector <db::DCplxTrans> tv (transformations.begin () + objects_for_service [ie].first, transformations.begin () + objects_for_service [ie].second);
// use the "transform" method to transform the shapes and instances (with individual transformations)
(*es)->transform (db::DCplxTrans () /*dummy*/, &tv);
}
manager ()->commit ();
}
}
void
MainService::cm_make_array ()
{
size_t n = 0;
@ -1941,21 +2071,67 @@ MainService::cm_make_array ()
void
MainService::cm_tap ()
{
tl_assert (view ()->is_editable ());
check_no_guiding_shapes ();
if (! view ()->view_object_widget ()->mouse_in_window ()) {
return;
}
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
lay::ShapeFinder finder (true /*point mode*/, false /*all hierarchy levels*/, db::ShapeIterator::All, 0);
// get (common) cellview index of the selected shapes
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) {
const lay::CellView &cv = view ()->cellview (s->cv_index ());
if (cv.is_valid () && ! s->is_cell_inst ()) {
view ()->set_current_layer (s->cv_index (), cv->layout ().get_properties (s->layer ()));
return;
}
// capture all objects in point mode (default: capture one only)
finder.set_catch_all (true);
// go through all visible layers of all cellviews
db::DPoint pt = view ()->view_object_widget ()->mouse_position_um ();
finder.find (view (), db::DBox (pt, pt));
std::set<std::pair<unsigned int, unsigned int> > layers_in_selection;
for (lay::ShapeFinder::iterator f = finder.begin (); f != finder.end (); ++f) {
// ignore guiding shapes
if (f->layer () != view ()->cellview (f->cv_index ())->layout ().guiding_shape_layer ()) {
layers_in_selection.insert (std::make_pair (f->cv_index (), f->layer ()));
}
}
std::vector<lay::LayerPropertiesConstIterator> tapped_layers;
for (lay::LayerPropertiesConstIterator lp = view ()->begin_layers (view ()->current_layer_list ()); ! lp.at_end (); ++lp) {
const lay::LayerPropertiesNode *ln = lp.operator-> ();
if (layers_in_selection.find (std::make_pair ((unsigned int) ln->cellview_index (), (unsigned int) ln->layer_index ())) != layers_in_selection.end ()) {
tapped_layers.push_back (lp);
}
}
if (tapped_layers.empty ()) {
return;
}
// List the layers under the cursor as pop up a menu
std::auto_ptr<QMenu> menu (new QMenu (view ()));
menu->show ();
int icon_size = menu->style ()->pixelMetric (QStyle::PM_ButtonIconSize);
QPoint mp = view ()->view_object_widget ()->mapToGlobal (view ()->view_object_widget ()->mouse_position ());
for (std::vector<lay::LayerPropertiesConstIterator>::const_iterator l = tapped_layers.begin (); l != tapped_layers.end (); ++l) {
QAction *a = menu->addAction (lay::LayerTreeModel::icon_for_layer (*l, view (), icon_size, icon_size, 0, true), tl::to_qstring ((*l)->source (true).to_string ()));
a->setData (int (l - tapped_layers.begin ()));
}
QAction *action = menu->exec (mp);
if (action) {
int index = action->data ().toInt ();
lay::LayerPropertiesConstIterator iter = tapped_layers [index];
view ()->set_current_layer (iter);
edt::Service *es = dynamic_cast<edt::Service *> (view ()->view_object_widget ()->active_service ());
if (es) {
es->tap (pt);
}
}
}
void
@ -1966,16 +2142,12 @@ MainService::cm_change_layer ()
int cv_index = -1;
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
// get (common) cellview index of the selected shapes
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 (cv_index >= 0 && cv_index != int (s->cv_index ())) {
throw tl::Exception (tl::to_string (QObject::tr ("Selections originate from different layouts - cannot switch layer in this case.")));
}
cv_index = int (s->cv_index ());
for (SelectionIterator s (view ()); ! s.at_end (); ++s) {
if (cv_index >= 0 && cv_index != int (s->cv_index ())) {
throw tl::Exception (tl::to_string (QObject::tr ("Selections originate from different layouts - cannot switch layer in this case.")));
}
cv_index = int (s->cv_index ());
}
if (cv_index >= 0) {
@ -2037,46 +2209,42 @@ MainService::cm_change_layer ()
// Insert and delete the shape. This exploits the fact, that a shape can be erased multiple times -
// this is important since the selection potentially contains the same shape multiple times.
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
for (SelectionIterator s (view ()); ! s.at_end (); ++s) {
for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) {
if (!s->is_cell_inst () && int (s->layer ()) != layer) {
if (!s->is_cell_inst () && int (s->layer ()) != layer) {
db::Cell &cell = layout.cell (s->cell_index ());
if (cell.shapes (s->layer ()).is_valid (s->shape ())) {
cell.shapes (layer).insert (s->shape ());
cell.shapes (s->layer ()).erase_shape (s->shape ());
}
db::Cell &cell = layout.cell (s->cell_index ());
if (cell.shapes (s->layer ()).is_valid (s->shape ())) {
cell.shapes (layer).insert (s->shape ());
cell.shapes (s->layer ()).erase_shape (s->shape ());
}
} else if (s->is_cell_inst ()) {
} else if (s->is_cell_inst ()) {
// If the selected object is a PCell instance, and there is exactly one visible, writable layer type parameter, change this one
// If the selected object is a PCell instance, and there is exactly one visible, writable layer type parameter, change this one
db::Instance inst = s->back ().inst_ptr;
db::Cell &cell = layout.cell (s->cell_index ());
db::Instance inst = s->back ().inst_ptr;
db::Cell &cell = layout.cell (s->cell_index ());
if (cell.is_valid (inst)) {
if (cell.is_valid (inst)) {
const db::PCellDeclaration *pcell_decl = layout.pcell_declaration_for_pcell_variant (inst.cell_index ());
if (pcell_decl) {
const db::PCellDeclaration *pcell_decl = layout.pcell_declaration_for_pcell_variant (inst.cell_index ());
if (pcell_decl) {
size_t layer_par_index = 0;
int n_layer_par = 0;
for (std::vector<db::PCellParameterDeclaration>::const_iterator d = pcell_decl->parameter_declarations ().begin (); d != pcell_decl->parameter_declarations ().end () && n_layer_par < 2; ++d) {
if (d->get_type () == db::PCellParameterDeclaration::t_layer && !d->is_hidden () && !d->is_readonly ()) {
++n_layer_par;
layer_par_index = size_t (d - pcell_decl->parameter_declarations ().begin ());
}
}
if (n_layer_par == 1) {
std::vector<tl::Variant> parameters = cell.get_pcell_parameters (inst);
tl_assert (layer_par_index < parameters.size ());
parameters [layer_par_index] = layout.get_properties (layer);
cell.change_pcell_parameters (inst, parameters);
size_t layer_par_index = 0;
int n_layer_par = 0;
for (std::vector<db::PCellParameterDeclaration>::const_iterator d = pcell_decl->parameter_declarations ().begin (); d != pcell_decl->parameter_declarations ().end () && n_layer_par < 2; ++d) {
if (d->get_type () == db::PCellParameterDeclaration::t_layer && !d->is_hidden () && !d->is_readonly ()) {
++n_layer_par;
layer_par_index = size_t (d - pcell_decl->parameter_declarations ().begin ());
}
}
if (n_layer_par == 1) {
std::vector<tl::Variant> parameters = cell.get_pcell_parameters (inst);
tl_assert (layer_par_index < parameters.size ());
parameters [layer_par_index] = layout.get_properties (layer);
cell.change_pcell_parameters (inst, parameters);
}
}
@ -2101,12 +2269,6 @@ MainService::cm_change_layer ()
}
void
MainService::cm_edit_options ()
{
show_editor_options_dialog ();
}
void
MainService::check_no_guiding_shapes ()
{

View File

@ -51,6 +51,7 @@ class RoundCornerOptionsDialog;
class MakeCellOptionsDialog;
class MakeArrayOptionsDialog;
class AlignOptionsDialog;
class DistributeOptionsDialog;
// -------------------------------------------------------------
@ -93,11 +94,6 @@ public:
*/
void cm_ascend ();
/**
* @brief Edit object options
*/
void cm_edit_options ();
/**
* @brief Change the layer of the shapes in the selection
*/
@ -153,6 +149,11 @@ public:
*/
void cm_align ();
/**
* @brief Distribute the selected shapes and instances
*/
void cm_distribute ();
/**
* @brief Flatten instances
*/
@ -205,6 +206,13 @@ private:
int m_align_hmode;
int m_align_vmode;
bool m_align_visible_layers;
bool m_hdistribute;
int m_distribute_hmode;
double m_distribute_hpitch, m_distribute_hspace;
bool m_vdistribute;
int m_distribute_vmode;
double m_distribute_vpitch, m_distribute_vspace;
bool m_distribute_visible_layers;
std::string m_make_cell_name;
int m_origin_mode_x, m_origin_mode_y;
bool m_origin_visible_layers_for_bbox;
@ -215,6 +223,7 @@ private:
bool m_undo_before_apply;
edt::RoundCornerOptionsDialog *mp_round_corners_dialog;
edt::AlignOptionsDialog *mp_align_options_dialog;
edt::DistributeOptionsDialog *mp_distribute_options_dialog;
lay::FlattenInstOptionsDialog *mp_flatten_inst_options_dialog;
edt::MakeCellOptionsDialog *mp_make_cell_options_dialog;
edt::MakeArrayOptionsDialog *mp_make_array_options_dialog;
@ -223,6 +232,7 @@ private:
void check_no_guiding_shapes ();
edt::RoundCornerOptionsDialog *round_corners_dialog ();
edt::AlignOptionsDialog *align_options_dialog ();
edt::DistributeOptionsDialog *distribute_options_dialog ();
lay::FlattenInstOptionsDialog *flatten_inst_options_dialog ();
edt::MakeCellOptionsDialog *make_cell_options_dialog ();
edt::MakeArrayOptionsDialog *make_array_options_dialog ();

View File

@ -1,65 +0,0 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "edtPCellParametersDialog.h"
#include <QPushButton>
namespace edt
{
PCellParametersDialog::PCellParametersDialog (QWidget *parent)
: QDialog (parent)
{
setupUi (this);
connect (buttons->button (QDialogButtonBox::Apply), SIGNAL (clicked ()), this, SLOT (apply_pressed ()));
}
void
PCellParametersDialog::apply_pressed ()
{
emit parameters_changed ();
parameters_changed_event ();
}
std::vector<tl::Variant>
PCellParametersDialog::get_parameters ()
{
return parameters->get_parameters ();
}
void
PCellParametersDialog::set_parameters (const std::vector<tl::Variant> &p)
{
parameters->set_parameters (p);
}
int
PCellParametersDialog::exec (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &p)
{
parameters->setup (layout, view, cv_index, pcell_decl, p);
return QDialog::exec ();
}
}

View File

@ -1,86 +0,0 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_edtPCellParametersDialog
#define HDR_edtPCellParametersDialog
#include "dbPCellDeclaration.h"
#include "ui_PCellParametersDialog.h"
#include <QDialog>
namespace lay
{
class LayoutView;
}
namespace edt
{
/**
* @brief A QScrollArea that displays and allows editing PCell parameters
*/
class PCellParametersDialog
: public QDialog, private Ui::PCellParametersDialog
{
Q_OBJECT
public:
/**
* @brief Constructor: create a dialog showing the given parameters
* @param parent The parent widget
*/
PCellParametersDialog (QWidget *parent);
/**
* @brief Executes the parameter dialog
* @param layout The layout in which the PCell instance resides
* @param view The layout view from which to take layers for example
* @param cv_index The index of the cellview in "view"
* @param pcell_decl The PCell declaration
* @param parameters The parameter values to show (if empty, the default values are used)
*/
int exec (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &p);
/**
* @brief Get the current parameters
*/
std::vector<tl::Variant> get_parameters ();
/**
* @brief Sets the given parameters as values
*/
void set_parameters (const std::vector<tl::Variant> &values);
tl::Event parameters_changed_event;
signals:
void parameters_changed ();
private slots:
void apply_pressed ();
};
}
#endif

View File

@ -22,7 +22,9 @@
#include "edtPCellParametersPage.h"
#include "edtPropertiesPageUtils.h"
#include "layWidgets.h"
#include "layQtTools.h"
#include "tlScriptError.h"
#include <QFrame>
@ -142,15 +144,8 @@ static void set_value (const db::PCellParameterDeclaration &p, const db::Layout
}
}
PCellParametersPage::PCellParametersPage (QWidget *parent, const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &parameters)
: QFrame (parent)
{
init ();
setup (layout, view, cv_index, pcell_decl, parameters);
}
PCellParametersPage::PCellParametersPage (QWidget *parent)
: QFrame (parent)
PCellParametersPage::PCellParametersPage (QWidget *parent, bool dense)
: QFrame (parent), m_dense (dense), dm_parameter_changed (this, &PCellParametersPage::do_parameter_changed)
{
init ();
}
@ -165,6 +160,8 @@ PCellParametersPage::init ()
mp_parameters_area = 0;
QGridLayout *frame_layout = new QGridLayout (this);
// spacing and margin for tool windows
frame_layout->setMargin (0);
setLayout (frame_layout);
mp_error_icon = new QLabel (this);
@ -173,6 +170,7 @@ PCellParametersPage::init ()
frame_layout->addWidget (mp_error_icon, 1, 0, 1, 1);
mp_error_label = new QLabel (this);
mp_error_label->setWordWrap (true);
QPalette palette = mp_error_label->palette ();
palette.setColor (QPalette::Foreground, Qt::red);
mp_error_label->setPalette (palette);
@ -200,6 +198,7 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int
m_widgets.clear ();
mp_parameters_area = new QScrollArea (this);
mp_parameters_area->setFrameShape (QFrame::NoFrame);
QGridLayout *frame_layout = dynamic_cast<QGridLayout *> (QFrame::layout ());
frame_layout->addWidget (mp_parameters_area, 0, 0, 1, 2);
frame_layout->setRowStretch (0, 1);
@ -211,6 +210,11 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int
QGridLayout *inner_grid = new QGridLayout (inner_frame);
inner_frame->setLayout (inner_grid);
if (m_dense) {
inner_grid->setMargin (4);
inner_grid->setHorizontalSpacing (6);
inner_grid->setVerticalSpacing (2);
}
QWidget *main_frame = inner_frame;
QGridLayout *main_grid = inner_grid;
@ -247,6 +251,11 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int
main_grid->addWidget (gb, main_row, 0, 1, 2);
inner_grid = new QGridLayout (gb);
if (m_dense) {
inner_grid->setMargin (4);
inner_grid->setHorizontalSpacing (6);
inner_grid->setVerticalSpacing (2);
}
gb->setLayout (inner_grid);
inner_frame = gb;
@ -286,11 +295,13 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int
QHBoxLayout *hb = new QHBoxLayout (f);
hb->setMargin (0);
f->setLayout (hb);
f->setFrameShape (QFrame::NoFrame);
QLineEdit *le = new QLineEdit (f);
le->setEnabled (! p->is_readonly ());
hb->addWidget (le);
le->setMaximumWidth (150);
le->setObjectName (tl::to_qstring (p->get_name ()));
m_widgets.push_back (le);
QLabel *ul = new QLabel (f);
@ -299,7 +310,7 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int
inner_grid->addWidget (f, row, 1);
connect (le, SIGNAL (editingFinished ()), this, SLOT (activated ()));
connect (le, SIGNAL (editingFinished ()), this, SLOT (parameter_changed ()));
}
break;
@ -309,10 +320,11 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int
{
QLineEdit *le = new QLineEdit (inner_frame);
le->setEnabled (! p->is_readonly ());
le->setObjectName (tl::to_qstring (p->get_name ()));
m_widgets.push_back (le);
inner_grid->addWidget (le, row, 1);
connect (le, SIGNAL (editingFinished ()), this, SLOT (activated ()));
connect (le, SIGNAL (editingFinished ()), this, SLOT (parameter_changed ()));
}
break;
@ -322,19 +334,25 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int
ly->setEnabled (! p->is_readonly ());
ly->set_no_layer_available (true);
ly->set_view (mp_view, m_cv_index, true /*all layers*/);
ly->setObjectName (tl::to_qstring (p->get_name ()));
m_widgets.push_back (ly);
inner_grid->addWidget (ly, row, 1);
connect (ly, SIGNAL (activated (int)), this, SLOT (parameter_changed ()));
}
break;
case db::PCellParameterDeclaration::t_boolean:
{
QCheckBox *cbx = new QCheckBox (inner_frame);
// this makes the checkbox not stretch over the full width - better when navigating with tab
cbx->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred));
cbx->setEnabled (! p->is_readonly ());
cbx->setObjectName (tl::to_qstring (p->get_name ()));
m_widgets.push_back (cbx);
inner_grid->addWidget (cbx, row, 1);
connect (cbx, SIGNAL (stateChanged (int)), this, SLOT (activated ()));
connect (cbx, SIGNAL (stateChanged (int)), this, SLOT (parameter_changed ()));
}
break;
@ -346,6 +364,7 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int
} else {
QComboBox *cb = new QComboBox (inner_frame);
cb->setObjectName (tl::to_qstring (p->get_name ()));
int i = 0;
for (std::vector<tl::Variant>::const_iterator c = p->get_choices ().begin (); c != p->get_choices ().end (); ++c, ++i) {
@ -356,7 +375,8 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int
}
}
connect (cb, SIGNAL (activated (int)), this, SLOT (activated ()));
connect (cb, SIGNAL (activated (int)), this, SLOT (parameter_changed ()));
cb->setEnabled (! p->is_readonly ());
cb->setMinimumContentsLength (30);
cb->setSizeAdjustPolicy (QComboBox::AdjustToMinimumContentsLengthWithIcon);
@ -377,17 +397,24 @@ PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int
mp_parameters_area->setWidget (main_frame);
main_frame->show ();
// does a first coerce and update
get_parameters ();
// does a first coerce and update. Ignore errors for now.
bool ok = false;
get_parameters (&ok);
}
PCellParametersPage::State
PCellParametersPage::get_state ()
{
State s;
s.valid = true;
s.vScrollPosition = mp_parameters_area->verticalScrollBar ()->value ();
s.hScrollPosition = mp_parameters_area->horizontalScrollBar ()->value ();
if (focusWidget ()) {
s.focusWidget = focusWidget ()->objectName ();
}
return s;
}
@ -395,29 +422,42 @@ void
PCellParametersPage::set_state (const State &s)
{
if (s.valid) {
mp_parameters_area->verticalScrollBar ()->setValue (s.vScrollPosition);
mp_parameters_area->horizontalScrollBar ()->setValue (s.hScrollPosition);
if (! s.focusWidget.isEmpty ()) {
QWidget *c = findChild<QWidget *> (s.focusWidget);
if (c) {
c->setFocus ();
}
}
}
}
void
PCellParametersPage::activated ()
PCellParametersPage::parameter_changed ()
{
// does a coerce and update
get_parameters ();
dm_parameter_changed ();
}
void
PCellParametersPage::clicked ()
void
PCellParametersPage::do_parameter_changed ()
{
// does a coerce and update
get_parameters ();
bool ok = false;
get_parameters (&ok);
if (ok) {
emit edited ();
}
}
std::vector<tl::Variant>
PCellParametersPage::get_parameters ()
PCellParametersPage::get_parameters (bool *ok)
{
std::vector<tl::Variant> parameters;
bool edit_error = true;
int r = 0;
const std::vector<db::PCellParameterDeclaration> &pcp = mp_pcell_decl->parameter_declarations ();
@ -443,9 +483,22 @@ PCellParametersPage::get_parameters ()
{
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
if (le) {
int v = 0;
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
try {
int v = 0;
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
lay::indicate_error (le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
edit_error = false;
}
}
}
break;
@ -454,9 +507,22 @@ PCellParametersPage::get_parameters ()
{
QLineEdit *le = dynamic_cast<QLineEdit *> (m_widgets [r]);
if (le) {
double v = 0;
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
try {
double v = 0;
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
lay::indicate_error (le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
edit_error = false;
}
}
}
break;
@ -516,22 +582,43 @@ PCellParametersPage::get_parameters ()
try {
if (! edit_error) {
throw tl::Exception (tl::to_string (tr ("There are errors. See the highlighted edit fields for details.")));
}
// coerce the parameters
mp_pcell_decl->coerce_parameters (*mp_layout, parameters);
set_parameters (parameters);
mp_error_label->hide ();
mp_error_icon->hide ();
if (ok) {
*ok = true;
}
} catch (tl::ScriptError &ex) {
mp_error_label->setText (tl::to_qstring (ex.basic_msg ()));
mp_error_label->setToolTip (tl::to_qstring (ex.msg ()));
mp_error_icon->show ();
mp_error_label->show ();
if (ok) {
mp_error_label->setText (tl::to_qstring (ex.basic_msg ()));
mp_error_label->setToolTip (tl::to_qstring (ex.msg ()));
mp_error_icon->show ();
mp_error_label->show ();
*ok = false;
} else {
throw;
}
} catch (tl::Exception &ex) {
mp_error_label->setText (tl::to_qstring (ex.msg ()));
mp_error_icon->show ();
mp_error_label->show ();
if (ok) {
mp_error_label->setText (tl::to_qstring (ex.msg ()));
mp_error_icon->show ();
mp_error_label->show ();
*ok = false;
} else {
throw;
}
}
@ -539,7 +626,7 @@ PCellParametersPage::get_parameters ()
}
void
PCellParametersPage::set_parameters (const std::vector<tl::Variant> &parameters)
PCellParametersPage::set_parameters (const std::vector<tl::Variant> &parameters)
{
// write the changed value back
size_t r = 0;

View File

@ -25,6 +25,7 @@
#define HDR_edtPCellParametersPage
#include "dbPCellDeclaration.h"
#include "tlDeferredExecution.h"
#include <QFrame>
#include <QScrollArea>
@ -42,7 +43,7 @@ namespace edt
* @brief A QScrollArea that displays and allows editing PCell parameters
*/
class PCellParametersPage
: public QFrame
: public QFrame, public tl::Object
{
Q_OBJECT
@ -54,31 +55,28 @@ public:
bool valid;
int hScrollPosition;
int vScrollPosition;
QString focusWidget;
};
/**
* @brief Constructor: creates a page showing the given parameters
*
* @param parent The parent widget
* @param layout The layout in which the PCell instance resides
* @param view The layout view from which to take layers for example
* @param cv_index The index of the cellview in "view"
* @param pcell_decl The PCell declaration
* @param parameters The parameter values to show (if empty, the default values are used)
*/
PCellParametersPage (QWidget *parent, const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &parameters);
/**
* @brief Default constructor
*
* Use "setup" to configure the page.
*
* @param dense Use a dense layout if true
*/
PCellParametersPage (QWidget *parent);
PCellParametersPage (QWidget *parent, bool dense = false);
/**
* @brief Delayed initialization
* @brief initialization
*
* Use this method to setup when the arguments are not available in the constructor
*
* @param layout The layout in which the PCell instance resides
* @param view The layout view from which to take layers for example
* @param cv_index The index of the cellview in "view"
* @param pcell_decl The PCell declaration
* @param parameters The parameter values to show (if empty, the default values are used)
*/
void setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type &parameters);
@ -94,8 +92,12 @@ public:
/**
* @brief Get the current parameters
*
* *ok is set to true, if there is no error. In case of an error it's set to false.
* The error is indicated in the error label in the editor page.
* If ok is null, an exception is thrown.
*/
std::vector<tl::Variant> get_parameters ();
std::vector<tl::Variant> get_parameters (bool *ok = 0);
/**
* @brief Get the PCell declaration pointer
@ -110,10 +112,12 @@ public:
*/
void set_parameters (const std::vector<tl::Variant> &values);
public slots:
void activated ();
void clicked ();
signals:
void edited ();
private slots:
void parameter_changed ();
private:
QScrollArea *mp_parameters_area;
QLabel *mp_error_label;
@ -124,8 +128,11 @@ private:
lay::LayoutView *mp_view;
int m_cv_index;
db::pcell_parameters_type m_parameters;
bool m_dense;
tl::DeferredMethod<PCellParametersPage> dm_parameter_changed;
void init ();
void do_parameter_changed ();
};
}

View File

@ -32,6 +32,7 @@
#include "edtService.h"
#include "edtConfig.h"
#include "edtDialogs.h"
#include "edtPlugin.h"
#include "edtEditorOptionsPages.h"
#include <cmath>
@ -1009,9 +1010,7 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &search_box,
PartialService::PartialService (db::Manager *manager, lay::LayoutView *view, lay::Dispatcher *root)
: QObject (),
lay::ViewService (view->view_object_widget ()),
lay::Editable (view),
lay::Plugin (view),
lay::EditorServiceBase (view),
db::Object (manager),
mp_view (view),
mp_root (root),
@ -1069,7 +1068,7 @@ PartialService::deactivated ()
void
PartialService::activated ()
{
// ...
// .. nothing yet ..
}
void
@ -1294,11 +1293,11 @@ PartialService::snap (const db::DVector &v) const
const int sr_pixels = 8; // TODO: make variable
db::DPoint
lay::PointSnapToObjectResult
PartialService::snap2 (const db::DPoint &p) const
{
double snap_range = widget ()->mouse_event_trans ().inverted ().ctrans (sr_pixels);
return lay::obj_snap (m_snap_to_objects ? view () : 0, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, snap_range).second;
return lay::obj_snap (m_snap_to_objects ? view () : 0, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, snap_range);
}
void
@ -1530,20 +1529,27 @@ PartialService::wheel_event (int /*delta*/, bool /*horizonal*/, const db::DPoint
bool
PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
clear_mouse_cursors ();
if (m_dragging) {
set_cursor (lay::Cursor::size_all);
m_alt_ac = ac_from_buttons (buttons);
// drag the vertex or edge/segment
lay::PointSnapToObjectResult snap_details;
// drag the vertex or edge/segment
if (is_single_point_selection ()) {
// for a single selected point, 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
m_current = snap2 (p);
// for a single selected point, 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);
m_current = snap_details.snapped_point;
} else {
m_current = m_start + snap (p - m_start);
}
mouse_cursor_from_snap_details (snap_details);
selection_to_view ();
m_alt_ac = lay::AC_Global;

View File

@ -25,10 +25,8 @@
#ifndef HDR_edtPartialService
#define HDR_edtPartialService
#include "layEditable.h"
#include "layEditorServiceBase.h"
#include "layObjectInstPath.h"
#include "layLayoutView.h"
#include "layPlugin.h"
#include "layViewObject.h"
#include "layRubberBox.h"
#include "laySnap.h"
@ -140,9 +138,7 @@ struct EdgeWithIndex
*/
class PartialService
: public QObject,
public lay::ViewService,
public lay::Editable,
public lay::Plugin,
public lay::EditorServiceBase,
public db::Object
{
Q_OBJECT
@ -326,7 +322,7 @@ private:
db::DPoint snap (const db::DPoint &p) const;
db::DVector snap (const db::DVector &p) const;
db::DPoint snap2 (const db::DPoint &p) const;
lay::PointSnapToObjectResult snap2 (const db::DPoint &p) const;
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

@ -22,6 +22,9 @@
#include "layTipDialog.h"
#include "layEditorOptionsPages.h"
#include "layDispatcher.h"
#include "layLayoutView.h"
#include "edtPlugin.h"
#include "edtConfig.h"
#include "edtService.h"
@ -29,13 +32,27 @@
#include "edtMainService.h"
#include "edtPartialService.h"
#include "edtEditorOptionsPages.h"
#include "edtRecentConfigurationPage.h"
#include <QApplication>
#include <QLayout>
namespace edt
{
static
edt::RecentConfigurationPage::ConfigurationDescriptor shape_cfg_descriptors[] =
{
edt::RecentConfigurationPage::ConfigurationDescriptor ("", tl::to_string (tr ("Layer")), edt::RecentConfigurationPage::Layer),
};
static
void get_shape_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret, lay::LayoutView *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])]));
}
static
void get_text_options (std::vector < std::pair<std::string, std::string> > &options)
{
options.push_back (std::pair<std::string, std::string> (cfg_edit_text_string, "ABC"));
@ -44,10 +61,21 @@ 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"));
}
static
void get_text_editor_options_pages (std::vector<edt::EditorOptionsPage *> &ret, lay::Dispatcher *)
edt::RecentConfigurationPage::ConfigurationDescriptor text_cfg_descriptors[] =
{
ret.push_back (new edt::EditorOptionsText ());
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)
};
static
void get_text_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret, lay::LayoutView *view, lay::Dispatcher *dispatcher)
{
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 (dispatcher));
}
static
@ -59,10 +87,21 @@ 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"));
}
static
void get_path_editor_options_pages (std::vector<edt::EditorOptionsPage *> &ret, lay::Dispatcher *)
edt::RecentConfigurationPage::ConfigurationDescriptor path_cfg_descriptors[] =
{
ret.push_back (new EditorOptionsPath ());
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)
};
static
void get_path_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret, lay::LayoutView *view, lay::Dispatcher *dispatcher)
{
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 (dispatcher));
}
static
@ -84,10 +123,30 @@ 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"));
}
static
void get_inst_editor_options_pages (std::vector<edt::EditorOptionsPage *> &ret, lay::Dispatcher *root)
edt::RecentConfigurationPage::ConfigurationDescriptor inst_cfg_descriptors[] =
{
ret.push_back (new EditorOptionsInst (root));
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)
};
static
void get_inst_editor_options_pages (std::vector<lay::EditorOptionsPage *> &ret, lay::LayoutView *view, lay::Dispatcher *dispatcher)
{
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 (dispatcher));
ret.push_back (new EditorOptionsInst (dispatcher));
}
template <class Svc>
@ -97,7 +156,7 @@ class PluginDeclaration
public:
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 <edt::EditorOptionsPage *> &, lay::Dispatcher *) = 0)
void (*pages_f) (std::vector <lay::EditorOptionsPage *> &, lay::LayoutView *, lay::Dispatcher *) = 0)
: m_title (title), m_mouse_mode (mouse_mode), mp_option_get_f (option_get_f), mp_pages_f (pages_f)
{
// .. nothing yet ..
@ -120,11 +179,11 @@ public:
// .. nothing yet ..
}
virtual void get_editor_options_pages (std::vector<edt::EditorOptionsPage *> &pages, lay::Dispatcher *root) const
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages, lay::LayoutView *view, lay::Dispatcher *root) const
{
if (mp_pages_f != 0) {
size_t nstart = pages.size ();
(*mp_pages_f) (pages, root);
(*mp_pages_f) (pages, view, root);
while (nstart < pages.size ()) {
pages [nstart++]->set_plugin_declaration (this);
}
@ -155,16 +214,16 @@ private:
std::string m_mouse_mode;
void (*mp_option_get_f) (std::vector < std::pair<std::string, std::string> > &options);
void (*mp_pages_f) (std::vector <edt::EditorOptionsPage *> &, lay::Dispatcher *);
void (*mp_pages_f) (std::vector <lay::EditorOptionsPage *> &, lay::LayoutView *, lay::Dispatcher *);
};
static tl::RegisteredClass<lay::PluginDeclaration> config_decl1 (
new edt::PluginDeclaration<edt::PolygonService> (tl::to_string (QObject::tr ("Polygons")), "polygon:edit_mode\t" + tl::to_string (QObject::tr ("Polygon")) + "<:polygon.png>" + tl::to_string (QObject::tr ("{Create a polygon}"))),
new edt::PluginDeclaration<edt::PolygonService> (tl::to_string (QObject::tr ("Polygons")), "polygon:edit_mode\t" + tl::to_string (QObject::tr ("Polygon")) + "<:polygon.png>" + tl::to_string (QObject::tr ("{Create a polygon}")), 0, &get_shape_editor_options_pages),
4010,
"edt::Service(Polygons)"
);
static tl::RegisteredClass<lay::PluginDeclaration> config_decl2 (
new edt::PluginDeclaration<edt::BoxService> (tl::to_string (QObject::tr ("Boxes")), "box:edit_mode\t" + tl::to_string (QObject::tr ("Box")) + "\t<:box.png>" + tl::to_string (QObject::tr ("{Create a box}"))),
new edt::PluginDeclaration<edt::BoxService> (tl::to_string (QObject::tr ("Boxes")), "box:edit_mode\t" + tl::to_string (QObject::tr ("Box")) + "\t<:box.png>" + tl::to_string (QObject::tr ("{Create a box}")), 0, &get_shape_editor_options_pages),
4011,
"edt::Service(Boxes)"
);
@ -189,7 +248,7 @@ class MainPluginDeclaration
{
public:
MainPluginDeclaration (const std::string &title)
: mp_root (0), m_title (title), mp_obj_prop_dialog (0)
: mp_root (0), m_title (title)
{
// .. nothing yet ..
}
@ -218,13 +277,12 @@ public:
menu_entries.push_back (lay::menu_item ("edt::descend", "descend", "zoom_menu.end", tl::to_string (QObject::tr ("Descend")) + "(Ctrl+D)"));
menu_entries.push_back (lay::menu_item ("edt::ascend", "ascend", "zoom_menu.end", tl::to_string (QObject::tr ("Ascend")) + "(Ctrl+A)"));
menu_entries.push_back (lay::separator ("edit_options_group:edit_mode", "edit_menu.end"));
menu_entries.push_back (lay::menu_item ("edt::edit_options", "edit_options:edit_mode", "edit_menu.end", tl::to_string (QObject::tr ("Editor Options")) + "(F3)"));
menu_entries.push_back (lay::menu_item ("edt::sel_make_array", "make_array:edit_mode", "edit_menu.selection_menu.end", tl::to_string (QObject::tr ("Make Array"))));
menu_entries.push_back (lay::separator ("selection_group:edit_mode", "edit_menu.selection_menu.end"));
menu_entries.push_back (lay::menu_item ("edt::sel_change_layer", "change_layer:edit_mode", "edit_menu.selection_menu.end", tl::to_string (QObject::tr ("Change Layer"))));
menu_entries.push_back (lay::menu_item ("edt::sel_tap", "tap:edit_mode", "edit_menu.selection_menu.end", tl::to_string (QObject::tr ("Tap")) + "(T)"));
menu_entries.push_back (lay::menu_item ("edt::sel_align", "align:edit_mode", "edit_menu.selection_menu.end", tl::to_string (QObject::tr ("Align"))));
menu_entries.push_back (lay::menu_item ("edt::sel_distribute", "distribute:edit_mode", "edit_menu.selection_menu.end", tl::to_string (QObject::tr ("Distribute"))));
menu_entries.push_back (lay::menu_item ("edt::sel_round_corners", "round_corners:edit_mode", "edit_menu.selection_menu.end", tl::to_string (QObject::tr ("Round Corners"))));
menu_entries.push_back (lay::menu_item ("edt::sel_size", "size:edit_mode", "edit_menu.selection_menu.end", tl::to_string (QObject::tr ("Size Shapes"))));
menu_entries.push_back (lay::menu_item ("edt::sel_union", "union:edit_mode", "edit_menu.selection_menu.end", tl::to_string (QObject::tr ("Merge Shapes"))));
@ -263,12 +321,19 @@ public:
{
return false;
}
virtual bool implements_mouse_mode (std::string & /*title*/) const
{
return false;
}
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages, lay::LayoutView * /*view*/, lay::Dispatcher *dispatcher) const
{
// NOTE: we do not set plugin_declaration which makes the page unspecific
EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (dispatcher);
pages.push_back (generic_opt);
}
virtual void initialize (lay::Dispatcher *root)
{
lay::Dispatcher *mp = lay::Dispatcher::instance ();
@ -278,24 +343,6 @@ public:
mp_root = root;
// create the editor options dialog
m_prop_dialog_pages.push_back (new edt::EditorOptionsGeneric ());
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
const PluginDeclarationBase *pd_base = dynamic_cast<const PluginDeclarationBase *> (&*cls);
if (pd_base) {
pd_base->get_editor_options_pages (m_prop_dialog_pages, root);
}
}
mp_obj_prop_dialog = new edt::EditorOptionsPages (m_prop_dialog_pages, root);
for (std::vector<edt::EditorOptionsPage *>::const_iterator op = m_prop_dialog_pages.begin (); op != m_prop_dialog_pages.end (); ++op) {
if ((*op)->plugin_declaration () != 0) {
(*op)->activate (false);
}
}
// add entries to the combine mode dialog
mp->menu ()->insert_item ("@toolbar.combine_mode.end", "combine_mode_add", new lay::ConfigureAction (tl::to_string (QObject::tr ("Add<:/cm_add.png>{Add shapes}")), cfg_edit_combine_mode, CMConverter ().to_string (CM_Add)));
mp->menu ()->insert_item ("@toolbar.combine_mode.end", "combine_mode_merge", new lay::ConfigureAction (tl::to_string (QObject::tr ("Merge<:/cm_merge.png>{Merge shapes with background}")), cfg_edit_combine_mode, CMConverter ().to_string (CM_Merge)));
@ -333,42 +380,6 @@ public:
}
}
virtual void uninitialize (lay::Dispatcher *)
{
if (mp_obj_prop_dialog) {
delete mp_obj_prop_dialog;
mp_obj_prop_dialog = 0;
}
}
virtual void config_finalize ()
{
if (mp_obj_prop_dialog && mp_obj_prop_dialog->isVisible ()) {
mp_obj_prop_dialog->setup ();
}
}
void show_dialog () const
{
if (mp_obj_prop_dialog) {
if (! mp_obj_prop_dialog->isVisible ()) {
mp_obj_prop_dialog->setup ();
mp_obj_prop_dialog->show ();
}
mp_obj_prop_dialog->activateWindow ();
mp_obj_prop_dialog->raise ();
}
}
void activate (const lay::PluginDeclaration *pd, bool active) const
{
for (std::vector<edt::EditorOptionsPage *>::const_iterator op = m_prop_dialog_pages.begin (); op != m_prop_dialog_pages.end (); ++op) {
if ((*op)->plugin_declaration () == pd) {
(*op)->activate (active);
}
}
}
void initialized (lay::Dispatcher *root)
{
lay::Dispatcher *mp = lay::Dispatcher::instance ();
@ -397,40 +408,27 @@ public:
private:
lay::Dispatcher *mp_root;
std::string m_title;
edt::EditorOptionsPages *mp_obj_prop_dialog;
std::vector<edt::EditorOptionsPage *> m_prop_dialog_pages;
};
static tl::RegisteredClass<lay::PluginDeclaration> config_decl_main (new edt::MainPluginDeclaration (tl::to_string (QObject::tr ("Instances and shapes"))), 4000, "edt::MainService");
void
show_editor_options_dialog ()
commit_recent (lay::LayoutView *view)
{
// look for the plugin declaration and show the dialog
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
const MainPluginDeclaration *main_pd = dynamic_cast<const MainPluginDeclaration *> (&*cls);
if (main_pd) {
main_pd->show_dialog ();
break;
lay::EditorOptionsPages *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)->active ()) {
(*op)->commit_recent (view);
}
}
}
void
activate_service (const lay::PluginDeclaration *pd, bool active)
{
// look for the plugin declaration and show the dialog
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
const MainPluginDeclaration *main_pd = dynamic_cast<const MainPluginDeclaration *> (&*cls);
if (main_pd) {
main_pd->activate (pd, active);
break;
}
}
}
static tl::RegisteredClass<lay::PluginDeclaration> config_decl20 (new edt::MainPluginDeclaration (tl::to_string (QObject::tr ("Instances and shapes"))), 4000, "edt::MainService");
class PartialPluginDeclaration
: public lay::PluginDeclaration
: public PluginDeclarationBase
{
public:
PartialPluginDeclaration (const std::string &title, const std::string &mouse_mode)
@ -444,6 +442,11 @@ public:
// .. nothing yet ..
}
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> & /*pages*/, lay::LayoutView * /*view*/, lay::Dispatcher * /*root*/) const
{
// .. no specific ones ..
}
virtual lay::Plugin *create_plugin (db::Manager *manager, lay::Dispatcher *root, lay::LayoutView *view) const
{
return new edt::PartialService (manager, view, root);

View File

@ -31,35 +31,24 @@
namespace lay
{
class Dispatcher;
class EditorOptionsPage;
}
namespace edt
{
class EditorOptionsPage;
/**
* @brief A helper class for plugin declarations for editor services
*/
class PluginDeclarationBase
: public lay::PluginDeclaration
{
public:
virtual void get_editor_options_pages (std::vector<edt::EditorOptionsPage *> &, lay::Dispatcher *) const = 0;
// .. nothing yet ..
};
/**
* @brief Show the editor options dialog
*
* This dialog is a global resource which is managed by the main plugin declaration
* @brief Commits the current configuration for the recently used configuration list
*/
void show_editor_options_dialog ();
/**
* @brief Activate or deactivate a certain service
*
* This will show or hide the editor properties pages for the respective service.
*/
void activate_service (const lay::PluginDeclaration *pd, bool active);
void commit_recent (lay::LayoutView *view);
}
#endif

View File

@ -26,6 +26,8 @@
#include "dbShapes.h"
#include "dbLayout.h"
#include <QLineEdit>
namespace edt
{

View File

@ -33,6 +33,8 @@
#include <vector>
class QLineEdit;
namespace edt
{

View File

@ -24,9 +24,11 @@
#include "edtPropertiesPages.h"
#include "edtPropertiesPageUtils.h"
#include "edtDialogs.h"
#include "edtPropertiesPageUtils.h"
#include "layDialogs.h"
#include "layObjectInstPath.h"
#include "layLayoutView.h"
#include "layQtTools.h"
#include "tlExceptions.h"
#include "tlString.h"
@ -174,7 +176,7 @@ ShapePropertiesPage::recompute_selection_ptrs (const std::vector<lay::ObjectInst
}
void
ShapePropertiesPage::do_apply (bool current_only)
ShapePropertiesPage::do_apply (bool current_only, bool relative)
{
std::auto_ptr<ChangeApplicator> applicator;
@ -203,32 +205,7 @@ ShapePropertiesPage::do_apply (bool current_only)
// Ask whether to use relative or absolute mode
bool relative_mode = false;
if (! current_only && applicator->supports_relative_mode ()) {
static bool s_relative_mode = true;
QMessageBox mb (QMessageBox::Question,
tr ("Apply Changes To All"),
tr ("For this operation absolute or relative mode is available which affects the way parameters of the selected objects are changed:\n\n"
"In absolute mode, they will be set to the given value. In relative mode, they will be adjusted by the same amount.\n"),
QMessageBox::NoButton, this);
mb.addButton (tr ("Cancel"), QMessageBox::RejectRole);
QPushButton *absolute = mb.addButton (tr ("Absolute"), QMessageBox::NoRole);
QPushButton *relative = mb.addButton (tr ("Relative"), QMessageBox::YesRole);
mb.setDefaultButton (s_relative_mode ? relative : absolute);
mb.exec ();
if (mb.clickedButton () == absolute) {
s_relative_mode = relative_mode = false;
} else if (mb.clickedButton () == relative) {
s_relative_mode = relative_mode = true;
} else {
// Cancel pressed
return;
}
relative_mode = relative;
}
// Note: using the apply-all scheme for applying a single change may look like overhead.
@ -333,7 +310,7 @@ ShapePropertiesPage::do_apply (bool current_only)
void
ShapePropertiesPage::apply ()
{
do_apply (true);
do_apply (true, false);
}
bool
@ -343,9 +320,9 @@ ShapePropertiesPage::can_apply_to_all () const
}
void
ShapePropertiesPage::apply_to_all ()
ShapePropertiesPage::apply_to_all (bool relative)
{
do_apply (false);
do_apply (false, relative);
}
void
@ -391,7 +368,9 @@ void
ShapePropertiesPage::show_props ()
{
lay::UserPropertiesForm props_form (this);
props_form.show (mp_service->view (), m_selection_ptrs [m_index]->cv_index (), m_prop_id);
if (props_form.show (mp_service->view (), m_selection_ptrs [m_index]->cv_index (), m_prop_id)) {
emit edited ();
}
}
bool
@ -404,13 +383,19 @@ ShapePropertiesPage::readonly ()
// PolygonPropertiesPage implementation
PolygonPropertiesPage::PolygonPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent)
: ShapePropertiesPage (service, manager, parent)
: ShapePropertiesPage (service, manager, parent), m_in_text_changed (false)
{
setupUi (this);
setup ();
connect (inst_pb, SIGNAL (clicked ()), this, SLOT (show_inst ()));
connect (prop_pb, SIGNAL (clicked ()), this, SLOT (show_props ()));
if (! readonly ()) {
connect (pointListEdit, SIGNAL (textChanged ()), this, SLOT (text_changed ()));
} else {
pointListEdit->setReadOnly (true);
}
}
void
@ -448,61 +433,87 @@ PolygonPropertiesPage::do_update (const db::Shape &shape, double dbu, const std:
}
pointListEdit->setText (tl::to_qstring (ptlist));
if (! m_in_text_changed) {
pointListEdit->blockSignals (true);
pointListEdit->setText (tl::to_qstring (ptlist));
pointListEdit->blockSignals (false);
}
pointCountLabel->setText (tl::to_qstring (tl::sprintf (tl::to_string (QObject::tr ("(%lu points)")), poly.vertices ())));
}
void
PolygonPropertiesPage::text_changed ()
{
m_in_text_changed = true;
try {
emit edited ();
} catch (tl::Exception &) {
// ignore exceptions
}
m_in_text_changed = false;
}
ChangeApplicator *
PolygonPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape &shape, double dbu)
{
std::string text (tl::to_string (pointListEdit->toPlainText ()));
tl::Extractor ex (text.c_str ());
db::VCplxTrans t = db::CplxTrans (trans ()).inverted ();
bool du = dbu_units ();
db::Polygon poly;
if (*ex.skip () == '(') {
try {
db::DPolygon dp;
ex.read (dp);
std::string text (tl::to_string (pointListEdit->toPlainText ()));
tl::Extractor ex (text.c_str ());
poly = db::Polygon (dp.transformed (db::DCplxTrans (t) * db::DCplxTrans (du ? 1.0 : 1.0 / dbu)));
db::VCplxTrans t = db::CplxTrans (trans ()).inverted ();
bool du = dbu_units ();
} else {
if (*ex.skip () == '(') {
unsigned int h = 0;
while (! ex.at_end ()) {
db::DPolygon dp;
ex.read (dp);
std::vector <db::Point> points;
poly = db::Polygon (dp.transformed (db::DCplxTrans (t) * db::DCplxTrans (du ? 1.0 : 1.0 / dbu)));
while (! ex.at_end () && ! ex.test ("/")) {
} else {
double dx = 0.0, dy = 0.0;
ex.read (dx);
ex.test (",");
ex.read (dy);
ex.test (";");
unsigned int h = 0;
while (! ex.at_end ()) {
points.push_back (point_from_dpoint (db::DPoint (dx, dy), dbu, du, t));
std::vector <db::Point> points;
while (! ex.at_end () && ! ex.test ("/")) {
double dx = 0.0, dy = 0.0;
ex.read (dx);
ex.test (",");
ex.read (dy);
ex.test (";");
points.push_back (point_from_dpoint (db::DPoint (dx, dy), dbu, du, t));
}
if (points.size () < 3) {
throw tl::Exception (tl::to_string (QObject::tr ("Polygon must have at least three points")));
}
if (h == 0) {
poly.assign_hull (points.begin (), points.end (), false /*not compressed*/);
} else {
poly.insert_hole (points.begin (), points.end (), false /*not compressed*/);
}
++h;
}
if (points.size () < 3) {
throw tl::Exception (tl::to_string (QObject::tr ("Polygon must have at least three points")));
}
if (h == 0) {
poly.assign_hull (points.begin (), points.end (), false /*not compressed*/);
} else {
poly.insert_hole (points.begin (), points.end (), false /*not compressed*/);
}
++h;
}
lay::indicate_error (pointListEdit, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (pointListEdit, &ex);
throw;
}
db::Polygon org_poly;
@ -525,15 +536,32 @@ BoxPropertiesPage::BoxPropertiesPage (edt::Service *service, db::Manager *manage
setup ();
mode_tab->setCurrentIndex (s_coordinateMode ? 0 : 1);
connect (mode_tab, SIGNAL (currentChanged (int)), this, SLOT (changed ()));
connect (x1_le_1, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (y1_le_1, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (x2_le_1, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (y2_le_1, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (w_le_2, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (h_le_2, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (cx_le_2, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (cy_le_2, SIGNAL (editingFinished ()), this, SLOT (changed ()));
if (! readonly ()) {
connect (mode_tab, SIGNAL (currentChanged (int)), this, SLOT (changed ()));
connect (x1_le_1, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (y1_le_1, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (x2_le_1, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (y2_le_1, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (w_le_2, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (h_le_2, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (cx_le_2, SIGNAL (editingFinished ()), this, SLOT (changed ()));
connect (cy_le_2, SIGNAL (editingFinished ()), this, SLOT (changed ()));
} else {
x1_le_1->setReadOnly (true);
y1_le_1->setReadOnly (true);
x2_le_1->setReadOnly (true);
y2_le_1->setReadOnly (true);
w_le_2->setReadOnly (true);
h_le_2->setReadOnly (true);
cx_le_2->setReadOnly (true);
cy_le_2->setReadOnly (true);
}
connect (inst_pb, SIGNAL (clicked ()), this, SLOT (show_inst ()));
connect (prop_pb, SIGNAL (clicked ()), this, SLOT (show_props ()));
}
@ -576,11 +604,44 @@ BoxPropertiesPage::get_box (int mode) const
{
if (mode == 0) {
bool has_error = false;
double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
tl::from_string (tl::to_string (x1_le_1->text ()), x1);
tl::from_string (tl::to_string (y1_le_1->text ()), y1);
tl::from_string (tl::to_string (x2_le_1->text ()), x2);
tl::from_string (tl::to_string (y2_le_1->text ()), y2);
try {
tl::from_string (tl::to_string (x1_le_1->text ()), x1);
lay::indicate_error (x1_le_1, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x1_le_1, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (y1_le_1->text ()), y1);
lay::indicate_error (y1_le_1, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y1_le_1, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (x2_le_1->text ()), x2);
lay::indicate_error (x2_le_1, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x2_le_1, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (y2_le_1->text ()), y2);
lay::indicate_error (y2_le_1, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y2_le_1, &ex);
has_error = true;
}
if (has_error) {
throw tl::Exception (tl::to_string (tr ("Invalid values - see highlighted entry boxes")));
}
if (m_lr_swapped) {
std::swap (x1, x2);
@ -603,11 +664,44 @@ BoxPropertiesPage::get_box (int mode) const
} else {
bool has_error = false;
double cx = 0.0, cy = 0.0, w = 0.0, h = 0.0;
tl::from_string (tl::to_string (cx_le_2->text ()), cx);
tl::from_string (tl::to_string (cy_le_2->text ()), cy);
tl::from_string (tl::to_string (w_le_2->text ()), w);
tl::from_string (tl::to_string (h_le_2->text ()), h);
try {
tl::from_string (tl::to_string (cx_le_2->text ()), cx);
lay::indicate_error (cx_le_2, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (cx_le_2, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (cy_le_2->text ()), cy);
lay::indicate_error (cy_le_2, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (cy_le_2, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (w_le_2->text ()), w);
lay::indicate_error (w_le_2, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (w_le_2, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (h_le_2->text ()), h);
lay::indicate_error (h_le_2, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (h_le_2, &ex);
has_error = true;
}
if (has_error) {
throw tl::Exception (tl::to_string (tr ("Invalid values - see highlighted entry boxes")));
}
db::VCplxTrans t = db::VCplxTrans (trans ().inverted ());
bool du = dbu_units ();
@ -664,6 +758,8 @@ BoxPropertiesPage::changed ()
set_box (get_box (m_tab_index));
} catch (...) {
}
emit edited ();
}
// -------------------------------------------------------------------------
@ -677,6 +773,28 @@ TextPropertiesPage::TextPropertiesPage (edt::Service *service, db::Manager *mana
connect (inst_pb, SIGNAL (clicked ()), this, SLOT (show_inst ()));
connect (prop_pb, SIGNAL (clicked ()), this, SLOT (show_props ()));
if (! readonly ()) {
connect (text_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (x_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (y_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (size_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (orient_cbx, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (halign_cbx, SIGNAL (activated (int)), this, SIGNAL (edited ()));
connect (valign_cbx, SIGNAL (activated (int)), this, SIGNAL (edited ()));
} else {
text_le->setReadOnly (true);
x_le->setReadOnly (true);
y_le->setReadOnly (true);
size_le->setReadOnly (true);
orient_cbx->setEnabled (false);
halign_cbx->setEnabled (false);
valign_cbx->setEnabled (false);
}
}
void
@ -707,12 +825,28 @@ TextPropertiesPage::do_update (const db::Shape &shape, double dbu, const std::st
ChangeApplicator *
TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape &shape, double dbu)
{
bool has_error = false;
db::VCplxTrans t = db::CplxTrans (trans ()).inverted ();
bool du = dbu_units ();
double x = 0.0, y = 0.0;
tl::from_string (tl::to_string (x_le->text ()), x);
tl::from_string (tl::to_string (y_le->text ()), y);
try {
tl::from_string (tl::to_string (x_le->text ()), x);
lay::indicate_error (x_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x_le, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (y_le->text ()), y);
lay::indicate_error (y_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y_le, &ex);
has_error = true;
}
db::Vector tp = db::Vector (point_from_dpoint (db::DPoint (x, y), dbu, du, t));
db::Trans tt (orient_cbx->currentIndex (), tp);
@ -739,7 +873,13 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape
db::Coord size = 0;
if (! size_le->text ().isEmpty ()) {
size = coord_from_string (tl::to_string (size_le->text ()).c_str (), dbu, du, t);
try {
size = coord_from_string (tl::to_string (size_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (size_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (size_le, &ex);
has_error = true;
}
}
if (size != org_text.size ()) {
appl->add (new TextSizeChangeApplicator (size));
@ -749,6 +889,10 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape
appl->add (new TextStringChangeApplicator (str));
}
if (has_error) {
throw tl::Exception (tl::to_string (tr ("Invalid values - see highlighted entry boxes")));
}
return appl.release ();
}
@ -756,16 +900,22 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape
// PathPropertiesPage implementation
PathPropertiesPage::PathPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent)
: ShapePropertiesPage (service, manager, parent)
: ShapePropertiesPage (service, manager, parent), m_in_text_changed (false)
{
setupUi (this);
setup ();
connect (inst_pb, SIGNAL (clicked ()), this, SLOT (show_inst ()));
connect (prop_pb, SIGNAL (clicked ()), this, SLOT (show_props ()));
ptlist_le->setReadOnly (true);
width_le->setReadOnly (true);
start_ext_le->setReadOnly (true);
end_ext_le->setReadOnly (true);
round_cb->setEnabled (false);
}
void
void
PathPropertiesPage::do_update (const db::Shape &shape, double dbu, const std::string &lname)
{
layer_lbl->setText (tl::to_qstring (lname));
@ -788,7 +938,12 @@ PathPropertiesPage::do_update (const db::Shape &shape, double dbu, const std::st
}
ptlist += coords_to_string (t * *pt, dbu, du);
}
ptlist_le->setText (tl::to_qstring (ptlist));
if (! m_in_text_changed) {
ptlist_le->blockSignals (true);
ptlist_le->setText (tl::to_qstring (ptlist));
ptlist_le->blockSignals (false);
}
width_le->setText (tl::to_qstring (coord_to_string (t.ctrans (path.width ()), dbu, du)));
start_ext_le->setText (tl::to_qstring (coord_to_string (t.ctrans (path.extensions ().first), dbu, du)));
@ -797,68 +952,16 @@ PathPropertiesPage::do_update (const db::Shape &shape, double dbu, const std::st
}
ChangeApplicator *
PathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape &shape, double dbu)
PathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape & /*shape*/, double /*dbu*/)
{
db::VCplxTrans t = db::CplxTrans (trans ()).inverted ();
bool du = dbu_units ();
std::string text (tl::to_string (ptlist_le->toPlainText ()));
tl::Extractor ex (text.c_str ());
std::vector <db::Point> points;
while (! ex.at_end ()) {
double dx = 0.0, dy = 0.0;
ex.read (dx);
ex.read (dy);
points.push_back (point_from_dpoint (db::DPoint (dx, dy), dbu, du, t));
}
if (points.size () < 1) {
throw tl::Exception (tl::to_string (QObject::tr ("The path must have at least one point")));
}
db::Coord w = coord_from_string (tl::to_string (width_le->text ()).c_str (), dbu, du, t);
db::Coord se = coord_from_string (tl::to_string (start_ext_le->text ()).c_str (), dbu, du, t);
db::Coord ee = coord_from_string (tl::to_string (end_ext_le->text ()).c_str (), dbu, du, t);
bool round = round_cb->isChecked ();
std::auto_ptr<CombinedChangeApplicator> appl;
db::Path org_path;
shape.path (org_path);
std::vector <db::Point> org_points;
for (db::Path::iterator p = org_path.begin (); p != org_path.end (); ++p) {
org_points.push_back (*p);
}
if (org_points != points) {
appl->add (new PathPointsChangeApplicator (points, org_points));
}
if (w != org_path.width ()) {
appl->add (new PathWidthChangeApplicator (w, org_path.width ()));
}
if (se != org_path.extensions ().first) {
appl->add (new PathStartExtensionChangeApplicator (se));
}
if (ee != org_path.extensions ().second) {
appl->add (new PathEndExtensionChangeApplicator (ee));
}
if (round != org_path.round ()) {
appl->add (new PathRoundEndChangeApplicator (round));
}
return appl.release ();
return 0;
}
// -------------------------------------------------------------------------
// EditablePathPropertiesPage implementation
EditablePathPropertiesPage::EditablePathPropertiesPage (edt::Service *service, db::Manager *manager, QWidget *parent)
: ShapePropertiesPage (service, manager, parent)
: ShapePropertiesPage (service, manager, parent), m_in_text_changed (false)
{
setupUi (this);
setup ();
@ -866,6 +969,12 @@ EditablePathPropertiesPage::EditablePathPropertiesPage (edt::Service *service, d
connect (inst_pb, SIGNAL (clicked ()), this, SLOT (show_inst ()));
connect (prop_pb, SIGNAL (clicked ()), this, SLOT (show_props ()));
connect (type_cb, SIGNAL (currentIndexChanged (int)), this, SLOT (type_selected (int)));
connect (ptlist_le, SIGNAL (textChanged ()), this, SLOT (text_changed ()));
connect (width_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (start_ext_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (end_ext_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (type_cb, SIGNAL (activated (int)), this, SIGNAL (edited ()));
}
static int
@ -886,7 +995,19 @@ path_type_choice (const db::Path &path)
}
}
void
void
EditablePathPropertiesPage::text_changed ()
{
m_in_text_changed = true;
try {
emit edited ();
} catch (tl::Exception &) {
// ignore exceptions
}
m_in_text_changed = false;
}
void
EditablePathPropertiesPage::do_update (const db::Shape &shape, double dbu, const std::string &lname)
{
layer_lbl->setText (tl::to_qstring (lname));
@ -909,7 +1030,12 @@ EditablePathPropertiesPage::do_update (const db::Shape &shape, double dbu, const
}
ptlist += coords_to_string (t * *pt, dbu, du);
}
ptlist_le->setText (tl::to_qstring (ptlist));
if (! m_in_text_changed) {
ptlist_le->blockSignals (true);
ptlist_le->setText (tl::to_qstring (ptlist));
ptlist_le->blockSignals (false);
}
db::Coord w = path.width ();
db::Coord se = path.extensions ().first;
@ -921,6 +1047,10 @@ EditablePathPropertiesPage::do_update (const db::Shape &shape, double dbu, const
end_ext_le->setText (tl::to_qstring (coord_to_string (t.ctrans (ee), dbu, du)));
int type_choice = path_type_choice (path);
if (type_cb->currentIndex () == 2) {
// keep "variable" mode, otherwise if's difficult to switch to it
type_choice = 2;
}
type_cb->setCurrentIndex (type_choice);
type_selected (type_choice);
}
@ -928,6 +1058,8 @@ EditablePathPropertiesPage::do_update (const db::Shape &shape, double dbu, const
ChangeApplicator *
EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape &shape, double dbu)
{
bool has_error = false;
db::VCplxTrans t = db::CplxTrans (trans ()).inverted ();
bool du = dbu_units ();
@ -936,22 +1068,38 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db
std::vector <db::Point> points;
while (! ex.at_end ()) {
try {
double dx = 0.0, dy = 0.0;
ex.read (dx);
ex.read (dy);
while (! ex.at_end ()) {
points.push_back (point_from_dpoint (db::DPoint (dx, dy), dbu, du, t));
double dx = 0.0, dy = 0.0;
ex.read (dx);
ex.read (dy);
points.push_back (point_from_dpoint (db::DPoint (dx, dy), dbu, du, t));
}
if (points.size () < 1) {
throw tl::Exception (tl::to_string (QObject::tr ("The path must have at least one point")));
}
lay::indicate_error (ptlist_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (ptlist_le, &ex);
has_error = true;
}
if (points.size () < 1) {
throw tl::Exception (tl::to_string (QObject::tr ("The path must have at least one point")));
db::Coord w = 0;
try {
w = coord_from_string (tl::to_string (width_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (width_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (width_le, &ex);
has_error = true;
}
db::Coord w = coord_from_string (tl::to_string (width_le->text ()).c_str (), dbu, du, t);
db::Coord se = 0, ee = 0;
switch (type_cb->currentIndex ()) {
case 0: // flush
@ -961,8 +1109,20 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db
se = ee = std::numeric_limits <db::Coord>::min (); // force to half width
break;
case 2: // variable
se = coord_from_string (tl::to_string (start_ext_le->text ()).c_str (), dbu, du, t);
ee = coord_from_string (tl::to_string (end_ext_le->text ()).c_str (), dbu, du, t);
try {
se = coord_from_string (tl::to_string (start_ext_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (start_ext_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (start_ext_le, &ex);
has_error = true;
}
try {
ee = coord_from_string (tl::to_string (end_ext_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (end_ext_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (end_ext_le, &ex);
has_error = true;
}
break;
}
@ -989,6 +1149,10 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db
appl->add (new PathRoundEndChangeApplicator (type_cb->currentIndex () == 3));
}
if (has_error) {
throw tl::Exception (tl::to_string (tr ("Invalid values - see highlighted entry boxes")));
}
return appl.release ();
}

View File

@ -56,13 +56,15 @@ public:
virtual void operator++ ();
virtual void leave ();
protected:
virtual bool readonly ();
private:
virtual void update ();
virtual void apply ();
virtual void apply_to_all ();
virtual void apply_to_all (bool relative);
virtual bool can_apply_to_all () const;
virtual void do_apply (bool current_only);
virtual bool readonly ();
virtual void do_apply (bool current_only, bool relative);
void recompute_selection_ptrs (const std::vector<lay::ObjectInstPath> &new_sel);
protected:
@ -104,6 +106,12 @@ public:
protected:
virtual QCheckBox *dbu_checkbox () const { return dbu_cb; }
virtual QCheckBox *abs_checkbox () const { return abs_cb; }
public slots:
void text_changed ();
private:
bool m_in_text_changed;
};
class BoxPropertiesPage
@ -167,6 +175,9 @@ public:
protected:
virtual QCheckBox *dbu_checkbox () const { return dbu_cb; }
virtual QCheckBox *abs_checkbox () const { return abs_cb; }
private:
bool m_in_text_changed;
};
class EditablePathPropertiesPage
@ -187,6 +198,10 @@ protected:
public slots:
void type_selected (int);
void text_changed ();
private:
bool m_in_text_changed;
};
}

View File

@ -0,0 +1,394 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "edtRecentConfigurationPage.h"
#include "edtUtils.h"
#include "layDispatcher.h"
#include "layLayoutView.h"
#include "layLayerTreeModel.h"
#include "dbLibraryManager.h"
#include "dbLibrary.h"
#include <QVBoxLayout>
#include <QHeaderView>
#include <QLabel>
namespace edt
{
static const size_t max_entries = 100;
void
RecentConfigurationPage::init ()
{
QVBoxLayout *ly = new QVBoxLayout (this);
ly->setMargin (0);
QLabel *label = new QLabel (this);
label->setText (tr ("Click to select a recent configuration"));
ly->addWidget (label);
mp_tree_widget = new QTreeWidget (this);
mp_tree_widget->setRootIsDecorated (false);
mp_tree_widget->setUniformRowHeights (true);
mp_tree_widget->setSelectionMode (QAbstractItemView::NoSelection);
mp_tree_widget->setAllColumnsShowFocus (true);
ly->addWidget (mp_tree_widget);
connect (mp_tree_widget, SIGNAL (itemClicked (QTreeWidgetItem *, int)), this, SLOT (item_clicked (QTreeWidgetItem *)));
mp_view->layer_list_changed_event.add (this, &RecentConfigurationPage::layers_changed);
mp_tree_widget->setColumnCount (int (m_cfg.size ()));
QStringList column_labels;
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c) {
column_labels << tl::to_qstring (c->title);
}
mp_tree_widget->setHeaderLabels (column_labels);
update_list (get_stored_values ());
}
RecentConfigurationPage::~RecentConfigurationPage ()
{
// .. nothing yet ..
}
std::string RecentConfigurationPage::title () const
{
return tl::to_string (tr ("Recent"));
}
int RecentConfigurationPage::order () const
{
return 100;
}
std::list<std::vector<std::string> >
RecentConfigurationPage::get_stored_values () const
{
std::string serialized_list = dispatcher ()->config_get (m_recent_cfg_name);
std::list<std::vector<std::string> > values;
tl::Extractor ex (serialized_list.c_str ());
while (! ex.at_end ()) {
values.push_back (std::vector<std::string> ());
while (! ex.at_end () && ! ex.test (";")) {
values.back ().push_back (std::string ());
ex.read_word_or_quoted (values.back ().back ());
ex.test (",");
}
}
return values;
}
void
RecentConfigurationPage::set_stored_values (const std::list<std::vector<std::string> > &values) const
{
std::string serialized_list;
for (std::list<std::vector<std::string> >::const_iterator v = values.begin (); v != values.end (); ++v) {
if (v != values.begin ()) {
serialized_list += ";";
}
for (std::vector<std::string>::const_iterator s = v->begin (); s != v->end (); ++s) {
serialized_list += tl::to_word_or_quoted_string (*s);
serialized_list += ",";
}
}
dispatcher ()->config_set (m_recent_cfg_name, serialized_list);
}
static lay::LayerPropertiesConstIterator
lp_iter_from_string (lay::LayoutView *view, const std::string &s)
{
// parse the layer spec (<layer-props>[@<cv-index>])
db::LayerProperties lp;
tl::Extractor ex (s.c_str ());
lp.read (ex);
int cv_index = 0;
if (ex.test ("@")) {
ex.read (cv_index);
}
// rename the ones that got shifted.
lay::LayerPropertiesConstIterator l = view->begin_layers ();
while (! l.at_end ()) {
if (l->source (true).cv_index () == int (cv_index) && l->source (true).layer_props ().log_equal (lp)) {
return l;
}
++l;
}
return l;
}
void
RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std::vector<std::string> &values, RecentConfigurationPage::ConfigurationRendering rendering)
{
// store original value
item->setData (column, Qt::UserRole, tl::to_qstring (values [column]));
switch (rendering) {
case RecentConfigurationPage::ArrayFlag:
case RecentConfigurationPage::Bool:
{
bool f = false;
tl::from_string (values [column], f);
static QString checkmark = QString::fromUtf8 ("\xe2\x9c\x93");
item->setText (column, f ? checkmark : QString ()); // "checkmark"
}
break;
case RecentConfigurationPage::Layer:
{
int icon_size = mp_view->style ()->pixelMetric (QStyle::PM_ButtonIconSize);
lay::LayerPropertiesConstIterator l = lp_iter_from_string (mp_view, values [column]);
if (! l.is_null () && ! l.at_end ()) {
item->setIcon (column, lay::LayerTreeModel::icon_for_layer (l, mp_view, icon_size, icon_size, 0, true));
item->setText (column, tl::to_qstring (values [column]));
} else {
item->setIcon (column, QIcon ());
item->setText (column, tl::to_qstring ("(" + values [column] + ")"));
}
}
break;
case RecentConfigurationPage::Int:
case RecentConfigurationPage::Double:
case RecentConfigurationPage::Text:
item->setText (column, tl::to_qstring (values [column]));
break;
case RecentConfigurationPage::CellLibraryName:
if (values [column].empty ()) {
item->setText (column, tr ("(local)"));
} else {
item->setText (column, tl::to_qstring (values [column]));
}
break;
case RecentConfigurationPage::IntIfArray:
case RecentConfigurationPage::DoubleIfArray:
{
bool is_array = false;
int flag_column = 0;
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++flag_column) {
if (c->rendering == RecentConfigurationPage::ArrayFlag) {
tl::from_string (values [flag_column], is_array);
break;
}
}
if (is_array) {
item->setText (column, tl::to_qstring (values [column]));
} else {
item->setText (column, QString ());
}
}
break;
case RecentConfigurationPage::CellDisplayName:
{
// search for a libname
int libname_column = 0;
const db::Library *lib = 0;
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++libname_column) {
if (c->rendering == RecentConfigurationPage::CellLibraryName) {
lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column]);
break;
}
}
if (lib) {
// search for a PCell parameters
int pcp_column = 0;
std::map<std::string, tl::Variant> pcp;
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++pcp_column) {
if (c->rendering == RecentConfigurationPage::PCellParameters) {
pcp = pcell_parameters_from_string (values [pcp_column]);
break;
}
}
std::pair<bool, db::Layout::pcell_id_type> pcid = lib->layout ().pcell_by_name (values [column].c_str ());
if (pcid.first) {
const db::PCellDeclaration *pc_decl = lib->layout ().pcell_declaration (pcid.second);
if (pc_decl) {
item->setText (column, tl::to_qstring (pc_decl->get_display_name (pc_decl->map_parameters (pcp))));
break;
}
}
}
item->setText (column, tl::to_qstring (values [column]));
}
break;
case RecentConfigurationPage::PCellParameters:
{
std::map<std::string, tl::Variant> pcp;
pcp = pcell_parameters_from_string (values [column]);
std::string r;
for (std::map<std::string, tl::Variant>::const_iterator p = pcp.begin (); p != pcp.end (); ++p) {
if (p != pcp.begin ()) {
r += ",";
}
r += p->first;
r += "=";
r += p->second.to_string ();
}
item->setText (column, tl::to_qstring (r));
}
break;
}
}
void
RecentConfigurationPage::layers_changed (int)
{
update_list (get_stored_values ());
}
void
RecentConfigurationPage::update_list (const std::list<std::vector<std::string> > &stored_values)
{
int row = 0;
for (std::list<std::vector<std::string> >::const_iterator v = stored_values.begin (); v != stored_values.end (); ++v, ++row) {
QTreeWidgetItem *item = 0;
if (row < mp_tree_widget->topLevelItemCount ()) {
item = mp_tree_widget->topLevelItem (row);
} else {
item = new QTreeWidgetItem (mp_tree_widget);
mp_tree_widget->addTopLevelItem (item);
}
int column = 0;
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++column) {
if (column < int (v->size ())) {
render_to (item, column, *v, c->rendering);
}
}
}
while (mp_tree_widget->topLevelItemCount () > row) {
delete mp_tree_widget->takeTopLevelItem (row);
}
mp_tree_widget->header ()->resizeSections (QHeaderView::ResizeToContents);
}
void
RecentConfigurationPage::item_clicked (QTreeWidgetItem *item)
{
int column = 0;
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++column) {
std::string v = tl::to_string (item->data (column, Qt::UserRole).toString ());
if (c->rendering == Layer) {
// "getting" a layer means making it current
db::LayerProperties lp;
tl::Extractor ex (v.c_str ());
lp.read (ex);
int cv_index = 0;
if (ex.test ("@")) {
ex.read (cv_index);
}
mp_view->set_or_request_current_layer (cv_index, lp);
} else {
dispatcher ()->config_set (c->cfg_name, v);
}
}
dispatcher ()->config_end ();
}
void
RecentConfigurationPage::commit_recent (lay::Dispatcher *root)
{
std::vector<std::string> values;
values.reserve (m_cfg.size ());
for (std::list<ConfigurationDescriptor>::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c) {
if (c->rendering == Layer) {
std::string s;
if (!(mp_view->current_layer ().is_null () || mp_view->current_layer ().at_end ()) && mp_view->current_layer ()->is_visual ()) {
int cv_index = mp_view->current_layer ()->cellview_index ();
const lay::CellView &cv = mp_view->cellview (cv_index);
int li = mp_view->current_layer ()->layer_index ();
if (cv.is_valid () && cv->layout ().is_valid_layer (li)) {
s = cv->layout ().get_properties (li).to_string ();
if (cv_index > 0) {
s += "@" + tl::to_string (cv_index);
}
}
}
values.push_back (s);
} else {
values.push_back (root->config_get (c->cfg_name));
}
}
std::list<std::vector<std::string> > stored_values = get_stored_values ();
for (std::list<std::vector<std::string> >::iterator v = stored_values.begin (); v != stored_values.end (); ++v) {
if (*v == values) {
stored_values.erase (v);
break;
}
}
stored_values.push_front (values);
while (stored_values.size () > max_entries) {
stored_values.erase (--stored_values.end ());
}
set_stored_values (stored_values);
update_list (stored_values);
}
}

View File

@ -0,0 +1,115 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_edtRecentConfigurationPage
#define HDR_edtRecentConfigurationPage
#include "layEditorOptionsPage.h"
#include "tlObject.h"
#include <list>
#include <QTreeWidget>
namespace lay
{
class LayoutView;
}
namespace edt
{
class PCellParametersPage;
class EditorOptionsPages;
/**
* @brief The base class for a object properties page
*/
class RecentConfigurationPage
: public lay::EditorOptionsPage,
public tl::Object
{
Q_OBJECT
public:
enum ConfigurationRendering
{
Text = 0,
Bool = 1,
Double = 2,
Int = 3,
Layer = 4,
PCellParameters = 5,
CellLibraryName = 6,
CellDisplayName = 7,
ArrayFlag = 8,
DoubleIfArray = 9,
IntIfArray = 10
};
struct ConfigurationDescriptor
{
ConfigurationDescriptor (const std::string &_cfg_name, const std::string &_title, ConfigurationRendering _rendering)
: cfg_name (_cfg_name), title (_title), rendering (_rendering)
{ }
std::string cfg_name, title;
ConfigurationRendering rendering;
};
template <class Iter>
RecentConfigurationPage (lay::LayoutView *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name, Iter begin_cfg, Iter end_cfg)
: EditorOptionsPage (dispatcher), mp_view (view), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg)
{
init ();
}
virtual ~RecentConfigurationPage ();
virtual std::string title () const;
virtual int order () const;
virtual void apply (lay::Dispatcher * /*root*/) { }
virtual void setup (lay::Dispatcher * /*root*/) { }
virtual void commit_recent (lay::Dispatcher *root);
private slots:
void item_clicked (QTreeWidgetItem *item);
private:
lay::LayoutView *mp_view;
std::string m_recent_cfg_name;
std::list<ConfigurationDescriptor> m_cfg;
QTreeWidget *mp_tree_widget;
void init ();
void update_list (const std::list<std::vector<std::string> > &stored_values);
std::list<std::vector<std::string> > get_stored_values () const;
void set_stored_values (const std::list<std::vector<std::string> > &values) const;
void render_to (QTreeWidgetItem *item, int column, const std::vector<std::string> &values, RecentConfigurationPage::ConfigurationRendering rendering);
void layers_changed (int);
};
}
#endif

View File

@ -60,49 +60,8 @@ ac_from_buttons (unsigned int buttons)
// -------------------------------------------------------------
std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> &parameters)
{
std::string param;
param = "!"; // flags PCells
for (std::map<std::string, tl::Variant>::const_iterator p = parameters.begin (); p != parameters.end (); ++p) {
param += tl::to_word_or_quoted_string (p->first);
param += ":";
param += p->second.to_parsable_string ();
param += ";";
}
return param;
}
std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::string &s)
{
tl::Extractor ex (s.c_str ());
std::map<std::string, tl::Variant> pm;
ex.test ("!");
try {
while (! ex.at_end ()) {
std::string n;
ex.read_word_or_quoted (n);
ex.test (":");
ex.read (pm.insert (std::make_pair (n, tl::Variant ())).first->second);
ex.test (";");
}
} catch (...) {
// ignore errors
}
return pm;
}
// -------------------------------------------------------------
Service::Service (db::Manager *manager, lay::LayoutView *view, db::ShapeIterator::flags_type flags)
: lay::ViewService (view->view_object_widget ()),
lay::Editable (view),
lay::Plugin (view),
: lay::EditorServiceBase (view),
db::Object (manager),
mp_view (view),
mp_transient_marker (0),
@ -122,9 +81,7 @@ Service::Service (db::Manager *manager, lay::LayoutView *view, db::ShapeIterator
}
Service::Service (db::Manager *manager, lay::LayoutView *view)
: lay::ViewService (view->view_object_widget ()),
lay::Editable (view),
lay::Plugin (view),
: lay::EditorServiceBase (view),
db::Object (manager),
mp_view (view),
mp_transient_marker (0),
@ -217,18 +174,30 @@ Service::snap (const db::DPoint &p, const db::DPoint &plast, bool connect) const
const int sr_pixels = 8; // TODO: make variable
db::DPoint
Service::snap2 (const db::DPoint &p) const
lay::PointSnapToObjectResult
Service::snap2_details (const db::DPoint &p) const
{
double snap_range = widget ()->mouse_event_trans ().inverted ().ctrans (sr_pixels);
return lay::obj_snap (m_snap_to_objects ? view () : 0, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, snap_range).second;
return lay::obj_snap (m_snap_to_objects ? view () : 0, p, m_edit_grid == db::DVector () ? m_global_grid : m_edit_grid, snap_range);
}
db::DPoint
Service::snap2 (const db::DPoint &p) const
{
return snap2_details (p).snapped_point;
}
db::DPoint
Service::snap2 (const db::DPoint &p, const db::DPoint &plast, bool connect) const
{
double snap_range = widget ()->mouse_event_trans ().inverted ().ctrans (sr_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).second;
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;
}
void
Service::service_configuration_changed ()
{
// The base class implementation does nothing
}
bool
@ -238,27 +207,60 @@ Service::configure (const std::string &name, const std::string &value)
edt::ACConverter acc;
if (name == cfg_edit_global_grid) {
egc.from_string (value, m_global_grid);
service_configuration_changed ();
} else if (name == cfg_edit_show_shapes_of_instances) {
tl::from_string (value, m_show_shapes_of_instances);
service_configuration_changed ();
} else if (name == cfg_edit_max_shapes_of_instances) {
tl::from_string (value, m_max_shapes_of_instances);
service_configuration_changed ();
} else if (name == cfg_edit_grid) {
egc.from_string (value, m_edit_grid);
service_configuration_changed ();
return true; // taken
} else if (name == cfg_edit_snap_to_objects) {
tl::from_string (value, m_snap_to_objects);
service_configuration_changed ();
return true; // taken
} else if (name == cfg_edit_move_angle_mode) {
acc.from_string (value, m_move_ac);
service_configuration_changed ();
return true; // taken
} else if (name == cfg_edit_connect_angle_mode) {
acc.from_string (value, m_connect_ac);
service_configuration_changed ();
return true; // taken
} else if (name == cfg_edit_top_level_selection) {
tl::from_string (value, m_top_level_sel);
service_configuration_changed ();
} else if (name == cfg_edit_hier_copy_mode) {
tl::from_string (value, m_hier_copy_mode);
service_configuration_changed ();
} else {
lay::EditorServiceBase::configure (name, value);
}
return false; // not taken
@ -710,14 +712,15 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio)
// in this mode, ignore exceptions here since it is rather annoying to have messages popping
// up then.
try {
do_begin_edit (p);
m_editing = true;
begin_edit (p);
} catch (...) {
set_edit_marker (0);
}
}
if (m_editing) {
do_mouse_move (p);
} else {
do_mouse_move_inactive (p);
}
m_alt_ac = lay::AC_Global;
@ -744,8 +747,7 @@ Service::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio
view ()->cancel (); // cancel any pending edit operations and clear the selection
set_edit_marker (0);
do_begin_edit (p);
m_editing = true;
begin_edit (p);
} else {
if (do_mouse_click (p)) {
@ -797,22 +799,21 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio
void
Service::activated ()
{
// make all editor option pages visible
activate_service (plugin_declaration (), true);
if (view ()->is_editable ()) {
view ()->cancel (); // cancel any pending edit operations and clear the selection
set_edit_marker (0);
m_immediate = do_activated ();
m_editing = false;
}
}
void
Service::deactivated ()
{
// make all editor option pages visible
activate_service (plugin_declaration (), false);
lay::EditorServiceBase::deactivated ();
edit_cancel ();
@ -1432,6 +1433,19 @@ Service::move_markers (const db::DTrans &t)
}
}
void
Service::begin_edit (const db::DPoint &p)
{
do_begin_edit (p);
m_editing = true;
}
void
Service::tap (const db::DPoint & /*initial*/)
{
// .. nothing here ..
}
void
Service::selection_to_view ()
{

View File

@ -27,9 +27,8 @@
#include "edtCommon.h"
#include "layEditable.h"
#include "layEditorServiceBase.h"
#include "layPlugin.h"
#include "layViewObject.h"
#include "layMarker.h"
#include "laySnap.h"
#include "layObjectInstPath.h"
@ -44,12 +43,14 @@
#include <vector>
#include <QColor>
namespace lay {
class LayerPropertiesConstIterator;
}
namespace edt {
class Service;
class PluginDeclarationBase;
class EditorOptionsPages;
class EditorOptionsPage;
// -------------------------------------------------------------
@ -70,9 +71,7 @@ std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::stri
// -------------------------------------------------------------
class EDT_PUBLIC Service
: public lay::ViewService,
public lay::Editable,
public lay::Plugin,
: public lay::EditorServiceBase,
public db::Object
{
public:
@ -216,22 +215,6 @@ public:
return m_color;
}
/**
* @brief Obtain the lay::ViewService interface
*/
lay::ViewService *view_service_interface ()
{
return this;
}
/**
* @brief Obtain the lay::Editable interface
*/
lay::Editable *editable_interface ()
{
return this;
}
/**
* @brief Get the selection container
*/
@ -344,6 +327,11 @@ public:
*/
virtual void edit_cancel ();
/**
* @brief Triggered by tap - gives the new layer and if required the initial point
*/
virtual void tap (const db::DPoint &initial);
/**
* @brief Delete the selected rulers
*
@ -383,6 +371,11 @@ protected:
*/
void selection_to_view ();
/**
* @brief starts editing at the given point.
*/
void begin_edit (const db::DPoint &p);
/**
* @brief Reimplemented by the specific implementation of the shape editors
*
@ -441,6 +434,11 @@ protected:
*/
virtual void do_cancel_edit () { }
/**
* @brief Called when a configuration parameter provided by the service base class has changed
*/
virtual void service_configuration_changed ();
/**
* @brief Install a marker for representing the edited object
*
@ -528,6 +526,16 @@ protected:
return m_max_shapes_of_instances;
}
bool editing () const
{
return m_editing;
}
/**
* @brief Point snapping with detailed return value
*/
lay::PointSnapToObjectResult snap2_details (const db::DPoint &p) const;
private:
// The layout view that the editor service is attached to
lay::LayoutView *mp_view;

View File

@ -25,8 +25,8 @@
#include "edtServiceImpl.h"
#include "edtPropertiesPages.h"
#include "edtInstPropertiesPage.h"
#include "edtPCellParametersDialog.h"
#include "edtService.h"
#include "edtPlugin.h"
#include "dbEdge.h"
#include "dbLibrary.h"
#include "dbLibraryManager.h"
@ -51,7 +51,7 @@ ShapeEditService::ShapeEditService (db::Manager *manager, lay::LayoutView *view,
: edt::Service (manager, view, shape_types),
m_layer (0), m_cv_index (0), mp_cell (0), mp_layout (0), m_combine_mode (CM_Add)
{
// .. nothing yet ..
view->current_layer_changed_event.add (this, &ShapeEditService::update_edit_layer);
}
bool
@ -69,17 +69,11 @@ void
ShapeEditService::get_edit_layer ()
{
lay::LayerPropertiesConstIterator cl = view ()->current_layer ();
if (cl.is_null ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Please select a layer first")));
}
if (! cl->visible (true)) {
lay::TipDialog td (QApplication::activeWindow (),
tl::to_string (QObject::tr ("You are about to draw on a hidden layer. The result won't be visible.")),
"drawing-on-invisible-layer");
td.exec_dialog ();
}
int cv_index = cl->cellview_index ();
const lay::CellView &cv = view ()->cellview (cv_index);
int layer = cl->layer_index ();
@ -88,6 +82,13 @@ ShapeEditService::get_edit_layer ()
throw tl::Exception (tl::to_string (QObject::tr ("Please select a cell first")));
}
if (! cl->visible (true)) {
lay::TipDialog td (QApplication::activeWindow (),
tl::to_string (QObject::tr ("You are about to draw on a hidden layer. The result won't be visible.")),
"drawing-on-invisible-layer");
td.exec_dialog ();
}
if (layer < 0 || ! cv->layout ().is_valid_layer ((unsigned int) layer)) {
if (cl->has_children ()) {
@ -128,6 +129,79 @@ ShapeEditService::get_edit_layer ()
}
}
void
ShapeEditService::update_edit_layer (const lay::LayerPropertiesConstIterator &cl)
{
if (! editing ()) {
return;
}
if (cl.is_null () || cl->has_children ()) {
return;
}
int cv_index = cl->cellview_index ();
const lay::CellView &cv = view ()->cellview (cv_index);
int layer = cl->layer_index ();
if (cv_index < 0 || ! cv.is_valid ()) {
return;
}
if (cv->layout ().cell (cv.cell_index ()).is_proxy ()) {
return;
}
if (! cl->visible (true)) {
lay::TipDialog td (QApplication::activeWindow (),
tl::to_string (QObject::tr ("You are now drawing on a hidden layer. The result won't be visible.")),
"drawing-on-invisible-layer");
td.exec_dialog ();
}
if (layer < 0 || ! cv->layout ().is_valid_layer ((unsigned int) layer)) {
// create this layer now
const lay::ParsedLayerSource &source = cl->source (true /*real*/);
db::LayerProperties db_lp;
if (source.has_name ()) {
db_lp.name = source.name ();
}
db_lp.layer = source.layer ();
db_lp.datatype = source.datatype ();
cv->layout ().insert_layer (db_lp);
// update the layer index inside the layer view
cl->realize_source ();
// Hint: we could have taken the new index from insert_layer, but this
// is a nice test:
layer = cl->layer_index ();
tl_assert (layer >= 0);
}
m_layer = (unsigned int) layer;
m_cv_index = (unsigned int) cv_index;
m_trans = (cl->trans ().front () * db::CplxTrans (cv->layout ().dbu ()) * cv.context_trans ()).inverted ();
mp_layout = &(cv->layout ());
mp_cell = &(mp_layout->cell (cv.cell_index ()));
current_layer_changed ();
}
void
ShapeEditService::tap (const db::DPoint &initial)
{
if (editing ()) {
get_edit_layer ();
} else {
begin_edit (initial);
}
}
/**
* @brief Deliver a good interpolation between two points m and p
*
@ -339,9 +413,18 @@ PolygonService::set_last_point (const db::DPoint &p)
}
}
void
void
PolygonService::do_mouse_move_inactive (const db::DPoint &p)
{
lay::PointSnapToObjectResult snap_details = snap2_details (p);
mouse_cursor_from_snap_details (snap_details);
}
void
PolygonService::do_mouse_move (const db::DPoint &p)
{
do_mouse_move_inactive (p);
set_cursor (lay::Cursor::cross);
if (m_points.size () >= 2) {
set_last_point (p);
@ -366,6 +449,7 @@ void
PolygonService::do_finish_edit ()
{
deliver_shape (get_polygon ());
commit_recent (view ());
}
db::Polygon
@ -644,9 +728,18 @@ BoxService::update_marker ()
}
}
void
void
BoxService::do_mouse_move_inactive (const db::DPoint &p)
{
lay::PointSnapToObjectResult snap_details = snap2_details (p);
mouse_cursor_from_snap_details (snap_details);
}
void
BoxService::do_mouse_move (const db::DPoint &p)
{
do_mouse_move_inactive (p);
set_cursor (lay::Cursor::cross);
m_p2 = snap2 (p);
update_marker ();
@ -663,6 +756,7 @@ void
BoxService::do_finish_edit ()
{
deliver_shape (get_box ());
commit_recent (view ());
}
void
@ -738,18 +832,21 @@ TextService::do_activated ()
{
m_rot = 0;
// Show editor options dialog to allow entering of width
std::vector<edt::MainService *> edt_main_services = view ()->get_plugins <edt::MainService> ();
if (edt_main_services.size () > 0) {
edt_main_services [0]->cm_edit_options ();
}
return true; // start editing immediately
}
void
void
TextService::do_mouse_move_inactive (const db::DPoint &p)
{
lay::PointSnapToObjectResult snap_details = snap2_details (p);
mouse_cursor_from_snap_details (snap_details);
}
void
TextService::do_mouse_move (const db::DPoint &p)
{
do_mouse_move_inactive (p);
set_cursor (lay::Cursor::cross);
m_text.trans (db::DTrans (m_rot, snap2 (p) - db::DPoint ()));
update_marker ();
@ -786,6 +883,8 @@ TextService::do_finish_edit ()
cell ().shapes (layer ()).insert (get_text ());
manager ()->commit ();
commit_recent (view ());
if (! view ()->text_visible ()) {
lay::TipDialog td (QApplication::activeWindow (),
@ -904,12 +1003,6 @@ PathService::do_begin_edit (const db::DPoint &p)
bool
PathService::do_activated ()
{
// Show editor options dialog to allow entering of width
std::vector<edt::MainService *> edt_main_services = view ()->get_plugins <edt::MainService> ();
if (edt_main_services.size () > 0) {
edt_main_services [0]->cm_edit_options ();
}
return false; // don't start editing immediately
}
@ -935,9 +1028,18 @@ PathService::set_last_point (const db::DPoint &p)
}
}
void
void
PathService::do_mouse_move_inactive (const db::DPoint &p)
{
lay::PointSnapToObjectResult snap_details = snap2_details (p);
mouse_cursor_from_snap_details (snap_details);
}
void
PathService::do_mouse_move (const db::DPoint &p)
{
do_mouse_move_inactive (p);
set_cursor (lay::Cursor::cross);
if (m_points.size () >= 2) {
set_last_point (p);
@ -966,6 +1068,8 @@ PathService::do_finish_edit ()
m_points.pop_back ();
deliver_shape (get_path ());
commit_recent (view ());
}
void
@ -1094,7 +1198,7 @@ InstService::InstService (db::Manager *manager, lay::LayoutView *view)
m_array (false), m_rows (1), m_columns (1),
m_row_x (0.0), m_row_y (0.0), m_column_x (0.0), m_column_y (0.0),
m_place_origin (false), m_reference_transaction_id (0),
m_needs_update (true), m_has_valid_cell (false), m_in_drag_drop (false),
m_needs_update (true), m_parameters_changed (false), m_has_valid_cell (false), m_in_drag_drop (false),
m_current_cell (0), mp_current_layout (0), mp_pcell_decl (0), m_cv_index (-1)
{
// .. nothing yet ..
@ -1109,12 +1213,6 @@ InstService::properties_page (db::Manager *manager, QWidget *parent)
bool
InstService::do_activated ()
{
// Show editor options dialog to allow entering of parameters
std::vector<edt::MainService *> edt_main_services = view ()->get_plugins <edt::MainService> ();
if (edt_main_services.size () > 0) {
edt_main_services [0]->cm_edit_options ();
}
m_cv_index = view ()->active_cellview_index ();
m_has_valid_cell = false;
@ -1137,63 +1235,69 @@ InstService::get_default_layer_for_pcell ()
bool
InstService::drag_enter_event (const db::DPoint &p, const lay::DragDropDataBase *data)
{
{
const lay::CellDragDropData *cd = dynamic_cast <const lay::CellDragDropData *> (data);
if (view ()->is_editable () && cd && (cd->layout () == & view ()->active_cellview ()->layout () || cd->library ())) {
view ()->cancel ();
set_edit_marker (0);
m_cv_index = view ()->active_cellview_index ();
m_in_drag_drop = true;
bool switch_parameters = true;
// configure from the drag/drop data
if (cd->library ()) {
// Reject drag & drop if the target technology does not match
if (cd->library ()->for_technologies () && view ()->cellview (view ()->active_cellview_index ()).is_valid ()) {
if (! cd->library ()->is_for_technology (view ()->cellview (view ()->active_cellview_index ())->tech_name ())) {
return false;
}
}
if (m_lib_name != cd->library ()->get_name ()) {
m_lib_name = cd->library ()->get_name ();
m_pcell_parameters.clear ();
}
} else {
m_lib_name.clear ();
}
m_is_pcell = false;
if (cd->is_pcell ()) {
const db::PCellDeclaration *pcell_decl = cd->layout ()->pcell_declaration (cd->cell_index ());
if (pcell_decl) {
if (! pcell_decl) {
return false;
}
if (m_cell_or_pcell_name != pcell_decl->name ()) {
m_cell_or_pcell_name = pcell_decl->name ();
m_pcell_parameters.clear ();
}
m_is_pcell = true;
// NOTE: we reuse previous parameters for convenience unless PCell or library has changed
const std::vector<db::PCellParameterDeclaration> &pd = pcell_decl->parameter_declarations();
for (std::vector<db::PCellParameterDeclaration>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
if (i->get_type () == db::PCellParameterDeclaration::t_layer && !i->is_hidden () && !i->is_readonly () && i->get_default ().is_nil ()) {
m_pcell_parameters.insert (std::make_pair (i->get_name (), get_default_layer_for_pcell ()));
} else {
m_pcell_parameters.insert (std::make_pair (i->get_name (), i->get_default ()));
}
}
do_begin_edit (p);
return true;
if (m_cell_or_pcell_name != pcell_decl->name ()) {
m_cell_or_pcell_name = pcell_decl->name ();
}
if (! cd->pcell_params ().empty ()) {
m_pcell_parameters = pcell_decl->named_parameters (cd->pcell_params ());
switch_parameters = false;
}
} else if (cd->layout ()->is_valid_cell_index (cd->cell_index ())) {
m_cell_or_pcell_name = cd->layout ()->cell_name (cd->cell_index ());
do_begin_edit (p);
return true;
} else {
return false;
}
switch_cell_or_pcell (switch_parameters);
sync_to_config ();
m_in_drag_drop = true;
view ()->switch_mode (plugin_declaration ()->id ());
do_begin_edit (p);
// action taken.
return true;
}
return false;
@ -1210,7 +1314,7 @@ InstService::drag_move_event (const db::DPoint &p, const lay::DragDropDataBase *
}
}
void
void
InstService::drag_leave_event ()
{
if (m_in_drag_drop) {
@ -1219,7 +1323,7 @@ InstService::drag_leave_event ()
}
}
bool
bool
InstService::selection_applies (const lay::ObjectInstPath &sel) const
{
return sel.is_cell_inst ();
@ -1228,53 +1332,8 @@ InstService::selection_applies (const lay::ObjectInstPath &sel) const
bool
InstService::drop_event (const db::DPoint & /*p*/, const lay::DragDropDataBase * /*data*/)
{
if (m_in_drag_drop) {
const lay::CellView &cv = view ()->cellview (m_cv_index);
if (! cv.is_valid ()) {
return false;
}
make_cell (cv);
bool accepted = true;
if (m_has_valid_cell && mp_pcell_decl) {
std::vector<tl::Variant> pv = mp_pcell_decl->map_parameters (m_pcell_parameters);
// Turn off the drag cursor for the modal dialog
QApplication::restoreOverrideCursor ();
// for PCells dragged show the parameter dialog for a chance to edit the initial parameters
if (! mp_pcell_parameters_dialog.get ()) {
mp_pcell_parameters_dialog.reset (new edt::PCellParametersDialog (view ()));
mp_pcell_parameters_dialog->parameters_changed_event.add (this, &InstService::apply_edits);
}
if (! mp_pcell_parameters_dialog->exec (mp_current_layout, view (), m_cv_index, mp_pcell_decl, pv)) {
accepted = false;
} else {
m_has_valid_cell = false;
m_pcell_parameters = mp_pcell_decl->named_parameters (mp_pcell_parameters_dialog->get_parameters ());
}
}
set_edit_marker (0);
if (accepted) {
do_finish_edit ();
} else {
do_cancel_edit ();
}
sync_to_config ();
return true;
} else {
return false;
}
m_in_drag_drop = false;
return false;
}
void
@ -1337,10 +1396,6 @@ InstService::do_begin_edit (const db::DPoint &p)
m_trans = db::VCplxTrans (1.0 / cv->layout ().dbu ()) * tv [0] * db::CplxTrans (cv->layout ().dbu ()) * cv.context_trans ();
}
lay::Marker *marker = new lay::Marker (view (), m_cv_index, ! show_shapes_of_instances (), show_shapes_of_instances () ? max_shapes_of_instances () : 0);
marker->set_vertex_shape (lay::ViewOp::Cross);
marker->set_vertex_size (9 /*cross vertex size*/);
set_edit_marker (marker);
update_marker ();
}
@ -1426,9 +1481,18 @@ InstService::make_cell (const lay::CellView &cv)
return std::pair<bool, db::cell_index_type> (true, inst_cell_index);
}
void
void
InstService::do_mouse_move_inactive (const db::DPoint &p)
{
clear_mouse_cursors ();
add_mouse_cursor (snap (p));
}
void
InstService::do_mouse_move (const db::DPoint &p)
{
do_mouse_move_inactive (p);
set_cursor (lay::Cursor::cross);
const lay::CellView &cv = view ()->cellview (m_cv_index);
@ -1470,6 +1534,14 @@ InstService::do_mouse_transform (const db::DPoint &p, db::DFTrans trans)
m_column_x = c.x ();
m_column_y = c.y ();
dispatcher ()->config_set (cfg_edit_inst_angle, m_angle);
dispatcher ()->config_set (cfg_edit_inst_mirror, m_mirror);
dispatcher ()->config_set (cfg_edit_inst_row_x, m_row_x);
dispatcher ()->config_set (cfg_edit_inst_row_y, m_row_y);
dispatcher ()->config_set (cfg_edit_inst_column_x, m_column_x);
dispatcher ()->config_set (cfg_edit_inst_column_y, m_column_y);
dispatcher ()->config_end ();
// honour the new transformation
do_mouse_move (p);
}
@ -1510,6 +1582,8 @@ InstService::do_finish_edit ()
cv->layout ().cleanup ();
manager ()->commit ();
commit_recent (view ());
if (m_in_drag_drop) {
lay::ObjectInstPath sel;
@ -1545,6 +1619,8 @@ InstService::do_cancel_edit ()
m_has_valid_cell = false;
m_in_drag_drop = false;
set_edit_marker (0);
// clean up any proxy cells created so far
const lay::CellView &cv = view ()->cellview (m_cv_index);
if (cv.is_valid ()) {
@ -1552,132 +1628,307 @@ InstService::do_cancel_edit ()
}
}
void
InstService::service_configuration_changed ()
{
m_needs_update = true;
}
bool
InstService::configure (const std::string &name, const std::string &value)
{
if (name == cfg_edit_inst_cell_name) {
m_cell_or_pcell_name = value;
m_needs_update = true;
if (value != m_cell_or_pcell_name) {
m_cell_or_pcell_name = value;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_lib_name) {
m_lib_name = value;
m_needs_update = true;
if (value != m_lib_name) {
m_lib_name_previous = m_lib_name;
m_lib_name = value;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_pcell_parameters) {
m_pcell_parameters = pcell_parameters_from_string (value);
m_is_pcell = ! value.empty ();
std::map<std::string, tl::Variant> pcp = pcell_parameters_from_string (value);
if (pcp != m_pcell_parameters) {
m_pcell_parameters = pcp;
m_is_pcell = ! value.empty ();
m_needs_update = true;
m_parameters_changed = true;
}
m_needs_update = true;
return true; // taken
}
if (name == cfg_edit_inst_place_origin) {
tl::from_string (value, m_place_origin);
m_needs_update = true;
bool f;
tl::from_string (value, f);
if (f != m_place_origin) {
m_place_origin = f;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_scale) {
tl::from_string (value, m_scale);
m_needs_update = true;
double s;
tl::from_string (value, s);
if (fabs (s - m_scale) > 1e-10) {
m_scale = s;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_angle) {
tl::from_string (value, m_angle);
m_needs_update = true;
double a;
tl::from_string (value, a);
if (fabs (a - m_angle) > 1e-10) {
m_angle = a;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_mirror) {
tl::from_string (value, m_mirror);
m_needs_update = true;
bool f;
tl::from_string (value, f);
if (f != m_mirror) {
m_mirror = f;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_array) {
tl::from_string (value, m_array);
m_needs_update = true;
bool f;
tl::from_string (value, f);
if (f != m_array) {
m_array = f;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_rows) {
tl::from_string (value, m_rows);
m_needs_update = true;
unsigned int v;
tl::from_string (value, v);
if (v != m_rows) {
m_rows = v;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_row_x) {
tl::from_string (value, m_row_x);
m_needs_update = true;
double v;
tl::from_string (value, v);
if (! db::coord_traits<double>::equal (m_row_x, v)) {
m_row_x = v;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_row_y) {
tl::from_string (value, m_row_y);
m_needs_update = true;
double v;
tl::from_string (value, v);
if (! db::coord_traits<double>::equal (m_row_y, v)) {
m_row_y = v;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_columns) {
tl::from_string (value, m_columns);
m_needs_update = true;
unsigned int v;
tl::from_string (value, v);
if (v != m_columns) {
m_columns = v;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_column_x) {
tl::from_string (value, m_column_x);
m_needs_update = true;
double v;
tl::from_string (value, v);
if (! db::coord_traits<double>::equal (m_column_x, v)) {
m_column_x = v;
m_needs_update = true;
}
return true; // taken
}
if (name == cfg_edit_inst_column_y) {
tl::from_string (value, m_column_y);
m_needs_update = true;
double v;
tl::from_string (value, v);
if (! db::coord_traits<double>::equal (m_column_y, v)) {
m_column_y = v;
m_needs_update = true;
}
return true; // taken
}
return edt::Service::configure (name, value);
}
void
InstService::switch_cell_or_pcell (bool switch_parameters)
{
// if the library or cell name has changed, store the current pcell parameters and try to reuse
// an existing parameter set
if (! m_cell_or_pcell_name_previous.empty () && (m_cell_or_pcell_name_previous != m_cell_or_pcell_name || m_lib_name_previous != m_lib_name)) {
m_stored_pcell_parameters[std::make_pair (m_cell_or_pcell_name_previous, m_lib_name_previous)] = m_pcell_parameters;
if (switch_parameters) {
std::map<std::pair<std::string, std::string>, std::map<std::string, tl::Variant> >::const_iterator p = m_stored_pcell_parameters.find (std::make_pair (m_cell_or_pcell_name, m_lib_name));
if (p != m_stored_pcell_parameters.end ()) {
m_pcell_parameters = p->second;
} else {
m_pcell_parameters.clear ();
}
}
}
db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name);
const lay::CellView &cv = view ()->cellview (m_cv_index);
// find the layout the cell has to be looked up: that is either the layout of the current instance or
// the library selected
const db::Layout *layout = 0;
if (lib) {
layout = &lib->layout ();
} else if (cv.is_valid ()) {
layout = &cv->layout ();
}
if (layout) {
m_is_pcell = layout->pcell_by_name (m_cell_or_pcell_name.c_str ()).first;
} else {
m_is_pcell = false;
}
// remember the current cell or library name
m_cell_or_pcell_name_previous = m_cell_or_pcell_name;
m_lib_name_previous = m_lib_name;
}
void
InstService::config_finalize ()
{
if (m_needs_update) {
// don't switch parameters if they have been updated explicitly
// since the last "config_finalize". This means the sender of the configuration events
// wants the parameters to be set in a specific way. Don't interfere.
bool switch_parameters = ! m_parameters_changed;
switch_cell_or_pcell (switch_parameters);
m_has_valid_cell = false;
update_marker ();
m_needs_update = false;
if (switch_parameters) {
// Reflects any changes in PCell parameters in the configuration
// TODO: it's somewhat questionable to do this inside "config_finalize" as this method is supposed
// to reflect changes rather than induce some.
if (m_is_pcell) {
dispatcher ()->config_set (cfg_edit_inst_pcell_parameters, pcell_parameters_to_string (m_pcell_parameters));
} else {
dispatcher ()->config_set (cfg_edit_inst_pcell_parameters, std::string ());
}
}
}
m_needs_update = false;
m_parameters_changed = false;
edt::Service::config_finalize ();
}
void
InstService::apply_edits()
{
if (mp_pcell_decl && mp_pcell_parameters_dialog.get ()) {
m_pcell_parameters = mp_pcell_decl->named_parameters (mp_pcell_parameters_dialog->get_parameters ());
}
sync_to_config ();
}
void
InstService::update_marker ()
{
lay::Marker *marker = dynamic_cast<lay::Marker *> (edit_marker ());
if (marker) {
marker->set ();
if (editing ()) {
lay::Marker *marker = new lay::Marker (view (), m_cv_index, ! show_shapes_of_instances (), show_shapes_of_instances () ? max_shapes_of_instances () : 0);
marker->set_vertex_shape (lay::ViewOp::Cross);
marker->set_vertex_size (9 /*cross vertex size*/);
set_edit_marker (marker);
db::CellInstArray inst;
if (get_inst (inst)) {
marker->set (inst, m_trans);
} else {
marker->set ();
}
} else {
set_edit_marker (0);
}
}
@ -1692,14 +1943,9 @@ InstService::get_inst (db::CellInstArray &inst)
// compute the instance's transformation
db::VCplxTrans pt = (db::CplxTrans (cv->layout ().dbu ()) * m_trans).inverted ();
db::ICplxTrans trans;
if (m_in_drag_drop) {
trans = db::ICplxTrans (1.0, 0.0, false, pt * m_disp - db::Point ());
} else {
trans = db::ICplxTrans (m_scale, m_angle, m_mirror, pt * m_disp - db::Point ());
}
db::ICplxTrans trans = db::ICplxTrans (m_scale, m_angle, m_mirror, pt * m_disp - db::Point ());
if (! m_in_drag_drop && m_array && m_rows > 0 && m_columns > 0) {
if (m_array && m_rows > 0 && m_columns > 0) {
db::Vector row = db::Vector (pt * db::DVector (m_row_x, m_row_y));
db::Vector column = db::Vector (pt * db::DVector (m_column_x, m_column_y));
inst = db::CellInstArray (db::CellInst (ci.second), trans, row, column, m_rows, m_columns);

View File

@ -32,13 +32,12 @@
namespace lay
{
class CellView;
class LayerPropertiesConstIterator;
}
namespace edt
{
class PCellParametersDialog;
/**
* @brief Implementation of the edt::Service for generic shape editing
*/
@ -57,15 +56,17 @@ protected:
db::Cell &cell () const { return *mp_cell; }
db::Layout &layout () const { return *mp_layout; }
void do_mouse_move_inactive (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual void tap (const db::DPoint &initial);
virtual bool configure (const std::string &name, const std::string &value);
bool configure (const std::string &name, const std::string &value);
protected:
std::pair <bool, db::DPoint> interpolate (const db::DPoint &m, const db::DPoint &o, const db::DPoint &p) const;
void deliver_shape (const db::Polygon &poly);
void deliver_shape (const db::Path &path);
void deliver_shape (const db::Box &box);
virtual void current_layer_changed () { }
private:
db::VCplxTrans m_trans;
@ -74,6 +75,8 @@ private:
db::Cell *mp_cell;
db::Layout *mp_layout;
combine_mode_type m_combine_mode;
void update_edit_layer (const lay::LayerPropertiesConstIterator &iter);
};
/**
@ -88,6 +91,7 @@ public:
virtual lay::PropertiesPage *properties_page (db::Manager *manager, QWidget *parent);
virtual void do_begin_edit (const db::DPoint &p);
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_cancel_edit ();
@ -117,6 +121,7 @@ public:
virtual lay::PropertiesPage *properties_page (db::Manager *manager, QWidget *parent);
virtual void do_begin_edit (const db::DPoint &p);
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_cancel_edit ();
@ -143,6 +148,7 @@ public:
virtual void do_begin_edit (const db::DPoint &p);
virtual void do_mouse_transform (const db::DPoint &p, db::DFTrans trans);
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_cancel_edit ();
@ -174,6 +180,7 @@ public:
virtual void do_begin_edit (const db::DPoint &p);
virtual void do_mouse_move (const db::DPoint &p);
virtual bool do_mouse_click (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
virtual void do_finish_edit ();
virtual void do_cancel_edit ();
virtual bool do_activated ();
@ -206,6 +213,7 @@ public:
virtual lay::PropertiesPage *properties_page (db::Manager *manager, QWidget *parent);
virtual void do_begin_edit (const db::DPoint &p);
virtual void do_mouse_move_inactive (const db::DPoint &p);
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);
@ -220,6 +228,8 @@ public:
protected:
bool configure (const std::string &name, const std::string &value);
void service_configuration_changed ();
void config_finalize ();
private:
@ -228,14 +238,16 @@ private:
bool m_mirror;
db::DPoint m_disp;
std::string m_cell_or_pcell_name, m_lib_name;
std::string m_cell_or_pcell_name_previous, m_lib_name_previous;
std::map<std::string, tl::Variant> m_pcell_parameters;
std::map<std::pair<std::string, std::string>, std::map<std::string, tl::Variant> > m_stored_pcell_parameters;
bool m_is_pcell;
bool m_array;
unsigned int m_rows, m_columns;
double m_row_x, m_row_y, m_column_x, m_column_y;
bool m_place_origin;
db::Manager::transaction_id_t m_reference_transaction_id;
bool m_needs_update;
bool m_needs_update, m_parameters_changed;
bool m_has_valid_cell;
bool m_in_drag_drop;
db::cell_index_type m_current_cell;
@ -243,14 +255,13 @@ private:
const db::PCellDeclaration *mp_pcell_decl;
int m_cv_index;
db::ICplxTrans m_trans;
std::auto_ptr<edt::PCellParametersDialog> mp_pcell_parameters_dialog;
void update_marker ();
void apply_edits ();
bool get_inst (db::CellInstArray &inst);
std::pair<bool, db::cell_index_type> make_cell (const lay::CellView &cv);
tl::Variant get_default_layer_for_pcell ();
void sync_to_config ();
void switch_cell_or_pcell (bool switch_parameters);
};
}

View File

@ -26,12 +26,121 @@
#include "dbLibrary.h"
#include "edtUtils.h"
#include "edtService.h"
#include "layCellView.h"
#include "layLayoutView.h"
#include "layEditable.h"
#include "tlException.h"
namespace edt {
// -------------------------------------------------------------
std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> &parameters)
{
std::string param;
param = "!"; // flags PCells
for (std::map<std::string, tl::Variant>::const_iterator p = parameters.begin (); p != parameters.end (); ++p) {
param += tl::to_word_or_quoted_string (p->first);
param += ":";
param += p->second.to_parsable_string ();
param += ";";
}
return param;
}
std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::string &s)
{
tl::Extractor ex (s.c_str ());
std::map<std::string, tl::Variant> pm;
ex.test ("!");
try {
while (! ex.at_end ()) {
std::string n;
ex.read_word_or_quoted (n);
ex.test (":");
ex.read (pm.insert (std::make_pair (n, tl::Variant ())).first->second);
ex.test (";");
}
} catch (...) {
// ignore errors
}
return pm;
}
// -------------------------------------------------------------
// SelectionIterator implementation
SelectionIterator::SelectionIterator (lay::LayoutView *view, bool including_transient)
: m_transient_mode (false)
{
mp_edt_services = view->get_plugins <edt::Service> ();
m_current_service = mp_edt_services.begin ();
if (m_current_service != mp_edt_services.end ()) {
m_current_object = (*m_current_service)->selection ().begin ();
}
next ();
if (at_end () && including_transient) {
m_transient_mode = true;
m_current_service = mp_edt_services.begin ();
if (m_current_service != mp_edt_services.end ()) {
m_current_object = (*m_current_service)->transient_selection ().begin ();
}
next ();
}
}
bool
SelectionIterator::at_end () const
{
return m_current_service == mp_edt_services.end ();
}
void
SelectionIterator::inc ()
{
tl_assert (! at_end ());
++m_current_object;
}
void
SelectionIterator::next ()
{
if (at_end ()) {
return;
}
const edt::Service::objects *sel = m_transient_mode ? &(*m_current_service)->transient_selection () : &(*m_current_service)->selection ();
while (m_current_object == sel->end ()) {
++m_current_service;
if (m_current_service != mp_edt_services.end ()) {
sel = m_transient_mode ? &(*m_current_service)->transient_selection () : &(*m_current_service)->selection ();
m_current_object = sel->begin ();
} else {
break;
}
}
}
// -------------------------------------------------------------
// TransformationsVariants implementation
// for a lay::LayoutView

View File

@ -27,9 +27,12 @@
#include <limits>
#include <list>
#include <utility>
#include <vector>
#include <QDialog>
#include "layObjectInstPath.h"
#include "dbInstElement.h"
#include "dbClipboardData.h"
#include "dbClipboard.h"
@ -42,6 +45,18 @@ namespace lay
namespace edt {
class Service;
/**
* @brief Serializes PCell parameters to a string
*/
std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> &parameters);
/**
* @brief Deerializes PCell parameters from a string
*/
std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::string &s);
/**
* @brief Fetch PCell parameters from a cell and merge the guiding shapes into them
*
@ -79,6 +94,73 @@ private:
std::map < std::pair<unsigned int, unsigned int>, std::vector<db::DCplxTrans> > m_per_cv_and_layer_tv;
};
/**
* @brief An iterator for the selected objects of all edt services in a layout view
*/
class SelectionIterator
{
public:
typedef lay::ObjectInstPath value_type;
typedef const lay::ObjectInstPath &reference;
typedef const lay::ObjectInstPath *pointer;
/**
* @brief Creates a new iterator iterating over all selected edt objects from the given view
*
* If "including_transient" is true, the transient selection will be used as fallback.
*/
SelectionIterator (lay::LayoutView *view, bool including_transient = true);
/**
* @brief Returns a value indicating whether the transient selection is taken
*/
bool is_transient () const
{
return m_transient_mode;
}
/**
* @brief Increments the iterator
*/
void operator++ ()
{
inc ();
next ();
}
/**
* @brief Dereferencing
*/
const lay::ObjectInstPath &operator* () const
{
tl_assert (! at_end ());
return *m_current_object;
}
/**
* @brief Arrow operator
*/
const lay::ObjectInstPath *operator-> () const
{
return & operator* ();
}
/**
* @brief Returns a value indicating whether the iterator has finished
*/
bool at_end () const;
private:
void inc ();
void next ();
private:
std::vector<edt::Service *> mp_edt_services;
std::vector<edt::Service *>::const_iterator m_current_service;
std::set<lay::ObjectInstPath>::const_iterator m_current_object;
bool m_transient_mode;
};
} // namespace edt
#endif

View File

@ -0,0 +1,159 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "tlUnitTest.h"
#include "edtDistribute.h"
template <class Box, class Value>
static std::string plc2string (const edt::distributed_placer<Box, Value> &plc)
{
std::string s;
for (typename edt::distributed_placer<Box, Value>::iterator i = plc.begin (); i != plc.end (); ++i) {
if (! s.empty ()) {
s += ",";
}
s += tl::to_string (i->first);
s += "[";
s += tl::to_string (i->second);
s += "]";
}
return s;
}
TEST(1)
{
edt::distributed_placer<db::Box, size_t> placer;
placer.insert (db::Box (1000, 0, 1100, 200), 0);
placer.insert (db::Box (2000, 0, 2100, 500), 1);
placer.insert (db::Box (0, -100, 100, 100), 2);
placer.insert (db::Box (1000, 100, 1050, 250), 3);
placer.insert (db::Box (1050, -50, 1100, 150), 4);
edt::distributed_placer<db::Box, size_t> p;
p = placer;
p.distribute_h (-1, 2, 0, 100);
EXPECT_EQ (plc2string (p), "(0,-100;100,100)[2],(200,0;300,200)[0],(400,100;450,250)[3],(550,-50;600,150)[4],(700,0;800,500)[1]");
p = placer;
p.distribute_h (-1, -1, 0, 100);
EXPECT_EQ (plc2string (p), "(0,-100;100,100)[2],(200,-100;300,100)[0],(400,-100;450,50)[3],(550,-100;600,100)[4],(700,-100;800,400)[1]");
p = placer;
p.distribute_h (-1, 0, 0, 100);
EXPECT_EQ (plc2string (p), "(0,100;100,300)[2],(200,100;300,300)[0],(400,125;450,275)[3],(550,100;600,300)[4],(700,-50;800,450)[1]");
p = placer;
p.distribute_h (-1, 1, 0, 100);
EXPECT_EQ (plc2string (p), "(0,300;100,500)[2],(200,300;300,500)[0],(400,350;450,500)[3],(550,300;600,500)[4],(700,0;800,500)[1]");
p = placer;
p.distribute_h (-1, 2, 100, 0);
EXPECT_EQ (plc2string (p), "(0,-100;100,100)[2],(100,0;200,200)[0],(200,100;250,250)[3],(300,-50;350,150)[4],(400,0;500,500)[1]");
p = placer;
p.distribute_h (-1, 2, 0, 0);
EXPECT_EQ (plc2string (p), "(0,-100;100,100)[2],(100,0;200,200)[0],(200,100;250,250)[3],(250,-50;300,150)[4],(300,0;400,500)[1]");
p = placer;
p.distribute_h (1, 2, 0, 100);
EXPECT_EQ (plc2string (p), "(1300,-100;1400,100)[2],(1500,100;1550,250)[3],(1650,-50;1700,150)[4],(1800,0;1900,200)[0],(2000,0;2100,500)[1]");
p = placer;
p.distribute_v (-1, 2, 0, 100);
EXPECT_EQ (plc2string (p), "(0,-100;100,100)[2],(1050,200;1100,400)[4],(1000,500;1100,700)[0],(2000,800;2100,1300)[1],(1000,1400;1050,1550)[3]");
}
TEST(2)
{
edt::distributed_placer<db::Box, size_t> placer;
placer.insert (db::Box (-5, 1, 95, 101), 0);
placer.insert (db::Box (1, 95, 101, 195), 1);
placer.insert (db::Box (110, 105, 210, 205), 2);
placer.insert (db::Box (101, 0, 201, 100), 3);
edt::distributed_placer<db::Box, size_t> p;
p = placer;
p.distribute_matrix (-1, 0, 0, -1, 0, 0);
EXPECT_EQ (plc2string (p), "(-5,0;95,100)[0],(-5,100;95,200)[1],(95,100;195,200)[2],(95,0;195,100)[3]");
}
TEST(3)
{
edt::distributed_placer<db::Box, size_t> placer;
placer.insert (db::Box (0, 20, 1, 23), 0);
placer.insert (db::Box (3, 8, 8, 19), 1);
placer.insert (db::Box (6, 0, 12, 5), 2);
placer.insert (db::Box (13, 1, 19, 6), 3);
placer.insert (db::Box (10, 16, 11, 17), 4);
edt::distributed_placer<db::Box, size_t> p;
p = placer;
p.distribute_matrix (-1, 0, 0, -1, 0, 0);
EXPECT_EQ (plc2string (p), "(0,17;1,20)[0],(1,5;6,16)[1],(6,0;12,5)[2],(13,0;19,5)[3],(12,16;13,17)[4]");
}
TEST(4)
{
edt::distributed_placer<db::Box, size_t> placer;
placer.insert (db::Box (0, 16, 1, 20), 0);
placer.insert (db::Box (0, 8, 5, 19), 1);
placer.insert (db::Box (0, 0, 12, 5), 2);
placer.insert (db::Box (12, 1, 19, 6), 3);
placer.insert (db::Box (0, 18, 1, 19), 4);
edt::distributed_placer<db::Box, size_t> p;
p = placer;
p.distribute_matrix (-1, 0, 0, 1, 0, 0);
EXPECT_EQ (plc2string (p), "(6,9;7,13)[0],(1,9;6,20)[1],(0,4;12,9)[2],(12,4;19,9)[3],(0,9;1,10)[4]");
p = placer;
p.distribute_matrix (1, 10, 0, -1, 10, 0);
EXPECT_EQ (plc2string (p), "(-38,30;-37,34)[0],(-18,10;-13,21)[1],(-8,0;4,5)[2],(12,0;19,5)[3],(-28,30;-27,31)[4]");
p = placer;
p.distribute_matrix (1, 0, 1, 1, 0, 1);
EXPECT_EQ (plc2string (p), "(-9,16;-8,20)[0],(-7,9;-2,20)[1],(-1,3;11,8)[2],(12,3;19,8)[3],(-11,19;-10,20)[4]");
}

View File

@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri)
SOURCES = \
edtBasicTests.cc \
edtDistributeTests.cc
INCLUDEPATH += $$EDT_INC $$TL_INC $$LAYBASIC_INC $$DB_INC $$GSI_INC
DEPENDPATH += $$EDT_INC $$TL_INC $$LAYBASIC_INC $$DB_INC $$GSI_INC

View File

@ -1058,16 +1058,6 @@ p, li { white-space: pre-wrap; }
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="preview_cbx">
<property name="text">
<string>Preview (Auto apply)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
@ -1141,7 +1131,6 @@ p, li { white-space: pre-wrap; }
<tabstop>g_sb</tabstop>
<tabstop>b_slider</tabstop>
<tabstop>b_sb</tabstop>
<tabstop>preview_cbx</tabstop>
<tabstop>reset_pb</tabstop>
<tabstop>contrast_sb</tabstop>
<tabstop>gamma_sb</tabstop>

View File

@ -26,6 +26,7 @@
#include "imgStream.h"
#include "layLayoutView.h"
#include "layFileDialog.h"
#include "layQtTools.h"
#include "tlExceptions.h"
#include "tlFileUtils.h"
@ -73,6 +74,7 @@ void
PropertiesPage::init ()
{
m_no_signals = false;
m_in_color_mapping_signal = false;
setupUi (this);
@ -108,6 +110,7 @@ PropertiesPage::init ()
connect (browse_pb, SIGNAL (clicked ()), this, SLOT (browse ()));
connect (colors, SIGNAL (color_changed (std::pair<QColor, QColor>)), false_color_control, SLOT (set_current_color (std::pair<QColor, QColor>)));
connect (false_color_control, SIGNAL (selection_changed (std::pair<QColor, QColor>)), colors, SLOT (set_color (std::pair<QColor, QColor>)));
connect (false_color_control, SIGNAL (color_mapping_changed ()), this, SLOT (color_mapping_changed ()));
connect (brightness_slider, SIGNAL (valueChanged (int)), this, SLOT (brightness_slider_changed (int)));
connect (brightness_sb, SIGNAL (valueChanged (int)), this, SLOT (brightness_spinbox_changed (int)));
@ -122,15 +125,22 @@ PropertiesPage::init ()
connect (b_slider, SIGNAL (valueChanged (int)), this, SLOT (blue_slider_changed (int)));
connect (b_sb, SIGNAL (valueChanged (double)), this, SLOT (blue_spinbox_changed (double)));
connect (false_color_control, SIGNAL (color_mapping_changed ()), this, SLOT (color_mapping_changed ()));
connect (false_color_control, SIGNAL (selection_changed ()), this, SLOT (color_mapping_changed ()));
connect (from_le, SIGNAL (returnPressed ()), this, SLOT (min_max_return_pressed ()));
connect (to_le, SIGNAL (returnPressed ()), this, SLOT (min_max_return_pressed ()));
connect (value_le, SIGNAL (returnPressed ()), this, SLOT (value_return_pressed ()));
connect (from_le, SIGNAL (editingFinished ()), this, SLOT (min_max_value_changed ()));
connect (to_le, SIGNAL (editingFinished ()), this, SLOT (min_max_value_changed ()));
connect (value_le, SIGNAL (editingFinished ()), this, SLOT (value_changed ()));
connect (width_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (height_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (x_offset_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (y_offset_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (angle_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (shear_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (persp_tx_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (persp_ty_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ()));
connect (mirror_cbx, SIGNAL (clicked ()), this, SIGNAL (edited ()));
connect (reset_pb, SIGNAL (clicked ()), this, SLOT (reset_pressed ()));
connect (save_pb, SIGNAL (clicked ()), this, SLOT (save_pressed ()));
connect (preview_cbx, SIGNAL (clicked ()), this, SLOT (preview_checked ()));
connect (define_landmarks_pb, SIGNAL (clicked ()), this, SLOT (define_landmarks_pressed ()));
}
@ -202,11 +212,42 @@ PropertiesPage::readonly ()
return false;
}
void
PropertiesPage::min_max_return_pressed ()
void
PropertiesPage::get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out)
{
BEGIN_PROTECTED
bool has_error = false;
try {
tl::from_string (tl::to_string (from_le->text ()), xmin);
lay::indicate_error (from_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (from_le, &ex);
has_error = true;
}
try {
tl::from_string (tl::to_string (to_le->text ()), xmax);
lay::indicate_error (to_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (to_le, &ex);
has_error = true;
}
if (! has_error && xmin >= xmax) {
tl::Exception ex (tl::to_string (QObject::tr ("Invalid data value range (min. value must be less than max. value)")));
lay::indicate_error (from_le, &ex);
lay::indicate_error (to_le, &ex);
has_error = true;
}
if (has_error) {
has_error_out = true;
}
}
void
PropertiesPage::min_max_value_changed ()
{
value_le->setText (QString ());
value_le->setEnabled (false);
@ -214,10 +255,11 @@ BEGIN_PROTECTED
colors->set_single_mode (false);
double xmin, xmax;
tl::from_string (tl::to_string (from_le->text ()), xmin);
tl::from_string (tl::to_string (to_le->text ()), xmax);
if (xmin >= xmax) {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid data value range (min. value must be less than max. value)")));
bool has_error = false;
get_xmin_xmax (xmin, xmax, has_error);
if (has_error) {
return;
}
if (false_color_control->has_selection () && false_color_control->selected_node () > 0 && false_color_control->selected_node () < int (false_color_control->nodes ().size ()) - 1) {
@ -236,9 +278,7 @@ BEGIN_PROTECTED
recompute_histogram ();
preview ();
END_PROTECTED
emit edited ();
}
void
@ -246,22 +286,20 @@ PropertiesPage::color_mapping_changed ()
{
if (! m_no_signals) {
bool has_error = false;
value_le->setText (QString ());
value_le->setEnabled (false);
colors->setEnabled (false_color_control->has_selection ());
colors->set_single_mode (false);
try {
if (false_color_control->has_selection () && false_color_control->selected_node () > 0 && false_color_control->selected_node () < int (false_color_control->nodes ().size ()) - 1) {
if (false_color_control->has_selection () && false_color_control->selected_node () > 0 && false_color_control->selected_node () < int (false_color_control->nodes ().size ()) - 1) {
double xmin, xmax;
get_xmin_xmax (xmin, xmax, has_error);
double xmin, xmax;
tl::from_string (tl::to_string (from_le->text ()), xmin);
tl::from_string (tl::to_string (to_le->text ()), xmax);
if (xmin >= xmax) {
throw tl::Exception ("");
}
if (! has_error) {
double x = false_color_control->nodes () [false_color_control->selected_node ()].first;
double xx = x * (xmax - xmin) + xmin;
@ -269,46 +307,57 @@ PropertiesPage::color_mapping_changed ()
value_le->setText (tl::to_qstring (tl::sprintf ("%.4g", xx)));
value_le->setEnabled (true);
} else if (false_color_control->has_selection ()) {
colors->set_single_mode (true);
}
} catch (...) { }
} else if (false_color_control->has_selection ()) {
preview ();
colors->set_single_mode (true);
}
if (! has_error) {
m_in_color_mapping_signal = true;
emit edited ();
m_in_color_mapping_signal = false;
}
}
}
void
PropertiesPage::value_return_pressed ()
PropertiesPage::value_changed ()
{
BEGIN_PROTECTED
double xx = 0;
bool has_error = false;
double xmin, xmax;
tl::from_string (tl::to_string (from_le->text ()), xmin);
tl::from_string (tl::to_string (to_le->text ()), xmax);
if (xmin >= xmax) {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid data value range (min. value must be less than max. value)")));
}
get_xmin_xmax (xmin, xmax, has_error);
double x = 0.0;
tl::from_string (tl::to_string (value_le->text ()), x);
double xx = (x - xmin) / (xmax - xmin);
if (xx < 0 || xx > 1.0) {
throw tl::Exception (tl::to_string (QObject::tr ("The position entered (%g) must be between the minimum (%g) and maximum (%g) value")), x, xmin, xmax);
try {
tl::from_string (tl::to_string (value_le->text ()), x);
lay::indicate_error (value_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (value_le, &ex);
has_error = true;
}
m_no_signals = true;
false_color_control->set_current_position (xx);
m_no_signals = false;
xx = (x - xmin) / (xmax - xmin);
if (! has_error && (xx < 0 || xx > 1.0)) {
tl::Exception ex (tl::to_string (QObject::tr ("The position entered (%g) must be between the minimum (%g) and maximum (%g) value")), x, xmin, xmax);
lay::indicate_error (value_le, &ex);
has_error = true;
}
preview ();
if (! has_error) {
END_PROTECTED
m_no_signals = true;
false_color_control->set_current_position (xx);
m_no_signals = false;
emit edited ();
}
}
inline double
@ -320,6 +369,10 @@ round_to_zero (double x)
void
PropertiesPage::update ()
{
if (m_in_color_mapping_signal) {
return;
}
m_no_signals = true;
if (mp_service) {
@ -498,7 +551,7 @@ PropertiesPage::brightness_slider_changed (int value)
m_no_signals = true;
brightness_sb->setValue (value);
preview ();
emit edited ();
m_no_signals = false;
}
@ -511,7 +564,7 @@ PropertiesPage::brightness_spinbox_changed (int value)
m_no_signals = true;
brightness_slider->setValue (value);
preview ();
emit edited ();
m_no_signals = false;
}
@ -524,7 +577,7 @@ PropertiesPage::contrast_slider_changed (int value)
m_no_signals = true;
contrast_sb->setValue (value);
preview ();
emit edited ();
m_no_signals = false;
}
@ -537,7 +590,7 @@ PropertiesPage::contrast_spinbox_changed (int value)
m_no_signals = true;
contrast_slider->setValue (value);
preview ();
emit edited ();
m_no_signals = false;
}
@ -556,7 +609,7 @@ PropertiesPage::gamma_spinbox_changed (double value)
gamma_slider->setValue (50 + int (0.5 + (value - 1.0) / (max_gamma - 1.0) * 50.0));
}
preview ();
emit edited ();
m_no_signals = false;
}
@ -578,7 +631,7 @@ PropertiesPage::gamma_slider_changed (int value)
}
gamma_sb->setValue (gamma);
preview ();
emit edited ();
m_no_signals = false;
}
@ -595,7 +648,7 @@ PropertiesPage::red_slider_changed (int value)
double gain = value * 0.02;
r_sb->setValue (gain);
preview ();
emit edited ();
m_no_signals = false;
}
@ -610,7 +663,7 @@ PropertiesPage::red_spinbox_changed (double value)
m_no_signals = true;
r_slider->setValue (int (0.5 + value * 50.0));
preview ();
emit edited ();
m_no_signals = false;
}
@ -627,7 +680,7 @@ PropertiesPage::green_slider_changed (int value)
double gain = value * 0.02;
g_sb->setValue (gain);
preview ();
emit edited ();
m_no_signals = false;
}
@ -642,7 +695,7 @@ PropertiesPage::green_spinbox_changed (double value)
m_no_signals = true;
g_slider->setValue (int (0.5 + value * 50.0));
preview ();
emit edited ();
m_no_signals = false;
}
@ -659,7 +712,7 @@ PropertiesPage::blue_slider_changed (int value)
double gain = value * 0.02;
b_sb->setValue (gain);
preview ();
emit edited ();
m_no_signals = false;
}
@ -674,9 +727,9 @@ PropertiesPage::blue_spinbox_changed (double value)
m_no_signals = true;
b_slider->setValue (int (0.5 + value * 50.0));
preview ();
emit edited ();
m_no_signals = false;
m_no_signals = false;
}
void
@ -686,6 +739,7 @@ PropertiesPage::black_to_white ()
nodes.push_back (std::make_pair (0.0, std::make_pair (QColor (0, 0, 0), QColor (0, 0, 0))));
nodes.push_back (std::make_pair (1.0, std::make_pair (QColor (255, 255, 255), QColor (255, 255, 255))));
false_color_control->set_nodes (nodes);
emit edited ();
}
void
@ -695,6 +749,7 @@ PropertiesPage::white_to_black ()
nodes.push_back (std::make_pair (0.0, std::make_pair (QColor (255, 255, 255), QColor (255, 255, 255))));
nodes.push_back (std::make_pair (1.0, std::make_pair (QColor (0, 0, 0), QColor (0, 0, 0))));
false_color_control->set_nodes (nodes);
emit edited ();
}
void
@ -704,7 +759,7 @@ PropertiesPage::red_to_blue ()
nodes.push_back (std::make_pair (0.0, std::make_pair (QColor (255, 0, 0), QColor (255, 0, 0))));
nodes.push_back (std::make_pair (1.0, std::make_pair (QColor (0, 0, 255), QColor (0, 0, 255))));
false_color_control->set_nodes (nodes);
emit edited ();
}
void
@ -714,6 +769,7 @@ PropertiesPage::blue_to_red ()
nodes.push_back (std::make_pair (0.0, std::make_pair (QColor (0, 0, 255), QColor (0, 0, 255))));
nodes.push_back (std::make_pair (1.0, std::make_pair (QColor (255, 0, 0), QColor (255, 0, 0))));
false_color_control->set_nodes (nodes);
emit edited ();
}
void
@ -725,11 +781,14 @@ PropertiesPage::reverse_color_order ()
std::swap (nodes [i].second.first, nodes [nodes.size () - 1 - i].second.second);
}
false_color_control->set_nodes (nodes);
emit edited ();
}
void
PropertiesPage::apply ()
{
bool has_error = false;
db::Matrix3d matrix = mp_direct_image->matrix ();
// The observer distance for perspective distortion is the average of the images width and height.
@ -741,45 +800,89 @@ PropertiesPage::apply ()
double w = matrix.mag_x (), h = matrix.mag_y (), x = matrix.disp ().x (), y = matrix.disp ().y (),
a = matrix.angle (), sa = matrix.shear_angle (), tx = matrix.perspective_tilt_x (z), ty = matrix.perspective_tilt_y (z);
bool mirror;
if (width_le->text () != tl::to_qstring (tl::micron_to_string (matrix.mag_x ()))) {
try {
tl::from_string (tl::to_string (width_le->text ()), w);
if (w <= 0.0 || h <= 0.0) {
throw tl::Exception (tl::to_string (QObject::tr ("Pixel width or height must be positive, non-null values")));
}
lay::indicate_error (width_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (width_le, &ex);
has_error = true;
}
if (height_le->text () != tl::to_qstring (tl::micron_to_string (matrix.mag_y ()))) {
try {
tl::from_string (tl::to_string (height_le->text ()), h);
lay::indicate_error (height_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (height_le, &ex);
has_error = true;
}
if (x_offset_le->text () != tl::to_qstring (tl::micron_to_string (round_to_zero (matrix.disp ().x ())))) {
try {
tl::from_string (tl::to_string (x_offset_le->text ()), x);
lay::indicate_error (x_offset_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x_offset_le, &ex);
has_error = true;
}
if (y_offset_le->text () != tl::to_qstring (tl::micron_to_string (round_to_zero (matrix.disp ().y ())))) {
try {
tl::from_string (tl::to_string (y_offset_le->text ()), y);
lay::indicate_error (y_offset_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y_offset_le, &ex);
has_error = true;
}
if (angle_le->text () != tl::to_qstring (tl::to_string (round_to_zero (matrix.angle ())))) {
try {
tl::from_string (tl::to_string (angle_le->text ()), a);
lay::indicate_error (angle_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (angle_le, &ex);
has_error = true;
}
if (shear_le->text () != tl::to_qstring (tl::to_string (round_to_zero (matrix.shear_angle ())))) {
try {
tl::from_string (tl::to_string (shear_le->text ()), sa);
if (sa <= -45 || sa >= 45) {
throw tl::Exception (tl::to_string (QObject::tr ("The shear angle must be larger than -45 and less than 45 degree")));
}
lay::indicate_error (shear_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (shear_le, &ex);
has_error = true;
}
if (persp_tx_le->text () != tl::to_qstring (tl::to_string (round_to_zero (matrix.perspective_tilt_x (z))))) {
try {
tl::from_string (tl::to_string (persp_tx_le->text ()), tx);
if (tx <= -90 || tx >= 90) {
throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree")));
}
lay::indicate_error (persp_tx_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (persp_tx_le, &ex);
has_error = true;
}
if (persp_ty_le->text () != tl::to_qstring (tl::to_string (round_to_zero (matrix.perspective_tilt_y (z))))) {
try {
tl::from_string (tl::to_string (persp_ty_le->text ()), ty);
if (ty <= -90 || ty >= 90) {
throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree")));
}
lay::indicate_error (persp_ty_le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (persp_ty_le, &ex);
has_error = true;
}
mirror = mirror_cbx->isChecked ();
bool mirror = mirror_cbx->isChecked ();
if (w <= 0.0 || h <= 0.0) {
throw tl::Exception (tl::to_string (QObject::tr ("Pixel width or height must be positive, non-null values")));
}
double xmin, xmax;
get_xmin_xmax (xmin, xmax, has_error);
if (sa <= -45 || sa >= 45) {
throw tl::Exception (tl::to_string (QObject::tr ("The shear angle must be larger than -45 and less than 45 degree")));
}
if (tx <= -90 || tx >= 90 || ty <= -90 || ty >= 90) {
throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree")));
if (has_error) {
throw tl::Exception (tl::to_string (tr ("At least one value is invalid - see highlighted entry fields")));
}
// Compute the new observer distance
@ -790,13 +893,6 @@ PropertiesPage::apply ()
matrix = db::Matrix3d::disp (db::DVector (x, y)) * db::Matrix3d::perspective (tx, ty, z) * db::Matrix3d::rotation (a) * db::Matrix3d::shear (sa) * db::Matrix3d::mag (w, h) * db::Matrix3d::mirror (mirror);
mp_direct_image->set_matrix (matrix);
double xmin, xmax;
tl::from_string (tl::to_string (from_le->text ()), xmin);
tl::from_string (tl::to_string (to_le->text ()), xmax);
if (xmin >= xmax) {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid data value range (min. value must be less than max. value)")));
}
mp_direct_image->set_min_value (xmin);
mp_direct_image->set_max_value (xmax);
@ -891,30 +987,7 @@ PropertiesPage::reset_pressed ()
m_no_signals = false;
preview ();
}
void
PropertiesPage::preview_checked ()
{
preview ();
}
void
PropertiesPage::preview ()
{
if (preview_cbx->isChecked ()) {
BEGIN_PROTECTED_CLEANUP
apply (); // this is a HACK, because it changes the current object
END_PROTECTED_CLEANUP
{
preview_cbx->setChecked (false);
}
}
emit edited ();
}
void
@ -922,7 +995,9 @@ PropertiesPage::define_landmarks_pressed ()
{
if (mp_direct_image) {
img::LandmarksDialog dialog (this, *mp_direct_image);
dialog.exec ();
if (dialog.exec ()) {
emit edited ();
}
}
}

View File

@ -64,7 +64,7 @@ public:
private slots:
void browse ();
void value_return_pressed ();
void value_changed ();
void color_mapping_changed ();
void brightness_slider_changed (int value);
void brightness_spinbox_changed (int value);
@ -83,8 +83,7 @@ private slots:
void red_to_blue ();
void blue_to_red ();
void reverse_color_order ();
void min_max_return_pressed ();
void preview_checked ();
void min_max_value_changed ();
void reset_pressed ();
void save_pressed ();
void define_landmarks_pressed ();
@ -95,11 +94,12 @@ private:
img::Service *mp_service;
img::Object *mp_direct_image;
bool m_no_signals;
bool m_in_color_mapping_signal;
void recompute_histogram ();
void invalidate ();
void init ();
void preview ();
void get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out);
};
}

75
src/lay/lay/HelpDialog.ui Normal file
View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HelpDialog</class>
<widget class="QDialog" name="HelpDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>500</height>
</rect>
</property>
<property name="windowTitle">
<string>Assistant</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="lay::BrowserPanel" name="browser_panel" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="button_frame">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>lay::BrowserPanel</class>
<extends>QWidget</extends>
<header>layBrowserPanel.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>button_frame</sender>
<signal>rejected()</signal>
<receiver>HelpDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>436</x>
<y>487</y>
</hint>
<hint type="destinationlabel">
<x>309</x>
<y>498</y>
</hint>
</hints>
</connection>
</connections>
</ui>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 659 B

After

Width:  |  Height:  |  Size: 722 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 708 B

After

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 B

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 703 B

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 528 B

After

Width:  |  Height:  |  Size: 776 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 585 B

After

Width:  |  Height:  |  Size: 797 B

View File

@ -9,9 +9,11 @@ DEFINES += MAKE_LAY_LIBRARY
HEADERS = \
layApplication.h \
layClipDialog.h \
layControlWidgetStack.h \
layCrashMessage.h \
layFillDialog.h \
layGSIHelpProvider.h \
layHelpAboutDialog.h \
layHelpDialog.h \
layHelpProvider.h \
layHelpSource.h \
@ -25,6 +27,7 @@ HEADERS = \
layMainWindow.h \
layNavigator.h \
layProgress.h \
layProgressDialog.h \
layProgressWidget.h \
layResourceHelpProvider.h \
layRuntimeErrorForm.h \
@ -35,6 +38,7 @@ HEADERS = \
laySettingsForm.h \
layTechSetupDialog.h \
layTextProgress.h \
layTextProgressDelegate.h \
layVersion.h \
layCommon.h \
layConfig.h \
@ -57,7 +61,8 @@ HEADERS = \
layMacroEditorSetupPage.h \
layPasswordDialog.h \
layForceLink.h \
layInit.h
layInit.h \
layViewWidgetStack.h
FORMS = \
ClipDialog.ui \
@ -66,6 +71,7 @@ FORMS = \
DeleteModeDialog.ui \
FillDialog.ui \
HelpAboutDialog.ui \
HelpDialog.ui \
LogViewerDialog.ui \
MacroEditorDialog.ui \
MacroPropertiesDialog.ui \
@ -112,9 +118,11 @@ SOURCES = \
gsiDeclLayMainWindow.cc \
layApplication.cc \
layClipDialog.cc \
layControlWidgetStack.cc \
layCrashMessage.cc \
layFillDialog.cc \
layGSIHelpProvider.cc \
layHelpAboutDialog.cc \
layHelpDialog.cc \
layHelpProvider.cc \
layHelpSource.cc \
@ -128,6 +136,7 @@ SOURCES = \
layMainWindow.cc \
layNavigator.cc \
layProgress.cc \
layProgressDialog.cc \
layProgressWidget.cc \
layResourceHelpProvider.cc \
layRuntimeErrorForm.cc \
@ -139,6 +148,7 @@ SOURCES = \
laySettingsForm.cc \
layTechSetupDialog.cc \
layTextProgress.cc \
layTextProgressDelegate.cc \
layVersion.cc \
layMacroController.cc \
layTechnologyController.cc \
@ -159,7 +169,8 @@ SOURCES = \
layMacroEditorSetupPage.cc \
layPasswordDialog.cc \
layForceLink.cc \
layInit.cc
layInit.cc \
layViewWidgetStack.cc
RESOURCES = layBuildInMacros.qrc \
layHelpResources.qrc \

View File

@ -40,6 +40,9 @@ static const std::string cfg_synchronized_views ("synchronized-views");
static const std::string cfg_edit_mode ("edit-mode");
static const std::string cfg_custom_macro_paths ("custom-macro-paths");
static const std::string cfg_mru ("mru");
static const std::string cfg_mru_layer_properties ("mru-layer-properties");
static const std::string cfg_mru_sessions ("mru-sessions");
static const std::string cfg_mru_bookmarks ("mru-bookmarks");
static const std::string cfg_technologies ("technology-data");
static const std::string cfg_key_bindings ("key-bindings");
static const std::string cfg_menu_items_hidden ("menu-items-hidden");
@ -57,6 +60,7 @@ static const std::string cfg_layout_file_watcher_enabled ("layout-file-watcher-e
static const std::string cfg_window_geometry ("window-geometry");
static const std::string cfg_micron_digits ("digits-micron");
static const std::string cfg_dbu_digits ("digits-dbu");
static const std::string cfg_assistant_bookmarks ("assistant-bookmarks");
}

View File

@ -0,0 +1,141 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "layControlWidgetStack.h"
#include <QLabel>
namespace lay
{
ControlWidgetStack::ControlWidgetStack(QWidget *parent, const char *name)
: QFrame (parent), mp_current_widget (0)
{
setObjectName (QString::fromUtf8 (name));
// Background ist a simple label without a text currently
mp_bglabel = new QLabel (this);
mp_bglabel->setAutoFillBackground (true);
mp_bglabel->setAlignment (Qt::AlignVCenter | Qt::AlignHCenter);
mp_bglabel->show ();
}
void ControlWidgetStack::focusInEvent(QFocusEvent *)
{
for (size_t i = 0; i < m_widgets.size (); ++i) {
if (m_widgets [i]->isVisible ()) {
m_widgets [i]->setFocus ();
break;
}
}
}
void ControlWidgetStack::add_widget(QWidget *w)
{
m_widgets.push_back (w);
w->setParent (this);
resize_children ();
raise_widget (m_widgets.size () - 1);
int mw = 0;
for (size_t i = 0; i < m_widgets.size (); ++i) {
mw = std::max (m_widgets [i]->sizeHint ().width (), mw);
mw = std::max (m_widgets [i]->minimumWidth (), mw);
}
if (mw > minimumWidth ()) {
setMinimumWidth (mw);
resize (minimumWidth (), height ());
}
}
QSize ControlWidgetStack::sizeHint() const
{
int w = 0;
for (size_t i = 0; i < m_widgets.size (); ++i) {
w = std::max (m_widgets [i]->sizeHint ().width (), w);
}
return QSize (w, 0);
}
void ControlWidgetStack::remove_widget(size_t index)
{
if (index < m_widgets.size ()) {
if (mp_current_widget == m_widgets [index]) {
mp_current_widget = 0;
}
m_widgets.erase (m_widgets.begin () + index);
}
if (m_widgets.size () == 0) {
mp_bglabel->show ();
}
}
void ControlWidgetStack::raise_widget(size_t index)
{
mp_current_widget = 0;
bool any_visible = false;
for (size_t i = 0; i < m_widgets.size (); ++i) {
if (m_widgets [i]) {
if (i == index) {
m_widgets [i]->show ();
mp_current_widget = m_widgets [i];
any_visible = true;
} else {
m_widgets [i]->hide ();
}
}
}
if (! any_visible) {
mp_bglabel->show ();
} else {
mp_bglabel->hide ();
}
}
QWidget *ControlWidgetStack::widget(size_t index)
{
if (index < m_widgets.size ()) {
return m_widgets [index];
} else {
return 0;
}
}
QWidget *ControlWidgetStack::background_widget()
{
return mp_bglabel;
}
void ControlWidgetStack::resize_children()
{
// set the geometry of all children
for (std::vector <QWidget *>::iterator child = m_widgets.begin (); child != m_widgets.end (); ++child) {
if (*child) {
(*child)->setGeometry (0, 0, width (), height ());
}
}
mp_bglabel->setGeometry (0, 0, width (), height ());
}
}

View File

@ -0,0 +1,77 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_layControlWidgetStack
#define HDR_layControlWidgetStack
#include "layCommon.h"
#include <QFrame>
class QLabel;
namespace lay
{
class ControlWidgetStack
: public QFrame
{
public:
ControlWidgetStack (QWidget *parent = 0, const char *name = 0);
void focusInEvent (QFocusEvent *);
QSize sizeHint () const;
void add_widget (QWidget *w);
void remove_widget (size_t index);
void raise_widget (size_t index);
QWidget *widget (size_t index);
QWidget *background_widget ();
QWidget *currentWidget () const
{
return mp_current_widget;
}
size_t count () const
{
return m_widgets.size ();
}
protected:
virtual void resizeEvent (QResizeEvent *)
{
resize_children ();
}
void resize_children ();
std::vector <QWidget *> m_widgets;
QWidget *mp_current_widget;
QLabel *mp_bglabel;
};
}
#endif

View File

@ -0,0 +1,140 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "layHelpAboutDialog.h"
#include "layApplication.h"
#include "layVersion.h"
#include "layHelpSource.h" // because of escape_xml
#include "layInit.h"
#include "dbInit.h"
#include "gsiInterpreter.h"
#include "ui_HelpAboutDialog.h"
#include <list>
namespace lay
{
// ------------------------------------------------------------
// Implementation of the "help about" dialog
HelpAboutDialog::HelpAboutDialog (QWidget *parent)
: QDialog (parent)
{
mp_ui = new Ui::HelpAboutDialog ();
mp_ui->setupUi (this);
std::vector<std::string> build_options;
if (lay::ApplicationBase::instance ()->ruby_interpreter ().available ()) {
build_options.push_back (tl::to_string (tr ("Ruby interpreter ")) + lay::ApplicationBase::instance ()->ruby_interpreter ().version ());
}
if (lay::ApplicationBase::instance ()->python_interpreter ().available ()) {
build_options.push_back (tl::to_string (tr ("Python interpreter ")) + lay::ApplicationBase::instance ()->python_interpreter ().version ());
}
#if defined(HAVE_QTBINDINGS)
build_options.push_back (tl::to_string (tr ("Qt bindings for scripts")));
#endif
#if defined(HAVE_64BIT_COORD)
build_options.push_back (tl::to_string (tr ("Wide coordinates (64 bit)")));
#endif
std::string s;
s = "<html><body>";
s += "<h1>";
s += escape_xml (std::string (lay::Version::name ()) + " " + lay::Version::version ());
s += "</h1>";
std::vector<std::string> about_paras = tl::split (lay::Version::about_text (), "\n\n");
for (std::vector<std::string>::const_iterator p = about_paras.begin (); p != about_paras.end (); ++p) {
s += std::string ("<p>") + escape_xml (*p) + "</p>";
}
if (! build_options.empty ()) {
s += "<p>";
s += "<h4>";
s += escape_xml (tl::to_string (QObject::tr ("Build options:")));
s += "</h4><ul>";
for (std::vector<std::string>::const_iterator bo = build_options.begin (); bo != build_options.end (); ++bo) {
s += "<li>";
s += escape_xml (*bo);
s += "</li>";
}
s += "</ul>";
}
if (! lay::plugins ().empty () || ! db::plugins ().empty ()) {
s += "<p>";
s += "<h4>";
s += escape_xml (tl::to_string (QObject::tr ("Binary extensions:")));
s += "</h4><ul>";
for (std::list<lay::PluginDescriptor>::const_iterator pd = lay::plugins ().begin (); pd != lay::plugins ().end (); ++pd) {
s += "<li>";
if (! pd->description.empty ()) {
s += escape_xml (pd->description);
} else {
s += escape_xml (pd->path);
}
if (! pd->version.empty ()) {
s += " (" + escape_xml (pd->version) + ")";
}
s += "</li>";
}
for (std::list<db::PluginDescriptor>::const_iterator pd = db::plugins ().begin (); pd != db::plugins ().end (); ++pd) {
s += "<li>";
if (! pd->description.empty ()) {
s += escape_xml (pd->description);
} else {
s += escape_xml (pd->path);
}
if (! pd->version.empty ()) {
s += " (" + escape_xml (pd->version) + ")";
}
s += "</li>";
}
s += "</ul>";
}
s += "</body></html>";
std::string t = tl::to_string (QObject::tr ("About ")) + lay::Version::name ();
setWindowTitle (tl::to_qstring (t));
mp_ui->main->setWordWrap (true);
mp_ui->main->setText (tl::to_qstring (s));
}
HelpAboutDialog::~HelpAboutDialog ()
{
delete mp_ui;
mp_ui = 0;
}
}

View File

@ -0,0 +1,55 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_layHelpAboutDialog
#define HDR_layHelpAboutDialog
#include "layCommon.h"
#include <QDialog>
namespace Ui {
class HelpAboutDialog;
}
namespace lay
{
/**
* @brief A dialog for showing the "help about" dialog
*/
class LAY_PUBLIC HelpAboutDialog
: public QDialog
{
public:
HelpAboutDialog (QWidget *parent);
~HelpAboutDialog ();
private:
Ui::HelpAboutDialog *mp_ui;
};
}
#endif

View File

@ -24,7 +24,10 @@
#include "layHelpDialog.h"
#include "layHelpSource.h"
#include "layBrowserPanel.h"
#include "layDispatcher.h"
#include "layConfig.h"
#include "tlStaticObjects.h"
#include "ui_HelpDialog.h"
#include "tlString.h"
@ -42,35 +45,17 @@ HelpDialog::HelpDialog (QWidget *parent, bool modal)
: QDialog (modal ? parent : 0 /*show as separate window*/, modal ? Qt::WindowFlags (0) : Qt::Window /*enabled minimize button*/),
m_initialized (false)
{
mp_ui = new Ui::HelpDialog ();
mp_ui->setupUi (this);
setModal (modal);
QVBoxLayout *help_layout = new QVBoxLayout (this);
setLayout (help_layout);
setWindowTitle (QObject::tr ("Assistant"));
mp_browser_panel = new lay::BrowserPanel (this);
help_layout->addWidget (mp_browser_panel);
QSizePolicy sp = mp_browser_panel->sizePolicy ();
sp.setVerticalStretch (1);
mp_browser_panel->setSizePolicy (sp);
if (modal) {
QFrame *button_frame = new QFrame (this);
help_layout->addWidget (button_frame);
QHBoxLayout *button_layout = new QHBoxLayout (button_frame);
button_layout->setMargin (0);
QPushButton *close_button = new QPushButton (button_frame);
button_layout->addStretch (1);
button_layout->addWidget (close_button);
close_button->setText (QObject::tr ("Close"));
close_button->setDefault (false);
close_button->setAutoDefault (false);
connect (close_button, SIGNAL (clicked ()), this, SLOT (accept ()));
}
mp_ui->button_frame->setVisible (modal);
mp_ui->browser_panel->set_dispatcher (lay::Dispatcher::instance (), cfg_assistant_bookmarks);
m_def_title = windowTitle ();
connect (mp_browser_panel, SIGNAL (title_changed (const QString &)), this, SLOT (title_changed (const QString &)));
connect (mp_browser_panel, SIGNAL (url_changed (const QString &)), this, SLOT (title_changed (const QString &)));
connect (mp_ui->browser_panel, SIGNAL (title_changed (const QString &)), this, SLOT (title_changed (const QString &)));
connect (mp_ui->browser_panel, SIGNAL (url_changed (const QString &)), this, SLOT (title_changed (const QString &)));
}
HelpDialog::~HelpDialog ()
@ -82,14 +67,14 @@ void HelpDialog::title_changed (const QString &)
{
QString wt;
QString title = tl::to_qstring (mp_browser_panel->title ());
QString title = tl::to_qstring (mp_ui->browser_panel->title ());
if (title.isNull () || title.size () == 0) {
wt = m_def_title;
} else {
wt = m_def_title + QString::fromUtf8 (" - ") + title;
}
QString url = tl::to_qstring (mp_browser_panel->url ());
QString url = tl::to_qstring (mp_ui->browser_panel->url ());
if (! url.isNull () && url.size () > 0) {
wt += QString::fromUtf8 (" [") + url + QString::fromUtf8 ("]");
}
@ -100,13 +85,13 @@ void HelpDialog::title_changed (const QString &)
void HelpDialog::load (const std::string &url)
{
initialize ();
mp_browser_panel->load (url);
mp_ui->browser_panel->load (url);
}
void HelpDialog::search (const std::string &topic)
{
initialize ();
mp_browser_panel->search (topic);
mp_ui->browser_panel->search (topic);
}
void HelpDialog::showEvent (QShowEvent *)
@ -121,13 +106,13 @@ void HelpDialog::initialize ()
{
if (! m_initialized) {
m_initialized = true;
mp_browser_panel->set_search_url ("int:/search.xml", "string");
mp_ui->browser_panel->set_search_url ("int:/search.xml", "string");
if (! mp_help_source) {
mp_help_source = new lay::HelpSource ();
tl::StaticObjects::reg (&mp_help_source);
}
mp_browser_panel->set_source (mp_help_source);
mp_browser_panel->set_home ("int:/index.xml");
mp_ui->browser_panel->set_source (mp_help_source);
mp_ui->browser_panel->set_home ("int:/index.xml");
}
}

View File

@ -31,6 +31,11 @@
#include <memory>
#include <string>
namespace Ui
{
class HelpDialog;
}
namespace lay
{
@ -58,7 +63,7 @@ protected slots:
void title_changed (const QString &t);
private:
lay::BrowserPanel *mp_browser_panel;
Ui::HelpDialog *mp_ui;
QRect m_geometry;
static lay::HelpSource *mp_help_source;
QString m_def_title;

View File

@ -554,6 +554,21 @@ HelpSource::get_outline (const std::string &u)
return ol;
}
void
HelpSource::search_completers (const std::string &string, std::list<std::string> &completers)
{
size_t n = 0;
const size_t max_completers = 100;
// first produce all hits with match
for (std::vector <IndexEntry>::const_iterator i = m_index.begin (); i < m_index.end () && n < max_completers; ++i) {
if (i->normalized_key.find (string) != std::string::npos) {
completers.push_back (i->key);
++n;
}
}
}
std::string
HelpSource::next_topic (const std::string &url)
{

View File

@ -82,8 +82,9 @@ public:
virtual QImage get_image (const std::string &url);
virtual std::string get_css (const std::string &url);
virtual std::string next_topic (const std::string &url);
virtual void search_completers(const std::string &search_string, std::list<std::string> &completers);
virtual std::string next_topic (const std::string &url);
virtual std::string prev_topic (const std::string &url);
QDomDocument get_dom (const std::string &u);

View File

@ -61,6 +61,9 @@ public:
options.push_back (std::pair<std::string, std::string> (cfg_synchronized_views, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_default_grids, "0.01,0.005,0.001"));
options.push_back (std::pair<std::string, std::string> (cfg_mru, ""));
options.push_back (std::pair<std::string, std::string> (cfg_mru_sessions, ""));
options.push_back (std::pair<std::string, std::string> (cfg_mru_layer_properties, ""));
options.push_back (std::pair<std::string, std::string> (cfg_mru_bookmarks, ""));
options.push_back (std::pair<std::string, std::string> (cfg_technologies, ""));
options.push_back (std::pair<std::string, std::string> (cfg_show_navigator, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_navigator_all_hier_levels, "false"));
@ -80,6 +83,7 @@ public:
options.push_back (std::pair<std::string, std::string> (cfg_micron_digits, "5"));
options.push_back (std::pair<std::string, std::string> (cfg_dbu_digits, "2"));
options.push_back (std::pair<std::string, std::string> (cfg_reader_options_show_always, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_assistant_bookmarks, ""));
}
virtual std::vector<std::pair <std::string, ConfigPage *> > config_pages (QWidget *parent) const

File diff suppressed because it is too large Load Diff

View File

@ -20,8 +20,6 @@
*/
#ifndef HDR_layMainWindow
#define HDR_layMainWindow
@ -46,6 +44,7 @@
#include "layProgress.h"
#include "layTextProgress.h"
#include "layTechnology.h"
#include "layTextProgressDelegate.h"
#include "tlException.h"
#include "tlDeferredExecution.h"
#include "tlObjectCollection.h"
@ -61,10 +60,6 @@ class QStackedWidget;
class QDockWidget;
class QAction;
namespace Ui {
class HelpAboutDialog;
}
namespace lay {
class SettingsForm;
@ -84,38 +79,19 @@ class Navigator;
class LayerToolbox;
class MainWindow;
class HelpDialog;
class HelpAboutDialog;
class ControlWidgetStack;
class ViewWidgetStack;
class ProgressWidget;
/**
* @brief A dialog for showing the "help about" dialog
* @brief A big main window class
*
* The main window is the core UI feature of the application.
* The main window is view container, basic controller, configuration root
* and holder of many resources.
* The main window is a singleton.
*/
class LAY_PUBLIC HelpAboutDialog
: public QDialog
{
public:
HelpAboutDialog (QWidget *parent);
~HelpAboutDialog ();
private:
Ui::HelpAboutDialog *mp_ui;
};
class TextProgressDelegate
: public lay::TextProgress
{
public:
TextProgressDelegate (MainWindow *mw, int verbosity);
virtual void update_progress (tl::Progress *progress);
virtual void show_progress_bar (bool show);
virtual bool progress_wants_widget () const;
virtual void progress_add_widget (QWidget *widget);
virtual QWidget *progress_get_widget () const;
virtual void progress_remove_widget ();
private:
MainWindow *mp_mw;
};
class LAY_PUBLIC MainWindow
: public QMainWindow,
public lay::Dispatcher
@ -564,17 +540,22 @@ public:
tl::event<int> view_created_event;
/**
* @brief Add an entry to the MRU list with the initial technology
* @brief Adds an entry to the MRU list with the initial technology
*/
void add_mru (const std::string &fn);
/**
* @brief Add an entry to the MRU list
* @brief Adds an entry to the MRU list
*/
void add_mru (const std::string &fn, const std::string &tech);
/**
* @brief Get the technology used for loading or creating layouts
* @brief Adds an entry to a specific MRU list given by the "cfg" configuration option
*/
void add_to_other_mru (const std::string &fn_rel, const std::string &cfg);
/**
* @brief Gets the technology used for loading or creating layouts
*/
const std::string &initial_technology ()
{
@ -582,7 +563,7 @@ public:
}
/**
* @brief Set the initial technology used for loading or creating layouts
* @brief Sets the initial technology used for loading or creating layouts
*/
void set_initial_technology (const std::string &tech)
{
@ -637,6 +618,9 @@ public slots:
void close_current_view ();
void tab_close_requested (int);
void open_recent (size_t n);
void open_recent_session (size_t n);
void open_recent_layer_properties (size_t n);
void open_recent_bookmarks (size_t n);
void view_selected (int index);
void view_title_changed ();
@ -670,7 +654,7 @@ protected slots:
protected:
void update_content ();
void do_update_menu ();
void do_update_file_menu ();
void do_update_mru_menus ();
private:
TextProgressDelegate m_text_progress;
@ -680,9 +664,9 @@ private:
QToolBar *mp_tool_bar;
QDockWidget *mp_navigator_dock_widget;
lay::Navigator *mp_navigator;
QDockWidget *mp_hp_dock_widget, *mp_lp_dock_widget, *mp_libs_dock_widget, *mp_bm_dock_widget;
ControlWidgetStack *mp_hp_stack, *mp_lp_stack, *mp_libs_stack, *mp_bm_stack;
bool m_hp_visible, m_lp_visible, m_libs_visible, m_bm_visible, m_navigator_visible, m_layer_toolbox_visible;
QDockWidget *mp_hp_dock_widget, *mp_lp_dock_widget, *mp_libs_dock_widget, *mp_eo_dock_widget, *mp_bm_dock_widget;
ControlWidgetStack *mp_hp_stack, *mp_lp_stack, *mp_libs_stack, *mp_eo_stack, *mp_bm_stack;
bool m_hp_visible, m_lp_visible, m_libs_visible, m_eo_visible, m_bm_visible, m_navigator_visible, m_layer_toolbox_visible;
QDockWidget *mp_layer_toolbox_dock_widget;
lay::LayerToolbox *mp_layer_toolbox;
ViewWidgetStack *mp_view_stack;
@ -700,6 +684,7 @@ private:
std::vector <lay::LayoutView *> mp_views;
int m_open_mode;
std::vector<std::pair<std::string, std::string> > m_mru;
std::vector<std::string> m_mru_sessions, m_mru_layer_properties, m_mru_bookmarks;
QStatusBar *mp_status_bar;
QStackedWidget *mp_main_stack_widget;
ProgressWidget *mp_progress_widget;
@ -712,7 +697,7 @@ private:
bool m_disable_tab_selected;
bool m_exited;
tl::DeferredMethod<MainWindow> dm_do_update_menu;
tl::DeferredMethod<MainWindow> dm_do_update_file_menu;
tl::DeferredMethod<MainWindow> dm_do_update_mru_menus;
tl::DeferredMethod<MainWindow> dm_exit;
QTimer m_message_timer;
QTimer m_file_changed_timer;

View File

@ -0,0 +1,75 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "layProgressDialog.h"
#include "layProgressWidget.h"
#include <QVBoxLayout>
namespace lay
{
ProgressDialog::ProgressDialog (QWidget *parent, ProgressReporter *pr)
: QDialog (parent), mp_pr (pr)
{
QVBoxLayout *vbl = new QVBoxLayout (this);
vbl->setMargin (0);
vbl->setSpacing (0);
mp_progress_widget = new ProgressWidget (pr, this, true);
mp_progress_widget->setObjectName (QString::fromUtf8 ("progress"));
vbl->addWidget (mp_progress_widget);
setWindowTitle (QObject::tr ("Progress"));
setWindowModality (Qt::WindowModal);
}
void ProgressDialog::closeEvent (QCloseEvent *)
{
if (mp_pr) {
// NOTE: We don't kill on close for now. This creates a too easy way to scrap results.
// mp_pr->signal_break ();
// TODO: there should be a warning saying some jobs are pending.
}
}
void ProgressDialog::set_progress (tl::Progress *progress)
{
mp_progress_widget->set_progress (progress);
}
void ProgressDialog::add_widget (QWidget *widget)
{
mp_progress_widget->add_widget (widget);
}
void ProgressDialog::remove_widget ()
{
mp_progress_widget->remove_widget ();
}
QWidget *ProgressDialog::get_widget () const
{
return mp_progress_widget->get_widget ();
}
}

View File

@ -0,0 +1,61 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_layProgressDialog
#define HDR_layProgressDialog
#include "layCommon.h"
#include "tlObject.h"
#include "tlProgress.h"
#include <QDialog>
namespace lay
{
class ProgressReporter;
class ProgressWidget;
class ProgressDialog
: public QDialog,
public tl::Object
{
public:
ProgressDialog (QWidget *parent, lay::ProgressReporter *pr);
void closeEvent (QCloseEvent * /*event*/);
void set_progress (tl::Progress *progress);
void add_widget (QWidget *widget);
void remove_widget ();
QWidget *get_widget () const;
private:
lay::ProgressWidget *mp_progress_widget;
lay::ProgressReporter *mp_pr;
};
}
#endif

View File

@ -135,6 +135,8 @@
<file alias="fit_bottom.png">images/fit_bottom.png</file>
<file alias="unlocked_16.png">images/unlocked_16.png</file>
<file alias="locked_16.png">images/locked_16.png</file>
<file alias="bookmark.png">images/bookmark.png</file>
<file alias="bookmark_16.png">images/bookmark_16.png</file>
</qresource>
<qresource prefix="/syntax">
<file alias="ruby.xml">syntax/ruby.xml</file>

View File

@ -0,0 +1,73 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "layTextProgressDelegate.h"
#include "layMainWindow.h"
namespace lay
{
TextProgressDelegate::TextProgressDelegate (MainWindow *mw, int verbosity)
: lay::TextProgress (verbosity), mp_mw (mw)
{
// .. nothing yet ..
}
void TextProgressDelegate::update_progress (tl::Progress *progress)
{
if (!mp_mw->update_progress (progress)) {
lay::TextProgress::update_progress (progress);
}
}
void TextProgressDelegate::show_progress_bar (bool show)
{
if (!mp_mw->show_progress_bar (show)) {
lay::TextProgress::show_progress_bar (show);
}
}
bool TextProgressDelegate::progress_wants_widget () const
{
return mp_mw != 0 && mp_mw->progress_wants_widget ();
}
void TextProgressDelegate::progress_add_widget (QWidget *widget)
{
if (mp_mw) {
mp_mw->progress_add_widget (widget);
}
}
QWidget *TextProgressDelegate::progress_get_widget () const
{
return mp_mw ? mp_mw->progress_get_widget () : 0;
}
void TextProgressDelegate::progress_remove_widget ()
{
if (mp_mw) {
mp_mw->progress_remove_widget ();
}
}
}

View File

@ -0,0 +1,55 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_layTextProgressDelegate
#define HDR_layTextProgressDelegate
#include "layCommon.h"
#include "layTextProgress.h"
namespace lay
{
class MainWindow;
class TextProgressDelegate
: public lay::TextProgress
{
public:
TextProgressDelegate (MainWindow *mw, int verbosity);
virtual void update_progress (tl::Progress *progress);
virtual void show_progress_bar (bool show);
virtual bool progress_wants_widget () const;
virtual void progress_add_widget (QWidget *widget);
virtual QWidget *progress_get_widget () const;
virtual void progress_remove_widget ();
private:
MainWindow *mp_mw;
};
}
#endif

View File

@ -0,0 +1,103 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "layViewWidgetStack.h"
#include "layLayoutView.h"
#include <QLabel>
namespace lay
{
ViewWidgetStack::ViewWidgetStack (QWidget *parent, const char *name)
: QWidget (parent)
{
setObjectName (QString::fromUtf8 (name));
mp_bglabel = new QLabel (this);
mp_bglabel->setAutoFillBackground (true);
mp_bglabel->setText (QObject::tr ("<html><body><p><img src=\":/logo.png\"/></p><p>Use File/Open to open a layout</p></body></html>"));
mp_bglabel->setAlignment (Qt::AlignVCenter | Qt::AlignHCenter);
mp_bglabel->show ();
}
void ViewWidgetStack::add_widget (LayoutView *w)
{
m_widgets.push_back (w);
w->setParent (this);
resize_children ();
raise_widget (m_widgets.size () - 1);
updateGeometry ();
}
void ViewWidgetStack::remove_widget (size_t index)
{
if (index < m_widgets.size ()) {
m_widgets.erase (m_widgets.begin () + index);
}
if (m_widgets.size () == 0) {
mp_bglabel->show ();
}
}
void ViewWidgetStack::raise_widget (size_t index)
{
if (index < m_widgets.size ()) {
mp_bglabel->hide ();
m_widgets [index]->show ();
} else {
mp_bglabel->show ();
}
size_t i = 0;
for (std::vector <LayoutView *>::iterator child = m_widgets.begin (); child != m_widgets.end (); ++child, ++i) {
if (i != index) {
(*child)->hide ();
}
}
}
LayoutView *ViewWidgetStack::widget (size_t index)
{
if (index < m_widgets.size ()) {
return m_widgets [index];
} else {
return 0;
}
}
QWidget *ViewWidgetStack::background_widget ()
{
return mp_bglabel;
}
void ViewWidgetStack::resize_children ()
{
// set the geometry of all children
for (std::vector <LayoutView *>::iterator child = m_widgets.begin (); child != m_widgets.end (); ++child) {
(*child)->setGeometry (0, 0, width (), height ());
}
mp_bglabel->setGeometry (0, 0, width (), height ());
}
}

View File

@ -0,0 +1,64 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_layViewWidgetStack
#define HDR_layViewWidgetStack
#include "layCommon.h"
#include <QWidget>
class QLabel;
namespace lay
{
class LayoutView;
class ViewWidgetStack
: public QWidget
{
public:
ViewWidgetStack (QWidget *parent = 0, const char *name = 0);
void add_widget (LayoutView *w);
void remove_widget (size_t index);
void raise_widget (size_t index);
LayoutView *widget (size_t index);
QWidget *background_widget ();
protected:
virtual void resizeEvent (QResizeEvent *)
{
resize_children ();
}
void resize_children ();
std::vector <LayoutView *> m_widgets;
QLabel *mp_bglabel;
};
}
#endif

View File

@ -29,7 +29,7 @@
<property name="spacing">
<number>2</number>
</property>
<item row="0" column="1">
<item row="0" column="5">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -45,30 +45,7 @@
</property>
</spacer>
</item>
<item row="0" column="7">
<widget class="QToolButton" name="next_topic_pb">
<property name="toolTip">
<string>Next Topic</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/next_topic.png</normaloff>:/next_topic.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="10">
<item row="1" column="0" colspan="14">
<widget class="QFrame" name="frame">
<property name="minimumSize">
<size>
@ -77,7 +54,7 @@
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
@ -100,54 +77,211 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeWidget" name="outline_tree">
<widget class="QFrame" name="frame_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="itemsExpandable">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<column>
<property name="text">
<string notr="true">1</string>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
</column>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSplitter" name="splitter_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QTreeWidget" name="outline_tree">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
<widget class="QTreeWidget" name="browser_bookmark_view">
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<column>
<property name="text">
<string>Favorites</string>
</property>
</column>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="lay::BrowserTextWidget" name="browser">
<widget class="QFrame" name="frame_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>4</horstretch>
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="lay::BrowserTextWidget" name="browser">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="search_frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string> Find on page </string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="on_page_search_next">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/find.png</normaloff>:/find.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="on_page_search_edit">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="search_close_button">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/clear_edit.png</normaloff>:/clear_edit.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="9">
<widget class="QLineEdit" name="searchEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="0" column="3">
<widget class="QToolButton" name="forward_pb">
<property name="toolTip">
<string>Forward</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/forward.png</normaloff>:/forward.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
@ -197,6 +331,22 @@
</property>
</widget>
</item>
<item row="0" column="1">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>6</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="6">
<widget class="QToolButton" name="prev_topic_pb">
<property name="toolTip">
@ -220,17 +370,47 @@
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QToolButton" name="forward_pb">
<item row="0" column="8">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="11">
<widget class="QToolButton" name="search_button">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/find.png</normaloff>:/find.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="7">
<widget class="QToolButton" name="next_topic_pb">
<property name="toolTip">
<string>Forward</string>
<string>Next Topic</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/forward.png</normaloff>:/forward.png</iconset>
<normaloff>:/next_topic.png</normaloff>:/next_topic.png</iconset>
</property>
<property name="iconSize">
<size>
@ -243,7 +423,20 @@
</property>
</widget>
</item>
<item row="0" column="8">
<item row="0" column="12">
<widget class="QLineEdit" name="search_edit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="10">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -266,23 +459,51 @@
</property>
</widget>
</item>
<item row="0" column="5">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="0" column="9">
<widget class="QToolButton" name="bookmark_pb">
<property name="toolTip">
<string>Add this location to the favorites list</string>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
<property name="text">
<string>...</string>
</property>
<property name="sizeHint" stdset="0">
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/bookmark.png</normaloff>:/bookmark.png</iconset>
</property>
<property name="iconSize">
<size>
<width>6</width>
<height>20</height>
<width>24</width>
<height>24</height>
</size>
</property>
</spacer>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
<action name="action_find">
<property name="text">
<string>Find</string>
</property>
<property name="shortcut">
<string>Ctrl+F</string>
</property>
</action>
<action name="action_bookmark">
<property name="text">
<string>Bookmark</string>
</property>
<property name="shortcut">
<string>Ctrl+B</string>
</property>
</action>
<action name="action_delete_bookmark">
<property name="text">
<string>Delete Entry</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
@ -292,7 +513,7 @@
</customwidget>
</customwidgets>
<tabstops>
<tabstop>searchEdit</tabstop>
<tabstop>search_edit</tabstop>
<tabstop>back_pb</tabstop>
<tabstop>forward_pb</tabstop>
<tabstop>home_pb</tabstop>
@ -300,5 +521,22 @@
<resources>
<include location="../../lay/lay/layResources.qrc"/>
</resources>
<connections/>
<connections>
<connection>
<sender>search_close_button</sender>
<signal>clicked()</signal>
<receiver>search_frame</receiver>
<slot>hide()</slot>
<hints>
<hint type="sourcelabel">
<x>816</x>
<y>571</y>
</hint>
<hint type="destinationlabel">
<x>371</x>
<y>577</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LayoutViewConfigPage2d</class>
<widget class="QFrame" name="LayoutViewConfigPage2d">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>608</width>
<height>318</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<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="tracking_cb">
<property name="title">
<string>Mouse tracking</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QGridLayout">
<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>
<property name="spacing">
<number>6</number>
</property>
<item row="1" column="1">
<widget class="lay::ColorButton" name="color_pb">
<property name="toolTip">
<string>The color in which the rulers are drawn</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="2">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>71</width>
<height>31</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="textLabel3_2">
<property name="text">
<string>Cursor color</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="text">
<string>With mouse tracking enabled, a cursor will appear which indicates the snapped mouse position and whether the mouse snaps to objects.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>lay::ColorButton</class>
<extends>QPushButton</extends>
<header>layWidgets.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>color_pb</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -17,7 +17,16 @@
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<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>
@ -54,7 +63,16 @@
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@ -69,7 +87,7 @@
<string>Previous</string>
</property>
<property name="icon">
<iconset resource="layResources.qrc">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/left.png</normaloff>:/left.png</iconset>
</property>
<property name="default">
@ -89,7 +107,7 @@
<string>Next</string>
</property>
<property name="icon">
<iconset resource="layResources.qrc">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/right.png</normaloff>:/right.png</iconset>
</property>
<property name="default">
@ -97,6 +115,39 @@
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="apply_to_all_cbx">
<property name="text">
<string>Change all</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="relative_cbx">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Relative</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
@ -120,20 +171,6 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="apply_button">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="apply_to_all_button">
<property name="text">
<string>Apply To All</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancel_button">
<property name="text">
@ -148,7 +185,24 @@
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
<include location="layResources.qrc"/>
<include location="../../lay/lay/layResources.qrc"/>
</resources>
<connections/>
<connections>
<connection>
<sender>apply_to_all_cbx</sender>
<signal>toggled(bool)</signal>
<receiver>relative_cbx</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>260</x>
<y>372</y>
</hint>
<hint type="destinationlabel">
<x>320</x>
<y>372</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -467,6 +467,12 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"\n"
"This constant has been introduced in version 0.27.\n"
) +
gsi::constant ("LV_NoEditorOptionsPanel", (unsigned int) lay::LayoutView::LV_NoEditorOptionsPanel,
"@brief With this option, no editor options panel will be provided (see \\editor_options_frame)\n"
"Use this value with the constructor's 'options' argument.\n"
"\n"
"This constant has been introduced in version 0.27.\n"
) +
gsi::constant ("LV_NoBookmarksView", (unsigned int) lay::LayoutView::LV_NoBookmarksView,
"@brief With this option, no bookmarks view will be provided (see \\bookmarks_frame)\n"
"Use this value with the constructor's 'options' argument.\n"

View File

@ -380,7 +380,38 @@ Bitmap::fill (unsigned int y, unsigned int x1, unsigned int x2)
}
}
struct PosCompareF
void
Bitmap::clear (unsigned int y, unsigned int x1, unsigned int x2)
{
unsigned int b1 = x1 / 32;
uint32_t *sl = scanline (y);
sl += b1;
unsigned int b = x2 / 32 - b1;
if (b == 0) {
*sl &= ~masks [x2 % 32] | masks [x1 % 32];
} else if (b > 0) {
*sl++ &= masks [x1 % 32];
while (b > 1) {
*sl++ = 0;
b--;
}
unsigned int m = masks [x2 % 32];
// Hint: if x2==width and width%32==0, sl must not be accessed. This is guaranteed by
// checking if m != 0.
if (m) {
*sl &= ~m;
}
}
}
struct PosCompareF
{
bool operator() (const RenderEdge &a, const RenderEdge &b) const
{

View File

@ -246,6 +246,17 @@ public:
*/
void fill (unsigned int y, unsigned int x1, unsigned int x2);
/**
* @brief Clears the given part of the scanline
*
* Same as fill(), but resets the bits.
*
* @param y The scanline
* @param x1 The start coordinate
* @param x2 The end coordinate
*/
void clear (unsigned int y, unsigned int x1, unsigned int x2);
/**
* @brief Merges the "from" bitmap into this
*

View File

@ -22,9 +22,11 @@
#include "layBrowserPanel.h"
#include "layDispatcher.h"
#include "tlExceptions.h"
#include "tlInternational.h"
#include "tlException.h"
#include "tlString.h"
#include "ui_BrowserPanel.h"
@ -34,6 +36,10 @@
#endif
#include <QTreeWidgetItem>
#include <QTextBlock>
#include <QCompleter>
#include <QStringListModel>
#include <QScrollBar>
namespace lay
{
@ -52,9 +58,44 @@ BrowserTextWidget::loadResource (int type, const QUrl &url)
// -------------------------------------------------------------
void
BookmarkItem::read (tl::Extractor &ex)
{
while (! ex.at_end () && ! ex.test (";")) {
std::string k, v;
ex.read_word (k);
ex.test (":");
ex.read_word_or_quoted (v, "+-.");
ex.test (",");
if (k == "url") {
url = v;
} else if (k == "title") {
title = v;
} else if (k == "position") {
tl::from_string (v, position);
}
}
}
std::string
BookmarkItem::to_string () const
{
std::string r;
r = "url:" + tl::to_quoted_string (url) + ",";
r += "title:" + tl::to_quoted_string (title) + ",";
r += "position:" + tl::to_string (position) + ";";
return r;
}
// -------------------------------------------------------------
BrowserPanel::BrowserPanel (QWidget *parent)
: QWidget (parent),
m_back_dm (this, &BrowserPanel::back)
m_back_dm (this, &BrowserPanel::back),
mp_dispatcher (0)
{
init ();
}
@ -72,21 +113,53 @@ BrowserPanel::init ()
mp_ui->browser->setReadOnly (true);
mp_ui->browser->set_panel (this);
mp_ui->browser->setWordWrapMode (QTextOption::WordWrap);
mp_ui->browser->setLineWrapMode (QTextEdit::FixedPixelWidth);
QFontMetrics fm (font ());
int text_width = fm.boundingRect ('m').width () * 80;
mp_ui->browser->setLineWrapColumnOrWidth (text_width);
mp_ui->browser->addAction (mp_ui->action_find);
mp_ui->browser->addAction (mp_ui->action_bookmark);
mp_ui->browser_bookmark_view->addAction (mp_ui->action_delete_bookmark);
mp_ui->browser_bookmark_view->setContextMenuPolicy (Qt::ActionsContextMenu);
connect (mp_ui->back_pb, SIGNAL (clicked ()), this, SLOT (back ()));
connect (mp_ui->forward_pb, SIGNAL (clicked ()), this, SLOT (forward ()));
connect (mp_ui->next_topic_pb, SIGNAL (clicked ()), this, SLOT (next ()));
connect (mp_ui->prev_topic_pb, SIGNAL (clicked ()), this, SLOT (prev ()));
connect (mp_ui->bookmark_pb, SIGNAL (clicked ()), this, SLOT (bookmark ()));
connect (mp_ui->home_pb, SIGNAL (clicked ()), this, SLOT (home ()));
connect (mp_ui->searchEdit, SIGNAL (returnPressed ()), this, SLOT (search_edited ()));
connect (mp_ui->search_edit, SIGNAL (textEdited (const QString &)), this, SLOT (search_text_changed (const QString &)));
connect (mp_ui->search_edit, SIGNAL (returnPressed ()), this, SLOT (search_edited ()));
connect (mp_ui->search_button, SIGNAL (clicked ()), this, SLOT (search_edited ()));
connect (mp_ui->browser, SIGNAL (textChanged ()), this, SLOT (text_changed ()));
connect (mp_ui->browser, SIGNAL (backwardAvailable (bool)), mp_ui->back_pb, SLOT (setEnabled (bool)));
connect (mp_ui->browser, SIGNAL (forwardAvailable (bool)), mp_ui->forward_pb, SLOT (setEnabled (bool)));
connect (mp_ui->outline_tree, SIGNAL (itemActivated (QTreeWidgetItem *, int)), this, SLOT (outline_item_clicked (QTreeWidgetItem *)));
connect (mp_ui->on_page_search_edit, SIGNAL (textChanged (const QString &)), this, SLOT (page_search_edited ()));
connect (mp_ui->search_close_button, SIGNAL (clicked ()), this, SLOT (page_search_edited ()), Qt::QueuedConnection);
connect (mp_ui->on_page_search_edit, SIGNAL (returnPressed ()), this, SLOT (page_search_next ()));
connect (mp_ui->on_page_search_next, SIGNAL (clicked ()), this, SLOT (page_search_next ()));
connect (mp_ui->action_find, SIGNAL (triggered ()), this, SLOT (find ()));
connect (mp_ui->action_bookmark, SIGNAL (triggered ()), this, SLOT (bookmark ()));
connect (mp_ui->action_delete_bookmark, SIGNAL (triggered ()), this, SLOT (delete_bookmark ()));
connect (mp_ui->browser_bookmark_view, SIGNAL (itemDoubleClicked (QTreeWidgetItem *, int)), this, SLOT (bookmark_item_selected (QTreeWidgetItem *)));
mp_ui->searchEdit->hide ();
mp_completer = new QCompleter (this);
mp_completer->setFilterMode (Qt::MatchStartsWith);
mp_completer->setCaseSensitivity (Qt::CaseInsensitive);
mp_completer->setCompletionMode (QCompleter::UnfilteredPopupCompletion);
mp_completer_model = new QStringListModel (mp_completer);
mp_completer->setModel (mp_completer_model);
mp_ui->search_edit->setCompleter (mp_completer);
mp_ui->search_frame->hide ();
mp_ui->search_edit->hide ();
set_label (std::string ());
refresh_bookmark_list ();
}
BrowserPanel::~BrowserPanel ()
@ -98,6 +171,37 @@ BrowserPanel::~BrowserPanel ()
mp_ui = 0;
}
void
BrowserPanel::set_dispatcher (lay::Dispatcher *dispatcher, const std::string &cfg_bookmarks)
{
mp_dispatcher = dispatcher;
m_cfg_bookmarks = cfg_bookmarks;
m_bookmarks.clear ();
// load the bookmarks
try {
if (mp_dispatcher) {
std::string v;
mp_dispatcher->config_get (m_cfg_bookmarks, v);
tl::Extractor ex (v.c_str ());
while (! ex.at_end ()) {
m_bookmarks.push_back (BookmarkItem ());
m_bookmarks.back ().read (ex);
}
}
} catch (...) {
// exceptions ignored here
}
refresh_bookmark_list ();
}
std::string
BrowserPanel::title () const
{
@ -110,6 +214,198 @@ BrowserPanel::url () const
return m_cached_url;
}
void
BrowserPanel::bookmark ()
{
BookmarkItem bm;
bm.url = tl::to_string (mp_ui->browser->historyUrl (0).toString ());
QString title = mp_ui->browser->document ()->metaInformation (QTextDocument::DocumentTitle);
bm.title = tl::to_string (title);
bm.position = mp_ui->browser->verticalScrollBar ()->value ();
add_bookmark (bm);
refresh_bookmark_list ();
store_bookmarks ();
}
void
BrowserPanel::store_bookmarks ()
{
if (mp_dispatcher) {
std::string s;
for (std::list<BookmarkItem>::const_iterator i = m_bookmarks.begin (); i != m_bookmarks.end (); ++i) {
s += i->to_string ();
}
mp_dispatcher->config_set (m_cfg_bookmarks, s);
}
}
void
BrowserPanel::bookmark_item_selected (QTreeWidgetItem *item)
{
int index = mp_ui->browser_bookmark_view->indexOfTopLevelItem (item);
if (index < 0 || index >= int (m_bookmarks.size ())) {
return;
}
std::list<BookmarkItem>::iterator i = m_bookmarks.begin ();
for ( ; i != m_bookmarks.end () && index > 0; --index, ++i)
;
if (i == m_bookmarks.end ()) {
return;
}
BookmarkItem bm = *i;
m_bookmarks.erase (i);
m_bookmarks.push_front (bm);
refresh_bookmark_list ();
store_bookmarks ();
load (bm.url);
mp_ui->browser->verticalScrollBar ()->setValue (bm.position);
mp_ui->browser_bookmark_view->topLevelItem (0)->setSelected (true);
}
void
BrowserPanel::clear_bookmarks ()
{
m_bookmarks.clear ();
}
void
BrowserPanel::add_bookmark (const BookmarkItem &item)
{
for (std::list<BookmarkItem>::iterator i = m_bookmarks.begin (); i != m_bookmarks.end (); ) {
std::list<BookmarkItem>::iterator ii = i;
++ii;
if (*i == item) {
m_bookmarks.erase (i);
}
i = ii;
}
m_bookmarks.push_front (item);
}
void
BrowserPanel::delete_bookmark ()
{
QTreeWidgetItem *item = mp_ui->browser_bookmark_view->currentItem ();
if (! item) {
return;
}
int index = mp_ui->browser_bookmark_view->indexOfTopLevelItem (item);
std::list<BookmarkItem>::iterator i = m_bookmarks.begin ();
for ( ; i != m_bookmarks.end () && index > 0; --index, ++i)
;
if (i != m_bookmarks.end ()) {
m_bookmarks.erase (i);
refresh_bookmark_list ();
store_bookmarks ();
}
}
void
BrowserPanel::refresh_bookmark_list ()
{
mp_ui->browser_bookmark_view->setVisible (! m_bookmarks.empty ());
mp_ui->browser_bookmark_view->clear ();
for (std::list<BookmarkItem>::const_iterator i = m_bookmarks.begin (); i != m_bookmarks.end (); ++i) {
QTreeWidgetItem *item = new QTreeWidgetItem (mp_ui->browser_bookmark_view);
item->setData (0, Qt::DisplayRole, tl::to_qstring (i->title));
item->setData (0, Qt::ToolTipRole, tl::to_qstring (i->title));
item->setData (0, Qt::DecorationRole, QIcon (":/bookmark_16.png"));
}
}
void
BrowserPanel::find ()
{
mp_ui->search_frame->show ();
mp_ui->on_page_search_edit->setFocus();
}
void
BrowserPanel::page_search_edited ()
{
m_search_selection.clear ();
m_search_index = -1;
if (! mp_ui->search_frame->isVisible () || mp_ui->on_page_search_edit->text ().size () < 2) {
mp_ui->browser->setExtraSelections (m_search_selection);
return;
}
QString search_text = mp_ui->on_page_search_edit->text ();
QTextDocument *doc = mp_ui->browser->document ();
for (QTextBlock b = doc->firstBlock (); b.isValid (); b = b.next ()) {
int from = 0;
int index;
QString t = b.text ();
while ((index = t.indexOf (search_text, from, Qt::CaseInsensitive)) >= 0) {
QTextCursor highlight (b);
highlight.movePosition (QTextCursor::NextCharacter, QTextCursor::MoveAnchor, index);
highlight.movePosition (QTextCursor::NextCharacter, QTextCursor::KeepAnchor, search_text.size ());
QTextEdit::ExtraSelection extra_selection;
extra_selection.cursor = highlight;
extra_selection.format.setBackground (QColor (255, 255, 160));
m_search_selection.push_back (extra_selection);
from = index + search_text.size ();
}
}
if (! m_search_selection.empty ()) {
m_search_index = 0;
mp_ui->browser->setExtraSelections (m_search_selection);
mp_ui->browser->setTextCursor (m_search_selection [m_search_index].cursor);
}
}
void
BrowserPanel::page_search_next ()
{
if (m_search_index >= 0) {
++m_search_index;
if (m_search_index >= m_search_selection.size ()) {
m_search_index = 0;
}
mp_ui->browser->setTextCursor (m_search_selection [m_search_index].cursor);
}
}
void
BrowserPanel::search_text_changed (const QString &text)
{
QList<QString> strings;
if (! text.isEmpty () && mp_source.get ()) {
std::list<std::string> cl;
mp_source->search_completers (tl::to_string (text.toLower ()), cl);
for (std::list<std::string>::const_iterator i = cl.begin (); i != cl.end (); ++i) {
strings.push_back (tl::to_qstring (*i));
}
}
mp_completer_model->setStringList (strings);
}
void
BrowserPanel::text_changed ()
{
@ -118,6 +414,9 @@ BrowserPanel::text_changed ()
m_current_title = title;
emit title_changed (title);
}
// refresh on-page search
page_search_edited ();
}
void
@ -259,15 +558,15 @@ BrowserPanel::search (const std::string &s)
void
BrowserPanel::search_edited ()
{
if (mp_ui->searchEdit->text ().size () > 0) {
if (mp_ui->search_edit->text ().size () > 0) {
QUrl url (tl::to_qstring (m_search_url));
#if QT_VERSION >= 0x050000
QUrlQuery qi;
qi.addQueryItem (tl::to_qstring (m_search_query_item), mp_ui->searchEdit->text ());
qi.addQueryItem (tl::to_qstring (m_search_query_item), mp_ui->search_edit->text ());
url.setQuery (qi);
#else
QList<QPair<QString, QString> > qi;
qi.push_back (QPair<QString, QString> (tl::to_qstring (m_search_query_item), mp_ui->searchEdit->text ()));
qi.push_back (QPair<QString, QString> (tl::to_qstring (m_search_query_item), mp_ui->search_edit->text ()));
url.setQueryItems (qi);
#endif
load (url.toEncoded ().constData ());
@ -279,7 +578,7 @@ BrowserPanel::set_search_url (const std::string &url, const std::string &query_i
{
m_search_url = url;
m_search_query_item = query_item;
mp_ui->searchEdit->setVisible (! url.empty ());
mp_ui->search_edit->setVisible (! url.empty ());
}
void
@ -474,6 +773,12 @@ BrowserSource::get_outline (const std::string & /*url*/)
return BrowserOutline ();
}
void
BrowserSource::search_completers (const std::string & /*search_string*/, std::list<std::string> & /*completers*/)
{
// .. nothing here ..
}
std::string
BrowserSource::get (const std::string & /*url*/)
{

View File

@ -30,12 +30,15 @@
#include "gsiObject.h"
#include <QTextBrowser>
#include <QCompleter>
#include <string>
#include <list>
#include <set>
class QTreeWidgetItem;
class QCompleter;
class QStringListModel;
namespace Ui
{
@ -46,6 +49,7 @@ namespace lay
{
class BrowserPanel;
class Dispatcher;
/**
* @brief Specifies the outline of the document
@ -204,6 +208,11 @@ public:
*/
virtual BrowserOutline get_outline (const std::string &url);
/**
* @brief Gets the search completer items for a given search string
*/
virtual void search_completers (const std::string &search_string, std::list<std::string> &completers);
/**
* @brief Get the image for a given "int" URL in an image
*/
@ -273,6 +282,26 @@ private:
BrowserPanel *mp_panel;
};
/**
* @brief A structure describing a bookmark item
*/
struct LAYBASIC_PUBLIC BookmarkItem
{
BookmarkItem () : position (0) { }
bool operator== (const BookmarkItem &other) const
{
return url == other.url && position == other.position;
}
void read (tl::Extractor &ex);
std::string to_string () const;
std::string url;
std::string title;
int position;
};
/**
* @brief A specialisation of QWidget around a TextBrowser that allows loading a specific resource
*/
@ -286,14 +315,26 @@ Q_OBJECT
public:
/**
* @brief Constructor
*
* @param p The parent widget
*/
BrowserPanel (QWidget *p);
BrowserPanel (QWidget *p);
/**
* @brief Dtor
*/
~BrowserPanel ();
/**
* @brief Connects the panel to a configuration dispatcher
*
* Doing so allows storing bookmarks and retrieving them.
*
* @param dispatcher If given, this interface will be used to retrieve and store the bookmark list
* @param cfg_bookmarks If dispatcher is given, this will be the configuration key to store the bookmarks
*/
void set_dispatcher (lay::Dispatcher *dispatcher, const std::string &cfg_bookmarks);
/**
* @brief Connect to a source object
* If "
@ -385,10 +426,25 @@ public slots:
*/
void home ();
/**
* @brief "find" activated
*/
void find ();
/**
* @brief "bookmark" activated
*/
void bookmark();
protected slots:
void page_search_edited ();
void page_search_next();
void search_text_changed(const QString &text);
void search_edited ();
void text_changed ();
void outline_item_clicked (QTreeWidgetItem *item);
void bookmark_item_selected (QTreeWidgetItem *item);
void delete_bookmark ();
protected:
virtual QVariant loadResource (int type, const QUrl &url);
@ -408,8 +464,19 @@ private:
tl::DeferredMethod<BrowserPanel> m_back_dm;
std::string m_search_url, m_search_query_item;
QString m_current_title;
QList<QTextEdit::ExtraSelection> m_search_selection;
int m_search_index;
QCompleter *mp_completer;
QStringListModel *mp_completer_model;
std::list<BookmarkItem> m_bookmarks;
lay::Dispatcher *mp_dispatcher;
std::string m_cfg_bookmarks;
void init ();
void clear_bookmarks ();
void add_bookmark (const BookmarkItem &item);
void refresh_bookmark_list ();
void store_bookmarks ();
};
}

View File

@ -28,6 +28,7 @@
#include "dbPCellVariant.h"
#include "dbLibraryProxy.h"
#include "dbLibrary.h"
#include "dbLibraryManager.h"
#include <QTreeView>
#include <QPalette>
@ -604,14 +605,53 @@ CellTreeModel::mimeData(const QModelIndexList &indexes) const
{
for (QModelIndexList::const_iterator i = indexes.begin (); i != indexes.end (); ++i) {
if (i->isValid()) {
if (! i->isValid()) {
continue;
}
if (is_pcell (*i)) {
lay::CellDragDropData data (mp_layout, mp_library, pcell_id (*i), true);
return data.to_mime_data ();
} else {
const db::Cell *c = cell (*i);
if (c) {
// resolve library proxies
const db::Layout *layout = mp_layout;
const db::Library *library = mp_library;
const db::LibraryProxy *lib_proxy;
while (layout != 0 && (lib_proxy = dynamic_cast <const db::LibraryProxy *> (c)) != 0) {
const db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ());
if (! lib) {
break;
}
library = lib;
layout = &lib->layout ();
if (layout->is_valid_cell_index (lib_proxy->library_cell_index ())) {
c = &layout->cell (lib_proxy->library_cell_index ());
} else {
c = 0;
}
}
// identify pcell variants and turn them into PCell drag targets
const db::PCellVariant *pcell_var = dynamic_cast<const db::PCellVariant *> (c);
if (pcell_var) {
lay::CellDragDropData data (layout, library, pcell_var->pcell_id (), true, pcell_var->parameters ());
return data.to_mime_data ();
} else if (c) {
lay::CellDragDropData data (layout, library, c->cell_index (), false);
return data.to_mime_data ();
}
if (is_pcell (*i)) {
lay::CellDragDropData data (mp_layout, mp_library, pcell_id (*i), true);
return data.to_mime_data ();
} else if (cell (*i)) {
lay::CellDragDropData data (mp_layout, mp_library, cell_index (*i), false);
return data.to_mime_data ();
}
}

View File

@ -80,6 +80,11 @@ Editables::Editables (db::Manager *manager)
Editables::~Editables ()
{
cancel_edits ();
if (mp_properties_dialog) {
delete mp_properties_dialog;
mp_properties_dialog = 0;
}
}
void
@ -444,6 +449,14 @@ Editables::select (const db::DPoint &pt, lay::Editable::SelectionMode mode)
signal_selection_changed ();
}
void
Editables::repeat_selection (Editable::SelectionMode mode)
{
if (m_last_selected_point.is_point ()) {
select (m_last_selected_point, mode);
}
}
bool
Editables::begin_move (const db::DPoint &p, lay::angle_constraint_type ac)
{
@ -602,9 +615,8 @@ Editables::cancel_edits ()
{
// close the property dialog
if (mp_properties_dialog) {
delete mp_properties_dialog;
mp_properties_dialog->hide ();
}
mp_properties_dialog = 0;
// cancel any edit operations
for (iterator e = begin (); e != end (); ++e) {
@ -615,7 +627,15 @@ Editables::cancel_edits ()
void
Editables::show_properties (QWidget *parent)
{
cancel_edits ();
if (selection_size () == 0) {
// try to use the transient selection for the real one
transient_to_selection ();
}
// re-create a new properties dialog
if (mp_properties_dialog) {
delete mp_properties_dialog;
}
mp_properties_dialog = new lay::PropertiesDialog (parent, manager (), this);
mp_properties_dialog->show ();
}

View File

@ -493,6 +493,13 @@ public:
*/
void select (const db::DPoint &pt, Editable::SelectionMode mode);
/**
* @brief Repeat the previous selection
*
* This method will not do anything if there is no previous, click-at selection.
*/
void repeat_selection (Editable::SelectionMode mode);
/**
* @brief Start "move" operation
*

View File

@ -0,0 +1,70 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "layEditorOptionsFrame.h"
#include "layEditorOptionsPage.h"
#include "layEditorOptionsPages.h"
#include "layPlugin.h"
#include "layLayoutView.h"
#include <QVBoxLayout>
namespace lay
{
EditorOptionsFrame::EditorOptionsFrame (QWidget *parent)
: QFrame (parent), mp_pages (0)
{
setObjectName (QString::fromUtf8 ("editor_options_frame"));
QVBoxLayout *left_frame_ly = new QVBoxLayout (this);
left_frame_ly->setMargin (0);
left_frame_ly->setSpacing (0);
}
EditorOptionsFrame::~EditorOptionsFrame ()
{
// .. nothing yet ..
}
void
EditorOptionsFrame::populate (LayoutView *view)
{
std::vector<lay::EditorOptionsPage *> prop_dialog_pages;
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
cls->get_editor_options_pages (prop_dialog_pages, view, view->dispatcher ());
}
for (std::vector<lay::EditorOptionsPage *>::const_iterator op = prop_dialog_pages.begin (); op != prop_dialog_pages.end (); ++op) {
(*op)->activate (false);
}
if (mp_pages) {
delete mp_pages;
}
mp_pages = new lay::EditorOptionsPages (this, prop_dialog_pages, view);
layout ()->addWidget (mp_pages);
setFocusProxy (mp_pages);
}
}

View File

@ -0,0 +1,55 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_layEditorOptionsFrame
#define HDR_layEditorOptionsFrame
#include "laybasicCommon.h"
#include <QFrame>
namespace lay
{
class EditorOptionsPages;
class LayoutView;
class LAYBASIC_PUBLIC EditorOptionsFrame
: public QFrame
{
public:
EditorOptionsFrame (QWidget *parent);
virtual ~EditorOptionsFrame ();
void populate (LayoutView *view);
EditorOptionsPages *pages_widget () const
{
return mp_pages;
}
public:
EditorOptionsPages *mp_pages;
};
}
#endif

View File

@ -0,0 +1,65 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "tlInternational.h"
#include "layEditorOptionsPage.h"
#include "layEditorOptionsPages.h"
namespace lay
{
// ------------------------------------------------------------------
// EditorOptionsPage implementation
EditorOptionsPage::EditorOptionsPage (lay::Dispatcher *dispatcher)
: QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (dispatcher)
{
// nothing yet ..
}
EditorOptionsPage::~EditorOptionsPage ()
{
set_owner (0);
}
void
EditorOptionsPage::set_owner (EditorOptionsPages *owner)
{
if (mp_owner) {
mp_owner->unregister_page (this);
}
mp_owner = owner;
}
void
EditorOptionsPage::activate (bool active)
{
if (m_active != active) {
m_active = active;
if (mp_owner) {
mp_owner->activate_page (this);
}
}
}
}

View File

@ -0,0 +1,84 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_layEditorOptionsPage
#define HDR_layEditorOptionsPage
#include "laybasicCommon.h"
#include <QWidget>
namespace lay
{
class PluginDeclaration;
class Dispatcher;
class Plugin;
class EditorOptionsPages;
/**
* @brief The base class for a object properties page
*/
class LAYBASIC_PUBLIC EditorOptionsPage
: public QWidget
{
Q_OBJECT
public:
EditorOptionsPage (lay::Dispatcher *dispatcher);
virtual ~EditorOptionsPage ();
virtual std::string title () const = 0;
virtual int order () const = 0;
virtual void apply (lay::Dispatcher * /*root*/) { }
virtual void setup (lay::Dispatcher * /*root*/) { }
virtual void commit_recent (lay::Dispatcher * /*root*/) { }
bool active () const { return m_active; }
void activate (bool active);
void set_owner (EditorOptionsPages *owner);
const lay::PluginDeclaration *plugin_declaration () const { return mp_plugin_declaration; }
void set_plugin_declaration (const lay::PluginDeclaration *pd) { mp_plugin_declaration = pd; }
protected slots:
void edited ()
{
apply (dispatcher ());
}
protected:
lay::Dispatcher *dispatcher () const
{
return mp_dispatcher;
}
private:
EditorOptionsPages *mp_owner;
bool m_active;
const lay::PluginDeclaration *mp_plugin_declaration;
lay::Dispatcher *mp_dispatcher;
};
}
#endif

View File

@ -0,0 +1,215 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "tlInternational.h"
#include "layEditorOptionsPages.h"
#include "tlExceptions.h"
#include "layPlugin.h"
#include "layLayoutView.h"
#include "layQtTools.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QTabWidget>
#include <QToolButton>
#include <QCompleter>
#include <QLineEdit>
namespace lay
{
// ------------------------------------------------------------------
// EditorOptionsPages implementation
struct EOPCompareOp
{
bool operator() (lay::EditorOptionsPage *a, lay::EditorOptionsPage *b) const
{
return a->order () < b->order ();
}
};
EditorOptionsPages::EditorOptionsPages (QWidget *parent, const std::vector<lay::EditorOptionsPage *> &pages, lay::Dispatcher *dispatcher)
: QFrame (parent), mp_dispatcher (dispatcher)
{
QVBoxLayout *ly1 = new QVBoxLayout (this);
ly1->setMargin (0);
mp_pages = new QTabWidget (this);
ly1->addWidget (mp_pages);
m_pages = pages;
for (std::vector <lay::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
(*p)->set_owner (this);
}
update (0);
setup ();
}
EditorOptionsPages::~EditorOptionsPages ()
{
while (m_pages.size () > 0) {
delete m_pages.front ();
}
}
void
EditorOptionsPages::focusInEvent (QFocusEvent * /*event*/)
{
// Sends the focus to the current page's last focus owner
if (mp_pages->currentWidget () && mp_pages->currentWidget ()->focusWidget ()) {
mp_pages->currentWidget ()->focusWidget ()->setFocus ();
}
}
bool EditorOptionsPages::has_content () const
{
for (std::vector <lay::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
// NOTE: we ignore unspecific pages because they are always visible and don't contribute specific content
if ((*p)->active () && (*p)->plugin_declaration () != 0) {
return true;
}
}
return false;
}
void
EditorOptionsPages::unregister_page (lay::EditorOptionsPage *page)
{
std::vector <lay::EditorOptionsPage *> pages;
for (std::vector <lay::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
if (*p != page) {
pages.push_back (*p);
}
}
m_pages = pages;
update (0);
}
void
EditorOptionsPages::activate_page (lay::EditorOptionsPage *page)
{
try {
if (page->active ()) {
page->setup (mp_dispatcher);
}
} catch (...) {
// catch any errors related to configuration file errors etc.
}
update (page);
}
void
EditorOptionsPages::update (lay::EditorOptionsPage *page)
{
std::vector <lay::EditorOptionsPage *> sorted_pages = m_pages;
std::sort (sorted_pages.begin (), sorted_pages.end (), EOPCompareOp ());
if (! page && m_pages.size () > 0) {
page = m_pages.back ();
}
while (mp_pages->count () > 0) {
mp_pages->removeTab (0);
}
int index = -1;
for (std::vector <lay::EditorOptionsPage *>::iterator p = sorted_pages.begin (); p != sorted_pages.end (); ++p) {
if ((*p)->active ()) {
if ((*p) == page) {
index = mp_pages->count ();
}
mp_pages->addTab (*p, tl::to_qstring ((*p)->title ()));
} else {
(*p)->setParent (0);
}
}
if (index < 0) {
index = mp_pages->currentIndex ();
}
if (index >= int (mp_pages->count ())) {
index = mp_pages->count () - 1;
}
mp_pages->setCurrentIndex (index);
setVisible (mp_pages->count () > 0);
}
void
EditorOptionsPages::setup ()
{
try {
for (std::vector <lay::EditorOptionsPage *>::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
if ((*p)->active ()) {
(*p)->setup (mp_dispatcher);
}
}
// make the display consistent with the status (this is important for
// PCell parameters where the PCell may be asked to modify the parameters)
do_apply ();
} catch (...) {
// catch any errors related to configuration file errors etc.
}
}
void
EditorOptionsPages::do_apply ()
{
for (std::vector <lay::EditorOptionsPage *>::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
if ((*p)->active ()) {
// NOTE: we apply to the root dispatcher, so other dispatchers (views) get informed too.
(*p)->apply (mp_dispatcher->dispatcher ());
}
}
}
void
EditorOptionsPages::apply ()
{
BEGIN_PROTECTED
do_apply ();
END_PROTECTED_W (this)
}
// ------------------------------------------------------------------
// Indicates an error on a line edit
template <class Value>
static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le, const std::string &cfg_name)
{
try {
Value value = Value (0);
tl::from_string (tl::to_string (le->text ()), value);
dispatcher->config_set (cfg_name, tl::to_string (value));
lay::indicate_error (le, 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
}
}
}

View File

@ -0,0 +1,85 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_layEditorOptionsPages
#define HDR_layEditorOptionsPages
#include "laybasicCommon.h"
#include "layEditorOptionsPage.h"
#include <tlVariant.h>
#include <QFrame>
#include <vector>
#include <string>
class QTabWidget;
class QLabel;
namespace lay
{
class PluginDeclaration;
class Dispatcher;
class Plugin;
/**
* @brief The object properties dialog
*/
class LAYBASIC_PUBLIC EditorOptionsPages
: public QFrame
{
Q_OBJECT
public:
EditorOptionsPages (QWidget *parent, const std::vector<lay::EditorOptionsPage *> &pages, lay::Dispatcher *root);
~EditorOptionsPages ();
void unregister_page (lay::EditorOptionsPage *page);
void activate_page (lay::EditorOptionsPage *page);
void focusInEvent (QFocusEvent *event);
const std::vector <lay::EditorOptionsPage *> &pages () const
{
return m_pages;
}
bool has_content () const;
public slots:
void apply ();
void setup ();
private:
std::vector <lay::EditorOptionsPage *> m_pages;
lay::Dispatcher *mp_dispatcher;
QTabWidget *mp_pages;
void update (lay::EditorOptionsPage *page);
void do_apply ();
};
}
#endif

View File

@ -0,0 +1,297 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "layEditorServiceBase.h"
#include "layViewport.h"
#include "layLayoutView.h"
#include "laybasicConfig.h"
#include "layConverters.h"
namespace lay
{
// --------------------------------------------------------------------------------------
template <size_t num_pts>
static void
make_circle (double r, const db::DPoint &center, db::DPolygon &poly, bool as_hole)
{
db::DPoint pts [num_pts];
for (size_t i = 0; i < num_pts; ++i) {
double x = r * cos (M_PI * 2.0 * double (i) / double (num_pts));
double y = r * sin (M_PI * 2.0 * double (i) / double (num_pts));
pts [i] = center + db::DVector (x, y);
}
if (! as_hole) {
poly.assign_hull (pts, pts + num_pts);
} else {
poly.insert_hole (pts, pts + num_pts);
}
}
class TrackingCursorBase
: public lay::ViewObject
{
public:
TrackingCursorBase (lay::EditorServiceBase *service, lay::ViewObjectWidget *widget)
: lay::ViewObject (widget, false), mp_service (service)
{ }
uint32_t cursor_color (lay::ViewObjectCanvas &canvas) const
{
QColor color;
if (mp_service) {
color = mp_service->tracking_cursor_color ();
}
if (! color.isValid ()) {
color = canvas.foreground_color ();
}
return color.rgb ();
}
virtual void render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas)
{
if (mp_service && mp_service->tracking_cursor_enabled ()) {
do_render (vp, canvas);
}
}
protected:
virtual void do_render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas) = 0;
private:
lay::EditorServiceBase *mp_service;
};
class MouseCursorViewObject
: public TrackingCursorBase
{
public:
MouseCursorViewObject (lay::EditorServiceBase *service, lay::ViewObjectWidget *widget, const db::DPoint &pt, bool solid)
: TrackingCursorBase (service, widget), m_pt (pt), m_solid (solid)
{ }
protected:
virtual void do_render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas)
{
int dither_pattern = 0; // solid
int cross_dither_pattern = 6; // dotted
int lw = int (0.5 + 1.0 / canvas.resolution ());
std::vector <lay::ViewOp> ops;
ops.resize (1);
ops[0] = lay::ViewOp (cursor_color (canvas), lay::ViewOp::Copy, 0, (unsigned int) dither_pattern, 0, lay::ViewOp::Rect, lw, 0);
lay::CanvasPlane *plane = canvas.plane (ops);
ops[0] = lay::ViewOp (cursor_color (canvas), lay::ViewOp::Copy, 0, (unsigned int) cross_dither_pattern, 0, lay::ViewOp::Rect, lw, 0);
lay::CanvasPlane *cross_plane = canvas.plane (ops);
lay::Renderer &r = canvas.renderer ();
double rad = 4.0 / canvas.resolution () / vp.trans ().mag ();
db::DPolygon c;
if (! m_solid) {
make_circle<size_t (16)> (rad, m_pt, c, false);
r.draw (c, vp.trans (), 0, plane, 0, 0);
} else {
make_circle<size_t (16)> (rad * 2, m_pt, c, false);
r.draw (c, vp.trans (), 0, plane, 0, 0);
make_circle<size_t (16)> (rad, m_pt, c, false);
r.draw (c, vp.trans (), 0, plane, 0, 0);
}
r.draw (db::DEdge (m_pt + db::DVector (0, -rad * 4), m_pt + db::DVector (0, rad * 4)), vp.trans (), 0, cross_plane, 0, 0);
r.draw (db::DEdge (m_pt + db::DVector (-rad * 4, 0), m_pt + db::DVector (rad * 4, 0)), vp.trans (), 0, cross_plane, 0, 0);
}
private:
db::DPoint m_pt;
bool m_solid;
};
class EdgeMarkerViewObject
: public TrackingCursorBase
{
public:
EdgeMarkerViewObject (lay::EditorServiceBase *service, lay::ViewObjectWidget *widget, const db::DEdge &edge, bool solid)
: TrackingCursorBase (service, widget), m_edge (edge), m_solid (solid)
{ }
protected:
virtual void do_render (const lay::Viewport &vp, lay::ViewObjectCanvas &canvas)
{
if (m_edge.is_degenerate ()) {
return;
}
int dashed_style = 2;
int solid_style = 0;
int lw = int (0.5 + 1.0 / canvas.resolution ());
std::vector <lay::ViewOp> ops;
ops.resize (1);
ops[0] = lay::ViewOp (cursor_color (canvas), lay::ViewOp::Copy, solid_style, 0, 0, lay::ViewOp::Rect, lw, 0);
lay::CanvasPlane *arrow_plane = canvas.plane (ops);
ops[0] = lay::ViewOp (cursor_color (canvas), lay::ViewOp::Copy, m_solid ? solid_style : dashed_style, 1, 0, lay::ViewOp::Rect, lw, 0);
lay::CanvasPlane *edge_plane = canvas.plane (ops);
lay::Renderer &r = canvas.renderer ();
r.draw (m_edge, vp.trans (), 0, edge_plane, 0, 0);
double arrow_length = 12.0 / canvas.resolution () / vp.trans ().mag ();
double arrow_width_half = arrow_length * 0.25882; // sin(15 deg)
db::DVector n = db::DVector (m_edge.dy (), -m_edge.dx ()) * (arrow_width_half / m_edge.length ());
db::DVector d = db::DVector (m_edge.dx (), m_edge.dy ()) * (arrow_length / m_edge.length ());
if (m_edge.length () < 2 * arrow_length) {
r.draw (db::DEdge (m_edge.p1 () - n, m_edge.p1 () + n), vp.trans (), 0, arrow_plane, 0, 0);
r.draw (db::DEdge (m_edge.p2 () - n, m_edge.p2 () + n), vp.trans (), 0, arrow_plane, 0, 0);
} else {
db::DPoint pts[3];
db::DPolygon p;
pts[0] = m_edge.p1 ();
pts[1] = m_edge.p1 () + d - n;
pts[2] = m_edge.p1 () + d + n;
p.assign_hull (pts, pts + 3);
r.draw (p, vp.trans (), 0, arrow_plane, 0, 0);
pts[0] = m_edge.p2 ();
pts[1] = m_edge.p2 () - d + n;
pts[2] = m_edge.p2 () - d - n;
p.assign_hull (pts, pts + 3);
r.draw (p, vp.trans (), 0, arrow_plane, 0, 0);
}
}
private:
db::DEdge m_edge;
bool m_solid;
};
// --------------------------------------------------------------------------------------
EditorServiceBase::EditorServiceBase (lay::LayoutView *view)
: lay::ViewService (view->view_object_widget ()),
lay::Editable (view),
lay::Plugin (view),
m_cursor_enabled (true)
{
// .. nothing yet ..
}
EditorServiceBase::~EditorServiceBase ()
{
clear_mouse_cursors ();
}
void
EditorServiceBase::add_mouse_cursor (const db::DPoint &pt, bool emphasize)
{
m_mouse_cursor_markers.push_back (new MouseCursorViewObject (this, widget (), pt, emphasize));
}
void
EditorServiceBase::add_edge_marker (const db::DEdge &e, bool emphasize)
{
m_mouse_cursor_markers.push_back (new EdgeMarkerViewObject (this, widget (), e, emphasize));
}
void
EditorServiceBase::clear_mouse_cursors ()
{
for (std::vector<lay::ViewObject *>::iterator r = m_mouse_cursor_markers.begin (); r != m_mouse_cursor_markers.end (); ++r) {
delete *r;
}
m_mouse_cursor_markers.clear ();
}
void
EditorServiceBase::mouse_cursor_from_snap_details (const lay::PointSnapToObjectResult &snap_details)
{
clear_mouse_cursors ();
add_mouse_cursor (snap_details.snapped_point,
snap_details.object_snap == lay::PointSnapToObjectResult::ObjectVertex ||
(snap_details.object_snap == lay::PointSnapToObjectResult::ObjectUnspecific && snap_details.object_ref.is_degenerate ()));
if (snap_details.object_snap == lay::PointSnapToObjectResult::ObjectEdge ||
(snap_details.object_snap == lay::PointSnapToObjectResult::ObjectUnspecific && ! snap_details.object_ref.is_degenerate ())) {
add_edge_marker (snap_details.object_ref, false);
}
}
bool
EditorServiceBase::configure (const std::string &name, const std::string &value)
{
bool needs_update = false;
if (name == cfg_tracking_cursor_color) {
QColor color;
lay::ColorConverter ().from_string (value, color);
if (color != m_cursor_color) {
m_cursor_color = color;
needs_update = true;
}
} else if (name == cfg_tracking_cursor_enabled) {
bool f = m_cursor_enabled;
tl::from_string (value, f);
if (f != m_cursor_enabled) {
m_cursor_enabled = f;
needs_update = true;
}
}
if (needs_update) {
for (std::vector<lay::ViewObject *>::iterator r = m_mouse_cursor_markers.begin (); r != m_mouse_cursor_markers.end (); ++r) {
(*r)->redraw ();
}
}
// NOTE: we don't take the value as other services may be interested too.
return false;
}
void
EditorServiceBase::deactivated ()
{
clear_mouse_cursors ();
}
}

View File

@ -0,0 +1,122 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#ifndef HDR_layEditorServiceBase
#define HDR_layEditorServiceBase
#include "laybasicCommon.h"
#include "layEditable.h"
#include "layViewObject.h"
#include "layPlugin.h"
namespace lay
{
/**
* @brief A generic base class for an editor service
*
* This class offers common services such as a mouse cursor.
*/
class LAYBASIC_PUBLIC EditorServiceBase
: public lay::ViewService,
public lay::Editable,
public lay::Plugin
{
public:
/**
* @brief Constructor
*/
EditorServiceBase (lay::LayoutView *view);
/**
* @brief Destructor
*/
~EditorServiceBase ();
/**
* @brief Obtain the lay::ViewService interface
*/
lay::ViewService *view_service_interface ()
{
return this;
}
/**
* @brief Obtain the lay::Editable interface
*/
lay::Editable *editable_interface ()
{
return this;
}
/**
* @brief Adds a mouse cursor to the given point
*/
void add_mouse_cursor (const db::DPoint &pt, bool emphasize = false);
/**
* @brief Adds an edge marker for the given edge
*/
void add_edge_marker (const db::DEdge &e, bool emphasize);
/**
* @brief Resets the mouse cursor
*/
void clear_mouse_cursors ();
/**
* @brief Provides a nice mouse tracking cursor from the given snap details
*/
void mouse_cursor_from_snap_details (const lay::PointSnapToObjectResult &snap_details);
/**
* @brief Gets the tracking cursor color
*/
QColor tracking_cursor_color () const
{
return m_cursor_color;
}
/**
* @brief Gets a value indicating whether the tracking cursor is enabled
*/
bool tracking_cursor_enabled () const
{
return m_cursor_enabled;
}
protected:
virtual bool configure (const std::string &name, const std::string &value);
virtual void deactivated ();
private:
// The marker representing the mouse cursor
std::vector<lay::ViewObject *> m_mouse_cursor_markers;
QColor m_cursor_color;
bool m_cursor_enabled;
};
}
#endif

View File

@ -62,7 +62,7 @@ static int inst_point_sel_tests = 10000;
Finder::Finder (bool point_mode, bool top_level_sel)
: m_min_level (0), m_max_level (0),
mp_layout (0), mp_view (0), m_cv_index (0), m_point_mode (point_mode), m_top_level_sel (top_level_sel)
mp_layout (0), mp_view (0), m_cv_index (0), m_point_mode (point_mode), m_catch_all (false), m_top_level_sel (top_level_sel)
{
m_distance = std::numeric_limits<double>::max ();
}
@ -564,41 +564,32 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const
if (match) {
lay::ObjectInstPath found;
found.set_cv_index (m_cv_index);
found.set_topcell (m_topcell);
found.assign_path (path ().begin (), path ().end ());
found.set_layer (*l);
found.set_shape (*shape);
if (mp_excludes) {
// with an exclude list first create the selection item so we can check
// if it's part of the exclude set.
lay::ObjectInstPath found;
found.set_cv_index (m_cv_index);
found.set_topcell (m_topcell);
found.assign_path (path ().begin (), path ().end ());
found.set_layer (*l);
found.set_shape (*shape);
// in point mode just store the found object that has the least "distance" and is
// not in the exclude set
if (mp_excludes->find (found) == mp_excludes->end () && closer (d)) {
match = (mp_excludes->find (found) == mp_excludes->end ());
if (m_founds.empty ()) {
m_founds.push_back (found);
} else {
m_founds.front () = found;
}
}
}
} else if (closer (d)) {
if (match && (catch_all () || closer (d))) {
// in point mode just store that found that has the least "distance"
if (m_founds.empty ()) {
m_founds.push_back (lay::ObjectInstPath ());
if (m_founds.empty () || catch_all ()) {
m_founds.push_back (found);
}
m_founds.back ().set_cv_index (m_cv_index);
m_founds.back ().set_topcell (m_topcell);
m_founds.back ().assign_path (path ().begin (), path ().end ());
m_founds.back ().set_layer (*l);
m_founds.back ().set_shape (*shape);
m_founds.back () = found;
}
@ -854,52 +845,38 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
if (match) {
lay::ObjectInstPath found;
found.set_cv_index (m_cv_index);
found.set_topcell (m_topcell);
found.assign_path (path ().begin (), path ().end ());
// add the selected instance as the last element of the path
db::InstElement el;
el.inst_ptr = *inst;
if (! m_full_arrays) {
el.array_inst = p;
}
found.add_path (el);
if (mp_excludes) {
// with an exclude list first create the selection item so we can check
// if it's part of the exclude set.
lay::ObjectInstPath found;
found.set_cv_index (m_cv_index);
found.set_topcell (m_topcell);
found.assign_path (path ().begin (), path ().end ());
// add the selected instance as the last element of the path
db::InstElement el;
el.inst_ptr = *inst;
if (! m_full_arrays) {
el.array_inst = p;
}
found.add_path (el);
// in point mode just store the found object that has the least "distance" and is
// not in the exclude set
if (mp_excludes->find (found) == mp_excludes->end () && closer (d)) {
if (m_founds.empty ()) {
m_founds.push_back (found);
} else {
m_founds.front () = found;
}
}
match = (mp_excludes->find (found) == mp_excludes->end ());
} else if (closer (d)) {
}
if (match && (catch_all () || closer (d))) {
// in point mode just store that found that has the least "distance"
if (m_founds.empty ()) {
if (m_founds.empty () || catch_all ()) {
m_founds.push_back (lay::ObjectInstPath ());
}
m_founds.back ().set_cv_index (m_cv_index);
m_founds.back ().set_topcell (m_topcell);
m_founds.back ().assign_path (path ().begin (), path ().end ());
// add the selected instance as the last element of the path
db::InstElement el;
el.inst_ptr = *inst;
if (! m_full_arrays) {
el.array_inst = p;
}
m_founds.back ().add_path (el);
m_founds.back () = found;
}

View File

@ -58,13 +58,42 @@ public:
*
* The point_mode is true, if the finder is supposed to operate in "point mode".
* In point mode, the center of the search region is the reference point. In
* non-point mode, every relevant found inside the search region should be
* recorded.
* non-point mode, every relevant found inside the search region will be
* recorded (also see point_mode method).
* The base class implementation just stores this flag and provides a read
* accessor with the point_mode () method.
*/
Finder (bool point_mode, bool top_level_sel);
/**
* @brief Gets a flag indicating whether point mode is enabled
* If point mode is enabled in the constructor, the first will check for objects overlapping the
* point (rather than being inside the box) and by default select a single object only.
* See also "set_catch_all".
*/
bool point_mode () const
{
return m_point_mode;
}
/**
* @brief Gets a flag indicating the capture all founds even in point mode
*/
bool catch_all () const
{
return m_catch_all;
}
/**
* @brief Sets a flag indicating the capture all founds even in point mode
* By default, in point mode only the closest found is returned. To catch all
* founds in point mode too, set this flag to true.
*/
void set_catch_all (bool f)
{
m_catch_all = f;
}
/**
* @brief Destructor (just provided to please the compiler)
*/
@ -87,11 +116,6 @@ protected:
return m_layers;
}
bool point_mode () const
{
return m_point_mode;
}
const std::vector<db::InstElement> &path () const
{
return m_path;
@ -168,6 +192,7 @@ private:
std::vector<int> m_layers;
double m_distance;
bool m_point_mode;
bool m_catch_all;
bool m_top_level_sel;
db::box_convert <db::CellInst> m_box_convert;
db::box_convert <db::Cell> m_cell_box_convert;

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