Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interactive CLI theme selection, 7 new themes, new project structure, updated README, bugfix #22

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Virtual Environment
_venv/

# Pycache
scripts/__pycache__/
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Directory Configurations
THEME_DIR=themes

# Python Virtual Environment Configurations
VENV_NAME=_venv
PYTHON_VERSION=3
PIP=$(VENV_NAME)/bin/pip$(PYTHON_VERSION)
PYTHON=$(VENV_NAME)/bin/python$(PYTHON_VERSION)

# Runs the theme selection script, which will prompt the user for a selection & then
# execute that selection to update the theme. This will also save a backup of the
# original eeschema file in the event the user wants to revert to previous settings.
.PHONY: theme
theme:
python$(PYTHON_VERSION) scripts/theme_selection.py $(THEME_DIR)

# Creates the Python virtual environment and syncs it with resources/requirements.txt.
.PHONY: venv-update
venv-update:
python$(PYTHON_VERSION) -m venv $(VENV_NAME)
. $(VENV_NAME)/bin/activate
$(PIP) install -r resources/requirements.txt
175 changes: 138 additions & 37 deletions README.md

Large diffs are not rendered by default.

File renamed without changes.
1 change: 1 addition & 0 deletions resources/kit-dev-coldfire-xilinx_5213/fp-info-cache
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
16 changes: 16 additions & 0 deletions resources/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Add a list of pip requirements to be installed for the virtual environment
# https://pip.pypa.io/en/stable/reference/pip_install/#requirements-file-format
#
# Examples:
# ###### Requirements without Version Specifiers ######
# nose
# nose-cov
# beautifulsoup4
#
# ###### Requirements with Version Specifiers ######
# docopt == 0.6.1 # Version Matching. Must be version 0.6.1
# keyring >= 4.1.1 # Minimum version 4.1.1
# coverage != 3.5 # Version Exclusion. Anything except version 3.5
# Mopidy-Dirble ~= 1.1 # Compatible release. Same as >= 1.1, == 1.*

# No extra packages currently used
File renamed without changes.
37 changes: 10 additions & 27 deletions patch.py → scripts/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ def __init__(self, filepath):
idx = 0
for line in file:
l = line.strip()
#print(line.startswith('#'), line)
if l != '' and not (line.startswith('[') or line.startswith('#')):
try:
key, value = l.split('=', 1)
Expand Down Expand Up @@ -42,6 +41,7 @@ def write(self):
with open(self.filepath, 'w') as file:
for key, value in self.content.items():
print("{}={}".format(key, value), file=file)
file.close()

parser = argparse.ArgumentParser(description='Patch the KiCad settings file with the given colour scheme.')
parser.add_argument('scheme_path', type=Path, nargs=1,
Expand All @@ -60,28 +60,20 @@ def write(self):
exit()

if not args.config_dir[0].is_dir():
print(args.config_dir[0])
print("'{}' expected to be the kicad config directory but it is not a directory or does not exist. (Use --help for instructions.)".format(args.config_dir[0]))
exit()

if not args.scheme_path[0].is_dir():
print("'{}' expected to be the colour scheme definition directory but it is not a directory or does not exist. (Use --help for instructions.)".format(args.scheme_path[0]))

if not args.eeschema_disable:
ee_patch = args.scheme_path[0] / 'eeschema'
if not ee_patch.is_file():
ee_patch = os.path.join(args.scheme_path[0], 'eeschema')
if not Path(ee_patch).is_file():
print("Scheme does not contain a definition for EESchema, skipped.")
else:
print("Updating EESchema configuration.")
ee_config = args.config_dir[0] / 'eeschema'
try:
shutil.copy(ee_config, str(ee_config)+".bak")
except:
answer = input("Unable to create backup file. Continue anyways? [y/n] ")
while(answer not in ['y', 'n']):
answer = input("Unable to create backup file. Continue anyways? [y/n] ")
if answer == 'n':
exit()

ee_config = os.path.join(args.config_dir[0], 'eeschema')

eeschema_handler = ConfigFile(ee_config)
eeschema_handler.patch(ee_patch)
Expand All @@ -91,29 +83,20 @@ def write(self):
print("Done")
exit()

pcb_config = args.config_dir[0] / 'pcbnew'
try:
shutil.copy(pcb_config, str(pcb_config)+".bak")
except:
answer = input("Unable to create backup file. Continue anyways? [y/n] ")
while(answer not in ['y', 'n']):
answer = input("Unable to create backup file. Continue anyways? [y/n] ")
if answer == 'n':
exit()

pcb_config = os.path.join(args.config_dir[0], 'pcbnew')
pcb_handler = ConfigFile(pcb_config)

if not args.pcb_disable:
pcb_patch = args.scheme_path[0] / 'pcbnew'
if not pcb_patch.is_file():
pcb_patch = os.path.join(args.scheme_path[0], 'pcbnew')
if not Path(pcb_patch).is_file():
print("Scheme does not contain a definition for pcb_new, skipped.")
else:
print("Updating pcb_new configuration.")
pcb_handler.patch(pcb_patch)

if not args.footprint_disable:
fpe_patch = args.scheme_path[0] / 'footprint_editor'
if not fpe_patch.is_file():
fpe_patch = os.path.join(args.scheme_path[0], 'footprint_editor')
if not Path(fpe_patch).is_file():
print("Scheme does not contain a definition for the footprint editor, skipped.")
else:
print("Updating footprint editor configuration.")
Expand Down
201 changes: 201 additions & 0 deletions scripts/theme_selection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
#!/usr/bin/env python3
import os
import sys
import shutil
import argparse
import subprocess
from pathlib import Path

def error(err_msg):
"""
Prints

Arguments:
err_msg {string} -- Error message to be displayed

Returns:
None
"""
print('[Error] {}\n'.format(err_msg))
print(' Run patch.py and manually point to your desired theme and eeschema location')
print(' Command: python3 scripts/patch.py <themes/selected-theme/> <path/to/your/eeschema/folder/>')
print(' IMPORTANT NOTE: You may need to back up your eeschema and pcbnew files manually first.\n')
sys.exit(1)

def get_user_preferences_path():
"""
Retrieve the eeschema and pcbnew folder path based on the operating system.

Arguments:
None

Returns:
Path -- This is the ABSOLUTE path to preference folder.
"""
preferences_path = ''

if sys.platform == 'linux':
preferences_path = os.path.join(os.getenv('HOME'), '.config/kicad')
elif sys.platform == 'darwin':
preferences_path = os.path.join(os.getenv('HOME'), 'Library/Preferences/kicad')
elif sys.platform == 'win32':
preferences_path = os.path.join('c:\\', 'Users', os.getlogin(), 'AppData', 'Roaming', 'kicad')
else:
error('Unsupported OS detected.')

return preferences_path

def backup():
"""
First checks for the presence of the backup directory. If it is not present, this function
will create it and copy the original eeschema & pcbnew files to it based on the operating
system. The following operating systems are supported:
- Linux Distributions
- MacOS
- Windows

Arguments:
None

Returns:
None
"""
# The backups should be stored in the user preference folder
preferences_folder = get_user_preferences_path()

# If the eeschema backup isn't present, then backups have not yet been made
backup_eeschema = os.path.join(preferences_folder, 'eeschema.bak')
if not os.path.exists(backup_eeschema):
# Find the original eeschema and make sure it exists where it should
original_eeschema = os.path.join(preferences_folder, 'eeschema')
if not os.path.exists(original_eeschema):
error('Unable to find {}'.format(original_eeschema))

# Find the original pcbnew and make sure it exists where it should
original_pcbnew = os.path.join(preferences_folder, 'pcbnew')
if not os.path.exists(original_pcbnew):
error('Unable to find {}'.format(original_pcbnew))

# Copy the original eeschema into the backup directory
backup_eeschema_path = os.path.join(preferences_folder,'eeschema.bak')
print('\n[Info] Backing up {} to {}'.format(original_eeschema, backup_eeschema_path))
try:
shutil.copyfile(original_eeschema, backup_eeschema_path)
except:
error('Unable to copy {} to {}'.format(original_eeschema, preferences_folder))

# Copy the original pcbnew into the backup directory
backup_pcbnew_path = os.path.join(preferences_folder,'pcbnew.bak')
print('[Info] Backing up {} to {}'.format(original_pcbnew, backup_pcbnew_path))
try:
shutil.copyfile(original_pcbnew, backup_pcbnew_path)
except:
# Remove the eeschema backup so it doesn't signify good backup on next run
os.remove(os.path.join(preferences_folder,'eeschema.bak'))
error('Unable to copy {} to {}'.format(original_pcbnew, preferences_folder))
else:
print('\n[Info] Backup files are 1already present in {}'.format(preferences_folder))

def find_themes(theme_dir):
"""
Finds available themes from the theme directory and populate a list of available options.

Arguments:
theme_dir {Path} - Path location of theme directory relative to top-level Makefile.

Returns:
string list -- Theme names of the available theme options.
"""
# Create an empty list for themes
themes = []

with os.scandir(theme_dir) as dir:
for entry in dir:
if entry.is_dir():
themes.append(entry.name)

# Organize the themes alphabetically and then add restore backup as the first in the list
themes = sorted(themes)
themes = ['restore_backup'] + themes

return themes

def select_theme(theme_dir):
"""
Prompts user to select a theme option from the available choices.

Arguments:
theme_dir {Path} - Path location of theme directory relative to top-level Makefile.

Returns:
string -- The selected theme.
"""
# First, find available themes
themes = find_themes(theme_dir)

while True:
# Display the themes for the user to select and prompt for a selection
print('\n')
for index,theme in enumerate(themes):
if index < 9:
print('{}. {}'.format(index + 1, theme))
else:
print('{}. {}'.format(index + 1, theme))
selection = input('\nSelect a Number: ')

if selection.isnumeric():
selection = int(selection)

if selection <= len(themes):
return themes[selection-1]

def install_theme(theme_dir, theme):
"""
Installs the specified theme

Arguments:
theme_dir {Path} -- Path location of theme directory relative to top-level Makefile.
themes {string} -- Available theme options.

Returns:
None
"""
# Define the preferences folder to reduce function calls
preferences_folder = get_user_preferences_path()

# If backup restoration is selected, overwrite the existing eeschema and pcbnew
# files with the eeschema.bak and pcbnew.bak backup files.
if theme == 'restore_backup':
print("[Info] Restoring Backup")
# Copy the backup files over the existing preference files
shutil.copyfile(os.path.join(preferences_folder,'eeschema.bak'),
os.path.join(preferences_folder, 'eeschema'))
shutil.copyfile(os.path.join(preferences_folder,'pcbnew.bak'),
os.path.join(preferences_folder, 'pcbnew'))

# Otherwise, call patch.py to install the selected theme
else:
theme_config_folder = os.path.join(os.getcwd(), theme_dir, theme)
print("[Info] Installing Theme: {}".format(theme))
print('[Info] SRC: {}/eeschema'.format(theme_config_folder))
print('[Info] DEST: {}/eeschema\n'.format(preferences_folder))
# Call patch.py to install the selected theme
os.system('python3 scripts/patch.py {} {}'.format(theme_config_folder, preferences_folder))

def main():
# Add & Parse available arguments
parser = argparse.ArgumentParser(description='Display and select KiCAD theme to be installed')
parser.add_argument('theme_dir', type=Path, nargs=1, help='Theme dir for KiCAD themes')
args = parser.parse_args()

# First and foremost, backup the existing eeschema if not done already
backup()

# Find & select theme
theme = select_theme(args.theme_dir[0])

# Use patch.py to install the selected theme
install_theme(args.theme_dir[0], theme)

if __name__ == '__main__':
main()
26 changes: 26 additions & 0 deletions themes/base16_dracula/eeschema
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Color4DBgCanvasEx=rgb(40, 41, 54)
Color4DBodyBgEx=rgb(77, 79, 104)
Color4DBodyEx=rgb(234, 81, 178)
Color4DPinEx=rgb(234, 81, 178)
Color4DPinNumEx=rgb(234, 81, 178)
Color4DGLabelEx=rgb(234, 81, 178)
Color4DWireEx=rgb(0, 247, 105)
Color4DConnEx=rgb(0, 247, 105)
Color4DPinNameEx=rgb(0, 247, 105)
Color4DGridEx=rgb(235, 255, 135)
Color4DLLabelEx=rgb(235, 255, 135)
Color4DHLabelEx=rgb(235, 255, 135)
Color4DBusEx=rgb(98, 214, 232)
Color4DNoConnectEx=rgb(98, 214, 232)
Color4DNoteEx=rgb(98, 214, 232)
Color4DSheetEx=rgb(180, 91, 207)
Color4DSheetLabelEx=rgb(180, 91, 207)
Color4DFieldEx=rgb(161, 239, 228)
Color4DReferenceEx=rgb(161, 239, 228)
Color4DValueEx=rgb(161, 239, 228)
Color4DErcWEx=rgb(255, 0, 0)
Color4DErcEEx=rgb(255, 0, 0)
Color4DNetNameEx=rgb(180, 91, 207)
Color4DSheetFileNameEx=rgb(180, 91, 207)
Color4DSheetNameEx=rgb(180, 91, 207)
Color4DBrighenedEx=rgb(180, 91, 207)
Binary file added themes/base16_dracula/eeschema.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions themes/base16_nord/eeschema
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Color4DBgCanvasEx=rgb(46, 52, 64)
Color4DBodyBgEx=rgb(76, 86, 106)
Color4DBodyEx=rgb(136, 192, 208)
Color4DPinEx=rgb(136, 192, 208)
Color4DPinNumEx=rgb(136, 192, 208)
Color4DGLabelEx=rgb(136, 192, 208)
Color4DWireEx=rgb(191, 97, 106)
Color4DConnEx=rgb(191, 97, 106)
Color4DPinNameEx=rgb(191, 97, 106)
Color4DGridEx=rgb(94, 129, 172)
Color4DLLabelEx=rgb(94, 129, 172)
Color4DHLabelEx=rgb(94, 129, 172)
Color4DBusEx=rgb(235, 203, 139)
Color4DNoConnectEx=rgb(235, 203, 139)
Color4DNoteEx=rgb(235, 203, 139)
Color4DSheetEx=rgb(163, 190, 140)
Color4DSheetLabelEx=rgb(163, 190, 140)
Color4DFieldEx=rgb(208, 135, 112)
Color4DReferenceEx=rgb(208, 135, 112)
Color4DValueEx=rgb(208, 135, 112)
Color4DErcWEx=rgb(255, 0, 0)
Color4DErcEEx=rgb(255, 0, 0)
Color4DNetNameEx=rgb(163, 190, 140)
Color4DSheetFileNameEx=rgb(163, 190, 140)
Color4DSheetNameEx=rgb(163, 190, 140)
Color4DBrighenedEx=rgb(163, 190, 140)
Binary file added themes/base16_nord/eeschema.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading