diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-10-30 09:08:09 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-10-30 09:08:09 +0200 |
commit | b1e9b313f6810afbadde0f8079326ecf04c89817 (patch) | |
tree | 93299da98c3f3fdffadb1e09a51ccd56df71b8f1 /src/ui | |
parent | 653c055d145d940a318025ca74762f6b8024bf5a (diff) |
Added a key binding mechanism
The document scrolling keys are now handled via bindings.
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/documentwidget.c | 75 | ||||
-rw-r--r-- | src/ui/keys.c | 154 | ||||
-rw-r--r-- | src/ui/keys.h | 17 |
3 files changed, 205 insertions, 41 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 5c6780d1..a2bea17b 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -1536,7 +1536,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1536 | updateVisible_DocumentWidget_(d); | 1536 | updateVisible_DocumentWidget_(d); |
1537 | return iTrue; | 1537 | return iTrue; |
1538 | } | 1538 | } |
1539 | else if (equalWidget_Command(cmd, w, "scroll.page")) { | 1539 | else if (equal_Command(cmd, "scroll.page") && document_App() == d) { |
1540 | if (argLabel_Command(cmd, "repeat")) { | 1540 | if (argLabel_Command(cmd, "repeat")) { |
1541 | /* TODO: Adjust scroll animation to be linear during repeated scroll? */ | 1541 | /* TODO: Adjust scroll animation to be linear during repeated scroll? */ |
1542 | } | 1542 | } |
@@ -1547,6 +1547,40 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1547 | smoothDuration_DocumentWidget_); | 1547 | smoothDuration_DocumentWidget_); |
1548 | return iTrue; | 1548 | return iTrue; |
1549 | } | 1549 | } |
1550 | else if (equal_Command(cmd, "scroll.top") && document_App() == d) { | ||
1551 | init_Anim(&d->scrollY, 0); | ||
1552 | invalidate_VisBuf(d->visBuf); | ||
1553 | scroll_DocumentWidget_(d, 0); | ||
1554 | updateVisible_DocumentWidget_(d); | ||
1555 | refresh_Widget(w); | ||
1556 | return iTrue; | ||
1557 | } | ||
1558 | else if (equal_Command(cmd, "scroll.bottom") && document_App() == d) { | ||
1559 | init_Anim(&d->scrollY, scrollMax_DocumentWidget_(d)); | ||
1560 | invalidate_VisBuf(d->visBuf); | ||
1561 | scroll_DocumentWidget_(d, 0); | ||
1562 | updateVisible_DocumentWidget_(d); | ||
1563 | refresh_Widget(w); | ||
1564 | return iTrue; | ||
1565 | } | ||
1566 | else if (equal_Command(cmd, "scroll.step") && document_App() == d) { | ||
1567 | smoothScroll_DocumentWidget_(d, | ||
1568 | 3 * lineHeight_Text(paragraph_FontId) * arg_Command(cmd), | ||
1569 | smoothDuration_DocumentWidget_); | ||
1570 | return iTrue; | ||
1571 | } | ||
1572 | #if 0 | ||
1573 | case SDLK_PAGEUP: | ||
1574 | case SDLK_PAGEDOWN: | ||
1575 | case SDLK_SPACE: | ||
1576 | postCommand_Widget( | ||
1577 | w, | ||
1578 | "scroll.page arg:%d repeat:%d", | ||
1579 | (key == SDLK_SPACE && mods & KMOD_SHIFT) || key == SDLK_PAGEUP ? -1 : +1, | ||
1580 | ev->key.repeat != 0); | ||
1581 | return iTrue; | ||
1582 | } | ||
1583 | #endif | ||
1550 | else if (equal_Command(cmd, "document.goto") && document_App() == d) { | 1584 | else if (equal_Command(cmd, "document.goto") && document_App() == d) { |
1551 | const iRangecc heading = range_Command(cmd, "heading"); | 1585 | const iRangecc heading = range_Command(cmd, "heading"); |
1552 | if (heading.start) { | 1586 | if (heading.start) { |
@@ -1790,45 +1824,6 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
1790 | refresh_Widget(w); | 1824 | refresh_Widget(w); |
1791 | } | 1825 | } |
1792 | break; | 1826 | break; |
1793 | case SDLK_HOME: | ||
1794 | init_Anim(&d->scrollY, 0); | ||
1795 | invalidate_VisBuf(d->visBuf); | ||
1796 | scroll_DocumentWidget_(d, 0); | ||
1797 | updateVisible_DocumentWidget_(d); | ||
1798 | refresh_Widget(w); | ||
1799 | return iTrue; | ||
1800 | case SDLK_END: | ||
1801 | init_Anim(&d->scrollY, scrollMax_DocumentWidget_(d)); | ||
1802 | invalidate_VisBuf(d->visBuf); | ||
1803 | scroll_DocumentWidget_(d, 0); | ||
1804 | updateVisible_DocumentWidget_(d); | ||
1805 | refresh_Widget(w); | ||
1806 | return iTrue; | ||
1807 | case SDLK_UP: | ||
1808 | case SDLK_DOWN: | ||
1809 | if (mods == 0) { | ||
1810 | if (ev->key.repeat) { | ||
1811 | // if (!d->smoothContinue) { | ||
1812 | // d->smoothContinue = iTrue; | ||
1813 | // } | ||
1814 | // else return iTrue; | ||
1815 | } | ||
1816 | smoothScroll_DocumentWidget_(d, | ||
1817 | 3 * lineHeight_Text(paragraph_FontId) * | ||
1818 | (key == SDLK_UP ? -1 : 1), | ||
1819 | /*gap_Text * */smoothDuration_DocumentWidget_); | ||
1820 | return iTrue; | ||
1821 | } | ||
1822 | break; | ||
1823 | case SDLK_PAGEUP: | ||
1824 | case SDLK_PAGEDOWN: | ||
1825 | case SDLK_SPACE: | ||
1826 | postCommand_Widget( | ||
1827 | w, | ||
1828 | "scroll.page arg:%d repeat:%d", | ||
1829 | (key == SDLK_SPACE && mods & KMOD_SHIFT) || key == SDLK_PAGEUP ? -1 : +1, | ||
1830 | ev->key.repeat != 0); | ||
1831 | return iTrue; | ||
1832 | #if 1 | 1827 | #if 1 |
1833 | case SDLK_KP_1: | 1828 | case SDLK_KP_1: |
1834 | case '`': { | 1829 | case '`': { |
diff --git a/src/ui/keys.c b/src/ui/keys.c new file mode 100644 index 00000000..d46d20bf --- /dev/null +++ b/src/ui/keys.c | |||
@@ -0,0 +1,154 @@ | |||
1 | /* Copyright 2020 Jaakko Keränen <jaakko.keranen@iki.fi> | ||
2 | |||
3 | Redistribution and use in source and binary forms, with or without | ||
4 | modification, are permitted provided that the following conditions are met: | ||
5 | |||
6 | 1. Redistributions of source code must retain the above copyright notice, this | ||
7 | list of conditions and the following disclaimer. | ||
8 | 2. Redistributions in binary form must reproduce the above copyright notice, | ||
9 | this list of conditions and the following disclaimer in the documentation | ||
10 | and/or other materials provided with the distribution. | ||
11 | |||
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||
16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
22 | |||
23 | #include "keys.h" | ||
24 | #include "util.h" | ||
25 | #include "app.h" | ||
26 | |||
27 | #include <the_Foundation/sortedarray.h> | ||
28 | |||
29 | iDeclareType(Keys) | ||
30 | iDeclareType(Binding) | ||
31 | |||
32 | struct Impl_Binding { | ||
33 | int key; | ||
34 | int mods; | ||
35 | iString command; | ||
36 | iString label; | ||
37 | }; | ||
38 | |||
39 | static int cmp_Binding_(const void *a, const void *b) { | ||
40 | const iBinding *d = a, *other = b; | ||
41 | const int cmp = iCmp(d->key, other->key); | ||
42 | if (cmp == 0) { | ||
43 | return iCmp(d->mods, other->mods); | ||
44 | } | ||
45 | return cmp; | ||
46 | } | ||
47 | |||
48 | struct Impl_Keys { | ||
49 | iSortedArray bindings; | ||
50 | }; | ||
51 | |||
52 | static iKeys keys_; | ||
53 | |||
54 | static void clear_Keys_(iKeys *d) { | ||
55 | iForEach(Array, i, &d->bindings.values) { | ||
56 | iBinding *bind = i.value; | ||
57 | deinit_String(&bind->command); | ||
58 | deinit_String(&bind->label); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | static void bindDefaults_(void) { | ||
63 | bind_Keys("scroll.top", SDLK_HOME, 0); | ||
64 | bind_Keys("scroll.bottom", SDLK_END, 0); | ||
65 | bind_Keys("scroll.step arg:-1", SDLK_UP, 0); | ||
66 | bind_Keys("scroll.step arg:1", SDLK_DOWN, 0); | ||
67 | bind_Keys("scroll.page arg:-1", SDLK_PAGEUP, 0); | ||
68 | bind_Keys("scroll.page arg:-1", SDLK_SPACE, KMOD_SHIFT); | ||
69 | bind_Keys("scroll.page arg:1", SDLK_PAGEDOWN, 0); | ||
70 | bind_Keys("scroll.page arg:1", SDLK_SPACE, 0); | ||
71 | } | ||
72 | |||
73 | static iBinding *find_Keys_(iKeys *d, int key, int mods) { | ||
74 | const iBinding bind = { .key = key, .mods = mods }; | ||
75 | size_t pos; | ||
76 | if (locate_SortedArray(&d->bindings, &bind, &pos)) { | ||
77 | return at_SortedArray(&d->bindings, pos); | ||
78 | } | ||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | static iBinding *findCommand_Keys_(iKeys *d, const char *command) { | ||
83 | /* Note: O(n) */ | ||
84 | iForEach(Array, i, &d->bindings.values) { | ||
85 | iBinding *bind = i.value; | ||
86 | if (!cmp_String(&bind->command, command)) { | ||
87 | return bind; | ||
88 | } | ||
89 | } | ||
90 | return NULL; | ||
91 | } | ||
92 | |||
93 | /*----------------------------------------------------------------------------------------------*/ | ||
94 | |||
95 | void init_Keys(void) { | ||
96 | iKeys *d = &keys_; | ||
97 | init_SortedArray(&d->bindings, sizeof(iBinding), cmp_Binding_); | ||
98 | bindDefaults_(); | ||
99 | } | ||
100 | |||
101 | void deinit_Keys(void) { | ||
102 | iKeys *d = &keys_; | ||
103 | clear_Keys_(d); | ||
104 | deinit_SortedArray(&d->bindings); | ||
105 | } | ||
106 | |||
107 | void load_Keys(const char *saveDir) { | ||
108 | |||
109 | } | ||
110 | |||
111 | void save_Keys(const char *saveDir) { | ||
112 | |||
113 | } | ||
114 | |||
115 | void bind_Keys(const char *command, int key, int mods) { | ||
116 | iKeys *d = &keys_; | ||
117 | iBinding *bind = find_Keys_(d, key, mods); | ||
118 | if (bind) { | ||
119 | setCStr_String(&bind->command, command); | ||
120 | } | ||
121 | else { | ||
122 | iBinding bind; | ||
123 | bind.key = key; | ||
124 | bind.mods = mods; | ||
125 | initCStr_String(&bind.command, command); | ||
126 | init_String(&bind.label); | ||
127 | insert_SortedArray(&d->bindings, &bind); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | void setLabel_Keys(const char *command, const char *label) { | ||
132 | iBinding *bind = findCommand_Keys_(&keys_, command); | ||
133 | if (bind) { | ||
134 | setCStr_String(&bind->label, label); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | //const iString *label_Keys(const char *command) { | ||
139 | |||
140 | //} | ||
141 | |||
142 | //const char *shortcutLabel_Keys(const char *command) {} | ||
143 | |||
144 | iBool processEvent_Keys(const SDL_Event *ev) { | ||
145 | iKeys *d = &keys_; | ||
146 | if (ev->type == SDL_KEYDOWN) { | ||
147 | const iBinding *bind = find_Keys_(d, ev->key.keysym.sym, keyMods_Sym(ev->key.keysym.mod)); | ||
148 | if (bind) { | ||
149 | postCommandString_App(&bind->command); | ||
150 | return iTrue; | ||
151 | } | ||
152 | } | ||
153 | return iFalse; | ||
154 | } | ||
diff --git a/src/ui/keys.h b/src/ui/keys.h index a9b13df3..157ddea5 100644 --- a/src/ui/keys.h +++ b/src/ui/keys.h | |||
@@ -22,7 +22,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
22 | 22 | ||
23 | #pragma once | 23 | #pragma once |
24 | 24 | ||
25 | #include <the_Foundation/defs.h> | 25 | #include <the_Foundation/string.h> |
26 | #include <SDL_events.h> | ||
26 | 27 | ||
27 | #if defined (iPlatformApple) | 28 | #if defined (iPlatformApple) |
28 | # define reload_KeyShortcut SDLK_r, KMOD_PRIMARY | 29 | # define reload_KeyShortcut SDLK_r, KMOD_PRIMARY |
@@ -41,3 +42,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
41 | # define byWord_KeyModifier KMOD_CTRL | 42 | # define byWord_KeyModifier KMOD_CTRL |
42 | # define byLine_KeyModifier 0 | 43 | # define byLine_KeyModifier 0 |
43 | #endif | 44 | #endif |
45 | |||
46 | void init_Keys (void); | ||
47 | void deinit_Keys (void); | ||
48 | |||
49 | void load_Keys (const char *saveDir); | ||
50 | void save_Keys (const char *saveDir); | ||
51 | |||
52 | void bind_Keys (const char *command, int key, int mods); | ||
53 | void setLabel_Keys (const char *command, const char *label); | ||
54 | |||
55 | //const iString * label_Keys (const char *command); | ||
56 | //const char * shortcutLabel_Keys (const char *command); | ||
57 | |||
58 | iBool processEvent_Keys (const SDL_Event *); | ||