summaryrefslogtreecommitdiffstats
path: root/common/layer_stack.c
blob: 0076bf77950c0ef81b3aca6c4b7859f4a3c07323 (plain)
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
#include <stdint.h>
#include "keyboard.h"
#include "layer_stack.h"
#include "debug.h"


static uint8_t top_layer = 0;

/* [0] always works as sentinel and not used for store.*/
static layer_item_t layer_stack[LAYER_STACK_SIZE] = {};


void layer_stack_clear(void)
{
    for (uint8_t i = 0; i < LAYER_STACK_SIZE; i++) {
        layer_stack[i] = (layer_item_t){ .layer = 0,
                                         .next = 0,
                                         .used = false };
    }
}

bool layer_stack_push(uint8_t layer)
{
    for (uint8_t i = 1; i < LAYER_STACK_SIZE; i++) {
        if (!layer_stack[i].used) {
            layer_stack[i] = (layer_item_t){ .layer = layer,
                                             .next = top_layer,
                                             .used = true };
            top_layer = i;
            return true;
        }
    }
    return false;
}

bool layer_stack_pop(void)
{
    if (layer_stack[top_layer].used) {
        uint8_t popped = top_layer;
        top_layer = layer_stack[popped].next;
        layer_stack[popped] = (layer_item_t){};
        return true;
    }
    return false;
}

bool layer_stack_remove(uint8_t layer)
{
    if (layer_stack[top_layer].used && layer_stack[top_layer].layer == layer) {
        layer_stack_pop();
        debug("layer_stack_remove: top_layer\n");
        return true;
    }

    for (uint8_t i = top_layer; layer_stack[i].used; i = layer_stack[i].next) {
        debug("layer_stack_remove: ["); debug_dec(i); debug("]");
        debug_dec(layer_stack[i].layer); debug("\n");
        uint8_t removed = layer_stack[i].next;
        if (layer_stack[removed].used && layer_stack[removed].layer == layer) {
            layer_stack[i].next = layer_stack[removed].next;
            layer_stack[removed] = (layer_item_t){};
            debug("layer_stack_remove: removed.\n");
            return true;
        }
    }
    return false;
}

bool layer_stack_remove_then_push(uint8_t layer)
{
    layer_stack_remove(layer);
    return layer_stack_push(layer);
}

bool layer_stack_remove_or_push(uint8_t layer)
{
    return (layer_stack_remove(layer)) || layer_stack_push(layer);
}

void layer_stack_debug(void)
{
    debug("layer_stack: ");
    layer_item_t item = layer_stack[top_layer];
    while (item.used) {
        debug_dec(item.layer);
        debug("["); debug_dec(item.next); debug("] ");
        item = layer_stack[item.next];
    }
    debug("\n");
}

action_t layer_stack_get_action(key_t key)
{
    action_t action;
    action.code = ACTION_TRANSPARENT;

    /* layer stack */
    for (layer_item_t i = layer_stack[top_layer]; i.used; i = layer_stack[i.next]) {
        action = action_for_key(i.layer, key);
        if (action.code != ACTION_TRANSPARENT) {
            layer_stack_debug();
            debug("layer_stack: used. "); debug_dec(i.layer); debug("\n");
            return action;
        }
        debug("layer_stack: through. "); debug_dec(i.layer); debug("\n");
    }
    return action;
}