diff --git a/src/db/db/dbD25TechnologyComponent.cc b/src/db/db/dbD25TechnologyComponent.cc index 2719bfbb7..62f9b24e4 100644 --- a/src/db/db/dbD25TechnologyComponent.cc +++ b/src/db/db/dbD25TechnologyComponent.cc @@ -119,6 +119,7 @@ D25TechnologyComponent::D25TechnologyComponent () // provide some explanation for the initialization m_src = "# Provide z stack information here\n" + "#\n" "# Each line is one layer. The specification consists of a layer specification, a colon and arguments.\n" "# The arguments are named (like \"x=...\") or in serial. Parameters are separated by comma or blanks.\n" "# Named arguments are:\n" @@ -127,7 +128,7 @@ D25TechnologyComponent::D25TechnologyComponent () "# zstop The upper z position of the extruded layer in µm\n" "# height The height of the extruded layer in µm\n" "#\n" - "# 'height', 'zstart' and 'zstop' can be used in any combination. If no value is given for 'zstart', " + "# 'height', 'zstart' and 'zstop' can be used in any combination. If no value is given for 'zstart',\n" "# the upper level of the previous layer will be used.\n" "#\n" "# If a single unnamed parameter is given, it corresponds to 'height'. Two parameters correspond to\n" @@ -139,25 +140,52 @@ D25TechnologyComponent::D25TechnologyComponent () "# 1: zstop=1.5, zstart=0.5 # same with named parameters\n" "# 1: height=1.0, zstop=1.5 # same with z stop minus height\n" "# 1: 1.0 zstop=1.5 # same with height as unnamed parameter\n" + "#\n" + "# VARIABLES\n" + "#\n" + "# You can declare variables with:\n" + "# var name = value\n" + "#\n" + "# You can use variables inside numeric expressions.\n" + "# Example:\n" + "# var hmetal = 0.48\n" + "# 7/0: 0.5 0.5+hmetal*2 # 2x thick metal\n" + "#\n" + "# You cannot use variables inside layer specifications currently.\n" + "#\n" + "# CONDITIONALS\n" + "#\n" + "# You can enable or disable branches of the table using 'if', 'else', 'elseif' and 'end':\n" + "# Example:\n" + "# var thick_m1 = true\n" + "# if thickm1\n" + "# 1: 0.5 1.5\n" + "# else\n" + "# 1: 0.5 1.2\n" + "# end\n" + "\n" ; } D25TechnologyComponent::D25TechnologyComponent (const D25TechnologyComponent &d) : db::TechnologyComponent (d25_component_name (), d25_description ()) { - m_layers = d.m_layers; m_src = d.m_src; } -void -D25TechnologyComponent::compile_from_source (const std::string &src) +D25TechnologyComponent::layers_type +D25TechnologyComponent::compile_from_source () const { + layers_type layers; + int current_line = 0; - m_layers.clear (); try { - std::vector lines = tl::split (src, "\n"); + tl::Eval eval; + std::vector conditional_stack; + + std::vector lines = tl::split (m_src, "\n"); for (std::vector::const_iterator l = lines.begin (); l != lines.end (); ++l) { ++current_line; @@ -168,12 +196,86 @@ D25TechnologyComponent::compile_from_source (const std::string &src) // ignore comments } else if (ex.at_end ()) { // ignore empty lines + + } else if (ex.test ("if")) { + + tl::Expression x; + eval.parse (x, ex); + conditional_stack.push_back (x.execute ().to_bool ()); + + ex.expect_end (); + + } else if (ex.test ("else")) { + + if (conditional_stack.empty ()) { + throw tl::Exception (tl::to_string (tr ("'else' without 'if'"))); + } + + conditional_stack.back () = ! conditional_stack.back (); + + ex.expect_end (); + + } else if (ex.test ("end")) { + + if (conditional_stack.empty ()) { + throw tl::Exception (tl::to_string (tr ("'end' without 'if'"))); + } + + conditional_stack.pop_back (); + + ex.expect_end (); + + } else if (ex.test ("elsif")) { + + if (conditional_stack.empty ()) { + throw tl::Exception (tl::to_string (tr ("'elsif' without 'if'"))); + } + + tl::Expression x; + eval.parse (x, ex); + conditional_stack.back () = x.execute ().to_bool (); + + ex.expect_end (); + + } else if (! conditional_stack.empty () && ! conditional_stack.back ()) { + + continue; + + } else if (ex.test ("var")) { + + std::string n; + ex.read_name (n); + + ex.expect ("="); + + tl::Expression x; + eval.parse (x, ex); + eval.set_var (n, x.execute ()); + + ex.expect_end (); + + } else if (ex.test ("print")) { + + tl::Expression x; + eval.parse (x, ex); + ex.expect_end (); + + tl::info << x.execute ().to_string (); + + } else if (ex.test ("error")) { + + tl::Expression x; + eval.parse (x, ex); + ex.expect_end (); + + throw tl::Exception (x.execute ().to_string ()); + } else { db::D25LayerInfo info; - if (! m_layers.empty ()) { - info.set_zstart (m_layers.back ().zstop ()); - info.set_zstop (m_layers.back ().zstop ()); + if (! layers.empty ()) { + info.set_zstart (layers.back ().zstop ()); + info.set_zstop (layers.back ().zstop ()); } tl::Variant z0, z1, h; @@ -191,16 +293,18 @@ D25TechnologyComponent::compile_from_source (const std::string &src) break; } - double pv = 0.0; + tl::Expression pvx; std::string pn; if (ex.try_read_name (pn)) { ex.expect ("="); - ex.read (pv); + eval.parse (pvx, ex); } else { - ex.read (pv); + eval.parse (pvx, ex); } + double pv = pvx.execute ().to_double (); + ex.test (","); if (pn.empty ()) { @@ -220,7 +324,7 @@ D25TechnologyComponent::compile_from_source (const std::string &src) if (args.size () == 0) { if (z0.is_nil () && z1.is_nil ()) { if (! h.is_nil ()) { - info.set_zstop (info.zstart () + h.to_double ()); + info.set_zstop (info.zstop () + h.to_double ()); } } else if (z0.is_nil ()) { info.set_zstop (z1.to_double ()); @@ -239,28 +343,28 @@ D25TechnologyComponent::compile_from_source (const std::string &src) } else if (args.size () == 1) { if (! h.is_nil ()) { if (! z0.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstart already given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstart already given"))); } if (! z1.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstop implicitly given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstop implicitly given"))); } info.set_zstart (args[0]); info.set_zstop (args[0] + h.to_double ()); } else { if (! z1.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstop implicitly given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstop implicitly given"))); } info.set_zstop ((! z0.is_nil () ? z0.to_double () : info.zstart ()) + args[0]); } } else if (args.size () == 2) { if (! z0.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstart already given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstart already given"))); } if (! z1.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstop already given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstop already given"))); } if (! h.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: height implicitly given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: height implicitly given"))); } info.set_zstart (args[0]); info.set_zstop (args[1]); @@ -268,25 +372,30 @@ D25TechnologyComponent::compile_from_source (const std::string &src) throw tl::Exception (tl::to_string (tr ("Too many parameters (max 2)"))); } - m_layers.push_back (info); + layers.push_back (info); } } + if (! conditional_stack.empty ()) { + throw tl::Exception (tl::to_string (tr ("'if', 'else' or 'elsif' without matching 'end'"))); + } + } catch (tl::Exception &ex) { throw tl::Exception (ex.msg () + tl::sprintf (tl::to_string (tr (" in line %d")), current_line)); } - m_src = src; + return layers; } std::string D25TechnologyComponent::to_string () const { + layers_type layers = compile_from_source (); std::string res; - for (const_iterator i = begin (); i != end (); ++i) { + for (layers_type::const_iterator i = layers.begin (); i != layers.end (); ++i) { if (! res.empty ()) { res += "\n"; } @@ -317,11 +426,6 @@ public: virtual tl::XMLElementBase *xml_element () const { return new db::TechnologyComponentXMLElement (d25_component_name (), - tl::make_element ((D25TechnologyComponent::const_iterator (D25TechnologyComponent::*) () const) &D25TechnologyComponent::begin, (D25TechnologyComponent::const_iterator (D25TechnologyComponent::*) () const) &D25TechnologyComponent::end, &D25TechnologyComponent::add, "layer", - tl::make_member (&D25LayerInfo::layer_as_string, &D25LayerInfo::set_layer_from_string, "layer") + - tl::make_member (&D25LayerInfo::zstart, &D25LayerInfo::set_zstart, "zstart") + - tl::make_member (&D25LayerInfo::zstop, &D25LayerInfo::set_zstop, "zstop") - ) + tl::make_member (&D25TechnologyComponent::src, &D25TechnologyComponent::set_src, "src") ); } diff --git a/src/db/db/dbD25TechnologyComponent.h b/src/db/db/dbD25TechnologyComponent.h index 5e4a1d51f..3beade105 100644 --- a/src/db/db/dbD25TechnologyComponent.h +++ b/src/db/db/dbD25TechnologyComponent.h @@ -76,55 +76,8 @@ public: D25TechnologyComponent (const D25TechnologyComponent &d); typedef std::list layers_type; - typedef layers_type::const_iterator const_iterator; - typedef layers_type::iterator iterator; - void compile_from_source (const std::string &src); - - const_iterator begin () const - { - return m_layers.begin (); - } - - iterator begin () - { - return m_layers.begin (); - } - - const_iterator end () const - { - return m_layers.end (); - } - - iterator end () - { - return m_layers.end (); - } - - void clear () - { - m_layers.clear (); - } - - void erase (iterator p) - { - m_layers.erase (p); - } - - void insert (iterator p, const D25LayerInfo &info) - { - m_layers.insert (p, info); - } - - void add (const D25LayerInfo &info) - { - m_layers.push_back (info); - } - - size_t size () const - { - return m_layers.size (); - } + layers_type compile_from_source () const; const std::string &src () const { @@ -145,7 +98,6 @@ public: } private: - layers_type m_layers; std::string m_src; }; diff --git a/src/db/unit_tests/dbD25TechnologyComponentTests.cc b/src/db/unit_tests/dbD25TechnologyComponentTests.cc index 76080ef09..b83365ea4 100644 --- a/src/db/unit_tests/dbD25TechnologyComponentTests.cc +++ b/src/db/unit_tests/dbD25TechnologyComponentTests.cc @@ -30,44 +30,73 @@ TEST(1) { db::D25TechnologyComponent comp; - comp.compile_from_source ("1/0: 1.0 1.5 # a comment"); + comp.set_src ("1/0: 1.0 1.5 # a comment"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); - comp.compile_from_source ("1/0: zstart=1.0 zstop=1.5"); + comp.set_src ("1/0: zstart=1.0 zstop=1.5"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); - comp.compile_from_source ("1/0: zstart=1.0 height=0.5"); + comp.set_src ("1/0: zstart=1.0 height=0.5"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); - comp.compile_from_source ("1/0: 1.0 height=0.5"); + comp.set_src ("1/0: 1.0 height=0.5"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); - comp.compile_from_source ("1/0: zstop=1.5 height=0.5"); + comp.set_src ("1/0: zstop=1.5 height=0.5"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); - comp.compile_from_source ("1/0: zstart=1.0 zstop=1.5\nname: height=3"); + comp.set_src ("1/0: zstart=1.0 zstop=1.5\nname: height=3"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=1.5, zstop=4.5"); - comp.compile_from_source ("1/0: zstart=1.0 zstop=1.5\nname: zstart=4.0 height=3\n\n# a comment line"); + comp.set_src ("1/0: zstart=1.0 zstop=1.5\nname: zstart=4.0 height=3\n\n# a comment line"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=4, zstop=7"); + comp.set_src ("var x=1.0\n1/0: zstart=x zstop=x+0.5\nname: zstart=4.0 height=3\n\n# a comment line"); + comp.compile_from_source (); + EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=4, zstop=7"); + + comp.set_src ("var x=1.0\nif x == 1.0\n1/0: zstart=x zstop=x+0.5\nelse\n1/0: zstart=0 zstop=0\nend\nname: zstart=4.0 height=3\n\n# a comment line"); + comp.compile_from_source (); + EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=4, zstop=7"); + + comp.set_src ("var x=2.0\nif x == 1.0\n1/0: zstart=x zstop=x+0.5\nelse\n1/0: zstart=0 zstop=0\nend\nname: zstart=4.0 height=3\n\n# a comment line"); + comp.compile_from_source (); + EXPECT_EQ (comp.to_string (), "1/0: zstart=0, zstop=0\nname: zstart=4, zstop=7"); + try { - comp.compile_from_source ("blabla"); + comp.set_src ("blabla"); + comp.compile_from_source (); EXPECT_EQ (false, true); } catch (...) { } try { - comp.compile_from_source ("1/0: 1 2 3"); + comp.set_src ("1/0: 1 2 3"); + comp.compile_from_source (); EXPECT_EQ (false, true); } catch (...) { } try { - comp.compile_from_source ("1/0: foo=1 bar=2"); + comp.set_src ("1/0: foo=1 bar=2"); + comp.compile_from_source (); EXPECT_EQ (false, true); } catch (...) { } try { - comp.compile_from_source ("1/0: 1;2"); + comp.set_src ("1/0: 1;*2"); + comp.compile_from_source (); + EXPECT_EQ (false, true); + } catch (...) { } + + try { + comp.set_src ("error 42"); + comp.compile_from_source (); EXPECT_EQ (false, true); } catch (...) { } } diff --git a/src/lay/lay/doc/about/25d_screenshot.png b/src/lay/lay/doc/about/25d_screenshot.png new file mode 100644 index 000000000..4515ae722 Binary files /dev/null and b/src/lay/lay/doc/about/25d_screenshot.png differ diff --git a/src/lay/lay/doc/about/25d_view.xml b/src/lay/lay/doc/about/25d_view.xml new file mode 100644 index 000000000..f112260b7 --- /dev/null +++ b/src/lay/lay/doc/about/25d_view.xml @@ -0,0 +1,147 @@ + + + + + + The 2.5d View + + + + + + + +

+ The "2.5d view" offers a semi-3d view of the layout. It's not a full 3d view as the layers are only extruded vertically + into layers with a certain thickness. The view cannot model process topology, but it can visualize + wiring congestions in a three-dimensional space or the vertical relative dimensions of features of the process stack. +

+ +

+ To open the view, use "Tools/2.5d View". Currently, the performance is limited, a rough number for a + practical limit is around 100k polygons. The 2.5d view is only available, if KLayout was compiled with + OpenGL support. +

+ +

+ +

+ +

Setup

+ +

+ The 2.5d view needs a technology setup explaining the way the layers are transformed into planes. + The setup is provided within a technology. Open the technology manager (File/Manage Technologies) and + navigate to the "Z Stack (2.5d)" component. The setup is basically a list of entries listing the + layer from which to take the shapes and the depth information. +

+ +

+ Each entry is a single line. Empty lines are ignored. Everything after a '#' character is + considered a comment. +

+ +

+ Each specification line consists of a layer specification, a colon and arguments. + The arguments are named (like "x=...") or in serial. Parameters are separated by comma or blanks. + Named arguments are: +

+ +
    +
  • zstart: The lower z position of the extruded layer in µm
  • +
  • zstop: The upper z position of the extruded layer in µm
  • +
  • height: The height of the extruded layer in µm
  • +
+ +

+ 'height', 'zstart' and 'zstop' can be used in any combination. If no value is given for 'zstart', + the upper level of the previous layer will be used. +

+ +

+ If a single unnamed parameter is given, it corresponds to 'height'. Two parameters correspond to + 'zstart' and 'zstop'. +

+ +

+ Here are some examples: +

+ +
1: 0.5 1.5                    # extrude layer 1/0 from 0.5 to 1.5 vertically\n"
+1/0: 0.5 1.5                  # same with explicit datatype\n"
+1: zstop=1.5, zstart=0.5      # same with named parameters\n"
+1: height=1.0, zstop=1.5      # same with z stop minus height\n"
+1: 1.0 zstop=1.5              # same with height as unnamed parameter\n"
+  
+ +

Variables

+ +

+ You can declare variables inside the setup files and use them in formulas for + computed values. Variables are defined and set with the "var" keyword on a single line. + The notation follows the "expression" syntax used in many other places inside KLayout + (). +

+ +

+ Here is an example: +

+ +
var hmetal = 0.48\n"
+7/0: 0.5 0.5+hmetal*2        # 2x thick metal\n"
+
+ +

Conditionals

+ +

+ For more flexibility, but of little practical use for now, conditionals are provided. + "if", "else", "elsif" and "end" for as in other languages, e.g. Ruby: +

+ +
var thick_m1 = true
+if thickm1
+  1: 0.5 1.5
+else
+  1: 0.5 1.2
+end
+
+ +

Navigating the 2.5d View

+ navigation + 2.5d navigation + +

+ The navigation is based on the movement of the camera while the scene is + formed by the extruded layout. The scene can be scaled to provide zoom features. + Scaling and rotation is relative to the pivot point which is indicated by the + compass icon on the ground plane. +

+ +

+ This is a short list of the navigation controls which act on the camera: +

+ +
    +
  • Dragging with the right mouse button down: change azimuth and elevation angle
  • +
  • Dragging with the middle mouse button down: move the pivot up and down or left and right
  • +
  • Mouse wheel: moves the pivot forward and backward
  • +
  • Control key + mouse wheel: magnify or shrink the layout
  • +
  • Press and hold shift key: switch to top level view (see below)
  • +
  • Up/down keys: move the pivot forward or backward
  • +
  • Left/right keys: move the pivot to the left or the right
  • +
  • Control + up/down keys: change the elevation angle
  • +
  • Control + left/right keys: change the azimuth angle
  • +
+ +

+ In top level view, the navigation is slightly different: +

+ +
    +
  • Dragging with the right mouse button down: change azimuth angle
  • +
  • mouse wheel: magnify or shrink the layout
  • +
  • Up/down/left/right keys: move the pivot on the horizontal plane
  • +
+ +
+ diff --git a/src/lay/lay/doc/about/index.xml b/src/lay/lay/doc/about/index.xml index f5c93bbe2..4a7efb65a 100644 --- a/src/lay/lay/doc/about/index.xml +++ b/src/lay/lay/doc/about/index.xml @@ -18,6 +18,7 @@ + diff --git a/src/lay/lay/layHelpResources.qrc b/src/lay/lay/layHelpResources.qrc index 52e9fc2f7..0e0053df0 100644 --- a/src/lay/lay/layHelpResources.qrc +++ b/src/lay/lay/layHelpResources.qrc @@ -47,6 +47,8 @@ doc/about/lvs_ref_global.xml doc/about/lvs_ref_netter.xml doc/about/packages.xml + doc/about/25d_view.xml + doc/about/25d_screenshot.png doc/manual/adjust_origin.xml diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index d40814b05..41cf82007 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -3942,7 +3942,7 @@ MainWindow::menu_activated (const std::string &symbol) if (current_view ()) { current_view ()->menu_activated (symbol); } else { - throw tl::Exception (tl::to_string (QObject::tr ("No view is active"))); + throw tl::Exception (tl::to_string (QObject::tr ("This function needs a layout but none was available"))); } } diff --git a/src/laybasic/laybasic/D25TechnologyComponentEditor.ui b/src/laybasic/laybasic/D25TechnologyComponentEditor.ui index b1901ba63..a550fe8ad 100644 --- a/src/laybasic/laybasic/D25TechnologyComponentEditor.ui +++ b/src/laybasic/laybasic/D25TechnologyComponentEditor.ui @@ -44,6 +44,12 @@ Monospace + + QTextEdit::NoWrap + + + false + diff --git a/src/laybasic/laybasic/layBrowserPanel.cc b/src/laybasic/laybasic/layBrowserPanel.cc index a6a16c9a3..b1421b426 100644 --- a/src/laybasic/laybasic/layBrowserPanel.cc +++ b/src/laybasic/laybasic/layBrowserPanel.cc @@ -95,6 +95,7 @@ BookmarkItem::to_string () const BrowserPanel::BrowserPanel (QWidget *parent) : QWidget (parent), m_back_dm (this, &BrowserPanel::back), + m_new_url_dm (this, &BrowserPanel::new_url), mp_dispatcher (0) { init (); @@ -125,6 +126,7 @@ BrowserPanel::init () mp_ui->browser->addAction (mp_ui->action_find); mp_ui->browser->addAction (mp_ui->action_bookmark); + mp_ui->browser->setOpenLinks (false); mp_ui->browser_bookmark_view->addAction (mp_ui->action_delete_bookmark); mp_ui->browser_bookmark_view->setContextMenuPolicy (Qt::ActionsContextMenu); @@ -138,7 +140,8 @@ BrowserPanel::init () 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 (sourceChanged (const QUrl &)), this, SLOT (source_changed ())); + connect (mp_ui->browser, SIGNAL (anchorClicked (const QUrl &)), this, SLOT (anchor_clicked (const QUrl &))); 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 *))); @@ -218,7 +221,7 @@ BrowserPanel::title () const std::string BrowserPanel::url () const { - return m_cached_url; + return tl::to_string (mp_ui->browser->source ().toString ()); } void @@ -416,13 +419,24 @@ BrowserPanel::search_text_changed (const QString &text) } void -BrowserPanel::text_changed () +BrowserPanel::source_changed () +{ + m_new_url_dm (); +} + +void +BrowserPanel::anchor_clicked (const QUrl &url) +{ + mp_ui->browser->setSource (url); + source_changed (); +} + +void +BrowserPanel::new_url () { QString title = mp_ui->browser->document ()->metaInformation (QTextDocument::DocumentTitle); - if (title != m_current_title) { - m_current_title = title; - emit title_changed (title); - } + m_current_title = title; + emit title_changed (title); // refresh on-page search page_search_edited (); diff --git a/src/laybasic/laybasic/layBrowserPanel.h b/src/laybasic/laybasic/layBrowserPanel.h index 0b3ed3465..2fe7d8aba 100644 --- a/src/laybasic/laybasic/layBrowserPanel.h +++ b/src/laybasic/laybasic/layBrowserPanel.h @@ -441,7 +441,9 @@ protected slots: void page_search_next(); void search_text_changed(const QString &text); void search_edited (); - void text_changed (); + void source_changed (); + void anchor_clicked (const QUrl &url); + void new_url (); void outline_item_clicked (QTreeWidgetItem *item); void bookmark_item_selected (QTreeWidgetItem *item); void delete_bookmark (); @@ -462,6 +464,7 @@ private: Ui::BrowserPanel *mp_ui; bool m_schedule_back; tl::DeferredMethod m_back_dm; + tl::DeferredMethod m_new_url_dm; std::string m_search_url, m_search_query_item; QString m_current_title; QList m_search_selection; diff --git a/src/laybasic/laybasic/layD25TechnologyComponent.cc b/src/laybasic/laybasic/layD25TechnologyComponent.cc index 5c7cb2c15..753d67c05 100644 --- a/src/laybasic/laybasic/layD25TechnologyComponent.cc +++ b/src/laybasic/laybasic/layD25TechnologyComponent.cc @@ -72,7 +72,13 @@ D25TechnologyComponentEditor::commit () } std::string src = tl::to_string (src_te->toPlainText ()); - data->compile_from_source (src); + + // test-compile before setting it + db::D25TechnologyComponent tc; + tc.set_src (src); + tc.compile_from_source (); + + data->set_src (src); } void diff --git a/src/laybasic/laybasic/syntax/d25_text.xml b/src/laybasic/laybasic/syntax/d25_text.xml index 5e0877b74..13fa5afc3 100644 --- a/src/laybasic/laybasic/syntax/d25_text.xml +++ b/src/laybasic/laybasic/syntax/d25_text.xml @@ -5,13 +5,35 @@ + + zstart + zstop + height + + + + true + false + nil + + - + + + + + + + + + + + + - @@ -22,22 +44,52 @@ - - - + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -46,19 +98,21 @@ - + - + + + @@ -73,4 +127,12 @@ + + + + + + + + diff --git a/src/plugins/tools/view_25d/lay_plugin/D25View.ui b/src/plugins/tools/view_25d/lay_plugin/D25View.ui index 5e509de09..04a6aac27 100644 --- a/src/plugins/tools/view_25d/lay_plugin/D25View.ui +++ b/src/plugins/tools/view_25d/lay_plugin/D25View.ui @@ -350,9 +350,9 @@ 0 - + - Press and hold SHIFT for top view + Press and hold SHIFT for top view (<a href="int:/about/25d_view.xml">more</a>) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc index db7d059b7..a9a585e7e 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc @@ -43,7 +43,7 @@ D25Camera::~D25Camera () void D25Camera::init () { - m_fov = 90.0; + m_fov = 45.0; m_cam_azimuth = m_cam_elevation = 0.0; m_top_view = false; } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc index 94b23b462..8a98ab2c4 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc @@ -89,7 +89,7 @@ public: virtual void get_menu_entries (std::vector &menu_entries) const { lay::PluginDeclaration::get_menu_entries (menu_entries); - menu_entries.push_back (lay::menu_item ("lay::d25_view", "d25_view:edit", "tools_menu.post_verification_group", tl::to_string (QObject::tr ("2.5d View")))); + menu_entries.push_back (lay::menu_item ("lay::d25_view", "d25_view:edit", "tools_menu.post_verification_group", tl::to_string (QObject::tr ("2.5d View - experimental")))); } virtual bool configure (const std::string & /*name*/, const std::string & /*value*/) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index b973cdc7f..6c57d177e 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -23,6 +23,7 @@ #include "layD25View.h" #include "layLayoutView.h" +#include "layQtTools.h" #include "ui_D25View.h" @@ -53,6 +54,8 @@ D25View::D25View (QWidget *parent) connect (mp_ui->d25_view, SIGNAL (init_failed ()), this, SLOT (init_failed ())); mp_ui->gl_stack->setCurrentIndex (0); + + lay::activate_help_links (mp_ui->doc_label); } D25View::~D25View () diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 4aaed12f1..67c6bc8c9 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -246,40 +246,23 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) } else { - // compute vector of line of sight - std::pair ray = camera_normal (cam_perspective () * cam_trans (), px, py); - - // by definition the ray goes through the camera position - QVector3D hp = hit_point_with_scene (ray.second); + double d = event->angleDelta ().y () * (1.0 / (90 * 16)); if (! (event->modifiers () & Qt::ControlModifier)) { - // No Ctrl is closeup + // No Ctrl is "move horizontally along the azimuth axis" - double f = event->angleDelta ().y () * (1.0 / (90 * 8)); - m_displacement += -((f / m_scale_factor) * std::min (cam_dist (), double ((cam_position () - hp).length ()))) * ray.second; + QMatrix4x4 t; + t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); + QVector3D cd = t.inverted ().map (QVector3D (0, 0, cam_dist ())); + + m_displacement += d * cd; } else { // "Ctrl" is zoom - double f = exp (event->angleDelta ().y () * (1.0 / (90 * 8))); - - QVector3D initial_displacement = m_displacement; - QVector3D displacement = m_displacement; - - m_scale_factor *= f; - displacement += hp * (1.0 - f) / m_scale_factor; - - // normalize the scene translation so the scene does not "flee" - - QMatrix4x4 ct = cam_trans (); - initial_displacement = ct.map (initial_displacement); - displacement = ct.map (displacement); - - lay::normalize_scene_trans (cam_perspective (), displacement, m_scale_factor, initial_displacement.z ()); - - m_displacement = ct.inverted ().map (displacement); + m_scale_factor *= exp (d); emit scale_factor_changed (m_scale_factor); @@ -294,8 +277,65 @@ void D25ViewWidget::keyPressEvent (QKeyEvent *event) { if (event->key () == Qt::Key_Shift) { + mp_mode.reset (0); set_top_view (true); + + } else if (event->key () == Qt::Key_Up || event->key () == Qt::Key_Down) { + + if (! top_view () && (event->modifiers () & Qt::ControlModifier) != 0) { + + // Ctrl + up/down changes elevation + + double d = (event->key () == Qt::Key_Up ? 2 : -2); + + set_cam_elevation (std::max (-90.0, std::min (90.0, cam_elevation () + d))); + + } else { + + // Move "into" or "out" + + double d = (event->key () == Qt::Key_Up ? 0.1 : -0.1); + + QMatrix4x4 t; + t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); + QVector3D cd = t.inverted ().map (QVector3D (0, 0, cam_dist ())); + + set_displacement (displacement () + d * cd); + + } + + } else if (event->key () == Qt::Key_Left || event->key () == Qt::Key_Right) { + + if (! top_view () && (event->modifiers () & Qt::ControlModifier) != 0) { + + // Ctrl + left/right changes azumith + + double d = (event->key () == Qt::Key_Right ? 2 : -2); + + double a = cam_azimuth () + d; + if (a < -180.0) { + a += 360.0; + } else if (a > 180.0) { + a -= 360.0; + } + + set_cam_azimuth (a); + + } else { + + // Move "left" and "right" + + double d = (event->key () == Qt::Key_Left ? 0.1 : -0.1); + + QMatrix4x4 t; + t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); + QVector3D cd = t.inverted ().map (QVector3D (cam_dist (), 0, 0)); + + set_displacement (displacement () + d * cd); + + } + } } @@ -435,17 +475,17 @@ namespace { const db::D25LayerInfo *operator() (lay::LayoutView *view, int cv_index, int layer_index) { - std::map >::const_iterator c = m_cache.find (cv_index); + std::map >::const_iterator c = m_cache.find (cv_index); if (c != m_cache.end ()) { - std::map::const_iterator l = c->second.find (layer_index); + std::map::const_iterator l = c->second.find (layer_index); if (l != c->second.end ()) { - return l->second; + return &l->second; } else { return 0; } } - std::map &lcache = m_cache [cv_index]; + std::map &lcache = m_cache [cv_index]; const db::D25TechnologyComponent *comp = 0; @@ -457,16 +497,18 @@ namespace { if (comp) { - std::map zi_by_lp; - for (db::D25TechnologyComponent::const_iterator i = comp->begin (); i != comp->end (); ++i) { - zi_by_lp.insert (std::make_pair (i->layer (), i.operator-> ())); + std::map zi_by_lp; + + db::D25TechnologyComponent::layers_type layers = comp->compile_from_source (); + for (db::D25TechnologyComponent::layers_type::const_iterator i = layers.begin (); i != layers.end (); ++i) { + zi_by_lp.insert (std::make_pair (i->layer (), *i)); } const db::Layout &ly = cv->layout (); for (int l = 0; l < int (ly.layers ()); ++l) { if (ly.is_valid_layer (l)) { const db::LayerProperties &lp = ly.get_properties (l); - std::map::const_iterator z = zi_by_lp.find (lp); + std::map::const_iterator z = zi_by_lp.find (lp); if (z == zi_by_lp.end () && ! lp.name.empty ()) { // If possible, try by name only z = zi_by_lp.find (db::LayerProperties (lp.name)); @@ -485,7 +527,7 @@ namespace { private: - std::map > m_cache; + std::map > m_cache; }; } @@ -955,9 +997,12 @@ D25ViewWidget::paintGL () vertexes.add (-0.25 * compass_rad, 0.0, 0.6 * compass_rad); vertexes.add (0.0, 0.0, -0.8 * compass_rad); + vertexes.add (0.0, 0.0, -0.8 * compass_rad); vertexes.add (0.25 * compass_rad, 0.0, 0.6 * compass_rad); + vertexes.add (0.25 * compass_rad, 0.0, 0.6 * compass_rad); + vertexes.add (-0.25 * compass_rad, 0.0, 0.6 * compass_rad); - vertexes.draw_to (this, positions, GL_TRIANGLES); + vertexes.draw_to (this, positions, GL_LINES); // draw base plane @@ -1029,8 +1074,8 @@ D25ViewWidget::paintGL () glDisable (GL_DEPTH_TEST); - int cube_size = 64; - int cube_margin = 20; + int cube_size = 32; + int cube_margin = 40; QMatrix4x4 into_top_right_corner; into_top_right_corner.translate (1.0 - 2.0 / width () * (cube_margin + cube_size / 2), 1.0 - 2.0 / height () * (cube_margin + cube_size / 2));