=> bb7bc6fac4fec804846d11c7d77e1b553ba2be6a
[1mdiff --git a/src/app.c b/src/app.c[m [1mindex ff5ec9b7..0916919e 100644[m [1m--- a/src/app.c[m [1m+++ b/src/app.c[m [36m@@ -649,12 +649,17 @@[m [miAny *findWidget_App(const char *id) {[m return findChild_Widget(app_.window->root, id);[m }[m [m [31m-void addTicker_App(void (*ticker)(iAny *), iAny *context) {[m [32m+[m[32mvoid addTicker_App(iTickerFunc ticker, iAny *context) {[m iApp *d = &app_;[m insert_SortedArray(&d->tickers, &(iTicker){ context, ticker });[m postRefresh_App();[m }[m [m [32m+[m[32mvoid removeTicker_App(iTickerFunc ticker, iAny *context) {[m [32m+[m[32m iApp *d = &app_;[m [32m+[m[32m remove_SortedArray(&d->tickers, &(iTicker){ context, ticker });[m [32m+[m[32m}[m [32m+[m iGmCerts *certs_App(void) {[m return app_.certs;[m }[m [36m@@ -737,7 +742,8 @@[m [miDocumentWidget *newTab_App(const iDocumentWidget *duplicateOf, iBool switchToNe[m doc = new_DocumentWidget();[m }[m setId_Widget(as_Widget(doc), format_CStr("document%03d", ++d->tabEnum));[m [31m- appendTabPage_Widget(tabs, iClob(doc), "", 0, 0);[m [32m+[m[32m appendTabPage_Widget(tabs, as_Widget(doc), "", 0, 0);[m [32m+[m[32m iRelease(doc); /* now owned by the tabs */[m addChild_Widget(findChild_Widget(tabs, "tabs.buttons"), iClob(newTabButton));[m if (switchToNew) {[m postCommandf_App("tabs.switch page:%p", doc);[m [1mdiff --git a/src/app.h b/src/app.h[m [1mindex db22230e..bf310d98 100644[m [1m--- a/src/app.h[m [1m+++ b/src/app.h[m [36m@@ -73,8 +73,11 @@[m [miObjectList * listDocuments_App (void);[m iDocumentWidget * document_Command (const char *cmd);[m iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew);[m [m [32m+[m[32mtypedef void (*iTickerFunc)(iAny *);[m [32m+[m iAny * findWidget_App (const char *id);[m [31m-void addTicker_App (void (*ticker)(iAny *), iAny *context);[m [32m+[m[32mvoid addTicker_App (iTickerFunc ticker, iAny *context);[m [32m+[m[32mvoid removeTicker_App (iTickerFunc ticker, iAny *context);[m void postRefresh_App (void);[m void postCommand_App (const char *command);[m void postCommandf_App (const char *command, ...);[m [1mdiff --git a/src/audio/player.c b/src/audio/player.c[m [1mindex 5b9d0103..07f41f01 100644[m [1m--- a/src/audio/player.c[m [1m+++ b/src/audio/player.c[m [36m@@ -563,3 +563,9 @@[m [mfloat streamProgress_Player(const iPlayer *d) {[m }[m return 0;[m }[m [32m+[m [32m+[m[32miString *metadataLabel_Player(const iPlayer *d) {[m [32m+[m[32m return newFormat_String("%d-bit %s %d Hz", SDL_AUDIO_BITSIZE(d->decoder->inputFormat),[m [32m+[m[32m SDL_AUDIO_ISFLOAT(d->decoder->inputFormat) ? "float" : "integer",[m [32m+[m[32m d->spec.freq);[m [32m+[m[32m}[m [1mdiff --git a/src/audio/player.h b/src/audio/player.h[m [1mindex c3552640..fe6717b0 100644[m [1m--- a/src/audio/player.h[m [1m+++ b/src/audio/player.h[m [36m@@ -45,3 +45,5 @@[m [miBool isPaused_Player (const iPlayer *);[m float time_Player (const iPlayer *);[m float duration_Player (const iPlayer *);[m float streamProgress_Player (const iPlayer *); /* normalized 0...1 */[m [32m+[m [32m+[m[32miString * metadataLabel_Player (const iPlayer *);[m [1mdiff --git a/src/media.c b/src/media.c[m [1mindex 253893fc..c447704b 100644[m [1m--- a/src/media.c[m [1m+++ b/src/media.c[m [36m@@ -75,8 +75,8 @@[m [mvoid deinit_GmImage(iGmImage *d) {[m }[m [m void makeTexture_GmImage(iGmImage *d) {[m [31m- iBlock *data = &d->partialData;[m [31m- d->numBytes = size_Block(data);[m [32m+[m[32m iBlock *data = &d->partialData;[m [32m+[m[32m d->numBytes = size_Block(data);[m uint8_t *imgData = stbi_load_from_memory([m constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4);[m if (!imgData) {[m [1mdiff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c[m [1mindex 9d94f200..bbe5ccba 100644[m [1m--- a/src/ui/documentwidget.c[m [1m+++ b/src/ui/documentwidget.c[m [36m@@ -191,6 +191,7 @@[m [mstruct Impl_DocumentWidget {[m iAnim outlineOpacity;[m iArray outline;[m iWidget * menu;[m [32m+[m[32m iWidget * playerMenu;[m iVisBuf * visBuf;[m iPtrSet * invalidRuns;[m };[m [36m@@ -241,6 +242,7 @@[m [mvoid init_DocumentWidget(iDocumentWidget *d) {[m init_Click(&d->click, d, SDL_BUTTON_LEFT);[m addChild_Widget(w, iClob(d->scroll = new_ScrollWidget()));[m d->menu = NULL; /* created when clicking */[m [32m+[m[32m d->playerMenu = NULL;[m #if !defined (iPlatformApple) /* in system menu */[m addAction_Widget(w, reload_KeyShortcut, "navigate.reload");[m addAction_Widget(w, SDLK_w, KMOD_PRIMARY, "tabs.close");[m [36m@@ -249,7 +251,10 @@[m [mvoid init_DocumentWidget(iDocumentWidget *d) {[m addAction_Widget(w, navigateForward_KeyShortcut, "navigate.forward");[m }[m [m [32m+[m[32mstatic void animatePlayingAudio_DocumentWidget_(void *);[m [32m+[m void deinit_DocumentWidget(iDocumentWidget *d) {[m [32m+[m[32m removeTicker_App(animatePlayingAudio_DocumentWidget_, d);[m delete_VisBuf(d->visBuf);[m delete_PtrSet(d->invalidRuns);[m deinit_Array(&d->outline);[m [36m@@ -1626,7 +1631,7 @@[m [mstatic void drawPlayerButton_(iPaint *p, iRect rect, const char *label) {[m adjusted_Rect(shrunk_Rect(frameRect, divi_I2(gap2_UI, 2)), zero_I2(), one_I2()),[m frame);[m }[m [31m- const int fg = isPressed ? uiBackground_ColorId : frame;[m [32m+[m[32m const int fg = isPressed ? (permanent_ColorId | uiBackground_ColorId) : uiHeading_ColorId;[m drawCentered_Text(uiContent_FontId, frameRect, iTrue, fg, "%s", label);[m }[m [m [36m@@ -1704,6 +1709,11 @@[m [mstatic iBool processAudioPlayerEvents_DocumentWidget_(iDocumentWidget *d, const[m ev->type != SDL_MOUSEMOTION) {[m return iFalse;[m }[m [32m+[m[32m if (ev->type == SDL_MOUSEBUTTONDOWN || ev->type == SDL_MOUSEBUTTONUP) {[m [32m+[m[32m if (ev->button.button != SDL_BUTTON_LEFT) {[m [32m+[m[32m return iFalse;[m [32m+[m[32m }[m [32m+[m[32m }[m const iInt2 mouse = init_I2(ev->button.x, ev->button.y);[m iConstForEach(PtrArray, i, &d->visiblePlayers) {[m const iGmRun *run = i.ptr;[m [36m@@ -1722,12 +1732,34 @@[m [mstatic iBool processAudioPlayerEvents_DocumentWidget_(iDocumentWidget *d, const[m return iTrue;[m }[m else if (contains_Rect(ui.rewindRect, mouse)) {[m [31m- stop_Player(plr);[m [31m- start_Player(plr);[m [31m- setPaused_Player(plr, iTrue);[m [32m+[m[32m if (isStarted_Player(plr) && time_Player(plr) > 0.5f) {[m [32m+[m[32m stop_Player(plr);[m [32m+[m[32m start_Player(plr);[m [32m+[m[32m setPaused_Player(plr, iTrue);[m [32m+[m[32m }[m refresh_Widget(d);[m return iTrue;[m }[m [32m+[m[32m else if (contains_Rect(ui.menuRect, mouse)) {[m [32m+[m[32m /* TODO: Add menu items for:[m [32m+[m[32m - output device[m [32m+[m[32m - Save to Downloads[m [32m+[m[32m */[m [32m+[m[32m if (d->playerMenu) {[m [32m+[m[32m destroy_Widget(d->playerMenu);[m [32m+[m[32m d->playerMenu = NULL;[m [32m+[m[32m return iTrue;[m [32m+[m[32m }[m [32m+[m[32m d->playerMenu = makeMenu_Widget([m [32m+[m[32m as_Widget(d),[m [32m+[m[32m (iMenuItem[]){[m [32m+[m[32m { cstrCollect_String(metadataLabel_Player(plr)), 0, 0, NULL },[m [32m+[m[32m },[m [32m+[m[32m 1);[m [32m+[m[32m openMenu_Widget(d->playerMenu,[m [32m+[m[32m localCoord_Widget(constAs_Widget(d), bottomLeft_Rect(ui.menuRect)));[m [32m+[m[32m return iTrue;[m [32m+[m[32m }[m }[m }[m return iFalse;[m [1mdiff --git a/src/ui/util.c b/src/ui/util.c[m [1mindex 13a7a7a2..89f71da2 100644[m [1m--- a/src/ui/util.c[m [1m+++ b/src/ui/util.c[m [36m@@ -498,9 +498,8 @@[m [miWidget *removeTabPage_Widget(iWidget *tabs, size_t index) {[m iWidget *button = removeChild_Widget(buttons, child_Widget(buttons, index));[m iRelease(button);[m iWidget *page = child_Widget(pages, index);[m [31m- ref_Object(page);[m setFlags_Widget(page, hidden_WidgetFlag | disabled_WidgetFlag, iFalse);[m [31m- removeChild_Widget(pages, page);[m [32m+[m[32m removeChild_Widget(pages, page); /* `page` is now ours */[m if (tabCount_Widget(tabs) <= 1 && flags_Widget(buttons) & collapse_WidgetFlag) {[m setFlags_Widget(buttons, hidden_WidgetFlag, iTrue);[m }[m [1mdiff --git a/src/ui/widget.c b/src/ui/widget.c[m [1mindex 459c2ae1..ea2e3fe2 100644[m [1m--- a/src/ui/widget.c[m [1m+++ b/src/ui/widget.c[m [36m@@ -55,7 +55,6 @@[m [miPtrArray *onTop_RootData_(void) {[m void destroyPending_Widget(void) {[m iForEach(PtrSet, i, rootData_.pendingDestruction) {[m iWidget *widget = *i.value;[m [31m- removeOne_PtrArray(onTop_RootData_(), widget);[m if (widget->parent) {[m iRelease(removeChild_Widget(widget->parent, widget));[m }[m [36m@@ -90,6 +89,9 @@[m [mstatic void aboutToBeDestroyed_Widget_(iWidget *d) {[m setFocus_Widget(NULL);[m return;[m }[m [32m+[m[32m if (flags_Widget(d) & keepOnTop_WidgetFlag) {[m [32m+[m[32m removeOne_PtrArray(onTop_RootData_(), d);[m [32m+[m[32m }[m if (isHover_Widget(d)) {[m rootData_.hover = NULL;[m }[m
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).