From ad027e713efb2ea54ac55bc7c82c20fdb5ab035b Mon Sep 17 00:00:00 2001 From: jzzhuang <840064358@qq.com> Date: Wed, 25 Oct 2023 20:54:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=BD=E9=99=85=E5=8C=96=E3=80=81=E6=97=A5?= =?UTF-8?q?=E6=9C=AC=E5=8F=8A=E4=B8=AD=E5=9B=BD=E5=A4=A7=E9=99=86=E5=9C=B0?= =?UTF-8?q?=E5=8C=BA=E8=AF=A2=E4=BB=B7=E4=B8=8B=E5=8D=95=20(#2)=20(#4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refact the dir * Update dev instruction p * Init modules * Add order and price * Add pcb_fabrication * Add service iIp * Remove service * Add adt for the request info * Add i18n template * add main dialog * Remove dists * add base_info_view * add ui_base_info * Finish the base info view * add UiProcessInfo * Add ui_personalized * Finish Personalized info * Finish the process info widget * Finish the dialog * Init i18n * Fix the sys path * Fix the syle * Fix base info * Fix the initial size * Fix the size * Fix the initial size for base info * Fix duplicated path * Add order info * Finish main window * Finish the order info panel * Fix the size for order info * Fix the scrollbar * Finish the flat button * add language * Add lang setting menu * Add models for order info * Remove dist * Remove dist * Add po files * Enable i18n * Remove dist files * Remove dist * Add setting manager * add re_translatable * add LocaleChangeEvent * Fix painting * Remove dist * read the language setting from kicad client * Remove dist * Update locales * Fix the base class for MainFrame * Fix the locale path * Update translation * Add ja * Finish the translation * Update translation * Fix translation * Update translation * Update UI * Fix the unit * Restore the old widgets * Update utils ' * Add kicad * Add board manager * add pcb_fabrication_evt_list * Finish the connection for base info * Fix base info * Add board manager * Adjust the base size for special process * Enable SILK_SCREEN_COLOR_BY_SOLDER_COLOR * Finish the constraint between the UI component * Fix the base info * Add base request * Fix the sp request * add snippy for params * Add number round * Finish the models mapping * Finish the api for querying price * Add order module * Add summary module * Add summary_panel * Add place order impl * Finish placing order * enable order region setting * Fix the OrderRegion * Add smt pcb models * Finish the price summary * Finish the pcb * Update translation * Prepare to import region change * Add cn params in the form * Fix translation Fix the region * Fix the width * Fix the available board thickness * Fix the board thickness * Record the window size * Finish adjusting the window layout * Adjust the order_summary_model * Finish showing the emergency price * Update Japanese translation * Finish the translatin * Add ComboBoxIgnoreWheel * Finish ComboBoxIgnoreWheel * add ComboBoxIgnoreWheel to builtin * FInish ComboBoxIgnoreWheel * Fix the summary model * Update the api * Remove dist files * Add release plugin * Always clear content while querying price * Migrate the original PCM * Update the create_pcm_archive.sh * Update git ignore * Adjust the ci for testing * Fxi the token * Fix the pcm script * Restore the original workflow yml * Fix the archive script * Revert "Restore the original workflow yml" This reverts commit f680d78ac63c24eae9b3267ec14e104338873ec0. * Fix the pcm script * Fix the pcm script * Fix the PCM script * Update the pcm script * Fix the pcm path * Fix the geni18n script * install wxPython in the script * Fix the translation * Update the mo files * Comment the translation step * Ignore the mo file * Fix the dumplicated lang_const * Adjust the geni18n script to run on github ci * Adjust the script to setup env * Install the python-gettext in the ci * Ajust the gen18n script to run on ci * Enable reading region from IP * Restore the yml * fmt the yml * Fix the lang setting menu * Adjust the yml for test * Revert "Adjust the yml for test" This reverts commit f839cd20430609ac365eb290785ab00872923472. * Fix the null parent in the price summary model * Fix the parent for price item * Fix the check state of the lang setting btn * Finish the api for placing order through hqpcb * Add value mapping * Add form value mapper * Enable jp order region * Finish the plugin * Fix the board manager * Fix the generate_geber method while layer_count>6 * Fix generate_geber * Check if the layer count is supported * Fix the stack up * Adjust the runner to WIndows * Use ubuntu-20.04 as runner * Restore the .yml * Formmatter test * Fix the panel calc * Fix the blind value * Remove dist * Fix the cover * Enable modal dialog * Add single plugin * Add setup_trace_and_via in the base info * Add test * add query price test case * Restore the original yml config * Fix the min trace * Add simple * Remove dist yml Co-authored-by: Yihuo <65127095+Liangtie@users.noreply.github.com> --- .github/workflows/kicad-pcm-simple.bak | 43 + .github/workflows/kicad-pcm.yml | 10 +- .gitignore | 151 ++ .pre-commit-config.yaml | 11 + DEVELOPMENT.md | 42 + PCM/create_pcm_archive.sh | 71 +- PCM/metadata.template.json | 64 +- __init__.py | 11 +- __main__.py | 4 + config.json | 43 - dialog_amf.py | 674 ------ dialog_amf_base.py | 659 ------ icon.png | Bin 1149 -> 0 bytes kicad_amf_plugin/__init__.py | 3 + kicad_amf_plugin/api/base_request.py | 9 + kicad_amf_plugin/gui/__init__.py | 0 kicad_amf_plugin/gui/app_base.py | 89 + kicad_amf_plugin/gui/event/__init__.py | 0 .../gui/event/pcb_fabrication_evt_list.py | 23 + kicad_amf_plugin/gui/main_frame.py | 288 +++ kicad_amf_plugin/gui/summary/__init__.py | 0 .../gui/summary/bom_price_model.py | 20 + .../gui/summary/order_summary_model.py | 85 + .../gui/summary/pcb_price_model.py | 120 ++ .../gui/summary/place_order_request.py | 8 + .../gui/summary/price_model_base.py | 46 + .../gui/summary/price_summary_model.py | 169 ++ .../gui/summary/smt_price_model.py | 20 + kicad_amf_plugin/gui/summary/summary_panel.py | 116 + .../gui/summary/ui_summary_panel.fbp | 443 ++++ .../gui/summary/ui_summary_panel.py | 139 ++ .../icon/Huaqiu.png | Bin kicad_amf_plugin/icon/__init__.py | 7 + kicad_amf_plugin/icon/cart.png | Bin 0 -> 303 bytes kicad_amf_plugin/icon/icon.png | Bin 0 -> 503 bytes kicad_amf_plugin/icon/language.png | Bin 0 -> 681 bytes kicad_amf_plugin/icon/query.png | Bin 0 -> 296 bytes kicad_amf_plugin/kicad/board_manager.py | 43 + .../kicad/fabrication_data_generator.py | 139 +- .../kicad/helpers.py | 0 kicad_amf_plugin/language/__init__.py | 0 kicad_amf_plugin/language/geni18n.py | 86 + kicad_amf_plugin/language/lang_const.py | 39 + .../language/lang_setting_pop_menu.py | 35 + .../locale/ja/LC_MESSAGES/kicad_amf_plugin.po | 740 +++++++ .../LC_MESSAGES/generate_param_mapping.py | 18 + .../zh_CN/LC_MESSAGES/kicad_amf_plugin.po | 821 +++++++ kicad_amf_plugin/order/__init__.py | 0 kicad_amf_plugin/order/order_region.py | 29 + kicad_amf_plugin/order/supported_region.py | 4 + kicad_amf_plugin/pcb_fabrication/__init__.py | 0 .../pcb_fabrication/base/__init__.py | 0 .../pcb_fabrication/base/base_info_model.py | 20 + .../pcb_fabrication/base/base_info_view.py | 370 ++++ .../pcb_fabrication/base/ui_base_info.fbp | 1918 +++++++++++++++++ .../pcb_fabrication/base/ui_base_info.py | 453 ++++ .../pcb_fabrication/personalized/__init__.py | 0 .../personalized/personalized_info_model.py | 19 + .../personalized/personalized_info_view.py | 156 ++ .../personalized/ui_personalized.fbp | 1537 +++++++++++++ .../personalized/ui_personalized.py | 335 +++ .../pcb_fabrication/process/__init__.py | 0 .../process/process_info_model.py | 15 + .../process/process_info_view.py | 307 +++ .../process/ui_process_info.fbp | 1413 ++++++++++++ .../process/ui_process_info.py | 308 +++ .../special_process/__init__.py | 0 .../special_process/special_process_model.py | 15 + .../special_process/special_process_view.py | 104 + .../special_process/ui_special_process.fbp | 1084 ++++++++++ .../special_process/ui_special_process.py | 241 +++ kicad_amf_plugin/plugin/__init__.py | 0 kicad_amf_plugin/plugin/_main.py | 9 + .../plugin/kicad_amf_action_plugin.py | 16 +- kicad_amf_plugin/settings/__init__.py | 0 kicad_amf_plugin/settings/default_express.py | 1 + .../settings/form_value_fitter.py | 43 + kicad_amf_plugin/settings/kicad_setting.py | 31 + kicad_amf_plugin/settings/setting_manager.py | 109 + kicad_amf_plugin/settings/single_plugin.py | 23 + .../settings/supported_layer_count.py | 1 + kicad_amf_plugin/utils/__init__.py | 0 .../utils/combo_box_ignore_wheel.py | 23 + kicad_amf_plugin/utils/constraint.py | 6 + kicad_amf_plugin/utils/form_panel_base.py | 42 + kicad_amf_plugin/utils/number_round.py | 8 + kicad_amf_plugin/utils/platebtn.py | 817 +++++++ kicad_amf_plugin/utils/public_ip/__init__.py | 3 + kicad_amf_plugin/utils/public_ip/_ip.py | 104 + kicad_amf_plugin/utils/request_helper.py | 7 + kicad_amf_plugin/utils/roles.py | 10 + .../utils/validators.py | 118 +- requirements-dev.txt | 4 + test/__init__.py | 5 + test/query_price/hq_pcb.json | 44 + test/query_price/next_pcb_en.json | 42 + test/query_price/next_pcb_jp.json | 42 + test/test_query_price.py | 35 + test/test_utils.py | 10 + urlencodeform.py | 21 - 100 files changed, 13600 insertions(+), 1591 deletions(-) create mode 100644 .github/workflows/kicad-pcm-simple.bak create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 DEVELOPMENT.md create mode 100644 __main__.py delete mode 100644 config.json delete mode 100644 dialog_amf.py delete mode 100644 dialog_amf_base.py delete mode 100644 icon.png create mode 100644 kicad_amf_plugin/__init__.py create mode 100644 kicad_amf_plugin/api/base_request.py create mode 100644 kicad_amf_plugin/gui/__init__.py create mode 100644 kicad_amf_plugin/gui/app_base.py create mode 100644 kicad_amf_plugin/gui/event/__init__.py create mode 100644 kicad_amf_plugin/gui/event/pcb_fabrication_evt_list.py create mode 100644 kicad_amf_plugin/gui/main_frame.py create mode 100644 kicad_amf_plugin/gui/summary/__init__.py create mode 100644 kicad_amf_plugin/gui/summary/bom_price_model.py create mode 100644 kicad_amf_plugin/gui/summary/order_summary_model.py create mode 100644 kicad_amf_plugin/gui/summary/pcb_price_model.py create mode 100644 kicad_amf_plugin/gui/summary/place_order_request.py create mode 100644 kicad_amf_plugin/gui/summary/price_model_base.py create mode 100644 kicad_amf_plugin/gui/summary/price_summary_model.py create mode 100644 kicad_amf_plugin/gui/summary/smt_price_model.py create mode 100644 kicad_amf_plugin/gui/summary/summary_panel.py create mode 100644 kicad_amf_plugin/gui/summary/ui_summary_panel.fbp create mode 100644 kicad_amf_plugin/gui/summary/ui_summary_panel.py rename Huaqiu.png => kicad_amf_plugin/icon/Huaqiu.png (100%) create mode 100644 kicad_amf_plugin/icon/__init__.py create mode 100644 kicad_amf_plugin/icon/cart.png create mode 100644 kicad_amf_plugin/icon/icon.png create mode 100644 kicad_amf_plugin/icon/language.png create mode 100644 kicad_amf_plugin/icon/query.png create mode 100644 kicad_amf_plugin/kicad/board_manager.py rename fabrication.py => kicad_amf_plugin/kicad/fabrication_data_generator.py (67%) rename helpers.py => kicad_amf_plugin/kicad/helpers.py (100%) create mode 100644 kicad_amf_plugin/language/__init__.py create mode 100644 kicad_amf_plugin/language/geni18n.py create mode 100644 kicad_amf_plugin/language/lang_const.py create mode 100644 kicad_amf_plugin/language/lang_setting_pop_menu.py create mode 100644 kicad_amf_plugin/language/locale/ja/LC_MESSAGES/kicad_amf_plugin.po create mode 100644 kicad_amf_plugin/language/locale/zh_CN/LC_MESSAGES/generate_param_mapping.py create mode 100644 kicad_amf_plugin/language/locale/zh_CN/LC_MESSAGES/kicad_amf_plugin.po create mode 100644 kicad_amf_plugin/order/__init__.py create mode 100644 kicad_amf_plugin/order/order_region.py create mode 100644 kicad_amf_plugin/order/supported_region.py create mode 100644 kicad_amf_plugin/pcb_fabrication/__init__.py create mode 100644 kicad_amf_plugin/pcb_fabrication/base/__init__.py create mode 100644 kicad_amf_plugin/pcb_fabrication/base/base_info_model.py create mode 100644 kicad_amf_plugin/pcb_fabrication/base/base_info_view.py create mode 100644 kicad_amf_plugin/pcb_fabrication/base/ui_base_info.fbp create mode 100644 kicad_amf_plugin/pcb_fabrication/base/ui_base_info.py create mode 100644 kicad_amf_plugin/pcb_fabrication/personalized/__init__.py create mode 100644 kicad_amf_plugin/pcb_fabrication/personalized/personalized_info_model.py create mode 100644 kicad_amf_plugin/pcb_fabrication/personalized/personalized_info_view.py create mode 100644 kicad_amf_plugin/pcb_fabrication/personalized/ui_personalized.fbp create mode 100644 kicad_amf_plugin/pcb_fabrication/personalized/ui_personalized.py create mode 100644 kicad_amf_plugin/pcb_fabrication/process/__init__.py create mode 100644 kicad_amf_plugin/pcb_fabrication/process/process_info_model.py create mode 100644 kicad_amf_plugin/pcb_fabrication/process/process_info_view.py create mode 100644 kicad_amf_plugin/pcb_fabrication/process/ui_process_info.fbp create mode 100644 kicad_amf_plugin/pcb_fabrication/process/ui_process_info.py create mode 100644 kicad_amf_plugin/pcb_fabrication/special_process/__init__.py create mode 100644 kicad_amf_plugin/pcb_fabrication/special_process/special_process_model.py create mode 100644 kicad_amf_plugin/pcb_fabrication/special_process/special_process_view.py create mode 100644 kicad_amf_plugin/pcb_fabrication/special_process/ui_special_process.fbp create mode 100644 kicad_amf_plugin/pcb_fabrication/special_process/ui_special_process.py create mode 100644 kicad_amf_plugin/plugin/__init__.py create mode 100644 kicad_amf_plugin/plugin/_main.py rename plugin.py => kicad_amf_plugin/plugin/kicad_amf_action_plugin.py (51%) create mode 100644 kicad_amf_plugin/settings/__init__.py create mode 100644 kicad_amf_plugin/settings/default_express.py create mode 100644 kicad_amf_plugin/settings/form_value_fitter.py create mode 100644 kicad_amf_plugin/settings/kicad_setting.py create mode 100644 kicad_amf_plugin/settings/setting_manager.py create mode 100644 kicad_amf_plugin/settings/single_plugin.py create mode 100644 kicad_amf_plugin/settings/supported_layer_count.py create mode 100644 kicad_amf_plugin/utils/__init__.py create mode 100644 kicad_amf_plugin/utils/combo_box_ignore_wheel.py create mode 100644 kicad_amf_plugin/utils/constraint.py create mode 100644 kicad_amf_plugin/utils/form_panel_base.py create mode 100644 kicad_amf_plugin/utils/number_round.py create mode 100644 kicad_amf_plugin/utils/platebtn.py create mode 100644 kicad_amf_plugin/utils/public_ip/__init__.py create mode 100644 kicad_amf_plugin/utils/public_ip/_ip.py create mode 100644 kicad_amf_plugin/utils/request_helper.py create mode 100644 kicad_amf_plugin/utils/roles.py rename validators.py => kicad_amf_plugin/utils/validators.py (72%) create mode 100644 requirements-dev.txt create mode 100644 test/__init__.py create mode 100644 test/query_price/hq_pcb.json create mode 100644 test/query_price/next_pcb_en.json create mode 100644 test/query_price/next_pcb_jp.json create mode 100644 test/test_query_price.py create mode 100644 test/test_utils.py delete mode 100644 urlencodeform.py diff --git a/.github/workflows/kicad-pcm-simple.bak b/.github/workflows/kicad-pcm-simple.bak new file mode 100644 index 0000000..910f1ac --- /dev/null +++ b/.github/workflows/kicad-pcm-simple.bak @@ -0,0 +1,43 @@ +--- +# This is a workflow to generate the zip file and metadata.json for KiCAD PCM +# https://gitlab.com/kicad/addons/metadata/-/merge_requests/14 + +name: KiCAD PCM packaging +on: # yamllint disable-line rule:truthy + release: + branches: [main] + types: + - published + workflow_dispatch: + +jobs: + create_archive: + runs-on: ubuntu-latest + steps: + - name: Get latest tag + uses: oprypin/find-latest-tag@v1 + with: + repository: Liangtie/kicad-amf-plugin + releases-only: true + id: latest-release + + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Setup env + run: pip3 install -r ./requirements-dev.txt + + - name: Unittest + run: pytest + + - name: Create archive + run: sh ./PCM/create_pcm_archive.sh ${{ steps.latest-release.outputs.tag }} + + - name: Upload zip as asset to release + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ./PCM/KiCAD-PCM-${{ steps.latest-release.outputs.tag }}.zip + asset_name: KiCAD-PCM-${{ steps.latest-release.outputs.tag }}.zip + overwrite: true + tag: ${{ steps.latest-release.outputs.tag }} diff --git a/.github/workflows/kicad-pcm.yml b/.github/workflows/kicad-pcm.yml index 9029375..07fd6a1 100644 --- a/.github/workflows/kicad-pcm.yml +++ b/.github/workflows/kicad-pcm.yml @@ -2,8 +2,8 @@ # This is a workflow to generate the zip file and metadata.json for KiCAD PCM # https://gitlab.com/kicad/addons/metadata/-/merge_requests/14 -name: KiCAD PCM packaging -on: # yamllint disable-line rule:truthy +name: KiCAD PCM packaging and trigger kicad-addone +on: # yamllint disable-line rule:truthy release: branches: [main] types: @@ -24,6 +24,12 @@ jobs: - name: Checkout repo uses: actions/checkout@v3 + - name: Setup env + run: pip3 install -r ./requirements-dev.txt + + - name: Unittest + run: pytest + - name: Create archive run: sh ./PCM/create_pcm_archive.sh ${{ steps.latest-release.outputs.tag }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5ff9e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,151 @@ +led / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +db_build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ +tmp +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py +.idea +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +jlcpcb +corrections +dev + +# vscode ignore +.vscode/ + +# OS cruft +.DS_Store + +PCM/archive diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3854349 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.3.0 + hooks: + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + - repo: https://github.com/psf/black + rev: 22.10.0 + hooks: + - id: black diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 0000000..3e41203 --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,42 @@ +# Building kicad-amf-plugin + +## Preparation + +1. Install wxBuilder + +https://github.com/wxFormBuilder/wxFormBuilder + +2. Install gettext + +https://mlocati.github.io/articles/gettext-iconv-windows.html + +3. Install POedit + +https://poedit.net/download + +## Python env + +Locate the python shipped with KiCad (e.g C:\Program Files\KiCad\7.0\bin\python) + +```sh +cd C:\Program Files\KiCad\7.0\bin +python -m venv .venv +source .venv/scripts/activate + +``` + +## Update translation + +1. Extract po files from py + +```sh +xgettext.exe xxx.py +``` + +2. Edit the po files in Poedit + +## Debug + +The **main**.py is the entry point for debugging + +## Deploy diff --git a/PCM/create_pcm_archive.sh b/PCM/create_pcm_archive.sh index 5b40cd5..4126fd2 100644 --- a/PCM/create_pcm_archive.sh +++ b/PCM/create_pcm_archive.sh @@ -1,46 +1,61 @@ #!/bin/sh -# inspired by https://github.com/Bouni/kicad-jlcpcb-tools/blob/main/PCM/create_pcm_archive.sh +# heavily inspired by https://github.com/4ms/4ms-kicad-lib/blob/master/PCM/make_archive.sh VERSION=$1 +PRJECT_ROOT=`pwd` +PCM_ROOT="$PRJECT_ROOT/PCM" +ACHIEVE_PATH="$PRJECT_ROOT/PCM/archive" +PLUGIN_PATH="$ACHIEVE_PATH/plugins" +RESOURCE_PATH="$ACHIEVE_PATH/resources" +OUTPUT_ZIP_PATH="$PCM_ROOT/KiCAD-PCM-$VERSION.zip" + + echo "Clean up old files" -rm -f PCM/*.zip -rm -rf PCM/archive +rm -f $PCM_ROOT/*.zip +rm -rf $PLUGIN_PATH +TRANSLATION_PATH="$PRJECT_ROOT/kicad_amf_plugin/language/geni18n.py" +echo "Excuting the translation script : $TRANSLATION_PATH" +python3 $TRANSLATION_PATH + echo "Create folder structure for ZIP" -mkdir -p PCM/archive/plugins -mkdir -p PCM/archive/resources +mkdir -p $PLUGIN_PATH +mkdir -p $RESOURCE_PATH + +echo "Copy plugin to destination" -echo "Copy files to destination" -cp VERSION PCM/archive/plugins -cp *.py PCM/archive/plugins -cp *.png PCM/archive/plugins -cp config.json PCM/archive/plugins -cp PCM/icon.png PCM/archive/resources -cp PCM/metadata.template.json PCM/archive/metadata.json +for i in __init__.py __main__.py kicad_amf_plugin + do cp -r $i $PLUGIN_PATH +done -echo "Write version info to file" -echo $VERSION > PCM/archive/plugins/VERSION +for i in `find $PLUGIN_PATH -iname __pycache__` ; do rm -rf $i ; done + +echo "Write version to achieve" +echo $VERSION > $PLUGIN_PATH/VERSION + +echo "Copy resource to destination" +cp $PCM_ROOT/icon.png $RESOURCE_PATH +META_DATA_PATH=$ACHIEVE_PATH/metadata.json +cp $PCM_ROOT/metadata.template.json $META_DATA_PATH echo "Modify archive metadata.json" -sed -i "s/VERSION_HERE/$VERSION/g" PCM/archive/metadata.json -sed -i "s/\"kicad_version\": \"6.0\",/\"kicad_version\": \"6.0\"/g" PCM/archive/metadata.json -sed -i "/SHA256_HERE/d" PCM/archive/metadata.json -sed -i "/DOWNLOAD_SIZE_HERE/d" PCM/archive/metadata.json -sed -i "/DOWNLOAD_URL_HERE/d" PCM/archive/metadata.json -sed -i "/INSTALL_SIZE_HERE/d" PCM/archive/metadata.json +sed -i "s/VERSION_HERE/$VERSION/g" $META_DATA_PATH +sed -i "s/\"kicad_version\": \"6.0\",/\"kicad_version\": \"6.0\"/g" $META_DATA_PATH +sed -i "/SHA256_HERE/d" $META_DATA_PATH +sed -i "/DOWNLOAD_SIZE_HERE/d" $META_DATA_PATH +sed -i "/DOWNLOAD_URL_HERE/d" $META_DATA_PATH +sed -i "/INSTALL_SIZE_HERE/d" $META_DATA_PATH echo "Zip PCM archive" -cd PCM/archive -zip -r ../KiCAD-PCM-$VERSION.zip . -cd ../.. +cd $ACHIEVE_PATH +zip -r $OUTPUT_ZIP_PATH . echo "Gather data for repo rebuild" echo VERSION=$VERSION >> $GITHUB_ENV -echo DOWNLOAD_SHA256=$(shasum --algorithm 256 PCM/KiCAD-PCM-$VERSION.zip | xargs | cut -d' ' -f1) >> $GITHUB_ENV -echo DOWNLOAD_SIZE=$(ls -l PCM/KiCAD-PCM-$VERSION.zip | xargs | cut -d' ' -f5) >> $GITHUB_ENV -echo DOWNLOAD_URL="https:\/\/github.com\/SYSUeric66\/kicad-amf-plugin\/releases\/download\/$VERSION\/KiCAD-PCM-$VERSION.zip" >> $GITHUB_ENV -echo INSTALL_SIZE=$(unzip -l PCM/KiCAD-PCM-$VERSION.zip | tail -1 | xargs | cut -d' ' -f1) >> $GITHUB_ENV - +echo DOWNLOAD_SHA256=$(shasum --algorithm 256 $OUTPUT_ZIP_PATH | xargs | cut -d' ' -f1) >> $GITHUB_ENV +echo DOWNLOAD_SIZE=$(ls -l $OUTPUT_ZIP_PATH | xargs | cut -d' ' -f5) >> $GITHUB_ENV +echo DOWNLOAD_URL="https:\/\/github.com\/Bouni\/kicad-jlcpcb-tools\/releases\/download\/$VERSION\/KiCAD-PCM-$VERSION.zip" >> $GITHUB_ENV +echo INSTALL_SIZE=$(unzip -l $OUTPUT_ZIP_PATH | tail -1 | xargs | cut -d' ' -f1) >> $GITHUB_ENV diff --git a/PCM/metadata.template.json b/PCM/metadata.template.json index b0f454a..be33730 100644 --- a/PCM/metadata.template.json +++ b/PCM/metadata.template.json @@ -1,33 +1,33 @@ -{ - "$schema": "https://go.kicad.org/pcm/schemas/v1", - "name": "KiCAD AMF tools", - "description": "A NextPCB Active Manufacturing addone for KiCAD", - "description_full": "Query price and place order", - "identifier": "com.github.SYSUeric66.kicad-amf-plugin", - "type": "plugin", - "author": { - "name": "SYSUeric66", - "contact": { - "email": "jzzhuang666@gmail.com" - } - }, - "maintainer": { - "name": "SYSUeric66", - "contact": { - "email": "jzzhuang666@gmail.com" - } - }, - "license": "GPL-3.0", - "resources": { - "Github": "https://github.com/SYSUeric66/kicad-amf-plugin" - }, - "versions": [{ - "version": "VERSION_HERE", - "status": "testing", - "kicad_version": "6.0", - "download_sha256": "SHA256_HERE", - "download_size": DOWNLOAD_SIZE_HERE, - "download_url": "DOWNLOAD_URL_HERE", - "install_size": INSTALL_SIZE_HERE - }] +{ + "$schema": "https://go.kicad.org/pcm/schemas/v1", + "name": "KiCAD AMF tools", + "description": "A NextPCB Active Manufacturing addone for KiCAD", + "description_full": "Query price and place order", + "identifier": "com.github.SYSUeric66.kicad-amf-plugin", + "type": "plugin", + "author": { + "name": "SYSUeric66", + "contact": { + "email": "jzzhuang666@gmail.com" + } + }, + "maintainer": { + "name": "SYSUeric66", + "contact": { + "email": "jzzhuang666@gmail.com" + } + }, + "license": "GPL-3.0", + "resources": { + "Github": "https://github.com/SYSUeric66/kicad-amf-plugin" + }, + "versions": [{ + "version": "VERSION_HERE", + "status": "testing", + "kicad_version": "6.0", + "download_sha256": "SHA256_HERE", + "download_size": DOWNLOAD_SIZE_HERE, + "download_url": "DOWNLOAD_URL_HERE", + "install_size": INSTALL_SIZE_HERE + }] } \ No newline at end of file diff --git a/__init__.py b/__init__.py index 8b895fa..0474a1a 100644 --- a/__init__.py +++ b/__init__.py @@ -1,8 +1,15 @@ -from .plugin import Plugin +import sys +import os try: - Plugin().register() + PLUGIN_ROOT = os.path.dirname(os.path.abspath(__file__)) + if PLUGIN_ROOT not in sys.path: + sys.path.append(PLUGIN_ROOT) + from .kicad_amf_plugin.plugin.kicad_amf_action_plugin import KiCadAmfActionPlugin + + KiCadAmfActionPlugin().register() except Exception as e: import logging + logger = logging.getLogger() logger.debug(repr(e)) diff --git a/__main__.py b/__main__.py new file mode 100644 index 0000000..204337b --- /dev/null +++ b/__main__.py @@ -0,0 +1,4 @@ +if __name__ == "__main__": + from kicad_amf_plugin.plugin._main import _main + + _main() diff --git a/config.json b/config.json deleted file mode 100644 index e545641..0000000 --- a/config.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "ui_param": { }, - "rule": { - "silkscreen":{ - "Green":["White"], - "Red":["White"], - "Yellow":["White"], - "Blue":["White"], - "White":["Black"], - "Matte Black":["White"], - "Black":["White"] - }, - "tg":{ - "showNoTG":["1","2"], - "showTG":["4","6","8","10","12","14","16","18","20"], - "1":["None"], - "2":["None"], - "4":["TG130","TG150"], - "6":["TG150","TG170"], - "8":["TG150","TG170"], - "10":["TG170"], - "12":["TG170"], - "14":["TG170"], - "16":["TG170"], - "18":["TG170"], - "20":["TG170"] - }, - "thickness":{ - "default":[14, "1.6", "2.0"], - "1":["0.6","0.8","1.0","1.2","1.6"], - "2":["0.6","0.8","1.0","1.2","1.6"], - "4":["0.6","0.8","1.0","1.2","1.6","2.0","2.5"], - "6":["1.0","1.2","1.6","2.0","2.5"], - "8":["1.2","1.6","2.0","2.5"], - "10":["1.2","1.6","2.0","2.5"], - "12":["1.6","2.0","2.5"], - "14":["1.6","2.0","2.5","3.0"], - "16":["2.0","2.5","3.0"], - "18":["2.0","2.5","3.0","3.2"], - "20":["2.0","2.5","3.0","3.2"] - } - } -} \ No newline at end of file diff --git a/dialog_amf.py b/dialog_amf.py deleted file mode 100644 index a10adc2..0000000 --- a/dialog_amf.py +++ /dev/null @@ -1,674 +0,0 @@ -import os -import wx -import wx.lib.masked as masked -import urllib.request -import urllib.parse -import json -import re -from .urlencodeform import UrlEncodeForm -from collections import defaultdict -import locale -from datetime import datetime -import requests -import webbrowser - -import pcbnew -from . import dialog_amf_base -from .fabrication import Fabrication -import gettext -_ = gettext.gettext - -from. import validators - -# Implementing AmfDialogBase -class AmfDialog( dialog_amf_base.AmfDialogBase ): - def __init__( self, parent ): - dialog_amf_base.AmfDialogBase.__init__( self, parent ) - - self.board = pcbnew.GetBoard() - - boardWidth = pcbnew.ToMM(self.board.GetBoardEdgesBoundingBox().GetWidth()) - boardHeight = pcbnew.ToMM(self.board.GetBoardEdgesBoundingBox().GetHeight()) - designSettings = self.board.GetDesignSettings() - boardThickness = designSettings.GetBoardThickness() - minTraceWidth = designSettings.m_TrackMinWidth - minTraceClearance = designSettings.m_MinClearance - minHoleSize = designSettings.m_MinThroughDrill - layerCount = self.board.GetCopperLayerCount() - self.load_config_file() - self.m_layerCountCtrl.SetSelection(self.m_layerCountCtrl.FindString(str(layerCount))) - self.OnThicknessChangebyLayer(None) - self.m_layerCountCtrl.Enabled = False - #self.m_placeOrderButton.Enabled = False - self.m_sizeXCtrl.SetValue(str(boardWidth)) - self.m_sizeXCtrl.SetEditable(False) - self.m_sizeYCtrl.SetValue(str(boardHeight)) - self.m_sizeYCtrl.SetEditable(False) - # self.m_asmSizeXCtrl.SetValue(str(boardWidth)) - # self.m_asmSizeXCtrl.SetEditable(False) - # self.m_asmSizeYCtrl.SetValue(str(boardHeight)) - # self.m_asmSizeYCtrl.SetEditable(False) - self.SetBoardThickness(pcbnew.ToMM(boardThickness)) - self.SetMinTrace(pcbnew.ToMils(minTraceWidth), pcbnew.ToMils(minTraceClearance)) - self.SetMinHole(pcbnew.ToMM(minHoleSize)) - self.m_pcbPackaingCtrl.SetSelection(0) - self.OnPcbPackagingChanged(None) - self.m_marginModeCtrl.SetSelection(0) - self.OnMarginModeChanged(None) - self.m_surfaceProcessCtrl.SetSelection(0) - self.OnSurfaceProcessChanged(None) - self.numericValidator = validators.NumericTextCtrlValidator() - self.m_panelizeXCtrl.SetValidator(self.numericValidator) - self.m_panelizeYCtrl.SetValidator(self.numericValidator) - self.floatValidator = validators.FloatTextCtrlValidator() - self.m_marginValueCtrl.SetValidator(self.floatValidator) - if layerCount == 2: - self.m_innerCopperThicknessLabel.Enabled = False - self.m_innerCopperThicknessCtrl.Enabled = False - self.m_blindViaLabel.Enabled = False - self.m_blindViaCtrl.Enabled = False - else: - self.m_innerCopperThicknessLabel.Enabled = True - self.m_innerCopperThicknessCtrl.Enabled = True - self.m_blindViaLabel.Enabled = True - self.m_blindViaCtrl.Enabled = True - self.m_template.SetSelection(0) - self.OnTemplateChanged(None) - self.OnPcbQuantityChanged(None) - self.OnHDIChanged(None) - #self.OnMaskColorChange(None) - self.fabrication = None - # self.SetSMTInfo() - # self.SetDIPInfo() - - # Handlers for AmfDialogBase events. - def OnTemplateChanged( self, event ): - if self.m_template.GetSelection() == 0 and self.m_notebook.PageCount > 1: - self.m_notebook.RemovePage(1) - elif self.m_template.GetSelection() == 1 and self.m_notebook.PageCount == 1: - self.m_notebook.AddPage( self.m_panelAsm, _(u"PCB Assembly"), True ) - - def OnPcbPackagingChanged(self, event): - if self.m_pcbPackaingCtrl.GetSelection() == 0: - self.m_sizeLabel.SetLabel('Size (single)') - self.m_quantityLbel.SetLabel('Qty(single)') - self.m_quantityUnit.SetLabel('Pcs') - self.m_panelizeRuleLbel.Enabled = False - self.m_panelizeXLabel.Enabled = False - self.m_panelizeXCtrl.Enabled = False - self.m_panelizeXUnit.Enabled = False - self.m_panelizeYLabel.Enabled = False - self.m_panelizeYCtrl.Enabled = False - self.m_panelizeYUnit.Enabled = False - self.m_marginLabel.Enabled = True - self.m_marginModeCtrl.Enabled = True - self.OnMarginModeChanged(None) - else: - self.m_sizeLabel.SetLabel('Size (set)') - self.m_quantityLbel.SetLabel('Qty(Set)') - self.m_quantityUnit.SetLabel('Set') - self.m_panelizeRuleLbel.Enabled = True - self.m_panelizeXLabel.Enabled = True - self.m_panelizeXCtrl.Enabled = True - self.m_panelizeXCtrl.SetEditable(True) - self.m_panelizeXUnit.Enabled = True - self.m_panelizeYLabel.Enabled = True - self.m_panelizeYCtrl.Enabled = True - self.m_panelizeYCtrl.SetEditable(True) - self.m_panelizeYUnit.Enabled = True - self.m_marginLabel.Enabled = True - self.m_marginModeCtrl.Enabled = True - self.OnMarginModeChanged(None) - - def OnMarginModeChanged( self, event ): - if self.m_marginModeCtrl.GetSelection() == 0: - self.m_marginValueCtrl.Enabled = False - self.m_marginValueUnit.Enabled = False - else: - self.m_marginValueCtrl.Enabled = True - self.m_marginValueCtrl.SetEditable(True) - self.m_marginValueUnit.Enabled = True - - def OnSurfaceProcessChanged( self, event ): - if self.m_surfaceProcessCtrl.GetSelection() == 2: - self.m_goldThicknessLabel.Enabled = True - self.m_goldThicknessCtrl.Enabled = True - else: - self.m_goldThicknessLabel.Enabled = False - self.m_goldThicknessCtrl.Enabled = False - - def OnPanelizeXChanged( self, event ): - if not self.m_panelizeXCtrl.Validate(): - wx.MessageBox("Panel Type X value isn't valid. Please input valid value.", "Error", wx.OK | wx.ICON_ERROR) - return - # self.m_asmQuantityCtrl.SetValue(str(self.GetPcbQuantity())) - - def OnPanelizeYChanged( self, event ): - if not self.m_panelizeYCtrl.Validate(): - wx.MessageBox("Panel Type Y value isn't valid. Please input valid value.", "Error", wx.OK | wx.ICON_ERROR) - return - # self.m_asmQuantityCtrl.SetValue(str(self.GetPcbQuantity())) - - def OnPcbQuantityChanged( self, event ): - # self.m_asmQuantityCtrl.SetValue(str(self.GetPcbQuantity())) - return - - def OnHDIChanged( self, event ): - if self.m_blindViaCtrl.GetSelection() == 1: - self.m_hdiStructureLabel.Enabled = True - self.m_hdiStructureCtrl.Enabled = True - else: - self.m_hdiStructureLabel.Enabled = False - self.m_hdiStructureCtrl.Enabled = False - - def OnReportChanged( self, event ): - if self.m_deliveryReportCtrl.GetSelection() == 0 and self.m_analysisReportCtrl.GetSelection() == 0: - self.m_reportFormatLabel.Enabled = False - self.m_reportFormatCtrl.Enabled = False - else: - self.m_reportFormatLabel.Enabled = True - self.m_reportFormatCtrl.Enabled = True - - def OnMaskColorChange(self, event): - self.m_silkscreenColorCtrl.Clear() - mask_color = self.m_solderColorCtrl.GetString(self.m_solderColorCtrl.GetSelection()) - val_list = self.config_json["rule"]["silkscreen"][mask_color] - self.m_silkscreenColorCtrl.Append(val_list) - self.m_silkscreenColorCtrl.SetSelection( 0 ) - - def OnThicknessChangebyLayer(self, event): - layer = self.m_layerCountCtrl.GetString(self.m_layerCountCtrl.GetSelection()) - self.m_boardThicknessCtrl.Clear() - val_list = self.config_json["rule"]["thickness"][layer] - self.m_boardThicknessCtrl.Append(val_list) - - - def load_config_file(self): - """Load config from config.json""" - if not os.path.isfile(os.path.join(os.path.dirname(__file__), "config.json")): - wx.MessageBox("Load config json file failed.Please reinstall plugin.", "Error", wx.OK | wx.ICON_ERROR) - return - with open(os.path.join(os.path.dirname(__file__), "config.json")) as j: - self.config_json = json.load(j) - - def init_fabrication(self): - """Initialize the fabrication""" - if not self.fabrication: - self.fabrication = Fabrication(self) - - # def OnDoDIPChanged( self, event ): - # if self.m_doDIPCtrl.GetSelection() == 0: - # self.m_dipComponentKindsCtrl.SetEditable(False) - # self.m_dipPadCountCtrl.SetEditable(False) - # else: - # self.m_dipComponentKindsCtrl.SetEditable(True) - # self.m_dipPadCountCtrl.SetEditable(True) - - def GetInfoFromSetting(self): - if self.m_pcbPackaingCtrl.GetSelection() == 1 or self.m_pcbPackaingCtrl.GetSelection() == 2: - if not self.m_panelizeXCtrl.Validate(): - wx.MessageBox("Panel Type X value isn't valid. Please input valid value.", "Error", wx.OK | wx.ICON_ERROR) - return - if not self.m_panelizeYCtrl.Validate(): - wx.MessageBox("Panel Type Y value isn't valid. Please input valid value.", "Error", wx.OK | wx.ICON_ERROR) - return - if self.m_marginValueCtrl.Enabled: - if not self.m_marginValueCtrl.Validate(): - wx.MessageBox("Break-away Rail value isn't valid. Please input valid value.", "Error", wx.OK | wx.ICON_ERROR) - return - - form = UrlEncodeForm() - form.add_field('service', 'pcb') - form.add_field('plate_type', 'Fr-4') #self.m_baseMaterialCtrl.GetString(self.m_baseMaterialCtrl.GetSelection())) - layercount = int(self.m_layerCountCtrl.GetString(self.m_layerCountCtrl.GetSelection())) - form.add_field('blayer', str(layercount)) - form.add_field('board_tg', 'TG130') #TODO - if self.m_pcbPackaingCtrl.GetSelection() == 0: - form.add_field('units', '1') - elif self.m_pcbPackaingCtrl.GetSelection() == 1: - form.add_field('units', '3') - else: - form.add_field('units', '2') - form.add_field('blength', str(round(self.GetPcbLength() / 10, 2))) - form.add_field('bwidth', str(round(self.GetPcbWidth() / 10, 2))) - if self.m_pcbPackaingCtrl.GetSelection() == 1 or self.m_pcbPackaingCtrl.GetSelection() == 2: - form.add_field('layoutx', self.m_panelizeXCtrl.GetValue()) - form.add_field('layouty', self.m_panelizeYCtrl.GetValue()) - form.add_field('bcount', self.m_quantityCtrl.GetString(self.m_quantityCtrl.GetSelection())) - form.add_field('sidedirection', self.GetMarginMode()) - if self.m_marginModeCtrl.GetSelection() != 0: - form.add_field('sidewidth', self.m_marginValueCtrl.GetValue()) - form.add_field('bheight', self.m_boardThicknessCtrl.GetString(self.m_boardThicknessCtrl.GetSelection())) - form.add_field('copper', str(self.GetOuterCopperThickness())) - if layercount > 2: - form.add_field('insidecopper', str(self.GetInnerCopperThickness())) - if self.m_stackupCtrl.GetSelection() == 0: - form.add_field('pressing', '') - else: - form.add_field('pressing', 'Customer Specified Stack up') - else: - form.add_field('insidecopper', '0') - form.add_field('pressing', '') - form.add_field('lineweight', str(self.GetMinTraceWidthAndClearance())) - form.add_field('vias', str(self.GetMinHoleSize())) - form.add_field('color', self.m_solderColorCtrl.GetString(self.m_solderColorCtrl.GetSelection())) - form.add_field('charcolor', self.m_silkscreenColorCtrl.GetString(self.m_silkscreenColorCtrl.GetSelection())) - form.add_field('cover', self.m_solderCoverCtrl.GetString(self.m_solderCoverCtrl.GetSelection())) - form.add_field('spray', self.m_surfaceProcessCtrl.GetString(self.m_surfaceProcessCtrl.GetSelection())) - if self.m_surfaceProcessCtrl.GetSelection() == 2: - form.add_field('cjh', str(self.GetCJH())) - form.add_field('impendance', str(self.m_impedanceCtrl.GetSelection())) - form.add_field('bankong', str(self.m_halfHoleCtrl.GetSelection())) - form.add_field('blind', self.GetBlindValue()) - form.add_field('via_in_pad', self.GetViaInPad()) - form.add_field('test', self.GetTestMethod()) - form.add_field('shipment_report', str(self.m_deliveryReportCtrl.GetSelection())) - form.add_field('slice_report', str(self.m_analysisReportCtrl.GetSelection())) - form.add_field('report_type', str(self.GetReportType())) - form.add_field('beveledge', str(self.m_goldFingerCtrl.GetSelection())) - form.add_field('review_file', self.GetReviewFile()) - form.add_field('has_period', self.GetHasPeriod()) - if self.m_ulMarkCtrl.GetSelection() != 0: - form.add_field('period_format', self.GetPeriodFormat()) - form.add_field('film_report', str(self.m_filmCtrl.GetSelection())) - form.add_field('pcb_note', self.m_specialRequestsCtrl.GetValue()) - - form.add_field('region_id', '211') #TODO - form.add_field('country', '211') #TODO - form.add_field('express', '31') #TODO - # form.add_field('express', '0') - # form.add_field('expresstime', '3-5%20days') - # form.add_field('calc_type', '0') - # form.add_field('deltime', '72%20hours') - # form.add_field('activity_code', '') - # form.add_field('active', '') - # form.add_field('history_pcb_order_sn', '0') - # form.add_field('pbnum', '1') - # form.add_field('isgerber', '1') - # form.add_field('thermalc', '') - # form.add_field('rogers', '') - # form.add_field('holedensity', '0') - # form.add_field('cjarea', '0') - # form.add_field('testpoint', '0') - # form.add_field('zknum', '0') - # form.add_field('baobian', '') - # form.add_field('pcscount', '20') - # form.add_field('pcb_po_number', '') - # form.add_field('pcb_note', '') - # form.add_field('review_file', '0') - # form.add_field('cross_board', '1') - # form.add_field('user_stamp', '3') - # form.add_field('paper', '1') - # form.add_field('file_standard', '2') - # form.add_field('acceptance', '1') - - self.form = form - - def OnUpdatePrice( self, event ): - self.GetInfoFromSetting() - self.form.convert_to_dict() - - self.form.make_result() - url = 'https://www.nextpcb.com/ajax/valuation' - req1 = urllib.request.Request(url, data=self.form.form_data) - fp = urllib.request.urlopen(req1) - data = fp.read() - self.m_priceDetailsViewListCtrl.DeleteAllItems() - encoding = fp.info().get_content_charset('utf-8') - quote = json.loads(data.decode(encoding)) - # text_file = open("d:\QuotePCB.txt", "w") - # n = text_file.write(data.decode(encoding)) - # text_file.close() - - if quote['code'] != 200: - wx.MessageBox(quote['msg'], "Error", wx.OK | wx.ICON_ERROR) - return - - data = ['Fabrication:', ''] - self.m_priceDetailsViewListCtrl.AppendItem(data) - - if 'discount' in quote['data']: - value = '$' + str(quote['data']['pcb_total_original']) - data = ['PCB Price', value] - self.m_priceDetailsViewListCtrl.AppendItem(data) - - value = '$' + str(quote['data']['discount']['pcb']['discount_amount']) - data =[quote['data']['discount']['pcb']['title'], value] - self.m_priceDetailsViewListCtrl.AppendItem(data) - else: - value = '$' + str(quote['data']['pcb_total']) - data = ['PCB Price', value] - self.m_priceDetailsViewListCtrl.AppendItem(data) - - #freight_value = quote['data']['freight'] - #data = ['Shipping Cost', value] - #self.m_priceDetailsViewListCtrl.AppendItem(data) - #wx.MessageBox(f"freight_value:{freight_value}.total{quote['data']['total']}", "Help", style=wx.ICON_INFORMATION) - - value = '$' + str(round(float(quote['data']['total']) - float(quote['data']['freight']), 2)) - data = ['Total', value] - self.m_priceDetailsViewListCtrl.AppendItem(data) - - value = quote['data']['delivery_date'] - data = ['Delivery Date', value] - self.m_priceDetailsViewListCtrl.AppendItem(data) - - locale.setlocale(locale.LC_ALL, '') - deldate = str(quote['data']['delivery_date'][0:10]) - fabDueDate = str((datetime.strptime(deldate, '%Y/%m/%d') - datetime.now()).days) - - value = str(round(quote['data']['weight'], 4)) + 'kg' - data = ['Weight', value] - self.m_priceDetailsViewListCtrl.AppendItem(data) - - value = str(round(quote['data']['list']['pcb']['area'] / 10000, 4)) + '㎡' - data = ['Area', value] - self.m_priceDetailsViewListCtrl.AppendItem(data) - - data = ['', ''] - self.m_priceDetailsViewListCtrl.AppendItem(data) - - totalPrice = round(float(quote['data']['total']) - float(quote['data']['freight']), 2) - - value = '$' + str(totalPrice) - data = ['Total Price', value] - self.m_priceDetailsViewListCtrl.AppendItem(data) - - self.m_amountCtrl.SetLabel(str(self.GetPcbQuantity())) - self.m_priceCtrl.SetLabel(str(totalPrice)) - if self.m_template.GetSelection() == 0: - self.m_dueDateCtrl.SetLabel(str(self.GetDaysFromString(fabDueDate))) - else: - self.m_dueDateCtrl.SetLabel('-') - - - def GetImagePath( self, bitmap_path ): - return os.path.join(os.path.dirname(__file__), bitmap_path) - - def GetPcbQuantity( self ): - n = int(self.m_quantityCtrl.GetString(self.m_quantityCtrl.GetSelection())) - if self.m_pcbPackaingCtrl.GetSelection() == 1 or self.m_pcbPackaingCtrl.GetSelection() == 2: - return n * int(self.m_panelizeXCtrl.GetValue()) * int(self.m_panelizeYCtrl.GetValue()) - else: - return n - - def GetPcbLength( self ): - if self.m_pcbPackaingCtrl.GetSelection() == 0: - if self.m_marginModeCtrl.GetSelection() == 1 or self.m_marginModeCtrl.GetSelection() == 3: - return float(self.m_sizeXCtrl.GetValue()) + float(self.m_marginValueCtrl.GetValue()) * 2 - else: - return float(self.m_sizeXCtrl.GetValue()) - else: - if self.m_marginModeCtrl.GetSelection() == 1 or self.m_marginModeCtrl.GetSelection() == 3: - return float(self.m_sizeXCtrl.GetValue()) * int(self.m_panelizeXCtrl.GetValue()) + float(self.m_marginValueCtrl.GetValue()) * 2 - else: - return float(self.m_sizeXCtrl.GetValue()) * int(self.m_panelizeXCtrl.GetValue()) - - def GetPcbWidth( self ): - if self.m_pcbPackaingCtrl.GetSelection() == 0: - if self.m_marginModeCtrl.GetSelection() == 1 or self.m_marginModeCtrl.GetSelection() == 3: - return float(self.m_sizeYCtrl.GetValue()) + float(self.m_marginValueCtrl.GetValue()) * 2 - else: - return float(self.m_sizeYCtrl.GetValue()) - else: - if self.m_marginModeCtrl.GetSelection() == 1 or self.m_marginModeCtrl.GetSelection() == 3: - return float(self.m_sizeYCtrl.GetValue()) * int(self.m_panelizeYCtrl.GetValue()) + float(self.m_marginValueCtrl.GetValue()) * 2 - else: - return float(self.m_sizeYCtrl.GetValue()) * int(self.m_panelizeYCtrl.GetValue()) - - def GetMarginMode( self ): - if self.m_marginModeCtrl.GetSelection() == 0: - return "N/A" - elif self.m_marginModeCtrl.GetSelection() == 1: - return "X" - elif self.m_marginModeCtrl.GetSelection() == 2: - return "Y" - elif self.m_marginModeCtrl.GetSelection() == 3: - return "XY" - else: - return "N/A" - - def GetOuterCopperThickness( self ): - if self.m_outerCopperThicknessCtrl.GetSelection() == 0: - return 1 - elif self.m_outerCopperThicknessCtrl.GetSelection() == 1: - return 2 - - def GetInnerCopperThickness( self ): - if self.m_innerCopperThicknessCtrl.GetSelection() == 0: - return 0.5 - if self.m_innerCopperThicknessCtrl.GetSelection() == 1: - return 1 - elif self.m_innerCopperThicknessCtrl.GetSelection() == 2: - return 2 - - def GetMinTraceWidthAndClearance( self ): - if self.m_minTraceWidthClearanceCtrl.GetSelection() == 0: - return 10 - elif self.m_minTraceWidthClearanceCtrl.GetSelection() == 1: - return 8 - elif self.m_minTraceWidthClearanceCtrl.GetSelection() == 2: - return 6 - elif self.m_minTraceWidthClearanceCtrl.GetSelection() == 3: - return 5 - elif self.m_minTraceWidthClearanceCtrl.GetSelection() == 4: - return 4 - elif self.m_minTraceWidthClearanceCtrl.GetSelection() == 5: - return 3.5 - else: - return 10 - - def GetMinHoleSize( self ): - if self.m_minHoleSizeCtrl.GetSelection() == 0: - return 0.3 - elif self.m_minHoleSizeCtrl.GetSelection() == 1: - return 0.25 - elif self.m_minHoleSizeCtrl.GetSelection() == 2: - return 0.2 - elif self.m_minHoleSizeCtrl.GetSelection() == 3: - return 0.15 - else: - return 0.3 - - def GetCJH( self ): - if self.m_goldThicknessCtrl.GetSelection() == 0: - return 1 - elif self.m_goldThicknessCtrl.GetSelection() == 1: - return 2 - elif self.m_goldThicknessCtrl.GetSelection() == 2: - return 3 - else: - return 1 - - def GetBlindValue( self ): - if self.m_blindViaCtrl.GetSelection() == 0: - return "0" - elif self.m_hdiStructureCtrl.GetSelection() == 0: - return "1" - elif self.m_hdiStructureCtrl.GetSelection() == 1: - return "2" - elif self.m_hdiStructureCtrl.GetSelection() == 2: - return "3" - - def GetTestMethod( self ): - if self.m_testMethodCtrl.GetSelection() == 0: - return 'Sample Test Free' - elif self.m_testMethodCtrl.GetSelection() == 1: - return 'Batch Flying Probe Test' - elif self.m_testMethodCtrl.GetSelection() == 2: - return 'Batch Fixture Test' - - def GetReviewFile( self ): - if self.m_approveWorkingGerberCtrl.GetSelection() == 0: - return '0' - else: - return '2' - - def GetHasPeriod( self ): - if self.m_ulMarkCtrl.GetSelection() == 0: - return '2' - else: - return '6' - - def GetPeriodFormat( self ): - if self.m_ulMarkCtrl.GetSelection() == 1: - return '2' - elif self.m_ulMarkCtrl.GetSelection() == 2: - return '1' - - def GetViaInPad( self ): - if self.m_padHoleCtrl.GetSelection() == 0: - return 'N/A' - else: - return 'Have' - - def GetReportType( self ): - if self.m_deliveryReportCtrl.GetSelection() == 0 and self.m_analysisReportCtrl.GetSelection() == 0: - return 0 - elif self.m_reportFormatCtrl.GetSelection() == 0: - return 2 - elif self.m_reportFormatCtrl.GetSelection() == 1: - return 1 - - def GetDaysFromString( self, str ): - numbers = re.findall('\d+', str) - if '小时' in str: - return int(int(numbers[0]) / 24) - else: - return int(numbers[0]) - - def SetBoardThickness( self, thickness ): - for i in range(self.m_boardThicknessCtrl.GetCount()): - if thickness <= float(self.m_boardThicknessCtrl.GetString(i)): - self.m_boardThicknessCtrl.SetSelection(i) - break - - def SetMinTrace( self, minTraceWidth, minTraceClearance ): - if minTraceWidth == 0 and minTraceClearance == 0: - minTrace = 6 - elif minTraceWidth == 0: - minTrace = minTraceClearance - elif minTraceClearance == 0: - minTrace = minTraceWidth - else: - minTrace = min(minTraceWidth, minTraceClearance) - - if minTrace == 0: - minTrace = 6 - self.m_minTraceWidthClearanceCtrl.SetSelection(2) - elif minTrace >= 10: - minTrace = 10 - self.m_minTraceWidthClearanceCtrl.SetSelection(0) - elif minTrace >= 8: - minTrace = 8 - self.m_minTraceWidthClearanceCtrl.SetSelection(1) - elif minTrace >= 6: - minTrace = 6 - self.m_minTraceWidthClearanceCtrl.SetSelection(2) - elif minTrace >= 5: - minTrace = 5 - self.m_minTraceWidthClearanceCtrl.SetSelection(3) - elif minTrace >= 4: - minTrace = 4 - self.m_minTraceWidthClearanceCtrl.SetSelection(4) - else: - minTrace = 3.5 - self.m_minTraceWidthClearanceCtrl.SetSelection(5) - - def SetMinHole( self, minHoleSize ): - if minHoleSize == 0: - minHoleSize = 0.3 - self.m_minHoleSizeCtrl.SetSelection(0) - elif minHoleSize >= 0.3: - minHoleSize = 0.3 - self.m_minHoleSizeCtrl.SetSelection(0) - elif minHoleSize >= 0.25: - minHoleSize = 0.25 - self.m_minHoleSizeCtrl.SetSelection(1) - elif minHoleSize >= 0.2: - minHoleSize = 0.2 - self.m_minHoleSizeCtrl.SetSelection(2) - else: - minHoleSize = 0.15 - self.m_minHoleSizeCtrl.SetSelection(3) - - def SetSMTInfo( self ): - smtPadCount = 0 - topSMT = False - bottomSMT = False - footprints = list(self.board.GetFootprints()) - footprints.sort(key=lambda x: x.GetReference()) - footprintReferecens = defaultdict(int) - for i, footprint in enumerate(footprints): - if footprint.GetAttributes() & pcbnew.FP_SMD == pcbnew.FP_SMD: - # if not footprint.HasThroughHolePads(): - if footprint.GetLayer() == pcbnew.F_Cu: - topSMT = True - elif footprint.GetLayer() == pcbnew.B_Cu: - bottomSMT = True - footprintReferecens[str(footprint.GetFPID().GetLibItemName()) + '&&&&' + footprint.GetValue().upper()] += 1 - smtPadCount += len(footprint.Pads()) - # pads = list(footprint.Pads()) - # for pad in pads: - # if pad.ShowPadAttr() == 'SMD': - # if pad.IsOnLayer(pcbnew.F_Cu) or pad.IsOnLayer(pcbnew.B_Cu): - # smtPadCount = smtPadCount + 1 - - # self.m_smtSingleDouleSideCtrl.SetSelection(1 if topSMT and bottomSMT else 0) - # self.m_smtComponentKindsCtrl.SetValue(str(len(footprintReferecens.items()))) - # self.m_smtPadCountCtrl.SetValue(str(smtPadCount)) - - def generate_fabrication_data(self, e): - """Generate fabrication data.""" - self.fabrication.fill_zones() - self.fabrication.generate_geber(None) - self.fabrication.generate_excellon() - self.fabrication.zip_gerber_excellon() - - - def OnPlaceOrder(self, e): - self.m_placeOrderButton.Enabled = False - try: - wx.BeginBusyCursor() - self.init_fabrication() - self.generate_fabrication_data(e) - self.place_order_request() - finally: - wx.EndBusyCursor() - self.m_placeOrderButton.Enabled = True - - def place_order_request(self): - zipname = f"GERBER-{self.fabrication.filename.split('.')[0]}.zip" - zipfile = os.path.join(self.fabrication.outputdir, zipname) - files = {'file': open(zipfile, 'rb')} - upload_url = "https://www.nextpcb.com/Upfile/kiCadUpFile" - self.GetInfoFromSetting() - self.form.add_field('type', 'pcbfile') - self.form.convert_to_dict() - self.form.form_dict['blength'] = str(round(self.GetPcbLength(), 2)) - self.form.form_dict['bwidth'] = str(round(self.GetPcbWidth(), 2)) - rsp = requests.post( - upload_url, - files=files, - data=self.form.form_dict - ) - urls = json.loads(rsp.content) - uat_url = str(urls['redirect']) - webbrowser.open(uat_url) - - # def SetDIPInfo( self ): - # dipPadCount = 0 - # footprints = list(self.board.GetFootprints()) - # footprints.sort(key=lambda x: x.GetReference()) - # footprintReferecens = defaultdict(int) - # for i, footprint in enumerate(footprints): - # if footprint.GetAttributes() & pcbnew.FP_THROUGH_HOLE == pcbnew.FP_THROUGH_HOLE: - # # if footprint.HasThroughHolePads(): - # footprintReferecens[str(footprint.GetFPID().GetLibItemName()) + '&&&&' + footprint.GetValue().upper()] += 1 - # dipPadCount += len(footprint.Pads()) - - # self.m_doDIPCtrl.SetSelection(1 if dipPadCount > 0 else 0) - # self.m_dipComponentKindsCtrl.SetValue(str(len(footprintReferecens.items()))) - # self.m_dipPadCountCtrl.SetValue(str(dipPadCount)) - # self.OnDoDIPChanged(None) - diff --git a/dialog_amf_base.py b/dialog_amf_base.py deleted file mode 100644 index 0c630f8..0000000 --- a/dialog_amf_base.py +++ /dev/null @@ -1,659 +0,0 @@ -# -*- coding: utf-8 -*- - -########################################################################### -## Python code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) -## http://www.wxformbuilder.org/ -## -## PLEASE DO *NOT* EDIT THIS FILE! -########################################################################### - -import wx -import wx.xrc -import wx.dataview - -import gettext -_ = gettext.gettext - -########################################################################### -## Class AmfDialogBase -########################################################################### - -class AmfDialogBase ( wx.Dialog ): - - def __init__( self, parent ): - wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = _(u"HQ NextPCB Active Manufacturing"), pos = wx.DefaultPosition, size = wx.Size( 800, 700 ), style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) - - self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) - - m_mainSizer = wx.BoxSizer( wx.VERTICAL ) - - m_topSizer = wx.BoxSizer( wx.HORIZONTAL ) - - m_topLeftSizer = wx.BoxSizer( wx.VERTICAL ) - - m_templateChoices = [ _(u"PCB Fabrication") ] - self.m_template = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.Size( 300,-1 ), m_templateChoices, 0 ) - self.m_template.SetSelection( 0 ) - m_topLeftSizer.Add( self.m_template, 0, wx.EXPAND|wx.TOP, 5 ) - - self.m_notebook = wx.Notebook( self, wx.ID_ANY, wx.DefaultPosition, wx.Size( 300,-1 ), 0 ) - self.m_panelFab = wx.ScrolledWindow( self.m_notebook, wx.ID_ANY, wx.DefaultPosition, wx.Size( 300,-1 ), wx.HSCROLL|wx.VSCROLL ) - self.m_panelFab.SetScrollRate( 10, 10 ) - m_panelFabSizer = wx.BoxSizer( wx.VERTICAL ) - - m_fabBaseInfo = wx.StaticBoxSizer( wx.StaticBox( self.m_panelFab, wx.ID_ANY, _(u"Base Info") ), wx.VERTICAL ) - - m_fabBaseInfoSizer = wx.GridBagSizer( 0, 0 ) - m_fabBaseInfoSizer.SetFlexibleDirection( wx.BOTH ) - m_fabBaseInfoSizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) - - self.m_baseMaterialLabel = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"Material Type:"), wx.DefaultPosition, wx.Size( -1,-1 ), 0 ) - self.m_baseMaterialLabel.Wrap( -1 ) - - self.m_baseMaterialLabel.SetToolTip( _(u"Non-conductive base material") ) - - m_fabBaseInfoSizer.Add( self.m_baseMaterialLabel, wx.GBPosition( 0, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_baseMaterialCtrlChoices = [ _(u"FR-4") ] - self.m_baseMaterialCtrl = wx.Choice( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_baseMaterialCtrlChoices, 0 ) - self.m_baseMaterialCtrl.SetSelection( 0 ) - m_fabBaseInfoSizer.Add( self.m_baseMaterialCtrl, wx.GBPosition( 0, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_layerCountLabel = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"Layer Count:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_layerCountLabel.Wrap( -1 ) - - self.m_layerCountLabel.SetToolTip( _(u"Number of copper layers") ) - - m_fabBaseInfoSizer.Add( self.m_layerCountLabel, wx.GBPosition( 1, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_layerCountCtrlChoices = [ _(u"1"), _(u"2"), _(u"4"), _(u"6"), _(u"8"), _(u"10"), _(u"12"), _(u"14"), _(u"16"), _(u"18"), _(u"20") ] - self.m_layerCountCtrl = wx.Choice( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_layerCountCtrlChoices, 0 ) - self.m_layerCountCtrl.SetSelection( 1 ) - m_fabBaseInfoSizer.Add( self.m_layerCountCtrl, wx.GBPosition( 1, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_pcbPackaingLabel = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"Board Type:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_pcbPackaingLabel.Wrap( -1 ) - - self.m_pcbPackaingLabel.SetToolTip( _(u"The finished PCB are by single or by panel") ) - - m_fabBaseInfoSizer.Add( self.m_pcbPackaingLabel, wx.GBPosition( 2, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_pcbPackaingCtrlChoices = [ _(u"Single Piece"), _(u"Panel by Customer"), _(u"Panel by NextPCB") ] - self.m_pcbPackaingCtrl = wx.Choice( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_pcbPackaingCtrlChoices, 0 ) - self.m_pcbPackaingCtrl.SetSelection( 0 ) - m_fabBaseInfoSizer.Add( self.m_pcbPackaingCtrl, wx.GBPosition( 2, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_panelizeRuleLbel = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"Panel Type:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_panelizeRuleLbel.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_panelizeRuleLbel, wx.GBPosition( 3, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - self.m_panelizeXLabel = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"X:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_panelizeXLabel.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_panelizeXLabel, wx.GBPosition( 4, 0 ), wx.GBSpan( 1, 1 ), wx.ALIGN_RIGHT|wx.ALL, 5 ) - - self.m_panelizeXCtrl = wx.TextCtrl( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 100,-1 ), wx.TE_READONLY ) - self.m_panelizeXCtrl.SetMaxLength( 0 ) - m_fabBaseInfoSizer.Add( self.m_panelizeXCtrl, wx.GBPosition( 4, 1 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_panelizeXUnit = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"pcs"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_panelizeXUnit.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_panelizeXUnit, wx.GBPosition( 4, 2 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - self.m_panelizeYCtrl = wx.TextCtrl( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 100,-1 ), wx.TE_READONLY ) - self.m_panelizeYCtrl.SetMaxLength( 0 ) - m_fabBaseInfoSizer.Add( self.m_panelizeYCtrl, wx.GBPosition( 5, 1 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_panelizeYLabel = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"Y:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_panelizeYLabel.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_panelizeYLabel, wx.GBPosition( 5, 0 ), wx.GBSpan( 1, 1 ), wx.ALIGN_RIGHT|wx.ALL, 5 ) - - self.m_panelizeYUnit = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"pcs"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_panelizeYUnit.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_panelizeYUnit, wx.GBPosition( 5, 2 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - self.m_sizeLabel = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"Size (single):"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_sizeLabel.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_sizeLabel, wx.GBPosition( 6, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - self.m_sizeXLabel = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"X:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_sizeXLabel.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_sizeXLabel, wx.GBPosition( 7, 0 ), wx.GBSpan( 1, 1 ), wx.ALIGN_RIGHT|wx.ALL, 5 ) - - self.m_sizeXCtrl = wx.TextCtrl( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 100,-1 ), wx.TE_READONLY ) - self.m_sizeXCtrl.SetMaxLength( 0 ) - m_fabBaseInfoSizer.Add( self.m_sizeXCtrl, wx.GBPosition( 7, 1 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_sizeXUnit = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"mm"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_sizeXUnit.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_sizeXUnit, wx.GBPosition( 7, 2 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - self.m_sizeYLabel1 = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"Y:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_sizeYLabel1.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_sizeYLabel1, wx.GBPosition( 8, 0 ), wx.GBSpan( 1, 1 ), wx.ALIGN_RIGHT|wx.ALL, 5 ) - - self.m_sizeYCtrl = wx.TextCtrl( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 100,-1 ), wx.TE_READONLY ) - self.m_sizeYCtrl.SetMaxLength( 0 ) - m_fabBaseInfoSizer.Add( self.m_sizeYCtrl, wx.GBPosition( 8, 1 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_sizeYUnit = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"mm"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_sizeYUnit.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_sizeYUnit, wx.GBPosition( 8, 2 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - self.m_quantityLbel = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"Qty(single):"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_quantityLbel.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_quantityLbel, wx.GBPosition( 9, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_quantityCtrlChoices = [ _(u"5"), _(u"10"), _(u"15"), _(u"20"), _(u"25"), _(u"30"), _(u"40"), _(u"50"), _(u"75"), _(u"100"), _(u"125"), _(u"150"), _(u"200"), _(u"250"), _(u"300"), _(u"350"), _(u"400"), _(u"450"), _(u"500"), _(u"600"), _(u"700"), _(u"800"), _(u"900"), _(u"1000"), _(u"1500"), _(u"2000"), _(u"2500"), _(u"3000"), _(u"3500"), _(u"4000"), _(u"4500"), _(u"5000"), _(u"5500"), _(u"6000"), _(u"6500"), _(u"7000"), _(u"7500"), _(u"8000"), _(u"9000"), _(u"10000") ] - self.m_quantityCtrl = wx.Choice( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_quantityCtrlChoices, 0 ) - self.m_quantityCtrl.SetSelection( 0 ) - m_fabBaseInfoSizer.Add( self.m_quantityCtrl, wx.GBPosition( 9, 1 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_quantityUnit = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"Pcs"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_quantityUnit.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_quantityUnit, wx.GBPosition( 9, 2 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - self.m_marginLabel = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"Break-away Rail:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_marginLabel.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_marginLabel, wx.GBPosition( 10, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_marginModeCtrlChoices = [ _(u"N/A"), _(u"Left & Right"), _(u"Top & Bottom"), _(u"All 4 sides") ] - self.m_marginModeCtrl = wx.Choice( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_marginModeCtrlChoices, 0 ) - self.m_marginModeCtrl.SetSelection( 0 ) - m_fabBaseInfoSizer.Add( self.m_marginModeCtrl, wx.GBPosition( 10, 1 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_marginValueCtrl = wx.TextCtrl( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 100,-1 ), wx.TE_READONLY ) - self.m_marginValueCtrl.SetMaxLength( 0 ) - m_fabBaseInfoSizer.Add( self.m_marginValueCtrl, wx.GBPosition( 11, 1 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_marginValueUnit = wx.StaticText( m_fabBaseInfo.GetStaticBox(), wx.ID_ANY, _(u"mm"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_marginValueUnit.Wrap( -1 ) - - m_fabBaseInfoSizer.Add( self.m_marginValueUnit, wx.GBPosition( 11, 2 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - - m_fabBaseInfoSizer.AddGrowableCol( 1 ) - - m_fabBaseInfo.Add( m_fabBaseInfoSizer, 1, wx.EXPAND, 5 ) - - - m_panelFabSizer.Add( m_fabBaseInfo, 0, wx.ALL|wx.EXPAND, 5 ) - - m_fabProcessInfo = wx.StaticBoxSizer( wx.StaticBox( self.m_panelFab, wx.ID_ANY, _(u"Process info") ), wx.VERTICAL ) - - m_fabProcessInfoSizer = wx.GridBagSizer( 0, 0 ) - m_fabProcessInfoSizer.SetFlexibleDirection( wx.BOTH ) - m_fabProcessInfoSizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) - - self.m_boardThicknessLabel = wx.StaticText( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, _(u"PCB Thickness:"), wx.DefaultPosition, wx.Size( -1,-1 ), 0 ) - self.m_boardThicknessLabel.Wrap( -1 ) - - m_fabProcessInfoSizer.Add( self.m_boardThicknessLabel, wx.GBPosition( 0, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_boardThicknessCtrlChoices = [ _(u"0.6"), _(u"0.8"), _(u"1.0"), _(u"1.2"), _(u"1.6"), _(u"2.0"), _(u"2.5"), _(u"3.0"), _(u"3.2") ] - self.m_boardThicknessCtrl = wx.Choice( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_boardThicknessCtrlChoices, 0 ) - self.m_boardThicknessCtrl.SetSelection( 4 ) - m_fabProcessInfoSizer.Add( self.m_boardThicknessCtrl, wx.GBPosition( 0, 1 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_boardThicknessUnit = wx.StaticText( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, _(u"mm"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_boardThicknessUnit.Wrap( -1 ) - - m_fabProcessInfoSizer.Add( self.m_boardThicknessUnit, wx.GBPosition( 0, 2 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - self.m_outerCopperThicknessLabel = wx.StaticText( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, _(u"Finished Copper Weight:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_outerCopperThicknessLabel.Wrap( -1 ) - - m_fabProcessInfoSizer.Add( self.m_outerCopperThicknessLabel, wx.GBPosition( 1, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_outerCopperThicknessCtrlChoices = [ _(u"1oz"), _(u"2oz") ] - self.m_outerCopperThicknessCtrl = wx.Choice( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_outerCopperThicknessCtrlChoices, 0 ) - self.m_outerCopperThicknessCtrl.SetSelection( 0 ) - m_fabProcessInfoSizer.Add( self.m_outerCopperThicknessCtrl, wx.GBPosition( 1, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_innerCopperThicknessLabel = wx.StaticText( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, _(u"Inner Copper Weight:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_innerCopperThicknessLabel.Wrap( -1 ) - - m_fabProcessInfoSizer.Add( self.m_innerCopperThicknessLabel, wx.GBPosition( 2, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_innerCopperThicknessCtrlChoices = [ _(u"0.5oz"), _(u"1oz"), _(u"2oz") ] - self.m_innerCopperThicknessCtrl = wx.Choice( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_innerCopperThicknessCtrlChoices, 0 ) - self.m_innerCopperThicknessCtrl.SetSelection( 0 ) - m_fabProcessInfoSizer.Add( self.m_innerCopperThicknessCtrl, wx.GBPosition( 2, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_minTraceWidthClearanceLabel = wx.StaticText( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, _(u"Min Trace/Space Outer:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_minTraceWidthClearanceLabel.Wrap( -1 ) - - m_fabProcessInfoSizer.Add( self.m_minTraceWidthClearanceLabel, wx.GBPosition( 3, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_minTraceWidthClearanceCtrlChoices = [ _(u"10/10mil"), _(u"8/8mil"), _(u"6/6mil"), _(u"5/5mil"), _(u"4/4mil"), _(u"3.5/3.5mil") ] - self.m_minTraceWidthClearanceCtrl = wx.Choice( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_minTraceWidthClearanceCtrlChoices, 0 ) - self.m_minTraceWidthClearanceCtrl.SetSelection( 2 ) - m_fabProcessInfoSizer.Add( self.m_minTraceWidthClearanceCtrl, wx.GBPosition( 3, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_minHoleSizeLabel = wx.StaticText( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, _(u"Min Drilled Hole:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_minHoleSizeLabel.Wrap( -1 ) - - m_fabProcessInfoSizer.Add( self.m_minHoleSizeLabel, wx.GBPosition( 4, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_minHoleSizeCtrlChoices = [ _(u"0.3mm"), _(u"0.25mm"), _(u"0.2mm"), _(u"0.15mm") ] - self.m_minHoleSizeCtrl = wx.Choice( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_minHoleSizeCtrlChoices, 0 ) - self.m_minHoleSizeCtrl.SetSelection( 0 ) - m_fabProcessInfoSizer.Add( self.m_minHoleSizeCtrl, wx.GBPosition( 4, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_solderColorLabel = wx.StaticText( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, _(u"Solder Mask Color:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_solderColorLabel.Wrap( -1 ) - - m_fabProcessInfoSizer.Add( self.m_solderColorLabel, wx.GBPosition( 5, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_solderColorCtrlChoices = [ _(u"Green"), _(u"Red"), _(u"Yellow"), _(u"Blue"), _(u"White"), _(u"Matte Black"), _(u"Black") ] - self.m_solderColorCtrl = wx.Choice( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_solderColorCtrlChoices, 0 ) - self.m_solderColorCtrl.SetSelection( 0 ) - m_fabProcessInfoSizer.Add( self.m_solderColorCtrl, wx.GBPosition( 5, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_silkscreenColorLabel = wx.StaticText( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, _(u"Silkscreen:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_silkscreenColorLabel.Wrap( -1 ) - - m_fabProcessInfoSizer.Add( self.m_silkscreenColorLabel, wx.GBPosition( 6, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_silkscreenColorCtrlChoices = [ _(u"White") ] - self.m_silkscreenColorCtrl = wx.Choice( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_silkscreenColorCtrlChoices, 0 ) - self.m_silkscreenColorCtrl.SetSelection( 0 ) - m_fabProcessInfoSizer.Add( self.m_silkscreenColorCtrl, wx.GBPosition( 6, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_solderCoverLabel = wx.StaticText( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, _(u"Via Process:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_solderCoverLabel.Wrap( -1 ) - - m_fabProcessInfoSizer.Add( self.m_solderCoverLabel, wx.GBPosition( 7, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_solderCoverCtrlChoices = [ _(u"Tenting Vias"), _(u"Vias not covered"), _(u"Solder Mask Plug (IV-B)"), _(u"Non-Conductive Fill") ] - self.m_solderCoverCtrl = wx.Choice( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_solderCoverCtrlChoices, 0 ) - self.m_solderCoverCtrl.SetSelection( 0 ) - m_fabProcessInfoSizer.Add( self.m_solderCoverCtrl, wx.GBPosition( 7, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_surfaceProcessLabel = wx.StaticText( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, _(u"Surface Finish:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_surfaceProcessLabel.Wrap( -1 ) - - m_fabProcessInfoSizer.Add( self.m_surfaceProcessLabel, wx.GBPosition( 8, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_surfaceProcessCtrlChoices = [ _(u"HASL"), _(u"Lead free HASL"), _(u"ENIG"), _(u"OSP") ] - self.m_surfaceProcessCtrl = wx.Choice( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_surfaceProcessCtrlChoices, 0 ) - self.m_surfaceProcessCtrl.SetSelection( 0 ) - m_fabProcessInfoSizer.Add( self.m_surfaceProcessCtrl, wx.GBPosition( 8, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_goldThicknessLabel = wx.StaticText( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, _(u"Immersion Gold Thickness:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_goldThicknessLabel.Wrap( -1 ) - - m_fabProcessInfoSizer.Add( self.m_goldThicknessLabel, wx.GBPosition( 9, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_goldThicknessCtrlChoices = [ _(u"1µm"), _(u"2µm"), _(u"3µm") ] - self.m_goldThicknessCtrl = wx.Choice( m_fabProcessInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_goldThicknessCtrlChoices, 0 ) - self.m_goldThicknessCtrl.SetSelection( 0 ) - m_fabProcessInfoSizer.Add( self.m_goldThicknessCtrl, wx.GBPosition( 9, 1 ), wx.GBSpan( 1, 2 ), wx.ALL|wx.EXPAND, 5 ) - - - m_fabProcessInfoSizer.AddGrowableCol( 1 ) - - m_fabProcessInfo.Add( m_fabProcessInfoSizer, 1, wx.EXPAND, 5 ) - - - m_panelFabSizer.Add( m_fabProcessInfo, 0, wx.ALL|wx.EXPAND, 5 ) - - m_fabSpecialProcess = wx.StaticBoxSizer( wx.StaticBox( self.m_panelFab, wx.ID_ANY, _(u"Special Process") ), wx.VERTICAL ) - - m_fabSpecialProcessSizer = wx.GridBagSizer( 0, 0 ) - m_fabSpecialProcessSizer.SetFlexibleDirection( wx.BOTH ) - m_fabSpecialProcessSizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) - - self.m_impedanceLabel = wx.StaticText( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, _(u"Impedance:"), wx.DefaultPosition, wx.Size( 100,-1 ), 0 ) - self.m_impedanceLabel.Wrap( -1 ) - - m_fabSpecialProcessSizer.Add( self.m_impedanceLabel, wx.GBPosition( 0, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_impedanceCtrlChoices = [ _(u"No"), _(u"Yes") ] - self.m_impedanceCtrl = wx.Choice( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_impedanceCtrlChoices, 0 ) - self.m_impedanceCtrl.SetSelection( 0 ) - m_fabSpecialProcessSizer.Add( self.m_impedanceCtrl, wx.GBPosition( 0, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_goldFingerLabel = wx.StaticText( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, _(u"Beveling of G/F:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_goldFingerLabel.Wrap( -1 ) - - m_fabSpecialProcessSizer.Add( self.m_goldFingerLabel, wx.GBPosition( 1, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_goldFingerCtrlChoices = [ _(u"No"), _(u"Yes") ] - self.m_goldFingerCtrl = wx.Choice( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_goldFingerCtrlChoices, 0 ) - self.m_goldFingerCtrl.SetSelection( 0 ) - m_fabSpecialProcessSizer.Add( self.m_goldFingerCtrl, wx.GBPosition( 1, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_halfHoleLabel = wx.StaticText( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, _(u"Plated Half Holes:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_halfHoleLabel.Wrap( -1 ) - - m_fabSpecialProcessSizer.Add( self.m_halfHoleLabel, wx.GBPosition( 2, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_halfHoleCtrlChoices = [ _(u"No"), _(u"Yes") ] - self.m_halfHoleCtrl = wx.Choice( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_halfHoleCtrlChoices, 0 ) - self.m_halfHoleCtrl.SetSelection( 0 ) - m_fabSpecialProcessSizer.Add( self.m_halfHoleCtrl, wx.GBPosition( 2, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_padHoleLabel = wx.StaticText( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, _(u"Pad Hole:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_padHoleLabel.Wrap( -1 ) - - m_fabSpecialProcessSizer.Add( self.m_padHoleLabel, wx.GBPosition( 3, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_padHoleCtrlChoices = [ _(u"No"), _(u"Yes") ] - self.m_padHoleCtrl = wx.Choice( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_padHoleCtrlChoices, 0 ) - self.m_padHoleCtrl.SetSelection( 0 ) - m_fabSpecialProcessSizer.Add( self.m_padHoleCtrl, wx.GBPosition( 3, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_blindViaLabel = wx.StaticText( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, _(u"HDI(Buried/blind vias):"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_blindViaLabel.Wrap( -1 ) - - m_fabSpecialProcessSizer.Add( self.m_blindViaLabel, wx.GBPosition( 4, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_blindViaCtrlChoices = [ _(u"No"), _(u"Yes") ] - self.m_blindViaCtrl = wx.Choice( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, m_blindViaCtrlChoices, 0 ) - self.m_blindViaCtrl.SetSelection( 0 ) - m_fabSpecialProcessSizer.Add( self.m_blindViaCtrl, wx.GBPosition( 4, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_hdiStructureLabel = wx.StaticText( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, _(u"HDI Structure:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_hdiStructureLabel.Wrap( -1 ) - - m_fabSpecialProcessSizer.Add( self.m_hdiStructureLabel, wx.GBPosition( 5, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_hdiStructureCtrlChoices = [ _(u"Rank 1"), _(u"Rank 2"), _(u"Rank 3") ] - self.m_hdiStructureCtrl = wx.Choice( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_hdiStructureCtrlChoices, 0 ) - self.m_hdiStructureCtrl.SetSelection( 0 ) - m_fabSpecialProcessSizer.Add( self.m_hdiStructureCtrl, wx.GBPosition( 5, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_stackupLabel = wx.StaticText( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, _(u"Stack up:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_stackupLabel.Wrap( -1 ) - - m_fabSpecialProcessSizer.Add( self.m_stackupLabel, wx.GBPosition( 6, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_stackupCtrlChoices = [ _(u"No Requirement"), _(u"Customer Specified Stack up") ] - self.m_stackupCtrl = wx.Choice( m_fabSpecialProcess.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_stackupCtrlChoices, 0 ) - self.m_stackupCtrl.SetSelection( 0 ) - m_fabSpecialProcessSizer.Add( self.m_stackupCtrl, wx.GBPosition( 6, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - - m_fabSpecialProcessSizer.AddGrowableCol( 1 ) - - m_fabSpecialProcess.Add( m_fabSpecialProcessSizer, 1, wx.EXPAND, 5 ) - - - m_panelFabSizer.Add( m_fabSpecialProcess, 0, wx.ALL|wx.EXPAND, 5 ) - - m_fabServiceInfo = wx.StaticBoxSizer( wx.StaticBox( self.m_panelFab, wx.ID_ANY, _(u"Personalized Service") ), wx.VERTICAL ) - - m_fabServiceInfoSizer = wx.GridBagSizer( 0, 0 ) - m_fabServiceInfoSizer.SetFlexibleDirection( wx.BOTH ) - m_fabServiceInfoSizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) - - self.m_testMethodLabel = wx.StaticText( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, _(u"Electrical Test:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_testMethodLabel.Wrap( -1 ) - - m_fabServiceInfoSizer.Add( self.m_testMethodLabel, wx.GBPosition( 0, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_testMethodCtrlChoices = [ _(u"Sample Test Free"), _(u"AOI+Flying Test"), _(u"AOI+Fixture") ] - self.m_testMethodCtrl = wx.Choice( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_testMethodCtrlChoices, 0 ) - self.m_testMethodCtrl.SetSelection( 0 ) - m_fabServiceInfoSizer.Add( self.m_testMethodCtrl, wx.GBPosition( 0, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_approveWorkingGerberLabel = wx.StaticText( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, _(u"Approve Working Gerber:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_approveWorkingGerberLabel.Wrap( -1 ) - - m_fabServiceInfoSizer.Add( self.m_approveWorkingGerberLabel, wx.GBPosition( 1, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_approveWorkingGerberCtrlChoices = [ _(u"No"), _(u"Yes") ] - self.m_approveWorkingGerberCtrl = wx.Choice( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_approveWorkingGerberCtrlChoices, 0 ) - self.m_approveWorkingGerberCtrl.SetSelection( 0 ) - m_fabServiceInfoSizer.Add( self.m_approveWorkingGerberCtrl, wx.GBPosition( 1, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_deliveryReportLabel = wx.StaticText( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, _(u"Delivery Report:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_deliveryReportLabel.Wrap( -1 ) - - m_fabServiceInfoSizer.Add( self.m_deliveryReportLabel, wx.GBPosition( 2, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_deliveryReportCtrlChoices = [ _(u"No"), _(u"Yes") ] - self.m_deliveryReportCtrl = wx.Choice( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_deliveryReportCtrlChoices, 0 ) - self.m_deliveryReportCtrl.SetSelection( 0 ) - m_fabServiceInfoSizer.Add( self.m_deliveryReportCtrl, wx.GBPosition( 2, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_analysisReportLabel = wx.StaticText( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, _(u"Microsection Analysis Report:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_analysisReportLabel.Wrap( -1 ) - - m_fabServiceInfoSizer.Add( self.m_analysisReportLabel, wx.GBPosition( 3, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_analysisReportCtrlChoices = [ _(u"No"), _(u"Yes") ] - self.m_analysisReportCtrl = wx.Choice( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_analysisReportCtrlChoices, 0 ) - self.m_analysisReportCtrl.SetSelection( 0 ) - m_fabServiceInfoSizer.Add( self.m_analysisReportCtrl, wx.GBPosition( 3, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_reportFormatLabel = wx.StaticText( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, _(u"Report Format:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_reportFormatLabel.Wrap( -1 ) - - m_fabServiceInfoSizer.Add( self.m_reportFormatLabel, wx.GBPosition( 4, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_reportFormatCtrlChoices = [ _(u"Paper"), _(u"Electronic") ] - self.m_reportFormatCtrl = wx.Choice( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_reportFormatCtrlChoices, 0 ) - self.m_reportFormatCtrl.SetSelection( 1 ) - m_fabServiceInfoSizer.Add( self.m_reportFormatCtrl, wx.GBPosition( 4, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_ulMarkLabel = wx.StaticText( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, _(u"UL Mark:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_ulMarkLabel.Wrap( -1 ) - - m_fabServiceInfoSizer.Add( self.m_ulMarkLabel, wx.GBPosition( 5, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_ulMarkCtrlChoices = [ _(u"No"), _(u"UL+Week/Year"), _(u"UL+Year/Week") ] - self.m_ulMarkCtrl = wx.Choice( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_ulMarkCtrlChoices, 0 ) - self.m_ulMarkCtrl.SetSelection( 0 ) - m_fabServiceInfoSizer.Add( self.m_ulMarkCtrl, wx.GBPosition( 5, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_filmLabel = wx.StaticText( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, _(u"Film:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_filmLabel.Wrap( -1 ) - - m_fabServiceInfoSizer.Add( self.m_filmLabel, wx.GBPosition( 6, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - m_filmCtrlChoices = [ _(u"No"), _(u"Yes") ] - self.m_filmCtrl = wx.Choice( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.Size( 100,-1 ), m_filmCtrlChoices, 0 ) - self.m_filmCtrl.SetSelection( 0 ) - m_fabServiceInfoSizer.Add( self.m_filmCtrl, wx.GBPosition( 6, 1 ), wx.GBSpan( 1, 3 ), wx.ALL|wx.EXPAND, 5 ) - - self.m_specialRequestsLabel = wx.StaticText( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, _(u"Special Requests:"), wx.DefaultPosition, wx.Size( -1,-1 ), 0 ) - self.m_specialRequestsLabel.Wrap( -1 ) - - m_fabServiceInfoSizer.Add( self.m_specialRequestsLabel, wx.GBPosition( 7, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - - self.m_specialRequestsCtrl = wx.TextCtrl( m_fabServiceInfo.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 100,-1 ), 0 ) - m_fabServiceInfoSizer.Add( self.m_specialRequestsCtrl, wx.GBPosition( 7, 1 ), wx.GBSpan( 5, 3 ), wx.ALL|wx.EXPAND, 5 ) - - - m_fabServiceInfoSizer.AddGrowableCol( 1 ) - - m_fabServiceInfo.Add( m_fabServiceInfoSizer, 1, wx.EXPAND, 5 ) - - - m_panelFabSizer.Add( m_fabServiceInfo, 0, wx.ALL|wx.EXPAND, 5 ) - - - self.m_panelFab.SetSizer( m_panelFabSizer ) - self.m_panelFab.Layout() - m_panelFabSizer.Fit( self.m_panelFab ) - self.m_notebook.AddPage( self.m_panelFab, _(u"PCB Fabrication"), False ) - - m_topLeftSizer.Add( self.m_notebook, 1, wx.ALIGN_CENTER|wx.EXPAND|wx.TOP, 12 ) - - - m_topSizer.Add( m_topLeftSizer, 6, wx.ALL|wx.EXPAND, 5 ) - - m_topRightSizer = wx.BoxSizer( wx.VERTICAL ) - - m_totalSummarySizer = wx.GridBagSizer( 0, 0 ) - m_totalSummarySizer.SetFlexibleDirection( wx.BOTH ) - m_totalSummarySizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) - - self.m_huaqiuLogo = wx.StaticBitmap( self, wx.ID_ANY, wx.Bitmap( self.GetImagePath( u"Huaqiu.png" ), wx.BITMAP_TYPE_ANY ), wx.DefaultPosition, wx.DefaultSize, 0 ) - m_totalSummarySizer.Add( self.m_huaqiuLogo, wx.GBPosition( 0, 0 ), wx.GBSpan( 3, 1 ), wx.ALL|wx.EXPAND|wx.RIGHT|wx.TOP, 5 ) - - self.m_amountLabel = wx.StaticText( self, wx.ID_ANY, _(u"PCB Qty:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_amountLabel.Wrap( -1 ) - - m_totalSummarySizer.Add( self.m_amountLabel, wx.GBPosition( 0, 1 ), wx.GBSpan( 1, 1 ), wx.LEFT|wx.TOP, 5 ) - - self.m_amountCtrl = wx.StaticText( self, wx.ID_ANY, _(u"-"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_amountCtrl.Wrap( -1 ) - - m_totalSummarySizer.Add( self.m_amountCtrl, wx.GBPosition( 0, 2 ), wx.GBSpan( 1, 1 ), wx.TOP, 5 ) - - self.m_amountUnit = wx.StaticText( self, wx.ID_ANY, _(u"pcs"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_amountUnit.Wrap( -1 ) - - m_totalSummarySizer.Add( self.m_amountUnit, wx.GBPosition( 0, 3 ), wx.GBSpan( 1, 1 ), wx.LEFT|wx.TOP, 5 ) - - self.m_dueDateLabel = wx.StaticText( self, wx.ID_ANY, _(u"Time:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_dueDateLabel.Wrap( -1 ) - - m_totalSummarySizer.Add( self.m_dueDateLabel, wx.GBPosition( 1, 1 ), wx.GBSpan( 1, 1 ), wx.LEFT, 5 ) - - self.m_dueDateCtrl = wx.StaticText( self, wx.ID_ANY, _(u"-"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_dueDateCtrl.Wrap( -1 ) - - m_totalSummarySizer.Add( self.m_dueDateCtrl, wx.GBPosition( 1, 2 ), wx.GBSpan( 1, 1 ), 0, 5 ) - - self.m_dueDateUnit = wx.StaticText( self, wx.ID_ANY, _(u"Days"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_dueDateUnit.Wrap( -1 ) - - m_totalSummarySizer.Add( self.m_dueDateUnit, wx.GBPosition( 1, 3 ), wx.GBSpan( 1, 1 ), wx.LEFT, 5 ) - - self.m_priceLabel = wx.StaticText( self, wx.ID_ANY, _(u"Cost:"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_priceLabel.Wrap( -1 ) - - m_totalSummarySizer.Add( self.m_priceLabel, wx.GBPosition( 2, 1 ), wx.GBSpan( 1, 1 ), wx.LEFT|wx.TOP, 5 ) - - self.m_priceCtrl = wx.StaticText( self, wx.ID_ANY, _(u"-"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_priceCtrl.Wrap( -1 ) - - m_totalSummarySizer.Add( self.m_priceCtrl, wx.GBPosition( 2, 2 ), wx.GBSpan( 1, 1 ), wx.TOP, 5 ) - - self.m_priceUnit = wx.StaticText( self, wx.ID_ANY, _(u"$"), wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_priceUnit.Wrap( -1 ) - - m_totalSummarySizer.Add( self.m_priceUnit, wx.GBPosition( 2, 3 ), wx.GBSpan( 1, 1 ), wx.LEFT|wx.TOP, 5 ) - - self.m_updatePriceButton = wx.Button( self, wx.ID_ANY, _(u"Update Price"), wx.DefaultPosition, wx.DefaultSize, 0 ) - m_totalSummarySizer.Add( self.m_updatePriceButton, wx.GBPosition( 2, 4 ), wx.GBSpan( 1, 1 ), wx.BOTTOM|wx.EXPAND|wx.RIGHT, 5 ) - - self.m_placeOrderButton = wx.Button( self, wx.ID_ANY, _(u"Place Order"), wx.DefaultPosition, wx.DefaultSize, 0 ) - m_totalSummarySizer.Add( self.m_placeOrderButton, wx.GBPosition( 0, 4 ), wx.GBSpan( 1, 1 ), wx.EXPAND|wx.RIGHT|wx.TOP, 5 ) - - - m_totalSummarySizer.AddGrowableCol( 2 ) - m_totalSummarySizer.AddGrowableCol( 3 ) - - m_topRightSizer.Add( m_totalSummarySizer, 0, wx.EXPAND, 5 ) - - self.m_priceDetailsViewListCtrl = wx.dataview.DataViewListCtrl( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_priceDescriptionColumn = self.m_priceDetailsViewListCtrl.AppendTextColumn( _(u"Item"), wx.dataview.DATAVIEW_CELL_INERT, 200, wx.ALIGN_LEFT, wx.dataview.DATAVIEW_COL_RESIZABLE ) - self.m_priceColumn = self.m_priceDetailsViewListCtrl.AppendTextColumn( _(u"Price"), wx.dataview.DATAVIEW_CELL_INERT, -1, wx.ALIGN_LEFT, wx.dataview.DATAVIEW_COL_RESIZABLE ) - m_topRightSizer.Add( self.m_priceDetailsViewListCtrl, 1, wx.ALL|wx.EXPAND, 5 ) - - self.m_drcPanel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.BORDER_SIMPLE|wx.TAB_TRAVERSAL ) - m_drcPanelSizer = wx.BoxSizer( wx.VERTICAL ) - - - self.m_drcPanel.SetSizer( m_drcPanelSizer ) - self.m_drcPanel.Layout() - m_drcPanelSizer.Fit( self.m_drcPanel ) - m_topRightSizer.Add( self.m_drcPanel, 1, wx.ALL|wx.EXPAND, 5 ) - - - m_topSizer.Add( m_topRightSizer, 5, wx.ALL|wx.EXPAND, 5 ) - - - m_mainSizer.Add( m_topSizer, 1, wx.EXPAND, 8 ) - - - self.SetSizer( m_mainSizer ) - self.Layout() - - self.Centre( wx.BOTH ) - - # Connect Events - self.m_template.Bind( wx.EVT_CHOICE, self.OnTemplateChanged ) - self.m_pcbPackaingCtrl.Bind( wx.EVT_CHOICE, self.OnPcbPackagingChanged ) - self.m_panelizeXCtrl.Bind( wx.EVT_TEXT, self.OnPanelizeXChanged ) - self.m_panelizeYCtrl.Bind( wx.EVT_TEXT, self.OnPanelizeYChanged ) - self.m_quantityCtrl.Bind( wx.EVT_CHOICE, self.OnPcbQuantityChanged ) - self.m_marginModeCtrl.Bind( wx.EVT_CHOICE, self.OnMarginModeChanged ) - self.m_surfaceProcessCtrl.Bind( wx.EVT_CHOICE, self.OnSurfaceProcessChanged ) - self.m_blindViaCtrl.Bind( wx.EVT_CHOICE, self.OnHDIChanged ) - self.m_deliveryReportCtrl.Bind( wx.EVT_CHOICE, self.OnReportChanged ) - self.m_analysisReportCtrl.Bind( wx.EVT_CHOICE, self.OnReportChanged ) - self.m_updatePriceButton.Bind( wx.EVT_BUTTON, self.OnUpdatePrice ) - self.m_placeOrderButton.Bind( wx.EVT_BUTTON, self.OnPlaceOrder ) - self.m_solderColorCtrl.Bind( wx.EVT_CHOICE, self.OnMaskColorChange ) - #self.m_layerCountCtrl.Bind( wx.EVT_CHOICE, self.OnTGChangebyLayer ) - self.m_layerCountCtrl.Bind( wx.EVT_CHOICE, self.OnThicknessChangebyLayer ) - - - def __del__( self ): - pass - - - # Virtual event handlers, override them in your derived class - def OnTemplateChanged( self, event ): - event.Skip() - - def OnPcbPackagingChanged( self, event ): - event.Skip() - - def OnPanelizeXChanged( self, event ): - event.Skip() - - def OnPanelizeYChanged( self, event ): - event.Skip() - - def OnPcbQuantityChanged( self, event ): - event.Skip() - - def OnMarginModeChanged( self, event ): - event.Skip() - - def OnSurfaceProcessChanged( self, event ): - event.Skip() - - def OnHDIChanged( self, event ): - event.Skip() - - def OnReportChanged( self, event ): - event.Skip() - - - def OnUpdatePrice( self, event ): - event.Skip() - - def OnPlaceOrder( self, event ): - event.Skip() - - def OnMaskColorChange(self, event): - event.Skip() - - def OnThicknessChangebyLayer(self, event): - event.Skip() - - # Virtual image path resolution method. Override this in your derived class. - def GetImagePath( self, bitmap_path ): - return bitmap_path - - diff --git a/icon.png b/icon.png deleted file mode 100644 index 4d869d138d35761d7800cc8868f75caf3ec0546b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1149 zcmV-@1cLjCP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^XO*0N*(00ZqwL_t(YOPyBXYa3-4|Gjs)yX4X~ZIdnS znxVq1!`XF{4ipss0|lo}H*qj=bSUnVUnVH{!Eb&NM3IS#h@dElpl%=3t#yr)(XQL* zT&h{^N>`gUZJJ!}E_bib`(C=tiMzAE@R0Cc^83B-`#jI@3F8DbVgGpz3&%fzT`YjL zX;94sMI5n&2{n-f({(6{3cumPvn_a54PK4Hs>55c5KCpy_2^?rJ@Rmq5x5~RefUMp zz5fn$vm0tB5q9YGPULO$IoU=6B&HjHs)D;hfJmz~G^%UxDkQd2M`O7TcWDXcw(Z#U z+XNV6fxz^UmofkDd(hIGg(j332QyWuZ6wle5P2Mmp@V4@^ds(h@Er$!-41rY>cCrb z!5vP|ID9%)tTTn7x!=L+v$On{Tn4iBthg#Gu4AD4GVQDx}W< z--j;|~yl28MF)xp}?aoSJ^SWJbxSi)UzzXi;^@g_f`ck+BX$46oE>mPk04z(fJ zbMt)6O!ItKAJ3V;`2 z+_nLQj!n51RkDuLbQL0gqL_O8ndWK>mXYIC&(LEyrIv$y~UL`E}0Ah~-GTaF%uIj{q6X&!89?|xqX{v=tk3N4$( z?#tuyi?s`vWc3JZR>|9qT%TNDhZr{XY4UrKY$7+e_e(Epl*_PZW|7=^A1e8?K=GAh z{7k$%uxpm&waZrm@7(~3$6n*7=$1yH^V8&`_2N~|R>$&u;(-TYWcq?hMLXMc@Bp2L zrdxzE^lA5Ex9O+$Vl*C?gG-p4Z#&Zd<;bML0BiE1^cPY0vT8i4{|NA$8hVcmqxYp@ zoZB%7J<}uCi56lM+!*@jwhhpo7Dyx|?^XJF1o(~%V{0FFUHBD0v)~VcXiAZb%)TdD zWqN;M5_f-m9Ld3*(t(@0p%9&2y*P>Tw 1: + qty = int(suggest[PCS_COUNT]) + price = float(suggest[TOTAL]) + suggests.append( + OrderSummary( + pcb_quantity=qty, + price=price, + build_time=BuildTime( + int(full_time_cost[0]), full_time_cost[1] + ), + ) + ) + self.summary_view.update_order_summary(suggests) + + def on_update_price(self, evt): + if not self.form_is_valid(): + return + url = OrderRegion.get_url(SETTING_MANAGER.order_region, URL_KIND.QUERY_PRICE) + if url is None: + wx.MessageBox(_("No available url for querying price in current region")) + return + try: + form = self.get_query_price_form() + rep = urllib.request.Request( + url, data=RequestHelper.convert_dict_to_request_data(form) + ) + fp = urllib.request.urlopen(rep) + data = fp.read() + encoding = fp.info().get_content_charset("utf-8") + content = data.decode(encoding) + quote = json.loads(content) + if DATA in quote and LIST in quote[DATA]: + return self.parse_price_list(quote[DATA][LIST]) + elif SUGGEST in quote: + return self.parse_price(quote) + else: + err_msg = quote + if "msg" in quote: + err_msg = quote["msg"] + wx.MessageBox(_("Incorrect form parameter: ") + err_msg) + except Exception as e: + wx.MessageBox(str(e)) + raise e # TODO remove me + + def on_place_order(self, evt): + if not self.form_is_valid(): + return + try: + url = OrderRegion.get_url( + SETTING_MANAGER.order_region, URL_KIND.PLACE_ORDER + ) + if url is None: + wx.MessageBox(_("No available url for placing order in current region")) + return + with self.fabrication_data_generator.create_kicad_pcb_file() as zipfile: + rsp = requests.post( + url, + files={"file": open(zipfile, "rb")}, + data=self.get_place_order_form(), + ) + urls = json.loads(rsp.content) + for key in "url", "redirect": + if key in urls: + uat_url = str(urls[key]) + webbrowser.open(uat_url) + return + raise Exception("No available order url in the response") + except Exception as e: + wx.MessageBox(str(e)) + raise e # TODO remove me + + def adjust_size(self): + for i in self._pcb_form_parts.values(): + i.Layout() + self.Layout() + + def on_order_region_changed(self, ev): + for i in self._pcb_form_parts.values(): + i.on_region_changed() + self.adjust_size() + + def OnSize(self, evt): + evt.Skip() + SETTING_MANAGER.set_window_size(self.Size) + + def OnClose(self, evt): + SINGLE_PLUGIN.register_main_wind(None) + self.Destroy() diff --git a/kicad_amf_plugin/gui/summary/__init__.py b/kicad_amf_plugin/gui/summary/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kicad_amf_plugin/gui/summary/bom_price_model.py b/kicad_amf_plugin/gui/summary/bom_price_model.py new file mode 100644 index 0000000..e1342a4 --- /dev/null +++ b/kicad_amf_plugin/gui/summary/bom_price_model.py @@ -0,0 +1,20 @@ +from .price_model_base import PriceModelBase, PriceItem + + +class BomPriceModel(PriceModelBase): + bom_price: float = 0 + + def data(self, row: int, col: int): + return 0 + + def name(self): + return _("BOM") + + def sum(self): + return 0 + + def get_items(self) -> "list[PriceItem]": + return [] + + def update(self, data: dict): + pass diff --git a/kicad_amf_plugin/gui/summary/order_summary_model.py b/kicad_amf_plugin/gui/summary/order_summary_model.py new file mode 100644 index 0000000..473d516 --- /dev/null +++ b/kicad_amf_plugin/gui/summary/order_summary_model.py @@ -0,0 +1,85 @@ +from dataclasses import dataclass +import wx.dataview as dv +from kicad_amf_plugin.settings.setting_manager import SETTING_MANAGER +from enum import Enum + +from collections import namedtuple + + +class TimeUnit(Enum): + DAY = "days" + HOUR = "hours" + + +AVAILABLE_TIME_UNIT = {TimeUnit.DAY.value: _("days"), TimeUnit.HOUR.value: _("hours")} + +BuildTime = namedtuple("BuildTime", ["Time", "Unit"]) + + +class OrderSummaryCol: + BUILD_TIME = 0 + QUANTITY = BUILD_TIME + 1 + PRICE = QUANTITY + 1 + + COL_COUNT = PRICE + 1 + + +@dataclass +class OrderSummary: + pcb_quantity: int + build_time: BuildTime + price: float + + +class OrderSummaryModel(dv.DataViewIndexListModel): + def __init__(self): + dv.DataViewIndexListModel.__init__(self) + self.orders_summary: "list[OrderSummary]" = [] + + # This method is called to provide the data object for a + # particular row,col + def GetValueByRow(self, row: int, col: int): + order = self.orders_summary[row] + map = { + 0: SETTING_MANAGER.get_build_time_formatter().format( + time=order.build_time.Time, unit=_(order.build_time.Unit) + ), + 1: str(order.pcb_quantity), + 2: f"{SETTING_MANAGER.get_price_unit()}{order.price}", + } + return map[col] + + # Report how many columns this model provides data for. + def GetColumnCount(self): + return OrderSummaryCol.COL_COUNT + + # Specify the data type for a column + def GetColumnType(self, col): + return "string" + + def SetValueByRow(self, value, row, col): + return False + + # Report the number of rows in the model + def GetCount(self): + # self.log.write('GetCount') + return len(self.orders_summary) + + # Called to check if non-standard attributes should be used in the + # cell at (row, col) + def GetAttrByRow(self, row, col, attr): + # self.log.write('GetAttrByRow: (%d, %d)' % (row, col)) + # if col == 3: + # attr.SetColour('red') + # attr.SetBold(True) + # return True + return False + + def update_order_info(self, data: "list[OrderSummary]"): + self.orders_summary = data + self.Reset(len(data)) + + def clear_content(self): + self.orders_summary = [] + self.Reset(len(self.orders_summary)) + self.Cleared() diff --git a/kicad_amf_plugin/gui/summary/pcb_price_model.py b/kicad_amf_plugin/gui/summary/pcb_price_model.py new file mode 100644 index 0000000..0a38a19 --- /dev/null +++ b/kicad_amf_plugin/gui/summary/pcb_price_model.py @@ -0,0 +1,120 @@ +from dataclasses import dataclass + +from .price_model_base import PriceModelBase, PriceModelCol, PriceItem +from kicad_amf_plugin.utils.number_round import number_round + +TRANSLATED = { + 0: _("testfee"), + 1: _("plate"), + 2: _("clc"), + 3: _("gch"), + 4: _("bgafee"), + 5: _("impendancefee"), + 6: _("pin"), + 7: _("copperfee"), + 8: _("colorfee"), + 9: _("sprayfee"), + 10: _("extraurgentfee"), + 11: _("viasfee"), + 12: _("bankongfee"), + 13: _("utilizationfee"), + 14: _("discountfee"), + 15: _("boardfee"), + 16: _("difficultyfee"), + 17: _("coverfee"), + 18: _("blindfee"), + 19: _("pressingfee"), + 20: _("cjfee"), + 21: _("pthfee"), + 22: _("viainpadfee"), + 23: _("reportfee"), + 24: _("populerfee"), + 25: _("paperfee"), + 26: _("userstampfee"), + 27: _("acceptancefee"), + 28: _("crossfee"), + 29: _("invoicefee"), + 30: _("insurancefee"), + 31: _("zkfee"), + 32: _("cutfee"), + 33: _("luocao"), + 34: _("luocheng"), +} + + +PROS = { + 0: "testfee", + 1: "plate", + 2: "clc", + 3: "gch", + 4: "bgafee", + 5: "impendancefee", + 6: "pin", + 7: "copperfee", + 8: "colorfee", + 9: "sprayfee", + 10: "extraurgentfee", + 11: "viasfee", + 12: "bankongfee", + 13: "utilizationfee", + 14: "discountfee", + 15: "boardfee", + 16: "difficultyfee", + 17: "coverfee", + 18: "blindfee", + 19: "pressingfee", + 20: "cjfee", + 21: "pthfee", + 22: "viainpadfee", + 23: "reportfee", + 24: "populerfee", + 25: "paperfee", + 26: "userstampfee", + 27: "acceptancefee", + 28: "crossfee", + 29: "invoicefee", + 30: "insurancefee", + 31: "zkfee", + 32: "cutfee", + 33: "luocao", + 34: "luocheng", +} + + +class PCBPriceModel(PriceModelBase): + def __init__(self) -> None: + super().__init__() + self.prices_item: "list[PriceItem]" = [] + for i in TRANSLATED: + self.prices_item.append(PriceItem(PROS[i], TRANSLATED[i], 0, self)) + + def data(self, row: int, col: int): + if col == PriceModelCol.VALUE: + return self.prices_item[row] + elif col == PriceModelCol.DESC: + return TRANSLATED[row] + + def name(self): + return "PCB" + + @number_round() + def sum(self): + num = 0 + for i in self.prices_item: + num = num + i.value + return num + + def get_items(self) -> "list[PriceItem]": + return [i for i in self.prices_item if i.value] + + def update(self, data: dict): + for i in PROS: + if PROS[i] in data: + self.prices_item[i].value = data[PROS[i]] + + def item_names(self): + return PROS + + def clear(self): + for i in self.prices_item: + i.value = 0 diff --git a/kicad_amf_plugin/gui/summary/place_order_request.py b/kicad_amf_plugin/gui/summary/place_order_request.py new file mode 100644 index 0000000..b117fc4 --- /dev/null +++ b/kicad_amf_plugin/gui/summary/place_order_request.py @@ -0,0 +1,8 @@ +from dataclasses import dataclass + + +@dataclass +class PlaceOrderRequest: + blength: str + bwidth: str + type: str = "pcbfile" diff --git a/kicad_amf_plugin/gui/summary/price_model_base.py b/kicad_amf_plugin/gui/summary/price_model_base.py new file mode 100644 index 0000000..16dc56e --- /dev/null +++ b/kicad_amf_plugin/gui/summary/price_model_base.py @@ -0,0 +1,46 @@ +from dataclasses import dataclass +from enum import Enum +import abc +import json + + +class PriceModelCol(Enum): + DESC = 0 + VALUE = DESC + 1 + COL_COUNT = VALUE + 1 + + +@dataclass +class PriceItem: + id: str + desc: str + value: float + parent: "PriceModelBase" + + +class PriceModelBase: + @abc.abstractclassmethod + def data(self, row: int, col: int): + pass + + @abc.abstractclassmethod + def name(self) -> "str": + pass + + @abc.abstractclassmethod + def sum(self): + pass + + @abc.abstractclassmethod + def get_items(self) -> "list[PriceItem]": + pass + + @abc.abstractclassmethod + def update(self, data: dict): + pass + + def item_names(self): + return [] + + def clear(self): + pass diff --git a/kicad_amf_plugin/gui/summary/price_summary_model.py b/kicad_amf_plugin/gui/summary/price_summary_model.py new file mode 100644 index 0000000..d376baa --- /dev/null +++ b/kicad_amf_plugin/gui/summary/price_summary_model.py @@ -0,0 +1,169 @@ +from dataclasses import dataclass +import wx.dataview as dv +from .bom_price_model import BomPriceModel +from .pcb_price_model import PCBPriceModel +from .smt_price_model import SmtPriceModel +from .price_model_base import PriceModelCol +from .price_model_base import PriceModelBase, PriceItem +from enum import Enum +from kicad_amf_plugin.settings.setting_manager import SETTING_MANAGER + + +class PriceCategory(Enum): + PCB = "pcb" + SMT = "smt" + BOM = "bom" + + +PRICE_KIND = 3 + + +@dataclass +class PriceSummary: + pcb_quantity: int = 0 + days: int = 0 + cost: int = 0 + + +class PriceSummaryModel(dv.PyDataViewModel): + def __init__(self): + dv.PyDataViewModel.__init__(self) + self.UseWeakRefs(True) + self.price_category: "dict[int,PriceModelBase]" = { + PriceCategory.PCB: PCBPriceModel(), + PriceCategory.SMT: SmtPriceModel(), + PriceCategory.BOM: BomPriceModel(), + } + self._days_cost = 0 + self._pcb_quantity = 0 + + @property + def day_cost(self): + return self._days_cost + + @property + def pcb_count(self): + return self._pcb_quantity + + def update_price(self, price: "dict"): + for i in PriceCategory.PCB, PriceCategory.SMT, PriceCategory.BOM: + if i.value in price: + self.price_category[i].update(price[i.value]) + self.Cleared() + + def get_sum(self): + s = 0 + for i in self.price_category: + s = s + self.price_category[i].sum() + return s + + def GetColumnCount(self): + return PriceModelCol.COL_COUNT + + def GetColumnType(self, col): + mapper = { + 0: "string", + 1: "string", + } + return mapper[col] + + def GetChildren(self, parent, children): + if not parent: + for cat in self.price_category: + children.append(self.ObjectToItem(self.price_category[cat])) + return PRICE_KIND + + # Otherwise we'll fetch the python object associated with the parent + # item and make DV items for each of its child objects. + node = self.ItemToObject(parent) + if isinstance(node, PriceModelBase): + for i in node.get_items(): + children.append(self.ObjectToItem(i)) + return len(node.get_items()) + return 0 + + def IsContainer(self, item): + # Return True if the item has children, False otherwise. + ##self.log.write("IsContainer\n") + + # The hidden root is a container + if not item: + return True + # and in this model the genre objects are containers + node = self.ItemToObject(item) + if isinstance(node, PriceModelBase): + return True + # but everything else (the song objects) are not + return False + + # def HasContainerColumns(self, item): + # self.log.write('HasContainerColumns\n') + # return True + + def GetParent(self, item): + # Return the item which is this item's parent. + ##self.log.write("GetParent\n") + + if not item: + return dv.NullDataViewItem + + node = self.ItemToObject(item) + if isinstance(node, PriceModelBase): + return dv.NullDataViewItem + elif isinstance(node, PriceItem): + return self.ObjectToItem(node.parent) + return dv.NullDataViewItem + + def HasValue(self, item, col): + # Overriding this method allows you to let the view know if there is any + # data at all in the cell. If it returns False then GetValue will not be + # called for this item and column. + node = self.ItemToObject(item) + if isinstance(node, PriceModelBase) or isinstance(node, PriceItem): + return True + return False + + def GetValue(self, item, col): + # Return the value to be displayed for this item and column. For this + # example we'll just pull the values from the data objects we + # associated with the items in GetChildren. + + # Fetch the data object for this item. + node = self.ItemToObject(item) + + if isinstance(node, PriceModelBase): + # Due to the HasValue implementation above, GetValue should only + # be called for the first column for PriceModelBase objects. We'll verify + # that with this assert. + if 0 == col: + return node.name() + else: + return f"{node.sum()}{SETTING_MANAGER.get_price_unit()}" + + elif isinstance(node, PriceItem): + mapper = { + 0: node.desc, + 1: f"{node.value}{SETTING_MANAGER.get_price_unit()}", + } + return mapper[col] + + else: + raise RuntimeError("unknown node type") + + def GetAttr(self, item, col, attr): + ##self.log.write('GetAttr') + node = self.ItemToObject(item) + if ( + isinstance(node, PCBPriceModel) + or isinstance(node, SmtPriceModel) + or isinstance(node, BomPriceModel) + ): + attr.SetColour("blue") + attr.SetBold(True) + return True + return False + + def clear_content(self): + for i in PriceCategory.PCB, PriceCategory.SMT, PriceCategory.BOM: + self.price_category[i].clear() + self.Cleared() diff --git a/kicad_amf_plugin/gui/summary/smt_price_model.py b/kicad_amf_plugin/gui/summary/smt_price_model.py new file mode 100644 index 0000000..e607c24 --- /dev/null +++ b/kicad_amf_plugin/gui/summary/smt_price_model.py @@ -0,0 +1,20 @@ +from .price_model_base import PriceModelBase, PriceItem + + +class SmtPriceModel(PriceModelBase): + smt_price: float = 0 + + def data(self, row: int, col: int): + return 0 + + def name(self): + return _("SMT") + + def sum(self): + return 0 + + def get_items(self) -> "list[PriceItem]": + return [] + + def update(self, data: dict): + pass diff --git a/kicad_amf_plugin/gui/summary/summary_panel.py b/kicad_amf_plugin/gui/summary/summary_panel.py new file mode 100644 index 0000000..37b439f --- /dev/null +++ b/kicad_amf_plugin/gui/summary/summary_panel.py @@ -0,0 +1,116 @@ +from .ui_summary_panel import UiSummaryPanel +from kicad_amf_plugin.icon import GetImagePath +from kicad_amf_plugin.language.lang_setting_pop_menu import LangSettingPopMenu +import wx +from .order_summary_model import OrderSummary, OrderSummaryModel +from .price_summary_model import PriceSummaryModel + +import wx.dataview as dv +from kicad_amf_plugin.settings.setting_manager import SETTING_MANAGER +from kicad_amf_plugin.gui.event.pcb_fabrication_evt_list import ( + UpdatePrice, + PlaceOrder, + OrderRegionChanged, +) + + +class SummaryPanel(UiSummaryPanel): + def __init__(self, *args, **kw): + super().__init__(*args, **kw) + + self.init_ui() + self.btn_set_language.Bind(wx.EVT_BUTTON, self.on_set_lang_clicked) + self.radio_box_order_region.Bind(wx.EVT_RADIOBOX, self.on_region_changed) + self.btn_update_price.Bind(wx.EVT_BUTTON, self.on_update_price_clicked) + self.btn_place_order.Bind(wx.EVT_BUTTON, self.on_place_order_clicked) + + def init_ui(self): + self.list_order_summary.AppendTextColumn( + _("Build Time"), + 0, + width=-1, + mode=dv.DATAVIEW_CELL_ACTIVATABLE, + align=wx.ALIGN_LEFT, + ) + self.list_order_summary.AppendTextColumn( + _("Qty"), + 1, + width=-1, + mode=dv.DATAVIEW_CELL_ACTIVATABLE, + align=wx.ALIGN_CENTER, + ) + self.list_order_summary.AppendTextColumn( + _("Price"), + 2, + width=-1, + mode=dv.DATAVIEW_CELL_ACTIVATABLE, + align=wx.ALIGN_LEFT, + ) + + self.list_order_summary.SetMinSize( + wx.Size(-1, SummaryPanel.GetLineHeight(self) * 3 + 30) + ) + self.model_order_summary = OrderSummaryModel() + self.list_order_summary.AssociateModel(self.model_order_summary) + + self.list_price_detail.AppendTextColumn( + _("Item"), + 0, + width=120, + mode=dv.DATAVIEW_CELL_ACTIVATABLE, + align=wx.ALIGN_LEFT, + ) + self.list_price_detail.AppendTextColumn( + _("Price"), + 1, + width=-1, + mode=dv.DATAVIEW_CELL_ACTIVATABLE, + align=wx.ALIGN_RIGHT, + ) + + self.model_price_summary = PriceSummaryModel() + self.list_price_detail.AssociateModel(self.model_price_summary) + self.radio_box_order_region.SetSelection(SETTING_MANAGER.order_region) + + def update_price_detail(self, price: "dict"): + self.model_price_summary.update_price(price) + + def get_total_price(self): + return self.model_price_summary.get_sum() + + def update_order_summary(self, price_summary: "list"): + self.model_order_summary.update_order_info(price_summary) + + def on_update_price_clicked(self, ev): + self.clear_content() + evt = UpdatePrice(id=-1) + wx.PostEvent(self.Parent, evt) + + def on_place_order_clicked(self, ev): + evt = PlaceOrder(id=-1) + wx.PostEvent(self.Parent, evt) + + def GetImagePath(self, bitmap_path): + return GetImagePath(bitmap_path) + + @staticmethod + def GetLineHeight(parent): + line = wx.TextCtrl(parent) + _, height = line.GetSize() + line.Destroy() + return height + + def on_set_lang_clicked(self, evt): + menu = LangSettingPopMenu(SETTING_MANAGER.language) + self.PopupMenu(menu) + menu.Destroy() + + def clear_content(self): + for i in self.model_order_summary, self.model_price_summary: + i.clear_content() + + def on_region_changed(self, evt): + SETTING_MANAGER.set_order_region(self.radio_box_order_region.GetSelection()) + self.clear_content() + ev = OrderRegionChanged(-1) + wx.PostEvent(self.Parent, ev) diff --git a/kicad_amf_plugin/gui/summary/ui_summary_panel.fbp b/kicad_amf_plugin/gui/summary/ui_summary_panel.fbp new file mode 100644 index 0000000..44c2e5c --- /dev/null +++ b/kicad_amf_plugin/gui/summary/ui_summary_panel.fbp @@ -0,0 +1,443 @@ + + + + + ; + Python + 1 + source_name + 0 + 0 + + UTF-8 + connect + ui_summary_panel + 1000 + none + GetImagePath + + 1 + UiSummaryPanel + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 1 + impl_virtual + + + 0 + wxID_ANY + + + UiSummaryPanel + + -1,-1 + ; ; forward_declare + + 0 + + + wxTAB_TRAVERSAL + + + bSizer1 + wxVERTICAL + none + + 5 + wxALIGN_CENTER|wxEXPAND + 0 + + + bSizer3 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxEXPAND + 1 + + wxID_ANY + Preference + + sbSizer4 + wxHORIZONTAL + 1 + none + + 5 + + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "CN" "JP" "EU/USA" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Order Region + 1 + + 0 + + + 0 + + 1 + radio_box_order_region + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxRA_SPECIFY_ROWS + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + PlateButton + 1 + self.btn_set_language=PlateButton(self,bmp= wx.Bitmap( self.GetImagePath(u"language.png" ),wx.BITMAP_TYPE_ANY ), style=PB_STYLE_GRADIENT ) + + 1 + + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + from kicad_amf_plugin.utils.platebtn import PlateButton ,PB_STYLE_GRADIENT + + 0 + + + 0 + + 1 + btn_set_language + 1 + + + protected + 1 + + Resizable + + 1 + + ; ; forward_declare + 0 + + + + + + + + + + + + 5 + wxEXPAND + 1 + + wxID_ANY + Cost detail + + sbSizer1 + wxVERTICAL + 1 + none + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + 1 + + + 0 + wxID_ANY + + + list_price_detail + protected + + + wxDV_ROW_LINES|wxDV_VERT_RULES + ; ; forward_declare + + + + + + + + + + 5 + wxEXPAND|wxFIXED_MINSIZE + 0 + + wxID_ANY + Order Summary + -1,-1 + sbSizer41 + wxVERTICAL + 1 + none + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + 1 + + + 0 + wxID_ANY + + + list_order_summary + protected + + + wxDV_ROW_LINES|wxDV_VERT_RULES + ; ; forward_declare + + + + + + + + + + 5 + wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxEXPAND + 0 + + + bSizer31 + wxVERTICAL + none + + 5 + wxALIGN_CENTER|wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + PlateButton + 1 + self.btn_update_price=PlateButton(self,bmp= wx.Bitmap( self.GetImagePath("query.png" ),wx.BITMAP_TYPE_ANY ),style=PB_STYLE_GRADIENT ,label=_("Update Price")) + + 1 + + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + from kicad_amf_plugin.utils.platebtn import PlateButton ,PB_STYLE_GRADIENT + + 0 + + + 0 + + 1 + btn_update_price + 1 + + + protected + 1 + + Resizable + + 1 + + ; ; forward_declare + 0 + + + + + + + + 5 + wxALIGN_CENTER|wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + PlateButton + 1 + self.btn_place_order=PlateButton(self,bmp= wx.Bitmap( self.GetImagePath("cart.png" ),wx.BITMAP_TYPE_ANY ),style=PB_STYLE_GRADIENT ,label=_("Add to Cart")) + + 1 + + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + from kicad_amf_plugin.utils.platebtn import PlateButton ,PB_STYLE_GRADIENT,PB_STYLE_SQUARE + + 0 + + + 0 + + 1 + btn_place_order + 1 + + + protected + 1 + + Resizable + + 1 + + ; ; forward_declare + 0 + + + + + + + + + + + + diff --git a/kicad_amf_plugin/gui/summary/ui_summary_panel.py b/kicad_amf_plugin/gui/summary/ui_summary_panel.py new file mode 100644 index 0000000..4a0b0a8 --- /dev/null +++ b/kicad_amf_plugin/gui/summary/ui_summary_panel.py @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc +from kicad_amf_plugin.utils.platebtn import PlateButton, PB_STYLE_GRADIENT +import wx.dataview +from kicad_amf_plugin.utils.platebtn import ( + PlateButton, + PB_STYLE_GRADIENT, + PB_STYLE_SQUARE, +) + + +########################################################################### +## Class UiSummaryPanel +########################################################################### + + +class UiSummaryPanel(wx.Panel): + def __init__( + self, + parent, + id=wx.ID_ANY, + pos=wx.DefaultPosition, + size=wx.Size(-1, -1), + style=wx.TAB_TRAVERSAL, + name=wx.EmptyString, + ): + wx.Panel.__init__( + self, parent, id=id, pos=pos, size=size, style=style, name=name + ) + + bSizer1 = wx.BoxSizer(wx.VERTICAL) + + bSizer3 = wx.BoxSizer(wx.HORIZONTAL) + + sbSizer4 = wx.StaticBoxSizer( + wx.StaticBox(self, wx.ID_ANY, _("Preference")), wx.HORIZONTAL + ) + + radio_box_order_regionChoices = [_("CN"), _("JP"), _("EU/USA")] + self.radio_box_order_region = wx.RadioBox( + sbSizer4.GetStaticBox(), + wx.ID_ANY, + _("Order Region"), + wx.DefaultPosition, + wx.DefaultSize, + radio_box_order_regionChoices, + 1, + wx.RA_SPECIFY_ROWS, + ) + self.radio_box_order_region.SetSelection(0) + sbSizer4.Add(self.radio_box_order_region, 0, 0, 5) + + sbSizer4.Add((0, 0), 1, wx.EXPAND, 5) + + self.btn_set_language = PlateButton( + self, + bmp=wx.Bitmap(self.GetImagePath("language.png"), wx.BITMAP_TYPE_ANY), + style=PB_STYLE_GRADIENT, + ) + sbSizer4.Add(self.btn_set_language, 0, wx.ALL, 5) + + bSizer3.Add(sbSizer4, 1, wx.ALIGN_CENTER | wx.EXPAND, 5) + + bSizer1.Add(bSizer3, 0, wx.ALIGN_CENTER | wx.EXPAND, 5) + + sbSizer1 = wx.StaticBoxSizer( + wx.StaticBox(self, wx.ID_ANY, _("Cost detail")), wx.VERTICAL + ) + + self.list_price_detail = wx.dataview.DataViewCtrl( + sbSizer1.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + wx.dataview.DV_ROW_LINES | wx.dataview.DV_VERT_RULES, + ) + sbSizer1.Add(self.list_price_detail, 1, wx.ALL | wx.EXPAND, 5) + + bSizer1.Add(sbSizer1, 1, wx.EXPAND, 5) + + sbSizer41 = wx.StaticBoxSizer( + wx.StaticBox(self, wx.ID_ANY, _("Order Summary")), wx.VERTICAL + ) + + self.list_order_summary = wx.dataview.DataViewCtrl( + sbSizer41.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + wx.dataview.DV_ROW_LINES | wx.dataview.DV_VERT_RULES, + ) + sbSizer41.Add(self.list_order_summary, 1, wx.ALL | wx.EXPAND, 5) + + bSizer1.Add(sbSizer41, 0, wx.EXPAND | wx.FIXED_MINSIZE, 5) + + bSizer31 = wx.BoxSizer(wx.VERTICAL) + + self.btn_update_price = PlateButton( + self, + bmp=wx.Bitmap(self.GetImagePath("query.png"), wx.BITMAP_TYPE_ANY), + style=PB_STYLE_GRADIENT, + label=_("Update Price"), + ) + bSizer31.Add(self.btn_update_price, 1, wx.ALIGN_CENTER | wx.ALL | wx.EXPAND, 5) + + self.btn_place_order = PlateButton( + self, + bmp=wx.Bitmap(self.GetImagePath("cart.png"), wx.BITMAP_TYPE_ANY), + style=PB_STYLE_GRADIENT, + label=_("Add to Cart"), + ) + bSizer31.Add(self.btn_place_order, 1, wx.ALIGN_CENTER | wx.ALL | wx.EXPAND, 5) + + bSizer1.Add( + bSizer31, + 0, + wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, + 5, + ) + + self.SetSizer(bSizer1) + self.Layout() + bSizer1.Fit(self) + + def __del__(self): + pass + + # Virtual image path resolution method. Override this in your derived class. + def GetImagePath(self, bitmap_path): + return bitmap_path diff --git a/Huaqiu.png b/kicad_amf_plugin/icon/Huaqiu.png similarity index 100% rename from Huaqiu.png rename to kicad_amf_plugin/icon/Huaqiu.png diff --git a/kicad_amf_plugin/icon/__init__.py b/kicad_amf_plugin/icon/__init__.py new file mode 100644 index 0000000..2b25d78 --- /dev/null +++ b/kicad_amf_plugin/icon/__init__.py @@ -0,0 +1,7 @@ +import os + +ICON_ROOT = os.path.dirname(__file__) + + +def GetImagePath(bitmap_path): + return os.path.join(ICON_ROOT, bitmap_path) diff --git a/kicad_amf_plugin/icon/cart.png b/kicad_amf_plugin/icon/cart.png new file mode 100644 index 0000000000000000000000000000000000000000..edd684ba5c65317522d3a6df225fd946ce4ba942 GIT binary patch literal 303 zcmV+~0nq-5P)Px#=}AOER5(wi)1gX4K@`UE-+cs&7z~ERN3g2hqAV8s`Uqm(hcNg628+#NSewD1 zMiERK)Ud1@6pPA{JFr}4yyzVmW;o}}|NG8?sdQXb$M@y|UpU78U!Y9~0g2c~3*-i` zQBwk(762g-Yd5_u0ouAqPKyry4S2%}UVb6;aE*oB3?8wA+Xf(t7qNr`d|*2VxWW)? z*upZR-*EPhDW1_!0?i?w;Q~i(Lnr|v9*U#-jCr<7&$u|m-FzL}Un#gG}IiSdSZS_al@enD9nWrV>FPZ9GbF;V;>3!4R5h!&l*yWms)fp*; zbE+zrtqtxc246JL3@V=P33QTbNswPKgXpP0KRm8>vt8hOC=|iCXpZbY-M71fKOOen zcYd-}TI0s^K=7Hz>p4)vFHaZ85RLOwC*Ce~TOQe1 zMJ8JCTX)DE;ub7czr?^<8@=K3%YYAOf*!|zJp6l6kM19b6sL|Q_OH19nY#NlUF-Ck zJjrRQ_Sl)PAi tK}4%Uu=L@z1u+K|Yr<64I<4)>k3XwxcjM-UOTbWI@O1TaS?83{1OTB{*A4&x literal 0 HcmV?d00001 diff --git a/kicad_amf_plugin/icon/language.png b/kicad_amf_plugin/icon/language.png new file mode 100644 index 0000000000000000000000000000000000000000..e4c20e199d8b4f95486539670f6c40c7d3759064 GIT binary patch literal 681 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k3?#4J%UA`Z@&kNAT-^(NfK0jpwhuy=fR?G2 z1o;Ish}W^q-SVidn?v(h*d!&xoi~Hy&I|F_?3ed(o?f25VUfzu>`%)c>W4BgFdp%A zaSX9I-8$vwv}OeX7wG^-N5P}Dr@#HbZy_ak@rlnXMaH7s7mIirmQQ;5LhG!TJfmGo zY)$BN-l_bhN~Ot<+*Y2b<>1fj5PEXV^O1AUt=z!K*}Gh7W?yA6s~K~Y=R8mrRnG5s@IcK7k#s=u@Uwq?kILp#4Nyfv@z&g~i3o?T4Q*Ick~ zrq`7ZD{p-{ogVtUC{%AY$LV>_v-BsG@yU^iG zU>?`a4MH22ZS{VyJAdYB5iKnTtEAI!!y^-|Yo%>uuAK_!KVk6hcH_&X2OqdLu2^eu zciz*_C2diT($kNNYJFaHL#Wolb(-1S;^pl|7dlU#uUp5tsBX?@_mb86%eK!dJM-rE z*KF18yPLZ*HtL=FYg~GjRmt4PqOfw=nf?1^z3x}8_5CHf$@u8CTcW|wb8ZTpHCujr zbw)g!k$tU(nE$_tivPa+6T5e|tH6V=G~kh<$ls?Mw;gB~>rX!0CH8NsNr=J^Rmqq4 e1$^YE{$n_rBemv1!~SYeYV&mUb6Mw<&;$U;!v$^t literal 0 HcmV?d00001 diff --git a/kicad_amf_plugin/icon/query.png b/kicad_amf_plugin/icon/query.png new file mode 100644 index 0000000000000000000000000000000000000000..e0943d8e1ac4f5261c19a77314b8fea62f7739b9 GIT binary patch literal 296 zcmV+@0oVSCP)Px#;z>k7R5(wi)1gj-F%-q|-}eLvBo+lE6X+!vh9W3Xh-nfeL4w3!C-wwnb6Y}? zBxq2}o`DCz63AV;r1>`Zx~-;7)Bf+dr>B(-N0sjXtjVczz None: + if board is None: + raise ("Empty kicad pcb board!") + self._board = board + + @property + def board(self): + return self._board + + +def load_board_manager(): + board = GetBoard() + if board: + return BoardManager(board) + else: + dlg = wx.FileDialog( + None, + message="Choose a kicad pcb file", + defaultDir=os.getcwd(), + defaultFile="", + wildcard="*.kicad_pcb", + style=wx.FD_OPEN + | wx.FD_MULTIPLE + | wx.FD_CHANGE_DIR + | wx.FD_FILE_MUST_EXIST + | wx.FD_PREVIEW, + ) + + # Show the dialog and retrieve the user response. If it is the OK response, + # process the data. + if dlg.ShowModal() == wx.ID_OK: + # This returns a Python list of files that were selected. + paths = dlg.GetPaths() + if len(paths): + board = LoadBoard(paths[0]) + dlg.Destroy() + return BoardManager(board) diff --git a/fabrication.py b/kicad_amf_plugin/kicad/fabrication_data_generator.py similarity index 67% rename from fabrication.py rename to kicad_amf_plugin/kicad/fabrication_data_generator.py index f1ad5cf..78d8f8f 100644 --- a/fabrication.py +++ b/kicad_amf_plugin/kicad/fabrication_data_generator.py @@ -4,6 +4,8 @@ import re from pathlib import Path from zipfile import ZipFile +import contextlib +import shutil from pcbnew import ( EXCELLON_WRITER, @@ -34,25 +36,34 @@ from .helpers import get_exclude_from_pos, get_footprint_by_ref, get_smd, is_nightly -class Fabrication: - def __init__(self, parent): +class FabricationDataGenerator: + def __init__(self, board): self.logger = logging.getLogger(__name__) - self.parent = parent - self.board = GetBoard() + self.board = board self.corrections = [] self.path, self.filename = os.path.split(self.board.GetFileName()) - self.create_folders() + + @property + def nextpcb_root(self): + return os.path.join(self.path, "nextpcb_amf") + + @property + def output_dir(self): + return os.path.join(self.nextpcb_root, "output_files") + + def __del__(self): + if os.path.exists(self.output_dir): + os.remove(self.output_dir) def create_folders(self): """Create output folders if they not already exist.""" - self.outputdir = os.path.join(self.path, "nextpcb_amf", "output_files") - Path(self.outputdir).mkdir(parents=True, exist_ok=True) + Path(self.output_dir).mkdir(parents=True, exist_ok=True) self.gerberdir = os.path.join(self.path, "nextpcb_amf", "gerber") Path(self.gerberdir).mkdir(parents=True, exist_ok=True) def fill_zones(self): """Refill copper zones following user prompt.""" - #if self.parent.settings.get("gerber", {}).get("fill_zones", True): + # if self.parent.settings.get("gerber", {}).get("fill_zones", True): filler = ZONE_FILLER(self.board) zones = self.board.Zones() filler.Fill(zones) @@ -122,60 +133,39 @@ def generate_geber(self, layer_count=None): if not layer_count: layer_count = self.board.GetCopperLayerCount() + plot_plan_top = [ + ("CuTop", F_Cu, "Top layer"), + ("SilkTop", F_SilkS, "Silk top"), + ("MaskTop", F_Mask, "Mask top"), + ("PasteTop", F_Paste, "Paste top"), + ] + plot_plan_bottom = [ + ("CuBottom", B_Cu, "Bottom layer"), + ("SilkBottom", B_SilkS, "Silk top"), + ("MaskBottom", B_Mask, "Mask bottom"), + ("PasteBottom", B_Paste, "Paste bottom"), + ("EdgeCuts", Edge_Cuts, "Edges"), + ("VScore", Cmts_User, "V score cut"), + ] + + plot_plan = [] + + # Single sided PCB if layer_count == 1: - plot_plan = [ - ("CuTop", F_Cu, "Top layer"), - ("SilkTop", F_SilkS, "Silk top"), - ("MaskTop", F_Mask, "Mask top"), - ("PasteTop", F_Paste, "Paste top"), - ("EdgeCuts", Edge_Cuts, "Edges"), - ("VScore", Cmts_User, "V score cut"), - ] + plot_plan = plot_plan_top + plot_plan_bottom[-2:] + # Double sided PCB elif layer_count == 2: - plot_plan = [ - ("CuTop", F_Cu, "Top layer"), - ("SilkTop", F_SilkS, "Silk top"), - ("MaskTop", F_Mask, "Mask top"), - ("PasteTop", F_Paste, "Paste top"), - ("CuBottom", B_Cu, "Bottom layer"), - ("SilkBottom", B_SilkS, "Silk top"), - ("MaskBottom", B_Mask, "Mask bottom"), - ("PasteBottom", B_Paste, "Paste bottom"), - ("EdgeCuts", Edge_Cuts, "Edges"), - ("VScore", Cmts_User, "V score cut"), - ] - elif layer_count == 4: - plot_plan = [ - ("CuTop", F_Cu, "Top layer"), - ("SilkTop", F_SilkS, "Silk top"), - ("MaskTop", F_Mask, "Mask top"), - ("PasteTop", F_Paste, "Paste top"), - ("CuIn1", In1_Cu, "Inner layer 1"), - ("CuIn2", In2_Cu, "Inner layer 2"), - ("CuBottom", B_Cu, "Bottom layer"), - ("SilkBottom", B_SilkS, "Silk top"), - ("MaskBottom", B_Mask, "Mask bottom"), - ("PasteBottom", B_Paste, "Paste bottom"), - ("EdgeCuts", Edge_Cuts, "Edges"), - ("VScore", Cmts_User, "V score cut"), - ] - elif layer_count == 6: - plot_plan = [ - ("CuTop", F_Cu, "Top layer"), - ("SilkTop", F_SilkS, "Silk top"), - ("MaskTop", F_Mask, "Mask top"), - ("PasteTop", F_Paste, "Paste top"), - ("CuIn1", In1_Cu, "Inner layer 1"), - ("CuIn2", In2_Cu, "Inner layer 2"), - ("CuIn3", In3_Cu, "Inner layer 3"), - ("CuIn4", In4_Cu, "Inner layer 4"), - ("CuBottom", B_Cu, "Bottom layer"), - ("SilkBottom", B_SilkS, "Silk top"), - ("MaskBottom", B_Mask, "Mask bottom"), - ("PasteBottom", B_Paste, "Paste bottom"), - ("EdgeCuts", Edge_Cuts, "Edges"), - ("VScore", Cmts_User, "V score cut"), - ] + plot_plan = plot_plan_top + plot_plan_bottom + # Everything with inner layers + else: + plot_plan = ( + plot_plan_top + + [ + (f"CuIn{layer}", layer, f"Inner layer {layer}") + for layer in range(1, layer_count - 1) + ] + + plot_plan_bottom + ) for layer_info in plot_plan: if layer_info[1] <= B_Cu: @@ -205,8 +195,7 @@ def generate_excellon(self): def zip_gerber_excellon(self): """Zip Gerber and Excellon files, ready for upload.""" - zipname = f"GERBER-{self.filename.split('.')[0]}.zip" - with ZipFile(os.path.join(self.outputdir, zipname), "w") as zipfile: + with ZipFile(self.zip_file_path, "w") as zipfile: for folderName, subfolders, filenames in os.walk(self.gerberdir): for filename in filenames: if not filename.endswith(("gbr", "drl", "pdf")): @@ -218,10 +207,10 @@ def zip_gerber_excellon(self): def generate_cpl(self): """Generate placement file (CPL).""" cplname = f"CPL-{self.filename.split('.')[0]}.csv" - #self.corrections = self.parent.library.get_all_correction_data() + # self.corrections = self.parent.library.get_all_correction_data() aux_orgin = self.board.GetDesignSettings().GetAuxOrigin() with open( - os.path.join(self.outputdir, cplname), "w", newline="", encoding="utf-8" + os.path.join(self.output_dir, cplname), "w", newline="", encoding="utf-8" ) as csvfile: writer = csv.writer(csvfile, delimiter=",") writer.writerow( @@ -239,7 +228,7 @@ def generate_cpl(self): part[2], ToMM(position.x), ToMM(position.y) * -1, - '', + "", "top" if fp.GetLayer() == 0 else "bottom", ] ) @@ -249,10 +238,28 @@ def generate_bom(self): """Generate BOM file.""" bomname = f"BOM-{self.filename.split('.')[0]}.csv" with open( - os.path.join(self.outputdir, bomname), "w", newline="", encoding="utf-8" + os.path.join(self.output_dir, bomname), "w", newline="", encoding="utf-8" ) as csvfile: writer = csv.writer(csvfile, delimiter=",") writer.writerow(["Value", "Designator", "Footprint", "MPN"]) for part in self.parent.store.read_bom_parts(): writer.writerow(part) self.logger.info("Finished generating BOM file") + + @property + def zip_file_path(self): + return os.path.join( + self.output_dir, f"GERBER-{self.filename.split('.')[0]}.zip" + ) + + @contextlib.contextmanager + def create_kicad_pcb_file(self): + try: + self.create_folders() + self.fill_zones() + self.generate_geber(None) + self.generate_excellon() + self.zip_gerber_excellon() + yield self.zip_file_path + except Exception as error: + logging.error(f"Error while processing kicad pcb file ,detail : {error}") diff --git a/helpers.py b/kicad_amf_plugin/kicad/helpers.py similarity index 100% rename from helpers.py rename to kicad_amf_plugin/kicad/helpers.py diff --git a/kicad_amf_plugin/language/__init__.py b/kicad_amf_plugin/language/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kicad_amf_plugin/language/geni18n.py b/kicad_amf_plugin/language/geni18n.py new file mode 100644 index 0000000..c3fd104 --- /dev/null +++ b/kicad_amf_plugin/language/geni18n.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +""" +This will generate the .pot and .mo files for the application domain and +languages defined below. + +The .po and .mo files are placed as per convention in + +"appfolder/locale/lang/LC_MESSAGES" + +The .pot file is placed in the locale folder. + +This script or something similar should be added to your build process. + +The actual translation work is normally done using a tool like poEdit or +similar, it allows you to generate a particular language catalog from the .pot +file or to use the .pot to merge new translations into an existing language +catalog. + +""" +import subprocess +import sys +import os +from lang_const import CODE_TO_NAME, LANG_DOMAIN, DEFAULT_LANG + +# we remove English as source code strings are in English +supportedLang = [] +for code in CODE_TO_NAME: + if CODE_TO_NAME[code] != DEFAULT_LANG: + supportedLang.append(code) + + +appFolder = os.path.abspath( + os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +) + +# if False: +if os.name == "nt": + # setup some stuff to get at Python I18N tools/utilities + pyExe = sys.executable + pyFolder = os.path.split(pyExe)[0] + pyToolsFolder = os.path.join(pyFolder, "Tools") + pyI18nFolder = os.path.join(pyToolsFolder, "i18n") + pyGettext = os.path.join(pyI18nFolder, "pygettext.py") + pyMsgfmt = os.path.join(pyI18nFolder, "msgfmt.py") + outFolder = os.path.join(appFolder, "language", "locale") + # build command for pygettext + gtOptions = "-a -d %s -o %s.pot -p %s %s" + + tCmd = ( + pyExe + + " " + + pyGettext + + " " + + (gtOptions % (LANG_DOMAIN, LANG_DOMAIN, outFolder, appFolder)) + ) + print("Generating the .pot file") + print("cmd: %s" % tCmd) + rCode = subprocess.call(tCmd) + print("return code: %s\n\n" % rCode) + + for tLang in supportedLang: + # build command for msgfmt + langDir = os.path.join(appFolder, (f"language/locale/{tLang}/LC_MESSAGES")) + if not os.path.exists(langDir): + os.mkdir(langDir) + poFile = os.path.join(langDir, LANG_DOMAIN + ".po") + tCmd = pyExe + " " + pyMsgfmt + " " + poFile + + print("Generating the .mo file") + print("cmd: %s" % tCmd) + rCode = subprocess.call(tCmd) + print("return code: %s\n\n" % rCode) +else: + from pythongettext.msgfmt import Msgfmt + + # Simply run the msg format cmd to update the .mo on the Ubuntu ci server + for tLang in supportedLang: + # build command for msgfmt + langDir = os.path.join(appFolder, (f"language/locale/{tLang}/LC_MESSAGES")) + if not os.path.exists(langDir): + os.mkdir(langDir) + poFile = os.path.join(langDir, LANG_DOMAIN + ".po") + moFile = os.path.join(langDir, LANG_DOMAIN + ".mo") + generator = Msgfmt(poFile).get() + with open(moFile, "wb") as f: + f.write(generator) diff --git a/kicad_amf_plugin/language/lang_const.py b/kicad_amf_plugin/language/lang_const.py new file mode 100644 index 0000000..ae111f1 --- /dev/null +++ b/kicad_amf_plugin/language/lang_const.py @@ -0,0 +1,39 @@ +# language domain +LANG_DOMAIN = "kicad_amf_plugin" + + +ENGLISH = "English" + +DEFAULT_LANG = ENGLISH + + +CODE_TO_NAME = {"en": "English", "ja": "Japanese", "zh_CN": "Chinese"} + + +def get_supported_language(): + import wx + + return ( + wx.LANGUAGE_ENGLISH, + wx.LANGUAGE_JAPANESE_JAPAN, + wx.LANGUAGE_CHINESE_SIMPLIFIED, + ) + + +def code_to_wx(): + import wx + + return { + "en": wx.LANGUAGE_ENGLISH, + "ja": wx.LANGUAGE_JAPANESE_JAPAN, + "zh_CN": wx.LANGUAGE_CHINESE_SIMPLIFIED, + } + + +def fool_translation(): + # Just for triggering the gettext + import wx + + _ = wx.GetTranslation + TRANSLATION = [_("English"), _("Japanese"), _("Chinese")] + return TRANSLATION diff --git a/kicad_amf_plugin/language/lang_setting_pop_menu.py b/kicad_amf_plugin/language/lang_setting_pop_menu.py new file mode 100644 index 0000000..3c8b719 --- /dev/null +++ b/kicad_amf_plugin/language/lang_setting_pop_menu.py @@ -0,0 +1,35 @@ +import wx +from .lang_const import CODE_TO_NAME, code_to_wx +from kicad_amf_plugin.settings.setting_manager import SETTING_MANAGER + + +WX_ID_MAP = code_to_wx() + + +class LangSettingPopMenu(wx.Menu): + def __init__(self, current_lang_id: int): + super().__init__() + for lang in enumerate(CODE_TO_NAME): + id, code = lang + item = wx.MenuItem(id=id, text=_(CODE_TO_NAME[code]), kind=wx.ITEM_CHECK) + wx_id = WX_ID_MAP[code] + if current_lang_id == wx_id: + item.Check(True) + else: + item.Check(False) + self.Append(item) + if wx.LANGUAGE_ENGLISH == wx_id: + self.Bind(wx.EVT_MENU, self.setup_en, id=id) + elif wx.LANGUAGE_JAPANESE_JAPAN == wx_id: + self.Bind(wx.EVT_MENU, self.setup_jp, id=id) + elif wx.LANGUAGE_CHINESE_SIMPLIFIED == wx_id: + self.Bind(wx.EVT_MENU, self.setup_zh, id=id) + + def setup_en(self, evt): + SETTING_MANAGER.set_language(wx.LANGUAGE_ENGLISH) + + def setup_jp(self, evt): + SETTING_MANAGER.set_language(wx.LANGUAGE_JAPANESE_JAPAN) + + def setup_zh(self, evt): + SETTING_MANAGER.set_language(wx.LANGUAGE_CHINESE_SIMPLIFIED) diff --git a/kicad_amf_plugin/language/locale/ja/LC_MESSAGES/kicad_amf_plugin.po b/kicad_amf_plugin/language/locale/ja/LC_MESSAGES/kicad_amf_plugin.po new file mode 100644 index 0000000..281cc1e --- /dev/null +++ b/kicad_amf_plugin/language/locale/ja/LC_MESSAGES/kicad_amf_plugin.po @@ -0,0 +1,740 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2023-10-23 09:59+0800\n" +"PO-Revision-Date: 2023-10-23 10:08+0800\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" +"X-Generator: Poedit 3.4\n" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\app_base.py:45 +msgid "Unsupported layer count!" +msgstr "ボードレイヤーの数はサポートされていません!" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\app_base.py:54 +msgid "" +"Restart the plugin to apply the new locale ?\n" +"For full translation(including the options), restarting KiCad is required" +msgstr "" +"プラグインを再起動して新しい言語設定を適用しますか?\n" +"完全な翻訳 (オプションを含む) が必要な場合は、KiCad を再起動してください" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\app_base.py:55 +msgid "Tip" +msgstr "先端" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\main_frame.py:75 +msgid "HQ NextPCB Active Manufacturing" +msgstr "HQネクストPCBアクティブ製造" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\main_frame.py:224 +msgid "No available url for querying price in current region" +msgstr "現在の地域の価格を照会するための使用可能なURLがありません" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\main_frame.py:244 +msgid "Incorrect form parameter: " +msgstr "フォームパラメータが正しくありません: " + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\main_frame.py:258 +msgid "No available url for placing order in current region" +msgstr "現在の地域で注文するための利用可能なURLがありません" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\bom_price_model.py:11 +msgid "BOM" +msgstr "BOM" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\order_summary_model.py:14 +msgid "days" +msgstr "日" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\order_summary_model.py:14 +msgid "hours" +msgstr "時" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:7 +msgid "testfee" +msgstr "受験料" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:8 +msgid "plate" +msgstr "撮影料" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:9 +msgid "clc" +msgstr "ボード料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:10 +msgid "gch" +msgstr "エンジニアリングコスト" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:11 +msgid "bgafee" +msgstr "bga料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:12 +msgid "impendancefee" +msgstr "インピーダンス料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:13 +msgid "pin" +msgstr "賦課手数料" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:14 +msgid "copperfee" +msgstr "銅厚料" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:15 +msgid "colorfee" +msgstr "カラー料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:16 +msgid "sprayfee" +msgstr "スパッタリング料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:17 +msgid "extraurgentfee" +msgstr "迅速な料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:18 +msgid "viasfee" +msgstr "ビア料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:19 +msgid "bankongfee" +msgstr "半穴料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:20 +msgid "utilizationfee" +msgstr "利用料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:21 +msgid "discountfee" +msgstr "優待額" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:22 +msgid "boardfee" +msgstr "貨物" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:23 +msgid "difficultyfee" +msgstr "難易度クラフト料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:24 +msgid "coverfee" +msgstr "はんだマスク適用料" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:25 +msgid "blindfee" +msgstr "ブラインド埋葬料" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:26 +msgid "pressingfee" +msgstr "ラミネート料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:27 +msgid "cjfee" +msgstr "沈没料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:28 +msgid "pthfee" +msgstr "めっきスルーホール料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:29 +msgid "viainpadfee" +msgstr "プレート内穴料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:30 +msgid "reportfee" +msgstr "報告料" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:31 +msgid "populerfee" +msgstr "人気のないクラフト料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:32 +msgid "paperfee" +msgstr "論文代" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:33 +msgid "userstampfee" +msgstr "ゲスト編集料なし" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:34 +msgid "acceptancefee" +msgstr "受入基準料" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:35 +msgid "crossfee" +msgstr "フォークボード料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:36 +msgid "invoicefee" +msgstr "請求手数料" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:37 +msgid "insurancefee" +msgstr "保険" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:38 +msgid "zkfee" +msgstr "掘削料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:39 +msgid "cutfee" +msgstr "カット料金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:40 +msgid "luocao" +msgstr "グルーブマークアップ" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:41 +msgid "luocheng" +msgstr "ロチェンマークアップ" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\smt_price_model.py:11 +msgid "SMT" +msgstr "SMT" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\summary_panel.py:29 +msgid "Build Time" +msgstr "納期" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\summary_panel.py:36 +msgid "Qty" +msgstr "量" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\summary_panel.py:43 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\summary_panel.py:64 +msgid "Price" +msgstr "価格" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\summary_panel.py:57 +msgid "Item" +msgstr "アイテム" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:45 +msgid "Preference" +msgstr "好み" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:48 +msgid "CN" +msgstr "CN" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:48 +msgid "EU/USA" +msgstr "EU/USA" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:48 +msgid "JP" +msgstr "JP" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:52 +msgid "Order Region" +msgstr "注文地域" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:76 +msgid "Cost detail" +msgstr "費用の詳細" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:91 +msgid "Order Summary" +msgstr "注文の概要" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:111 +msgid "Update Price" +msgstr "価格を更新する" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:119 +msgid "Add to Cart" +msgstr "カートに追加" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\language\lang_const.py:38 +msgid "Chinese" +msgstr "簡体字中国語" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\language\lang_const.py:38 +msgid "English" +msgstr "英語" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\language\lang_const.py:38 +msgid "Japanese" +msgstr "日本語" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:37 +msgid "Single Piece" +msgstr "単品出荷" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:38 +msgid "Panel by Customer" +msgstr "顧客別パネル" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:39 +msgid "Panel by NextPCB" +msgstr "連続チップ(NextPCBスペル)" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:50 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:14 +msgid "N/A" +msgstr "N/A" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:51 +msgid "Left & Right" +msgstr "左と右" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:52 +msgid "Top & Bottom" +msgstr "トップ&ボトム" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:53 +msgid "All 4 sides" +msgstr "全4面" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:120 +msgid "Panel Type X value isn't valid. Please input valid value." +msgstr "スライスの長さが無効です。有効な整数を入力してください。" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:121 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:128 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:136 +msgid "Error" +msgstr "エロー" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:127 +msgid "Panel Type Y value isn't valid. Please input valid value." +msgstr "連続幅が無効なため、有効な整数を入力してください。" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:135 +msgid "Break-away Rail value isn't valid. Please input valid value." +msgstr "プロセスフレームサイズが無効なため、有効な数値を入力してください。" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:324 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:207 +msgid "Size (single)" +msgstr "サイズ(シングル)" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:325 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:162 +msgid "Qty(single)" +msgstr "数量(シングル)" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:326 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:191 +msgid "Pcs" +msgstr "ある" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:328 +msgid "Size (set)" +msgstr "モノリシック サイズ" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:329 +msgid "Qty(Set)" +msgstr "連続するピースの数" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:330 +msgid "Set" +msgstr "Set" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:38 +msgid "Base Info" +msgstr "ベース情報" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:49 +msgid "Material Type" +msgstr "素材タイプ" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:56 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:70 +msgid "Non-conductive base material" +msgstr "非導電性基材" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:77 +msgid "Layer Count" +msgstr "レイヤー数" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:101 +msgid "Board TG" +msgstr "ボード TG" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:132 +msgid "Board Type" +msgstr "ボードタイプ" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:139 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:154 +msgid "The finished PCB are by single or by panel" +msgstr "完成したPCBは単一またはパネルごとです" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:219 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:315 +msgid "X:" +msgstr "X:" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:246 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:287 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:435 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:74 +msgid "mm" +msgstr "mm" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:260 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:356 +msgid "Y:" +msgstr "Y:" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:303 +msgid "Panel Type" +msgstr "パネルの種類" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:342 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:383 +msgid "pcs" +msgstr "pcs" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:401 +msgid "Break-away Rail" +msgstr "離脱レール" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:13 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:25 +msgid "Need" +msgstr "必要" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:14 +msgid "Need & Auto Confirm" +msgstr "&自動確認が必要" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:15 +msgid "Need & Manual Confirm" +msgstr "&手動確認が必要です" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:19 +msgid "Accept" +msgstr "受け入れる" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:20 +msgid "Reject" +msgstr "断る" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:26 +msgid "No need" +msgstr "必須ではありません" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:30 +msgid "Add customer stamp" +msgstr "顧客番号を追加する" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:31 +msgid "Add it to specified location" +msgstr "指定した場所にゲスト編集者を追加する" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:32 +msgid "Don't add customer stamp" +msgstr "ゲスト編集なし" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:36 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\utils\constraint.py:6 +msgid "Yes" +msgstr "はい" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:37 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:50 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\utils\constraint.py:6 +msgid "No" +msgstr "いいえ" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:42 +msgid "Sample Test Free" +msgstr "無料サンプルテスト" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:43 +msgid "AOI+Flying Test" +msgstr "AOI+飛行テスト" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:44 +msgid "AOI+Fixture" +msgstr "AOI+フィクスチャ" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:48 +msgid "Electronic" +msgstr "電子" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:48 +msgid "Paper" +msgstr "紙" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:50 +msgid "UL+Week/Year" +msgstr "UL+週/年" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:50 +msgid "UL+Year/Week" +msgstr "UL+年/週" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:35 +msgid "Personalized Service" +msgstr "パーソナライズされたサービス" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:46 +msgid "Electrical Test" +msgstr "電気試験" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:70 +msgid "Approve Working Gerber" +msgstr "作業中のガーバーを承認する" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:94 +msgid "Delivery Report" +msgstr "送達通知" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:118 +msgid "Microsection Analysis Report" +msgstr "微細断面分析レポート" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:142 +msgid "Report Format" +msgstr "レポート形式" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:166 +msgid "UL Mark" +msgstr "ULマーク" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:190 +msgid "Film" +msgstr "Film" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:214 +msgid "Cross Board" +msgstr "フォークプレート" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:238 +msgid "Bulkhead Paper" +msgstr "バルクヘッド紙" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:262 +msgid "User Stamp Process" +msgstr "顧客番号処理" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:286 +msgid "HQ Pack" +msgstr "NextPCB包装" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:311 +msgid "Special Request" +msgstr "特別なリクエスト" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:40 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:50 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:79 +msgid "Green" +msgstr "緑" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:41 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:51 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:80 +msgid "Red" +msgstr "赤" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:42 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:52 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:81 +msgid "Yellow" +msgstr "黄" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:43 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:53 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:82 +msgid "Blue" +msgstr "青" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:44 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:54 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:79 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:80 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:81 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:82 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:83 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:84 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:85 +msgid "White" +msgstr "白" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:45 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:55 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:84 +msgid "Matte Black" +msgstr "マットブラック" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:46 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:56 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:83 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:85 +msgid "Black" +msgstr "黒" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:61 +msgid "Tenting Vias" +msgstr "テンティングビア" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:62 +msgid "Vias not covered" +msgstr "ビアはカバーされていません" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:63 +msgid "Solder Mask Plug (IV-B)" +msgstr "ソルダーマスクプラグ(IV-B)" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:64 +msgid "Non-Conductive Fill" +msgstr "非導電性充填" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:68 +msgid "HASL" +msgstr "HASL" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:69 +msgid "Lead free HASL" +msgstr "鉛フリーHASL" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:70 +msgid "ENIG" +msgstr "ENIG" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:71 +msgid "OSP" +msgstr "OSP" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:34 +msgid "Process info" +msgstr "プロセス情報" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:45 +msgid "PCB Thickness" +msgstr "プリント基板の厚さ" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:88 +msgid "FInsihed Copper weight" +msgstr "仕上げられた銅の重量" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:112 +msgid "Inner Copper Weight" +msgstr "内側の銅の重量" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:136 +msgid "Min Trace/Space Outer" +msgstr "最小トレース/スペースアウター" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:160 +msgid "Min Drilled Hole" +msgstr "最小ドリル穴" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:184 +msgid "Solder Mask Color" +msgstr "はんだマスクの色" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:208 +msgid "Silkscreen" +msgstr "シルクスクリーン" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:232 +msgid "Via Process" +msgstr "プロセス経由" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:256 +msgid "Surface Finish" +msgstr "表面仕上げ" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:280 +msgid "Immersion Gold Thickness" +msgstr "浸漬金の厚さ" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:14 +msgid "Rank 1" +msgstr "ランク1" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:14 +msgid "Rank 2" +msgstr "ランク2" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:14 +msgid "Rank 3" +msgstr "ランク3" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:16 +msgid "Customer Specified Stack up" +msgstr "顧客指定のスタックアップ" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:16 +msgid "No Requirement" +msgstr "要件なし" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:34 +msgid "Special Process" +msgstr "特殊加工" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:45 +msgid "Impedance" +msgstr "インピーダンス" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:69 +msgid "Beveling of G/F" +msgstr "G/Fの面取り加工" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:93 +msgid "Plated Half Holes" +msgstr "メッキ半穴" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:117 +msgid "Pad Hole" +msgstr "パッド穴" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:141 +msgid "HDI(Buried/blind vais)" +msgstr "HDI(埋没/ブラインドゴーイング)" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:165 +msgid "HDI Structure" +msgstr "HDIの構造" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:189 +msgid "Stack up" +msgstr "積み重ねる" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:213 +msgid "Metallized Sides Count" +msgstr "" + +#~ msgid "Restart the plugin to apply the new locale ?" +#~ msgstr "プラグインを再起動して新しいロケールを適用しますか?" + +#~ msgid "en" +#~ msgstr "英語" + +#~ msgid "ja" +#~ msgstr "日本語" + +#~ msgid "zh_CN" +#~ msgstr "簡体字中国語" + +#~ msgid "PCB Quantity" +#~ msgstr "PCBの数量" + +#~ msgid "Time" +#~ msgstr "時間" + +#~ msgid "Cost" +#~ msgstr "料金" + +#~ msgid "$" +#~ msgstr "$" + +#~ msgid "jp" +#~ msgstr "日本語" diff --git a/kicad_amf_plugin/language/locale/zh_CN/LC_MESSAGES/generate_param_mapping.py b/kicad_amf_plugin/language/locale/zh_CN/LC_MESSAGES/generate_param_mapping.py new file mode 100644 index 0000000..e2c9269 --- /dev/null +++ b/kicad_amf_plugin/language/locale/zh_CN/LC_MESSAGES/generate_param_mapping.py @@ -0,0 +1,18 @@ +import json + +mapping = {} +with open("kicad_amf_plugin.po", encoding="utf-8", errors="ignore") as f: + pair = [] + for line in f.readlines(): + if line.startswith("msgstr"): + pair.append((line.removeprefix("msgstr").strip()).replace('"', "")) + elif line.startswith("msgid"): + pair.append(line.removeprefix("msgid").strip().replace('"', "")) + if len(pair) == 2: + mapping[pair[0]] = pair[1] + pair = [] + + +with open("mapping.json", "w", encoding="utf-8") as f: + (json.dump(mapping, f, ensure_ascii=False)) + # f.write(str(mapping)) diff --git a/kicad_amf_plugin/language/locale/zh_CN/LC_MESSAGES/kicad_amf_plugin.po b/kicad_amf_plugin/language/locale/zh_CN/LC_MESSAGES/kicad_amf_plugin.po new file mode 100644 index 0000000..123b572 --- /dev/null +++ b/kicad_amf_plugin/language/locale/zh_CN/LC_MESSAGES/kicad_amf_plugin.po @@ -0,0 +1,821 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2023-10-23 09:59+0800\n" +"PO-Revision-Date: 2023-10-23 10:07+0800\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" +"X-Generator: Poedit 3.4\n" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\app_base.py:45 +msgid "Unsupported layer count!" +msgstr "板子层数不支持!" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\app_base.py:54 +msgid "" +"Restart the plugin to apply the new locale ?\n" +"For full translation(including the options), restarting KiCad is required" +msgstr "" +"是否重启插件以应用新的语言设置?\n" +"如果需要完全翻译(包括选项),请重启 KiCad" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\app_base.py:55 +msgid "Tip" +msgstr "提示" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\main_frame.py:75 +msgid "HQ NextPCB Active Manufacturing" +msgstr "HQ NextPCB Active Manufacturing" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\main_frame.py:224 +msgid "No available url for querying price in current region" +msgstr "当前区域无可询价接口" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\main_frame.py:244 +msgid "Incorrect form parameter: " +msgstr "无效的表单参数: " + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\main_frame.py:258 +msgid "No available url for placing order in current region" +msgstr "当前区域无可下单接口" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\bom_price_model.py:11 +msgid "BOM" +msgstr "BOM" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\order_summary_model.py:14 +msgid "days" +msgstr "天" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\order_summary_model.py:14 +msgid "hours" +msgstr "小时" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:7 +msgid "testfee" +msgstr "测试费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:8 +msgid "plate" +msgstr "菲林费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:9 +msgid "clc" +msgstr "板费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:10 +msgid "gch" +msgstr "工程费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:11 +msgid "bgafee" +msgstr "bga费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:12 +msgid "impendancefee" +msgstr "阻抗" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:13 +msgid "pin" +msgstr "拼版费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:14 +msgid "copperfee" +msgstr "铜厚费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:15 +msgid "colorfee" +msgstr "颜色费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:16 +msgid "sprayfee" +msgstr "喷镀费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:17 +msgid "extraurgentfee" +msgstr "加急费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:18 +msgid "viasfee" +msgstr "过孔费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:19 +msgid "bankongfee" +msgstr "半孔费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:20 +msgid "utilizationfee" +msgstr "使用费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:21 +msgid "discountfee" +msgstr "优惠金额" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:22 +msgid "boardfee" +msgstr "运费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:23 +msgid "difficultyfee" +msgstr "难度工艺费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:24 +msgid "coverfee" +msgstr "阻焊覆盖费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:25 +msgid "blindfee" +msgstr "盲埋孔费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:26 +msgid "pressingfee" +msgstr "叠层结构费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:27 +msgid "cjfee" +msgstr "沉金费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:28 +msgid "pthfee" +msgstr "电镀通孔费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:29 +msgid "viainpadfee" +msgstr "盘中孔费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:30 +msgid "reportfee" +msgstr "报告费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:31 +msgid "populerfee" +msgstr "冷门工艺费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:32 +msgid "paperfee" +msgstr "隔白纸费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:33 +msgid "userstampfee" +msgstr "不加客编费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:34 +msgid "acceptancefee" +msgstr "验收标准费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:35 +msgid "crossfee" +msgstr "打叉板费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:36 +msgid "invoicefee" +msgstr "发票费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:37 +msgid "insurancefee" +msgstr "保险费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:38 +msgid "zkfee" +msgstr "钻孔费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:39 +msgid "cutfee" +msgstr "割刀费" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:40 +msgid "luocao" +msgstr "罗槽加价" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\pcb_price_model.py:41 +msgid "luocheng" +msgstr "罗程加价" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\smt_price_model.py:11 +msgid "SMT" +msgstr "SMT" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\summary_panel.py:29 +msgid "Build Time" +msgstr "交期" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\summary_panel.py:36 +msgid "Qty" +msgstr "数量" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\summary_panel.py:43 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\summary_panel.py:64 +msgid "Price" +msgstr "价格" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\summary_panel.py:57 +msgid "Item" +msgstr "项目" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:45 +msgid "Preference" +msgstr "偏好设置" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:48 +msgid "CN" +msgstr "中国大陆" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:48 +msgid "EU/USA" +msgstr "欧美" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:48 +msgid "JP" +msgstr "日本" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:52 +msgid "Order Region" +msgstr "订购区域" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:76 +msgid "Cost detail" +msgstr "价格明细" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:91 +msgid "Order Summary" +msgstr "订单信息汇总" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:111 +msgid "Update Price" +msgstr "更新价格" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\gui\summary\ui_summary_panel.py:119 +msgid "Add to Cart" +msgstr "加入购物车" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\language\lang_const.py:38 +msgid "Chinese" +msgstr "简体中文" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\language\lang_const.py:38 +msgid "English" +msgstr "英文" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\language\lang_const.py:38 +msgid "Japanese" +msgstr "日文" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:37 +msgid "Single Piece" +msgstr "单片出货" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:38 +msgid "Panel by Customer" +msgstr "连片(按文件)" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:39 +msgid "Panel by NextPCB" +msgstr "连片(华秋代拼)" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:50 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:14 +msgid "N/A" +msgstr "无" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:51 +msgid "Left & Right" +msgstr "左右" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:52 +msgid "Top & Bottom" +msgstr "上下" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:53 +msgid "All 4 sides" +msgstr "四边" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:120 +msgid "Panel Type X value isn't valid. Please input valid value." +msgstr "连片长度无效,请输入有效整数." + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:121 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:128 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:136 +msgid "Error" +msgstr "错误" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:127 +msgid "Panel Type Y value isn't valid. Please input valid value." +msgstr "连片宽度无效,请输入有效整数." + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:135 +msgid "Break-away Rail value isn't valid. Please input valid value." +msgstr "工艺边框尺寸无效,请输入有效数字." + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:324 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:207 +msgid "Size (single)" +msgstr "单片尺寸" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:325 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:162 +msgid "Qty(single)" +msgstr "单片数量" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:326 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:191 +msgid "Pcs" +msgstr "片" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:328 +msgid "Size (set)" +msgstr "单片尺寸" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:329 +msgid "Qty(Set)" +msgstr "连片数量" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\base_info_view.py:330 +msgid "Set" +msgstr "Set" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:38 +msgid "Base Info" +msgstr "基础信息" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:49 +msgid "Material Type" +msgstr "板材" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:56 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:70 +msgid "Non-conductive base material" +msgstr "非导电基材" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:77 +msgid "Layer Count" +msgstr "板子层数" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:101 +msgid "Board TG" +msgstr "板子TG" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:132 +msgid "Board Type" +msgstr "出货形式" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:139 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:154 +msgid "The finished PCB are by single or by panel" +msgstr "单片或者连片出货" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:219 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:315 +msgid "X:" +msgstr "X:" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:246 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:287 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:435 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:74 +msgid "mm" +msgstr "mm" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:260 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:356 +msgid "Y:" +msgstr "Y:" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:303 +msgid "Panel Type" +msgstr "拼版规则" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:342 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:383 +msgid "pcs" +msgstr "片" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\base\ui_base_info.py:401 +msgid "Break-away Rail" +msgstr "工艺边框" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:13 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:25 +msgid "Need" +msgstr "需要" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:14 +msgid "Need & Auto Confirm" +msgstr "需要&自动确认" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:15 +msgid "Need & Manual Confirm" +msgstr "需要&手动确认" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:19 +msgid "Accept" +msgstr "接受" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:20 +msgid "Reject" +msgstr "拒绝" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:26 +msgid "No need" +msgstr "不需要" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:30 +msgid "Add customer stamp" +msgstr "加客编" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:31 +msgid "Add it to specified location" +msgstr "在指定位置加客编" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:32 +msgid "Don't add customer stamp" +msgstr "不加客编" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:36 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\utils\constraint.py:6 +msgid "Yes" +msgstr "是" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:37 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:50 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\utils\constraint.py:6 +msgid "No" +msgstr "否" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:42 +msgid "Sample Test Free" +msgstr "AOl+飞针抽测(免费)" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:43 +msgid "AOI+Flying Test" +msgstr "AOI+飞针全测" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:44 +msgid "AOI+Fixture" +msgstr "AOI+测试架" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:48 +msgid "Electronic" +msgstr "电子" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:48 +msgid "Paper" +msgstr "纸质" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:50 +msgid "UL+Week/Year" +msgstr "UL+周/年" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\personalized_info_view.py:50 +msgid "UL+Year/Week" +msgstr "UL+年/周" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:35 +msgid "Personalized Service" +msgstr "服务信息" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:46 +msgid "Electrical Test" +msgstr "测试方式" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:70 +msgid "Approve Working Gerber" +msgstr "确认生产稿" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:94 +msgid "Delivery Report" +msgstr "产品报告" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:118 +msgid "Microsection Analysis Report" +msgstr "显微切片分析报告" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:142 +msgid "Report Format" +msgstr "报告格式" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:166 +msgid "UL Mark" +msgstr "UL 标志" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:190 +msgid "Film" +msgstr "感光膜" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:214 +msgid "Cross Board" +msgstr "打叉板" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:238 +msgid "Bulkhead Paper" +msgstr "隔板纸" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:262 +msgid "User Stamp Process" +msgstr "客编处理" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:286 +msgid "HQ Pack" +msgstr "华秋包装" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\personalized\ui_personalized.py:311 +msgid "Special Request" +msgstr "特殊要求" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:40 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:50 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:79 +msgid "Green" +msgstr "绿" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:41 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:51 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:80 +msgid "Red" +msgstr "红" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:42 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:52 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:81 +msgid "Yellow" +msgstr "黄" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:43 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:53 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:82 +msgid "Blue" +msgstr "蓝" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:44 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:54 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:79 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:80 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:81 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:82 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:83 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:84 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:85 +msgid "White" +msgstr "白" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:45 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:55 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:84 +msgid "Matte Black" +msgstr "哑黑" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:46 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:56 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:83 +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:85 +msgid "Black" +msgstr "黑" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:61 +msgid "Tenting Vias" +msgstr "过孔盖油" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:62 +msgid "Vias not covered" +msgstr "过孔开窗" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:63 +msgid "Solder Mask Plug (IV-B)" +msgstr "过孔塞油墨" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:64 +msgid "Non-Conductive Fill" +msgstr "过孔塞树脂+电镀填平" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:68 +msgid "HASL" +msgstr "有铅喷锡" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:69 +msgid "Lead free HASL" +msgstr "无铅喷锡" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:70 +msgid "ENIG" +msgstr "沉金" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\process_info_view.py:71 +msgid "OSP" +msgstr "OSP" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:34 +msgid "Process info" +msgstr "工艺信息" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:45 +msgid "PCB Thickness" +msgstr "板子厚度" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:88 +msgid "FInsihed Copper weight" +msgstr "外层铜厚" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:112 +msgid "Inner Copper Weight" +msgstr "内层铜厚" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:136 +msgid "Min Trace/Space Outer" +msgstr "最小线宽/线距" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:160 +msgid "Min Drilled Hole" +msgstr "最小孔径" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:184 +msgid "Solder Mask Color" +msgstr "阻焊颜色" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:208 +msgid "Silkscreen" +msgstr "字符颜色" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:232 +msgid "Via Process" +msgstr "阻焊覆盖" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:256 +msgid "Surface Finish" +msgstr "表面处理" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\process\ui_process_info.py:280 +msgid "Immersion Gold Thickness" +msgstr "沉金厚度" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:14 +msgid "Rank 1" +msgstr "一阶" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:14 +msgid "Rank 2" +msgstr "二阶" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:14 +msgid "Rank 3" +msgstr "三阶" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:16 +msgid "Customer Specified Stack up" +msgstr "自定义堆叠方式" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\special_process_view.py:16 +msgid "No Requirement" +msgstr "无需求" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:34 +msgid "Special Process" +msgstr "特殊要求" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:45 +msgid "Impedance" +msgstr "阻抗" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:69 +msgid "Beveling of G/F" +msgstr "手指斜边" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:93 +msgid "Plated Half Holes" +msgstr "半孔" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:117 +msgid "Pad Hole" +msgstr "盘中孔" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:141 +msgid "HDI(Buried/blind vais)" +msgstr "HDI(埋地/盲走)" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:165 +msgid "HDI Structure" +msgstr "HDI结构" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:189 +msgid "Stack up" +msgstr "堆叠" + +#: C:\Users\ws\Documents\KiCad\7.0\scripting\plugins\kicad-amf-plugin\kicad_amf_plugin\pcb_fabrication\special_process\ui_special_process.py:213 +msgid "Metallized Sides Count" +msgstr "金属化边框数量" + +#~ msgid "Restart the plugin to apply the new locale ?" +#~ msgstr "重启插件以应用新的语言配置?" + +#~ msgid "PCB Quantity" +#~ msgstr "PCB数量" + +#~ msgid "Time" +#~ msgstr "时间" + +#~ msgid "Cost" +#~ msgstr "价格" + +#~ msgid "BGA isn't valid. Please input valid number." +#~ msgstr "BGA无效,请输入有效数字." + +#~ msgid "Turnhole density isn't valid. Please input valid number." +#~ msgstr "通孔密度无效,请输入有效数字." + +#~ msgid "BGA" +#~ msgstr "BGA" + +#~ msgid "Turnhole Density" +#~ msgstr "通孔密度" + +#~ msgid "en" +#~ msgstr "英语" + +#~ msgid "ja" +#~ msgstr "日语" + +#~ msgid "zh_CN" +#~ msgstr "中文简体" + +#~ msgid "Test point count isn't valid. Please input valid number." +#~ msgstr "测试点数量无效,请输入数字." + +#~ msgid "PCB design count isn't valid. Please input valid number." +#~ msgstr "PCB设计稿数量无效,请输入数字." + +#~ msgid "Designs Count" +#~ msgstr "设计稿数量" + +#~ msgid "Test Point Count" +#~ msgstr "测试点数量" + +#~ msgid "Unexpected response from server" +#~ msgstr "不符合预期的服务器响应" + +#~ msgid "$" +#~ msgstr "元" + +#~ msgid "Material Type:" +#~ msgstr "板材:" + +#~ msgid "FR-4" +#~ msgstr "FR-4" + +#~ msgid "Layer Count:" +#~ msgstr "板子层数:" + +#~ msgid "Board Type:" +#~ msgstr "出货形式:" + +#~ msgid "Panel Type:" +#~ msgstr "拼版规则:" + +#~ msgid "Size (single):" +#~ msgstr "单片尺寸:" + +#~ msgid "Qty(single):" +#~ msgstr "连片数量:" + +#~ msgid "Break-away Rail:" +#~ msgstr "工艺边框:" + +#~ msgid "PCB Thickness:" +#~ msgstr "板子厚度:" + +#~ msgid "Finished Copper Weight:" +#~ msgstr "外层铜厚:" + +#~ msgid "Inner Copper Weight:" +#~ msgstr "内层铜厚:" + +#~ msgid "Min Trace/Space Outer:" +#~ msgstr "最小线宽/线距:" + +#~ msgid "Min Drilled Hole:" +#~ msgstr "最小孔径:" + +#~ msgid "Solder Mask Color:" +#~ msgstr "阻焊颜色:" + +#~ msgid "Silkscreen:" +#~ msgstr "丝网印刷:" + +#~ msgid "Via Process:" +#~ msgstr "阻焊覆盖:" + +#~ msgid "Surface Finish:" +#~ msgstr "表面处理:" + +#~ msgid "Immersion Gold Thickness:" +#~ msgstr "沉金厚度:" + +#~ msgid "jp" +#~ msgstr "日语" diff --git a/kicad_amf_plugin/order/__init__.py b/kicad_amf_plugin/order/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kicad_amf_plugin/order/order_region.py b/kicad_amf_plugin/order/order_region.py new file mode 100644 index 0000000..8809572 --- /dev/null +++ b/kicad_amf_plugin/order/order_region.py @@ -0,0 +1,29 @@ +from enum import Enum +from .supported_region import SupportedRegion + + +class URL_KIND(Enum): + QUERY_PRICE = 0 + PLACE_ORDER = 1 + + +class OrderRegion: + AVAILABLE_URLS = { + SupportedRegion.CHINA_MAINLAND: { + URL_KIND.PLACE_ORDER: "https://www.hqpcb.com/External/fileQuote", + URL_KIND.QUERY_PRICE: "https://www.hqpcb.com/public/ajax_valuation", + }, + SupportedRegion.EUROPE_USA: { + URL_KIND.PLACE_ORDER: "https://www.nextpcb.com/Upfile/kiCadUpFile", + URL_KIND.QUERY_PRICE: "https://www.nextpcb.com/ajax/valuation", + }, + SupportedRegion.JAPAN: { + URL_KIND.PLACE_ORDER: "https://jp.nextpcb.com/Upfile/kiCadUpFile", + URL_KIND.QUERY_PRICE: "https://jp.nextpcb.com/ajax/valuation", + }, + } + + @staticmethod + def get_url(region: SupportedRegion, kind: URL_KIND): + if region in OrderRegion.AVAILABLE_URLS: + return OrderRegion.AVAILABLE_URLS[region][kind] diff --git a/kicad_amf_plugin/order/supported_region.py b/kicad_amf_plugin/order/supported_region.py new file mode 100644 index 0000000..967cdac --- /dev/null +++ b/kicad_amf_plugin/order/supported_region.py @@ -0,0 +1,4 @@ +class SupportedRegion: + CHINA_MAINLAND = 0 + JAPAN = 1 + EUROPE_USA = 2 diff --git a/kicad_amf_plugin/pcb_fabrication/__init__.py b/kicad_amf_plugin/pcb_fabrication/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kicad_amf_plugin/pcb_fabrication/base/__init__.py b/kicad_amf_plugin/pcb_fabrication/base/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kicad_amf_plugin/pcb_fabrication/base/base_info_model.py b/kicad_amf_plugin/pcb_fabrication/base/base_info_model.py new file mode 100644 index 0000000..89bb3fd --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/base/base_info_model.py @@ -0,0 +1,20 @@ +from dataclasses import dataclass + + +@dataclass +class BaseInfoModel: + blayer: str # Layer Count + blength: str # GetPcbLength + bwidth: str # GetPcbWidth + bcount: str # Qty(single) + sidedirection: str # Decided by the marginMode automatically + + plate_type: str = "Fr-4" # Material Type + units: str = "2" # Board Type + layoutx: str = None # X + layouty: str = None # Y + sidewidth: str = None # Break-away Rail + + testpoint: int = 0 # 测试点数,默认为0 + pbnum: int = None # 拼版款数,指文件内不同款的板子个数, 不传默认为1 + board_tg: str = None # 4层及以上可选TG值,TG130、TG150、TG170 diff --git a/kicad_amf_plugin/pcb_fabrication/base/base_info_view.py b/kicad_amf_plugin/pcb_fabrication/base/base_info_view.py new file mode 100644 index 0000000..49813a3 --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/base/base_info_view.py @@ -0,0 +1,370 @@ +from kicad_amf_plugin.kicad.board_manager import BoardManager +from kicad_amf_plugin.order.supported_region import SupportedRegion +from kicad_amf_plugin.settings.setting_manager import SETTING_MANAGER +from kicad_amf_plugin.settings.single_plugin import SINGLE_PLUGIN +from kicad_amf_plugin.utils.form_panel_base import FormKind, FormPanelBase +from .base_info_model import BaseInfoModel +from kicad_amf_plugin.gui.event.pcb_fabrication_evt_list import LayerCountChange +from .ui_base_info import ( + UiBaseInfo, + BOX_SIZE_SETTING, + BOX_PANEL_SETTING, + BOX_BREAK_AWAY, +) +from kicad_amf_plugin.utils.validators import ( + NumericTextCtrlValidator, + FloatTextCtrlValidator, +) +from kicad_amf_plugin.utils.roles import EditDisplayRole +from kicad_amf_plugin.settings.form_value_fitter import fitter_and_map_form_value +from kicad_amf_plugin.settings.supported_layer_count import AVAILABLE_LAYER_COUNTS + +import pcbnew +import wx + + +AVAILABLE_MATERIAL_TYPES = ["FR-4"] + +AVAILABLE_BOARD_TG_TYPES = ["TG130", "TG150", "TG170"] + + +class PcbPackageKind: + SINGLE_PIECE = 1 + PANEL_BY_CUSTOMER = 3 + PANEL_BY_NEXT_PCB = 2 + + PCB_PACKAGE_KIND = ( + EditDisplayRole(SINGLE_PIECE, _("Single Piece")), + EditDisplayRole(PANEL_BY_CUSTOMER, _("Panel by Customer")), + EditDisplayRole(PANEL_BY_NEXT_PCB, _("Panel by NextPCB")), + ) + + +class MarginMode: + NA = "N/A" + LEFT_RIGHT = "X" + TOP_BOTTOM = "Y" + ALL_4_SIDE = "XY" + + MARGIN_MODE_CHOICE = [ + EditDisplayRole(NA, _("N/A")), + EditDisplayRole(LEFT_RIGHT, _("Left & Right")), + EditDisplayRole(TOP_BOTTOM, _("Top & Bottom")), + EditDisplayRole(ALL_4_SIDE, _("All 4 sides")), + ] + + +AVAILABLE_QUANTITY = [ + 5, + 10, + 15, + 20, + 25, + 30, + 40, + 50, + 75, + 100, + 125, + 150, + 200, + 250, + 300, + 350, + 400, + 450, + 500, + 600, + 700, + 800, + 900, + 1000, + 1500, + 2000, + 2500, + 3000, + 3500, + 4000, + 4500, + 5000, + 5500, + 6000, + 6500, + 7000, + 7500, + 8000, + 9000, + 10000, +] + + +class BaseInfoView(UiBaseInfo, FormPanelBase): + def __init__(self, parent, board_manager: BoardManager): + super().__init__(parent) + self.board_manager = board_manager + + self.combo_pcb_package_kind.Bind(wx.EVT_CHOICE, self.on_pcb_packaging_changed) + self.comb_margin_mode.Bind(wx.EVT_CHOICE, self.on_margin_mode_changed) + self.combo_layer_count.Bind(wx.EVT_CHOICE, self.on_layer_count_changed) + for editor in self.edit_panel_x, self.edit_panel_y: + editor.SetValidator(NumericTextCtrlValidator()) + self.edit_margin_size.SetValidator(FloatTextCtrlValidator()) + + def is_valid(self) -> bool: + if ( + self.pcb_package_kind != PcbPackageKind.SINGLE_PIECE + and not self.should_apply_single_board_geometry() + ): + if not self.edit_panel_x.Validate(): + wx.MessageBox( + _("Panel Type X value isn't valid. Please input valid value."), + _("Error"), + wx.OK | wx.ICON_ERROR, + ) + return False + if not self.edit_panel_y.Validate(): + wx.MessageBox( + _("Panel Type Y value isn't valid. Please input valid value."), + _("Error"), + wx.OK | wx.ICON_ERROR, + ) + return False + if self.edit_margin_size.Enabled: + if not self.edit_margin_size.Validate(): + wx.MessageBox( + _("Break-away Rail value isn't valid. Please input valid value."), + _("Error"), + wx.OK | wx.ICON_ERROR, + ) + return False + return True + + @property + def box_piece_or_panel_size(self): + return self.FindWindowById(BOX_SIZE_SETTING) + + @property + def box_panel_setting(self): + return self.FindWindowById(BOX_PANEL_SETTING) + + @property + def box_break_away(self): + return self.FindWindowById(BOX_BREAK_AWAY) + + @property + def pcb_package_kind(self): + return PcbPackageKind.PCB_PACKAGE_KIND[ + int(self.combo_pcb_package_kind.GetSelection()) + ].EditRole + + @property + def margin_mode(self): + return MarginMode.MARGIN_MODE_CHOICE[ + int(self.comb_margin_mode.GetSelection()) + ].EditRole + + def should_apply_single_board_geometry(self): + return ( + self.pcb_package_kind == PcbPackageKind.SINGLE_PIECE + or SETTING_MANAGER.order_region == SupportedRegion.CHINA_MAINLAND + and self.pcb_package_kind + in (PcbPackageKind.SINGLE_PIECE, PcbPackageKind.PANEL_BY_CUSTOMER) + ) + + def get_pcb_length(self): + """Default is mm + + + Returns: + _type_: float + """ + if self.should_apply_single_board_geometry(): + if self.margin_mode in (MarginMode.LEFT_RIGHT, MarginMode.ALL_4_SIDE): + return ( + float(self.edit_size_x.GetValue()) + + float(self.edit_margin_size.GetValue()) * 2 + ) + else: + return float(self.edit_size_x.GetValue()) + else: + if self.margin_mode in (MarginMode.LEFT_RIGHT, MarginMode.ALL_4_SIDE): + return ( + float(self.edit_size_x.GetValue()) + * int(self.edit_panel_x.GetValue()) + + float(self.edit_margin_size.GetValue()) * 2 + ) + else: + return float(self.edit_size_x.GetValue()) * int( + self.edit_panel_x.GetValue() + ) + + def get_pcb_width(self): + """Default is mm + + + Returns: + _type_: float + """ + if self.should_apply_single_board_geometry(): + if self.margin_mode in (MarginMode.LEFT_RIGHT, MarginMode.ALL_4_SIDE): + return ( + float(self.edit_size_y.GetValue()) + + float(self.edit_margin_size.GetValue()) * 2 + ) + else: + return float(self.edit_size_y.GetValue()) + else: + if self.margin_mode in (MarginMode.LEFT_RIGHT, MarginMode.ALL_4_SIDE): + return ( + float(self.edit_size_y.GetValue()) + * int(self.edit_panel_y.GetValue()) + + float(self.edit_margin_size.GetValue()) * 2 + ) + else: + return float(self.edit_size_y.GetValue()) * int( + self.edit_panel_y.GetValue() + ) + + @fitter_and_map_form_value + def get_from(self, kind: FormKind) -> "dict": + data = BaseInfoModel( + blayer=self.combo_layer_count.GetStringSelection(), + plate_type=AVAILABLE_MATERIAL_TYPES[0], + board_tg=self.combo_board_tg.GetStringSelection() + if self.combo_board_tg.Enabled + else None, + units=str(self.pcb_package_kind), + blength=str( + FormPanelBase.convert_geometry( + kind, SETTING_MANAGER.order_region, self.get_pcb_length() + ) + ), + bwidth=str( + FormPanelBase.convert_geometry( + kind, SETTING_MANAGER.order_region, self.get_pcb_width() + ) + ), + bcount=self.combo_quantity.GetStringSelection(), + sidedirection=str(self.margin_mode), + ) + + if self.pcb_package_kind in ( + PcbPackageKind.PANEL_BY_CUSTOMER, + PcbPackageKind.PANEL_BY_NEXT_PCB, + ): + if not self.order_region_is_cn_and_package_by_customer(): + data.layoutx = self.edit_panel_x.GetValue() + data.layouty = self.edit_panel_y.GetValue() + + if self.margin_mode != MarginMode.NA: + data.sidewidth = self.edit_margin_size.GetValue() + + return vars(data) + + def order_region_is_cn_and_package_by_customer(self): + return ( + SETTING_MANAGER.order_region == SupportedRegion.CHINA_MAINLAND + and self.pcb_package_kind == PcbPackageKind.PANEL_BY_CUSTOMER + ) + + def init(self): + self.initUI() + self.loadBoardInfo() + + def getBaseInfo(self): + return self.base_info + + def initUI(self): + self.combo_material_type.Append(AVAILABLE_MATERIAL_TYPES) + self.combo_material_type.SetSelection(0) + + self.combo_layer_count.AppendItems([str(i) for i in AVAILABLE_LAYER_COUNTS]) + self.combo_layer_count.SetSelection(1) + + self.combo_pcb_package_kind.Append( + [i.DisplayRole for i in PcbPackageKind.PCB_PACKAGE_KIND] + ) + self.comb_margin_mode.Append( + [i.DisplayRole for i in MarginMode.MARGIN_MODE_CHOICE] + ) + + self.combo_quantity.Append([str(i) for i in AVAILABLE_QUANTITY]) + self.combo_quantity.SetSelection(0) + self.comb_margin_mode.SetSelection(0) + self.combo_pcb_package_kind.SetSelection(0) + + self.combo_board_tg.Append(AVAILABLE_BOARD_TG_TYPES) + self.combo_board_tg.SetSelection(0) + + for i in self.edit_size_x, self.edit_size_y: + i.SetEditable(False) + self.edit_margin_size.Enabled = False + self.box_panel_setting.Show( + self.pcb_package_kind != PcbPackageKind.SINGLE_PIECE + ) + + def loadBoardInfo(self): + boardWidth = pcbnew.ToMM( + self.board_manager.board.GetBoardEdgesBoundingBox().GetWidth() + ) + boardHeight = pcbnew.ToMM( + self.board_manager.board.GetBoardEdgesBoundingBox().GetHeight() + ) + layerCount = self.board_manager.board.GetCopperLayerCount() + self.combo_layer_count.SetSelection( + self.combo_layer_count.FindString(str(layerCount)) + ) + self.combo_layer_count.Enabled = False + self.edit_size_x.SetValue(str(boardWidth)) + self.edit_size_y.SetValue(str(boardHeight)) + self.combo_board_tg.Enabled = layerCount > 3 + + def on_pcb_packaging_changed(self, evt=None): + if self.pcb_package_kind == PcbPackageKind.SINGLE_PIECE: + self.box_piece_or_panel_size.SetLabelText(_("Size (single)")) + self.label_quantity.SetLabel(_("Qty(single)")) + self.label_quantity_unit.SetLabel(_("Pcs")) + else: + self.box_piece_or_panel_size.SetLabelText(_("Size (set)")) + self.label_quantity.SetLabel(_("Qty(Set)")) + self.label_quantity_unit.SetLabel(_("Set")) + + self.box_panel_setting.Show( + self.pcb_package_kind != PcbPackageKind.SINGLE_PIECE + and not self.order_region_is_cn_and_package_by_customer() + ) + self.box_break_away.Enabled = ( + self.pcb_package_kind != PcbPackageKind.PANEL_BY_CUSTOMER + ) + self.on_margin_mode_changed() + if SINGLE_PLUGIN.get_main_wind() is not None: + SINGLE_PLUGIN.get_main_wind().adjust_size() + + def on_margin_mode_changed(self, event=None): + self.edit_margin_size.Enabled = self.margin_mode != MarginMode.NA + if self.margin_mode == MarginMode.NA: + self.edit_margin_size.SetValue("0") + + def on_layer_count_changed(self, evt): + evt = LayerCountChange(id=-1) + count = int(self.combo_layer_count.GetStringSelection()) + evt.SetInt(count) + self.combo_board_tg.Enabled = count > 3 + wx.PostEvent(self.Parent, evt) + + def get_pcb_count(self): + n = int(self.combo_quantity.GetStringSelection()) + if ( + self.combo_pcb_package_kind.GetSelection() == 1 + or self.combo_pcb_package_kind.GetSelection() == 2 + ): + return ( + n + * int(self.edit_panel_x.GetValue()) + * int(self.edit_panel_y.GetValue()) + ) + else: + return n + + def on_region_changed(self): + self.on_pcb_packaging_changed(None) diff --git a/kicad_amf_plugin/pcb_fabrication/base/ui_base_info.fbp b/kicad_amf_plugin/pcb_fabrication/base/ui_base_info.fbp new file mode 100644 index 0000000..1fe74d2 --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/base/ui_base_info.fbp @@ -0,0 +1,1918 @@ + + + + + ; + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + ui_base_info + 1000 + none + + + 1 + UiBaseInfo + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 1 + impl_virtual + + + 0 + wxID_ANY + + + UiBaseInfo + + -1,-1 + ; ; forward_declare + + 0 + + + wxTAB_TRAVERSAL + + wxID_ANY + Base Info + + sbSizer2 + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 0 + + 2 + wxBOTH + 1 + + 0 + + fgSizer2 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Material Type + 0 + + 0 + + + 0 + + 1 + m_staticText3 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + Non-conductive base material + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_material_type + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + Non-conductive base material + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Layer Count + 0 + + 0 + + + 0 + + 1 + m_staticText4 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_layer_count + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Board TG + 0 + + 0 + + + 0 + + 1 + m_staticText18 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_board_tg + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND + 0 + + 2 + wxHORIZONTAL + 1 + + 0 + + fgSizer3 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Board Type + 0 + + 0 + + + 0 + + 1 + m_staticText5 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + The finished PCB are by single or by panel + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_pcb_package_kind + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + The finished PCB are by single or by panel + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Qty(single) + 0 + + 0 + + + 0 + + 1 + label_quantity + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + 0 + + 0 + + fgSizer21 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_quantity + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Pcs + 0 + + 0 + + + 0 + + 1 + label_quantity_unit + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer2 + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + BOX_SIZE_SETTING + Size (single) + + box_piece_or_panel_size + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + 1 + + 0 + + fgSizer41 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + X: + 0 + + 0 + + + 0 + + 1 + m_staticText82 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + 0 + + 0 + + fgSizer62 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + edit_size_x + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + 0 + + 0 + + + 0 + + 1 + m_staticText102 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Y: + 0 + + 0 + + + 0 + + 1 + m_staticText811 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + 0 + + 0 + + fgSizer611 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + edit_size_y + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + 0 + + 0 + + + 0 + + 1 + m_staticText1011 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + + + + + + + 5 + wxEXPAND + 1 + + BOX_PANEL_SETTING + Panel Type + + sbSizer21 + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + 1 + + 0 + + fgSizer4 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + X: + 0 + + 0 + + + 0 + + 1 + m_staticText8 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + 0 + + 0 + + fgSizer6 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + edit_panel_x + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + pcs + 0 + + 0 + + + 0 + + 1 + m_staticText10 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Y: + 0 + + 0 + + + 0 + + 1 + m_staticText81 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + 0 + + 0 + + fgSizer61 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + edit_panel_y + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + pcs + 0 + + 0 + + + 0 + + 1 + m_staticText101 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + + + + + + + + + 5 + wxEXPAND + 0 + + BOX_BREAK_AWAY + Break-away Rail + + sbSizer12 + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 1 + + 3 + wxBOTH + 1 + + 0 + + fgSizer24 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + comb_margin_mode + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + edit_margin_size + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + 0 + + 0 + + + 0 + + 1 + m_staticText39 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + + + + + + + diff --git a/kicad_amf_plugin/pcb_fabrication/base/ui_base_info.py b/kicad_amf_plugin/pcb_fabrication/base/ui_base_info.py new file mode 100644 index 0000000..a94d1e9 --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/base/ui_base_info.py @@ -0,0 +1,453 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + + +BOX_SIZE_SETTING = 1000 +BOX_PANEL_SETTING = 1001 +BOX_BREAK_AWAY = 1002 + +########################################################################### +## Class UiBaseInfo +########################################################################### + + +class UiBaseInfo(wx.Panel): + def __init__( + self, + parent, + id=wx.ID_ANY, + pos=wx.DefaultPosition, + size=wx.Size(-1, -1), + style=wx.TAB_TRAVERSAL, + name=wx.EmptyString, + ): + wx.Panel.__init__( + self, parent, id=id, pos=pos, size=size, style=style, name=name + ) + + sbSizer2 = wx.StaticBoxSizer( + wx.StaticBox(self, wx.ID_ANY, _("Base Info")), wx.VERTICAL + ) + + fgSizer2 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer2.AddGrowableCol(1) + fgSizer2.SetFlexibleDirection(wx.BOTH) + fgSizer2.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + self.m_staticText3 = wx.StaticText( + sbSizer2.GetStaticBox(), + wx.ID_ANY, + _("Material Type"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText3.Wrap(-1) + + self.m_staticText3.SetToolTip(_("Non-conductive base material")) + + fgSizer2.Add(self.m_staticText3, 0, wx.ALL, 5) + + combo_material_typeChoices = [] + self.combo_material_type = wx.Choice( + sbSizer2.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_material_typeChoices, + 0, + ) + self.combo_material_type.SetSelection(0) + self.combo_material_type.SetToolTip(_("Non-conductive base material")) + + fgSizer2.Add(self.combo_material_type, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText4 = wx.StaticText( + sbSizer2.GetStaticBox(), + wx.ID_ANY, + _("Layer Count"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText4.Wrap(-1) + + fgSizer2.Add(self.m_staticText4, 0, wx.ALL, 5) + + combo_layer_countChoices = [] + self.combo_layer_count = wx.Choice( + sbSizer2.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_layer_countChoices, + 0, + ) + self.combo_layer_count.SetSelection(0) + fgSizer2.Add(self.combo_layer_count, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText18 = wx.StaticText( + sbSizer2.GetStaticBox(), + wx.ID_ANY, + _("Board TG"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText18.Wrap(-1) + + fgSizer2.Add(self.m_staticText18, 0, wx.ALL, 5) + + combo_board_tgChoices = [] + self.combo_board_tg = wx.Choice( + sbSizer2.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_board_tgChoices, + 0, + ) + self.combo_board_tg.SetSelection(0) + fgSizer2.Add(self.combo_board_tg, 0, wx.ALL | wx.EXPAND, 5) + + sbSizer2.Add(fgSizer2, 0, wx.EXPAND, 5) + + fgSizer3 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer3.AddGrowableCol(1) + fgSizer3.SetFlexibleDirection(wx.HORIZONTAL) + fgSizer3.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + self.m_staticText5 = wx.StaticText( + sbSizer2.GetStaticBox(), + wx.ID_ANY, + _("Board Type"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText5.Wrap(-1) + + self.m_staticText5.SetToolTip(_("The finished PCB are by single or by panel")) + + fgSizer3.Add(self.m_staticText5, 0, wx.ALL, 5) + + combo_pcb_package_kindChoices = [] + self.combo_pcb_package_kind = wx.Choice( + sbSizer2.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_pcb_package_kindChoices, + 0, + ) + self.combo_pcb_package_kind.SetSelection(0) + self.combo_pcb_package_kind.SetToolTip( + _("The finished PCB are by single or by panel") + ) + + fgSizer3.Add(self.combo_pcb_package_kind, 0, wx.ALL | wx.EXPAND, 5) + + self.label_quantity = wx.StaticText( + sbSizer2.GetStaticBox(), + wx.ID_ANY, + _("Qty(single)"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.label_quantity.Wrap(-1) + + fgSizer3.Add(self.label_quantity, 0, wx.ALL, 5) + + fgSizer21 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer21.AddGrowableCol(0) + fgSizer21.SetFlexibleDirection(wx.BOTH) + fgSizer21.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + combo_quantityChoices = [] + self.combo_quantity = wx.Choice( + sbSizer2.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_quantityChoices, + 0, + ) + self.combo_quantity.SetSelection(0) + fgSizer21.Add(self.combo_quantity, 0, wx.ALL | wx.EXPAND, 5) + + self.label_quantity_unit = wx.StaticText( + sbSizer2.GetStaticBox(), + wx.ID_ANY, + _("Pcs"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.label_quantity_unit.Wrap(-1) + + fgSizer21.Add(self.label_quantity_unit, 0, wx.ALL, 5) + + fgSizer3.Add(fgSizer21, 1, wx.EXPAND, 5) + + sbSizer2.Add(fgSizer3, 0, wx.EXPAND, 5) + + bSizer2 = wx.BoxSizer(wx.VERTICAL) + + box_piece_or_panel_size = wx.StaticBoxSizer( + wx.StaticBox(sbSizer2.GetStaticBox(), BOX_SIZE_SETTING, _("Size (single)")), + wx.VERTICAL, + ) + + fgSizer41 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer41.AddGrowableCol(1) + fgSizer41.SetFlexibleDirection(wx.BOTH) + fgSizer41.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + self.m_staticText82 = wx.StaticText( + box_piece_or_panel_size.GetStaticBox(), + wx.ID_ANY, + _("X:"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText82.Wrap(-1) + + fgSizer41.Add(self.m_staticText82, 0, wx.ALL, 5) + + fgSizer62 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer62.AddGrowableCol(0) + fgSizer62.SetFlexibleDirection(wx.BOTH) + fgSizer62.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + self.edit_size_x = wx.TextCtrl( + box_piece_or_panel_size.GetStaticBox(), + wx.ID_ANY, + wx.EmptyString, + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + fgSizer62.Add(self.edit_size_x, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText102 = wx.StaticText( + box_piece_or_panel_size.GetStaticBox(), + wx.ID_ANY, + _("mm"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText102.Wrap(-1) + + fgSizer62.Add(self.m_staticText102, 0, wx.ALL, 5) + + fgSizer41.Add(fgSizer62, 1, wx.EXPAND, 5) + + self.m_staticText811 = wx.StaticText( + box_piece_or_panel_size.GetStaticBox(), + wx.ID_ANY, + _("Y:"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText811.Wrap(-1) + + fgSizer41.Add(self.m_staticText811, 0, wx.ALL, 5) + + fgSizer611 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer611.AddGrowableCol(0) + fgSizer611.SetFlexibleDirection(wx.BOTH) + fgSizer611.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + self.edit_size_y = wx.TextCtrl( + box_piece_or_panel_size.GetStaticBox(), + wx.ID_ANY, + wx.EmptyString, + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + fgSizer611.Add(self.edit_size_y, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText1011 = wx.StaticText( + box_piece_or_panel_size.GetStaticBox(), + wx.ID_ANY, + _("mm"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText1011.Wrap(-1) + + fgSizer611.Add(self.m_staticText1011, 0, wx.ALL, 5) + + fgSizer41.Add(fgSizer611, 1, wx.EXPAND, 5) + + box_piece_or_panel_size.Add(fgSizer41, 1, wx.EXPAND, 5) + + bSizer2.Add(box_piece_or_panel_size, 1, wx.EXPAND, 5) + + sbSizer21 = wx.StaticBoxSizer( + wx.StaticBox(sbSizer2.GetStaticBox(), BOX_PANEL_SETTING, _("Panel Type")), + wx.VERTICAL, + ) + + fgSizer4 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer4.AddGrowableCol(1) + fgSizer4.SetFlexibleDirection(wx.BOTH) + fgSizer4.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + self.m_staticText8 = wx.StaticText( + sbSizer21.GetStaticBox(), + wx.ID_ANY, + _("X:"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText8.Wrap(-1) + + fgSizer4.Add(self.m_staticText8, 0, wx.ALL, 5) + + fgSizer6 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer6.AddGrowableCol(0) + fgSizer6.SetFlexibleDirection(wx.BOTH) + fgSizer6.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + self.edit_panel_x = wx.TextCtrl( + sbSizer21.GetStaticBox(), + wx.ID_ANY, + wx.EmptyString, + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + fgSizer6.Add(self.edit_panel_x, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText10 = wx.StaticText( + sbSizer21.GetStaticBox(), + wx.ID_ANY, + _("pcs"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText10.Wrap(-1) + + fgSizer6.Add(self.m_staticText10, 0, wx.ALL, 5) + + fgSizer4.Add(fgSizer6, 1, wx.EXPAND, 5) + + self.m_staticText81 = wx.StaticText( + sbSizer21.GetStaticBox(), + wx.ID_ANY, + _("Y:"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText81.Wrap(-1) + + fgSizer4.Add(self.m_staticText81, 0, wx.ALL, 5) + + fgSizer61 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer61.AddGrowableCol(0) + fgSizer61.SetFlexibleDirection(wx.BOTH) + fgSizer61.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + self.edit_panel_y = wx.TextCtrl( + sbSizer21.GetStaticBox(), + wx.ID_ANY, + wx.EmptyString, + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + fgSizer61.Add(self.edit_panel_y, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText101 = wx.StaticText( + sbSizer21.GetStaticBox(), + wx.ID_ANY, + _("pcs"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText101.Wrap(-1) + + fgSizer61.Add(self.m_staticText101, 0, wx.ALL, 5) + + fgSizer4.Add(fgSizer61, 1, wx.EXPAND, 5) + + sbSizer21.Add(fgSizer4, 1, wx.EXPAND, 5) + + bSizer2.Add(sbSizer21, 1, wx.EXPAND, 5) + + sbSizer2.Add(bSizer2, 0, wx.EXPAND, 5) + + sbSizer12 = wx.StaticBoxSizer( + wx.StaticBox(sbSizer2.GetStaticBox(), BOX_BREAK_AWAY, _("Break-away Rail")), + wx.VERTICAL, + ) + + fgSizer24 = wx.FlexGridSizer(0, 3, 0, 0) + fgSizer24.AddGrowableCol(1) + fgSizer24.SetFlexibleDirection(wx.BOTH) + fgSizer24.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + comb_margin_modeChoices = [] + self.comb_margin_mode = wx.Choice( + sbSizer12.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + comb_margin_modeChoices, + 0, + ) + self.comb_margin_mode.SetSelection(0) + fgSizer24.Add(self.comb_margin_mode, 0, wx.ALL | wx.EXPAND, 5) + + self.edit_margin_size = wx.TextCtrl( + sbSizer12.GetStaticBox(), + wx.ID_ANY, + wx.EmptyString, + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + fgSizer24.Add(self.edit_margin_size, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText39 = wx.StaticText( + sbSizer12.GetStaticBox(), + wx.ID_ANY, + _("mm"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText39.Wrap(-1) + + fgSizer24.Add(self.m_staticText39, 0, wx.ALL, 5) + + sbSizer12.Add(fgSizer24, 1, wx.EXPAND, 5) + + sbSizer2.Add(sbSizer12, 0, wx.EXPAND, 5) + + self.SetSizer(sbSizer2) + self.Layout() + sbSizer2.Fit(self) + + def __del__(self): + pass diff --git a/kicad_amf_plugin/pcb_fabrication/personalized/__init__.py b/kicad_amf_plugin/pcb_fabrication/personalized/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kicad_amf_plugin/pcb_fabrication/personalized/personalized_info_model.py b/kicad_amf_plugin/pcb_fabrication/personalized/personalized_info_model.py new file mode 100644 index 0000000..0c7af50 --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/personalized/personalized_info_model.py @@ -0,0 +1,19 @@ +from dataclasses import dataclass + + +@dataclass +class PersonalizedInfoModel: + test: str # Electrical Test + shipment_report: str # Delivery Report + slice_report: str # Microsection Analysis Report + report_type: str # Report Format + review_file: str # Approve Working Gerber: 确认生产稿 0无需 1需要-自动确认 2需要-非自动确认 + has_period: str # Decided by period_format + period_format: str or None # UL Mark + film_report: str # Film + pcb_note: str # Special Requests # Non-CN + + cross_board: int # 打叉板 1接受 2不接受 + paper: int # 隔白纸 1无需 2需要 + user_stamp: int # 不加客编 1无要求 2指定位置加客编 3不加客编 + hq_pack: int = None # 包装要求,默认 1华秋包装,0中性包装 #CN only diff --git a/kicad_amf_plugin/pcb_fabrication/personalized/personalized_info_view.py b/kicad_amf_plugin/pcb_fabrication/personalized/personalized_info_view.py new file mode 100644 index 0000000..903bbcf --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/personalized/personalized_info_view.py @@ -0,0 +1,156 @@ +from kicad_amf_plugin.order.order_region import OrderRegion, SupportedRegion +from kicad_amf_plugin.settings.setting_manager import SETTING_MANAGER +from kicad_amf_plugin.settings.form_value_fitter import fitter_and_map_form_value +from .personalized_info_model import PersonalizedInfoModel +from .ui_personalized import UiPersonalizedService, BOX_SP_REQUEST +from kicad_amf_plugin.utils.constraint import BOOLEAN_CHOICE +from .personalized_info_model import PersonalizedInfoModel +from kicad_amf_plugin.utils.form_panel_base import FormKind, FormPanelBase +from kicad_amf_plugin.utils.roles import EditDisplayRole + + +REVIEW_FILE_OPTION = [ + EditDisplayRole(0, _("Need")), + EditDisplayRole(1, _("Need & Auto Confirm")), + EditDisplayRole(2, _("Need & Manual Confirm")), +] + +CROSS_BOARD = [ + EditDisplayRole(1, _("Accept")), + EditDisplayRole(2, _("Reject")), +] + + +PAPER = [ + EditDisplayRole(1, _("Need")), + EditDisplayRole(2, _("No need")), +] + +USER_STAMP = [ + EditDisplayRole(1, _("Add customer stamp")), + EditDisplayRole(2, _("Add it to specified location")), + EditDisplayRole(3, _("Don't add customer stamp")), +] + +HQ_PACK = [ + EditDisplayRole(1, _("Yes")), + EditDisplayRole(0, _("No")), +] + + +TEST_METHOD_CHOICE = { + _("Sample Test Free"): "Sample Test Free", + _("AOI+Flying Test"): "Batch Flying Probe Test", + _("AOI+Fixture"): "Batch Fixture Test", +} + + +REPORT_FORMAT_CHOICE = [_("Paper"), _("Electronic")] + +UL_MARK_CHOICE = [_("No"), _("UL+Week/Year"), _("UL+Year/Week")] + + +class PersonalizedInfoView(UiPersonalizedService, FormPanelBase): + def __init__(self, parent, _): + super().__init__(parent) + self.special_process: PersonalizedInfoModel = None + self.initUI() + + def initUI(self): + # NOTE It seems that all tests are free now + self.comb_test_method.Append([i for i in TEST_METHOD_CHOICE]) + self.comb_test_method.SetSelection(0) + + for ctrl in ( + self.combo_microsection_report, + self.comb_film, + self.comb_delivery_report, + ): + for i in BOOLEAN_CHOICE: + ctrl.Append(_(i)) + ctrl.SetSelection(0) + + self.comb_report_format.Append(REPORT_FORMAT_CHOICE) + self.comb_report_format.SetSelection(1) + + self.comb_ul_mark.Append(UL_MARK_CHOICE) + self.comb_ul_mark.SetSelection(0) + + map = { + self.comb_approve_gerber: REVIEW_FILE_OPTION, + self.combo_cross_board: CROSS_BOARD, + self.combo_paper: PAPER, + self.combo_user_stamp: USER_STAMP, + self.combo_hq_pack: HQ_PACK, + } + map = { + self.comb_approve_gerber: REVIEW_FILE_OPTION, + self.combo_cross_board: CROSS_BOARD, + self.combo_paper: PAPER, + self.combo_user_stamp: USER_STAMP, + self.combo_hq_pack: HQ_PACK, + } + for comb in map: + comb.Append([i.DisplayRole for i in map[comb]]) + comb.SetSelection(0) + + @fitter_and_map_form_value + def get_from(self, kind: FormKind) -> "dict": + info = PersonalizedInfoModel( + test=TEST_METHOD_CHOICE[self.comb_test_method.StringSelection] + if self.comb_test_method.Shown + else None, + shipment_report=str(self.comb_delivery_report.GetSelection()), + slice_report=str(self.combo_microsection_report.GetSelection()), + report_type=str(self.GetReportType()), + review_file=REVIEW_FILE_OPTION[ + int(self.comb_approve_gerber.GetSelection()) + ].EditRole, + has_period=str(self.GetHasPeriod()), + period_format=self.GetPeriodFormat() + if self.comb_ul_mark.GetSelection() + else None, + film_report=str(self.comb_film.GetSelection()), + cross_board=CROSS_BOARD[self.combo_cross_board.GetSelection()].EditRole, + paper=PAPER[self.combo_paper.GetSelection()].EditRole, + user_stamp=USER_STAMP[self.combo_user_stamp.GetSelection()].EditRole, + hq_pack=HQ_PACK[int(self.combo_hq_pack.GetSelection())].EditRole + if self.combo_hq_pack.Shown + else None, + pcb_note=self.edit_special_request.GetValue() + if self.edit_special_request.Shown + else None, + ) + return vars(info) + + def GetReportType(self): + if ( + self.comb_delivery_report.GetSelection() == 0 + and self.combo_microsection_report.GetSelection() == 0 + ): + return 0 + elif self.comb_report_format.GetSelection() == 0: + return 2 + elif self.comb_report_format.GetSelection() == 1: + return 1 + + def GetHasPeriod(self): + if self.comb_ul_mark.GetSelection() == 0: + return "2" + else: + return "6" + + @property + def sp_box(self): + return self.FindWindowById(BOX_SP_REQUEST) + + def GetPeriodFormat(self): + if self.comb_ul_mark.GetSelection() == 1: + return "2" + elif self.comb_ul_mark.GetSelection() == 2: + return "1" + + def on_region_changed(self): + for i in self.combo_hq_pack, self.label_hq_pack: + i.Show(SETTING_MANAGER.order_region == SupportedRegion.CHINA_MAINLAND) + self.sp_box.Show(SETTING_MANAGER.order_region != SupportedRegion.CHINA_MAINLAND) diff --git a/kicad_amf_plugin/pcb_fabrication/personalized/ui_personalized.fbp b/kicad_amf_plugin/pcb_fabrication/personalized/ui_personalized.fbp new file mode 100644 index 0000000..6b72798 --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/personalized/ui_personalized.fbp @@ -0,0 +1,1537 @@ + + + + + ; + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + ui_personalized + 1030 + none + + + 1 + MyProject2 + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 1 + impl_virtual + + + 0 + wxID_ANY + + + UiPersonalizedService + + -1,-1 + ; ; forward_declare + + 0 + + + wxTAB_TRAVERSAL + + wxID_ANY + Personalized Service + + labelProcessInfo + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 0 + + 2 + wxBOTH + 1 + + 0 + + fgSizer25 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Electrical Test + 0 + + 0 + + + 0 + + 1 + label_electric_test + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + comb_test_method + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Approve Working Gerber + 0 + + 0 + + + 0 + + 1 + m_staticText4011 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + comb_approve_gerber + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Delivery Report + 0 + + 0 + + + 0 + + 1 + m_staticText40111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_microsection_report + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Microsection Analysis Report + 0 + + 0 + + + 0 + + 1 + m_staticText401111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + comb_delivery_report + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Report Format + 0 + + 0 + + + 0 + + 1 + m_staticText4011111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + comb_report_format + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + UL Mark + 0 + + 0 + + + 0 + + 1 + m_staticText40111111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + comb_ul_mark + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Film + 0 + + 0 + + + 0 + + 1 + label_stackup + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + comb_film + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Cross Board + 0 + + 0 + + + 0 + + 1 + m_staticText8 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_cross_board + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Bulkhead Paper + 0 + + 0 + + + 0 + + 1 + m_staticText9 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_paper + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + User Stamp Process + 0 + + 0 + + + 0 + + 1 + m_staticText10 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_user_stamp + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + HQ Pack + 0 + + 0 + + + 0 + + 1 + label_hq_pack + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_hq_pack + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND + 1 + + BOX_SP_REQUEST + Special Request + + sp_box + wxVERTICAL + 1 + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + -1,60 + 1 + edit_special_request + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_MULTILINE + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + diff --git a/kicad_amf_plugin/pcb_fabrication/personalized/ui_personalized.py b/kicad_amf_plugin/pcb_fabrication/personalized/ui_personalized.py new file mode 100644 index 0000000..360322e --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/personalized/ui_personalized.py @@ -0,0 +1,335 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + +BOX_SP_REQUEST = 1030 + +########################################################################### +## Class UiPersonalizedService +########################################################################### + + +class UiPersonalizedService(wx.Panel): + def __init__( + self, + parent, + id=wx.ID_ANY, + pos=wx.DefaultPosition, + size=wx.Size(-1, -1), + style=wx.TAB_TRAVERSAL, + name=wx.EmptyString, + ): + wx.Panel.__init__( + self, parent, id=id, pos=pos, size=size, style=style, name=name + ) + + labelProcessInfo = wx.StaticBoxSizer( + wx.StaticBox(self, wx.ID_ANY, _("Personalized Service")), wx.VERTICAL + ) + + fgSizer25 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer25.AddGrowableCol(1) + fgSizer25.SetFlexibleDirection(wx.BOTH) + fgSizer25.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + self.label_electric_test = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Electrical Test"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.label_electric_test.Wrap(-1) + + fgSizer25.Add(self.label_electric_test, 0, wx.ALL, 5) + + comb_test_methodChoices = [] + self.comb_test_method = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + comb_test_methodChoices, + 0, + ) + self.comb_test_method.SetSelection(0) + fgSizer25.Add(self.comb_test_method, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText4011 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Approve Working Gerber"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText4011.Wrap(-1) + + fgSizer25.Add(self.m_staticText4011, 0, wx.ALL, 5) + + comb_approve_gerberChoices = [] + self.comb_approve_gerber = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + comb_approve_gerberChoices, + 0, + ) + self.comb_approve_gerber.SetSelection(0) + fgSizer25.Add(self.comb_approve_gerber, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText40111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Delivery Report"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText40111.Wrap(-1) + + fgSizer25.Add(self.m_staticText40111, 0, wx.ALL, 5) + + combo_microsection_reportChoices = [] + self.combo_microsection_report = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_microsection_reportChoices, + 0, + ) + self.combo_microsection_report.SetSelection(0) + fgSizer25.Add(self.combo_microsection_report, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText401111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Microsection Analysis Report"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText401111.Wrap(-1) + + fgSizer25.Add(self.m_staticText401111, 0, wx.ALL, 5) + + comb_delivery_reportChoices = [] + self.comb_delivery_report = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + comb_delivery_reportChoices, + 0, + ) + self.comb_delivery_report.SetSelection(0) + fgSizer25.Add(self.comb_delivery_report, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText4011111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Report Format"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText4011111.Wrap(-1) + + fgSizer25.Add(self.m_staticText4011111, 0, wx.ALL, 5) + + comb_report_formatChoices = [] + self.comb_report_format = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + comb_report_formatChoices, + 0, + ) + self.comb_report_format.SetSelection(0) + fgSizer25.Add(self.comb_report_format, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText40111111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("UL Mark"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText40111111.Wrap(-1) + + fgSizer25.Add(self.m_staticText40111111, 0, wx.ALL, 5) + + comb_ul_markChoices = [] + self.comb_ul_mark = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + comb_ul_markChoices, + 0, + ) + self.comb_ul_mark.SetSelection(0) + fgSizer25.Add(self.comb_ul_mark, 0, wx.ALL | wx.EXPAND, 5) + + self.label_stackup = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Film"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.label_stackup.Wrap(-1) + + fgSizer25.Add(self.label_stackup, 0, wx.ALL, 5) + + comb_filmChoices = [] + self.comb_film = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + comb_filmChoices, + 0, + ) + self.comb_film.SetSelection(0) + fgSizer25.Add(self.comb_film, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText8 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Cross Board"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText8.Wrap(-1) + + fgSizer25.Add(self.m_staticText8, 0, wx.ALL, 5) + + combo_cross_boardChoices = [] + self.combo_cross_board = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_cross_boardChoices, + 0, + ) + self.combo_cross_board.SetSelection(0) + fgSizer25.Add(self.combo_cross_board, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText9 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Bulkhead Paper"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText9.Wrap(-1) + + fgSizer25.Add(self.m_staticText9, 0, wx.ALL, 5) + + combo_paperChoices = [] + self.combo_paper = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_paperChoices, + 0, + ) + self.combo_paper.SetSelection(0) + fgSizer25.Add(self.combo_paper, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText10 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("User Stamp Process"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText10.Wrap(-1) + + fgSizer25.Add(self.m_staticText10, 0, wx.ALL, 5) + + combo_user_stampChoices = [] + self.combo_user_stamp = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_user_stampChoices, + 0, + ) + self.combo_user_stamp.SetSelection(0) + fgSizer25.Add(self.combo_user_stamp, 0, wx.ALL | wx.EXPAND, 5) + + self.label_hq_pack = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("HQ Pack"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.label_hq_pack.Wrap(-1) + + fgSizer25.Add(self.label_hq_pack, 0, wx.ALL, 5) + + combo_hq_packChoices = [] + self.combo_hq_pack = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_hq_packChoices, + 0, + ) + self.combo_hq_pack.SetSelection(0) + fgSizer25.Add(self.combo_hq_pack, 0, wx.ALL | wx.EXPAND, 5) + + labelProcessInfo.Add(fgSizer25, 0, wx.EXPAND, 5) + + sp_box = wx.StaticBoxSizer( + wx.StaticBox( + labelProcessInfo.GetStaticBox(), BOX_SP_REQUEST, _("Special Request") + ), + wx.VERTICAL, + ) + + self.edit_special_request = wx.TextCtrl( + sp_box.GetStaticBox(), + wx.ID_ANY, + wx.EmptyString, + wx.DefaultPosition, + wx.DefaultSize, + wx.TE_MULTILINE, + ) + self.edit_special_request.SetMinSize(wx.Size(-1, 60)) + + sp_box.Add(self.edit_special_request, 1, wx.ALL | wx.EXPAND, 5) + + labelProcessInfo.Add(sp_box, 1, wx.EXPAND, 5) + + self.SetSizer(labelProcessInfo) + self.Layout() + labelProcessInfo.Fit(self) + + def __del__(self): + pass diff --git a/kicad_amf_plugin/pcb_fabrication/process/__init__.py b/kicad_amf_plugin/pcb_fabrication/process/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kicad_amf_plugin/pcb_fabrication/process/process_info_model.py b/kicad_amf_plugin/pcb_fabrication/process/process_info_model.py new file mode 100644 index 0000000..2c5fed8 --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/process/process_info_model.py @@ -0,0 +1,15 @@ +from dataclasses import dataclass + + +@dataclass +class ProcessInfoModel: + bheight: str # PCB Thickness + copper: str # Finished Copper Weight + lineweight: str # Min Trace/Space Outer + vias: str # Min Drilled Hole + color: str # Solder Mask Color + charcolor: str # Silkscreen + cover: str # Via Process + spray: str # Surface Finish + insidecopper: str = "0" # Inner Copper Weight + cjh: str = None # SurfaceProcessCtrl diff --git a/kicad_amf_plugin/pcb_fabrication/process/process_info_view.py b/kicad_amf_plugin/pcb_fabrication/process/process_info_view.py new file mode 100644 index 0000000..c42d5af --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/process/process_info_view.py @@ -0,0 +1,307 @@ +from kicad_amf_plugin.kicad.board_manager import BoardManager +from kicad_amf_plugin.settings.form_value_fitter import fitter_and_map_form_value +from .process_info_model import ProcessInfoModel +from kicad_amf_plugin.utils.form_panel_base import FormKind, FormPanelBase + + +from .ui_process_info import UiProcessInfo +import wx +import pcbnew +from pcbnew import PCB_TRACK, PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T + + +THICKNESS_SETTING = { + "1": ["0.6", "0.8", "1.0", "1.2", "1.6"], + "2": ["0.6", "0.8", "1.0", "1.2", "1.6"], + "4": ["0.6", "0.8", "1.0", "1.2", "1.6", "2.0", "2.5"], + "6": ["1.0", "1.2", "1.6", "2.0", "2.5"], + "8": ["1.2", "1.6", "2.0", "2.5"], + "10": ["1.2", "1.6", "2.0", "2.5"], + "12": ["1.6", "2.0", "2.5"], + "14": ["1.6", "2.0", "2.5", "3.0"], + "16": ["2.0", "2.5", "3.0"], + "18": ["2.0", "2.5", "3.0", "3.2"], + "20": ["2.0", "2.5", "3.0", "3.2"], +} + +OZ = "oz" + +OUTER_THICKNESS_CHOICE = [1, 2] + + +INNER_COPPER_THICKNESS_CHOICE = [0.5, 1, 2] + +MIL = "mil" + +MIN_TRACE_WIDTH_CLEARANCE_CHOICE = [10, 8, 6, 5, 4, 3.5] +MIN_HOLE_SIZE_CHOICE = [0.3, 0.25, 0.2, 0.15] + +MM = "mm" + +DEFAULT_MIN_TRACK_WIDTH = 6 + +KNOW_COLOR_MAPPING = { + _("Green"): "Green", + _("Red"): "Red", + _("Yellow"): "Yellow", + _("Blue"): "Blue", + _("White"): "White", + _("Matte Black"): "Matte Black", + _("Black"): "Black", +} + +SOLDER_COLOR_CHOICE = [ + _("Green"), + _("Red"), + _("Yellow"), + _("Blue"), + _("White"), + _("Matte Black"), + _("Black"), +] + + +SOLDER_COVER_CHOICE = { + _("Tenting Vias"): "Tenting Vias", + _("Vias not covered"): "Vias not covered", + _("Solder Mask Plug (IV-B)"): "Solder Mask Plug (IV-B)", + _("Non-Conductive Fill"): "Non-Conductive Fill & Cap (VII)", +} + +SURFACE_PROCESS_CHOICE = { + _("HASL"): "HASL", + _("Lead free HASL"): "Lead free HASL", + _("ENIG"): "ENIG", + _("OSP"): "OSP", +} + +GOLD_THICKNESS_CHOICE = [1, 2, 3] + +GOLD_THICKNESS_CHOICE_UNIT = "µm" + +SILK_SCREEN_COLOR_BY_SOLDER_COLOR = { + _("Green"): [_("White")], + _("Red"): [_("White")], + _("Yellow"): [_("White")], + _("Blue"): [_("White")], + _("White"): [_("Black")], + _("Matte Black"): [_("White")], + _("Black"): [_("White")], +} + + +class ProcessInfoView(UiProcessInfo, FormPanelBase): + def __init__(self, parent, board_manager: BoardManager): + super().__init__(parent) + self.board_manager = board_manager + + self.combo_surface_process.Bind(wx.EVT_CHOICE, self.on_surface_process_changed) + self.combo_solder_color.Bind(wx.EVT_CHOICE, self.OnMaskColorChange) + + self.Fit() + + @fitter_and_map_form_value + def get_from(self, kind: FormKind) -> "dict": + info = ProcessInfoModel( + bheight=self.combo_board_thickness.GetStringSelection(), + copper=str( + self.combo_outer_copper_thickness.GetStringSelection() + ).removesuffix(OZ), + lineweight=str( + self.combo_min_trace_width_clearance.GetStringSelection() + ).split("/")[0], + vias=str(self.combo_min_hole_size.GetStringSelection()).removesuffix(MM), + color=KNOW_COLOR_MAPPING[self.combo_solder_color.GetStringSelection()], + charcolor=KNOW_COLOR_MAPPING[ + self.combo_silk_screen_color.GetStringSelection() + ], + cover=SOLDER_COVER_CHOICE[self.combo_solder_cover.GetStringSelection()], + spray=SURFACE_PROCESS_CHOICE[ + self.combo_surface_process.GetStringSelection() + ], + ) + if self.layer_count > 2: + info.insidecopper = str( + self.combo_inner_copper_thickness.GetStringSelection() + ).removesuffix(OZ) + if self.combo_surface_process.GetCurrentSelection() == 2: + info.cjh = str(self.combo_gold_thickness.GetCurrentSelection() + 1) + return vars(info) + + def init(self): + self.initUI() + self.loadBoardInfo() + + def initUI(self): + self.combo_board_thickness.Append(THICKNESS_SETTING["1"]) + self.combo_board_thickness.SetSelection(4) + + self.combo_outer_copper_thickness.Append( + [f"{i}{OZ}" for i in OUTER_THICKNESS_CHOICE] + ) + self.combo_outer_copper_thickness.SetSelection(0) + + self.combo_inner_copper_thickness.Append( + [f"{i}{OZ}" for i in INNER_COPPER_THICKNESS_CHOICE] + ) + self.combo_inner_copper_thickness.SetSelection(0) + + self.combo_min_trace_width_clearance.Append( + [f"{i}/{i}{MIL}" for i in MIN_TRACE_WIDTH_CLEARANCE_CHOICE] + ) + self.combo_min_trace_width_clearance.SetSelection(2) + + self.combo_min_hole_size.Append([f"{i}{MM}" for i in MIN_HOLE_SIZE_CHOICE]) + self.combo_min_hole_size.SetSelection(0) + + self.combo_solder_color.Append(SOLDER_COLOR_CHOICE) + self.combo_solder_color.SetSelection(0) + + self.combo_silk_screen_color.Append( + SILK_SCREEN_COLOR_BY_SOLDER_COLOR[ + self.combo_solder_color.GetStringSelection() + ] + ) + self.combo_silk_screen_color.SetSelection(0) + + self.combo_solder_cover.Append([i for i in SOLDER_COVER_CHOICE]) + self.combo_solder_cover.SetSelection(0) + + self.combo_surface_process.Append([i for i in SURFACE_PROCESS_CHOICE]) + self.combo_surface_process.SetSelection(0) + + self.combo_gold_thickness.Append( + [f"{i}{GOLD_THICKNESS_CHOICE_UNIT}" for i in GOLD_THICKNESS_CHOICE] + ) + self.combo_gold_thickness.SetSelection(0) + + @property + def layer_count(self): + return self.board_manager.board.GetCopperLayerCount() + + def get_board_thickness_in_kicad_setting(self): + return self.board_manager.board.GetDesignSettings().GetBoardThickness() + + def loadBoardInfo(self): + for i in self.label_immersion_gold, self.combo_gold_thickness: + i.Show(False) + + self.combo_inner_copper_thickness.Enabled = self.layer_count > 2 + self.setup_board_thickness_choice(self.layer_count) + self.setup_trace_and_via() + + def setup_board_thickness_choice(self, event): + layer_count = event if isinstance(event, int) else event.GetInt() + self.combo_board_thickness.Clear() + val_list = THICKNESS_SETTING[str(layer_count)] + self.combo_board_thickness.Append(val_list) + self.set_board_thickness( + pcbnew.ToMM(self.get_board_thickness_in_kicad_setting()) + ) + + def on_surface_process_changed(self, evt=None): + for i in self.label_immersion_gold, self.combo_gold_thickness: + i.Show(self.combo_surface_process.GetSelection() == 2) + self.Layout() + self.Parent.Layout() + + def set_board_thickness(self, thickness): + for i in range(self.combo_board_thickness.GetCount()): + if thickness <= float(self.combo_board_thickness.GetString(i)): + self.combo_board_thickness.SetSelection(i) + break + + def set_min_trace(self, minTraceWidth, minTraceClearance): + if minTraceWidth == 0 and minTraceClearance == 0: + minTrace = 6 + elif minTraceWidth == 0: + minTrace = minTraceClearance + elif minTraceClearance == 0: + minTrace = minTraceWidth + else: + minTrace = min(minTraceWidth, minTraceClearance) + + if minTrace == 0: + minTrace = 6 + self.combo_min_trace_width_clearance.SetSelection(2) + elif minTrace > 8: + minTrace = 10 + self.combo_min_trace_width_clearance.SetSelection(0) + elif minTrace > 6: + minTrace = 8 + self.combo_min_trace_width_clearance.SetSelection(1) + elif minTrace > 5: + minTrace = 6 + self.combo_min_trace_width_clearance.SetSelection(2) + elif minTrace > 4: + minTrace = 5 + self.combo_min_trace_width_clearance.SetSelection(3) + elif minTrace > 3.5: + minTrace = 4 + self.combo_min_trace_width_clearance.SetSelection(4) + else: + minTrace = 3.5 + self.combo_min_trace_width_clearance.SetSelection(5) + + def set_min_hole(self, minHoleSize): + if minHoleSize == 0: + minHoleSize = 0.3 + self.combo_min_hole_size.SetSelection(0) + elif minHoleSize >= 0.3: + minHoleSize = 0.3 + self.combo_min_hole_size.SetSelection(0) + elif minHoleSize >= 0.25: + minHoleSize = 0.25 + self.combo_min_hole_size.SetSelection(1) + elif minHoleSize >= 0.2: + minHoleSize = 0.2 + self.combo_min_hole_size.SetSelection(2) + else: + minHoleSize = 0.15 + self.combo_min_hole_size.SetSelection(3) + + def OnMaskColorChange(self, event): + self.combo_silk_screen_color.Clear() + self.combo_silk_screen_color.Append( + SILK_SCREEN_COLOR_BY_SOLDER_COLOR[ + self.combo_solder_color.GetStringSelection() + ] + ) + self.combo_silk_screen_color.SetSelection(0) + + def on_region_changed(self): + pass + + def setup_trace_and_via(self): + + designSettings = self.board_manager.board.GetDesignSettings() + minTraceWidth = ( + designSettings.m_TrackMinWidth + if designSettings.m_TrackMinWidth != 0 + else None + ) + minTraceClearance = designSettings.m_MinClearance + minHoleSize = ( + designSettings.m_MinThroughDrill + if designSettings.m_MinThroughDrill != 0 + else None + ) + + tracks: "list[PCB_TRACK]" = self.board_manager.board.Tracks() + for i in tracks: + type_id = i.Type() + if type_id in (PCB_TRACE_T, PCB_ARC_T): + if minTraceWidth is None: + minTraceWidth = i.GetWidth() + continue + minTraceWidth = min(minTraceWidth, i.GetWidth()) + elif type_id == PCB_VIA_T: + if minHoleSize is None: + minHoleSize = i.GetDrillValue() + continue + minHoleSize = min(minHoleSize, i.GetDrillValue()) + + self.set_min_trace( + pcbnew.ToMils(minTraceWidth), pcbnew.ToMils(minTraceClearance) + ) + self.set_min_hole(pcbnew.ToMM(minHoleSize)) diff --git a/kicad_amf_plugin/pcb_fabrication/process/ui_process_info.fbp b/kicad_amf_plugin/pcb_fabrication/process/ui_process_info.fbp new file mode 100644 index 0000000..df1d642 --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/process/ui_process_info.fbp @@ -0,0 +1,1413 @@ + + + + + ; + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + ui_process_info + 1000 + none + + + 1 + UiProcessInfo + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 1 + impl_virtual + + + 0 + wxID_ANY + + + UiProcessInfo + + -1,-1 + ; ; forward_declare + + 0 + + + wxTAB_TRAVERSAL + + wxID_ANY + Process info + + labelProcessInfo + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 0 + + 2 + wxBOTH + 1 + + 0 + + fgSizer25 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + PCB Thickness + 0 + + 0 + + + 0 + + 1 + label_pcb_thick + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + 0 + + 0 + + fgSizer26 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_board_thickness + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + 0 + + 0 + + + 0 + + 1 + m_staticText41 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + FInsihed Copper weight + 0 + + 0 + + + 0 + + 1 + m_staticText401 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_outer_copper_thickness + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Inner Copper Weight + 0 + + 0 + + + 0 + + 1 + m_staticText4011 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_inner_copper_thickness + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Min Trace/Space Outer + 0 + + 0 + + + 0 + + 1 + m_staticText40111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_min_trace_width_clearance + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Min Drilled Hole + 0 + + 0 + + + 0 + + 1 + m_staticText401111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_min_hole_size + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Solder Mask Color + 0 + + 0 + + + 0 + + 1 + m_staticText4011111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_solder_color + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Silkscreen + 0 + + 0 + + + 0 + + 1 + m_staticText40111111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_silk_screen_color + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Via Process + 0 + + 0 + + + 0 + + 1 + label_stackup + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_solder_cover + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Surface Finish + 0 + + 0 + + + 0 + + 1 + m_staticText4011111111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_surface_process + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Immersion Gold Thickness + 0 + + 0 + + + 0 + + 1 + label_immersion_gold + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_gold_thickness + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + diff --git a/kicad_amf_plugin/pcb_fabrication/process/ui_process_info.py b/kicad_amf_plugin/pcb_fabrication/process/ui_process_info.py new file mode 100644 index 0000000..2f53dd6 --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/process/ui_process_info.py @@ -0,0 +1,308 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + + +########################################################################### +## Class UiProcessInfo +########################################################################### + + +class UiProcessInfo(wx.Panel): + def __init__( + self, + parent, + id=wx.ID_ANY, + pos=wx.DefaultPosition, + size=wx.Size(-1, -1), + style=wx.TAB_TRAVERSAL, + name=wx.EmptyString, + ): + wx.Panel.__init__( + self, parent, id=id, pos=pos, size=size, style=style, name=name + ) + + labelProcessInfo = wx.StaticBoxSizer( + wx.StaticBox(self, wx.ID_ANY, _("Process info")), wx.VERTICAL + ) + + fgSizer25 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer25.AddGrowableCol(1) + fgSizer25.SetFlexibleDirection(wx.BOTH) + fgSizer25.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + self.label_pcb_thick = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("PCB Thickness"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.label_pcb_thick.Wrap(-1) + + fgSizer25.Add(self.label_pcb_thick, 0, wx.ALL, 5) + + fgSizer26 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer26.AddGrowableCol(0) + fgSizer26.SetFlexibleDirection(wx.BOTH) + fgSizer26.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + combo_board_thicknessChoices = [] + self.combo_board_thickness = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_board_thicknessChoices, + 0, + ) + self.combo_board_thickness.SetSelection(0) + fgSizer26.Add(self.combo_board_thickness, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText41 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("mm"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText41.Wrap(-1) + + fgSizer26.Add(self.m_staticText41, 0, wx.ALL, 5) + + fgSizer25.Add(fgSizer26, 1, wx.EXPAND, 5) + + self.m_staticText401 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("FInsihed Copper weight"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText401.Wrap(-1) + + fgSizer25.Add(self.m_staticText401, 0, wx.ALL, 5) + + combo_outer_copper_thicknessChoices = [] + self.combo_outer_copper_thickness = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_outer_copper_thicknessChoices, + 0, + ) + self.combo_outer_copper_thickness.SetSelection(0) + fgSizer25.Add(self.combo_outer_copper_thickness, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText4011 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Inner Copper Weight"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText4011.Wrap(-1) + + fgSizer25.Add(self.m_staticText4011, 0, wx.ALL, 5) + + combo_inner_copper_thicknessChoices = [] + self.combo_inner_copper_thickness = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_inner_copper_thicknessChoices, + 0, + ) + self.combo_inner_copper_thickness.SetSelection(0) + fgSizer25.Add(self.combo_inner_copper_thickness, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText40111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Min Trace/Space Outer"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText40111.Wrap(-1) + + fgSizer25.Add(self.m_staticText40111, 0, wx.ALL, 5) + + combo_min_trace_width_clearanceChoices = [] + self.combo_min_trace_width_clearance = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_min_trace_width_clearanceChoices, + 0, + ) + self.combo_min_trace_width_clearance.SetSelection(0) + fgSizer25.Add(self.combo_min_trace_width_clearance, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText401111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Min Drilled Hole"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText401111.Wrap(-1) + + fgSizer25.Add(self.m_staticText401111, 0, wx.ALL, 5) + + combo_min_hole_sizeChoices = [] + self.combo_min_hole_size = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_min_hole_sizeChoices, + 0, + ) + self.combo_min_hole_size.SetSelection(0) + fgSizer25.Add(self.combo_min_hole_size, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText4011111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Solder Mask Color"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText4011111.Wrap(-1) + + fgSizer25.Add(self.m_staticText4011111, 0, wx.ALL, 5) + + combo_solder_colorChoices = [] + self.combo_solder_color = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_solder_colorChoices, + 0, + ) + self.combo_solder_color.SetSelection(0) + fgSizer25.Add(self.combo_solder_color, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText40111111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Silkscreen"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText40111111.Wrap(-1) + + fgSizer25.Add(self.m_staticText40111111, 0, wx.ALL, 5) + + combo_silk_screen_colorChoices = [] + self.combo_silk_screen_color = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_silk_screen_colorChoices, + 0, + ) + self.combo_silk_screen_color.SetSelection(0) + fgSizer25.Add(self.combo_silk_screen_color, 0, wx.ALL | wx.EXPAND, 5) + + self.label_stackup = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Via Process"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.label_stackup.Wrap(-1) + + fgSizer25.Add(self.label_stackup, 0, wx.ALL, 5) + + combo_solder_coverChoices = [] + self.combo_solder_cover = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_solder_coverChoices, + 0, + ) + self.combo_solder_cover.SetSelection(0) + fgSizer25.Add(self.combo_solder_cover, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText4011111111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Surface Finish"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText4011111111.Wrap(-1) + + fgSizer25.Add(self.m_staticText4011111111, 0, wx.ALL, 5) + + combo_surface_processChoices = [] + self.combo_surface_process = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_surface_processChoices, + 0, + ) + self.combo_surface_process.SetSelection(0) + fgSizer25.Add(self.combo_surface_process, 0, wx.ALL | wx.EXPAND, 5) + + self.label_immersion_gold = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Immersion Gold Thickness"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.label_immersion_gold.Wrap(-1) + + fgSizer25.Add(self.label_immersion_gold, 0, wx.ALL, 5) + + combo_gold_thicknessChoices = [] + self.combo_gold_thickness = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_gold_thicknessChoices, + 0, + ) + self.combo_gold_thickness.SetSelection(0) + fgSizer25.Add(self.combo_gold_thickness, 0, wx.ALL | wx.EXPAND, 5) + + labelProcessInfo.Add(fgSizer25, 0, wx.EXPAND, 5) + + self.SetSizer(labelProcessInfo) + self.Layout() + labelProcessInfo.Fit(self) + + def __del__(self): + pass diff --git a/kicad_amf_plugin/pcb_fabrication/special_process/__init__.py b/kicad_amf_plugin/pcb_fabrication/special_process/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kicad_amf_plugin/pcb_fabrication/special_process/special_process_model.py b/kicad_amf_plugin/pcb_fabrication/special_process/special_process_model.py new file mode 100644 index 0000000..74e2ed5 --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/special_process/special_process_model.py @@ -0,0 +1,15 @@ +from dataclasses import dataclass + + +@dataclass +class SpecialProcessModel: + impendance: str # Impendance + bankong: str # Plated Half Holes: + blind: str # HDI(Buried/blind vias): + via_in_pad: str # Pad Hole: + beveledge: str # Beveling of G/F: + pressing: str = "" # Stack up + + baobian: str = None # 包边,默认 0 无 1-4 边 + bga: str = None # BGA,默认0 无,可选值 0.35 – 0.35及以上 0.25 #CN only + zknum: str = None # 钻孔密度 diff --git a/kicad_amf_plugin/pcb_fabrication/special_process/special_process_view.py b/kicad_amf_plugin/pcb_fabrication/special_process/special_process_view.py new file mode 100644 index 0000000..e2c4ffc --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/special_process/special_process_view.py @@ -0,0 +1,104 @@ +from kicad_amf_plugin.kicad.board_manager import BoardManager +from kicad_amf_plugin.order.order_region import SupportedRegion +from kicad_amf_plugin.settings.setting_manager import SETTING_MANAGER +from kicad_amf_plugin.settings.form_value_fitter import fitter_and_map_form_value +from .ui_special_process import UiSpecialProcess +from .special_process_model import SpecialProcessModel +import wx +import wx.xrc +import wx.dataview +from kicad_amf_plugin.utils.constraint import BOOLEAN_CHOICE +from .special_process_model import SpecialProcessModel +from kicad_amf_plugin.utils.form_panel_base import FormKind, FormPanelBase + +HDI_STRUCTURE_CHOICE = [_("N/A"), _("Rank 1"), _("Rank 2"), _("Rank 3")] + +STACKUP_CHOICE = [_("No Requirement"), _("Customer Specified Stack up")] + + +class SpecialProcessView(UiSpecialProcess, FormPanelBase): + def __init__(self, parent, board_manager: BoardManager): + super().__init__(parent) + self.board_manager = board_manager + + self.combo_blind_via.Enabled = ( + self.board_manager.board.GetCopperLayerCount() != 2 + ) + self.combo_blind_via.Bind(wx.EVT_CHOICE, self.on_HDI_changed) + + def is_valid(self) -> bool: + return True + + def init(self): + self.initUI() + + def initUI(self): + for ctrl in ( + self.combo_impedance, + self.combo_goldFinger, + self.combo_halfHole, + self.combo_pad_hole, + self.combo_blind_via, + ): + for i in BOOLEAN_CHOICE: + ctrl.Append(_(i)) + ctrl.SetSelection(0) + + self.combo_hdi_structure.Append(HDI_STRUCTURE_CHOICE) + self.combo_hdi_structure.SetSelection(0) + + self.combo_stackup.Append(STACKUP_CHOICE) + self.combo_stackup.SetSelection(0) + self.combo_hdi_structure.Enabled = False + self.combo_baobian.Append([str(i) for i in range(0, 5)]) + self.combo_baobian.SetSelection(0) + + @fitter_and_map_form_value + def get_from(self, kind: FormKind) -> "dict": + info = SpecialProcessModel( + impendance=str(self.combo_impedance.GetSelection()), + bankong=str(self.combo_halfHole.GetSelection()), + blind=self.GetBlindValue(), + via_in_pad="N/A" if self.combo_pad_hole.GetSelection() == 0 else "Have", + beveledge=str(self.combo_goldFinger.GetSelection()), + baobian=self.combo_baobian.GetStringSelection(), + ) + if ( + self.combo_stackup.Shown + and self.layer_count > 2 + and self.combo_stackup.GetSelection() != 0 + ): + info.pressing = "Customer Specified Stack up" + return vars(info) + + @property + def layer_count(self): + return self.board_manager.board.GetCopperLayerCount() + + def on_HDI_changed(self, event): + self.combo_hdi_structure.Enabled = self.combo_blind_via.GetSelection() == 1 + if not self.combo_hdi_structure.Enabled: + self.combo_hdi_structure.SetSelection(0) + + def on_layer_count_changed(self, event): + self.combo_blind_via.Enabled = event.GetInt() > 2 + if not self.combo_blind_via.Enabled: + self.combo_blind_via.SetSelection(0) + self.combo_hdi_structure.Enabled = False + + def GetBlindValue(self): + if ( + self.combo_blind_via.GetSelection() == 0 + or self.combo_hdi_structure.GetSelection() == 0 + ): + return "0" + elif self.combo_hdi_structure.GetSelection() == 1: + return "1" + elif self.combo_hdi_structure.GetSelection() == 2: + return "2" + elif self.combo_hdi_structure.GetSelection() == 3: + return "3" + + def on_region_changed(self): + for i in self.label_stackup, self.combo_stackup: + i.Show(SETTING_MANAGER.order_region != SupportedRegion.CHINA_MAINLAND) diff --git a/kicad_amf_plugin/pcb_fabrication/special_process/ui_special_process.fbp b/kicad_amf_plugin/pcb_fabrication/special_process/ui_special_process.fbp new file mode 100644 index 0000000..2c1a769 --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/special_process/ui_special_process.fbp @@ -0,0 +1,1084 @@ + + + + + ; + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + ui_special_process + 1000 + none + + + 1 + UiSpecialProcess + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 1 + impl_virtual + + + 0 + wxID_ANY + + + UiSpecialProcess + + -1,-1 + ; ; forward_declare + + 0 + + + wxTAB_TRAVERSAL + + wxID_ANY + Special Process + + labelProcessInfo + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 0 + + 2 + wxBOTH + 1 + + 0 + + fgSizer25 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Impedance + 0 + + 0 + + + 0 + + 1 + m_staticText401 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_impedance + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Beveling of G/F + 0 + + 0 + + + 0 + + 1 + m_staticText4011 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_goldFinger + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Plated Half Holes + 0 + + 0 + + + 0 + + 1 + m_staticText40111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_halfHole + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Pad Hole + 0 + + 0 + + + 0 + + 1 + m_staticText401111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_pad_hole + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + HDI(Buried/blind vais) + 0 + + 0 + + + 0 + + 1 + m_staticText4011111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_blind_via + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + HDI Structure + 0 + + 0 + + + 0 + + 1 + label_hdi + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_hdi_structure + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Stack up + 0 + + 0 + + + 0 + + 1 + label_stackup + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_stackup + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Metallized Sides Count + 0 + + 0 + + + 0 + + 1 + m_staticText8 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + combo_baobian + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + diff --git a/kicad_amf_plugin/pcb_fabrication/special_process/ui_special_process.py b/kicad_amf_plugin/pcb_fabrication/special_process/ui_special_process.py new file mode 100644 index 0000000..73fbb13 --- /dev/null +++ b/kicad_amf_plugin/pcb_fabrication/special_process/ui_special_process.py @@ -0,0 +1,241 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + + +########################################################################### +## Class UiSpecialProcess +########################################################################### + + +class UiSpecialProcess(wx.Panel): + def __init__( + self, + parent, + id=wx.ID_ANY, + pos=wx.DefaultPosition, + size=wx.Size(-1, -1), + style=wx.TAB_TRAVERSAL, + name=wx.EmptyString, + ): + wx.Panel.__init__( + self, parent, id=id, pos=pos, size=size, style=style, name=name + ) + + labelProcessInfo = wx.StaticBoxSizer( + wx.StaticBox(self, wx.ID_ANY, _("Special Process")), wx.VERTICAL + ) + + fgSizer25 = wx.FlexGridSizer(0, 2, 0, 0) + fgSizer25.AddGrowableCol(1) + fgSizer25.SetFlexibleDirection(wx.BOTH) + fgSizer25.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) + + self.m_staticText401 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Impedance"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText401.Wrap(-1) + + fgSizer25.Add(self.m_staticText401, 0, wx.ALL, 5) + + combo_impedanceChoices = [] + self.combo_impedance = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_impedanceChoices, + 0, + ) + self.combo_impedance.SetSelection(0) + fgSizer25.Add(self.combo_impedance, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText4011 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Beveling of G/F"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText4011.Wrap(-1) + + fgSizer25.Add(self.m_staticText4011, 0, wx.ALL, 5) + + combo_goldFingerChoices = [] + self.combo_goldFinger = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_goldFingerChoices, + 0, + ) + self.combo_goldFinger.SetSelection(0) + fgSizer25.Add(self.combo_goldFinger, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText40111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Plated Half Holes"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText40111.Wrap(-1) + + fgSizer25.Add(self.m_staticText40111, 0, wx.ALL, 5) + + combo_halfHoleChoices = [] + self.combo_halfHole = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_halfHoleChoices, + 0, + ) + self.combo_halfHole.SetSelection(0) + fgSizer25.Add(self.combo_halfHole, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText401111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Pad Hole"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText401111.Wrap(-1) + + fgSizer25.Add(self.m_staticText401111, 0, wx.ALL, 5) + + combo_pad_holeChoices = [] + self.combo_pad_hole = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_pad_holeChoices, + 0, + ) + self.combo_pad_hole.SetSelection(0) + fgSizer25.Add(self.combo_pad_hole, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText4011111 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("HDI(Buried/blind vais)"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText4011111.Wrap(-1) + + fgSizer25.Add(self.m_staticText4011111, 0, wx.ALL, 5) + + combo_blind_viaChoices = [] + self.combo_blind_via = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_blind_viaChoices, + 0, + ) + self.combo_blind_via.SetSelection(0) + fgSizer25.Add(self.combo_blind_via, 0, wx.ALL | wx.EXPAND, 5) + + self.label_hdi = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("HDI Structure"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.label_hdi.Wrap(-1) + + fgSizer25.Add(self.label_hdi, 0, wx.ALL, 5) + + combo_hdi_structureChoices = [] + self.combo_hdi_structure = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_hdi_structureChoices, + 0, + ) + self.combo_hdi_structure.SetSelection(0) + fgSizer25.Add(self.combo_hdi_structure, 0, wx.ALL | wx.EXPAND, 5) + + self.label_stackup = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Stack up"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.label_stackup.Wrap(-1) + + fgSizer25.Add(self.label_stackup, 0, wx.ALL, 5) + + combo_stackupChoices = [] + self.combo_stackup = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_stackupChoices, + 0, + ) + self.combo_stackup.SetSelection(0) + fgSizer25.Add(self.combo_stackup, 0, wx.ALL | wx.EXPAND, 5) + + self.m_staticText8 = wx.StaticText( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + _("Metallized Sides Count"), + wx.DefaultPosition, + wx.DefaultSize, + 0, + ) + self.m_staticText8.Wrap(-1) + + fgSizer25.Add(self.m_staticText8, 0, wx.ALL, 5) + + combo_baobianChoices = [] + self.combo_baobian = wx.Choice( + labelProcessInfo.GetStaticBox(), + wx.ID_ANY, + wx.DefaultPosition, + wx.DefaultSize, + combo_baobianChoices, + 0, + ) + self.combo_baobian.SetSelection(0) + fgSizer25.Add(self.combo_baobian, 0, wx.ALL | wx.EXPAND, 5) + + labelProcessInfo.Add(fgSizer25, 0, wx.EXPAND, 5) + + self.SetSizer(labelProcessInfo) + self.Layout() + labelProcessInfo.Fit(self) + + def __del__(self): + pass diff --git a/kicad_amf_plugin/plugin/__init__.py b/kicad_amf_plugin/plugin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kicad_amf_plugin/plugin/_main.py b/kicad_amf_plugin/plugin/_main.py new file mode 100644 index 0000000..551dc07 --- /dev/null +++ b/kicad_amf_plugin/plugin/_main.py @@ -0,0 +1,9 @@ +from kicad_amf_plugin.settings.single_plugin import SINGLE_PLUGIN + + +def _main(): + if not SINGLE_PLUGIN.show_existing(): + from kicad_amf_plugin.gui.app_base import BaseApp + + app = BaseApp() + app.MainLoop() diff --git a/plugin.py b/kicad_amf_plugin/plugin/kicad_amf_action_plugin.py similarity index 51% rename from plugin.py rename to kicad_amf_plugin/plugin/kicad_amf_action_plugin.py index 802a6c7..c7bced2 100644 --- a/plugin.py +++ b/kicad_amf_plugin/plugin/kicad_amf_action_plugin.py @@ -1,20 +1,18 @@ import pcbnew import os -import wx -from pcbnew import * -from . import dialog_amf +from kicad_amf_plugin.plugin._main import _main +from kicad_amf_plugin.icon import ICON_ROOT -class Plugin(pcbnew.ActionPlugin): + +class KiCadAmfActionPlugin(pcbnew.ActionPlugin): def __init__(self): self.name = "HQ NextPCB Active Manufacturing" self.category = "Manufacturing" self.description = "Quote and place order with one button click." self.pcbnew_icon_support = hasattr(self, "show_toolbar_button") self.show_toolbar_button = True - self.icon_file_name = os.path.join( - os.path.dirname(__file__), 'icon.png') - self.dark_icon_file_name = os.path.join( - os.path.dirname(__file__), 'icon.png') + self.icon_file_name = os.path.join(ICON_ROOT, "icon.png") + self.dark_icon_file_name = os.path.join(ICON_ROOT, "icon.png") def Run(self): - dialog_amf.AmfDialog(None).ShowModal() \ No newline at end of file + _main() diff --git a/kicad_amf_plugin/settings/__init__.py b/kicad_amf_plugin/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kicad_amf_plugin/settings/default_express.py b/kicad_amf_plugin/settings/default_express.py new file mode 100644 index 0000000..435112c --- /dev/null +++ b/kicad_amf_plugin/settings/default_express.py @@ -0,0 +1 @@ +DEFAULT_EXPRESS = {"address": "广东省深圳市", "express": "顺丰快递"} diff --git a/kicad_amf_plugin/settings/form_value_fitter.py b/kicad_amf_plugin/settings/form_value_fitter.py new file mode 100644 index 0000000..1521932 --- /dev/null +++ b/kicad_amf_plugin/settings/form_value_fitter.py @@ -0,0 +1,43 @@ +from kicad_amf_plugin.order.supported_region import SupportedRegion +from .setting_manager import SETTING_MANAGER + +MAPPING = { + "N/A": "无", + "Left & Right": "左右", + "Top & Bottom": "上下", + "All 4 sides": "四边", + "Green": "绿色", + "Red": "红色", + "Yellow": "黄色", + "Blue": "蓝色", + "White": "白色", + "Matte Black": "哑黑", + "Black": "黑色", + "Solder Mask Plug (IV-B)": "过孔塞油墨", + "Tenting Vias": "过孔盖油", + "Vias not covered": "过孔开窗", + "Non-Conductive Fill & Cap (VII)": "过孔塞树脂+电镀填平", + "HASL": "有铅喷锡", + "Lead free HASL": "无铅喷锡", + "ENIG": "沉金", + "Have": "有", +} + + +def fitter_and_map_form_value(fn): + def wrapper(*args, **kwargs): + form: "dict" = fn(*args, **kwargs) + new_form = {} + for i in form: + if form[i] is None: + continue + if ( + SETTING_MANAGER.order_region == SupportedRegion.CHINA_MAINLAND + and form[i] in MAPPING + ): + new_form[i] = MAPPING[form[i]] + else: + new_form[i] = form[i] + return new_form + + return wrapper diff --git a/kicad_amf_plugin/settings/kicad_setting.py b/kicad_amf_plugin/settings/kicad_setting.py new file mode 100644 index 0000000..293ed57 --- /dev/null +++ b/kicad_amf_plugin/settings/kicad_setting.py @@ -0,0 +1,31 @@ +import json + +import wx +import os +import logging + + +class KiCadSetting: + def read_lang_setting(): + try: + import pcbnew + + kicad_setting_path = str(pcbnew.SETTINGS_MANAGER.GetUserSettingsPath()) + logging.info(f"Kicad setting path {kicad_setting_path}") + print(f"Kicad setting path {kicad_setting_path}") + if len(kicad_setting_path): + kicad_common_json = os.path.join( + kicad_setting_path, "kicad_common.json" + ) + with open(kicad_common_json) as f: + data = json.loads(f.read()) + lang: str = data["system"]["language"] + if lang.count("中文"): + return wx.LANGUAGE_CHINESE_SIMPLIFIED + elif lang.count("日本"): + return wx.LANGUAGE_JAPANESE_JAPAN + else: + logging.error("Empty KiCad config path!") + except: + logging.error("Cannot read the language setting of KiCad!") + return wx.LANGUAGE_ENGLISH diff --git a/kicad_amf_plugin/settings/setting_manager.py b/kicad_amf_plugin/settings/setting_manager.py new file mode 100644 index 0000000..fcc2f8b --- /dev/null +++ b/kicad_amf_plugin/settings/setting_manager.py @@ -0,0 +1,109 @@ +import wx +import os +from kicad_amf_plugin.gui.event.pcb_fabrication_evt_list import LocaleChangeEvent +from .kicad_setting import KiCadSetting +from kicad_amf_plugin.order.supported_region import SupportedRegion +from kicad_amf_plugin.utils.public_ip import get_ip_country + +APP_NAME = "kicad_amf_plugin" + +VENDOR_NAME = "NextPCB" + +LANGUAGE = "language" + +ORDER_REGION = "order_region" + +WIDTH = "width" + +HEIGHT = "height" + +PRICE_UNIT = {0: "¥", 1: "$"} + +TRANSLATED_PRICE_UNIT = {"¥": "元", "$": "美元"} + + +CN_JP_BUILD_TIME_FORMATTER = "{time}{unit}" + +EN_BUILD_TIME_FORMATTER = "{time} {unit}" + + +class _SettingManager(wx.EvtHandler): + def __init__(self) -> None: + self.app: wx.App = None + sp = wx.StandardPaths.Get() + config_loc = sp.GetUserConfigDir() + config_loc = os.path.join(config_loc, APP_NAME) + + if not os.path.exists(config_loc): + os.mkdir(config_loc) + + self.app_conf = wx.FileConfig( + appName=APP_NAME, + vendorName=VENDOR_NAME, + localFilename=os.path.join(config_loc, "common.ini"), + ) + + if not self.app_conf.HasEntry(LANGUAGE): + self.set_language(KiCadSetting.read_lang_setting()) + self.app_conf.Flush() + if not self.app_conf.HasEntry(WIDTH) or not self.app_conf.HasEntry(HEIGHT): + self.set_window_size((660, 700)) + if not self.app_conf.HasEntry(ORDER_REGION): + location = get_ip_country() + if location == "China": + self.set_order_region(SupportedRegion.CHINA_MAINLAND) + elif location == "Japan": + self.set_order_region(SupportedRegion.JAPAN) + else: + self.set_order_region(SupportedRegion.EUROPE_USA) + + def register_app(self, app: wx.App): + self.app = app + + def set_language(self, now: int): + old = self.language + if old == now: + return + self.app_conf.WriteInt(key=LANGUAGE, value=now) + if self.app: + evt = LocaleChangeEvent(id=-1) + evt.SetInt(now) + self.app_conf.Flush() + wx.PostEvent(self.app, evt) + + @property + def language(self): + return self.app_conf.ReadInt(LANGUAGE) + + def set_order_region(self, region: int): + self.app_conf.WriteInt(key=ORDER_REGION, value=region) + + @property + def order_region(self): + return self.app_conf.ReadInt(ORDER_REGION) + + def get_price_unit(self, translated=False): + sym = "¥" if not self.order_region else "$" + if not translated: + return sym + if self.language == wx.LANGUAGE_CHINESE_SIMPLIFIED: + return TRANSLATED_PRICE_UNIT[sym] + return sym + + def get_build_time_formatter(self): + return ( + EN_BUILD_TIME_FORMATTER + if SupportedRegion.EUROPE_USA == self.order_region + else CN_JP_BUILD_TIME_FORMATTER + ) + + def set_window_size(self, s: "tuple[int,int]"): + self.app_conf.WriteInt(key=WIDTH, value=s[0]) + self.app_conf.WriteInt(key=HEIGHT, value=s[1]) + self.app_conf.Flush() + + def get_window_size(self): + return wx.Size(self.app_conf.ReadInt(WIDTH), self.app_conf.ReadInt(HEIGHT)) + + +SETTING_MANAGER = _SettingManager() diff --git a/kicad_amf_plugin/settings/single_plugin.py b/kicad_amf_plugin/settings/single_plugin.py new file mode 100644 index 0000000..bb6535e --- /dev/null +++ b/kicad_amf_plugin/settings/single_plugin.py @@ -0,0 +1,23 @@ +import wx + + +class _SinglePlugin: + def __init__(self) -> None: + self.app: wx.App = None + self.wind: wx.TopLevelWindow = None + + def register_main_wind(self, wind: wx.TopLevelWindow): + self.wind = wind + + def get_main_wind(self): + return self.wind + + def show_existing(self): + if not self.wind is None: + self.wind.Show(False) + self.wind.Show(True) + return True + return False + + +SINGLE_PLUGIN = _SinglePlugin() diff --git a/kicad_amf_plugin/settings/supported_layer_count.py b/kicad_amf_plugin/settings/supported_layer_count.py new file mode 100644 index 0000000..59df4d2 --- /dev/null +++ b/kicad_amf_plugin/settings/supported_layer_count.py @@ -0,0 +1 @@ +AVAILABLE_LAYER_COUNTS = [1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20] diff --git a/kicad_amf_plugin/utils/__init__.py b/kicad_amf_plugin/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kicad_amf_plugin/utils/combo_box_ignore_wheel.py b/kicad_amf_plugin/utils/combo_box_ignore_wheel.py new file mode 100644 index 0000000..a9b5bf6 --- /dev/null +++ b/kicad_amf_plugin/utils/combo_box_ignore_wheel.py @@ -0,0 +1,23 @@ +import wx + + +class ComboBoxIgnoreWheel(wx.Choice): + def __init__(self, *args, **kw): + super().__init__(*args, **kw) + self.wheel_evt_handle = None + self.parent_can_hand_wheel = True + + def ProcessEvent(self, evt: wx.Event): + if evt.EventType == wx.wxEVT_MOUSEWHEEL: + if self.parent_can_hand_wheel and self.wheel_evt_handle is not None: + self.wheel_evt_handle.HandleWindowEvent(evt) + if not self.wheel_evt_handle: + p = self.Parent + while p: + if p.HandleWindowEvent(evt): + self.wheel_evt_handle = p + return True + p = p.Parent + self.parent_can_hand_wheel = False + return True + return super().ProcessEvent(evt) diff --git a/kicad_amf_plugin/utils/constraint.py b/kicad_amf_plugin/utils/constraint.py new file mode 100644 index 0000000..f02b4d1 --- /dev/null +++ b/kicad_amf_plugin/utils/constraint.py @@ -0,0 +1,6 @@ +import wx + +_ = wx.GetTranslation + + +BOOLEAN_CHOICE = [_("No"), _("Yes")] diff --git a/kicad_amf_plugin/utils/form_panel_base.py b/kicad_amf_plugin/utils/form_panel_base.py new file mode 100644 index 0000000..12b76f0 --- /dev/null +++ b/kicad_amf_plugin/utils/form_panel_base.py @@ -0,0 +1,42 @@ +import abc +from enum import Enum + +from kicad_amf_plugin.order.supported_region import SupportedRegion +from .number_round import number_round + + +class FormKind(Enum): + QUERY_PRICE = 0 + PLACE_ORDER = 1 + + +class FormPanelBase: + def init(self) -> "None": + pass + + def is_valid(self) -> bool: + return True + + @abc.abstractclassmethod + def get_from(self, kind: FormKind) -> "dict": + pass + + def on_region_changed(self): + pass + + @staticmethod + @number_round() + def convert_geometry(form_kind: FormKind, region: SupportedRegion, geometry: float): + """Convert the geometry (mm) to proper unit + + Args: + form_kind (FormKind): + region (SupportedRegion): + geometry (float): mm + """ + if ( + SupportedRegion.CHINA_MAINLAND != region + and FormKind.PLACE_ORDER == form_kind + ): + return geometry + return geometry / 10 diff --git a/kicad_amf_plugin/utils/number_round.py b/kicad_amf_plugin/utils/number_round.py new file mode 100644 index 0000000..fd5c38c --- /dev/null +++ b/kicad_amf_plugin/utils/number_round.py @@ -0,0 +1,8 @@ +def number_round(digit=2): + def decorate(fn): + def wrapper(*args, **kwargs): + return round(fn(*args, **kwargs), digit) + + return wrapper + + return decorate diff --git a/kicad_amf_plugin/utils/platebtn.py b/kicad_amf_plugin/utils/platebtn.py new file mode 100644 index 0000000..e87327a --- /dev/null +++ b/kicad_amf_plugin/utils/platebtn.py @@ -0,0 +1,817 @@ +############################################################################### +# Name: platebtn.py # +# Purpose: PlateButton is a flat label button with support for bitmaps and # +# drop menu. # +# Author: Cody Precord # +# Copyright: (c) 2007 Cody Precord # +# Licence: wxWindows Licence # +# Tags: phoenix-port +############################################################################### + +""" +Editra Control Library: PlateButton + +The PlateButton is a custom owner drawn flat button, that in many ways emulates +the buttons found the bookmark bar of the Safari browser. It can be used as a +drop in replacement for wx.Button/wx.BitmapButton under most circumstances. It +also offers a wide range of options for customizing its appearance, a +description of each of the main style settings is listed below. + +Main Button Styles: +Any combination of the following values may be passed to the constructor's style +keyword parameter. + +PB_STYLE_DEFAULT: +Creates a flat label button with rounded corners, the highlight for mouse over +and press states is based off of the highlight color from the systems current +theme. + +PB_STYLE_GRADIENT: +The highlight and press states are drawn with gradient using the current +highlight color. + +PB_STYLE_SQUARE: +Instead of the default rounded shape use a rectangular shaped button with +square edges. + +PB_STYLE_NOBG: +This style only has an effect on Windows but does not cause harm to use on the +platforms. It should only be used when the control is shown on a panel or other +window that has a non solid color for a background. i.e a gradient or image is +painted on the background of the parent window. If used on a background with +a solid color it may cause the control to loose its transparent appearance. + +PB_STYLE_DROPARROW: +Add a drop button arrow to the button that will send a separate event when +clicked on. + +Other attributes can be configured after the control has been created. The +settings that are currently available are as follows: + + - SetBitmap: Change/Add the bitmap at any time and the control will resize and + refresh to display it. + - SetLabelColor: Explicitly set text colors + - SetMenu: Set the button to have a popupmenu. When a menu is set a small drop + arrow will be drawn on the button that can then be clicked to show + a menu. + - SetPressColor: Use a custom highlight color + + +Overridden Methods Inherited from PyControl: + + - SetFont: Changing the font is one way to set the size of the button, by + default the control will inherit its font from its parent. + + - SetWindowVariant: Setting the window variant will cause the control to + resize to the corresponding variant size. However if the + button is using a bitmap the bitmap will remain unchanged + and only the font will be adjusted. + +Requirements: + - python2.4 or higher + - wxPython2.8 or higher + +""" + +__author__ = "Cody Precord " + +__all__ = [ + "PlateButton", + "PLATE_NORMAL", + "PLATE_PRESSED", + "PLATE_HIGHLIGHT", + "PB_STYLE_DEFAULT", + "PB_STYLE_GRADIENT", + "PB_STYLE_SQUARE", + "PB_STYLE_NOBG", + "PB_STYLE_DROPARROW", + "PB_STYLE_TOGGLE", + "EVT_PLATEBTN_DROPARROW_PRESSED", +] + +# -----------------------------------------------------------------------------# +# Imports +import wx +import wx.lib.newevent + +# Local Imports +from wx.lib.colourutils import * + +# -----------------------------------------------------------------------------# +# Button States +PLATE_NORMAL = 0 +PLATE_PRESSED = 1 +PLATE_HIGHLIGHT = 2 + +# Button Styles +PB_STYLE_DEFAULT = 1 # Normal Flat Background +PB_STYLE_GRADIENT = 2 # Gradient Filled Background +PB_STYLE_SQUARE = 4 # Use square corners instead of rounded +PB_STYLE_NOBG = 8 # Useful on Windows to get a transparent appearance +# when the control is shown on a non solid background +PB_STYLE_DROPARROW = 16 # Draw drop arrow and fire EVT_PLATEBTN_DROPRROW_PRESSED event +PB_STYLE_TOGGLE = 32 # Stay pressed until clicked again + +# -----------------------------------------------------------------------------# + +# EVT_BUTTON used for normal event notification +# EVT_TOGGLE_BUTTON used for toggle button mode notification +PlateBtnDropArrowPressed, EVT_PLATEBTN_DROPARROW_PRESSED = wx.lib.newevent.NewEvent() + +# -----------------------------------------------------------------------------# + + +class PlateButton(wx.Control): + """PlateButton is a custom type of flat button with support for + displaying bitmaps and having an attached dropdown menu. + + """ + + def __init__( + self, + parent, + id=wx.ID_ANY, + label="", + bmp=None, + pos=wx.DefaultPosition, + size=wx.DefaultSize, + style=PB_STYLE_DEFAULT, + name=wx.ButtonNameStr, + ): + """Create a PlateButton + + :keyword string `label`: Buttons label text + :keyword wx.Bitmap `bmp`: Buttons bitmap + :keyword `style`: Button style + + """ + super(PlateButton, self).__init__( + parent, id, pos, size, wx.BORDER_NONE | wx.TRANSPARENT_WINDOW, name=name + ) + + # Attributes + self.InheritAttributes() + self._bmp = dict(enable=None, disable=None) + if bmp is not None: + assert isinstance(bmp, wx.Bitmap) and bmp.IsOk() + self._bmp["enable"] = bmp + img = bmp.ConvertToImage() + img = img.ConvertToGreyscale(0.795, 0.073, 0.026) # (.634, .224, .143) + self._bmp["disable"] = wx.Bitmap(img) + + self._menu = None + self.SetLabel(label) + self._style = style + self._state = dict(pre=PLATE_NORMAL, cur=PLATE_NORMAL) + self._color = self.__InitColors() + self._pressed = False + + # Setup Initial Size + self.SetInitialSize(size) + + # Event Handlers + self.Bind(wx.EVT_PAINT, lambda evt: self.__DrawButton()) + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase) + self.Bind(wx.EVT_SET_FOCUS, self.OnFocus) + self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) + + # Mouse Events + self.Bind(wx.EVT_LEFT_DCLICK, lambda evt: self._ToggleState()) + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) + self.Bind(wx.EVT_ENTER_WINDOW, lambda evt: self._SetState(PLATE_HIGHLIGHT)) + self.Bind(wx.EVT_LEAVE_WINDOW, lambda evt: wx.CallLater(80, self.__LeaveWindow)) + + # Other events + self.Bind(wx.EVT_KEY_UP, self.OnKeyUp) + self.Bind(wx.EVT_CONTEXT_MENU, lambda evt: self.ShowMenu()) + + def __DrawBitmap(self, gc): + """Draw the bitmap if one has been set + + :param wx.GCDC `gc`: :class:`wx.GCDC` to draw with + :return: x coordinate to draw text at + + """ + + tw, _ = gc.GetTextExtent(self.Label) + width, height = self.GetSize() + if self.IsEnabled(): + bmp = self._bmp["enable"] + else: + bmp = self._bmp["disable"] + + if bmp is not None and bmp.IsOk(): + bw, bh = bmp.GetSize() + ypos = (self.GetSize()[1] - bh) // 2 + if tw > 0: + gc.DrawBitmap( + bmp, (width - tw) // 2 - bw - 6, ypos, bmp.GetMask() is not None + ) + else: + gc.DrawBitmap(bmp, 6, ypos, bmp.GetMask() is not None) + + def __DrawDropArrow(self, gc, xpos, ypos): + """Draw a drop arrow if needed and restore pen/brush after finished + + :param wx.GCDC `gc`: :class:`wx.GCDC` to draw with + :param int `xpos`: x cord to start at + :param int `ypos`: y cord to start at + + """ + if self._menu is not None or self._style & PB_STYLE_DROPARROW: + # Positioning needs a little help on Windows + if wx.Platform == "__WXMSW__": + xpos -= 2 + tripoints = [(xpos, ypos), (xpos + 6, ypos), (xpos + 3, ypos + 5)] + brush_b = gc.GetBrush() + pen_b = gc.GetPen() + gc.SetPen(wx.TRANSPARENT_PEN) + gc.SetBrush(wx.Brush(gc.GetTextForeground())) + gc.DrawPolygon(tripoints) + gc.SetBrush(brush_b) + gc.SetPen(pen_b) + else: + pass + + def __DrawHighlight(self, gc, width, height): + """Draw the main highlight/pressed state + + :param wx.GCDC `gc`: :class:`wx.GCDC` to draw with + :param int `width`: width of highlight + :param int `height`: height of highlight + + """ + if self._state["cur"] == PLATE_PRESSED: + color = self._color["press"] + else: + color = self._color["hlight"] + + if self._style & PB_STYLE_SQUARE: + rad = 0 + else: + rad = (height - 3) // 2 + + if self._style & PB_STYLE_GRADIENT: + gc.SetBrush(wx.TRANSPARENT_BRUSH) + rgc = gc.GetGraphicsContext() + brush = rgc.CreateLinearGradientBrush( + 0, 1, 0, height, color, AdjustAlpha(color, 55) + ) + rgc.SetBrush(brush) + else: + gc.SetBrush(wx.Brush(color)) + + gc.DrawRoundedRectangle(1, 1, width - 2, height - 2, rad) + + def __DrawNormal(self, gc, width, height): + """Draw the main highlight/pressed state + + :param wx.GCDC `gc`: :class:`wx.GCDC` to draw with + :param int `width`: width of highlight + :param int `height`: height of highlight + + """ + # if self._state['cur'] == PLATE_PRESSED: + # color = self._color['press'] + # else: + # color = self._color['hlight'] + + color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_MENUBAR) + + if self._style & PB_STYLE_SQUARE: + rad = 0 + else: + rad = (height - 3) // 2 + + if self._style & PB_STYLE_GRADIENT: + gc.SetBrush(wx.TRANSPARENT_BRUSH) + rgc = gc.GetGraphicsContext() + brush = rgc.CreateLinearGradientBrush( + 0, 1, 0, height, color, AdjustAlpha(color, 55) + ) + rgc.SetBrush(brush) + else: + gc.SetBrush(wx.Brush(color)) + + gc.DrawRoundedRectangle(1, 1, width - 2, height - 2, rad) + + def __PostEvent(self): + """Post a button event to parent of this control""" + if self._style & PB_STYLE_TOGGLE: + etype = wx.wxEVT_COMMAND_TOGGLEBUTTON_CLICKED + else: + etype = wx.wxEVT_COMMAND_BUTTON_CLICKED + bevt = wx.CommandEvent(etype, self.GetId()) + bevt.SetEventObject(self) + bevt.SetString(self.GetLabel()) + self.GetEventHandler().ProcessEvent(bevt) + + def __DrawButton(self): + """Draw the button""" + # TODO using a buffered paintdc on windows with the nobg style + # causes lots of weird drawing. So currently the use of a + # buffered dc is disabled for this style. + if PB_STYLE_NOBG & self._style: + dc = wx.PaintDC(self) + else: + dc = wx.AutoBufferedPaintDCFactory(self) + + gc = wx.GCDC(dc) + + # Setup + dc.SetBrush(wx.TRANSPARENT_BRUSH) + gc.SetBrush(wx.TRANSPARENT_BRUSH) + gc.SetFont(self.Font) + dc.SetFont(self.Font) + gc.SetBackgroundMode(wx.TRANSPARENT) + + # The background needs some help to look transparent on + # on Gtk and Windows + if wx.Platform in ["__WXGTK__", "__WXMSW__"]: + gc.SetBackground(self.GetBackgroundBrush(gc)) + gc.Clear() + + # Calc Object Positions + width, height = self.GetSize() + if wx.Platform == "__WXGTK__": + tw, th = dc.GetTextExtent(self.Label) + else: + tw, th = gc.GetTextExtent(self.Label) + txt_y = max((height - th) // 2, 1) + + if self._state["cur"] == PLATE_HIGHLIGHT: + gc.SetTextForeground(self._color["htxt"]) + gc.SetPen(wx.TRANSPARENT_PEN) + self.__DrawHighlight(gc, width, height) + + elif self._state["cur"] == PLATE_PRESSED: + gc.SetTextForeground(self._color["htxt"]) + if wx.Platform == "__WXMAC__": + pen = wx.Pen(GetHighlightColour(), 1, wx.PENSTYLE_SOLID) + else: + pen = wx.Pen(AdjustColour(self._color["press"], -80, 220), 1) + gc.SetPen(pen) + + self.__DrawHighlight(gc, width, height) + self.__DrawBitmap(gc) + # if wx.Platform == '__WXGTK__': + # dc.DrawText(self.Label, txt_x + 2, txt_y) + # else: + # gc.DrawText(self.Label, txt_x + 2, txt_y) + if wx.Platform == "__WXGTK__": + dc.DrawText(self.Label, (width - tw) // 2, txt_y) + else: + gc.DrawText(self.Label, (width - tw) // 2, txt_y) + self.__DrawDropArrow(gc, width - 10, (height // 2) - 2) + + else: + if self.IsEnabled(): + gc.SetTextForeground(self.GetForegroundColour()) + else: + txt_c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT) + gc.SetTextForeground(txt_c) + self.__DrawNormal(gc, width, height) + + # Draw bitmap and text + if self._state["cur"] != PLATE_PRESSED: + self.__DrawBitmap(gc) + # if wx.Platform == '__WXGTK__': + # dc.DrawText(self.Label, txt_x + 2, txt_y) + # else: + # gc.DrawText(self.Label, txt_x + 2, txt_y) + if wx.Platform == "__WXGTK__": + dc.DrawText(self.Label, (width - tw) // 2, txt_y) + else: + gc.DrawText(self.Label, (width - tw) // 2, txt_y) + self.__DrawDropArrow(gc, width - 10, (height // 2) - 2) + + def __InitColors(self): + """Initialize the default colors""" + color = GetHighlightColour() + pcolor = AdjustColour(color, -12) + colors = dict( + default=True, + hlight=color, + press=pcolor, + htxt=BestLabelColour(self.GetForegroundColour()), + ) + return colors + + def __LeaveWindow(self): + """Handle updating the buttons state when the mouse cursor leaves""" + if (self._style & PB_STYLE_TOGGLE) and self._pressed: + self._SetState(PLATE_PRESSED) + else: + self._SetState(PLATE_NORMAL) + self._pressed = False + + def _SetState(self, state): + """Manually set the state of the button + + :param `state`: one of the PLATE_* values + + .. note:: + the state may be altered by mouse actions + + .. note:: + Internal use only! + + """ + self._state["pre"] = self._state["cur"] + self._state["cur"] = state + if wx.Platform == "__WXMSW__": + self.Parent.RefreshRect(self.Rect, False) + else: + self.Refresh() + + def _ToggleState(self): + """Toggle button state + + ..note:: + Internal Use Only! + + """ + if self._state["cur"] != PLATE_PRESSED: + self._SetState(PLATE_PRESSED) + else: + self._SetState(PLATE_HIGHLIGHT) + + # ---- End Private Member Function ----# + + # ---- Public Member Functions ----# + + BitmapDisabled = property( + lambda self: self.GetBitmapDisabled(), + lambda self, bmp: self.SetBitmapDisabled(bmp), + ) + BitmapLabel = property( + lambda self: self.GetBitmapLabel(), lambda self, bmp: self.SetBitmap(bmp) + ) + + # Aliases + BitmapFocus = BitmapLabel + BitmapHover = BitmapLabel + BitmapSelected = BitmapLabel + + LabelText = property( + lambda self: self.GetLabel(), lambda self, lbl: self.SetLabel(lbl) + ) + + def AcceptsFocus(self): + """Can this window have the focus?""" + return self.IsEnabled() + + def Disable(self): + """Disable the control""" + super(PlateButton, self).Disable() + self.Refresh() + + def DoGetBestSize(self): + """Calculate the best size of the button + + :return: :class:`wx.Size` + + """ + width = 4 + height = 6 + if self.Label: + # NOTE: Should measure with a GraphicsContext to get right + # size, but due to random segfaults on linux special + # handling is done in the drawing instead... + lsize = self.GetFullTextExtent(self.Label) + width += lsize[0] + height += lsize[1] + + if self._bmp["enable"] is not None: + bsize = self._bmp["enable"].Size + width += bsize[0] + 10 + if height <= bsize[1]: + height = bsize[1] + 6 + else: + height += 3 + else: + width += 10 + + if self._menu is not None or self._style & PB_STYLE_DROPARROW: + width += 12 + + best = wx.Size(width, height) + self.CacheBestSize(best) + return best + + def Enable(self, enable=True): + """Enable/Disable the control""" + super(PlateButton, self).Enable(enable) + self.Refresh() + + def GetBackgroundBrush(self, dc): + """Get the brush for drawing the background of the button + + :return: :class:`wx.Brush` + + ..note:: + used internally when on gtk + + """ + if wx.Platform == "__WXMAC__" or self._style & PB_STYLE_NOBG: + return wx.TRANSPARENT_BRUSH + + bkgrd = self.GetBackgroundColour() + brush = wx.Brush(bkgrd, wx.BRUSHSTYLE_SOLID) + my_attr = self.GetDefaultAttributes() + p_attr = self.Parent.GetDefaultAttributes() + my_def = bkgrd == my_attr.colBg + p_def = self.Parent.GetBackgroundColour() == p_attr.colBg + if my_def and not p_def: + bkgrd = self.Parent.GetBackgroundColour() + brush = wx.Brush(bkgrd, wx.BRUSHSTYLE_SOLID) + return brush + + def GetBitmapDisabled(self): + """Get the bitmap of the disable state + + :return: :class:`wx.Bitmap` or None + + """ + return self.BitmapDisabled + + def GetBitmapLabel(self): + """Get the label bitmap + + :return: :class:`wx.Bitmap` or None + + """ + return self.BitmapLabel + + # GetBitmap Aliases for BitmapButton api + GetBitmapFocus = GetBitmapLabel + GetBitmapHover = GetBitmapLabel + + # Alias for GetLabel + GetLabelText = wx.Control.GetLabel + + def GetMenu(self): + """Return the menu associated with this button or None if no + menu is associated with it. + + """ + return self._menu + + def GetState(self): + """Get the current state of the button + + :return: int + + .. seeAlso:: + PLATE_NORMAL, PLATE_HIGHLIGHT, PLATE_PRESSED + + """ + return self._state["cur"] + + def HasTransparentBackground(self): + """Override setting of background fill""" + return True + + def IsPressed(self): + """Return if button is pressed (PB_STYLE_TOGGLE) + + :return: bool + + """ + return self._pressed + + # ---- Event Handlers ----# + + def OnErase(self, evt): + """Trap the erase event to keep the background transparent + on windows. + + :param `evt`: wx.EVT_ERASE_BACKGROUND + + """ + pass + + def OnFocus(self, evt): + """Set the visual focus state if need be""" + if self._state["cur"] == PLATE_NORMAL: + self._SetState(PLATE_HIGHLIGHT) + + def OnKeyUp(self, evt): + """Execute a single button press action when the Return key is pressed + and this control has the focus. + + :param `evt`: wx.EVT_KEY_UP + + """ + if evt.GetKeyCode() == wx.WXK_SPACE: + self._SetState(PLATE_PRESSED) + self.__PostEvent() + wx.CallLater(100, self._SetState, PLATE_HIGHLIGHT) + else: + evt.Skip() + + def OnKillFocus(self, evt): + """Set the visual state back to normal when focus is lost + unless the control is currently in a pressed state. + + """ + # Note: this delay needs to be at least as much as the on in the KeyUp + # handler to prevent ghost highlighting from happening when + # quickly changing focus and activating buttons + if self._state["cur"] != PLATE_PRESSED: + self._SetState(PLATE_NORMAL) + + def OnLeftDown(self, evt): + """Sets the pressed state and depending on the click position will + show the popup menu if one has been set. + + """ + if self._style & PB_STYLE_TOGGLE: + self._pressed = not self._pressed + + pos = evt.GetPosition() + self._SetState(PLATE_PRESSED) + size = self.GetSize() + if pos[0] >= size[0] - 16: + if self._menu is not None: + self.ShowMenu() + elif self._style & PB_STYLE_DROPARROW: + event = PlateBtnDropArrowPressed() + event.SetEventObject(self) + self.EventHandler.ProcessEvent(event) + + self.SetFocus() + + def OnLeftUp(self, evt): + """Post a button event if the control was previously in a + pressed state. + + :param `evt`: :class:`wx.MouseEvent` + + """ + if self._state["cur"] == PLATE_PRESSED: + pos = evt.GetPosition() + size = self.GetSize() + if not (self._style & PB_STYLE_DROPARROW and pos[0] >= size[0] - 16): + self.__PostEvent() + + if self._pressed: + self._SetState(PLATE_PRESSED) + else: + self._SetState(PLATE_HIGHLIGHT) + + def OnMenuClose(self, evt): + """Refresh the control to a proper state after the menu has been + dismissed. + + :param `evt`: wx.EVT_MENU_CLOSE + + """ + mpos = wx.GetMousePosition() + if self.HitTest(self.ScreenToClient(mpos)) != wx.HT_WINDOW_OUTSIDE: + self._SetState(PLATE_HIGHLIGHT) + else: + self._SetState(PLATE_NORMAL) + evt.Skip() + + # ---- End Event Handlers ----# + + def SetBitmap(self, bmp): + """Set the bitmap displayed in the button + + :param `bmp`: :class:`wx.Bitmap` + + """ + self._bmp["enable"] = bmp + img = bmp.ConvertToImage() + img = img.ConvertToGreyscale(0.795, 0.073, 0.026) # (.634, .224, .143) + self._bmp["disable"] = img.ConvertToBitmap() + self.InvalidateBestSize() + + def SetBitmapDisabled(self, bmp): + """Set the bitmap for the disabled state + + :param `bmp`: :class:`wx.Bitmap` + + """ + self._bmp["disable"] = bmp + + # Aliases for SetBitmap* functions from BitmapButton + SetBitmapFocus = SetBitmap + SetBitmapHover = SetBitmap + SetBitmapLabel = SetBitmap + SetBitmapSelected = SetBitmap + + def SetFocus(self): + """Set this control to have the focus""" + if self._state["cur"] != PLATE_PRESSED: + self._SetState(PLATE_HIGHLIGHT) + super(PlateButton, self).SetFocus() + + def SetFont(self, font): + """Adjust size of control when font changes""" + super(PlateButton, self).SetFont(font) + self.InvalidateBestSize() + + def SetLabel(self, label): + """Set the label of the button + + :param string `label`: label string + + """ + super(PlateButton, self).SetLabel(label) + self.InvalidateBestSize() + + def SetLabelColor(self, normal, hlight=wx.NullColour): + """Set the color of the label. The optimal label color is usually + automatically selected depending on the button color. In some + cases the colors that are chosen may not be optimal. + + The normal state must be specified, if the other two params are left + Null they will be automatically guessed based on the normal color. To + prevent this automatic color choices from happening either specify + a color or None for the other params. + + :param wx.Colour `normal`: Label color for normal state (:class:`wx.Colour`) + :keyword wx.Colour `hlight`: Color for when mouse is hovering over + + """ + assert isinstance(normal, wx.Colour), "Must supply a colour object" + self._color["default"] = False + self.SetForegroundColour(normal) + + if hlight is not None: + if hlight.IsOk(): + self._color["htxt"] = hlight + else: + self._color["htxt"] = BestLabelColour(normal) + + if wx.Platform == "__WXMSW__": + self.Parent.RefreshRect(self.GetRect(), False) + else: + self.Refresh() + + def SetMenu(self, menu): + """Set the menu that can be shown when clicking on the + drop arrow of the button. + + :param wx.Menu `menu`: :class:`wx.Menu` to use as a PopupMenu + + .. note:: + Arrow is not drawn unless a menu is set + + """ + if self._menu is not None: + self.Unbind(wx.EVT_MENU_CLOSE) + + self._menu = menu + self.Bind(wx.EVT_MENU_CLOSE, self.OnMenuClose) + self.InvalidateBestSize() + + def SetPressColor(self, color): + """Set the color used for highlighting the pressed state + + :param wx.Colour `color`: :class:`wx.Colour` + + .. note:: + also resets all text colours as necessary + + """ + self._color["default"] = False + if color.Alpha() == 255: + self._color["hlight"] = AdjustAlpha(color, 200) + else: + self._color["hlight"] = color + self._color["press"] = AdjustColour(color, -10, 160) + self._color["htxt"] = BestLabelColour(self._color["hlight"]) + self.Refresh() + + def SetWindowStyle(self, style): + """Sets the window style bytes, the updates take place + immediately no need to call refresh afterwards. + + :param `style`: bitmask of PB_STYLE_* values + + """ + self._style = style + self.Refresh() + + def SetWindowVariant(self, variant): + """Set the variant/font size of this control""" + super(PlateButton, self).SetWindowVariant(variant) + self.InvalidateBestSize() + + def ShouldInheritColours(self): + """Overridden base class virtual. If the parent has non-default + colours then we want this control to inherit them. + + """ + return True + + def ShowMenu(self): + """Show the dropdown menu if one is associated with this control""" + if self._menu is not None: + self.PopupMenu(self._menu) + + # ---- End Public Member Functions ----# diff --git a/kicad_amf_plugin/utils/public_ip/__init__.py b/kicad_amf_plugin/utils/public_ip/__init__.py new file mode 100644 index 0000000..2cc25a7 --- /dev/null +++ b/kicad_amf_plugin/utils/public_ip/__init__.py @@ -0,0 +1,3 @@ +from ._ip import get, get_ip_country + +__version__ = "0.12" diff --git a/kicad_amf_plugin/utils/public_ip/_ip.py b/kicad_amf_plugin/utils/public_ip/_ip.py new file mode 100644 index 0000000..98f081f --- /dev/null +++ b/kicad_amf_plugin/utils/public_ip/_ip.py @@ -0,0 +1,104 @@ +#! /usr/bin/env python3 + +import collections +import logging +import random +import requests +import threading +import typing +from queue import Queue +import urllib +import json + +URLS = [ + "https://api.ipify.org", + "https://checkip.amazonaws.com", + "https://icanhazip.com", + "https://ifconfig.co/ip", + "https://ipecho.net/plain", + "https://ipinfo.io/ip", +] + + +def _get_ip(url: str, queue: Queue, timeout: float) -> None: + """Get external IP from 'url' and put it into 'queue'.""" + + try: + r = requests.get(url, timeout=timeout) + r.raise_for_status() + ip = r.text.strip() + logging.info("Asked %s for our IP -> %s", url, ip) + queue.put(ip) + except (requests.exceptions.HTTPError, requests.exceptions.Timeout): + pass + + +def get(nurls: int = len(URLS), timeout: float = 1) -> str: + """ "Returns the current external IP. + + Launches 'nurls' processes in parallel, each one of them fetching the + external IP from one of the websites in the URLS module-level variable. + Each independent request timeouts after 'timeout' seconds. After all of + them have completed, returns the most common IP. In this manner we will + return the correct IP as long as the majority of URLs we talk to report + our actual IP. + """ + + threads = [] + queue: Queue = Queue() + for url in random.sample(URLS, nurls): + t = threading.Thread(target=_get_ip, args=(url, queue, timeout)) + threads.append(t) + t.start() + + for t in threads: + t.join() + + ips = [] + while not queue.empty(): + ips.append(queue.get()) + + if not ips: + raise IOError("all server queries failed") + + # If there's a single IP among the responses, we're done. + counter = collections.Counter(ips) + if len(counter) == 1: + return counter.most_common(1)[0][0] + + # Make sure there isn't a tie among the two most common IPs. + top_two = counter.most_common(2) + first_ip, first_votes = top_two[0] + second_ip, second_votes = top_two[1] + if first_votes == second_votes: + raise ValueError( + f"tie between {first_ip} and {second_ip} among the " + "responses ({first_votes} occurrences each)" + ) + return first_ip + + +def get_ip(): + response = requests.get("https://api64.ipify.org?format=json").json() + return response["ip"] + + +def get_ip_country(): + GEO_IP_API_URL = "http://ip-api.com/json/" + + # Can be also site URL like this : 'google.com' + IP_TO_SEARCH = "210.138.184.59" + + # Creating request object to GeoLocation API + req = urllib.request.Request(GEO_IP_API_URL + IP_TO_SEARCH) + # Getting in response JSON + response = urllib.request.urlopen(req).read() + # Loading JSON from text to object + json_response = json.loads(response.decode("utf-8")) + + # Print country + return json_response["country"] + + +if __name__ == "__main__": + print(get_ip_country()) diff --git a/kicad_amf_plugin/utils/request_helper.py b/kicad_amf_plugin/utils/request_helper.py new file mode 100644 index 0000000..26d5c09 --- /dev/null +++ b/kicad_amf_plugin/utils/request_helper.py @@ -0,0 +1,7 @@ +from urllib import parse + + +class RequestHelper: + @staticmethod + def convert_dict_to_request_data(input: "dict"): + return parse.urlencode(list(input.items())).encode() diff --git a/kicad_amf_plugin/utils/roles.py b/kicad_amf_plugin/utils/roles.py new file mode 100644 index 0000000..778f4ce --- /dev/null +++ b/kicad_amf_plugin/utils/roles.py @@ -0,0 +1,10 @@ +import collections +from enum import Enum + + +class Role(Enum): + EditRole = 0 + DisplayRole = EditRole + 1 + + +EditDisplayRole = collections.namedtuple("EditDisplayRole", ["EditRole", "DisplayRole"]) diff --git a/validators.py b/kicad_amf_plugin/utils/validators.py similarity index 72% rename from validators.py rename to kicad_amf_plugin/utils/validators.py index 44581e2..710a4eb 100644 --- a/validators.py +++ b/kicad_amf_plugin/utils/validators.py @@ -1,55 +1,63 @@ -import wx - -class NumericTextCtrlValidator(wx.Validator): - def __init__(self): - wx.Validator.__init__(self) - - def Clone(self): - return NumericTextCtrlValidator() - - def Validate(self, parent): - text_ctrl = self.GetWindow() - value = text_ctrl.GetValue() - if value.isdigit(): - text_ctrl.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - text_ctrl.Refresh() - return True - else: - text_ctrl.SetBackgroundColour(wx.Colour(255, 128, 128)) - text_ctrl.Refresh() - return False - - def TransferToWindow(self): - return True - - def TransferFromWindow(self): - return True - -class FloatTextCtrlValidator(wx.Validator): - def __init__(self): - wx.Validator.__init__(self) - - def Clone(self): - return FloatTextCtrlValidator() - - def Validate(self, parent): - text_ctrl = self.GetWindow() - value = text_ctrl.GetValue() - if value.isdigit(): - text_ctrl.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - text_ctrl.Refresh() - return True - elif value.replace('.','',1).isdigit() and value.count('.') < 2: - text_ctrl.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)) - text_ctrl.Refresh() - return True - else: - text_ctrl.SetBackgroundColour(wx.Colour(255, 128, 128)) - text_ctrl.Refresh() - return False - - def TransferToWindow(self): - return True - - def TransferFromWindow(self): - return True +import wx + + +class NumericTextCtrlValidator(wx.Validator): + def __init__(self): + wx.Validator.__init__(self) + + def Clone(self): + return NumericTextCtrlValidator() + + def Validate(self, parent): + text_ctrl = self.GetWindow() + value = text_ctrl.GetValue() + if value.isdigit(): + text_ctrl.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + text_ctrl.Refresh() + return True + else: + text_ctrl.SetBackgroundColour(wx.Colour(255, 128, 128)) + text_ctrl.Refresh() + return False + + def TransferToWindow(self): + return True + + def TransferFromWindow(self): + return True + + +class FloatTextCtrlValidator(wx.Validator): + def __init__(self): + wx.Validator.__init__(self) + + def Clone(self): + return FloatTextCtrlValidator() + + def Validate(self, parent): + text_ctrl = self.GetWindow() + value = text_ctrl.GetValue() + if value.isdigit(): + text_ctrl.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + text_ctrl.Refresh() + return True + elif value.replace(".", "", 1).isdigit() and value.count(".") < 2: + text_ctrl.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) + ) + text_ctrl.Refresh() + return True + else: + text_ctrl.SetBackgroundColour(wx.Colour(255, 128, 128)) + text_ctrl.Refresh() + return False + + def TransferToWindow(self): + return True + + def TransferFromWindow(self): + return True diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..6eed8bb --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,4 @@ +python-gettext +pytest +requests +pre-commit diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..7bb0456 --- /dev/null +++ b/test/__init__.py @@ -0,0 +1,5 @@ +import sys +import os + +TEST_ROOT = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(os.path.abspath(os.path.join(TEST_ROOT, ".."))) diff --git a/test/query_price/hq_pcb.json b/test/query_price/hq_pcb.json new file mode 100644 index 0000000..0b553ea --- /dev/null +++ b/test/query_price/hq_pcb.json @@ -0,0 +1,44 @@ +{ + "service": "pcb", + "region_id": "211", + "country": "211", + "express": "顺丰快递", + "blayer": "4", + "blength": "10.09", + "bwidth": "8.02", + "bcount": "5", + "sidedirection": "无", + "plate_type": "FR-4", + "units": "1", + "testpoint": 0, + "board_tg": "TG130", + "bheight": "2.5", + "copper": "1", + "lineweight": "10", + "vias": "0.15", + "color": "绿色", + "charcolor": "白色", + "cover": "过孔盖油", + "spray": "有铅喷锡", + "insidecopper": "0.5", + "impendance": "0", + "bankong": "0", + "blind": "0", + "via_in_pad": "无", + "beveledge": "0", + "pressing": "", + "baobian": "0", + "test": "Sample Test Free", + "shipment_report": "0", + "slice_report": "0", + "report_type": "0", + "review_file": 0, + "has_period": "2", + "film_report": "0", + "pcb_note": "", + "cross_board": 1, + "paper": 1, + "user_stamp": 1, + "hq_pack": 1, + "address": "广东省深圳市" +} diff --git a/test/query_price/next_pcb_en.json b/test/query_price/next_pcb_en.json new file mode 100644 index 0000000..dcadd8a --- /dev/null +++ b/test/query_price/next_pcb_en.json @@ -0,0 +1,42 @@ +{ + "service": "pcb", + "region_id": "211", + "country": "211", + "express": "31", + "blayer": "4", + "blength": "10.09", + "bwidth": "8.02", + "bcount": "5", + "sidedirection": "N/A", + "plate_type": "FR-4", + "units": "1", + "testpoint": 0, + "board_tg": "TG130", + "bheight": "2.5", + "copper": "1", + "lineweight": "10", + "vias": "0.15", + "color": "Green", + "charcolor": "White", + "cover": "Tenting Vias", + "spray": "HASL", + "insidecopper": "0.5", + "impendance": "0", + "bankong": "0", + "blind": "0", + "via_in_pad": "N/A", + "beveledge": "0", + "pressing": "", + "baobian": "0", + "test": "Sample Test Free", + "shipment_report": "0", + "slice_report": "0", + "report_type": "0", + "review_file": 0, + "has_period": "2", + "film_report": "0", + "pcb_note": "", + "cross_board": 1, + "paper": 1, + "user_stamp": 1 +} diff --git a/test/query_price/next_pcb_jp.json b/test/query_price/next_pcb_jp.json new file mode 100644 index 0000000..dcadd8a --- /dev/null +++ b/test/query_price/next_pcb_jp.json @@ -0,0 +1,42 @@ +{ + "service": "pcb", + "region_id": "211", + "country": "211", + "express": "31", + "blayer": "4", + "blength": "10.09", + "bwidth": "8.02", + "bcount": "5", + "sidedirection": "N/A", + "plate_type": "FR-4", + "units": "1", + "testpoint": 0, + "board_tg": "TG130", + "bheight": "2.5", + "copper": "1", + "lineweight": "10", + "vias": "0.15", + "color": "Green", + "charcolor": "White", + "cover": "Tenting Vias", + "spray": "HASL", + "insidecopper": "0.5", + "impendance": "0", + "bankong": "0", + "blind": "0", + "via_in_pad": "N/A", + "beveledge": "0", + "pressing": "", + "baobian": "0", + "test": "Sample Test Free", + "shipment_report": "0", + "slice_report": "0", + "report_type": "0", + "review_file": 0, + "has_period": "2", + "film_report": "0", + "pcb_note": "", + "cross_board": 1, + "paper": 1, + "user_stamp": 1 +} diff --git a/test/test_query_price.py b/test/test_query_price.py new file mode 100644 index 0000000..711b524 --- /dev/null +++ b/test/test_query_price.py @@ -0,0 +1,35 @@ +from .test_utils import TestUtils +from . import TEST_ROOT +from kicad_amf_plugin.utils.request_helper import RequestHelper +from kicad_amf_plugin.order.supported_region import SupportedRegion +from kicad_amf_plugin.order.order_region import OrderRegion, URL_KIND + +import requests + +import urllib +import os +import json + +REQUESTS = { + SupportedRegion.CHINA_MAINLAND: "hq_pcb.json", + SupportedRegion.JAPAN: "next_pcb_jp.json", + SupportedRegion.EUROPE_USA: "next_pcb_en.json", +} + + +def test_query_price(): + for i in REQUESTS: + form = TestUtils.read_json(os.path.join(TEST_ROOT, "query_price", REQUESTS[i])) + rep = urllib.request.Request( + OrderRegion.get_url(i, URL_KIND.QUERY_PRICE), + data=RequestHelper.convert_dict_to_request_data(form), + ) + fp = urllib.request.urlopen(rep) + data = fp.read() + encoding = fp.info().get_content_charset("utf-8") + content = data.decode(encoding) + quote = json.loads(content) + if "code" in quote: + assert quote["code"] == 200 + else: + assert quote["total"] > 0 diff --git a/test/test_utils.py b/test/test_utils.py new file mode 100644 index 0000000..32885fe --- /dev/null +++ b/test/test_utils.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import json + + +class TestUtils: + @staticmethod + def read_json(fp: str): + with open(fp, encoding="utf-8") as f: + return json.load(f) diff --git a/urlencodeform.py b/urlencodeform.py deleted file mode 100644 index e67ef68..0000000 --- a/urlencodeform.py +++ /dev/null @@ -1,21 +0,0 @@ -from urllib import parse - -class UrlEncodeForm(): - def __init__(self): - self.form_fields = [] - return - - def get_content_type(self): - return 'application/x-www-form-urlencoded' - - def add_field(self, name, value): - """Add a simple field to the form data.""" - self.form_fields.append((name, value)) - return - def convert_to_dict(self): - """Convert form fields list to a dictionary.""" - self.form_dict = dict(self.form_fields) - return - - def make_result(self): - self.form_data = parse.urlencode(self.form_fields).encode()