Keyboard: move common code to mixin (atreus21, keypad)

This commit is contained in:
Guillaume Collic 2021-02-14 13:33:57 +01:00 committed by Florian Festi
parent ec8abee265
commit 0d4d4f308b
3 changed files with 147 additions and 112 deletions

View File

@ -4,13 +4,14 @@ from copy import deepcopy
from boxes import Boxes, Color, holeCol, restore, boolarg
from boxes.edges import FingerJointSettings
from .keyboard import Keyboard
class Atreus21(Boxes):
class Atreus21(Boxes, Keyboard):
"""Generator for a split atreus keyboard."""
ui_group = 'Misc'
btn_size = 15.6
btn_outer = btn_size + 3.4
half_btn = btn_size / 2
border = 6
row_offsets=[3, 6, 11, 5, 0, btn_size * .5]
@ -82,73 +83,36 @@ class Atreus21(Boxes):
corner = [90, b]
self.polyline(*([x, corner, y, corner] * 2))
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_keys=self.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:
hole_cb = self.key
for _ in range(n):
hole_cb()
self.moveTo(0, -n * (self.btn_outer))
self.moveTo(self.half_btn, self.half_btn)
self.apply_callback_on_columns(
hole_cb,
scheme,
self.STANDARD_KEY_SPACING,
reverse,
)
self.moveTo(-self.half_btn, -self.half_btn)
def support(self):
btn = [11.6, (-90, 2)] * 4
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)
self.outer_hole()
def hotplug(self):
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(0, self.btn_outer)
self.pcb_holes()
def key(self):
self.set_source_color(Color.BLUE)
# 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)
self.castle_shaped_plate_cutout()
# get case sizes
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([
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
-4,
])

View File

@ -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)

View File

@ -4,13 +4,16 @@ from copy import deepcopy
from boxes import Boxes, boolarg
from boxes.edges import FingerJointSettings
from .keyboard import Keyboard
class Keypad(Boxes):
class Keypad(Boxes, Keyboard):
"""Generator for keypads with mechanical switches."""
ui_group = 'Box'
btn_size = 15.6
triangle = 25.
space_between_btn = 4
box_padding = 10
triangle = 25.0
def __init__(self):
super().__init__()
@ -45,8 +48,8 @@ class Keypad(Boxes):
def _get_x_y(self):
"""Gets the keypad's size based on the number of buttons."""
x = self.btn_x * (self.btn_size) + (self.btn_x - 1) * 4 + 20
y = self.btn_y * (self.btn_size) + (self.btn_y - 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) * self.space_between_btn + 2*self.box_padding
return x, y
def render(self):
@ -69,10 +72,10 @@ class Keypad(Boxes):
self.rectangularWall(x, h, "GFEF", callback=[self.wallx_cb], move="left up")
# keypad lids
self.rectangularWall(x, y, "ffff", 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.support_hole), move="right")
self.rectangularWall(x, y, "ffff", callback=self.to_grid_callback(self.key_hole), move="up")
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
tr = self.triangle
@ -87,64 +90,27 @@ class Keypad(Boxes):
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):
"""Callback for the key stabelizers."""
# 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(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)
self.pcb_holes()
def support_hole(self):
"""Callback for the key stabelizers."""
# 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)
self.outer_hole()
def key_hole(self):
"""Callback for the key holes."""
# 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)
self.castle_shaped_plate_cutout()
# stolen form electronics-box
def wallx_cb(self):