[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/plain
This content has been proxied by September (ba2dc).