All files / src/types/kmx/kmx-plus-builder build-layr.ts

43.12% Statements 69/160
100% Branches 0/0
0% Functions 0/1
43.12% Lines 69/160

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 1611x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                                                                                                                                                                                        
 
import { constants } from "@keymanapp/ldml-keyboard-constants";
import { KMXPlus } from "@keymanapp/common-types";
import { build_strs_index, BUILDER_STR_REF, BUILDER_STRS } from "./build-strs.js";
import { BUILDER_LIST } from "./build-list.js";
import { BUILDER_SECTION } from "./builder-section.js";
 
import KMXPlusData = KMXPlus.KMXPlusData;
import LayrEntry = KMXPlus.LayrEntry;
import LayrRow = KMXPlus.LayrRow;
import StrsItem = KMXPlus.StrsItem;
 
/* ------------------------------------------------------------------
 * layr section -
 ------------------------------------------------------------------ */
 
/**
 * List of layers, the <layers> element
 */
interface BUILDER_LAYR_LIST {
  hardware: BUILDER_STR_REF; // hardware or 'touch'
  layer: number; // index of first layer in the list, in the
  count: number; // number of layer entries in the list
  minDeviceWidth: number; // width in millimeters
  _layers: LayrEntry[]; // original layer entry, for in-memory only
};
 
/**
 * <layer> element
 */
interface BUILDER_LAYR_LAYER {
  id: BUILDER_STR_REF; // str of layer id
  _id: string; // original layer id, for sorting
  mod: number; // bitfield with modifier info
  row: number; // row index into row subtable
  _rows: LayrRow[]; // original rows, for in-memory only
  count: number; // number of row entries
};
 
/**
 * <row> element
 */
interface BUILDER_LAYR_ROW {
  key: number; // index into key subtable
  count: number; // number of keys
};
 
/**
 * portion of keys attribute of <row>
 */
interface BUILDER_LAYR_KEY {
  key: number;
};
 
/**
 * Builder for the 'keys' section
 */
export interface BUILDER_LAYR extends BUILDER_SECTION {
  listCount: number, // number of entries in lists subtable
  layerCount: number, // number of entries in layers subtable
  rowCount: number, // number of entries in rows subtable
  keyCount: number, // number of entries in keys subtable
  lists: BUILDER_LAYR_LIST[], // subtable of <layers> elements
  layers: BUILDER_LAYR_LAYER[], // subtable of <layer> elements
  rows: BUILDER_LAYR_ROW[], // subtable of <row> elements
  keys: BUILDER_LAYR_KEY[], // subtable of key entries
};
 
export function build_layr(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_list: BUILDER_LIST): BUILDER_LAYR {
  if (!kmxplus.layr?.lists) {
    return null;  // if there aren't any layers at all (which should be an invalid keyboard)
  }

  const layr: BUILDER_LAYR = {
    ident: constants.hex_section_id(constants.section.layr),
    size: constants.length_layr,
    _offset: 0,
    listCount: kmxplus.layr.lists.length,
    layerCount: 0, // calculated below
    rowCount: 0, // calculated below
    keyCount: 0, // calculated below
    lists: [],
    layers: [],
    rows: [],
    keys: []
  };

  layr.lists = kmxplus.layr.lists.map((list) => {
    const blist: BUILDER_LAYR_LIST = {
      hardware: build_strs_index(sect_strs, list.hardware),
      layer: null, // to be set below
      _layers: list.layers,
      count: list.layers.length,
      minDeviceWidth: list.minDeviceWidth,
    };
    return blist;
  });
  // now sort the lists
  layr.lists.sort((a, b) => {
    // sort by string #
    if (a.hardware < b.hardware) {
      return -1;
    } else if (a.hardware > b.hardware) {
      return 1;
    }
    if (a.minDeviceWidth < b.minDeviceWidth) {
      return -1;
    } else if (a.minDeviceWidth > b.minDeviceWidth) {
      return 1;
    } else {
      return 0; // same
    }
  });
  // Now allocate the layers, rows, and keys
  layr.lists.forEach((list) => {
    list.layer = layr.layers.length; // index to first layer in list
    const blayers = list._layers.map((layer) => {
      const blayer: BUILDER_LAYR_LAYER = {
        _id: layer.id.value, // original id
        id: build_strs_index(sect_strs, layer.id),
        mod: layer.mod,
        row: null, // row ID, to be filled in
        _rows: layer.rows, // temporary
        count: layer.rows.length, // number of rows
      };
      return blayer;
    });
    // sort the new layers
    blayers.sort((a, b) => StrsItem.binaryStringCompare(a._id, b._id));
    blayers.forEach((layer) => {
      layer.row = layr.rows.length; // index to first row in list
      layer._rows.forEach((row) => {
        const brow: BUILDER_LAYR_ROW = {
          key: layr.keys.length,
          count: row.keys.length,
        };
        row.keys.forEach((key) => {
          const bkey: BUILDER_LAYR_KEY = {
            key: build_strs_index(sect_strs, key),
          };
          layr.keys.push(bkey);
        });
        layr.rows.push(brow);
      });
      layr.layers.push(layer);
    });
  });

  layr.layerCount = layr.layers.length;
  layr.rowCount = layr.rows.length;
  layr.keyCount = layr.keys.length;

  const offset = constants.length_layr +
    (constants.length_layr_list * layr.listCount) +
    (constants.length_layr_entry * layr.layerCount) +
    (constants.length_layr_row * layr.rowCount) +
    (constants.length_layr_key * layr.keyCount);
  layr.size = offset;
  return layr;
}