mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into complex_drc_ops
This commit is contained in:
commit
db6b3d280e
|
|
@ -37,6 +37,8 @@ build-*
|
|||
bin-*
|
||||
mkqtdecl.tmp
|
||||
testtmp
|
||||
*build.macos*
|
||||
*bin.macos*
|
||||
|
||||
# private data
|
||||
private
|
||||
|
|
@ -54,3 +56,12 @@ src/klayout.pro.user
|
|||
*.egg-info/
|
||||
build/
|
||||
dist/
|
||||
|
||||
|
||||
# IDEs
|
||||
.vscode
|
||||
|
||||
|
||||
# Macos artifacts
|
||||
*.dmg
|
||||
*.dmg.md5
|
||||
|
|
|
|||
31
.travis.yml
31
.travis.yml
|
|
@ -7,6 +7,37 @@ branches:
|
|||
matrix:
|
||||
include:
|
||||
# python manylinux packages
|
||||
- name: "cp39-cp39m-manylinux1_x86_64.whl"
|
||||
os: linux
|
||||
sudo: true
|
||||
language: python
|
||||
python: '3.9'
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- DOCKER_IMAGE="quay.io/pypa/manylinux1_x86_64"
|
||||
- PY_VERSION="cp39-cp39"
|
||||
- DOCKER_BUILD=true
|
||||
- TEST_IN_HOST=true
|
||||
- MATRIX_EVAL=""
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
|
||||
- name: "cp39-cp39m-manylinux1_i686.whl"
|
||||
os: linux
|
||||
sudo: true
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- DOCKER_IMAGE="quay.io/pypa/manylinux1_i686"
|
||||
- PY_VERSION="cp39-cp39"
|
||||
- DOCKER_BUILD=true
|
||||
- MATRIX_EVAL=""
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
|
||||
- name: "cp38-cp38m-manylinux1_x86_64.whl"
|
||||
os: linux
|
||||
sudo: true
|
||||
|
|
|
|||
48
Makefile
48
Makefile
|
|
@ -3,10 +3,10 @@
|
|||
GITCOMMIT := $(shell git rev-parse --short HEAD)
|
||||
KLAYOUT_VERSION := $(shell source version.sh && echo $$KLAYOUT_VERSION)
|
||||
ifndef PYTHON_VERSION
|
||||
PYTHON_VERSION := B37
|
||||
PYTHON_VERSION := HB38
|
||||
endif
|
||||
ifndef MACOS_VERSION
|
||||
MACOS_VERSION := HighSierra
|
||||
MACOS_VERSION := Catalina
|
||||
endif
|
||||
|
||||
.ONESHELL:
|
||||
|
|
@ -15,11 +15,11 @@ default: help
|
|||
|
||||
help:
|
||||
@echo "For Mac OS only"
|
||||
@echo "make build PYTHON_VERSION=B37"
|
||||
@echo "make deploy PYTHON_VERSION=B37"
|
||||
@echo "make build PYTHON_VERSION=HB38"
|
||||
@echo "make deploy PYTHON_VERSION=HB38"
|
||||
@echo "make test MACOS_VERSION=HighSierra"
|
||||
@echo "Valid Mac OS Versions: [Yosemite, ElCapitan, Sierra, HighSierra]"
|
||||
@echo "Valid Python Version: [nil, Sys, B37]"
|
||||
@echo "Valid Mac OS Versions: [Yosemite, ElCapitan, Sierra, HighSierra, Mojave, Catalina]"
|
||||
@echo "Valid Python Version: [nil, Sys, HB38]"
|
||||
|
||||
build:
|
||||
@echo "Building for Mac $(GITCOMMIT)"
|
||||
|
|
@ -29,11 +29,11 @@ build:
|
|||
deploy:
|
||||
@echo "Deploying 4 Mac $(GITCOMMIT)"
|
||||
./build4mac.py -p $(PYTHON_VERSION) -q Qt5Brew -y
|
||||
|
||||
|
||||
test:
|
||||
@echo "Testing 4 Mac $(GITCOMMIT)"
|
||||
qt5.pkg.macos-$(MACOS_VERSION)-release/klayout.app/Contents/MacOS/klayout -b -r test-pylib-script.py; \
|
||||
cd qt5.build.macos-$(MACOS_VERSION)-release; \
|
||||
PIP_REQUIRE_VIRTUALENV="false" HW-qt5Brew.pkg.macos-$(MACOS_VERSION)-release-RsysPhb38/klayout.app/Contents/MacOS/klayout -b -r test-pylib-script.py; \
|
||||
cd qt5Brew.build.macos-$(MACOS_VERSION)-release-RsysPhb38; \
|
||||
ln -s klayout.app/Contents/MacOS/klayout klayout; \
|
||||
export TESTTMP=testtmp; \
|
||||
export TESTSRC=..; \
|
||||
|
|
@ -41,18 +41,24 @@ test:
|
|||
./ut_runner -h || true; \
|
||||
cd ..
|
||||
|
||||
dmg-template:
|
||||
mkdir -p testtemplate/klayout.app
|
||||
./makeDMG4mac.py -p testtemplate -m -z -t klayoutDMGTemplate.dmg
|
||||
cp -a klayoutDMGTemplate.dmg* macbuild/Resources/
|
||||
rm -Rf testtemplate
|
||||
|
||||
dropbox-deploy:
|
||||
@echo "Preparing for dropbox deployment $(MACOS_VERSION) $(GITCOMMIT)"
|
||||
mkdir -p deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION); \
|
||||
pwd; \
|
||||
ls -lah; \
|
||||
touch build.txt; \
|
||||
cp build.txt deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).log.txt; \
|
||||
hdiutil convert macbuild/Resources/klayoutDMGTemplate.dmg -format UDRW -o work-KLayout.dmg; \
|
||||
hdiutil resize -size 500m work-KLayout.dmg; \
|
||||
hdiutil attach work-KLayout.dmg -readwrite -noverify -quiet -mountpoint tempKLayout -noautoopen; \
|
||||
cp -a qt5.pkg.macos-$(MACOS_VERSION)-release/ tempKLayout/; \
|
||||
hdiutil detach tempKLayout; \
|
||||
hdiutil convert work-KLayout.dmg -format UDZO -imagekey zlib-level=9 -o deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg; \
|
||||
md5 -q deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg > deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg.md5; \
|
||||
mkdir -p deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)
|
||||
pwd
|
||||
ls -lah
|
||||
touch build.txt
|
||||
cp build.txt deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).log.txt
|
||||
hdiutil convert macbuild/Resources/klayoutDMGTemplate.dmg -ov -format UDRW -o work-KLayout.dmg
|
||||
hdiutil resize -size 500m work-KLayout.dmg
|
||||
hdiutil attach -readwrite -noverify -quiet -mountpoint tempKLayout -noautoopen work-KLayout.dmg
|
||||
cp -a HW-qt5Brew.pkg.macos-$(MACOS_VERSION)-release-RsysPhb38/ tempKLayout/
|
||||
hdiutil detach tempKLayout
|
||||
hdiutil convert work-KLayout.dmg -ov -format UDZO -imagekey zlib-level=9 -o deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg
|
||||
md5 -q deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg > deploy/$(MACOS_VERSION)/$(PYTHON_VERSION)/$(KLAYOUT_VERSION)/qt5.pkg.macos-$(MACOS_VERSION)-$(PYTHON_VERSION)-release-$(KLAYOUT_VERSION)-$(GITCOMMIT).dmg.md5
|
||||
rm work-KLayout.dmg
|
||||
|
|
|
|||
5
build.sh
5
build.sh
|
|
@ -532,6 +532,11 @@ if [ "$BIN" = "" ]; then
|
|||
BIN=$CURR_DIR/bin-$CONFIG
|
||||
fi
|
||||
|
||||
if [ "$QMAKE_CCACHE" = 1 ]; then
|
||||
echo " Compilation caching is activated."
|
||||
else
|
||||
echo " Compilation caching is deactivated!"
|
||||
fi
|
||||
echo " Installation target: $BIN"
|
||||
echo " Build directory: $BUILD"
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
*.pyc
|
||||
KLayoutDMG.applescript
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Relevant KLayout version: 0.26.5
|
||||
Relevant KLayout version: 0.26.7
|
||||
|
||||
# 1. Introduction
|
||||
This directory **`macbuild`** contains different files required for building KLayout (http://www.klayout.de/) version 0.26.1 or later for different 64-bit Mac OSXs including:
|
||||
|
|
@ -72,16 +72,16 @@ $ [python] ./build4mac.py
|
|||
: MP26: use Ruby 2.6 from MacPorts |
|
||||
: HB27: use Ruby 2.7 from Homebrew |
|
||||
: Ana3: use Ruby 2.5 from Anaconda3 |
|
||||
[-p|--python <type>] : case-insensitive type=['nil', 'Sys', 'MP37', 'HB37', 'Ana3'] | sys
|
||||
[-p|--python <type>] : case-insensitive type=['nil', 'Sys', 'MP38', 'HB38', 'Ana3'] | sys
|
||||
: nil: don't bind Python |
|
||||
: Sys: use OS-bundled Python 2.7 [ElCapitan -- Catalina] |
|
||||
: MP37: use Python 3.7 from MacPorts |
|
||||
: HB37: use Python 3.7 from Homebrew |
|
||||
: Ana3: use Python 3.7 from Anaconda3 |
|
||||
: MP38: use Python 3.8 from MacPorts |
|
||||
: HB38: use Python 3.8 from Homebrew |
|
||||
: Ana3: use Python 3.8 from Anaconda3 |
|
||||
[-n|--noqtbinding] : don't create Qt bindings for ruby scripts | disabled
|
||||
[-m|--make <option>] : option passed to 'make' | '-j4'
|
||||
[-d|--debug] : enable debug mode build | disabled
|
||||
[-c|--checkcom] : check command-line and exit without building | disabled
|
||||
[-c|--checkcom] : check command line and exit without building | disabled
|
||||
[-y|--deploy] : deploy executables and dylibs including Qt's Frameworks | disabled
|
||||
[-Y|--DEPLOY] : deploy executables and dylibs for those who built KLayout | disabled
|
||||
: from the source code and use the tools in the same machine |
|
||||
|
|
@ -126,64 +126,64 @@ Then the directory name will be **`LW-qt5MP.pkg.macos-Catalina-release-RsysPsys`
|
|||
|
||||
#### If you build KLayout from the source code AND use it on the same machine, "-Y" option is highly recommended. ####
|
||||
|
||||
### 6B. Fully MacPorts-flavored build with MacPorts Ruby 2.6 and MacPorts Python 3.7
|
||||
### 6B. Fully MacPorts-flavored build with MacPorts Ruby 2.6 and MacPorts Python 3.8
|
||||
```
|
||||
$ cd /where/'build.sh'/exists
|
||||
$ ./build4mac.py -q qt5macports -r mp26 -p mp37
|
||||
$ ./build4mac.py -q qt5macports -r mp26 -p mp38
|
||||
```
|
||||
2. Confirm successful build (it will take about one hour depending on your machine spec).
|
||||
3. Run **`build4mac.py`** again with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.<br>
|
||||
The buddy command-line tools (strm*) will also be deployed in this step.
|
||||
```
|
||||
$ ./build4mac.py -q qt5macports -r mp26 -p mp37 -Y
|
||||
$ ./build4mac.py -q qt5macports -r mp26 -p mp38 -Y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`LW-qt5MP.pkg.macos-Catalina-release-Rmp26Pmp37`** directory, where
|
||||
**`LW-qt5MP.pkg.macos-Catalina-release-Rmp26Pmp38`** directory, where
|
||||
* "LW-" means that this is a lightweight package.
|
||||
* "qt5MP" means that Qt5 from MacPorts is used.
|
||||
* "Rmp26Pmp37" means that Ruby is 2.6 from MacPorts; Python is 3.7 from MacPorts.
|
||||
* "Rmp26Pmp38" means that Ruby is 2.6 from MacPorts; Python is 3.8 from MacPorts.
|
||||
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
|
||||
|
||||
### 6C. Fully Homebrew-flavored build with Homebrew Ruby 2.7 and Homebrew Python 3.7
|
||||
### 6C. Fully Homebrew-flavored build with Homebrew Ruby 2.7 and Homebrew Python 3.8
|
||||
```
|
||||
$ cd /where/'build.sh'/exists
|
||||
$ ./build4mac.py -q qt5brew -r hb27 -p hb37
|
||||
$ ./build4mac.py -q qt5brew -r hb27 -p hb38
|
||||
```
|
||||
2. Confirm successful build (it will take about one hour depending on your machine spec).
|
||||
3. Run **`build4mac.py`** again with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.<br>
|
||||
The buddy command-line tools (strm*) will also be deployed in this step.
|
||||
```
|
||||
$ ./build4mac.py -q qt5brew -r hb27 -p hb37 -Y
|
||||
$ ./build4mac.py -q qt5brew -r hb27 -p hb38 -Y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`LW-qt5Brew.pkg.macos-Catalina-release-Rhb27Phb37`** directory, where
|
||||
**`LW-qt5Brew.pkg.macos-Catalina-release-Rhb27Phb38`** directory, where
|
||||
* "LW-" means that this is a lightweight package.
|
||||
* "qt5Brew" means that Qt5 from Homebrew is used.
|
||||
* "Rhb27Phb37" means that Ruby is 2.7 from Homebrew; Python is 3.7 from Homebrew.
|
||||
* "Rhb27Phb38" means that Ruby is 2.7 from Homebrew; Python is 3.8 from Homebrew.
|
||||
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
|
||||
|
||||
### 6D. Partially Homebrew-flavored build with System Ruby and Homebrew Python 3.7
|
||||
### 6D. Partially Homebrew-flavored build with System Ruby and Homebrew Python 3.8
|
||||
```
|
||||
$ cd /where/'build.sh'/exists
|
||||
$ ./build4mac.py -q qt5brew -r sys -p hb37
|
||||
$ ./build4mac.py -q qt5brew -r sys -p hb38
|
||||
```
|
||||
2. Confirm successful build (it will take about one hour depending on your machine spec).
|
||||
3. Run **`build4mac.py`** again with the same options used in 1. PLUS "-y" to deploy executables and libraries (including Qt's frameworks and Python frameworks) under **`klayout.app`** bundle.<br>
|
||||
The buddy command-line tools (strm*) will also be deployed in this step.
|
||||
```
|
||||
$ ./build4mac.py -q qt5brew -r sys -p hb37 -y
|
||||
$ ./build4mac.py -q qt5brew -r sys -p hb38 -y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`HW-qt5Brew.pkg.macos-Catalina-release-RsysPhb37`** directory, where
|
||||
**`HW-qt5Brew.pkg.macos-Catalina-release-RsysPhb38`** directory, where
|
||||
* "HW-" means that this is a heavyweight package because both Qt5 and Python are deployed.
|
||||
* "qt5Brew" means that Qt5 from Homebrew is used.
|
||||
* "RsysPhb37" means that Ruby is OS-bundled; Python is 3.7 from Homebrew.
|
||||
* "RsysPhb38" means that Ruby is OS-bundled; Python is 3.8 from Homebrew.
|
||||
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
|
||||
### Important ###
|
||||
So far, deployment of Homebrew Ruby is not supported. <br>
|
||||
Therefore, if you intend to use "-y" option, you need to use "-r sys" for building.
|
||||
|
||||
### 6E. Fully Anaconda3-flavored build with Anaconda3 Ruby 2.5 and Anaconda3 Python 3.7
|
||||
### 6E. Fully Anaconda3-flavored build with Anaconda3 Ruby 2.5 and Anaconda3 Python 3.8
|
||||
```
|
||||
$ cd /where/'build.sh'/exists
|
||||
$ ./build4mac.py -q qt5ana3 -r ana3 -p ana3
|
||||
|
|
@ -198,7 +198,7 @@ $ ./build4mac.py -q qt5ana3 -r ana3 -p ana3 -Y
|
|||
**`LW-qt5Ana3.pkg.macos-Catalina-release-Rana3Pana3`** directory, where
|
||||
* "LW-" means that this is a lightweight package.
|
||||
* "qt5Ana3" means that Qt5 from Anaconda3 is used.
|
||||
* "Rana3Pana3" means that Ruby (2.5) is from Anaconda3; Python (3.7) is from Anaconda3.
|
||||
* "Rana3Pana3" means that Ruby (2.5) is from Anaconda3; Python (3.8) is from Anaconda3.
|
||||
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
|
||||
5. You may have to set `PYTHONHOME` environment variable like:
|
||||
```
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -26,6 +26,12 @@
|
|||
-------------------------------------------------------------------------------------------------
|
||||
on run (volumeName) -- most likely, the volume name is "KLayout"
|
||||
tell application "Finder"
|
||||
repeat 20 times
|
||||
if (exists (disk (volumeName as string))) then
|
||||
exit repeat
|
||||
end if
|
||||
delay 1
|
||||
end repeat
|
||||
tell disk (volumeName as string)
|
||||
-- [1] Open the volume
|
||||
open
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -104,9 +104,10 @@ RubyMojave = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions/2
|
|||
# !!! Catalina does not allow to hack the "/System" directory; it's READ ONLY even for the super user!
|
||||
# Hence, we need to refer to the Ruby header file in "Xcode.app" directly.
|
||||
# [Key Type Name] = 'Sys'
|
||||
CatalinaSDK = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk"
|
||||
CatalinaSDK = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk"
|
||||
RubyCatalina = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/bin/ruby',
|
||||
'inc': '%s/System/Library/Frameworks/Ruby.framework/Headers' % CatalinaSDK,
|
||||
'inc2': '%s/System/Library/Frameworks/Ruby.framework/Headers/ruby' % CatalinaSDK,
|
||||
'lib': '/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/libruby.dylib'
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +155,7 @@ RubyDictionary = { 'nil' : None,
|
|||
#-----------------------------------------------------
|
||||
PythonNil = [ 'nil' ]
|
||||
PythonSys = [ 'PythonElCapitan', 'PythonSierra', 'PythonHighSierra', 'PythonMojave', 'PythonCatalina' ]
|
||||
PythonExt = [ 'Python37MacPorts', 'Python37Brew', 'PythonAnaconda3' ]
|
||||
PythonExt = [ 'Python38MacPorts', 'Python38Brew', 'PythonAnaconda3' ]
|
||||
Pythons = PythonNil + PythonSys + PythonExt
|
||||
|
||||
#-----------------------------------------------------
|
||||
|
|
@ -204,30 +205,45 @@ PythonCatalina = { 'exe': '/System/Library/Frameworks/Python.framework/Versions
|
|||
'lib': '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/libpython2.7.dylib'
|
||||
}
|
||||
|
||||
# Python 3.7 from MacPorts (https://www.macports.org/) *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# install with 'sudo port install python37'
|
||||
# [Key Type Name] = 'MP37'
|
||||
Python37MacPorts= { 'exe': '/opt/local/Library/Frameworks/Python.framework/Versions/3.7/bin/python3.7m',
|
||||
'inc': '/opt/local/Library/Frameworks/Python.framework/Versions/3.7/include/python3.7m',
|
||||
'lib': '/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/libpython3.7m.dylib'
|
||||
# Python 3.8 from MacPorts (https://www.macports.org/) *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# install with 'sudo port install python38'
|
||||
# [Key Type Name] = 'MP38'
|
||||
Python38MacPorts= { 'exe': '/opt/local/Library/Frameworks/Python.framework/Versions/3.8/bin/python3.8',
|
||||
'inc': '/opt/local/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8',
|
||||
'lib': '/opt/local/Library/Frameworks/Python.framework/Versions/3.8/lib/libpython3.8.dylib'
|
||||
}
|
||||
|
||||
# Python 3.7 from Homebrew *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# Python 3.8 from Homebrew *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# install with 'brew install python'
|
||||
# [Key Type Name] = 'HB37'
|
||||
HBPython37FrameworkPath = '/usr/local/opt/python3/Frameworks/Python.framework'
|
||||
Python37Brew = { 'exe': '%s/Versions/3.7/bin/python3.7m' % HBPython37FrameworkPath,
|
||||
'inc': '%s/Versions/3.7/include/python3.7m' % HBPython37FrameworkPath,
|
||||
'lib': '%s/Versions/3.7/lib/libpython3.7m.dylib' % HBPython37FrameworkPath
|
||||
# [Key Type Name] = 'HB38'
|
||||
HBPython38FrameworkPath = '/usr/local/opt/python3/Frameworks/Python.framework'
|
||||
Python38Brew = { 'exe': '%s/Versions/3.8/bin/python3.8' % HBPython38FrameworkPath,
|
||||
'inc': '%s/Versions/3.8/include/python3.8' % HBPython38FrameworkPath,
|
||||
'lib': '%s/Versions/3.8/lib/libpython3.8.dylib' % HBPython38FrameworkPath
|
||||
}
|
||||
|
||||
# Python 3.7 bundled with anaconda3 installed under /Applications/anaconda3/ *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# # Latest Python from Homebrew *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# # install with 'brew install python'
|
||||
# # [Key Type Name] = 'HBAuto'
|
||||
|
||||
# import glob
|
||||
# # In my system, there are four candidates: (python, python3, python@3, python@3.8)
|
||||
# # Hard to tell which is going to be available to the user. Picking the last one
|
||||
# HBAutoFrameworkPath = glob.glob("/usr/local/opt/python*/Frameworks/Python.framework/")[-1]
|
||||
# # expand 3* into _py_version, there should be only one, but I am taking no chances.
|
||||
# HBAutoFrameworkVersionPath, _py_version = os.path.split(glob.glob("%s/Versions/3*" % HBAutoFrameworkPath)[0])
|
||||
# PythonAutoBrew = { 'exe': '%s/bin/python%s' % (HBAutoFrameworkVersionPath, _py_version),
|
||||
# 'inc': '%s/include/python%s' % (HBAutoFrameworkVersionPath, _py_version),
|
||||
# 'lib': glob.glob("%s/lib/*.dylib" % HBAutoFrameworkVersionPath)[0]
|
||||
# }
|
||||
|
||||
# Python 3.8 bundled with anaconda3 installed under /Applications/anaconda3/ *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# The standard installation deploys the tool under $HOME/opt/anaconda3/.
|
||||
# If so, you need to make a symbolic link: /Applications/anaconda3 ---> $HOME/opt/anaconda3/
|
||||
# [Key Type Name] = 'Ana3'
|
||||
PythonAnaconda3 = { 'exe': '/Applications/anaconda3/bin/python3.7m',
|
||||
'inc': '/Applications/anaconda3/include/python3.7m',
|
||||
'lib': '/Applications/anaconda3/lib/libpython3.7m.dylib'
|
||||
PythonAnaconda3 = { 'exe': '/Applications/anaconda3/bin/python3.8',
|
||||
'inc': '/Applications/anaconda3/include/python3.8',
|
||||
'lib': '/Applications/anaconda3/lib/libpython3.8.dylib'
|
||||
}
|
||||
|
||||
# Consolidated dictionary kit for Python
|
||||
|
|
@ -237,8 +253,8 @@ PythonDictionary= { 'nil' : None,
|
|||
'PythonHighSierra': PythonHighSierra,
|
||||
'PythonMojave' : PythonMojave,
|
||||
'PythonCatalina' : PythonCatalina,
|
||||
'Python37MacPorts': Python37MacPorts,
|
||||
'Python37Brew' : Python37Brew,
|
||||
'Python38MacPorts': Python38MacPorts,
|
||||
'Python38Brew' : Python38Brew,
|
||||
'PythonAnaconda3' : PythonAnaconda3
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#===============================================================================
|
||||
#========================================================================================
|
||||
# File: "macbuild/build4mac_util.py"
|
||||
#
|
||||
# Here are utility functions and classes ...
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
# version 0.26.1 or later on different Apple Mac OSX platforms.
|
||||
#
|
||||
# This file is imported by 'build4mac.py' script.
|
||||
#===============================================================================
|
||||
#========================================================================================
|
||||
from __future__ import print_function # to use print() of Python 3 in Python >= 2.7
|
||||
import sys
|
||||
import os
|
||||
|
|
@ -18,14 +18,14 @@ import string
|
|||
import subprocess
|
||||
import shutil
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To import global dictionaries of different modules
|
||||
#-------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
mydir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.append( mydir )
|
||||
from build4mac_env import *
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To decompose strings obtained by 'otool -L <*.dylib>' command and to
|
||||
# generate a dictionary of KLayout's inter-library dependency.
|
||||
#
|
||||
|
|
@ -41,81 +41,81 @@ from build4mac_env import *
|
|||
# :
|
||||
#
|
||||
# @return a dictionary
|
||||
#------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
def DecomposeLibraryDependency( depstr ):
|
||||
alllines = depstr.split('\n')
|
||||
numlines = len(alllines)
|
||||
dependent = alllines[0].split(':')[0].strip()
|
||||
supporters = []
|
||||
for line in alllines[1:]:
|
||||
supporter = line.strip().split(' ')[0].strip()
|
||||
if not supporter == '':
|
||||
supporters.append(supporter)
|
||||
return { dependent: supporters }
|
||||
alllines = depstr.split('\n')
|
||||
numlines = len(alllines)
|
||||
dependent = alllines[0].split(':')[0].strip()
|
||||
supporters = []
|
||||
for line in alllines[1:]:
|
||||
supporter = line.strip().split(' ')[0].strip()
|
||||
if not supporter == '':
|
||||
supporters.append(supporter)
|
||||
return { dependent: supporters }
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To print the contents of a library dependency dictionary
|
||||
#
|
||||
# @param[in] depdic dictionary
|
||||
# @param[in] pathdic path dictionary
|
||||
# @param[in] namedic dictionary name
|
||||
#------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
def PrintLibraryDependencyDictionary( depdic, pathdic, namedic ):
|
||||
keys = depdic.keys()
|
||||
print("")
|
||||
print("##### Contents of <%s> #####:" % namedic )
|
||||
for key in keys:
|
||||
supporters = depdic[key]
|
||||
keyName = os.path.basename(key)
|
||||
print( " %s: (%s)" % (key, pathdic[keyName]) )
|
||||
for item in supporters:
|
||||
itemName = os.path.basename(item)
|
||||
if itemName != keyName and (itemName in pathdic):
|
||||
print( " %s (%s)" % (item, pathdic[itemName]) )
|
||||
keys = depdic.keys()
|
||||
print("")
|
||||
print("##### Contents of <%s> #####:" % namedic )
|
||||
for key in keys:
|
||||
supporters = depdic[key]
|
||||
keyName = os.path.basename(key)
|
||||
print( " %s: (%s)" % (key, pathdic[keyName]) )
|
||||
for item in supporters:
|
||||
itemName = os.path.basename(item)
|
||||
if itemName != keyName and (itemName in pathdic):
|
||||
print( " %s (%s)" % (item, pathdic[itemName]) )
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To set and change identification name of KLayout's dylib
|
||||
#
|
||||
# @param[in] libdic inter-library dependency dictionary
|
||||
#
|
||||
# @return 0 on success; non-zero on failure
|
||||
#------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
def SetChangeIdentificationNameOfDyLib( libdic, pathDic ):
|
||||
cmdNameId = XcodeToolChain['nameID']
|
||||
cmdNameChg = XcodeToolChain['nameCH']
|
||||
dependentLibs = libdic.keys()
|
||||
cmdNameId = XcodeToolChain['nameID']
|
||||
cmdNameChg = XcodeToolChain['nameCH']
|
||||
dependentLibs = libdic.keys()
|
||||
|
||||
for lib in dependentLibs:
|
||||
#-----------------------------------------------------------
|
||||
# [1] Set the identification name of each dependent library
|
||||
#-----------------------------------------------------------
|
||||
nameOld = "%s" % lib
|
||||
libName = os.path.basename(lib)
|
||||
nameNew = pathDic[libName]
|
||||
command = "%s %s %s" % ( cmdNameId, nameNew, nameOld )
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % lib, file=sys.stderr )
|
||||
return 1
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# [2] Make the library aware of the new identifications of all supporters
|
||||
#-------------------------------------------------------------------------
|
||||
supporters = libdic[lib]
|
||||
for sup in supporters:
|
||||
supName = os.path.basename(sup)
|
||||
if libName != supName and (supName in pathDic):
|
||||
nameOld = "%s" % sup
|
||||
nameNew = pathDic[supName]
|
||||
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, lib )
|
||||
for lib in dependentLibs:
|
||||
#-----------------------------------------------------------
|
||||
# [1] Set the identification name of each dependent library
|
||||
#-----------------------------------------------------------
|
||||
nameOld = "%s" % lib
|
||||
libName = os.path.basename(lib)
|
||||
nameNew = pathDic[libName]
|
||||
command = "%s %s %s" % ( cmdNameId, nameNew, nameOld )
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to make the library aware of the new identification name <%s> of supporter <%s> !!!"
|
||||
print( msg % (nameNew, sup), file=sys.stderr )
|
||||
return 1
|
||||
# for-lib
|
||||
return 0
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % lib, file=sys.stderr )
|
||||
return 1
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------------
|
||||
# [2] Make the library aware of the new identifications of all supporters
|
||||
#-------------------------------------------------------------------------
|
||||
supporters = libdic[lib]
|
||||
for sup in supporters:
|
||||
supName = os.path.basename(sup)
|
||||
if libName != supName and (supName in pathDic):
|
||||
nameOld = "%s" % sup
|
||||
nameNew = pathDic[supName]
|
||||
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, lib )
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to make the library aware of the new identification name <%s> of supporter <%s> !!!"
|
||||
print( msg % (nameNew, sup), file=sys.stderr )
|
||||
return 1
|
||||
# for-lib
|
||||
return 0
|
||||
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To set the identification names of KLayout's libraries to an executable
|
||||
# and make the application aware of the library locations
|
||||
#
|
||||
|
|
@ -146,259 +146,321 @@ def SetChangeIdentificationNameOfDyLib( libdic, pathDic ):
|
|||
# +-- 'strmxor'
|
||||
#
|
||||
# @return 0 on success; non-zero on failure
|
||||
#------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
def SetChangeLibIdentificationName( executable, relativedir ):
|
||||
cmdNameId = XcodeToolChain['nameID']
|
||||
cmdNameChg = XcodeToolChain['nameCH']
|
||||
otoolCm = "otool -L %s | grep libklayout" % executable
|
||||
otoolOut = os.popen( otoolCm ).read()
|
||||
exedepdic = DecomposeLibraryDependency( executable + ":\n" + otoolOut )
|
||||
keys = exedepdic.keys()
|
||||
deplibs = exedepdic[ list(keys)[0] ]
|
||||
cmdNameId = XcodeToolChain['nameID']
|
||||
cmdNameChg = XcodeToolChain['nameCH']
|
||||
otoolCm = "otool -L %s | grep libklayout" % executable
|
||||
otoolOut = os.popen( otoolCm ).read()
|
||||
exedepdic = DecomposeLibraryDependency( executable + ":\n" + otoolOut )
|
||||
keys = exedepdic.keys()
|
||||
deplibs = exedepdic[ list(keys)[0] ]
|
||||
|
||||
for lib in deplibs:
|
||||
#-----------------------------------------------------------
|
||||
# [1] Set the identification names for the library
|
||||
#-----------------------------------------------------------
|
||||
nameOld = "klayout.app/Contents/Frameworks/%s" % lib
|
||||
nameNew = "@executable_path/%s/%s" % ( relativedir, lib )
|
||||
command = "%s %s %s" % ( cmdNameId, nameNew, nameOld )
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % lib, file=sys.stderr )
|
||||
return 1
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# [2] Make the application aware of the new identification
|
||||
#-----------------------------------------------------------
|
||||
nameOld = "%s" % lib
|
||||
nameNew = "@executable_path/%s/%s" % ( relativedir, lib )
|
||||
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, executable )
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to make the application aware of the new identification name <%s> !!!"
|
||||
print( msg % nameNew, file=sys.stderr )
|
||||
return 1
|
||||
# for-lib
|
||||
return 0
|
||||
|
||||
def WalkLibDependencyTree( dylibPath, depth=0, filter_regex=r'\t+/usr/local/opt'):
|
||||
NOTHINGTODO = [] # return empty list if nothing to do.
|
||||
cmdNameId = XcodeToolChain['nameID']
|
||||
cmdNameChg = XcodeToolChain['nameCH']
|
||||
otoolCm = 'otool -L %s | grep -E "%s"' % (dylibPath, filter_regex)
|
||||
otoolOut = os.popen( otoolCm ).read()
|
||||
exedepdic = DecomposeLibraryDependency( dylibPath + ":\n" + otoolOut )
|
||||
keys = exedepdic.keys()
|
||||
deplibs = exedepdic[ list(keys)[0] ]
|
||||
|
||||
if depth < 5:
|
||||
if len(deplibs) > 0:
|
||||
for idx, lib in enumerate(deplibs):
|
||||
lib = str(lib)
|
||||
if lib != list(keys)[0]:
|
||||
deplibs[idx] = WalkLibDependencyTree(lib, depth+1, filter_regex)
|
||||
if depth == 0:
|
||||
return deplibs
|
||||
return exedepdic
|
||||
else:
|
||||
raise RuntimeError("Exceeded maximum recursion depth.")
|
||||
|
||||
def WalkFrameworkPaths(frameworkPaths, filter_regex=r'\.(so|dylib)$', search_path_filter=r'\t+/usr/local/opt'):
|
||||
|
||||
if isinstance(frameworkPaths, str):
|
||||
frameworkPathsIter = [frameworkPaths]
|
||||
else:
|
||||
frameworkPathsIter = frameworkPaths
|
||||
|
||||
dependency_dict = dict()
|
||||
|
||||
for frameworkPath in frameworkPathsIter:
|
||||
# print("Calling:", 'find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex))
|
||||
find_grep_results = os.popen('find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex)).read().split('\n')
|
||||
framework_files = filter(lambda x: x != '',
|
||||
map(lambda x: x.strip(),
|
||||
find_grep_results))
|
||||
|
||||
dependency_dict[frameworkPath] = list()
|
||||
for idx, file in enumerate(framework_files):
|
||||
dict_file = {file: WalkLibDependencyTree(file, filter_regex=search_path_filter)}
|
||||
dependency_dict[frameworkPath].append(dict_file)
|
||||
return dependency_dict
|
||||
|
||||
def WalkDictTree(dependencyDict, visited_files):
|
||||
libNameChanges = list()
|
||||
for lib, dependencies in dependencyDict.items():
|
||||
if lib in visited_files:
|
||||
continue
|
||||
|
||||
dependency_list = list()
|
||||
if isinstance(dependencies, list):
|
||||
for deplib in dependencies:
|
||||
if isinstance(deplib, str):
|
||||
dependency_list.append(deplib)
|
||||
if deplib not in visited_files:
|
||||
visited_files.append(deplib)
|
||||
elif isinstance(deplib, dict):
|
||||
dependency_list.append(next(iter(deplib)))
|
||||
libNameChanges.extend(WalkDictTree(deplib, visited_files))
|
||||
else:
|
||||
#raise RuntimeError("Unexpected value: %s" % deplib)
|
||||
pass
|
||||
else:
|
||||
raise RuntimeError("Unexpected value: %s" % dependencies)
|
||||
if len(dependency_list) > 0:
|
||||
libNameChanges.append((lib, dependency_list))
|
||||
else:
|
||||
libNameChanges.append((lib, ))
|
||||
visited_files.append(lib)
|
||||
return libNameChanges
|
||||
|
||||
|
||||
def FindFramework(path, root_path):
|
||||
relPath = os.path.relpath(path, root_path)
|
||||
return os.path.join(root_path, relPath.split(os.sep)[0])
|
||||
def ResolveExecutablePath(path, executable_path):
|
||||
""" Transforms @executable_path into executable_path"""
|
||||
p = path.replace("@executable_path", "/%s/" % executable_path)
|
||||
return p
|
||||
|
||||
def DetectChanges(frameworkDependencyDict):
|
||||
visited_files = list()
|
||||
libNameChanges = list()
|
||||
for framework, libraries in frameworkDependencyDict.items():
|
||||
for libraryDict in libraries:
|
||||
libNameChanges.extend(WalkDictTree(libraryDict, visited_files))
|
||||
# Changes are stored in libNameChanges in the form of ('lib.dylib', ['dep1.dylib', ...])
|
||||
|
||||
return libNameChanges
|
||||
|
||||
def PerformChanges(frameworkDependencyDict, replaceFromToPairs=None, executable_path="/tmp/klayout"):
|
||||
libNameChanges = DetectChanges(frameworkDependencyDict)
|
||||
cmdNameId = XcodeToolChain['nameID']
|
||||
cmdNameChg = XcodeToolChain['nameCH']
|
||||
|
||||
if replaceFromToPairs is not None:
|
||||
for libNameChange in libNameChanges:
|
||||
libNameChangeIterator = iter(libNameChange)
|
||||
lib = next(libNameChangeIterator)
|
||||
try:
|
||||
dependencies = next(libNameChangeIterator)
|
||||
except StopIteration:
|
||||
dependencies = list()
|
||||
for replaceFrom, replaceTo, libdir in replaceFromToPairs:
|
||||
fileName = ResolveExecutablePath(lib.replace(replaceFrom, replaceTo), executable_path)
|
||||
if fileName.startswith('/usr'):
|
||||
# print(f'skipping fileName: {fileName}')
|
||||
continue
|
||||
|
||||
if lib.find(replaceFrom) >= 0:
|
||||
if libdir:
|
||||
frameworkPath = FindFramework(lib, replaceFrom)
|
||||
else:
|
||||
frameworkPath = lib
|
||||
destFrameworkPath = frameworkPath.replace(replaceFrom, replaceTo)
|
||||
destFrameworkPath = ResolveExecutablePath(destFrameworkPath, executable_path)
|
||||
|
||||
if not os.path.exists(fileName):
|
||||
print (lib.replace(replaceFrom, replaceTo), "DOES NOT EXIST")
|
||||
print ("COPY", frameworkPath, " -> ", destFrameworkPath)
|
||||
shutil.copytree(frameworkPath, destFrameworkPath)
|
||||
|
||||
nameId = lib.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s" % ( cmdNameId, nameId, fileName )
|
||||
if not os.access(fileName, os.W_OK):
|
||||
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
|
||||
# print("\t%s" % command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
for lib in deplibs:
|
||||
#-----------------------------------------------------------
|
||||
# [1] Set the identification names for the library
|
||||
#-----------------------------------------------------------
|
||||
nameOld = "klayout.app/Contents/Frameworks/%s" % lib
|
||||
nameNew = "@executable_path/%s/%s" % ( relativedir, lib )
|
||||
command = "%s %s %s" % ( cmdNameId, nameNew, nameOld )
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % fileName, file=sys.stderr )
|
||||
print( msg % lib, file=sys.stderr )
|
||||
return 1
|
||||
|
||||
for dependency in dependencies:
|
||||
if dependency.find(replaceFrom) >= 0:
|
||||
print("\tIn:", fileName)
|
||||
print("\tRENAME", dependency, " -> ", dependency.replace(replaceFrom, replaceTo))
|
||||
#-----------------------------------------------------------
|
||||
# [2] Make the application aware of the new identification
|
||||
#-----------------------------------------------------------
|
||||
nameOld = "%s" % lib
|
||||
nameNew = "@executable_path/%s/%s" % ( relativedir, lib )
|
||||
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, executable )
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to make the application aware of the new identification name <%s> !!!"
|
||||
print( msg % nameNew, file=sys.stderr )
|
||||
return 1
|
||||
# for-lib
|
||||
return 0
|
||||
|
||||
# Try changing id first
|
||||
nameId = dependency.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s" % ( cmdNameId, nameId, fileName)
|
||||
if not os.access(str(fileName), os.W_OK):
|
||||
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
|
||||
# print("\t%s" % command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % fileName, file=sys.stderr )
|
||||
return 1
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To make a library dependency dictionary by recursively walk down the lib hierarchy
|
||||
#
|
||||
# @param[in] dylibPath: dylib path
|
||||
# @param[in] depth: hierarchy depth (< 5)
|
||||
# @param[in] filter_regex: filter regular expression
|
||||
#
|
||||
# @return a dictionary
|
||||
#----------------------------------------------------------------------------------------
|
||||
def WalkLibDependencyTree( dylibPath, depth=0, filter_regex=r'\t+/usr/local/opt' ):
|
||||
otoolCm = 'otool -L %s | grep -E "%s"' % (dylibPath, filter_regex)
|
||||
otoolOut = os.popen( otoolCm ).read()
|
||||
exedepdic = DecomposeLibraryDependency( dylibPath + ":\n" + otoolOut )
|
||||
keys = exedepdic.keys()
|
||||
deplibs = exedepdic[ list(keys)[0] ]
|
||||
|
||||
# Rename dependencies
|
||||
nameOld = dependency
|
||||
nameNew = dependency.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, str(fileName) )
|
||||
if not os.access(str(fileName), os.W_OK):
|
||||
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
|
||||
if depth < 5:
|
||||
if len(deplibs) > 0:
|
||||
for idx, lib in enumerate(deplibs):
|
||||
lib = str(lib)
|
||||
if lib != list(keys)[0]:
|
||||
deplibs[idx] = WalkLibDependencyTree(lib, depth+1, filter_regex)
|
||||
if depth == 0:
|
||||
return deplibs
|
||||
return exedepdic
|
||||
else:
|
||||
raise RuntimeError( "Exceeded maximum recursion depth." )
|
||||
|
||||
# print("\t%s" % command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % fileName, file=sys.stderr )
|
||||
return 1
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To make a library dependency dictionary by recursively walk down the Framework
|
||||
#
|
||||
# @param[in] frameworkPaths: Framework path
|
||||
# @param[in] filter_regex: filter regular expression
|
||||
# @param[in] search_path_filter: search path filter regular expression
|
||||
#
|
||||
# @return a dictionary
|
||||
#----------------------------------------------------------------------------------------
|
||||
def WalkFrameworkPaths( frameworkPaths, filter_regex=r'\.(so|dylib)$',
|
||||
search_path_filter=r'\t+/usr/local/opt' ):
|
||||
|
||||
if isinstance(frameworkPaths, str):
|
||||
frameworkPathsIter = [frameworkPaths]
|
||||
else:
|
||||
frameworkPathsIter = frameworkPaths
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
dependency_dict = dict()
|
||||
|
||||
for frameworkPath in frameworkPathsIter:
|
||||
# print("Calling:", 'find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex))
|
||||
find_grep_results = os.popen('find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex)).read().split('\n')
|
||||
framework_files = filter(lambda x: x != '',
|
||||
map(lambda x: x.strip(),
|
||||
find_grep_results))
|
||||
|
||||
dependency_dict[frameworkPath] = list()
|
||||
for idx, file in enumerate(framework_files):
|
||||
dict_file = {file: WalkLibDependencyTree(file, filter_regex=search_path_filter)}
|
||||
dependency_dict[frameworkPath].append(dict_file)
|
||||
return dependency_dict
|
||||
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To make a list of changed libraries
|
||||
#
|
||||
# @param[in] dependencyDict: library dependency dictionary
|
||||
# @param[in] visited_files: list of visited files
|
||||
#
|
||||
# @return a list
|
||||
#----------------------------------------------------------------------------------------
|
||||
def WalkDictTree( dependencyDict, visited_files ):
|
||||
libNameChanges = list()
|
||||
for lib, dependencies in dependencyDict.items():
|
||||
if lib in visited_files:
|
||||
continue
|
||||
|
||||
dependency_list = list()
|
||||
if isinstance(dependencies, list):
|
||||
for deplib in dependencies:
|
||||
if isinstance(deplib, str):
|
||||
dependency_list.append(deplib)
|
||||
if deplib not in visited_files:
|
||||
visited_files.append(deplib)
|
||||
elif isinstance(deplib, dict):
|
||||
dependency_list.append(next(iter(deplib)))
|
||||
libNameChanges.extend(WalkDictTree(deplib, visited_files))
|
||||
else:
|
||||
#raise RuntimeError("Unexpected value: %s" % deplib)
|
||||
pass
|
||||
else:
|
||||
raise RuntimeError("Unexpected value: %s" % dependencies)
|
||||
if len(dependency_list) > 0:
|
||||
libNameChanges.append((lib, dependency_list))
|
||||
else:
|
||||
libNameChanges.append((lib, ))
|
||||
visited_files.append(lib)
|
||||
return libNameChanges
|
||||
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To find the Framework name from a library name
|
||||
#
|
||||
# @param[in] path: path to a library
|
||||
# @param[in] root_path: root path
|
||||
#
|
||||
# @return the path to a Framework
|
||||
#----------------------------------------------------------------------------------------
|
||||
def FindFramework( path, root_path ):
|
||||
relPath = os.path.relpath(path, root_path)
|
||||
frmPath = os.path.join(root_path, relPath.split(os.sep)[0])
|
||||
#print( "###", frmPath, path, root_path )
|
||||
return frmPath
|
||||
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To resolve an executable path
|
||||
#
|
||||
# @param[in] path: a path to resolve
|
||||
# @param[in] executable_path: an executable path
|
||||
#
|
||||
# @return the resolved path
|
||||
#----------------------------------------------------------------------------------------
|
||||
def ResolveExecutablePath( path, executable_path ):
|
||||
""" Transforms @executable_path into executable_path"""
|
||||
p = path.replace("@executable_path", "/%s/" % executable_path)
|
||||
return p
|
||||
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To detect the changed library names
|
||||
#
|
||||
# @param[in] frameworkDependencyDict: framework dependency dictionary
|
||||
#
|
||||
# @return a list of changes, each of which is stored in the form of
|
||||
# * ('lib.dylib', ['dep1.dylib', ...])
|
||||
# OR
|
||||
# * ('lib.dylib',)
|
||||
#----------------------------------------------------------------------------------------
|
||||
def DetectChanges(frameworkDependencyDict):
|
||||
visited_files = list()
|
||||
libNameChanges = list()
|
||||
for framework, libraries in frameworkDependencyDict.items():
|
||||
for libraryDict in libraries:
|
||||
libNameChanges.extend(WalkDictTree(libraryDict, visited_files))
|
||||
return libNameChanges
|
||||
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To perform the required changes
|
||||
#
|
||||
# @param[in] frameworkDependencyDict: framework dependency dictionary
|
||||
# @param[in] replaceFromToPairs: (from, to)-pair for replacement
|
||||
# @param[in] executable_path: executable path
|
||||
#
|
||||
# @return 0 on success; > 0 on failure
|
||||
#----------------------------------------------------------------------------------------
|
||||
def PerformChanges( frameworkDependencyDict, replaceFromToPairs=None, executable_path="/tmp/klayout" ):
|
||||
libNameChanges = DetectChanges(frameworkDependencyDict)
|
||||
#print(libNameChanges)
|
||||
cmdNameId = XcodeToolChain['nameID']
|
||||
cmdNameChg = XcodeToolChain['nameCH']
|
||||
|
||||
if replaceFromToPairs is None:
|
||||
return 0
|
||||
else:
|
||||
for libNameChange in libNameChanges:
|
||||
libNameChangeIterator = iter(libNameChange)
|
||||
lib = next(libNameChangeIterator)
|
||||
try:
|
||||
dependencies = next(libNameChangeIterator)
|
||||
except StopIteration:
|
||||
dependencies = list()
|
||||
for replaceFrom, replaceTo, libdir in replaceFromToPairs:
|
||||
fileName = ResolveExecutablePath(lib.replace(replaceFrom, replaceTo), executable_path)
|
||||
if fileName.startswith('/usr'):
|
||||
# print(f'skipping fileName: {fileName}')
|
||||
continue
|
||||
|
||||
if lib.find(replaceFrom) >= 0:
|
||||
if libdir:
|
||||
frameworkPath = FindFramework(lib, replaceFrom)
|
||||
else:
|
||||
frameworkPath = lib
|
||||
destFrameworkPath = frameworkPath.replace(replaceFrom, replaceTo)
|
||||
destFrameworkPath = ResolveExecutablePath(destFrameworkPath, executable_path)
|
||||
|
||||
if not os.path.exists(fileName):
|
||||
print( " NOT FOUND:", lib.replace(replaceFrom, replaceTo) )
|
||||
print( " COPYING:", frameworkPath, " -> ", destFrameworkPath )
|
||||
shutil.copytree(frameworkPath, destFrameworkPath)
|
||||
|
||||
nameId = lib.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s" % ( cmdNameId, nameId, fileName )
|
||||
if not os.access(fileName, os.W_OK):
|
||||
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
|
||||
# print("\t%s" % command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % fileName, file=sys.stderr )
|
||||
return 1
|
||||
|
||||
for dependency in dependencies:
|
||||
if dependency.find(replaceFrom) >= 0:
|
||||
print( " IN:", fileName )
|
||||
print( " RENAMING:", dependency, " -> ", dependency.replace(replaceFrom, replaceTo) )
|
||||
|
||||
# Try changing id first
|
||||
nameId = dependency.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s" % ( cmdNameId, nameId, fileName)
|
||||
if not os.access(str(fileName), os.W_OK):
|
||||
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
|
||||
# print("\t%s" % command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % fileName, file=sys.stderr )
|
||||
return 1
|
||||
|
||||
# Rename dependencies
|
||||
nameOld = dependency
|
||||
nameNew = dependency.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, str(fileName) )
|
||||
if not os.access(str(fileName), os.W_OK):
|
||||
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
|
||||
|
||||
# print("\t%s" % command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % fileName, file=sys.stderr )
|
||||
return 1
|
||||
return 0
|
||||
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To get KLayout's version from a file; most likely from 'version.sh'
|
||||
#
|
||||
# @param[in] verfile version file from which version is retrieved
|
||||
#
|
||||
# @return version string
|
||||
#------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
def GetKLayoutVersionFrom( verfile='version.h' ):
|
||||
version = "?.?.?"
|
||||
try:
|
||||
fd = open( verfile, "r" )
|
||||
contents = fd.readlines()
|
||||
fd.close()
|
||||
except Exception as e:
|
||||
version = "?.?.?"
|
||||
try:
|
||||
fd = open( verfile, "r" )
|
||||
contents = fd.readlines()
|
||||
fd.close()
|
||||
except Exception as e:
|
||||
return version
|
||||
|
||||
verReg = re.compile( u'(KLAYOUT_VERSION=\")([0-9A-Z_a-z\.]+)(\")' )
|
||||
for line in contents:
|
||||
m = verReg.match(line)
|
||||
if m:
|
||||
# print(m.group(0)) # KLAYOUT_VERSION="0.26.1"
|
||||
# print(m.group(1)) # KLAYOUT_VERSION="
|
||||
# print(m.group(2)) # 0.26.1
|
||||
# print(m.group(3)) # "
|
||||
version = m.group(2)
|
||||
return version
|
||||
return version
|
||||
|
||||
verReg = re.compile( u'(KLAYOUT_VERSION=\")([0-9A-Z_a-z\.]+)(\")' )
|
||||
for line in contents:
|
||||
m = verReg.match(line)
|
||||
if m:
|
||||
# print(m.group(0)) # KLAYOUT_VERSION="0.26.1"
|
||||
# print(m.group(1)) # KLAYOUT_VERSION="
|
||||
# print(m.group(2)) # 0.26.1
|
||||
# print(m.group(3)) # "
|
||||
version = m.group(2)
|
||||
return version
|
||||
return version
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
## To generate the contents of "Info.plist" file from a template
|
||||
#
|
||||
# @param[in] keydic dictionary of four key words ['exe', 'icon', 'bname', 'ver']
|
||||
# @param[in] templfile template file ("macbuild/Resources/Info.plist.template")
|
||||
#
|
||||
# @return generated strings
|
||||
#------------------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------------------------
|
||||
def GenerateInfoPlist( keydic, templfile ):
|
||||
val_exe = keydic['exe']
|
||||
val_icon = keydic['icon']
|
||||
val_bname = keydic['bname']
|
||||
val_ver = keydic['ver']
|
||||
val_exe = keydic['exe']
|
||||
val_icon = keydic['icon']
|
||||
val_bname = keydic['bname']
|
||||
val_ver = keydic['ver']
|
||||
|
||||
try:
|
||||
fd = open( templfile, "r" )
|
||||
template = fd.read()
|
||||
fd.close()
|
||||
except Exception as e:
|
||||
return "???"
|
||||
try:
|
||||
fd = open( templfile, "r" )
|
||||
template = fd.read()
|
||||
fd.close()
|
||||
except Exception as e:
|
||||
return "???"
|
||||
|
||||
t = string.Template(template)
|
||||
s = t.substitute( EXECUTABLE = val_exe,
|
||||
ICONFILE = val_icon,
|
||||
BUNDLENAME = val_bname,
|
||||
VERSION = val_ver)
|
||||
return s
|
||||
t = string.Template(template)
|
||||
s = t.substitute( EXECUTABLE = val_exe,
|
||||
ICONFILE = val_icon,
|
||||
BUNDLENAME = val_bname,
|
||||
VERSION = val_ver)
|
||||
return s
|
||||
|
||||
#----------------
|
||||
# End of File
|
||||
|
|
|
|||
|
|
@ -0,0 +1,278 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#===============================================================================
|
||||
# File: "macbuild/macQAT.py"
|
||||
#
|
||||
# The top Python script to run "ut_runner" after building KLayout
|
||||
# (http://www.klayout.de/index.php) version 0.26.1 or later on different Apple
|
||||
# ßMac OSX platforms.
|
||||
#
|
||||
# This script must be copied to a "*.macQAT/" directory to run.
|
||||
#===============================================================================
|
||||
from __future__ import print_function # to use print() of Python 3 in Python >= 2.7
|
||||
import sys
|
||||
import os
|
||||
import datetime
|
||||
from time import sleep
|
||||
import six
|
||||
import shutil
|
||||
import glob
|
||||
import platform
|
||||
import optparse
|
||||
import subprocess
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
## To set global variables including present directory and platform info.
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
def SetGlobals():
|
||||
global ProjectDir # project directory where "ut_runner" exists
|
||||
global RunnerUsage # True to print the usage of 'ut_runner'
|
||||
global Run # True to run this script
|
||||
global ContinueOnError # True to continue after an error
|
||||
global TestsExcluded # list of tests to exclude
|
||||
global Arguments # other arguments
|
||||
global GitSHA1 # Git's short SHA1 value of the HEAD
|
||||
global TimeStamp # time stamp
|
||||
global WorkDir # work directory name
|
||||
global LogFile # log file name
|
||||
global Usage # string on usage
|
||||
# auxiliary variables on platform
|
||||
global System # 6-tuple from platform.uname()
|
||||
global Node # - do -
|
||||
global Release # - do -
|
||||
global Version # - do -
|
||||
global Machine # - do -
|
||||
global Processor # - do -
|
||||
global Bit # machine bit-size
|
||||
|
||||
Usage = "\n"
|
||||
Usage += "----------------------------------------------------------------------------------------\n"
|
||||
Usage += "<< Usage of 'macQAT.py' >>\n"
|
||||
Usage += " for running 'ut_runner' after building KLayout.\n"
|
||||
Usage += "\n"
|
||||
Usage += "$ [python] ./macQAT.py \n"
|
||||
Usage += " option & argument : descriptions | default value\n"
|
||||
Usage += " -----------------------------------------------------------------+---------------\n"
|
||||
Usage += " [-u|--usage] : print usage of 'ut_runner'and exit | disabled \n"
|
||||
Usage += " | \n"
|
||||
Usage += " <-r|--run> : run this script | disabled \n"
|
||||
Usage += " [-s|--stop] : stop on error | disabled \n"
|
||||
Usage += " [-x|--exclude <tests>] : exclude test(s) such as 'pymod,pya' | '' \n"
|
||||
Usage += " [-a|--args <string>] : arguments other than '-x' and '-c' | '' \n"
|
||||
Usage += " [-?|--?] : print this usage and exit | disabled \n"
|
||||
Usage += "--------------------------------------------------------------------+-------------------\n"
|
||||
|
||||
ProjectDir = os.getcwd()
|
||||
RunnerUsage = False
|
||||
Run = False
|
||||
ContinueOnError = True
|
||||
TestsExcluded = list()
|
||||
Arguments = ""
|
||||
GitSHA1 = GetGitShortSHA1()
|
||||
TimeStamp = GetTimeStamp()
|
||||
WorkDir = "QATest_%s_%s__%s" % (GitSHA1, TimeStamp, os.path.basename(ProjectDir) )
|
||||
LogFile = WorkDir + ".log"
|
||||
|
||||
(System, Node, Release, Version, Machine, Processor) = platform.uname()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
## Get git's short SHA1 value of the HEAD
|
||||
#
|
||||
# @return SHA1 value string
|
||||
#-------------------------------------------------------------------------------
|
||||
def GetGitShortSHA1():
|
||||
command = "git rev-parse --short HEAD 2>/dev/null"
|
||||
sha1val = os.popen( command ).read().strip()
|
||||
return sha1val
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
## Get the time stamp
|
||||
#
|
||||
# @return time stamp string
|
||||
#-------------------------------------------------------------------------------
|
||||
def GetTimeStamp():
|
||||
ts = datetime.datetime.today()
|
||||
return "%04d_%02d%02d_%02d%02d" % (ts.year, ts.month, ts.day, ts.hour, ts.minute)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
## To parse the command line arguments
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
def ParseCommandLineArguments():
|
||||
global Usage
|
||||
global RunnerUsage
|
||||
global Run
|
||||
global ContinueOnError
|
||||
global TestsExcluded
|
||||
global Arguments
|
||||
|
||||
p = optparse.OptionParser( usage=Usage )
|
||||
p.add_option( '-u', '--usage',
|
||||
action='store_true',
|
||||
dest='runner_usage',
|
||||
default=False,
|
||||
help="print usage of 'ut_runner' and exit (false)" )
|
||||
|
||||
p.add_option( '-r', '--run',
|
||||
action='store_true',
|
||||
dest='runme',
|
||||
default=False,
|
||||
help='run this script (false)' )
|
||||
|
||||
p.add_option( '-s', '--stop',
|
||||
action='store_true',
|
||||
dest='stop_on_error',
|
||||
default=False,
|
||||
help='stop on error (false)' )
|
||||
|
||||
p.add_option( '-x', '--exclude',
|
||||
dest='exclude_tests',
|
||||
help="exclude test(s) such as 'pymod,pya' ('')" )
|
||||
|
||||
p.add_option( '-a', '--args',
|
||||
dest='arguments',
|
||||
help="arguments other than '-x' and '-c' ('')" )
|
||||
|
||||
p.add_option( '-?', '--??',
|
||||
action='store_true',
|
||||
dest='checkusage',
|
||||
default=False,
|
||||
help='check usage (false)' )
|
||||
|
||||
p.set_defaults( runner_usage = False,
|
||||
runme = False,
|
||||
stop_on_error = False,
|
||||
exclude_tests = "",
|
||||
arguments = "",
|
||||
checkusage = False )
|
||||
|
||||
opt, args = p.parse_args()
|
||||
if opt.checkusage:
|
||||
print(Usage)
|
||||
quit()
|
||||
|
||||
RunnerUsage = opt.runner_usage
|
||||
Run = opt.runme
|
||||
ContinueOnError = not opt.stop_on_error
|
||||
if not opt.exclude_tests == "":
|
||||
TestsExcluded = [ item.strip() for item in opt.exclude_tests.split(',') ]
|
||||
else:
|
||||
TestsExcluded = []
|
||||
Arguments = opt.arguments
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
## Hide/Show the private directory
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
def HidePrivateDir():
|
||||
if os.path.isdir( "../private" ):
|
||||
os.rename( "../private", "../private.stash" )
|
||||
|
||||
def ShowPrivateDir():
|
||||
if os.path.isdir( "../private.stash" ):
|
||||
os.rename( "../private.stash", "../private" )
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
## Export environment variables for "ut_runner"
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
def ExportEnvVariables():
|
||||
global ProjectDir
|
||||
global WorkDir
|
||||
global MyEnviron # my environment variables; can be independently used later
|
||||
|
||||
# In older versions of subprocess module, 'env=None' argument is not provided
|
||||
MyEnviron = os.environ.copy()
|
||||
MyEnviron[ 'TESTSRC' ] = ".."
|
||||
MyEnviron[ 'TESTTMP' ] = WorkDir
|
||||
if System == "Darwin":
|
||||
MyEnviron[ 'DYLD_LIBRARY_PATH' ] = "%s:%s/db_plugins" % (ProjectDir, ProjectDir)
|
||||
for env in [ 'TESTSRC', 'TESTTMP', 'DYLD_LIBRARY_PATH' ]:
|
||||
os.environ[env] = MyEnviron[env]
|
||||
else:
|
||||
MyEnviron[ 'LD_LIBRARY_PATH' ] = "%s:%s/db_plugins" % (ProjectDir, ProjectDir)
|
||||
for env in [ 'TESTSRC', 'TESTTMP', 'LD_LIBRARY_PATH' ]:
|
||||
os.environ[env] = MyEnviron[env]
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
## Run the tester
|
||||
#
|
||||
# @param[in] command command string to run
|
||||
# @param[in] logfile log file name
|
||||
#-------------------------------------------------------------------------------
|
||||
def RunTester( command, logfile="" ):
|
||||
if six.PY3:
|
||||
proc = subprocess.Popen( command.split(), stdout=subprocess.PIPE, \
|
||||
stderr=subprocess.STDOUT, \
|
||||
universal_newlines=True )
|
||||
else:
|
||||
proc = subprocess.Popen( command.split(), stdout=subprocess.PIPE, \
|
||||
stderr=subprocess.STDOUT )
|
||||
|
||||
if not logfile == "":
|
||||
with proc.stdout, open( logfile, 'w' ) as file:
|
||||
for line in proc.stdout:
|
||||
sys.stdout.write(line)
|
||||
file.write(line)
|
||||
proc.wait()
|
||||
else:
|
||||
with proc.stdout:
|
||||
for line in proc.stdout:
|
||||
sys.stdout.write(line)
|
||||
proc.wait()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Main function
|
||||
#-------------------------------------------------------------------------------
|
||||
def Main():
|
||||
#-------------------------------------------------------
|
||||
# [1] Initialize
|
||||
#-------------------------------------------------------
|
||||
SetGlobals()
|
||||
ParseCommandLineArguments()
|
||||
ExportEnvVariables()
|
||||
|
||||
#-------------------------------------------------------
|
||||
# [2] Print the runner's usage
|
||||
#-------------------------------------------------------
|
||||
if RunnerUsage:
|
||||
command = './ut_runner --help-all'
|
||||
RunTester( command )
|
||||
quit()
|
||||
|
||||
#-------------------------------------------------------
|
||||
# [3] Run the unit tester
|
||||
#-------------------------------------------------------
|
||||
if not Run:
|
||||
print( "! pass <-r|--run> option to run" )
|
||||
print(Usage)
|
||||
quit()
|
||||
|
||||
command = './ut_runner'
|
||||
if ContinueOnError:
|
||||
command += " -c"
|
||||
for item in TestsExcluded:
|
||||
command += ' -x %s' % item
|
||||
if not Arguments == "":
|
||||
command += " %s" % Arguments
|
||||
|
||||
print( "" )
|
||||
print( "### Dumping the log to <%s>" % LogFile )
|
||||
print( "------------------------------------------------------------" )
|
||||
print( " Git SHA1 = %s" % GitSHA1 )
|
||||
print( " Time stamp = %s" % TimeStamp )
|
||||
print( "------------------------------------------------------------" )
|
||||
sleep( 1.0 )
|
||||
HidePrivateDir()
|
||||
RunTester( command, logfile=LogFile )
|
||||
ShowPrivateDir()
|
||||
|
||||
#===================================================================================
|
||||
if __name__ == "__main__":
|
||||
Main()
|
||||
|
||||
#---------------
|
||||
# End of file
|
||||
#---------------
|
||||
|
|
@ -23,6 +23,7 @@ import platform
|
|||
import optparse
|
||||
import subprocess
|
||||
import hashlib
|
||||
import string
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
## To import global dictionaries of different modules and utility functions
|
||||
|
|
@ -41,6 +42,7 @@ def SetGlobals():
|
|||
global GenOSName # generic OS name
|
||||
global Platform # platform
|
||||
global PkgDir # the package directory where "klayout.app" exists
|
||||
global UnsafePkg # flags whether to proceed to making "invalid" dmg
|
||||
global OpClean # 'clean' operation
|
||||
global OpMake # 'make' operation
|
||||
global DefaultBundleName # the default bundle name 'klayout.app'
|
||||
|
|
@ -87,6 +89,8 @@ def SetGlobals():
|
|||
Usage += " : <-c|--clean> and <-m|--make> are mutually exclusive | \n"
|
||||
Usage += " [-b|--bundle <name>] : forcibly use this bundle name in the DMG | '' \n"
|
||||
Usage += " [-s|--serial <num>] : DMG serial number | 1 \n"
|
||||
Usage += " <-u|--unsafe> : Ignores a few checks (use with caution) | disabled \n"
|
||||
Usage += " <-t|--targetdmg> : Specify output .dmg filename | chosen by script \n"
|
||||
Usage += " [-?|--?] : print this usage and exit | disabled \n"
|
||||
Usage += "-------------------------------------------------------------------------------------+------------------\n"
|
||||
|
||||
|
|
@ -131,6 +135,7 @@ def SetGlobals():
|
|||
sys.exit(1)
|
||||
|
||||
PkgDir = ""
|
||||
UnsafePkg = False
|
||||
OpClean = False
|
||||
OpMake = False
|
||||
DefaultBundleName = "klayout.app"
|
||||
|
|
@ -179,8 +184,8 @@ def SetGlobals():
|
|||
# The package directory name should look like:
|
||||
# * ST-qt5MP.pkg.macos-Catalina-release-RsysPsys --- (1)
|
||||
# * LW-qt5Ana3.pkg.macos-Catalina-release-Rana3Pana3
|
||||
# * LW-qt5Brew.pkg.macos-Catalina-release-Rhb26Phb37
|
||||
# * LW-qt5MP.pkg.macos-Catalina-release-Rmp26Pmp37
|
||||
# * LW-qt5Brew.pkg.macos-Catalina-release-Rhb26Phb38
|
||||
# * LW-qt5MP.pkg.macos-Catalina-release-Rmp26Pmp38
|
||||
#
|
||||
# Generated DMG will be, for example,
|
||||
# (1) ---> ST-klayout-0.26.1-macOS-Catalina-1-qt5MP-RsysPsys.dmg
|
||||
|
|
@ -189,6 +194,8 @@ def SetGlobals():
|
|||
# on failure, -1
|
||||
#------------------------------------------------------------------------------
|
||||
def CheckPkgDirectory():
|
||||
global PkgDir
|
||||
global UnsafePkg
|
||||
global Platform
|
||||
global OpClean
|
||||
global OpMake
|
||||
|
|
@ -221,84 +228,87 @@ def CheckPkgDirectory():
|
|||
#
|
||||
# * ST-qt5MP.pkg.macos-Catalina-release-RsysPsys
|
||||
# * LW-qt5Ana3.pkg.macos-Catalina-release-Rana3Pana3
|
||||
# * LW-qt5Brew.pkg.macos-Catalina-release-Rhb27Phb37
|
||||
# * HW-qt5Brew.pkg.macos-Catalina-release-RsysPhb37
|
||||
# * EX-qt5MP.pkg.macos-Catalina-release-Rmp26Pmp37
|
||||
# * LW-qt5Brew.pkg.macos-Catalina-release-Rhb27Phb38
|
||||
# * HW-qt5Brew.pkg.macos-Catalina-release-RsysPhb38
|
||||
# * EX-qt5MP.pkg.macos-Catalina-release-Rmp26Pmp38
|
||||
#-----------------------------------------------------------------------------
|
||||
patQRP = u'(ST|LW|HW|EX)([-])(qt5[0-9A-Za-z]+)([.]pkg[.])([A-Za-z]+[-][A-Za-z]+[-]release[-])([0-9A-Za-z]+)'
|
||||
regQRP = re.compile(patQRP)
|
||||
if not regQRP.match(PkgDir):
|
||||
print( "! Cannot identify (Qt, Ruby, Python) from the package directory name" )
|
||||
print( "" )
|
||||
return -1
|
||||
if UnsafePkg:
|
||||
print( "! Ignoring..." )
|
||||
else:
|
||||
print( "" )
|
||||
return -1
|
||||
else:
|
||||
pkgdirComponents = regQRP.match(PkgDir).groups()
|
||||
PackagePrefix = pkgdirComponents[0]
|
||||
QtIdentification = pkgdirComponents[2]
|
||||
RubyPythonID = pkgdirComponents[5]
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# [3] Check if the "LatestOS" with MacPorts / Homebrew / Anaconda3
|
||||
#-----------------------------------------------------------------------------
|
||||
LatestOSMacPorts = Platform == LatestOS
|
||||
LatestOSMacPorts &= PackagePrefix == "LW"
|
||||
LatestOSMacPorts &= QtIdentification == "qt5MP"
|
||||
LatestOSMacPorts &= RubyPythonID == "Rmp26Pmp37"
|
||||
#-----------------------------------------------------------------------------
|
||||
# [3] Check if the "LatestOS" with MacPorts / Homebrew / Anaconda3
|
||||
#-----------------------------------------------------------------------------
|
||||
LatestOSMacPorts = Platform == LatestOS
|
||||
LatestOSMacPorts &= PackagePrefix == "LW"
|
||||
LatestOSMacPorts &= QtIdentification == "qt5MP"
|
||||
LatestOSMacPorts &= RubyPythonID == "Rmp26Pmp38"
|
||||
|
||||
LatestOSHomebrew = Platform == LatestOS
|
||||
LatestOSHomebrew &= PackagePrefix == "LW"
|
||||
LatestOSHomebrew &= QtIdentification == "qt5Brew"
|
||||
LatestOSHomebrew &= RubyPythonID == "Rhb27Phb37"
|
||||
LatestOSHomebrew = Platform == LatestOS
|
||||
LatestOSHomebrew &= PackagePrefix == "LW"
|
||||
LatestOSHomebrew &= QtIdentification == "qt5Brew"
|
||||
LatestOSHomebrew &= RubyPythonID == "Rhb27Phb38"
|
||||
|
||||
LatestOSAnaconda3 = Platform == LatestOS
|
||||
LatestOSAnaconda3 &= PackagePrefix == "LW"
|
||||
LatestOSAnaconda3 &= QtIdentification == "qt5Ana3"
|
||||
LatestOSAnaconda3 &= RubyPythonID == "Rana3Pana3"
|
||||
LatestOSAnaconda3 = Platform == LatestOS
|
||||
LatestOSAnaconda3 &= PackagePrefix == "LW"
|
||||
LatestOSAnaconda3 &= QtIdentification == "qt5Ana3"
|
||||
LatestOSAnaconda3 &= RubyPythonID == "Rana3Pana3"
|
||||
|
||||
if LatestOSMacPorts:
|
||||
mydic = DicLightWeight["ports"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
if OpMake:
|
||||
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
|
||||
zip_ref.extractall(PkgDir)
|
||||
os.rename( srcDir, desDir )
|
||||
if OpClean:
|
||||
if os.path.isdir(srcDir):
|
||||
shutil.rmtree(srcDir)
|
||||
if os.path.isdir(desDir):
|
||||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
if LatestOSMacPorts:
|
||||
mydic = DicLightWeight["ports"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
if OpMake:
|
||||
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
|
||||
zip_ref.extractall(PkgDir)
|
||||
os.rename( srcDir, desDir )
|
||||
if OpClean:
|
||||
if os.path.isdir(srcDir):
|
||||
shutil.rmtree(srcDir)
|
||||
if os.path.isdir(desDir):
|
||||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
|
||||
if LatestOSHomebrew:
|
||||
mydic = DicLightWeight["brew"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
if OpMake:
|
||||
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
|
||||
zip_ref.extractall(PkgDir)
|
||||
os.rename( srcDir, desDir )
|
||||
if OpClean:
|
||||
if os.path.isdir(srcDir):
|
||||
shutil.rmtree(srcDir)
|
||||
if os.path.isdir(desDir):
|
||||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
if LatestOSHomebrew:
|
||||
mydic = DicLightWeight["brew"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
if OpMake:
|
||||
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
|
||||
zip_ref.extractall(PkgDir)
|
||||
os.rename( srcDir, desDir )
|
||||
if OpClean:
|
||||
if os.path.isdir(srcDir):
|
||||
shutil.rmtree(srcDir)
|
||||
if os.path.isdir(desDir):
|
||||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
|
||||
if LatestOSAnaconda3:
|
||||
mydic = DicLightWeight["ana3"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
if OpMake:
|
||||
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
|
||||
zip_ref.extractall(PkgDir)
|
||||
os.rename( srcDir, desDir )
|
||||
if OpClean:
|
||||
if os.path.isdir(srcDir):
|
||||
shutil.rmtree(srcDir)
|
||||
if os.path.isdir(desDir):
|
||||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
if LatestOSAnaconda3:
|
||||
mydic = DicLightWeight["ana3"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
if OpMake:
|
||||
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
|
||||
zip_ref.extractall(PkgDir)
|
||||
os.rename( srcDir, desDir )
|
||||
if OpClean:
|
||||
if os.path.isdir(srcDir):
|
||||
shutil.rmtree(srcDir)
|
||||
if os.path.isdir(desDir):
|
||||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
|
||||
#------------------------------------------------------
|
||||
# [4] Check the presence of the default bundle
|
||||
|
|
@ -337,6 +347,7 @@ def ParseCommandLineArguments():
|
|||
global OpMake
|
||||
global BundleName
|
||||
global DMGSerialNum
|
||||
global UnsafePkg
|
||||
global PackagePrefix
|
||||
global QtIdentification
|
||||
global RubyPythonID
|
||||
|
|
@ -369,6 +380,16 @@ def ParseCommandLineArguments():
|
|||
dest='dmg_serial',
|
||||
help="DMG serial number" )
|
||||
|
||||
p.add_option( '-t', '--targetdmg',
|
||||
dest='target_dmg',
|
||||
help="output DMG filename" )
|
||||
|
||||
p.add_option( '-z', '--unsafe',
|
||||
action='store_true',
|
||||
dest='unsafe',
|
||||
default=False,
|
||||
help="If set, do not check whether pkg folder is empty" )
|
||||
|
||||
p.add_option( '-?', '--??',
|
||||
action='store_true',
|
||||
dest='checkusage',
|
||||
|
|
@ -379,7 +400,9 @@ def ParseCommandLineArguments():
|
|||
operation_clean = False,
|
||||
operation_make = False,
|
||||
bundle_name = "",
|
||||
target_dmg = "",
|
||||
dmg_serial = "1",
|
||||
unsafe = False,
|
||||
checkusage = False )
|
||||
|
||||
#-----------------------------------------------------------
|
||||
|
|
@ -394,6 +417,7 @@ def ParseCommandLineArguments():
|
|||
OpClean = opt.operation_clean
|
||||
OpMake = opt.operation_make
|
||||
DMGSerialNum = int(opt.dmg_serial)
|
||||
UnsafePkg = opt.unsafe
|
||||
|
||||
if not opt.bundle_name == "":
|
||||
base, ext = os.path.splitext( os.path.basename(opt.bundle_name) )
|
||||
|
|
@ -410,10 +434,13 @@ def ParseCommandLineArguments():
|
|||
# [2] Check the PKG directory to set QtIdentification, RubyPythonID, and BundleName
|
||||
#------------------------------------------------------------------------------------
|
||||
OccupiedDS = CheckPkgDirectory()
|
||||
if not 0 < OccupiedDS:
|
||||
if not 0 < OccupiedDS and not UnsafePkg:
|
||||
print( "! Failed to check the PKG directory" )
|
||||
print( "" )
|
||||
quit()
|
||||
|
||||
if opt.target_dmg != "":
|
||||
TargetDMG = opt.target_dmg
|
||||
else:
|
||||
TargetDMG = "%s-klayout-%s-%s-%s-%d-%s-%s.dmg" \
|
||||
% (PackagePrefix, KLVersion, GenOSName, Platform, DMGSerialNum, QtIdentification, RubyPythonID)
|
||||
|
|
@ -663,7 +690,8 @@ def CleanUp(msg=""):
|
|||
os.chdir(ProjectDir)
|
||||
dmgs = glob.glob( "*.dmg*" )
|
||||
for item in dmgs:
|
||||
os.system( "rm -Rf %s" % item )
|
||||
print("Removing %s" % item)
|
||||
os.system( "rm -Rf -- \"%s\"" % item )
|
||||
|
||||
#----------------------------------------------------
|
||||
# [3] Clean up AppleScript if any
|
||||
|
|
|
|||
|
|
@ -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 ()));
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ private:
|
|||
bool m_enable_cb_callback;
|
||||
|
||||
const ant::Object ¤t () const;
|
||||
void get_points(db::DPoint &p1, db::DPoint &p2);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 ¤t_template () const;
|
||||
|
||||
void show_message ();
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@ SOURCES = \
|
|||
gsiDeclDbNetlistCrossReference.cc \
|
||||
gsiDeclDbLayoutVsSchematic.cc \
|
||||
dbNetlistObject.cc \
|
||||
dbD25TechnologyComponent.cc \
|
||||
gsiDeclDbTexts.cc \
|
||||
dbTexts.cc \
|
||||
dbDeepTexts.cc \
|
||||
|
|
@ -354,6 +355,7 @@ HEADERS = \
|
|||
dbLayoutVsSchematicFormatDefs.h \
|
||||
dbLayoutVsSchematic.h \
|
||||
dbNetlistObject.h \
|
||||
dbD25TechnologyComponent.h \
|
||||
dbTexts.h \
|
||||
dbDeepTexts.h \
|
||||
dbAsIfFlatTexts.h \
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@ Cell::collect_caller_cells (std::set<cell_index_type> &callers, const std::set<c
|
|||
{
|
||||
if (levels != 0) {
|
||||
for (parent_cell_iterator cc = begin_parent_cells (); cc != end_parent_cells (); ++cc) {
|
||||
if (cone.find (*cc) != cone.end () && callers.find (*cc) == callers.end ()) {
|
||||
if (cone.find (*cc) != cone.end () && callers.find (*cc) == callers.end () && mp_layout->is_valid_cell_index (*cc)) {
|
||||
callers.insert (*cc);
|
||||
mp_layout->cell (*cc).collect_caller_cells (callers, levels < 0 ? levels : levels - 1);
|
||||
}
|
||||
|
|
@ -519,7 +519,7 @@ Cell::collect_caller_cells (std::set<cell_index_type> &callers, int levels) cons
|
|||
{
|
||||
if (levels != 0) {
|
||||
for (parent_cell_iterator cc = begin_parent_cells (); cc != end_parent_cells (); ++cc) {
|
||||
if (callers.find (*cc) == callers.end ()) {
|
||||
if (callers.find (*cc) == callers.end () && mp_layout->is_valid_cell_index (*cc)) {
|
||||
callers.insert (*cc);
|
||||
mp_layout->cell (*cc).collect_caller_cells (callers, levels < 0 ? levels : levels - 1);
|
||||
}
|
||||
|
|
@ -538,7 +538,7 @@ Cell::collect_called_cells (std::set<cell_index_type> &called, int levels) const
|
|||
{
|
||||
if (levels != 0) {
|
||||
for (child_cell_iterator cc = begin_child_cells (); ! cc.at_end (); ++cc) {
|
||||
if (called.find (*cc) == called.end ()) {
|
||||
if (called.find (*cc) == called.end () && mp_layout->is_valid_cell_index (*cc)) {
|
||||
called.insert (*cc);
|
||||
mp_layout->cell (*cc).collect_called_cells (called, levels < 0 ? levels : levels - 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,361 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Common reader implementation
|
||||
|
||||
static const size_t null_id = std::numeric_limits<size_t>::max ();
|
||||
|
||||
CommonReader::CommonReader ()
|
||||
: m_cc_resolution (AddToCell)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
db::cell_index_type
|
||||
CommonReader::make_cell (db::Layout &layout, const std::string &cn)
|
||||
{
|
||||
tl_assert (! cn.empty ());
|
||||
|
||||
std::map<std::string, std::pair<size_t, db::cell_index_type> >::iterator iname = m_name_map.find (cn);
|
||||
if (iname != m_name_map.end ()) {
|
||||
|
||||
db::Cell &cell = layout.cell (iname->second.second);
|
||||
|
||||
if (! cell.is_ghost_cell ()) {
|
||||
common_reader_error (tl::sprintf (tl::to_string (tr ("A cell with name %s already exists")), cn));
|
||||
}
|
||||
|
||||
cell.set_ghost_cell (false);
|
||||
return cell.cell_index ();
|
||||
|
||||
} else {
|
||||
|
||||
db::cell_index_type ci = layout.add_anonymous_cell ();
|
||||
|
||||
m_name_map [cn] = std::make_pair (null_id, ci);
|
||||
return ci;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CommonReader::has_cell (const std::string &cn) const
|
||||
{
|
||||
return m_name_map.find (cn) != m_name_map.end ();
|
||||
}
|
||||
|
||||
std::pair<bool, db::cell_index_type>
|
||||
CommonReader::cell_by_name (const std::string &cn) const
|
||||
{
|
||||
std::map<std::string, std::pair<size_t, db::cell_index_type> >::const_iterator iname = m_name_map.find (cn);
|
||||
if (iname != m_name_map.end ()) {
|
||||
return std::make_pair (true, iname->second.second);
|
||||
} else {
|
||||
return std::make_pair (false, size_t (0));
|
||||
}
|
||||
}
|
||||
|
||||
db::cell_index_type
|
||||
CommonReader::make_cell (db::Layout &layout, size_t id)
|
||||
{
|
||||
tl_assert (id != null_id);
|
||||
|
||||
std::map<size_t, std::pair<std::string, db::cell_index_type> >::iterator iid = m_id_map.find (id);
|
||||
if (iid != m_id_map.end ()) {
|
||||
|
||||
db::Cell &cell = layout.cell (iid->second.second);
|
||||
|
||||
if (! cell.is_ghost_cell ()) {
|
||||
common_reader_error (tl::sprintf (tl::to_string (tr ("A cell with ID %ld already exists")), id));
|
||||
}
|
||||
|
||||
cell.set_ghost_cell (false);
|
||||
return cell.cell_index ();
|
||||
|
||||
} else {
|
||||
|
||||
db::cell_index_type ci = layout.add_anonymous_cell ();
|
||||
|
||||
m_id_map [id] = std::make_pair (std::string (), ci);
|
||||
return ci;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CommonReader::has_cell (size_t id) const
|
||||
{
|
||||
return m_id_map.find (id) != m_id_map.end ();
|
||||
}
|
||||
|
||||
std::pair<bool, db::cell_index_type>
|
||||
CommonReader::cell_by_id (size_t id) const
|
||||
{
|
||||
std::map<size_t, std::pair<std::string, db::cell_index_type> >::const_iterator iid = m_id_map.find (id);
|
||||
if (iid != m_id_map.end ()) {
|
||||
return std::make_pair (true, iid->second.second);
|
||||
} else {
|
||||
return std::make_pair (false, size_t (0));
|
||||
}
|
||||
}
|
||||
|
||||
const std::string &
|
||||
CommonReader::name_for_id (size_t id) const
|
||||
{
|
||||
std::map<size_t, std::string>::const_iterator n = m_name_for_id.find (id);
|
||||
if (n != m_name_for_id.end ()) {
|
||||
return n->second;
|
||||
} else {
|
||||
static std::string empty;
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CommonReader::rename_cell (db::Layout &layout, size_t id, const std::string &cn)
|
||||
{
|
||||
m_name_for_id.insert (std::make_pair (id, cn));
|
||||
|
||||
std::map<size_t, std::pair<std::string, db::cell_index_type> >::iterator iid = m_id_map.find (id);
|
||||
std::map<std::string, std::pair<size_t, db::cell_index_type> >::iterator iname = m_name_map.find (cn);
|
||||
|
||||
if (iid != m_id_map.end () && iname != m_name_map.end ()) {
|
||||
|
||||
if (! iid->second.first.empty () && iid->second.first != cn) {
|
||||
common_reader_error (tl::sprintf (tl::to_string (tr ("Cell named %s with ID %ld was already given name %s")), cn, id, iid->second.first));
|
||||
}
|
||||
|
||||
if (iname->second.second != iid->second.second) {
|
||||
|
||||
// Both cells already exist and are not identical: merge ID-declared cell into the name-declared one
|
||||
layout.force_update ();
|
||||
merge_cell (layout, iname->second.second, iid->second.second);
|
||||
iid->second.second = iname->second.second;
|
||||
|
||||
}
|
||||
|
||||
iid->second.first = cn;
|
||||
iname->second.first = id;
|
||||
|
||||
} else if (iid != m_id_map.end ()) {
|
||||
|
||||
m_name_map [cn] = std::make_pair (id, iid->second.second);
|
||||
iid->second.first = cn;
|
||||
|
||||
} else if (iname != m_name_map.end ()) {
|
||||
|
||||
m_id_map [id] = std::make_pair (cn, iname->second.second);
|
||||
iname->second.first = id;
|
||||
|
||||
} else {
|
||||
|
||||
db::cell_index_type ci = layout.add_anonymous_cell ();
|
||||
layout.cell (ci).set_ghost_cell (true);
|
||||
|
||||
m_id_map [id] = std::make_pair (cn, ci);
|
||||
m_name_map [cn] = std::make_pair (id, ci);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
db::cell_index_type
|
||||
CommonReader::cell_for_instance (db::Layout &layout, size_t id)
|
||||
{
|
||||
tl_assert (id != null_id);
|
||||
|
||||
std::map<size_t, std::pair<std::string, db::cell_index_type> >::iterator iid = m_id_map.find (id);
|
||||
if (iid != m_id_map.end ()) {
|
||||
|
||||
return iid->second.second;
|
||||
|
||||
} else {
|
||||
|
||||
db::cell_index_type ci = layout.add_anonymous_cell ();
|
||||
layout.cell (ci).set_ghost_cell (true);
|
||||
|
||||
m_id_map [id] = std::make_pair (std::string (), ci);
|
||||
return ci;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
db::cell_index_type
|
||||
CommonReader::cell_for_instance (db::Layout &layout, const std::string &cn)
|
||||
{
|
||||
tl_assert (! cn.empty ());
|
||||
|
||||
std::map<std::string, std::pair<size_t, db::cell_index_type> >::iterator iname = m_name_map.find (cn);
|
||||
if (iname != m_name_map.end ()) {
|
||||
|
||||
return iname->second.second;
|
||||
|
||||
} else {
|
||||
|
||||
db::cell_index_type ci = layout.add_anonymous_cell ();
|
||||
layout.cell (ci).set_ghost_cell (true);
|
||||
|
||||
m_name_map [cn] = std::make_pair (null_id, ci);
|
||||
return ci;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CommonReader::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const
|
||||
{
|
||||
const db::Cell &src_cell = layout.cell (src_cell_index);
|
||||
db::Cell &target_cell = layout.cell (target_cell_index);
|
||||
|
||||
// copy over the instances
|
||||
for (db::Cell::const_iterator i = src_cell.begin (); ! i.at_end (); ++i) {
|
||||
// NOTE: cell indexed may be invalid because we delete subcells without update()
|
||||
if (layout.is_valid_cell_index (i->cell_index ())) {
|
||||
target_cell.insert (*i);
|
||||
}
|
||||
}
|
||||
|
||||
merge_cell_without_instances (layout, target_cell_index, src_cell_index);
|
||||
}
|
||||
|
||||
void
|
||||
CommonReader::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const
|
||||
{
|
||||
const db::Cell &src_cell = layout.cell (src_cell_index);
|
||||
db::Cell &target_cell = layout.cell (target_cell_index);
|
||||
|
||||
// copy over the shapes
|
||||
for (unsigned int l = 0; l < layout.layers (); ++l) {
|
||||
if (layout.is_valid_layer (l) && ! src_cell.shapes (l).empty ()) {
|
||||
target_cell.shapes (l).insert (src_cell.shapes (l));
|
||||
}
|
||||
}
|
||||
|
||||
// replace all instances of the new cell with the original one
|
||||
std::vector<std::pair<db::cell_index_type, db::Instance> > parents;
|
||||
for (db::Cell::parent_inst_iterator pi = src_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
|
||||
parents.push_back (std::make_pair (pi->parent_cell_index (), pi->child_inst ()));
|
||||
}
|
||||
|
||||
for (std::vector<std::pair<db::cell_index_type, db::Instance> >::const_iterator p = parents.begin (); p != parents.end (); ++p) {
|
||||
db::CellInstArray ia = p->second.cell_inst ();
|
||||
ia.object ().cell_index (target_cell.cell_index ());
|
||||
layout.cell (p->first).replace (p->second, ia);
|
||||
}
|
||||
|
||||
// finally delete the new cell
|
||||
layout.delete_cell (src_cell.cell_index ());
|
||||
}
|
||||
|
||||
void
|
||||
CommonReader::finish (db::Layout &layout)
|
||||
{
|
||||
bool any_missing = false;
|
||||
|
||||
for (std::map<size_t, std::pair<std::string, db::cell_index_type> >::const_iterator i = m_id_map.begin (); i != m_id_map.end (); ++i) {
|
||||
if (i->second.first.empty ()) {
|
||||
common_reader_warn (tl::sprintf (tl::to_string (tr ("No cellname defined for cell name id %ld")), i->first));
|
||||
any_missing = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (any_missing) {
|
||||
common_reader_error (tl::to_string (tr ("Some cell IDs don't have a name (see previous warnings)")));
|
||||
}
|
||||
|
||||
// check if we need to resolve conflicts
|
||||
|
||||
bool has_conflict = false;
|
||||
for (std::map<std::string, std::pair<size_t, db::cell_index_type> >::const_iterator i = m_name_map.begin (); i != m_name_map.end () && ! has_conflict; ++i) {
|
||||
has_conflict = layout.cell_by_name (i->first.c_str ()).first;
|
||||
}
|
||||
|
||||
if (! has_conflict) {
|
||||
|
||||
// no conflict - plain rename
|
||||
|
||||
for (std::map<std::string, std::pair<size_t, db::cell_index_type> >::const_iterator i = m_name_map.begin (); i != m_name_map.end () && ! has_conflict; ++i) {
|
||||
layout.rename_cell (i->second.second, i->first.c_str ());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// elaborate conflict resolution
|
||||
|
||||
layout.force_update ();
|
||||
|
||||
std::map<db::cell_index_type, std::string> new_cells;
|
||||
for (std::map<std::string, std::pair<size_t, db::cell_index_type> >::const_iterator i = m_name_map.begin (); i != m_name_map.end (); ++i) {
|
||||
new_cells.insert (std::make_pair (i->second.second, i->first));
|
||||
}
|
||||
|
||||
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > cells_with_conflict;
|
||||
|
||||
// First treat all the cells without conflict
|
||||
for (db::Layout::bottom_up_iterator bu = layout.begin_bottom_up (); bu != layout.end_bottom_up (); ++bu) {
|
||||
|
||||
db::cell_index_type ci_new = *bu;
|
||||
std::map<db::cell_index_type, std::string>::const_iterator i = new_cells.find (ci_new);
|
||||
|
||||
if (i == new_cells.end ()) {
|
||||
// not a new cell
|
||||
continue;
|
||||
}
|
||||
|
||||
std::pair<bool, db::cell_index_type> c2n = layout.cell_by_name (i->second.c_str ());
|
||||
db::cell_index_type ci_org = c2n.second;
|
||||
|
||||
// NOTE: proxy cells are never resolved. "RenameCell" is a plain and simple case.
|
||||
if (c2n.first && m_cc_resolution != RenameCell && ! layout.cell (ci_org).is_proxy ()) {
|
||||
cells_with_conflict.push_back (std::make_pair (ci_new, ci_org));
|
||||
} else {
|
||||
layout.rename_cell (ci_new, layout.uniquify_cell_name (i->second.c_str ()).c_str ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Then treat all the cells with conflict
|
||||
for (std::vector<std::pair<db::cell_index_type, db::cell_index_type> >::const_iterator cc = cells_with_conflict.begin (); cc != cells_with_conflict.end (); ++cc) {
|
||||
|
||||
db::cell_index_type ci_new = cc->first;
|
||||
db::cell_index_type ci_org = cc->second;
|
||||
|
||||
// we have a cell conflict
|
||||
|
||||
if (m_cc_resolution == OverwriteCell && ! layout.cell (ci_new).is_ghost_cell ()) {
|
||||
|
||||
if (! layout.cell (ci_org).begin ().at_end ()) {
|
||||
|
||||
// NOTE: because prune_subcells needs the parents for sub cells and we are going do delete
|
||||
// the current cell, we cannot save the "update()" just by traversing bottom-up.
|
||||
layout.force_update ();
|
||||
layout.prune_subcells (ci_org);
|
||||
|
||||
}
|
||||
|
||||
layout.cell (ci_org).clear_shapes ();
|
||||
|
||||
merge_cell (layout, ci_org, ci_new);
|
||||
|
||||
} else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) {
|
||||
|
||||
layout.prune_subcells (ci_new);
|
||||
layout.cell (ci_new).clear_shapes ();
|
||||
|
||||
// NOTE: ignore instances -> this saves us a layout update
|
||||
merge_cell_without_instances (layout, ci_org, ci_new);
|
||||
|
||||
} else {
|
||||
|
||||
merge_cell (layout, ci_org, ci_new);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Common format declaration
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,128 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A common reader base for GDS2 and OASIS providing common services for both readers
|
||||
*/
|
||||
class DB_PUBLIC CommonReader
|
||||
: public ReaderBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The CellConflictResolution enum
|
||||
*/
|
||||
enum CellConflictResolution
|
||||
{
|
||||
AddToCell = 0,
|
||||
OverwriteCell = 1,
|
||||
SkipNewCell = 2,
|
||||
RenameCell = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
CommonReader ();
|
||||
|
||||
/**
|
||||
* @brief Sets the cell name conflict resolution mode
|
||||
*/
|
||||
void set_cell_conflict_resolution (CellConflictResolution cc_resolution)
|
||||
{
|
||||
m_cc_resolution = cc_resolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the cell name conflict resolution mode
|
||||
*/
|
||||
CellConflictResolution cell_conflict_resolution () const
|
||||
{
|
||||
return m_cc_resolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Make a cell from a name
|
||||
*/
|
||||
db::cell_index_type make_cell (db::Layout &layout, const std::string &cn);
|
||||
|
||||
/**
|
||||
* @brief Returns true, if there is a cell with the given name already
|
||||
*/
|
||||
bool has_cell (const std::string &cn) const;
|
||||
|
||||
/**
|
||||
* @brief Returns a pair with a bool (indicating whether the cell name is known) and the cell index for this name
|
||||
*/
|
||||
std::pair<bool, db::cell_index_type> cell_by_name (const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief Make a cell from an ID (OASIS)
|
||||
*/
|
||||
db::cell_index_type make_cell (db::Layout &layout, size_t id);
|
||||
|
||||
/**
|
||||
* @brief Returns true, if there is a cell with the given ID alreay
|
||||
*/
|
||||
bool has_cell (size_t id) const;
|
||||
|
||||
/**
|
||||
* @brief Returns a pair with a bool (indicating whether the cell ID is known) and the cell index for this ID
|
||||
*/
|
||||
std::pair<bool, db::cell_index_type> cell_by_id (size_t id) const;
|
||||
|
||||
/**
|
||||
* @brief Registers a cell name for an ID
|
||||
*/
|
||||
void rename_cell (db::Layout &layout, size_t id, const std::string &cn);
|
||||
|
||||
/**
|
||||
* @brief Gets the name for a given cell ID if known, otherwise returns an empty string
|
||||
*/
|
||||
const std::string &name_for_id (size_t id) const;
|
||||
|
||||
/**
|
||||
* @brief Returns a cell reference by ID
|
||||
* If the cell does not exist, it's created. It is marked as ghost cell until
|
||||
* "make_cell" is called.
|
||||
*/
|
||||
db::cell_index_type cell_for_instance (db::Layout &layout, size_t id);
|
||||
|
||||
/**
|
||||
* @brief Returns a cell reference by name
|
||||
* Same as the previous method, but acting on cell names.
|
||||
*/
|
||||
db::cell_index_type cell_for_instance (db::Layout &layout, const std::string &cn);
|
||||
|
||||
/**
|
||||
* @brief Finishes the reading process
|
||||
*
|
||||
* This method will first check if all cells IDs got a name.
|
||||
* After this, the cells are renamed and cell conflict resolution will happen in the
|
||||
* specified way (cell_conflict_resolution attribute).
|
||||
*/
|
||||
void finish (db::Layout &layout);
|
||||
|
||||
protected:
|
||||
virtual void common_reader_error (const std::string &msg) = 0;
|
||||
virtual void common_reader_warn (const std::string &msg) = 0;
|
||||
|
||||
/**
|
||||
* @brief Merge (and delete) the src_cell into target_cell
|
||||
*/
|
||||
void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const;
|
||||
|
||||
/**
|
||||
* @brief Merge (and delete) the src_cell into target_cell without instances
|
||||
*/
|
||||
void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const;
|
||||
|
||||
private:
|
||||
std::map<size_t, std::pair<std::string, db::cell_index_type> > m_id_map;
|
||||
std::map<std::string, std::pair<size_t, db::cell_index_type> > m_name_map;
|
||||
std::map<size_t, std::string> m_name_for_id;
|
||||
CellConflictResolution m_cc_resolution;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Structure that holds the GDS2 and OASIS specific options for the reader
|
||||
*/
|
||||
|
|
@ -44,7 +166,8 @@ public:
|
|||
CommonReaderOptions ()
|
||||
: create_other_layers (true),
|
||||
enable_text_objects (true),
|
||||
enable_properties (true)
|
||||
enable_properties (true),
|
||||
cell_conflict_resolution (CommonReader::AddToCell)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -83,6 +206,22 @@ public:
|
|||
*/
|
||||
bool enable_properties;
|
||||
|
||||
/**
|
||||
* @brief Specifies the cell merge behavior
|
||||
*
|
||||
* This enum controls how cells are read if a cell with the requested name already
|
||||
* exists.
|
||||
*
|
||||
* AddToCell In this mode, instances or shapes are added to any existing cell
|
||||
* OverwriteCell Overwrite existing cell. If the existing cell has children, those are removed unless used otherwise
|
||||
* SkipNewCell Ignore the new cell and it's children
|
||||
* RenameCell Rename the new cell
|
||||
*
|
||||
* If the existing opr the new cell is a ghost cell, AddToCell is applied always. In other words,
|
||||
* ghost cells are always merged.
|
||||
*/
|
||||
CommonReader::CellConflictResolution cell_conflict_resolution;
|
||||
|
||||
/**
|
||||
* @brief Implementation of FormatSpecificReaderOptions
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,332 @@
|
|||
|
||||
/*
|
||||
|
||||
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 "dbD25TechnologyComponent.h"
|
||||
#include "tlClassRegistry.h"
|
||||
#include "tlString.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
std::string d25_component_name ()
|
||||
{
|
||||
return std::string ("d25");
|
||||
}
|
||||
|
||||
std::string d25_description ()
|
||||
{
|
||||
return tl::to_string (tr ("Z stack (2.5d)"));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// D25LayerInfo implementation
|
||||
|
||||
D25LayerInfo::D25LayerInfo ()
|
||||
: m_layer (), m_zstart (0.0), m_zstop (0.0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
D25LayerInfo::~D25LayerInfo ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
D25LayerInfo::D25LayerInfo (const D25LayerInfo &other)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
||||
D25LayerInfo &
|
||||
D25LayerInfo::operator= (const D25LayerInfo &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_layer = other.m_layer;
|
||||
m_zstart = other.m_zstart;
|
||||
m_zstop = other.m_zstop;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
D25LayerInfo::operator== (const D25LayerInfo &other) const
|
||||
{
|
||||
return fabs (m_zstart - other.m_zstart) < db::epsilon && fabs (m_zstop - other.m_zstop) < db::epsilon;
|
||||
}
|
||||
|
||||
void
|
||||
D25LayerInfo::set_layer (const db::LayerProperties &l)
|
||||
{
|
||||
m_layer = l;
|
||||
}
|
||||
|
||||
void
|
||||
D25LayerInfo::set_layer_from_string (const std::string &l)
|
||||
{
|
||||
db::LayerProperties lp;
|
||||
tl::Extractor ex (l.c_str ());
|
||||
try {
|
||||
lp.read (ex);
|
||||
} catch (tl::Exception &) {
|
||||
// ignore errors for now.
|
||||
}
|
||||
m_layer = lp;
|
||||
}
|
||||
|
||||
std::string
|
||||
D25LayerInfo::layer_as_string () const
|
||||
{
|
||||
return m_layer.to_string ();
|
||||
}
|
||||
|
||||
void
|
||||
D25LayerInfo::set_zstart (double z0)
|
||||
{
|
||||
m_zstart = z0;
|
||||
}
|
||||
|
||||
void
|
||||
D25LayerInfo::set_zstop (double z1)
|
||||
{
|
||||
m_zstop = z1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// D25TechnologyComponent implementation
|
||||
|
||||
D25TechnologyComponent::D25TechnologyComponent ()
|
||||
: db::TechnologyComponent (d25_component_name (), d25_description ())
|
||||
{
|
||||
// provide some explanation for the initialization
|
||||
m_src =
|
||||
"# Provide z stack information here\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"
|
||||
"#\n"
|
||||
"# zstart The lower z position of the extruded layer in µm\n"
|
||||
"# 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', "
|
||||
"# 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"
|
||||
"# 'zstart' and 'zstop'.\n"
|
||||
"#\n"
|
||||
"# Examples:\n"
|
||||
"# 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"
|
||||
;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int current_line = 0;
|
||||
m_layers.clear ();
|
||||
|
||||
try {
|
||||
|
||||
std::vector<std::string> lines = tl::split (src, "\n");
|
||||
for (std::vector<std::string>::const_iterator l = lines.begin (); l != lines.end (); ++l) {
|
||||
|
||||
++current_line;
|
||||
|
||||
tl::Extractor ex (l->c_str ());
|
||||
|
||||
if (ex.test ("#")) {
|
||||
// ignore comments
|
||||
} else if (ex.at_end ()) {
|
||||
// ignore empty lines
|
||||
} else {
|
||||
|
||||
db::D25LayerInfo info;
|
||||
if (! m_layers.empty ()) {
|
||||
info.set_zstart (m_layers.back ().zstop ());
|
||||
info.set_zstop (m_layers.back ().zstop ());
|
||||
}
|
||||
|
||||
tl::Variant z0, z1, h;
|
||||
std::vector<double> args;
|
||||
|
||||
db::LayerProperties lp;
|
||||
lp.read (ex);
|
||||
info.set_layer (lp);
|
||||
|
||||
ex.expect (":");
|
||||
|
||||
while (! ex.at_end ()) {
|
||||
|
||||
if (ex.test ("#")) {
|
||||
break;
|
||||
}
|
||||
|
||||
double pv = 0.0;
|
||||
|
||||
std::string pn;
|
||||
if (ex.try_read_name (pn)) {
|
||||
ex.expect ("=");
|
||||
ex.read (pv);
|
||||
} else {
|
||||
ex.read (pv);
|
||||
}
|
||||
|
||||
ex.test (",");
|
||||
|
||||
if (pn.empty ()) {
|
||||
args.push_back (pv);
|
||||
} else if (pn == "zstart") {
|
||||
z0 = pv;
|
||||
} else if (pn == "zstop") {
|
||||
z1 = pv;
|
||||
} else if (pn == "height") {
|
||||
h = pv;
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid parameter name: ")) + pn);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (args.size () == 0) {
|
||||
if (z0.is_nil () && z1.is_nil ()) {
|
||||
if (! h.is_nil ()) {
|
||||
info.set_zstop (info.zstart () + h.to_double ());
|
||||
}
|
||||
} else if (z0.is_nil ()) {
|
||||
info.set_zstop (z1.to_double ());
|
||||
if (! h.is_nil ()) {
|
||||
info.set_zstart (info.zstop () - h.to_double ());
|
||||
}
|
||||
} else if (z1.is_nil ()) {
|
||||
info.set_zstart (z0.to_double ());
|
||||
if (! h.is_nil ()) {
|
||||
info.set_zstop (info.zstart () + h.to_double ());
|
||||
}
|
||||
} else {
|
||||
info.set_zstart (z0.to_double ());
|
||||
info.set_zstop (z1.to_double ());
|
||||
}
|
||||
} 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")));
|
||||
}
|
||||
if (! z1.is_nil ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Rundundant 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")));
|
||||
}
|
||||
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")));
|
||||
}
|
||||
if (! z1.is_nil ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstop already given")));
|
||||
}
|
||||
if (! h.is_nil ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Rundundant parameters: height implicitly given")));
|
||||
}
|
||||
info.set_zstart (args[0]);
|
||||
info.set_zstop (args[1]);
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Too many parameters (max 2)")));
|
||||
}
|
||||
|
||||
m_layers.push_back (info);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (ex.msg () + tl::sprintf (tl::to_string (tr (" in line %d")), current_line));
|
||||
}
|
||||
|
||||
m_src = src;
|
||||
}
|
||||
|
||||
std::string
|
||||
D25TechnologyComponent::to_string () const
|
||||
{
|
||||
std::string res;
|
||||
|
||||
for (const_iterator i = begin (); i != end (); ++i) {
|
||||
if (! res.empty ()) {
|
||||
res += "\n";
|
||||
}
|
||||
res += i->layer ().to_string () + ": zstart=" + tl::to_string (i->zstart ()) + ", zstop=" + tl::to_string (i->zstop ());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// D25TechnologyComponent technology component registration
|
||||
|
||||
class D25TechnologyComponentProvider
|
||||
: public db::TechnologyComponentProvider
|
||||
{
|
||||
public:
|
||||
D25TechnologyComponentProvider ()
|
||||
: db::TechnologyComponentProvider ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual db::TechnologyComponent *create_component () const
|
||||
{
|
||||
return new D25TechnologyComponent ();
|
||||
}
|
||||
|
||||
virtual tl::XMLElementBase *xml_element () const
|
||||
{
|
||||
return new db::TechnologyComponentXMLElement<D25TechnologyComponent> (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")
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<db::TechnologyComponentProvider> tc_decl (new D25TechnologyComponentProvider (), 3100, d25_component_name ().c_str ());
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
|
||||
/*
|
||||
|
||||
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_dbD25TechnologyComponent
|
||||
#define HDR_dbD25TechnologyComponent
|
||||
|
||||
#include "dbTechnology.h"
|
||||
#include "dbLayerProperties.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class DB_PUBLIC D25LayerInfo
|
||||
{
|
||||
public:
|
||||
D25LayerInfo ();
|
||||
~D25LayerInfo ();
|
||||
D25LayerInfo (const D25LayerInfo &other);
|
||||
D25LayerInfo &operator= (const D25LayerInfo &other);
|
||||
|
||||
bool operator== (const D25LayerInfo &other) const;
|
||||
|
||||
const db::LayerProperties &layer () const
|
||||
{
|
||||
return m_layer;
|
||||
}
|
||||
|
||||
void set_layer_from_string (const std::string &l);
|
||||
std::string layer_as_string () const;
|
||||
|
||||
void set_layer (const db::LayerProperties &l);
|
||||
|
||||
double zstart () const
|
||||
{
|
||||
return m_zstart;
|
||||
}
|
||||
|
||||
void set_zstart (double z0);
|
||||
|
||||
double zstop () const
|
||||
{
|
||||
return m_zstop;
|
||||
}
|
||||
|
||||
void set_zstop (double z1);
|
||||
|
||||
private:
|
||||
db::LayerProperties m_layer;
|
||||
double m_zstart, m_zstop;
|
||||
};
|
||||
|
||||
class DB_PUBLIC D25TechnologyComponent
|
||||
: public db::TechnologyComponent
|
||||
{
|
||||
public:
|
||||
D25TechnologyComponent ();
|
||||
D25TechnologyComponent (const D25TechnologyComponent &d);
|
||||
|
||||
typedef std::list<D25LayerInfo> 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 ();
|
||||
}
|
||||
|
||||
const std::string &src () const
|
||||
{
|
||||
return m_src;
|
||||
}
|
||||
|
||||
// for persistency only, use "compile_from_source" to read from a source string
|
||||
void set_src (const std::string &s)
|
||||
{
|
||||
m_src = s;
|
||||
}
|
||||
|
||||
std::string to_string () const;
|
||||
|
||||
db::TechnologyComponent *clone () const
|
||||
{
|
||||
return new D25TechnologyComponent (*this);
|
||||
}
|
||||
|
||||
private:
|
||||
layers_type m_layers;
|
||||
std::string m_src;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -931,7 +931,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
|
|||
cm = m_delivery_mapping_cache.insert (std::make_pair (key, db::CellMapping ())).first;
|
||||
|
||||
// collects the cell mappings we skip because they are variants (variant building or box variants)
|
||||
std::map<db::cell_index_type, std::pair<db::cell_index_type, std::set<db::Box> > > cm_skipped_variants;
|
||||
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey> cm_skipped_variants;
|
||||
|
||||
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell ()) {
|
||||
|
||||
|
|
@ -945,14 +945,14 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
|
|||
HierarchyBuilder::cell_map_type::const_iterator mm = m;
|
||||
++mm;
|
||||
bool skip = original_builder.is_variant (m->second); // skip variant cells
|
||||
while (mm != original_builder.end_cell_map () && mm->first.first == m->first.first) {
|
||||
while (mm != original_builder.end_cell_map () && mm->first.original_cell == m->first.original_cell) {
|
||||
// we have cell (box) variants and cannot simply map
|
||||
++mm;
|
||||
skip = true;
|
||||
}
|
||||
|
||||
if (! skip) {
|
||||
cm->second.map (m->second, m->first.first);
|
||||
cm->second.map (m->second, m->first.original_cell);
|
||||
} else {
|
||||
for (HierarchyBuilder::cell_map_type::const_iterator n = m; n != mm; ++n) {
|
||||
tl_assert (cm_skipped_variants.find (n->second) == cm_skipped_variants.end ());
|
||||
|
|
@ -988,17 +988,19 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
|
|||
|
||||
db::cell_index_type var_org = original_builder.original_target_for_variant (np->first);
|
||||
|
||||
std::map<db::cell_index_type, std::pair<db::cell_index_type, std::set<db::Box> > >::const_iterator icm = cm_skipped_variants.find (var_org);
|
||||
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey>::const_iterator icm = cm_skipped_variants.find (var_org);
|
||||
if (icm != cm_skipped_variants.end ()) {
|
||||
|
||||
// create the variant clone in the original layout too and delete this cell
|
||||
VariantsCollectorBase::copy_shapes (*into_layout, np->second, icm->second.first);
|
||||
cells_to_delete.insert (icm->second.first);
|
||||
VariantsCollectorBase::copy_shapes (*into_layout, np->second, icm->second.original_cell);
|
||||
cells_to_delete.insert (icm->second.original_cell);
|
||||
|
||||
// forget the original cell (now separated into variants) and map the variants back into the
|
||||
// DSS layout
|
||||
original_builder.unmap (icm->second);
|
||||
original_builder.map (std::make_pair (np->second, icm->second.second), np->first);
|
||||
db::HierarchyBuilder::CellMapKey k = icm->second;
|
||||
k.original_cell = np->second;
|
||||
original_builder.map (k, np->first);
|
||||
|
||||
// forget the variant as now it's a real cell in the source layout
|
||||
original_builder.unregister_variant (np->first);
|
||||
|
|
|
|||
|
|
@ -799,10 +799,18 @@ struct cluster_building_receiver
|
|||
typedef std::set<size_t> global_nets;
|
||||
typedef std::pair<shape_vector, global_nets> cluster_value;
|
||||
|
||||
cluster_building_receiver (const db::Connectivity &conn)
|
||||
: mp_conn (&conn)
|
||||
cluster_building_receiver (const db::Connectivity &conn, const tl::equivalence_clusters<size_t> *attr_equivalence)
|
||||
: mp_conn (&conn), mp_attr_equivalence (attr_equivalence)
|
||||
{
|
||||
// .. nothing yet..
|
||||
if (mp_attr_equivalence) {
|
||||
// cache the global nets per attribute equivalence cluster
|
||||
for (size_t gid = 0; gid < conn.global_nets (); ++gid) {
|
||||
tl::equivalence_clusters<size_t>::cluster_id_type cl = attr_equivalence->cluster_id (global_net_id_to_attr (gid));
|
||||
if (cl > 0) {
|
||||
m_global_nets_by_attribute_cluster [cl].insert (gid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generate_clusters (local_clusters<T> &clusters)
|
||||
|
|
@ -817,7 +825,32 @@ struct cluster_building_receiver
|
|||
cluster->add_attr (s->second.second);
|
||||
}
|
||||
|
||||
cluster->set_global_nets (c->second);
|
||||
std::set<size_t> global_nets = c->second;
|
||||
|
||||
// Add the global nets we derive from the attribute equivalence (join_nets of labelled vs.
|
||||
// global nets)
|
||||
if (mp_attr_equivalence) {
|
||||
|
||||
for (typename shape_vector::const_iterator s = c->first.begin (); s != c->first.end (); ++s) {
|
||||
|
||||
size_t a = s->second.second;
|
||||
if (a == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tl::equivalence_clusters<size_t>::cluster_id_type cl = mp_attr_equivalence->cluster_id (a);
|
||||
if (cl > 0) {
|
||||
std::map<size_t, std::set<size_t> >::const_iterator gn = m_global_nets_by_attribute_cluster.find (cl);
|
||||
if (gn != m_global_nets_by_attribute_cluster.end ()) {
|
||||
global_nets.insert (gn->second.begin (), gn->second.end ());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cluster->set_global_nets (global_nets);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -913,6 +946,8 @@ private:
|
|||
std::map<const T *, typename std::list<cluster_value>::iterator> m_shape_to_clusters;
|
||||
std::map<size_t, typename std::list<cluster_value>::iterator> m_global_to_clusters;
|
||||
std::list<cluster_value> m_clusters;
|
||||
std::map<size_t, std::set<size_t> > m_global_nets_by_attribute_cluster;
|
||||
const tl::equivalence_clusters<size_t> *mp_attr_equivalence;
|
||||
|
||||
void join (typename std::list<cluster_value>::iterator ic1, typename std::list<cluster_value>::iterator ic2)
|
||||
{
|
||||
|
|
@ -1035,7 +1070,7 @@ local_clusters<T>::build_clusters (const db::Cell &cell, const db::Connectivity
|
|||
}
|
||||
}
|
||||
|
||||
cluster_building_receiver<T, box_type> rec (conn);
|
||||
cluster_building_receiver<T, box_type> rec (conn, attr_equivalence);
|
||||
bs.process (rec, 1 /*==touching*/, bc);
|
||||
rec.generate_clusters (*this);
|
||||
|
||||
|
|
@ -1048,36 +1083,27 @@ template <class T>
|
|||
void
|
||||
local_clusters<T>::apply_attr_equivalences (const tl::equivalence_clusters<size_t> &attr_equivalence)
|
||||
{
|
||||
tl::equivalence_clusters<size_t> eq;
|
||||
|
||||
// collect all local attributes (the ones which are present in attr_equivalence) into "eq"
|
||||
// and form equivalences for multi-attribute clusters.
|
||||
for (const_iterator c = begin (); c != end (); ++c) {
|
||||
typename local_cluster<T>::attr_iterator a0;
|
||||
for (typename local_cluster<T>::attr_iterator a = c->begin_attr (); a != c->end_attr (); ++a) {
|
||||
if (attr_equivalence.has_attribute (*a)) {
|
||||
if (a0 == typename local_cluster<T>::attr_iterator ()) {
|
||||
a0 = a;
|
||||
}
|
||||
eq.same (*a0, *a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply the equivalences implied by attr_equivalence
|
||||
eq.apply_equivalences (attr_equivalence);
|
||||
|
||||
// identify the layout clusters joined into one attribute cluster and join them
|
||||
|
||||
std::map<tl::equivalence_clusters<size_t>::cluster_id_type, std::set<size_t> > c2c;
|
||||
|
||||
for (const_iterator c = begin (); c != end (); ++c) {
|
||||
|
||||
for (typename local_cluster<T>::attr_iterator a = c->begin_attr (); a != c->end_attr (); ++a) {
|
||||
tl::equivalence_clusters<size_t>::cluster_id_type cl = attr_equivalence.cluster_id (*a);
|
||||
if (cl > 0) {
|
||||
c2c [cl].insert (c->id ());
|
||||
}
|
||||
}
|
||||
|
||||
for (typename local_cluster<T>::global_nets_iterator g = c->begin_global_nets (); g != c->end_global_nets (); ++g) {
|
||||
size_t a = global_net_id_to_attr (*g);
|
||||
tl::equivalence_clusters<size_t>::cluster_id_type cl = attr_equivalence.cluster_id (a);
|
||||
if (cl > 0) {
|
||||
c2c [cl].insert (c->id ());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::map<tl::equivalence_clusters<size_t>::cluster_id_type, std::set<size_t> >::const_iterator c = c2c.begin (); c != c2c.end (); ++c) {
|
||||
|
|
|
|||
|
|
@ -1396,11 +1396,11 @@ private:
|
|||
|
||||
/**
|
||||
* @brief A helper function generating an attribute ID from a property ID
|
||||
* This function is used to provide a generic attribute wrapping a property ID and a text ID.
|
||||
* This function is used to provide a generic attribute wrapping a property ID, text ID and global net ID
|
||||
*/
|
||||
inline size_t prop_id_to_attr (db::properties_id_type id)
|
||||
{
|
||||
return size_t (id) * 2;
|
||||
return size_t (id) * 4;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1408,7 +1408,7 @@ inline size_t prop_id_to_attr (db::properties_id_type id)
|
|||
*/
|
||||
inline bool is_prop_id_attr (size_t attr)
|
||||
{
|
||||
return (attr & 1) == 0;
|
||||
return (attr & 3) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1416,7 +1416,32 @@ inline bool is_prop_id_attr (size_t attr)
|
|||
*/
|
||||
inline db::properties_id_type prop_id_from_attr (size_t attr)
|
||||
{
|
||||
return attr / 2;
|
||||
return attr / 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A helper function generating an attribute ID from a global net ID
|
||||
* This function is used to provide a generic attribute wrapping a property ID, text ID and global net ID
|
||||
*/
|
||||
inline size_t global_net_id_to_attr (size_t id)
|
||||
{
|
||||
return size_t (id) * 4 + 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the attribute is a global net ID
|
||||
*/
|
||||
inline bool is_global_net_id_attr (size_t attr)
|
||||
{
|
||||
return (attr & 3) == 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the global net ID from an attribute
|
||||
*/
|
||||
inline size_t global_net_id_from_attr (size_t attr)
|
||||
{
|
||||
return attr / 4;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1424,9 +1449,18 @@ inline db::properties_id_type prop_id_from_attr (size_t attr)
|
|||
*/
|
||||
inline size_t text_ref_to_attr (const db::Text *tr)
|
||||
{
|
||||
// NOTE: pointers are 32bit aligned, hence the lower two bits are 0
|
||||
return size_t (tr) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the attribute is a StringRef
|
||||
*/
|
||||
inline bool is_text_ref_attr (size_t attr)
|
||||
{
|
||||
return (attr & 3) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the text value from an attribute ID
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -62,6 +62,14 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter
|
|||
return iter1.max_depth () < iter2.max_depth () ? -1 : 1;
|
||||
}
|
||||
|
||||
// take potential selection of cells into account
|
||||
if (iter1.disables () != iter2.disables ()) {
|
||||
return iter1.disables () < iter2.disables () ? -1 : 1;
|
||||
}
|
||||
if (iter1.enables () != iter2.enables ()) {
|
||||
return iter1.enables () < iter2.enables () ? -1 : 1;
|
||||
}
|
||||
|
||||
// if a region is set, the hierarchical appearance is the same only if the layers and
|
||||
// complex region are identical
|
||||
if ((iter1.region () == db::Box::world ()) != (iter2.region () == db::Box::world ())) {
|
||||
|
|
@ -238,11 +246,11 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter)
|
|||
return;
|
||||
}
|
||||
|
||||
std::pair<db::cell_index_type, std::set<db::Box> > key (iter->top_cell ()->cell_index (), std::set<db::Box> ());
|
||||
CellMapKey key (iter->top_cell ()->cell_index (), false, std::set<db::Box> ());
|
||||
m_cm_entry = m_cell_map.find (key);
|
||||
|
||||
if (m_cm_entry == m_cell_map.end ()) {
|
||||
db::cell_index_type new_top_index = mp_target->add_cell (iter->layout ()->cell_name (key.first));
|
||||
db::cell_index_type new_top_index = mp_target->add_cell (iter->layout ()->cell_name (key.original_cell));
|
||||
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_top_index)).first;
|
||||
}
|
||||
|
||||
|
|
@ -300,27 +308,47 @@ HierarchyBuilder::leave_cell (const RecursiveShapeIterator * /*iter*/, const db:
|
|||
m_cell_stack.pop_back ();
|
||||
}
|
||||
|
||||
db::cell_index_type
|
||||
HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, const std::string &cell_name)
|
||||
{
|
||||
m_cm_entry = m_cell_map.find (key);
|
||||
m_cm_new_entry = false;
|
||||
|
||||
db::cell_index_type new_cell;
|
||||
|
||||
if (m_cm_entry == m_cell_map.end ()) {
|
||||
|
||||
std::string cn = cell_name;
|
||||
if (! key.clip_region.empty ()) {
|
||||
cn += "$CLIP_VAR";
|
||||
}
|
||||
if (key.inactive) {
|
||||
cn += "$DIS";
|
||||
}
|
||||
new_cell = mp_target->add_cell (cn.c_str ());
|
||||
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
|
||||
m_cm_new_entry = true;
|
||||
m_cells_to_be_filled.insert (new_cell);
|
||||
|
||||
} else {
|
||||
new_cell = m_cm_entry->second;
|
||||
}
|
||||
|
||||
return new_cell;
|
||||
}
|
||||
|
||||
HierarchyBuilder::new_inst_mode
|
||||
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
|
||||
{
|
||||
if (all) {
|
||||
|
||||
std::pair<db::cell_index_type, std::set<db::Box> > key (inst.object ().cell_index (), std::set<db::Box> ());
|
||||
|
||||
m_cm_entry = m_cell_map.find (key);
|
||||
m_cm_new_entry = false;
|
||||
|
||||
if (m_cm_entry == m_cell_map.end ()) {
|
||||
db::cell_index_type new_cell = mp_target->add_cell (iter->layout ()->cell_name (inst.object ().cell_index ()));
|
||||
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
|
||||
m_cm_new_entry = true;
|
||||
m_cells_to_be_filled.insert (new_cell);
|
||||
}
|
||||
CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst.object ().cell_index ()), std::set<db::Box> ());
|
||||
db::cell_index_type new_cell = make_cell_variant (key, iter->layout ()->cell_name (inst.object ().cell_index ()));
|
||||
|
||||
// for new cells, create this instance
|
||||
if (m_cell_stack.back ().first) {
|
||||
db::CellInstArray new_inst (inst, &mp_target->array_repository ());
|
||||
new_inst.object () = db::CellInst (m_cm_entry->second);
|
||||
new_inst.object () = db::CellInst (new_cell);
|
||||
new_inst.transform_into (m_trans);
|
||||
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
|
||||
(*c)->insert (new_inst);
|
||||
|
|
@ -353,24 +381,12 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
|
|||
return false;
|
||||
}
|
||||
|
||||
std::pair<db::cell_index_type, std::set<db::Box> > key (inst.object ().cell_index (), clip_variant.second);
|
||||
m_cm_entry = m_cell_map.find (key);
|
||||
m_cm_new_entry = false;
|
||||
|
||||
if (m_cm_entry == m_cell_map.end ()) {
|
||||
std::string suffix;
|
||||
if (! key.second.empty ()) {
|
||||
suffix = "$CLIP_VAR";
|
||||
}
|
||||
db::cell_index_type new_cell = mp_target->add_cell ((std::string (iter->layout ()->cell_name (inst.object ().cell_index ())) + suffix).c_str ());
|
||||
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
|
||||
m_cm_new_entry = true;
|
||||
m_cells_to_be_filled.insert (new_cell);
|
||||
}
|
||||
CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst.object ().cell_index ()), clip_variant.second);
|
||||
db::cell_index_type new_cell = make_cell_variant (key, iter->layout ()->cell_name (inst.object ().cell_index ()));
|
||||
|
||||
// for a new cell, create this instance
|
||||
if (m_cell_stack.back ().first) {
|
||||
db::CellInstArray new_inst (db::CellInst (m_cm_entry->second), trans);
|
||||
db::CellInstArray new_inst (db::CellInst (new_cell), trans);
|
||||
new_inst.transform_into (m_trans);
|
||||
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
|
||||
(*c)->insert (new_inst);
|
||||
|
|
|
|||
|
|
@ -225,8 +225,36 @@ class DB_PUBLIC HierarchyBuilder
|
|||
: public db::RecursiveShapeReceiver
|
||||
{
|
||||
public:
|
||||
struct CellMapKey
|
||||
{
|
||||
CellMapKey ()
|
||||
: original_cell (0), inactive (false)
|
||||
{ }
|
||||
|
||||
typedef std::map<std::pair<db::cell_index_type, std::set<db::Box> >, db::cell_index_type> cell_map_type;
|
||||
CellMapKey (db::cell_index_type _original_cell, bool _inactive, const std::set<db::Box> &_clip_region)
|
||||
: original_cell (_original_cell), inactive (_inactive), clip_region (_clip_region)
|
||||
{ }
|
||||
|
||||
bool operator== (const CellMapKey &other) const
|
||||
{
|
||||
return original_cell == other.original_cell && inactive == other.inactive && clip_region == other.clip_region;
|
||||
}
|
||||
|
||||
bool operator< (const CellMapKey &other) const
|
||||
{
|
||||
if (original_cell != other.original_cell) { return original_cell < other.original_cell; }
|
||||
if (inactive != other.inactive) { return inactive < other.inactive; }
|
||||
if (clip_region != other.clip_region) { return clip_region < other.clip_region; }
|
||||
return false;
|
||||
}
|
||||
|
||||
db::cell_index_type original_cell;
|
||||
bool inactive;
|
||||
std::set<db::Box> clip_region;
|
||||
};
|
||||
|
||||
|
||||
typedef std::map<CellMapKey, db::cell_index_type> cell_map_type;
|
||||
typedef std::map<db::cell_index_type, std::vector<db::cell_index_type> > original_target_to_variants_map_type;
|
||||
typedef std::map<db::cell_index_type, db::cell_index_type> variant_to_original_target_map_type;
|
||||
|
||||
|
|
@ -346,6 +374,8 @@ public:
|
|||
db::cell_index_type original_target_for_variant (db::cell_index_type ci) const;
|
||||
|
||||
private:
|
||||
db::cell_index_type make_cell_variant (const HierarchyBuilder::CellMapKey &key, const std::string &cell_name);
|
||||
|
||||
tl::weak_ptr<db::Layout> mp_target;
|
||||
HierarchyBuilderShapeReceiver *mp_pipe;
|
||||
bool m_initial_pass;
|
||||
|
|
|
|||
|
|
@ -1068,14 +1068,41 @@ Layout::add_cell (const char *name)
|
|||
return new_index;
|
||||
}
|
||||
|
||||
cell_index_type
|
||||
Layout::add_anonymous_cell ()
|
||||
{
|
||||
std::string b;
|
||||
|
||||
// create a new cell
|
||||
cell_index_type new_index = allocate_new_cell ();
|
||||
|
||||
cell_type *new_cell = new cell_type (new_index, *this);
|
||||
m_cells.push_back_ptr (new_cell);
|
||||
m_cell_ptrs [new_index] = new_cell;
|
||||
|
||||
// enter it's index and cell_name
|
||||
register_cell_name (0, new_index);
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0));
|
||||
}
|
||||
|
||||
return new_index;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::register_cell_name (const char *name, cell_index_type ci)
|
||||
{
|
||||
// enter it's index and cell_name
|
||||
char *cp;
|
||||
|
||||
cp = new char [strlen (name) + 1];
|
||||
strcpy (cp, name);
|
||||
if (name == 0) {
|
||||
cp = new char [1];
|
||||
*cp = 0;
|
||||
} else {
|
||||
cp = new char [strlen (name) + 1];
|
||||
strcpy (cp, name);
|
||||
}
|
||||
|
||||
while (m_cell_names.size () < ci) {
|
||||
char *e = new char [1];
|
||||
|
|
@ -1090,7 +1117,9 @@ Layout::register_cell_name (const char *name, cell_index_type ci)
|
|||
m_cell_names.push_back (cp);
|
||||
}
|
||||
|
||||
m_cell_map.insert (std::make_pair (cp, ci));
|
||||
if (name) {
|
||||
m_cell_map.insert (std::make_pair (cp, ci));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -727,7 +727,17 @@ public:
|
|||
*/
|
||||
cell_index_type add_cell (const char *name = 0);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Add a cell without a name
|
||||
*
|
||||
* The cell is created, but cannot be found by name. The name returned is an empty string.
|
||||
* The cell is created with the purpose of being renamed later.
|
||||
*
|
||||
* @return The index of the new cell
|
||||
*/
|
||||
cell_index_type add_anonymous_cell ();
|
||||
|
||||
/**
|
||||
* @brief Rename a cell
|
||||
*
|
||||
* Rename the cell with the given id.
|
||||
|
|
@ -1065,8 +1075,7 @@ public:
|
|||
* @brief Delete the subcells of the given cells which are not used otherwise
|
||||
*
|
||||
* All subcells referenced directy or indirectly but not used otherwise
|
||||
* are deleted as well. This basically prunes the cell tree by this cell.
|
||||
* All instances of this cell are deleted as well.
|
||||
* are deleted as well.
|
||||
* This method is more efficent than calling prune_subcells for single cells multiple times.
|
||||
*
|
||||
* @param from A begin iterator delivering the cell id's to delete
|
||||
|
|
@ -1085,8 +1094,7 @@ public:
|
|||
* @brief Delete the subcells of the given cells which are not used otherwise
|
||||
*
|
||||
* All subcells referenced directy or indirectly but not used otherwise
|
||||
* are deleted as well. This basically prunes the cell tree by this cell.
|
||||
* All instances of this cell are deleted as well.
|
||||
* are deleted as well.
|
||||
* This method is more efficent than calling prune_subcells for single cells multiple times.
|
||||
*
|
||||
* @param cells A set of cell id's to prune
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ void NetlistExtractor::set_include_floating_subcircuits (bool f)
|
|||
}
|
||||
|
||||
static void
|
||||
build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters<size_t> &eq)
|
||||
build_net_name_equivalence (const db::Layout *layout, const db::Connectivity &conn, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters<size_t> &eq)
|
||||
{
|
||||
std::map<std::string, std::set<size_t> > prop_by_name;
|
||||
tl::GlobPattern jn_pattern (joined_net_names);
|
||||
|
|
@ -67,6 +67,14 @@ build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type
|
|||
}
|
||||
}
|
||||
|
||||
// include pseudo-attributes for global nets to implement "join_with" for global nets
|
||||
for (size_t gid = 0; gid < conn.global_nets (); ++gid) {
|
||||
const std::string &gn = conn.global_net_name (gid);
|
||||
if (jn_pattern.match (gn)) {
|
||||
prop_by_name [gn].insert (db::global_net_id_to_attr (gid));
|
||||
}
|
||||
}
|
||||
|
||||
const db::repository<db::Text> &text_repository = layout->shape_repository ().repository (db::object_tag<db::Text> ());
|
||||
for (db::repository<db::Text>::iterator t = text_repository.begin (); t != text_repository.end (); ++t) {
|
||||
std::string nn = t->string ();
|
||||
|
|
@ -107,12 +115,12 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > net_name_equivalence;
|
||||
if (m_text_annot_name_id.first) {
|
||||
if (! m_joined_net_names.empty ()) {
|
||||
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence [hier_clusters_type::top_cell_index]);
|
||||
build_net_name_equivalence (mp_layout, conn, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence [hier_clusters_type::top_cell_index]);
|
||||
}
|
||||
for (std::list<std::pair<std::string, std::string> >::const_iterator m = m_joined_net_names_per_cell.begin (); m != m_joined_net_names_per_cell.end (); ++m) {
|
||||
std::pair<bool, db::cell_index_type> cp = mp_layout->cell_by_name (m->first.c_str ());
|
||||
if (cp.first) {
|
||||
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m->second, net_name_equivalence [cp.second]);
|
||||
build_net_name_equivalence (mp_layout, conn, m_text_annot_name_id.second, m->second, net_name_equivalence [cp.second]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -313,7 +321,7 @@ void NetlistExtractor::collect_labels (const connected_clusters_type &clusters,
|
|||
|
||||
}
|
||||
|
||||
} else {
|
||||
} else if (db::is_text_ref_attr (*a)) {
|
||||
|
||||
net_names.insert (db::text_from_attr (*a));
|
||||
|
||||
|
|
|
|||
|
|
@ -104,46 +104,66 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
std::string cn = model;
|
||||
db::DeviceClass *cls = circuit->netlist ()->device_class_by_name (cn);
|
||||
|
||||
if (cls) {
|
||||
if (element == "R") {
|
||||
|
||||
// use given class
|
||||
|
||||
} else if (element == "R") {
|
||||
|
||||
if (cn.empty ()) {
|
||||
cn = "RES";
|
||||
if (cls) {
|
||||
if (! dynamic_cast<db::DeviceClassResistor *>(cls)) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a resistor device class as required by 'R' element")), cn));
|
||||
}
|
||||
} else {
|
||||
if (cn.empty ()) {
|
||||
cn = "RES";
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassResistor> (circuit, cn);
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassResistor> (circuit, cn);
|
||||
|
||||
// Apply multiplier
|
||||
value /= mult;
|
||||
|
||||
} else if (element == "L") {
|
||||
|
||||
if (cn.empty ()) {
|
||||
cn = "IND";
|
||||
if (cls) {
|
||||
if (! dynamic_cast<db::DeviceClassInductor *>(cls)) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a inductor device class as required by 'L' element")), cn));
|
||||
}
|
||||
} else {
|
||||
if (cn.empty ()) {
|
||||
cn = "IND";
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassInductor> (circuit, cn);
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassInductor> (circuit, cn);
|
||||
|
||||
// Apply multiplier
|
||||
value /= mult;
|
||||
|
||||
} else if (element == "C") {
|
||||
|
||||
if (cn.empty ()) {
|
||||
cn = "CAP";
|
||||
if (cls) {
|
||||
if (! dynamic_cast<db::DeviceClassCapacitor *>(cls)) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a capacitor device class as required by 'C' element")), cn));
|
||||
}
|
||||
} else {
|
||||
if (cn.empty ()) {
|
||||
cn = "CAP";
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassCapacitor> (circuit, cn);
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassCapacitor> (circuit, cn);
|
||||
|
||||
// Apply multiplier
|
||||
value *= mult;
|
||||
|
||||
} else if (element == "D") {
|
||||
|
||||
if (cn.empty ()) {
|
||||
cn = "DIODE";
|
||||
if (cls) {
|
||||
if (! dynamic_cast<db::DeviceClassDiode *>(cls)) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a diode device class as required by 'D' element")), cn));
|
||||
}
|
||||
} else {
|
||||
if (cn.empty ()) {
|
||||
cn = "DIODE";
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassDiode> (circuit, cn);
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassDiode> (circuit, cn);
|
||||
|
||||
// Apply multiplier to "A"
|
||||
std::map<std::string, double>::iterator p;
|
||||
|
|
@ -154,18 +174,30 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
|
||||
} else if (element == "Q") {
|
||||
|
||||
if (nets.size () == 3) {
|
||||
if (cn.empty ()) {
|
||||
cn = "BJT3";
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassBJT3Transistor> (circuit, cn);
|
||||
} else if (nets.size () == 4) {
|
||||
if (cn.empty ()) {
|
||||
cn = "BJT4";
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassBJT4Transistor> (circuit, cn);
|
||||
} else {
|
||||
if (nets.size () != 3 && nets.size () != 4) {
|
||||
error (tl::to_string (tr ("'Q' element needs to have 3 or 4 terminals")));
|
||||
} else if (cls) {
|
||||
if (nets.size () == 3) {
|
||||
if (! dynamic_cast<db::DeviceClassBJT3Transistor *>(cls)) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a 3-terminal BJT device class as required by 'Q' element")), cn));
|
||||
}
|
||||
} else {
|
||||
if (! dynamic_cast<db::DeviceClassBJT4Transistor *>(cls)) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a 4-terminal BJT device class as required by 'Q' element")), cn));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (nets.size () == 3) {
|
||||
if (cn.empty ()) {
|
||||
cn = "BJT3";
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassBJT3Transistor> (circuit, cn);
|
||||
} else {
|
||||
if (cn.empty ()) {
|
||||
cn = "BJT4";
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassBJT4Transistor> (circuit, cn);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply multiplier to "AE"
|
||||
|
|
@ -177,22 +209,28 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
|
||||
} else if (element == "M") {
|
||||
|
||||
if (nets.size () == 4) {
|
||||
if (cn.empty ()) {
|
||||
cn = "MOS4";
|
||||
if (cls) {
|
||||
if (! dynamic_cast<db::DeviceClassMOS4Transistor *>(cls)) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a 4-terminal MOS device class as required by 'M' element")), cn));
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassMOS4Transistor> (circuit, cn);
|
||||
|
||||
// Apply multiplier to "W"
|
||||
std::map<std::string, double>::iterator p;
|
||||
p = params.find ("W");
|
||||
if (p != params.end ()) {
|
||||
p->second *= mult;
|
||||
}
|
||||
|
||||
} else {
|
||||
error (tl::to_string (tr ("'M' element needs to have 4 terminals")));
|
||||
if (nets.size () == 4) {
|
||||
if (cn.empty ()) {
|
||||
cn = "MOS4";
|
||||
}
|
||||
cls = make_device_class<db::DeviceClassMOS4Transistor> (circuit, cn);
|
||||
} else {
|
||||
error (tl::to_string (tr ("'M' element needs to have 4 terminals")));
|
||||
}
|
||||
}
|
||||
|
||||
// Apply multiplier to "W"
|
||||
std::map<std::string, double>::iterator p;
|
||||
p = params.find ("W");
|
||||
if (p != params.end ()) {
|
||||
p->second *= mult;
|
||||
}
|
||||
|
||||
} else {
|
||||
error (tl::sprintf (tl::to_string (tr ("Not a known element type: '%s'")), element));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -864,10 +864,9 @@ RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const
|
|||
m_layer = m_layers.front ();
|
||||
}
|
||||
|
||||
if (! m_start.empty () && m_start.find (cell_index ()) != m_start.end ()) {
|
||||
set_inactive (false);
|
||||
} else if (! m_stop.empty () && m_stop.find (cell_index ()) != m_stop.end ()) {
|
||||
set_inactive (true);
|
||||
bool new_cell_inactive = is_child_inactive (cell_index ());
|
||||
if (is_inactive () != new_cell_inactive) {
|
||||
set_inactive (new_cell_inactive);
|
||||
}
|
||||
|
||||
new_layer ();
|
||||
|
|
@ -975,6 +974,18 @@ RecursiveShapeIterator::is_outside_complex_region (const db::Box &box) const
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RecursiveShapeIterator::is_child_inactive (db::cell_index_type new_child) const
|
||||
{
|
||||
bool inactive = is_inactive ();
|
||||
if (! m_start.empty () && m_start.find (new_child) != m_start.end ()) {
|
||||
inactive = false;
|
||||
} else if (! m_stop.empty () && m_stop.find (new_child) != m_stop.end ()) {
|
||||
inactive = true;
|
||||
}
|
||||
return inactive;
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -704,6 +704,19 @@ public:
|
|||
*/
|
||||
void push (RecursiveShapeReceiver *receiver);
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether the current cell is inactive (disabled)
|
||||
*/
|
||||
bool is_inactive () const
|
||||
{
|
||||
return (reinterpret_cast<size_t> (mp_cell) & size_t (1)) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether a new child cell of the current cell will be inactive
|
||||
*/
|
||||
bool is_child_inactive (db::cell_index_type new_child) const;
|
||||
|
||||
private:
|
||||
std::vector<unsigned int> m_layers;
|
||||
bool m_has_layers;
|
||||
|
|
@ -760,11 +773,6 @@ private:
|
|||
|
||||
bool is_outside_complex_region (const db::Box &box) const;
|
||||
|
||||
bool is_inactive () const
|
||||
{
|
||||
return (reinterpret_cast<size_t> (mp_cell) & size_t (1)) != 0;
|
||||
}
|
||||
|
||||
void set_inactive (bool a) const
|
||||
{
|
||||
size_t c = reinterpret_cast<size_t> (mp_cell);
|
||||
|
|
|
|||
|
|
@ -174,9 +174,15 @@ Shapes::do_insert (const Shapes &d)
|
|||
if (layout () == d.layout ()) {
|
||||
|
||||
// both shape containers reside in the same repository space - simply copy
|
||||
m_layers.reserve (d.m_layers.size ());
|
||||
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
|
||||
m_layers.push_back ((*l)->clone (this, manager ()));
|
||||
if (m_layers.empty ()) {
|
||||
m_layers.reserve (d.m_layers.size ());
|
||||
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
|
||||
m_layers.push_back ((*l)->clone (this, manager ()));
|
||||
}
|
||||
} else {
|
||||
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
|
||||
(*l)->insert_into (this);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (layout () == 0) {
|
||||
|
|
|
|||
|
|
@ -494,6 +494,7 @@ public:
|
|||
virtual void transform_into (Shapes *target, const Trans &trans, GenericRepository &rep, ArrayRepository &array_rep, pm_delegate_type &pm) const = 0;
|
||||
virtual void transform_into (Shapes *target, const ICplxTrans &trans, GenericRepository &rep, ArrayRepository &array_rep) const = 0;
|
||||
virtual void transform_into (Shapes *target, const ICplxTrans &trans, GenericRepository &rep, ArrayRepository &array_rep, pm_delegate_type &pm) const = 0;
|
||||
virtual void insert_into (Shapes *target) = 0;
|
||||
virtual void deref_into (Shapes *target) = 0;
|
||||
virtual void deref_into (Shapes *target, pm_delegate_type &pm) = 0;
|
||||
virtual void deref_and_transform_into (Shapes *target, const Trans &trans) = 0;
|
||||
|
|
|
|||
|
|
@ -834,6 +834,13 @@ layer_class<Sh, StableTag>::transform_into (Shapes *target, const ICplxTrans &tr
|
|||
}
|
||||
}
|
||||
|
||||
template <class Sh, class StableTag>
|
||||
void
|
||||
layer_class<Sh, StableTag>::insert_into (Shapes *target)
|
||||
{
|
||||
target->insert (m_layer.begin (), m_layer.end ());
|
||||
}
|
||||
|
||||
template <class Sh, class StableTag>
|
||||
void
|
||||
layer_class<Sh, StableTag>::deref_into (Shapes *target)
|
||||
|
|
@ -870,6 +877,7 @@ layer_class<Sh, StableTag>::deref_and_transform_into (Shapes *target, const Tran
|
|||
{
|
||||
deref_and_transform_into_shapes deref_op (target);
|
||||
for (typename layer_type::iterator s = m_layer.begin (); s != m_layer.end (); ++s) {
|
||||
|
||||
deref_op (*s, trans, pm);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ public:
|
|||
virtual void transform_into (Shapes *target, const Trans &trans, GenericRepository &rep, ArrayRepository &array_rep, pm_delegate_type &pm) const;
|
||||
virtual void transform_into (Shapes *target, const ICplxTrans &trans, GenericRepository &rep, ArrayRepository &array_rep) const;
|
||||
virtual void transform_into (Shapes *target, const ICplxTrans &trans, GenericRepository &rep, ArrayRepository &array_rep, pm_delegate_type &pm) const;
|
||||
virtual void insert_into (Shapes *target);
|
||||
virtual void deref_into (Shapes *target);
|
||||
virtual void deref_into (Shapes *target, pm_delegate_type &pm);
|
||||
virtual void deref_and_transform_into (Shapes *target, const Trans &trans);
|
||||
|
|
|
|||
|
|
@ -1491,6 +1491,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"If no property with that key exists, it will create one. Using that method is more "
|
||||
"convenient than creating a new property set with a new ID and assigning that properties ID.\n"
|
||||
"This method may change the properties ID. "
|
||||
"Note: GDS only supports integer keys. OASIS supports numeric and string keys. "
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
|
|
@ -3453,6 +3454,7 @@ Class<db::Instance> decl_Instance ("db", "Instance",
|
|||
"If no property with that key exists, it will create one. Using that method is more "
|
||||
"convenient than creating a new property set with a new ID and assigning that properties ID.\n"
|
||||
"This method may change the properties ID. "
|
||||
"Note: GDS only supports integer keys. OASIS supports numeric and string keys. "
|
||||
"Calling this method may invalidate any iterators. It should not be called inside a "
|
||||
"loop iterating over instances.\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "dbCommonReader.h"
|
||||
#include "dbLoadLayoutOptions.h"
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiEnums.h"
|
||||
|
||||
namespace dn
|
||||
{
|
||||
|
|
@ -84,6 +85,16 @@ static void set_properties_enabled (db::LoadLayoutOptions *options, bool l)
|
|||
options->get_options<db::CommonReaderOptions> ().enable_properties = l;
|
||||
}
|
||||
|
||||
static db::CommonReader::CellConflictResolution get_cell_conflict_resolution (const db::LoadLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::CommonReaderOptions> ().cell_conflict_resolution;
|
||||
}
|
||||
|
||||
static void set_cell_conflict_resolution (db::LoadLayoutOptions *options, db::CommonReader::CellConflictResolution cc)
|
||||
{
|
||||
options->get_options<db::CommonReaderOptions> ().cell_conflict_resolution = cc;
|
||||
}
|
||||
|
||||
// extend lay::LoadLayoutOptions with the Common options
|
||||
static
|
||||
gsi::ClassExt<db::LoadLayoutOptions> common_reader_options (
|
||||
|
|
@ -156,10 +167,56 @@ gsi::ClassExt<db::LoadLayoutOptions> common_reader_options (
|
|||
"@param enabled True, if properties should be read."
|
||||
"\n"
|
||||
"Starting with version 0.25 this option only applies to GDS2 and OASIS format. Other formats provide their own configuration."
|
||||
) +
|
||||
gsi::method_ext ("cell_conflict_resolution", &get_cell_conflict_resolution,
|
||||
"@brief Gets the cell conflict resolution mode\n"
|
||||
"\n"
|
||||
"Multiple layout files can be collected into a single Layout object by reading file after file into the Layout object. "
|
||||
"Cells with same names are considered a conflict. This mode indicates how such conflicts are resolved. See \\LoadLayoutOptions::CellConflictResolution "
|
||||
"for the values allowed. The default mode is \\LoadLayoutOptions::CellConflictResolution#AddToCell.\n"
|
||||
"\n"
|
||||
"This option has been introduced in version 0.27."
|
||||
) +
|
||||
gsi::method_ext ("cell_conflict_resolution=", &set_cell_conflict_resolution, gsi::arg ("mode"),
|
||||
"@brief Sets the cell conflict resolution mode\n"
|
||||
"\n"
|
||||
"See \\cell_conflict_resolution for details about this option.\n"
|
||||
"\n"
|
||||
"This option has been introduced in version 0.27."
|
||||
),
|
||||
""
|
||||
);
|
||||
|
||||
|
||||
gsi::EnumIn<db::LoadLayoutOptions, db::CommonReader::CellConflictResolution> decl_dbCommonReader_CellConflictResolution ("db", "CellConflictResolution",
|
||||
gsi::enum_const ("AddToCell", db::CommonReader::AddToCell,
|
||||
"@brief Add content to existing cell\n"
|
||||
"This is the mode use in before version 0.27. Content of new cells is simply added to existing cells with the same name."
|
||||
) +
|
||||
gsi::enum_const ("OverwriteCell", db::CommonReader::OverwriteCell,
|
||||
"@brief The old cell is overwritten entirely (including child cells which are not used otherwise)\n"
|
||||
) +
|
||||
gsi::enum_const ("SkipNewCell", db::CommonReader::SkipNewCell,
|
||||
"@brief The new cell is skipped entirely (including child cells which are not used otherwise)\n"
|
||||
) +
|
||||
gsi::enum_const ("RenameCell", db::CommonReader::RenameCell,
|
||||
"@brief The new cell will be renamed to become unique\n"
|
||||
),
|
||||
"@brief This enum specifies how cell conflicts are handled if a layout read into another layout and a cell name conflict arises. "
|
||||
"Until version 0.26.8 and before, the mode was always 'AddToCell'. On reading, a cell was 'reopened' when encountering a cell name "
|
||||
"which already existed. This mode is still the default. The other modes are made available to support other ways of merging layouts.\n"
|
||||
"\n"
|
||||
"Proxy cells are never modified in the existing layout. Proxy cells are always local to their layout file. So if the existing cell is "
|
||||
"a proxy cell, the new cell will be renamed.\n"
|
||||
"\n"
|
||||
"If the new or existing cell is a ghost cell, both cells are merged always.\n"
|
||||
"\n"
|
||||
"This enum was introduced in version 0.27.\n"
|
||||
);
|
||||
|
||||
// Inject the NetlistCrossReference::Status declarations into NetlistCrossReference:
|
||||
gsi::ClassExt<db::LoadLayoutOptions> inject_CellConflictResolution_in_parent (decl_dbCommonReader_CellConflictResolution.defs ());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1028,11 +1028,12 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"This method has been introduced in version 0.24."
|
||||
) +
|
||||
gsi::method_ext ("set_property", &set_layout_property, gsi::arg ("key"), gsi::arg ("value"),
|
||||
"@brief Set the user property with the given key to the given value\n"
|
||||
"@brief Sets the user property with the given key to the given value\n"
|
||||
"This method is a convenience method that sets the property with the given key to the given value. "
|
||||
"If no property with that key exists, it will create one. Using that method is more "
|
||||
"convenient than creating a new property set with a new ID and assigning that properties ID.\n"
|
||||
"This method may change the properties ID. "
|
||||
"Note: GDS only supports integer keys. OASIS supports numeric and string keys. "
|
||||
"\n"
|
||||
"This method has been introduced in version 0.24."
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -1283,6 +1283,7 @@ Class<db::Shape> decl_Shape ("db", "Shape",
|
|||
"If no property with that key exists, it will create one. Using that method is more "
|
||||
"convenient than creating a new property set with a new ID and assigning that properties ID.\n"
|
||||
"This method may change the properties ID. "
|
||||
"Note: GDS only supports integer keys. OASIS supports numeric and string keys. "
|
||||
"Calling this method will invalidate any iterators. It should not be called inside a "
|
||||
"loop iterating over shapes.\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -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 "dbD25TechnologyComponent.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
|
||||
TEST(1)
|
||||
{
|
||||
db::D25TechnologyComponent comp;
|
||||
|
||||
comp.compile_from_source ("1/0: 1.0 1.5 # a comment");
|
||||
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5");
|
||||
|
||||
comp.compile_from_source ("1/0: zstart=1.0 zstop=1.5");
|
||||
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5");
|
||||
|
||||
comp.compile_from_source ("1/0: zstart=1.0 height=0.5");
|
||||
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5");
|
||||
|
||||
comp.compile_from_source ("1/0: 1.0 height=0.5");
|
||||
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5");
|
||||
|
||||
comp.compile_from_source ("1/0: zstop=1.5 height=0.5");
|
||||
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");
|
||||
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");
|
||||
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=4, zstop=7");
|
||||
|
||||
try {
|
||||
comp.compile_from_source ("blabla");
|
||||
EXPECT_EQ (false, true);
|
||||
} catch (...) { }
|
||||
|
||||
try {
|
||||
comp.compile_from_source ("1/0: 1 2 3");
|
||||
EXPECT_EQ (false, true);
|
||||
} catch (...) { }
|
||||
|
||||
try {
|
||||
comp.compile_from_source ("1/0: foo=1 bar=2");
|
||||
EXPECT_EQ (false, true);
|
||||
} catch (...) { }
|
||||
|
||||
try {
|
||||
comp.compile_from_source ("1/0: 1;2");
|
||||
EXPECT_EQ (false, true);
|
||||
} catch (...) { }
|
||||
}
|
||||
|
|
@ -606,8 +606,8 @@ TEST(BasicAnd9)
|
|||
// from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than
|
||||
// 6. And the shapes from top inside the ring are not seen by the RING's subject shapes.
|
||||
"TOP[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"RING[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"CHILD1[1] 0 insts, 4 shapes (2 times)\n"
|
||||
"RING[1] 0 insts, 0 shapes (1 times)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -622,8 +622,8 @@ TEST(BasicNot9)
|
|||
// from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than
|
||||
// 6. And the shapes from top inside the ring are not seen by the RING's subject shapes.
|
||||
"TOP[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"RING[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"CHILD1[1] 0 insts, 4 shapes (2 times)\n"
|
||||
"RING[1] 0 insts, 0 shapes (1 times)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -746,8 +746,8 @@ TEST(BasicAndWithSize9)
|
|||
// from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than
|
||||
// 6. And the shapes from top inside the ring are not seen by the RING's subject shapes.
|
||||
"TOP[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"RING[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"CHILD1[1] 0 insts, 6 shapes (2 times)\n"
|
||||
"RING[1] 0 insts, 0 shapes (1 times)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -762,8 +762,8 @@ TEST(BasicNotWithSize9)
|
|||
// from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than
|
||||
// 6. And the shapes from top inside the ring are not seen by the RING's subject shapes.
|
||||
"TOP[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"RING[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"CHILD1[1] 0 insts, 6 shapes (2 times)\n"
|
||||
"RING[1] 0 insts, 0 shapes (1 times)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -898,8 +898,8 @@ TEST(TwoInputsAnd9)
|
|||
// from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than
|
||||
// 6. And the shapes from top inside the ring are not seen by the RING's subject shapes.
|
||||
"TOP[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"RING[1] 1 insts, 0 shapes (1 times)\n"
|
||||
"CHILD1[1] 0 insts, 4 shapes (2 times)\n"
|
||||
"RING[1] 1 insts, 0 shapes (1 times)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -914,8 +914,8 @@ TEST(TwoInputsNot9)
|
|||
// from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than
|
||||
// 6. And the shapes from top inside the ring are not seen by the RING's subject shapes.
|
||||
"TOP[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"RING[1] 1 insts, 0 shapes (1 times)\n"
|
||||
"CHILD1[1] 0 insts, 4 shapes (2 times)\n"
|
||||
"RING[1] 1 insts, 0 shapes (1 times)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1038,8 +1038,8 @@ TEST(TwoInputsAndWithSize9)
|
|||
// from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than
|
||||
// 6. And the shapes from top inside the ring are not seen by the RING's subject shapes.
|
||||
"TOP[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"RING[1] 1 insts, 0 shapes (1 times)\n"
|
||||
"CHILD1[1] 0 insts, 6 shapes (2 times)\n"
|
||||
"RING[1] 1 insts, 0 shapes (1 times)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1054,8 +1054,8 @@ TEST(TwoInputsNotWithSize9)
|
|||
// from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than
|
||||
// 6. And the shapes from top inside the ring are not seen by the RING's subject shapes.
|
||||
"TOP[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"RING[1] 1 insts, 0 shapes (1 times)\n"
|
||||
"CHILD1[1] 0 insts, 6 shapes (2 times)\n"
|
||||
"RING[1] 1 insts, 0 shapes (1 times)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1130,8 +1130,8 @@ TEST(BasicSelfOverlap9)
|
|||
// from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than
|
||||
// 6. And the shapes from top inside the ring are not seen by the RING's subject shapes.
|
||||
"TOP[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"RING[1] 0 insts, 1 shapes (1 times)\n"
|
||||
"CHILD1[1] 0 insts, 4 shapes (2 times)\n"
|
||||
"RING[1] 0 insts, 1 shapes (1 times)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1200,8 +1200,8 @@ TEST(BasicSelfOverlapWithSize9)
|
|||
// from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than
|
||||
// 6. And the shapes from top inside the ring are not seen by the RING's subject shapes.
|
||||
"TOP[1] 0 insts, 0 shapes (1 times)\n"
|
||||
"RING[1] 0 insts, 1 shapes (1 times)\n"
|
||||
"CHILD1[1] 0 insts, 6 shapes (2 times)\n"
|
||||
"RING[1] 0 insts, 1 shapes (1 times)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3156,3 +3156,232 @@ TEST(12_FlattenCircuitDoesFlattenLayout)
|
|||
db::compare_layouts (_this, ly, au);
|
||||
}
|
||||
|
||||
TEST(13_JoinNets)
|
||||
{
|
||||
db::Layout ly;
|
||||
db::LayerMap lmap;
|
||||
|
||||
unsigned int nwell = define_layer (ly, lmap, 1);
|
||||
unsigned int active = define_layer (ly, lmap, 2);
|
||||
unsigned int pplus = define_layer (ly, lmap, 10);
|
||||
unsigned int nplus = define_layer (ly, lmap, 11);
|
||||
unsigned int poly = define_layer (ly, lmap, 3);
|
||||
unsigned int poly_lbl = define_layer (ly, lmap, 3, 1);
|
||||
unsigned int diff_cont = define_layer (ly, lmap, 4);
|
||||
unsigned int poly_cont = define_layer (ly, lmap, 5);
|
||||
unsigned int metal1 = define_layer (ly, lmap, 6);
|
||||
unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1);
|
||||
unsigned int via1 = define_layer (ly, lmap, 7);
|
||||
unsigned int metal2 = define_layer (ly, lmap, 8);
|
||||
unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1);
|
||||
|
||||
{
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
|
||||
std::string fn (tl::testsrc ());
|
||||
fn = tl::combine_path (fn, "testdata");
|
||||
fn = tl::combine_path (fn, "algo");
|
||||
fn = tl::combine_path (fn, "device_extract_l13.gds");
|
||||
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly, options);
|
||||
}
|
||||
|
||||
db::Cell &tc = ly.cell (*ly.begin_top_down ());
|
||||
db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set<unsigned int> ()));
|
||||
|
||||
std::auto_ptr<db::Region> rbulk (l2n.make_layer ("bulk"));
|
||||
std::auto_ptr<db::Region> rnwell (l2n.make_layer (nwell, "nwell"));
|
||||
std::auto_ptr<db::Region> ractive (l2n.make_layer (active, "active"));
|
||||
std::auto_ptr<db::Region> rpplus (l2n.make_layer (pplus, "pplus"));
|
||||
std::auto_ptr<db::Region> rnplus (l2n.make_layer (nplus, "nplus"));
|
||||
std::auto_ptr<db::Region> rpoly (l2n.make_polygon_layer (poly, "poly"));
|
||||
std::auto_ptr<db::Texts> rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl"));
|
||||
std::auto_ptr<db::Region> rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont"));
|
||||
std::auto_ptr<db::Region> rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont"));
|
||||
std::auto_ptr<db::Region> rmetal1 (l2n.make_polygon_layer (metal1, "metal1"));
|
||||
std::auto_ptr<db::Texts> rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl"));
|
||||
std::auto_ptr<db::Region> rvia1 (l2n.make_polygon_layer (via1, "via1"));
|
||||
std::auto_ptr<db::Region> rmetal2 (l2n.make_polygon_layer (metal2, "metal2"));
|
||||
std::auto_ptr<db::Texts> rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl"));
|
||||
|
||||
// derived regions
|
||||
|
||||
db::Region ractive_in_nwell = *ractive & *rnwell;
|
||||
db::Region rpactive = ractive_in_nwell & *rpplus;
|
||||
db::Region rntie = ractive_in_nwell & *rnplus;
|
||||
db::Region rpgate = rpactive & *rpoly;
|
||||
db::Region rpsd = rpactive - rpgate;
|
||||
|
||||
db::Region ractive_outside_nwell = *ractive - *rnwell;
|
||||
db::Region rnactive = ractive_outside_nwell & *rnplus;
|
||||
db::Region rptie = ractive_outside_nwell & *rpplus;
|
||||
db::Region rngate = rnactive & *rpoly;
|
||||
db::Region rnsd = rnactive - rngate;
|
||||
|
||||
// return the computed layers into the original layout and write it for debugging purposes
|
||||
|
||||
unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 20/0 -> Gate
|
||||
unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 21/0 -> Source/Drain
|
||||
unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 22/0 -> P Diffusion
|
||||
unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 23/0 -> N Diffusion
|
||||
unsigned int lptie = ly.insert_layer (db::LayerProperties (24, 0)); // 24/0 -> P Tie
|
||||
unsigned int lntie = ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie
|
||||
|
||||
rpgate.insert_into (&ly, tc.cell_index (), lgate);
|
||||
rngate.insert_into (&ly, tc.cell_index (), lgate);
|
||||
rpsd.insert_into (&ly, tc.cell_index (), lsd);
|
||||
rnsd.insert_into (&ly, tc.cell_index (), lsd);
|
||||
rpsd.insert_into (&ly, tc.cell_index (), lpdiff);
|
||||
rnsd.insert_into (&ly, tc.cell_index (), lndiff);
|
||||
rpsd.insert_into (&ly, tc.cell_index (), lptie);
|
||||
rnsd.insert_into (&ly, tc.cell_index (), lntie);
|
||||
|
||||
db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS");
|
||||
db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS");
|
||||
|
||||
// device extraction
|
||||
|
||||
db::NetlistDeviceExtractor::input_layers dl;
|
||||
|
||||
dl["SD"] = &rpsd;
|
||||
dl["G"] = &rpgate;
|
||||
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
|
||||
dl["W"] = rnwell.get ();
|
||||
l2n.extract_devices (pmos_ex, dl);
|
||||
|
||||
dl["SD"] = &rnsd;
|
||||
dl["G"] = &rngate;
|
||||
dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes
|
||||
dl["W"] = rbulk.get ();
|
||||
l2n.extract_devices (nmos_ex, dl);
|
||||
|
||||
// net extraction
|
||||
|
||||
l2n.register_layer (rpsd, "psd");
|
||||
l2n.register_layer (rnsd, "nsd");
|
||||
l2n.register_layer (rptie, "ptie");
|
||||
l2n.register_layer (rntie, "ntie");
|
||||
|
||||
// Intra-layer
|
||||
l2n.connect (rpsd);
|
||||
l2n.connect (rnsd);
|
||||
l2n.connect (*rnwell);
|
||||
l2n.connect (*rpoly);
|
||||
l2n.connect (*rdiff_cont);
|
||||
l2n.connect (*rpoly_cont);
|
||||
l2n.connect (*rmetal1);
|
||||
l2n.connect (*rvia1);
|
||||
l2n.connect (*rmetal2);
|
||||
l2n.connect (rptie);
|
||||
l2n.connect (rntie);
|
||||
// Inter-layer
|
||||
l2n.connect (rpsd, *rdiff_cont);
|
||||
l2n.connect (rnsd, *rdiff_cont);
|
||||
l2n.connect (*rpoly, *rpoly_cont);
|
||||
l2n.connect (*rpoly_cont, *rmetal1);
|
||||
l2n.connect (*rdiff_cont, *rmetal1);
|
||||
l2n.connect (*rdiff_cont, rptie);
|
||||
l2n.connect (*rdiff_cont, rntie);
|
||||
l2n.connect (*rnwell, rntie);
|
||||
l2n.connect (*rmetal1, *rvia1);
|
||||
l2n.connect (*rvia1, *rmetal2);
|
||||
l2n.connect (*rpoly, *rpoly_lbl); // attaches labels
|
||||
l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels
|
||||
l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels
|
||||
// Global
|
||||
l2n.connect_global (rntie, "VDD");
|
||||
l2n.connect_global (*rnwell, "VDD");
|
||||
l2n.connect_global (rptie, "VSS");
|
||||
l2n.connect_global (*rbulk, "VSS");
|
||||
|
||||
// Extract with joining VSS and VDD
|
||||
l2n.extract_netlist ("{VSS,VDD}");
|
||||
|
||||
// debug layers produced for nets
|
||||
// 201/0 -> Well
|
||||
// 203/0 -> Poly
|
||||
// 204/0 -> Diffusion contacts
|
||||
// 205/0 -> Poly contacts
|
||||
// 206/0 -> Metal1
|
||||
// 207/0 -> Via1
|
||||
// 208/0 -> Metal2
|
||||
// 210/0 -> N source/drain
|
||||
// 211/0 -> P source/drain
|
||||
// 212/0 -> N tie
|
||||
// 213/0 -> P tie
|
||||
std::map<const db::Region *, unsigned int> dump_map;
|
||||
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (210, 0));
|
||||
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (211, 0));
|
||||
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (212, 0));
|
||||
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (213, 0));
|
||||
dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (214, 0));
|
||||
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (201, 0));
|
||||
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (203, 0));
|
||||
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (204, 0));
|
||||
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (205, 0));
|
||||
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (206, 0));
|
||||
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (207, 0));
|
||||
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (208, 0));
|
||||
|
||||
// write nets to layout
|
||||
db::CellMapping cm = l2n.cell_mapping_into (ly, tc);
|
||||
dump_nets_to_layout (l2n, ly, dump_map, cm);
|
||||
|
||||
dump_map.clear ();
|
||||
dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (310, 0));
|
||||
dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (311, 0));
|
||||
dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (312, 0));
|
||||
dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (313, 0));
|
||||
dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (314, 0));
|
||||
dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (301, 0));
|
||||
dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (303, 0));
|
||||
dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (304, 0));
|
||||
dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (305, 0));
|
||||
dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (306, 0));
|
||||
dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (307, 0));
|
||||
dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (308, 0));
|
||||
|
||||
dump_recursive_nets_to_layout (l2n, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
CHECKPOINT ();
|
||||
db::compare_netlist (_this, *l2n.netlist (),
|
||||
"circuit RINGO ();\n"
|
||||
" subcircuit INV2 $1 (IN=$I7,$2=FB,OUT=OSC,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n"
|
||||
" subcircuit INV2 $2 (IN=FB,$2=$I34,OUT=$I17,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n"
|
||||
" subcircuit INV2 $3 (IN=$3,$2=$I38,OUT=$I4,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n"
|
||||
" subcircuit INV2 $4 (IN=$I2,$2=$I37,OUT=$3,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n"
|
||||
" subcircuit INV2 $5 (IN=$I4,$2=$I39,OUT=$I5,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n"
|
||||
" subcircuit INV2 $6 (IN=$I5,$2=$I40,OUT=$I6,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n"
|
||||
" subcircuit INV2 $7 (IN=$I6,$2=$I41,OUT=$I7,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n"
|
||||
" subcircuit INV2 $8 (IN=$I17,$2=$I35,OUT=$I1,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n"
|
||||
" subcircuit INV2 $9 (IN=$I1,$2=$I36,OUT=$I2,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n"
|
||||
"end;\n"
|
||||
"circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5,VDD=VDD,VSS=VSS);\n"
|
||||
" device PMOS $1 (S=$2,G=IN,D=$5,B=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device PMOS $2 (S=$5,G=$2,D=OUT,B=VDD) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" device NMOS $3 (S=$2,G=IN,D=$4,B=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
|
||||
" device NMOS $4 (S=$4,G=$2,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n"
|
||||
" subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n"
|
||||
" subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n"
|
||||
" subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n"
|
||||
" subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n"
|
||||
"end;\n"
|
||||
"circuit TRANS ($1=$1,$2=$2,$3=$3);\n"
|
||||
"end;\n"
|
||||
);
|
||||
|
||||
// compare the collected test data
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au = tl::combine_path (au, "testdata");
|
||||
au = tl::combine_path (au, "algo");
|
||||
au = tl::combine_path (au, "device_extract_au13_circuits.gds");
|
||||
|
||||
db::compare_layouts (_this, ly, au);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -359,28 +359,75 @@ TEST(9_DeviceMultipliers)
|
|||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader9.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
{
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
std::string nl_string = nl.to_string ();
|
||||
// normalization of exponential representation:
|
||||
nl_string = tl::replaced (nl_string, "e-009", "e-09");
|
||||
std::string nl_string = nl.to_string ();
|
||||
// normalization of exponential representation:
|
||||
nl_string = tl::replaced (nl_string, "e-009", "e-09");
|
||||
|
||||
EXPECT_EQ (nl_string,
|
||||
"circuit .TOP ();\n"
|
||||
" device RES $1 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||
" device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
||||
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
||||
" device DIODE $1 (A='1',C='2') (A=20,P=0);\n"
|
||||
" device DIODE $2 (A='3',C='4') (A=10,P=0);\n"
|
||||
" device BIP $1 (C='1',B='2',E='3',S='4') (AE=20,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
|
||||
" device BIP $2 (C='1',B='2',E='3',S='4') (AE=10,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
|
||||
"end;\n"
|
||||
);
|
||||
EXPECT_EQ (nl_string,
|
||||
"circuit .TOP ();\n"
|
||||
" device RES $1 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||
" device RMODEL $3 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
|
||||
" device RMODEL $4 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||
" device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
||||
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
||||
" device CMODEL $3 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
||||
" device CMODEL $4 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
||||
" device IND $1 (A='1',B='2') (L=5e-10);\n"
|
||||
" device IND $2 (A='3',B='4') (L=1e-09);\n"
|
||||
" device LMODEL $3 (A='1',B='2') (L=5e-10);\n"
|
||||
" device LMODEL $4 (A='3',B='4') (L=1e-09);\n"
|
||||
" device DIODE $1 (A='1',C='2') (A=20,P=0);\n"
|
||||
" device DIODE $2 (A='3',C='4') (A=10,P=0);\n"
|
||||
" device BIP $1 (C='1',B='2',E='3',S='4') (AE=20,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
|
||||
" device BIP $2 (C='1',B='2',E='3',S='4') (AE=10,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
db::Circuit *top = nl.circuit_by_name (".TOP");
|
||||
nl.remove_circuit (top);
|
||||
|
||||
// read once again, this time with known classes (must not trigger issue-652)
|
||||
{
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
std::string nl_string = nl.to_string ();
|
||||
// normalization of exponential representation:
|
||||
nl_string = tl::replaced (nl_string, "e-009", "e-09");
|
||||
|
||||
EXPECT_EQ (nl_string,
|
||||
"circuit .TOP ();\n"
|
||||
" device RES $1 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
|
||||
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||
" device RMODEL $3 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
|
||||
" device RMODEL $4 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||
" device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
||||
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
||||
" device CMODEL $3 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
||||
" device CMODEL $4 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
||||
" device IND $1 (A='1',B='2') (L=5e-10);\n"
|
||||
" device IND $2 (A='3',B='4') (L=1e-09);\n"
|
||||
" device LMODEL $3 (A='1',B='2') (L=5e-10);\n"
|
||||
" device LMODEL $4 (A='3',B='4') (L=1e-09);\n"
|
||||
" device DIODE $1 (A='1',C='2') (A=20,P=0);\n"
|
||||
" device DIODE $2 (A='3',C='4') (A=10,P=0);\n"
|
||||
" device BIP $1 (C='1',B='2',E='3',S='4') (AE=20,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
|
||||
" device BIP $2 (C='1',B='2',E='3',S='4') (AE=10,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(10_SubcircuitsNoPins)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ SOURCES = \
|
|||
dbPolygonToolsTests.cc \
|
||||
dbTechnologyTests.cc \
|
||||
dbStreamLayerTests.cc \
|
||||
dbD25TechnologyComponentTests.cc \
|
||||
dbVectorTests.cc \
|
||||
dbVariableWidthPathTests.cc \
|
||||
dbTransTests.cc \
|
||||
|
|
|
|||
|
|
@ -1352,7 +1352,7 @@ module DRC
|
|||
# @/code
|
||||
#
|
||||
# (Technically, the cheat code block is a Ruby Proc and cannot create variables
|
||||
# outside it's scope. Hence the results of this code block have to be passed
|
||||
# outside its scope. Hence the results of this code block have to be passed
|
||||
# through the "cheat" method).
|
||||
#
|
||||
# To apply cheats for device extraction, use the following scheme:
|
||||
|
|
@ -2003,7 +2003,7 @@ CODE
|
|||
|
||||
sel.each do |s|
|
||||
if s == "-"
|
||||
iter.unselect_cells(cell.cell_index)
|
||||
iter.unselect_cells([cell_index])
|
||||
elsif s == "-*"
|
||||
iter.unselect_all_cells
|
||||
elsif s == "+*"
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ module DRC
|
|||
# @li \global#capacitor_with_bulk - A capacitor with a separate bulk terminal @/li
|
||||
# @/ul
|
||||
#
|
||||
# Each device class (e.g. n-MOS/p-MOS or high Vt/low Vt) needs it's own instance
|
||||
# Each device class (e.g. n-MOS/p-MOS or high Vt/low Vt) needs its own instance
|
||||
# of device extractor. The device extractor beside the algorithm and specific
|
||||
# extraction settings defines the name of the device to be built.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -22,14 +22,27 @@ module DRC
|
|||
@layout_var = layout_var
|
||||
@path = path
|
||||
@cell = cell
|
||||
@inside = nil
|
||||
@box = nil
|
||||
@layers = nil
|
||||
@sel = []
|
||||
@clip = false
|
||||
@overlapping = false
|
||||
@tmp_layers = []
|
||||
end
|
||||
|
||||
# Conceptual deep copy (not including the temp layers)
|
||||
def dup
|
||||
d = DRCSource::new(@engine, @layout, @layout_var, @cell, @path)
|
||||
d._init_internal(@box ? @box.dup : nil, @sel.dup, @clip, @overlapping)
|
||||
d
|
||||
end
|
||||
|
||||
# internal copy initialization
|
||||
def _init_internal(box, sel, clip, overlapping)
|
||||
@box = box
|
||||
@sel = sel
|
||||
@clip = clip
|
||||
@overlapping = overlapping
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name layout
|
||||
|
|
@ -139,19 +152,34 @@ module DRC
|
|||
# code:
|
||||
#
|
||||
# @code
|
||||
# layout_with_selection = layout.select("-TOP", "+B")
|
||||
# l1 = layout_with_selection.input(1, 0)
|
||||
# layout_with_selection = source.select("-TOP", "+B")
|
||||
# l1 = source.input(1, 0)
|
||||
# ...
|
||||
# @/code
|
||||
#
|
||||
# Please note that the sample above will deliver the children of "B" because there is
|
||||
# nothing said about how to proceed with cells other than "TOP" or "B".
|
||||
# The following code will just select "B" without it's children, because in the
|
||||
# nothing said about how to proceed with cells other than "TOP" or "B". Conceptually,
|
||||
# the instantiation path of a cell will be matched against the different filters in the
|
||||
# order they are given.
|
||||
# A matching negative expression will disable the cell, a matching positive expression
|
||||
# will enable the cell. Hence, every cell that has a "B" in the instantiation path
|
||||
# is enabled.
|
||||
#
|
||||
# The following code will just select "B" without its children, because in the
|
||||
# first "-*" selection, all cells including the children of "B" are disabled:
|
||||
#
|
||||
# @code
|
||||
# layout_with_selection = layout.select("-*", "+B")
|
||||
# l1 = layout_with_selection.input(1, 0)
|
||||
# layout_with_selection = source.select("-*", "+B")
|
||||
# l1 = source.input(1, 0)
|
||||
# ...
|
||||
# @/code
|
||||
#
|
||||
# The short form "-" will disable the top cell. This code is identical to the first example
|
||||
# and will start with a disabled top cell regardless of its name:
|
||||
#
|
||||
# @code
|
||||
# layout_with_selection = source.select("-", "+B")
|
||||
# l1 = source.input(1, 0)
|
||||
# ...
|
||||
# @/code
|
||||
|
||||
|
|
|
|||
|
|
@ -756,6 +756,47 @@ TEST(16_issue570)
|
|||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
// Problems with Source#select
|
||||
TEST(17_issue570)
|
||||
{
|
||||
std::string rs = tl::testsrc ();
|
||||
rs += "/testdata/drc/drcSimpleTests_17.drc";
|
||||
|
||||
std::string input = tl::testsrc ();
|
||||
input += "/testdata/drc/drcSimpleTests_17.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/drc/drcSimpleTests_au17.gds";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.gds");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
, input, output)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
TEST(18_forget)
|
||||
{
|
||||
std::string rs = tl::testsrc ();
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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 ("gx,gy")</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 ("gx,gy")</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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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) ..
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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> ¶meters)
|
||||
void
|
||||
EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector <tl::Variant> ¶meters)
|
||||
{
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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> ¶meters);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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 ¶meters)
|
||||
: 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> ¶meters)
|
||||
PCellParametersPage::set_parameters (const std::vector<tl::Variant> ¶meters)
|
||||
{
|
||||
// write the changed value back
|
||||
size_t r = 0;
|
||||
|
|
|
|||
|
|
@ -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 ¶meters);
|
||||
|
||||
/**
|
||||
* @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 ¶meters);
|
||||
|
||||
|
|
@ -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 ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 >, 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 >, const std::vector<db::DCplxTrans> &tv, bool transient);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
#include "dbShapes.h"
|
||||
#include "dbLayout.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
namespace edt
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
namespace edt
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -60,49 +60,8 @@ ac_from_buttons (unsigned int buttons)
|
|||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> ¶meters)
|
||||
{
|
||||
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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> ¶meters)
|
||||
{
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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> ¶meters);
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
|
|
|||
|
|
@ -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]");
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ equals(HAVE_QT, "0") {
|
|||
} else {
|
||||
|
||||
DEFINES += HAVE_QT
|
||||
QT += core network xml sql
|
||||
QT += core network xml sql widgets
|
||||
|
||||
equals(HAVE_QT5, "1") {
|
||||
QT += designer printsupport
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue