Keyboard: move common code to mixin (atreus21, keypad)
This commit is contained in:
parent
ec8abee265
commit
0d4d4f308b
|
@ -4,13 +4,14 @@ from copy import deepcopy
|
||||||
|
|
||||||
from boxes import Boxes, Color, holeCol, restore, boolarg
|
from boxes import Boxes, Color, holeCol, restore, boolarg
|
||||||
from boxes.edges import FingerJointSettings
|
from boxes.edges import FingerJointSettings
|
||||||
|
from .keyboard import Keyboard
|
||||||
|
|
||||||
|
|
||||||
class Atreus21(Boxes):
|
class Atreus21(Boxes, Keyboard):
|
||||||
"""Generator for a split atreus keyboard."""
|
"""Generator for a split atreus keyboard."""
|
||||||
ui_group = 'Misc'
|
ui_group = 'Misc'
|
||||||
btn_size = 15.6
|
btn_size = 15.6
|
||||||
btn_outer = btn_size + 3.4
|
half_btn = btn_size / 2
|
||||||
border = 6
|
border = 6
|
||||||
|
|
||||||
row_offsets=[3, 6, 11, 5, 0, btn_size * .5]
|
row_offsets=[3, 6, 11, 5, 0, btn_size * .5]
|
||||||
|
@ -82,73 +83,36 @@ class Atreus21(Boxes):
|
||||||
corner = [90, b]
|
corner = [90, b]
|
||||||
self.polyline(*([x, corner, y, corner] * 2))
|
self.polyline(*([x, corner, y, corner] * 2))
|
||||||
self.moveTo(0, b)
|
self.moveTo(0, b)
|
||||||
|
|
||||||
def half(self, cb=None, reverse=False):
|
def half(self, hole_cb=None, reverse=False):
|
||||||
row_offsets=self.row_offsets
|
row_offsets=self.row_offsets
|
||||||
row_keys=self.row_keys
|
row_keys=self.row_keys
|
||||||
scheme = list(zip(row_offsets, row_keys))
|
scheme = list(zip(row_offsets, row_keys))
|
||||||
if reverse:
|
|
||||||
scheme.reverse()
|
|
||||||
for offset, keys in scheme:
|
|
||||||
self.moveTo(0, offset)
|
|
||||||
self.key_row(keys, cb)
|
|
||||||
self.moveTo(self.btn_outer)
|
|
||||||
self.moveTo(0, -offset)
|
|
||||||
|
|
||||||
total_moved_rows = len(row_offsets) * (self.btn_outer)
|
|
||||||
self.moveTo(total_moved_rows * -1, 0)
|
|
||||||
|
|
||||||
def key_row(self, n, hole_cb=None):
|
|
||||||
"""Callback for the key holes."""
|
|
||||||
if hole_cb == None:
|
if hole_cb == None:
|
||||||
hole_cb = self.key
|
hole_cb = self.key
|
||||||
for _ in range(n):
|
self.moveTo(self.half_btn, self.half_btn)
|
||||||
hole_cb()
|
self.apply_callback_on_columns(
|
||||||
self.moveTo(0, -n * (self.btn_outer))
|
hole_cb,
|
||||||
|
scheme,
|
||||||
|
self.STANDARD_KEY_SPACING,
|
||||||
|
reverse,
|
||||||
|
)
|
||||||
|
self.moveTo(-self.half_btn, -self.half_btn)
|
||||||
|
|
||||||
def support(self):
|
def support(self):
|
||||||
btn = [11.6, (-90, 2)] * 4
|
self.outer_hole()
|
||||||
self.set_source_color(Color.BLUE)
|
|
||||||
self.moveTo(0, 2, 90)
|
|
||||||
self.polyline(*btn)
|
|
||||||
self.moveTo(-2, 0, 270)
|
|
||||||
self.moveTo(0, self.btn_outer)
|
|
||||||
self.set_source_color(Color.BLACK)
|
|
||||||
|
|
||||||
def hotplug(self):
|
def hotplug(self):
|
||||||
self.moveTo(7.8 , 7.8)
|
self.pcb_holes()
|
||||||
self.hole(0, 0, d=4)
|
|
||||||
self.hole(1.27 * -3, 1.27 * 2, d=2.9)
|
|
||||||
self.hole(1.27 * 2, 1.27 * 4, d=2.9)
|
|
||||||
|
|
||||||
# pcb mounts
|
|
||||||
self.hole(1.27 * -4, 0, d=1.7)
|
|
||||||
self.hole(1.27 * 4, 0, d=1.7)
|
|
||||||
|
|
||||||
self.moveTo(-7.8, -7.8)
|
|
||||||
self.moveTo(0, self.btn_outer)
|
|
||||||
|
|
||||||
def key(self):
|
def key(self):
|
||||||
self.set_source_color(Color.BLUE)
|
self.castle_shaped_plate_cutout()
|
||||||
|
|
||||||
# draw clock wise to work with burn correction
|
|
||||||
btn_half_side = [0.98, 90, 0.81, -90, 3.5, -90, 0.81, 90, 2.505]
|
|
||||||
btn_full_side = [*btn_half_side, 0, *btn_half_side[::-1]]
|
|
||||||
btn = [*btn_full_side, -90] * 4
|
|
||||||
|
|
||||||
self.moveTo(0.81, 0.81, 90)
|
|
||||||
self.polyline(*btn)
|
|
||||||
self.moveTo(0, 0, 270)
|
|
||||||
self.moveTo(-0.81, -0.81)
|
|
||||||
self.moveTo(0, self.btn_outer)
|
|
||||||
|
|
||||||
self.set_source_color(Color.BLACK)
|
|
||||||
|
|
||||||
# get case sizes
|
# get case sizes
|
||||||
def _case_x_y(self):
|
def _case_x_y(self):
|
||||||
x = len(self.row_offsets) * self.btn_outer - 4
|
x = len(self.row_offsets) * self.STANDARD_KEY_SPACING - 4
|
||||||
y = sum([
|
y = sum([
|
||||||
max(self.row_keys) * self.btn_outer, # total button sizes
|
max(self.row_keys) * self.STANDARD_KEY_SPACING, # total button sizes
|
||||||
max(self.row_offsets), # offset of highest row
|
max(self.row_offsets), # offset of highest row
|
||||||
-4,
|
-4,
|
||||||
])
|
])
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2021 Guillaume Collic
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
class Keyboard:
|
||||||
|
"""
|
||||||
|
Code to manage Cherry MX compatible switches and Kailh hotswap socket.
|
||||||
|
"""
|
||||||
|
|
||||||
|
STANDARD_KEY_SPACING = 19
|
||||||
|
SWITCH_CASE_SIZE = 15.6
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def pcb_holes(self):
|
||||||
|
grid_unit = 1.27
|
||||||
|
main_hole_size = 4
|
||||||
|
pcb_mount_size = 1.7
|
||||||
|
led_hole_size = 1
|
||||||
|
pin_hole_size = 2.9
|
||||||
|
|
||||||
|
def grid_hole(x, y, d):
|
||||||
|
self.hole(grid_unit * x, grid_unit * y, d=d)
|
||||||
|
|
||||||
|
# main hole
|
||||||
|
grid_hole(0, 0, main_hole_size)
|
||||||
|
|
||||||
|
# switch pins
|
||||||
|
grid_hole(-3, 2, pin_hole_size)
|
||||||
|
grid_hole(2, 4, pin_hole_size)
|
||||||
|
|
||||||
|
grid_hole(-4, 0, pcb_mount_size)
|
||||||
|
grid_hole(4, 0, pcb_mount_size)
|
||||||
|
|
||||||
|
def apply_callback_on_columns(self, cb, columns_definition, spacing, reverse=False):
|
||||||
|
if reverse:
|
||||||
|
columns_definition = list(reversed(columns_definition))
|
||||||
|
|
||||||
|
for offset, nb_keys in columns_definition:
|
||||||
|
self.moveTo(0, offset)
|
||||||
|
for _ in range(nb_keys):
|
||||||
|
cb()
|
||||||
|
self.moveTo(0, spacing)
|
||||||
|
self.moveTo(spacing, -nb_keys * spacing)
|
||||||
|
self.moveTo(0, -offset)
|
||||||
|
|
||||||
|
total_width = len(columns_definition) * spacing
|
||||||
|
self.moveTo(-1 * total_width)
|
||||||
|
|
||||||
|
def outer_hole(self, radius=2, centered=True):
|
||||||
|
"""
|
||||||
|
Draws a rounded square big enough to go around a whole switch (15.6mm)
|
||||||
|
"""
|
||||||
|
half_size = Keyboard.SWITCH_CASE_SIZE / 2
|
||||||
|
if centered:
|
||||||
|
self.moveTo(-half_size, -half_size)
|
||||||
|
|
||||||
|
# draw clock wise to work with burn correction
|
||||||
|
straight_edge = Keyboard.SWITCH_CASE_SIZE - 2 * radius
|
||||||
|
polyline = [straight_edge, (-90, radius)] * 4
|
||||||
|
self.moveTo(0, radius, 90)
|
||||||
|
self.polyline(*polyline)
|
||||||
|
self.moveTo(0, 0, 270)
|
||||||
|
self.moveTo(0, -radius)
|
||||||
|
self.moveTo(0)
|
||||||
|
|
||||||
|
if centered:
|
||||||
|
self.moveTo(half_size, half_size)
|
||||||
|
|
||||||
|
def castle_shaped_plate_cutout(self, centered=True):
|
||||||
|
"""
|
||||||
|
This cutout shaped like a castle enables switch modding and rotation.
|
||||||
|
More information (type 4) on https://geekhack.org/index.php?topic=59837.0
|
||||||
|
"""
|
||||||
|
half_size = Keyboard.SWITCH_CASE_SIZE / 2
|
||||||
|
if centered:
|
||||||
|
self.moveTo(-half_size, -half_size)
|
||||||
|
|
||||||
|
# draw clock wise to work with burn correction
|
||||||
|
btn_half_side = [0.98, 90, 0.81, -90, 3.5, -90, 0.81, 90, 2.505]
|
||||||
|
btn_full_side = [*btn_half_side, 0, *btn_half_side[::-1]]
|
||||||
|
btn = [*btn_full_side, -90] * 4
|
||||||
|
|
||||||
|
self.moveTo(0.81, 0.81, 90)
|
||||||
|
self.polyline(*btn)
|
||||||
|
self.moveTo(0, 0, 270)
|
||||||
|
self.moveTo(-0.81, -0.81)
|
||||||
|
|
||||||
|
if centered:
|
||||||
|
self.moveTo(half_size, half_size)
|
|
@ -4,13 +4,16 @@ from copy import deepcopy
|
||||||
|
|
||||||
from boxes import Boxes, boolarg
|
from boxes import Boxes, boolarg
|
||||||
from boxes.edges import FingerJointSettings
|
from boxes.edges import FingerJointSettings
|
||||||
|
from .keyboard import Keyboard
|
||||||
|
|
||||||
|
|
||||||
class Keypad(Boxes):
|
class Keypad(Boxes, Keyboard):
|
||||||
"""Generator for keypads with mechanical switches."""
|
"""Generator for keypads with mechanical switches."""
|
||||||
ui_group = 'Box'
|
ui_group = 'Box'
|
||||||
btn_size = 15.6
|
btn_size = 15.6
|
||||||
triangle = 25.
|
space_between_btn = 4
|
||||||
|
box_padding = 10
|
||||||
|
triangle = 25.0
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -45,8 +48,8 @@ class Keypad(Boxes):
|
||||||
|
|
||||||
def _get_x_y(self):
|
def _get_x_y(self):
|
||||||
"""Gets the keypad's size based on the number of buttons."""
|
"""Gets the keypad's size based on the number of buttons."""
|
||||||
x = self.btn_x * (self.btn_size) + (self.btn_x - 1) * 4 + 20
|
x = self.btn_x * (self.btn_size) + (self.btn_x - 1) * self.space_between_btn + 2*self.box_padding
|
||||||
y = self.btn_y * (self.btn_size) + (self.btn_y - 1) * 4 + 20
|
y = self.btn_y * (self.btn_size) + (self.btn_y - 1) * self.space_between_btn + 2*self.box_padding
|
||||||
return x, y
|
return x, y
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
|
@ -69,10 +72,10 @@ class Keypad(Boxes):
|
||||||
self.rectangularWall(x, h, "GFEF", callback=[self.wallx_cb], move="left up")
|
self.rectangularWall(x, h, "GFEF", callback=[self.wallx_cb], move="left up")
|
||||||
|
|
||||||
# keypad lids
|
# keypad lids
|
||||||
self.rectangularWall(x, y, "ffff", callback=[self.support_hole], move="right")
|
self.rectangularWall(x, y, "ffff", callback=self.to_grid_callback(self.support_hole), move="right")
|
||||||
self.rectangularWall(x, y, "ffff", callback=[self.key_hole], move="up")
|
self.rectangularWall(x, y, "ffff", callback=self.to_grid_callback(self.key_hole), move="up")
|
||||||
if self.top2_enable:
|
if self.top2_enable:
|
||||||
self.rectangularWall(x, y, "ffff", callback=[self.hotplug])
|
self.rectangularWall(x, y, "ffff", callback=self.to_grid_callback(self.hotplug))
|
||||||
|
|
||||||
# screwable
|
# screwable
|
||||||
tr = self.triangle
|
tr = self.triangle
|
||||||
|
@ -87,64 +90,27 @@ class Keypad(Boxes):
|
||||||
callback=[None, lambda: self.hole(trh, trh, d=d1)]
|
callback=[None, lambda: self.hole(trh, trh, d=d1)]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def to_grid_callback(self, inner_callback):
|
||||||
|
scheme = [(0, self.btn_y)]*self.btn_x
|
||||||
|
def callback():
|
||||||
|
# move to first key center
|
||||||
|
key_margin = self.box_padding + self.btn_size / 2
|
||||||
|
self.moveTo(key_margin, key_margin)
|
||||||
|
self.apply_callback_on_columns(
|
||||||
|
inner_callback, scheme, self.btn_size + self.space_between_btn
|
||||||
|
)
|
||||||
|
|
||||||
|
return [callback]
|
||||||
|
|
||||||
def hotplug(self):
|
def hotplug(self):
|
||||||
"""Callback for the key stabelizers."""
|
"""Callback for the key stabelizers."""
|
||||||
# draw clock wise to work with burn correction
|
self.pcb_holes()
|
||||||
btn = [11.6, (-90, 2)] * 4
|
|
||||||
s = self.btn_size
|
|
||||||
self.moveTo(10, 10)
|
|
||||||
for _ in range(self.btn_y):
|
|
||||||
for _ in range(self.btn_x):
|
|
||||||
self.moveTo(7.8 , 7.8)
|
|
||||||
|
|
||||||
self.hole(0, 0, d=4)
|
|
||||||
self.hole(1.27 * -3, 1.27 * 2, d=2.9)
|
|
||||||
self.hole(1.27 * 2, 1.27 * 4, d=2.9)
|
|
||||||
|
|
||||||
# pcb mounts
|
|
||||||
self.hole(1.27 * -4, 0, d=1.7)
|
|
||||||
self.hole(1.27 * 4, 0, d=1.7)
|
|
||||||
|
|
||||||
self.moveTo(-7.8, -7.8)
|
|
||||||
self.moveTo(s + 4)
|
|
||||||
|
|
||||||
#self.moveTo(1.27 * -2, 1.17 * 3)
|
|
||||||
#self.moveTo(1.27 * 2, 1.17 * -3)
|
|
||||||
self.moveTo(self.btn_x * (s + 4) * -1, s + 4)
|
|
||||||
|
|
||||||
def support_hole(self):
|
def support_hole(self):
|
||||||
"""Callback for the key stabelizers."""
|
self.outer_hole()
|
||||||
# draw clock wise to work with burn correction
|
|
||||||
btn = [11.6, (-90, 2)] * 4
|
|
||||||
|
|
||||||
s = self.btn_size
|
|
||||||
self.moveTo(10, 10)
|
|
||||||
for _ in range(self.btn_y):
|
|
||||||
for _ in range(self.btn_x):
|
|
||||||
self.moveTo(0, 2, 90)
|
|
||||||
self.polyline(*btn)
|
|
||||||
self.moveTo(0, 0, 270)
|
|
||||||
self.moveTo(s + 4, -2)
|
|
||||||
self.moveTo(self.btn_x * (s + 4) * -1, s + 4)
|
|
||||||
|
|
||||||
def key_hole(self):
|
def key_hole(self):
|
||||||
"""Callback for the key holes."""
|
self.castle_shaped_plate_cutout()
|
||||||
# draw clock wise to work with burn correction
|
|
||||||
btn_half_side = [0.98, 90, 0.81, -90, 3.5, -90, 0.81, 90, 2.505]
|
|
||||||
btn_full_side = [*btn_half_side, 0, *btn_half_side[::-1]]
|
|
||||||
btn = [*btn_full_side, -90] * 4
|
|
||||||
|
|
||||||
s = self.btn_size
|
|
||||||
self.moveTo(10, 10)
|
|
||||||
for _ in range(self.btn_y):
|
|
||||||
for _ in range(self.btn_x):
|
|
||||||
self.moveTo(0.81, 0.81, 90)
|
|
||||||
self.polyline(*btn)
|
|
||||||
self.moveTo(0, 0, 270)
|
|
||||||
self.moveTo(-0.81, -0.81)
|
|
||||||
self.moveTo(s + 4)
|
|
||||||
self.moveTo(self.btn_x * (s + 4) * -1, s + 4)
|
|
||||||
|
|
||||||
# stolen form electronics-box
|
# stolen form electronics-box
|
||||||
def wallx_cb(self):
|
def wallx_cb(self):
|
||||||
|
|
Loading…
Reference in New Issue