Compare commits

...
Sign in to create a new pull request.

9 commits

Author SHA1 Message Date
Morgan 'ARR\!' Allen
934aaaf354 more prefs 2025-06-10 22:12:07 -07:00
Morgan 'ARR\!' Allen
7ee3ed89c6 toolbar button to open preferences 2025-06-10 18:01:25 -07:00
Morgan 'ARR\!' Allen
b19c95cd2e added preferences
fixes #8
2025-06-10 17:53:30 -07:00
Morgan 'ARR\!' Allen
205254a4f3 make parts use sync_from 2025-05-19 21:23:11 -07:00
Morgan 'ARR\!' Allen
6137b50208 improving sync_from 2025-05-19 21:22:43 -07:00
Morgan 'ARR\!' Allen
0a95b5529e more migration to BoardSketch 2025-05-19 21:22:18 -07:00
Morgan 'ARR\!' Allen
a162b98000 Type doesnt want to be writable anymore 2025-05-19 21:21:50 -07:00
Morgan 'ARR\!' Allen
c61020242d make KiConnect::BoardSketch syncable 2025-05-19 21:20:25 -07:00
Morgan 'ARR\!' Allen
638fda2daf ensure doc is recompute after updates 2025-05-19 21:18:39 -07:00
10 changed files with 238 additions and 18 deletions

View file

@ -54,7 +54,7 @@ class BaseObject:
self.feature.addExtension(ext)
def setup_properties(self, feature):
feature.addProperty('App::PropertyString', 'Type', 'KiConnect', 'Internal KiConnect Type', read_only=True, hidden=True)
feature.addProperty('App::PropertyString', 'Type', 'KiConnect', 'Internal KiConnect Type', hidden=True)
def sync_from(self):
pass

View file

@ -19,6 +19,7 @@ class BoardObject(BaseObject):
def __init__(self, feature, kicad_board, board_polygon):
self.feature = feature
self.kicad_board = kicad_board
self.board_sketch = None
# TODO add this to FreeCAD Preferences and Property?
self.do_offset = True
# TODO needs to be resotred in onDocumentRestored
@ -72,6 +73,9 @@ class BoardObject(BaseObject):
return self.board_sketch
def get_polygon(self, kiid):
return [ s for s in self.kicad_board.get_shapes() if s.id.value == kiid ][0]
def get_boardpoly(self):
# TODO remove in favor of extract_polygons class method
board = self.kicad_board
@ -128,17 +132,8 @@ class BoardObject(BaseObject):
Pulls outline from KiCAD PolygonBoard and saves points as Vectors
'''
# bit of a quick hack to keep the board in one place, needs more testing
if self.do_offset and not self.feature.BoardOffset:
bb = self.board_polygon.bounding_box()
self.feature.BoardOffset.Base = (App.Vector(bb.pos.x, -bb.pos.y) + App.Vector(bb.size.x, -bb.size.y) / 2) / 1000000.0
vectors = []
for node in self.board_polygon.polygons[0].outline:
vectors.append(self.point_to_vector(node.point))
self.feature.Vectors = vectors
if self.board_sketch:
self.board_sketch.Proxy.sync_from()
def sync_to(self):
board = self.kicad_board

View file

@ -23,6 +23,12 @@ class BoardSketchObject(BaseObject):
def execute(self, feature):
feature.recompute()
def get_parent_board(self):
try:
return self.feature.getParent().getParent().Proxy
except:
return None
def point_to_vector(self, point, offset=True):
return (
App.Vector(point.x,
@ -39,6 +45,11 @@ class BoardSketchObject(BaseObject):
feature = self.feature
vectors = []
board = self.get_parent_board()
if board:
self.board_polygon = board.get_polygon(board.polygon_id)
# board.get_shapes needs to be called to ensure polygons are actually up to date
for node in self.board_polygon.polygons[0].outline:
vectors.append(self.point_to_vector(node.point))

View file

@ -1,7 +1,8 @@
import FreeCAD as App
import FreeCADGui as Gui
class Syncable:
SYNCABLES = [ 'KiConnect::Project', 'KiConnect::Board', 'KiConnect::Parts', 'KiConnect::BoardBody', ]
SYNCABLES = [ 'KiConnect::Project', 'KiConnect::Board', 'KiConnect::Parts', 'KiConnect::BoardBody', 'KiConnect::BoardSketch' ]
def IsActive(self):
sel = Gui.Selection.getSelection()
@ -41,3 +42,5 @@ class Syncable:
getattr(feature, self.method)()
s.recompute()
App.ActiveDocument.recompute()

View file

@ -0,0 +1,24 @@
import importlib
import FreeCADGui as Gui
import os
import sys
from .. import settings
from ..project import Project
class EditPrefs:
def GetResources(self):
tooltip = '<p>EditPrefs KiConnect Workbench for development.\nNOTE: Does not reload toolbars.</p>'
iconFile = 'preferences-system.svg'
return {
'MenuText': 'Edit Preferences',
'ToolTip': tooltip,
'Pixmap' : iconFile
}
def Activated(self):
Gui.showPreferences("KiConnect")
Gui.addCommand('cmd_edit_prefs', EditPrefs())

View file

@ -7,7 +7,7 @@ sys.path.insert(1, os.path.join(os.path.dirname(os.path.realpath(__file__)), '..
import FreeCADGui as Gui
import FreeCAD as App
from .commands import cmd_new_pcb, cmd_reload, cmd_sync_from, cmd_sync_to
from .commands import cmd_edit_prefs, cmd_new_pcb, cmd_reload, cmd_sync_from, cmd_sync_to
from . import settings
translate=App.Qt.translate
@ -19,12 +19,18 @@ TRANSLATIONSPATH = os.path.join(os.path.dirname(__file__), "resources", "transla
Gui.addLanguagePath(TRANSLATIONSPATH)
Gui.updateLocale()
default_preferences = [
('Bool', 'debug_reload', True),
('Bool', 'prefs_toolbar', True),
('Float', 'default_thickness', 1.6),
]
class KiConnect(Gui.Workbench):
MenuText = translate("Workbench", "KiConnect")
ToolTip = translate("Workbench", "KiConnect PCB Workbench")
Icon = os.path.join(settings.ICONPATH, "kiconnect.svg")
toolbox = [ 'kiconn_new', 'kiconn_reload', 'kiconn_sync_to', 'kiconn_sync_from' ]
toolbox = [ 'kiconn_new', 'kiconn_sync_to', 'kiconn_sync_from' ]
def GetClassName(self):
return "Gui::PythonWorkbench"
@ -35,11 +41,27 @@ class KiConnect(Gui.Workbench):
here is the place to import all the commands
"""
# setup default preferences on first load
if settings.preferences.IsEmpty():
for pref in default_preferences:
print('setting pref: ', f'Set{pref[0]}', pref[1], pref[2])
getattr(settings.preferences, f'Set{pref[0]}')(pref[1], pref[2])
# add debug reload button if enabled
if settings.preferences.GetBool('debug_reload'):
self.toolbox.append('kiconn_reload')
if settings.preferences.GetBool('prefs_toolbar'):
self.toolbox.append('cmd_edit_prefs')
print('setting up toolbar')
# NOTE: Context for this commands must be "Workbench"
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "KiConnect"), self.toolbox)
self.appendMenu(QT_TRANSLATE_NOOP("Workbench", "KiConnect"), self.toolbox)
Gui.addPreferencePage(os.path.join(settings.UIPATH, 'preferences.ui'), 'KiConnect')
def Activated(self):
App.Console.PrintMessage(translate("Log", "Workbench KiConnect activated.") + "\n")

View file

@ -15,12 +15,13 @@ from .bases import BaseObject, BaseViewProvider
class PartsObject(BaseObject):
TYPE = 'KiConnect::Parts'
def __init__(self, feature):
super(PartsObject, self).__init__(feature)
def execute(self, feature):
super(PartsObject, self).execute(feature)
self.import_footprints()
def import_footprints(self):
def sync_from(self):
kiconn_board = self.feature.getParentGroup()
kicad_board = self.get_api().kicad.get_board()

View file

@ -32,6 +32,7 @@ class Project:
kicad_board = self.API.Proxy.kicad.get_board()
polygons = Board.extract_polygons(kicad_board)
for polygon in polygons:
self.board = Board.makeBoard(self.feature, kicad_board, polygon)

View file

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KiConnect::DlgSettingsKiConnect</class>
<widget class="QWidget" name="KiConnect::DlgSettingsKiConnect">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1151</width>
<height>663</height>
</rect>
</property>
<property name="maximumSize">
<size>
<width>1151</width>
<height>16777215</height>
</size>
</property>
<property name="windowTitle">
<string>General</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="defaults_group">
<property name="title">
<string>Defaults</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Default Board Thickness</string>
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefUnitSpinBox" name="spin_thickness">
<property name="unit" stdset="0">
<string>mm</string>
</property>
<property name="value">
<double>1.600000000000000</double>
</property>
<property name="prefEntry" stdset="0">
<cstring>default_thickness</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/KiConnect</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Gui::PrefCheckBox" name="check_load_parts">
<property name="text">
<string>Load Parts</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>parts_load</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/KiConnect</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="debug_group">
<property name="title">
<string>Debug and Development</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignHCenter|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="Gui::PrefCheckBox" name="check_debug_reload">
<property name="font">
<font>
<pointsize>10</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Enable Reload</string>
</property>
<property name="tristate">
<bool>false</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>debug_reload</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/KiConnect</cstring>
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefCheckBox" name="checkBox">
<property name="text">
<string> Preferences from toolbar</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>Mod/KiConnect</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>prefs_toolbar</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::QuantitySpinBox</class>
<extends>QAbstractSpinBox</extends>
<header>Gui/QuantitySpinBox.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefCheckBox</class>
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefUnitSpinBox</class>
<extends>Gui::QuantitySpinBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -1,5 +1,10 @@
import os
import FreeCAD as App
BOARD_THICKNESS = 0.80
ICONPATH = os.path.join(os.path.dirname(__file__), "resources", 'icons')
UIPATH = os.path.join(os.path.dirname(__file__), "resources", 'ui')
KICAD9_3DMODEL_DIR = '/usr/share/kicad/3dmodels/'
PREF_PATH = 'User parameter:BaseApp/Preferences/Mod/KiConnect'
preferences = App.ParamGet(PREF_PATH)