diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-06-25 16:22:29 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-06-25 16:22:29 +0300 |
commit | f99a9111170f2ff28383fd3172fdaf4b9a1ba069 (patch) | |
tree | a4c5b801298a569c5043ba69a1b9a6c010a9234c | |
parent | e84b1a4a13ee1932c609e9d9d64b0915fbf468b9 (diff) | |
parent | d06c19e7fdd07ffc52ca4d4903fecf5b539f85ea (diff) |
Merge branch 'dev' into work/v1.6
# Conflicts:
# CMakeLists.txt
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | res/fonts/SmolEmoji-Regular.ttf | bin | 51452 -> 57296 bytes | |||
-rw-r--r-- | src/app.c | 41 | ||||
-rw-r--r-- | src/gmdocument.c | 12 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 7 | ||||
-rw-r--r-- | src/ui/text.c | 28 | ||||
-rw-r--r-- | src/ui/text.h | 3 |
7 files changed, 85 insertions, 11 deletions
@@ -21,11 +21,10 @@ Like Gemini, Lagrange has been designed with minimalism in mind. It depends on a | |||
21 | 21 | ||
22 | Prebuilt binaries for Windows, macOS and Linux can be found in [Releases][rel]. You can also find [Lagrange on Flathub for Linux](https://flathub.org/apps/details/fi.skyjake.Lagrange). | 22 | Prebuilt binaries for Windows, macOS and Linux can be found in [Releases][rel]. You can also find [Lagrange on Flathub for Linux](https://flathub.org/apps/details/fi.skyjake.Lagrange). |
23 | 23 | ||
24 | On macOS you can install and upgrade via a Homebrew tap: | 24 | On macOS you can install and upgrade via Homebrew: |
25 | 25 | ||
26 | ``` | 26 | ``` |
27 | $ brew tap skyjake/lagrange | 27 | brew install --cask lagrange |
28 | $ brew install lagrange | ||
29 | ``` | 28 | ``` |
30 | 29 | ||
31 | On openSUSE Tumbleweed: | 30 | On openSUSE Tumbleweed: |
diff --git a/res/fonts/SmolEmoji-Regular.ttf b/res/fonts/SmolEmoji-Regular.ttf index 26810648..5ef05e27 100644 --- a/res/fonts/SmolEmoji-Regular.ttf +++ b/res/fonts/SmolEmoji-Regular.ttf | |||
Binary files differ | |||
@@ -59,6 +59,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
59 | #include <stdarg.h> | 59 | #include <stdarg.h> |
60 | #include <errno.h> | 60 | #include <errno.h> |
61 | 61 | ||
62 | //#define LAGRANGE_ENABLE_MOUSE_TOUCH_EMULATION 1 | ||
63 | |||
62 | #if defined (iPlatformAppleDesktop) | 64 | #if defined (iPlatformAppleDesktop) |
63 | # include "macos.h" | 65 | # include "macos.h" |
64 | #endif | 66 | #endif |
@@ -1197,6 +1199,45 @@ void processEvents_App(enum iAppEventMode eventMode) { | |||
1197 | ev.wheel.x = -ev.wheel.x; | 1199 | ev.wheel.x = -ev.wheel.x; |
1198 | #endif | 1200 | #endif |
1199 | } | 1201 | } |
1202 | #if defined (LAGRANGE_ENABLE_MOUSE_TOUCH_EMULATION) | ||
1203 | /* Convert mouse events to finger events to test the touch handling. */ { | ||
1204 | static float xPrev = 0.0f; | ||
1205 | static float yPrev = 0.0f; | ||
1206 | if (ev.type == SDL_MOUSEBUTTONDOWN || ev.type == SDL_MOUSEBUTTONUP) { | ||
1207 | const float xf = (d->window->pixelRatio * ev.button.x) / (float) d->window->size.x; | ||
1208 | const float yf = (d->window->pixelRatio * ev.button.y) / (float) d->window->size.y; | ||
1209 | ev.type = (ev.type == SDL_MOUSEBUTTONDOWN ? SDL_FINGERDOWN : SDL_FINGERUP); | ||
1210 | ev.tfinger.x = xf; | ||
1211 | ev.tfinger.y = yf; | ||
1212 | ev.tfinger.dx = xf - xPrev; | ||
1213 | ev.tfinger.dy = yf - yPrev; | ||
1214 | xPrev = xf; | ||
1215 | yPrev = yf; | ||
1216 | ev.tfinger.fingerId = 0x1234; | ||
1217 | ev.tfinger.pressure = 1.0f; | ||
1218 | ev.tfinger.timestamp = SDL_GetTicks(); | ||
1219 | ev.tfinger.touchId = SDL_TOUCH_MOUSEID; | ||
1220 | } | ||
1221 | else if (ev.type == SDL_MOUSEMOTION) { | ||
1222 | if (~ev.motion.state & SDL_BUTTON(SDL_BUTTON_LEFT)) { | ||
1223 | continue; /* only when pressing a button */ | ||
1224 | } | ||
1225 | const float xf = (d->window->pixelRatio * ev.motion.x) / (float) d->window->size.x; | ||
1226 | const float yf = (d->window->pixelRatio * ev.motion.y) / (float) d->window->size.y; | ||
1227 | ev.type = SDL_FINGERMOTION; | ||
1228 | ev.tfinger.x = xf; | ||
1229 | ev.tfinger.y = yf; | ||
1230 | ev.tfinger.dx = xf - xPrev; | ||
1231 | ev.tfinger.dy = yf - yPrev; | ||
1232 | xPrev = xf; | ||
1233 | yPrev = yf; | ||
1234 | ev.tfinger.fingerId = 0x1234; | ||
1235 | ev.tfinger.pressure = 1.0f; | ||
1236 | ev.tfinger.timestamp = SDL_GetTicks(); | ||
1237 | ev.tfinger.touchId = SDL_TOUCH_MOUSEID; | ||
1238 | } | ||
1239 | } | ||
1240 | #endif | ||
1200 | iBool wasUsed = processEvent_Window(d->window, &ev); | 1241 | iBool wasUsed = processEvent_Window(d->window, &ev); |
1201 | if (!wasUsed) { | 1242 | if (!wasUsed) { |
1202 | /* There may be a key bindings for this. */ | 1243 | /* There may be a key bindings for this. */ |
diff --git a/src/gmdocument.c b/src/gmdocument.c index aa2baa4a..f15d9d1d 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -289,6 +289,12 @@ static void clearLinks_GmDocument_(iGmDocument *d) { | |||
289 | clear_PtrArray(&d->links); | 289 | clear_PtrArray(&d->links); |
290 | } | 290 | } |
291 | 291 | ||
292 | static iBool isGopher_GmDocument_(const iGmDocument *d) { | ||
293 | const iRangecc scheme = urlScheme_String(&d->url); | ||
294 | return (equalCase_Rangecc(scheme, "gopher") || | ||
295 | equalCase_Rangecc(scheme, "finger")); | ||
296 | } | ||
297 | |||
292 | static iBool isForcedMonospace_GmDocument_(const iGmDocument *d) { | 298 | static iBool isForcedMonospace_GmDocument_(const iGmDocument *d) { |
293 | const iRangecc scheme = urlScheme_String(&d->url); | 299 | const iRangecc scheme = urlScheme_String(&d->url); |
294 | if (equalCase_Rangecc(scheme, "gemini")) { | 300 | if (equalCase_Rangecc(scheme, "gemini")) { |
@@ -364,6 +370,7 @@ static void updateOpenURLs_GmDocument_(iGmDocument *d) { | |||
364 | static void doLayout_GmDocument_(iGmDocument *d) { | 370 | static void doLayout_GmDocument_(iGmDocument *d) { |
365 | const iPrefs *prefs = prefs_App(); | 371 | const iPrefs *prefs = prefs_App(); |
366 | const iBool isMono = isForcedMonospace_GmDocument_(d); | 372 | const iBool isMono = isForcedMonospace_GmDocument_(d); |
373 | const iBool isGopher = isGopher_GmDocument_(d); | ||
367 | const iBool isNarrow = d->size.x < 90 * gap_Text; | 374 | const iBool isNarrow = d->size.x < 90 * gap_Text; |
368 | const iBool isVeryNarrow = d->size.x <= 70 * gap_Text; | 375 | const iBool isVeryNarrow = d->size.x <= 70 * gap_Text; |
369 | const iBool isExtremelyNarrow = d->size.x <= 60 * gap_Text; | 376 | const iBool isExtremelyNarrow = d->size.x <= 60 * gap_Text; |
@@ -482,7 +489,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
482 | meta.flags = constValue_Array(oldPreMeta, preIndex, iGmPreMeta).flags & | 489 | meta.flags = constValue_Array(oldPreMeta, preIndex, iGmPreMeta).flags & |
483 | folded_GmPreMetaFlag; | 490 | folded_GmPreMetaFlag; |
484 | } | 491 | } |
485 | else if (prefs->collapsePreOnLoad) { | 492 | else if (prefs->collapsePreOnLoad && !isGopher) { |
486 | meta.flags |= folded_GmPreMetaFlag; | 493 | meta.flags |= folded_GmPreMetaFlag; |
487 | } | 494 | } |
488 | pushBack_Array(&d->preMeta, &meta); | 495 | pushBack_Array(&d->preMeta, &meta); |
@@ -1451,6 +1458,9 @@ iBool updateOpenURLs_GmDocument(iGmDocument *d) { | |||
1451 | const iBool isOpen = contains_StringSet(d->openURLs, &link->url); | 1458 | const iBool isOpen = contains_StringSet(d->openURLs, &link->url); |
1452 | if (isOpen ^ ((link->flags & isOpen_GmLinkFlag) != 0)) { | 1459 | if (isOpen ^ ((link->flags & isOpen_GmLinkFlag) != 0)) { |
1453 | iChangeFlags(link->flags, isOpen_GmLinkFlag, isOpen); | 1460 | iChangeFlags(link->flags, isOpen_GmLinkFlag, isOpen); |
1461 | if (isOpen) { | ||
1462 | link->flags |= visited_GmLinkFlag; | ||
1463 | } | ||
1454 | wasChanged = iTrue; | 1464 | wasChanged = iTrue; |
1455 | } | 1465 | } |
1456 | } | 1466 | } |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 7f8d70a3..cb1fde28 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -4155,11 +4155,12 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
4155 | linkOrdinalChar_DocumentWidget_(d->widget, ord - d->widget->ordinalBase); | 4155 | linkOrdinalChar_DocumentWidget_(d->widget, ord - d->widget->ordinalBase); |
4156 | if (ordChar) { | 4156 | if (ordChar) { |
4157 | const char *circle = "\u25ef"; /* Large Circle */ | 4157 | const char *circle = "\u25ef"; /* Large Circle */ |
4158 | const int circleFont = defaultContentRegular_FontId; | ||
4158 | iRect nbArea = { init_I2(d->viewPos.x - gap_UI / 3, visPos.y), | 4159 | iRect nbArea = { init_I2(d->viewPos.x - gap_UI / 3, visPos.y), |
4159 | init_I2(3.95f * gap_Text, 1.0f * lineHeight_Text(run->font)) }; | 4160 | init_I2(3.95f * gap_Text, 1.0f * lineHeight_Text(circleFont)) }; |
4160 | drawRange_Text( | 4161 | drawRange_Text( |
4161 | run->font, topLeft_Rect(nbArea), tmQuote_ColorId, range_CStr(circle)); | 4162 | circleFont, topLeft_Rect(nbArea), tmQuote_ColorId, range_CStr(circle)); |
4162 | iRect circleArea = visualBounds_Text(run->font, range_CStr(circle)); | 4163 | iRect circleArea = visualBounds_Text(circleFont, range_CStr(circle)); |
4163 | addv_I2(&circleArea.pos, topLeft_Rect(nbArea)); | 4164 | addv_I2(&circleArea.pos, topLeft_Rect(nbArea)); |
4164 | drawCentered_Text(defaultContentSmall_FontId, | 4165 | drawCentered_Text(defaultContentSmall_FontId, |
4165 | circleArea, | 4166 | circleArea, |
diff --git a/src/ui/text.c b/src/ui/text.c index ae1248a7..edbc6583 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -116,6 +116,7 @@ iDefineTypeConstructionArgs(Glyph, (iChar ch), ch) | |||
116 | 116 | ||
117 | struct Impl_Font { | 117 | struct Impl_Font { |
118 | iBlock * data; | 118 | iBlock * data; |
119 | enum iTextFont family; | ||
119 | stbtt_fontinfo font; | 120 | stbtt_fontinfo font; |
120 | float xScale, yScale; | 121 | float xScale, yScale; |
121 | int vertOffset; /* offset due to scaling */ | 122 | int vertOffset; /* offset due to scaling */ |
@@ -134,6 +135,15 @@ static void init_Font(iFont *d, const iBlock *data, int height, float scale, | |||
134 | enum iFontSize sizeId, iBool isMonospaced) { | 135 | enum iFontSize sizeId, iBool isMonospaced) { |
135 | init_Hash(&d->glyphs); | 136 | init_Hash(&d->glyphs); |
136 | d->data = NULL; | 137 | d->data = NULL; |
138 | d->family = undefined_TextFont; | ||
139 | /* Note: We only use `family` currently for applying a kerning fix to Nunito. */ | ||
140 | if (data == &fontNunitoRegular_Embedded || | ||
141 | data == &fontNunitoBold_Embedded || | ||
142 | data == &fontNunitoExtraBold_Embedded || | ||
143 | data == &fontNunitoLightItalic_Embedded || | ||
144 | data == &fontNunitoExtraLight_Embedded) { | ||
145 | d->family = nunito_TextFont; | ||
146 | } | ||
137 | d->isMonospaced = isMonospaced; | 147 | d->isMonospaced = isMonospaced; |
138 | d->height = height; | 148 | d->height = height; |
139 | iZap(d->font); | 149 | iZap(d->font); |
@@ -1131,14 +1141,26 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1131 | const iChar next = nextChar_(&peek, args->text.end); | 1141 | const iChar next = nextChar_(&peek, args->text.end); |
1132 | if (enableKerning_Text && !d->manualKernOnly && next) { | 1142 | if (enableKerning_Text && !d->manualKernOnly && next) { |
1133 | const uint32_t nextGlyphIndex = glyphIndex_Font_(glyph->font, next); | 1143 | const uint32_t nextGlyphIndex = glyphIndex_Font_(glyph->font, next); |
1134 | const int kern = stbtt_GetGlyphKernAdvance( | 1144 | int kern = stbtt_GetGlyphKernAdvance( |
1135 | &glyph->font->font, glyph->glyphIndex, nextGlyphIndex); | 1145 | &glyph->font->font, glyph->glyphIndex, nextGlyphIndex); |
1146 | /* Nunito needs some kerning fixes. */ | ||
1147 | if (glyph->font->family == nunito_TextFont) { | ||
1148 | if (ch == 'W' && (next == 'i' || next == 'h')) { | ||
1149 | kern = -30; | ||
1150 | } | ||
1151 | else if (ch == 'T' && next == 'h') { | ||
1152 | kern = -15; | ||
1153 | } | ||
1154 | else if (ch == 'V' && next == 'i') { | ||
1155 | kern = -15; | ||
1156 | } | ||
1157 | } | ||
1136 | if (kern) { | 1158 | if (kern) { |
1137 | // printf("%lc(%u) -> %lc(%u): kern %d (%f)\n", ch, glyph->glyphIndex, next, | 1159 | // printf("%lc(%u) -> %lc(%u): kern %d (%f)\n", ch, glyph->glyphIndex, next, |
1138 | // nextGlyphIndex, | 1160 | // nextGlyphIndex, |
1139 | // kern, d->xScale * kern); | 1161 | // kern, d->xScale * kern); |
1140 | xpos += d->xScale * kern; | 1162 | xpos += glyph->font->xScale * kern; |
1141 | xposExtend += d->xScale * kern; | 1163 | xposExtend += glyph->font->xScale * kern; |
1142 | } | 1164 | } |
1143 | } | 1165 | } |
1144 | } | 1166 | } |
diff --git a/src/ui/text.h b/src/ui/text.h index dd377247..5a099142 100644 --- a/src/ui/text.h +++ b/src/ui/text.h | |||
@@ -117,7 +117,8 @@ iLocalDef iBool isJapanese_FontId(enum iFontId id) { | |||
117 | #define emojiVariationSelector_Char ((iChar) 0xfe0f) | 117 | #define emojiVariationSelector_Char ((iChar) 0xfe0f) |
118 | 118 | ||
119 | enum iTextFont { | 119 | enum iTextFont { |
120 | nunito_TextFont, | 120 | undefined_TextFont = -1, |
121 | nunito_TextFont = 0, | ||
121 | firaSans_TextFont, | 122 | firaSans_TextFont, |
122 | literata_TextFont, | 123 | literata_TextFont, |
123 | tinos_TextFont, | 124 | tinos_TextFont, |