[1mdiff --git a/CMakeLists.txt b/CMakeLists.txt[m
[1mindex 20def6a7..7d73956d 100644[m
[1m--- a/CMakeLists.txt[m
[1m+++ b/CMakeLists.txt[m
[36m@@ -135,6 +135,7 @@[m [mset (SOURCES[m
src/ui/listwidget.h[m
src/ui/lookupwidget.c[m
src/ui/lookupwidget.h[m
[32m+[m[32m src/ui/keys.c[m
src/ui/keys.h[m
src/ui/metrics.c[m
src/ui/metrics.h[m
[1mdiff --git a/src/app.c b/src/app.c[m
[1mindex e4c31eaf..10f5f0d2 100644[m
[1m--- a/src/app.c[m
[1m+++ b/src/app.c[m
[36m@@ -32,6 +32,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
#include "ui/command.h"[m
#include "ui/documentwidget.h"[m
#include "ui/inputwidget.h"[m
[32m+[m[32m#include "ui/keys.h"[m
#include "ui/labelwidget.h"[m
#include "ui/sidebarwidget.h"[m
#include "ui/text.h"[m
[36m@@ -357,9 +358,11 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m
#if defined (iPlatformApple)[m
setupApplication_MacOS();[m
#endif[m
[32m+[m[32m init_Keys();[m
loadPrefs_App_(d);[m
[32m+[m[32m load_Keys(dataDir_App_);[m
load_Visited(d->visited, dataDir_App_);[m
[31m- load_Bookmarks(d->bookmarks, dataDir_App_);[m
[32m+[m[32m load_Bookmarks(d->bookmarks, dataDir_App_);[m[41m [m
if (isFirstRun) {[m
/* Create the default bookmarks for a quick start. */[m
add_Bookmarks(d->bookmarks,[m
[36m@@ -426,6 +429,7 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m
[m
static void deinit_App(iApp *d) {[m
saveState_App_(d);[m
[32m+[m[32m save_Keys(dataDir_App_);[m
savePrefs_App_(d);[m
deinit_Prefs(&d->prefs);[m
save_Bookmarks(d->bookmarks, dataDir_App_);[m
[36m@@ -501,6 +505,10 @@[m [mvoid processEvents_App(enum iAppEventMode eventMode) {[m
}[m
default: {[m
iBool wasUsed = processEvent_Window(d->window, &ev);[m
[32m+[m[32m if (!wasUsed) {[m
[32m+[m[32m /* There may be a key bindings for this. */[m
[32m+[m[32m wasUsed = processEvent_Keys(&ev);[m
[32m+[m[32m }[m
if (ev.type == SDL_USEREVENT && ev.user.code == command_UserEventCode) {[m
#if defined (iPlatformApple) && !defined (iPlatformIOS)[m
handleCommand_MacOS(command_UserEvent(&ev));[m
[1mdiff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c[m
[1mindex 5c6780d1..a2bea17b 100644[m
[1m--- a/src/ui/documentwidget.c[m
[1m+++ b/src/ui/documentwidget.c[m
[36m@@ -1536,7 +1536,7 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m
updateVisible_DocumentWidget_(d);[m
return iTrue;[m
}[m
[31m- else if (equalWidget_Command(cmd, w, "scroll.page")) {[m
[32m+[m[32m else if (equal_Command(cmd, "scroll.page") && document_App() == d) {[m
if (argLabel_Command(cmd, "repeat")) {[m
/* TODO: Adjust scroll animation to be linear during repeated scroll? */[m
}[m
[36m@@ -1547,6 +1547,40 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m
smoothDuration_DocumentWidget_);[m
return iTrue;[m
}[m
[32m+[m[32m else if (equal_Command(cmd, "scroll.top") && document_App() == d) {[m
[32m+[m[32m init_Anim(&d->scrollY, 0);[m
[32m+[m[32m invalidate_VisBuf(d->visBuf);[m
[32m+[m[32m scroll_DocumentWidget_(d, 0);[m
[32m+[m[32m updateVisible_DocumentWidget_(d);[m
[32m+[m[32m refresh_Widget(w);[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m }[m
[32m+[m[32m else if (equal_Command(cmd, "scroll.bottom") && document_App() == d) {[m
[32m+[m[32m init_Anim(&d->scrollY, scrollMax_DocumentWidget_(d));[m
[32m+[m[32m invalidate_VisBuf(d->visBuf);[m
[32m+[m[32m scroll_DocumentWidget_(d, 0);[m
[32m+[m[32m updateVisible_DocumentWidget_(d);[m
[32m+[m[32m refresh_Widget(w);[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m }[m
[32m+[m[32m else if (equal_Command(cmd, "scroll.step") && document_App() == d) {[m
[32m+[m[32m smoothScroll_DocumentWidget_(d,[m
[32m+[m[32m 3 * lineHeight_Text(paragraph_FontId) * arg_Command(cmd),[m
[32m+[m[32m smoothDuration_DocumentWidget_);[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m }[m
[32m+[m[32m#if 0[m
[32m+[m[32m case SDLK_PAGEUP:[m
[32m+[m[32m case SDLK_PAGEDOWN:[m
[32m+[m[32m case SDLK_SPACE:[m
[32m+[m[32m postCommand_Widget([m
[32m+[m[32m w,[m
[32m+[m[32m "scroll.page arg:%d repeat:%d",[m
[32m+[m[32m (key == SDLK_SPACE && mods & KMOD_SHIFT) || key == SDLK_PAGEUP ? -1 : +1,[m
[32m+[m[32m ev->key.repeat != 0);[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m }[m
[32m+[m[32m#endif[m
else if (equal_Command(cmd, "document.goto") && document_App() == d) {[m
const iRangecc heading = range_Command(cmd, "heading");[m
if (heading.start) {[m
[36m@@ -1790,45 +1824,6 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m
refresh_Widget(w);[m
}[m
break;[m
[31m- case SDLK_HOME:[m
[31m- init_Anim(&d->scrollY, 0);[m
[31m- invalidate_VisBuf(d->visBuf);[m
[31m- scroll_DocumentWidget_(d, 0);[m
[31m- updateVisible_DocumentWidget_(d);[m
[31m- refresh_Widget(w);[m
[31m- return iTrue;[m
[31m- case SDLK_END:[m
[31m- init_Anim(&d->scrollY, scrollMax_DocumentWidget_(d));[m
[31m- invalidate_VisBuf(d->visBuf);[m
[31m- scroll_DocumentWidget_(d, 0);[m
[31m- updateVisible_DocumentWidget_(d);[m
[31m- refresh_Widget(w);[m
[31m- return iTrue;[m
[31m- case SDLK_UP:[m
[31m- case SDLK_DOWN:[m
[31m- if (mods == 0) {[m
[31m- if (ev->key.repeat) {[m
[31m-// if (!d->smoothContinue) {[m
[31m-// d->smoothContinue = iTrue;[m
[31m-// }[m
[31m-// else return iTrue;[m
[31m- }[m
[31m- smoothScroll_DocumentWidget_(d,[m
[31m- 3 * lineHeight_Text(paragraph_FontId) *[m
[31m- (key == SDLK_UP ? -1 : 1),[m
[31m- /*gap_Text * */smoothDuration_DocumentWidget_);[m
[31m- return iTrue;[m
[31m- }[m
[31m- break;[m
[31m- case SDLK_PAGEUP:[m
[31m- case SDLK_PAGEDOWN:[m
[31m- case SDLK_SPACE:[m
[31m- postCommand_Widget([m
[31m- w,[m
[31m- "scroll.page arg:%d repeat:%d",[m
[31m- (key == SDLK_SPACE && mods & KMOD_SHIFT) || key == SDLK_PAGEUP ? -1 : +1,[m
[31m- ev->key.repeat != 0);[m
[31m- return iTrue;[m
#if 1[m
case SDLK_KP_1:[m
case '`': {[m
[1mdiff --git a/src/ui/keys.c b/src/ui/keys.c[m
[1mnew file mode 100644[m
[1mindex 00000000..d46d20bf[m
[1m--- /dev/null[m
[1m+++ b/src/ui/keys.c[m
[36m@@ -0,0 +1,154 @@[m
[32m+[m[32m/* Copyright 2020 Jaakko Keränen jaakko.keranen@iki.fi[m
[32m+[m
[32m+[m[32mRedistribution and use in source and binary forms, with or without[m
[32m+[m[32mmodification, are permitted provided that the following conditions are met:[m
[32m+[m
[32m+[m[32m1. Redistributions of source code must retain the above copyright notice, this[m
[32m+[m[32m list of conditions and the following disclaimer.[m
[32m+[m[32m2. Redistributions in binary form must reproduce the above copyright notice,[m
[32m+[m[32m this list of conditions and the following disclaimer in the documentation[m
[32m+[m[32m and/or other materials provided with the distribution.[m
[32m+[m
[32m+[m[32mTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND[m
[32m+[m[32mANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED[m
[32m+[m[32mWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE[m
[32m+[m[32mDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR[m
[32m+[m[32mANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES[m
[32m+[m[32m(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;[m
[32m+[m[32mLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON[m
[32m+[m[32mANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT[m
[32m+[m[32m(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS[m
[32m+[m[32mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
[32m+[m
[32m+[m[32m#include "keys.h"[m
[32m+[m[32m#include "util.h"[m
[32m+[m[32m#include "app.h"[m
[32m+[m
[32m+[m[32m#include <the_Foundation/sortedarray.h>[m
[32m+[m
[32m+[m[32miDeclareType(Keys)[m
[32m+[m[32miDeclareType(Binding)[m
[32m+[m
[32m+[m[32mstruct Impl_Binding {[m
[32m+[m[32m int key;[m
[32m+[m[32m int mods;[m
[32m+[m[32m iString command;[m
[32m+[m[32m iString label;[m
[32m+[m[32m};[m
[32m+[m
[32m+[m[32mstatic int cmp_Binding_(const void *a, const void *b) {[m
[32m+[m[32m const iBinding *d = a, *other = b;[m
[32m+[m[32m const int cmp = iCmp(d->key, other->key);[m
[32m+[m[32m if (cmp == 0) {[m
[32m+[m[32m return iCmp(d->mods, other->mods);[m
[32m+[m[32m }[m
[32m+[m[32m return cmp;[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mstruct Impl_Keys {[m
[32m+[m[32m iSortedArray bindings;[m
[32m+[m[32m};[m
[32m+[m
[32m+[m[32mstatic iKeys keys_;[m
[32m+[m
[32m+[m[32mstatic void clear_Keys_(iKeys *d) {[m
[32m+[m[32m iForEach(Array, i, &d->bindings.values) {[m
[32m+[m[32m iBinding *bind = i.value;[m
[32m+[m[32m deinit_String(&bind->command);[m
[32m+[m[32m deinit_String(&bind->label);[m
[32m+[m[32m }[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mstatic void bindDefaults_(void) {[m
[32m+[m[32m bind_Keys("scroll.top", SDLK_HOME, 0);[m
[32m+[m[32m bind_Keys("scroll.bottom", SDLK_END, 0);[m
[32m+[m[32m bind_Keys("scroll.step arg:-1", SDLK_UP, 0);[m
[32m+[m[32m bind_Keys("scroll.step arg:1", SDLK_DOWN, 0);[m
[32m+[m[32m bind_Keys("scroll.page arg:-1", SDLK_PAGEUP, 0);[m
[32m+[m[32m bind_Keys("scroll.page arg:-1", SDLK_SPACE, KMOD_SHIFT);[m
[32m+[m[32m bind_Keys("scroll.page arg:1", SDLK_PAGEDOWN, 0);[m
[32m+[m[32m bind_Keys("scroll.page arg:1", SDLK_SPACE, 0);[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mstatic iBinding *find_Keys_(iKeys *d, int key, int mods) {[m
[32m+[m[32m const iBinding bind = { .key = key, .mods = mods };[m
[32m+[m[32m size_t pos;[m
[32m+[m[32m if (locate_SortedArray(&d->bindings, &bind, &pos)) {[m
[32m+[m[32m return at_SortedArray(&d->bindings, pos);[m
[32m+[m[32m }[m
[32m+[m[32m return NULL;[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mstatic iBinding *findCommand_Keys_(iKeys *d, const char *command) {[m
[32m+[m[32m /* Note: O(n) */[m
[32m+[m[32m iForEach(Array, i, &d->bindings.values) {[m
[32m+[m[32m iBinding *bind = i.value;[m
[32m+[m[32m if (!cmp_String(&bind->command, command)) {[m
[32m+[m[32m return bind;[m
[32m+[m[32m }[m
[32m+[m[32m }[m
[32m+[m[32m return NULL;[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32m/----------------------------------------------------------------------------------------------/[m
[32m+[m
[32m+[m[32mvoid init_Keys(void) {[m
[32m+[m[32m iKeys *d = &keys_;[m
[32m+[m[32m init_SortedArray(&d->bindings, sizeof(iBinding), cmp_Binding_);[m
[32m+[m[32m bindDefaults_();[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mvoid deinit_Keys(void) {[m
[32m+[m[32m iKeys *d = &keys_;[m
[32m+[m[32m clear_Keys_(d);[m
[32m+[m[32m deinit_SortedArray(&d->bindings);[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mvoid load_Keys(const char *saveDir) {[m
[32m+[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mvoid save_Keys(const char *saveDir) {[m
[32m+[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mvoid bind_Keys(const char *command, int key, int mods) {[m
[32m+[m[32m iKeys *d = &keys_;[m
[32m+[m[32m iBinding *bind = find_Keys_(d, key, mods);[m
[32m+[m[32m if (bind) {[m
[32m+[m[32m setCStr_String(&bind->command, command);[m
[32m+[m[32m }[m
[32m+[m[32m else {[m
[32m+[m[32m iBinding bind;[m
[32m+[m[32m bind.key = key;[m
[32m+[m[32m bind.mods = mods;[m
[32m+[m[32m initCStr_String(&bind.command, command);[m
[32m+[m[32m init_String(&bind.label);[m
[32m+[m[32m insert_SortedArray(&d->bindings, &bind);[m
[32m+[m[32m }[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mvoid setLabel_Keys(const char *command, const char *label) {[m
[32m+[m[32m iBinding *bind = findCommand_Keys_(&keys_, command);[m
[32m+[m[32m if (bind) {[m
[32m+[m[32m setCStr_String(&bind->label, label);[m
[32m+[m[32m }[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32m//const iString *label_Keys(const char *command) {[m
[32m+[m
[32m+[m[32m//}[m
[32m+[m
[32m+[m[32m//const char *shortcutLabel_Keys(const char *command) {}[m
[32m+[m
[32m+[m[32miBool processEvent_Keys(const SDL_Event *ev) {[m
[32m+[m[32m iKeys *d = &keys_;[m
[32m+[m[32m if (ev->type == SDL_KEYDOWN) {[m
[32m+[m[32m const iBinding *bind = find_Keys_(d, ev->key.keysym.sym, keyMods_Sym(ev->key.keysym.mod));[m
[32m+[m[32m if (bind) {[m
[32m+[m[32m postCommandString_App(&bind->command);[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m }[m
[32m+[m[32m }[m
[32m+[m[32m return iFalse;[m
[32m+[m[32m}[m
[1mdiff --git a/src/ui/keys.h b/src/ui/keys.h[m
[1mindex a9b13df3..157ddea5 100644[m
[1m--- a/src/ui/keys.h[m
[1m+++ b/src/ui/keys.h[m
[36m@@ -22,7 +22,8 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
[m
#pragma once[m
[m
[31m-#include <the_Foundation/defs.h>[m
[32m+[m[32m#include <the_Foundation/string.h>[m
[32m+[m[32m#include <SDL_events.h>[m
[m
#if defined (iPlatformApple)[m
[36m@@ -41,3 +42,17 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
#endif[m
[32m+[m
[32m+[m[32mvoid init_Keys (void);[m
[32m+[m[32mvoid deinit_Keys (void);[m
[32m+[m
[32m+[m[32mvoid load_Keys (const char *saveDir);[m
[32m+[m[32mvoid save_Keys (const char *saveDir);[m
[32m+[m
[32m+[m[32mvoid bind_Keys (const char *command, int key, int mods);[m
[32m+[m[32mvoid setLabel_Keys (const char *command, const char *label);[m
[32m+[m
[32m+[m[32m//const iString * label_Keys (const char *command);[m
[32m+[m[32m//const char * shortcutLabel_Keys (const char *command);[m
[32m+[m
[32m+[m[32miBool processEvent_Keys (const SDL_Event *);[m
text/plain
This content has been proxied by September (ba2dc).