diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-24 12:41:46 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-24 12:41:46 +0200 |
commit | 83e936f53d3129433edfdb229a2faf78e48687b1 (patch) | |
tree | 4af84e84b7ba5faccac71522fd665bfb63491acf | |
parent | 740c95a2b0eda0297865b739d780474cea13e75c (diff) |
GmDocument: Media type flexibility
Allow defining new inline media types.
-rw-r--r-- | src/gmdocument.c | 21 | ||||
-rw-r--r-- | src/gmdocument.h | 11 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 32 |
3 files changed, 38 insertions, 26 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index e33be932..5e762dff 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -285,7 +285,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
285 | 0.0f, 0.333f, 1.0f, 0.5f, 2.0f, 1.5f, 1.0f, 0.25f | 285 | 0.0f, 0.333f, 1.0f, 0.5f, 2.0f, 1.5f, 1.0f, 0.25f |
286 | }; | 286 | }; |
287 | static const float bottomMargin[max_GmLineType] = { | 287 | static const float bottomMargin[max_GmLineType] = { |
288 | 0.0f, 0.333f, 1.0f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f | 288 | 0.0f, 0.333f, 1.0f, 0.5f, 0.5f, 0.5f, 0.5f, 0.25f |
289 | }; | 289 | }; |
290 | static const char *arrow = "\u27a4"; | 290 | static const char *arrow = "\u27a4"; |
291 | static const char *envelope = "\U0001f4e7"; | 291 | static const char *envelope = "\U0001f4e7"; |
@@ -578,15 +578,17 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
578 | const iInt2 maxSize = mulf_I2(img.size, get_Window()->pixelRatio); | 578 | const iInt2 maxSize = mulf_I2(img.size, get_Window()->pixelRatio); |
579 | if (width_Rect(run.visBounds) > maxSize.x) { | 579 | if (width_Rect(run.visBounds) > maxSize.x) { |
580 | /* Don't scale the image up. */ | 580 | /* Don't scale the image up. */ |
581 | run.visBounds.size.y = run.visBounds.size.y * maxSize.x / width_Rect(run.visBounds); | 581 | run.visBounds.size.y = |
582 | run.visBounds.size.y * maxSize.x / width_Rect(run.visBounds); | ||
582 | run.visBounds.size.x = maxSize.x; | 583 | run.visBounds.size.x = maxSize.x; |
583 | run.visBounds.pos.x = run.bounds.size.x / 2 - width_Rect(run.visBounds) / 2; | 584 | run.visBounds.pos.x = run.bounds.size.x / 2 - width_Rect(run.visBounds) / 2; |
584 | run.bounds.size.y = run.visBounds.size.y; | 585 | run.bounds.size.y = run.visBounds.size.y; |
585 | } | 586 | } |
586 | run.text = iNullRange; | 587 | run.text = iNullRange; |
587 | run.font = 0; | 588 | run.font = 0; |
588 | run.color = 0; | 589 | run.color = 0; |
589 | run.imageId = imageId; | 590 | run.mediaType = image_GmRunMediaType; |
591 | run.mediaId = imageId; | ||
590 | pushBack_Array(&d->layout, &run); | 592 | pushBack_Array(&d->layout, &run); |
591 | pos.y += run.bounds.size.y + margin; | 593 | pos.y += run.bounds.size.y + margin; |
592 | } | 594 | } |
@@ -608,7 +610,8 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
608 | run.visBounds = run.bounds; | 610 | run.visBounds = run.bounds; |
609 | run.text = iNullRange; | 611 | run.text = iNullRange; |
610 | run.color = 0; | 612 | run.color = 0; |
611 | run.audioId = audioId; | 613 | run.mediaType = audio_GmRunMediaType; |
614 | run.mediaId = audioId; | ||
612 | pushBack_Array(&d->layout, &run); | 615 | pushBack_Array(&d->layout, &run); |
613 | pos.y += run.bounds.size.y + margin; | 616 | pos.y += run.bounds.size.y + margin; |
614 | } | 617 | } |
diff --git a/src/gmdocument.h b/src/gmdocument.h index e2c7e10c..16127ea3 100644 --- a/src/gmdocument.h +++ b/src/gmdocument.h | |||
@@ -85,17 +85,24 @@ enum iGmRunFlags { | |||
85 | wide_GmRunFlag = iBit(6), /* horizontally scrollable */ | 85 | wide_GmRunFlag = iBit(6), /* horizontally scrollable */ |
86 | }; | 86 | }; |
87 | 87 | ||
88 | enum iGmRunMediaType { | ||
89 | none_GmRunMediaType, | ||
90 | image_GmRunMediaType, | ||
91 | audio_GmRunMediaType, | ||
92 | download_GmRunMediaType, | ||
93 | }; | ||
94 | |||
88 | struct Impl_GmRun { | 95 | struct Impl_GmRun { |
89 | iRangecc text; | 96 | iRangecc text; |
90 | uint8_t font; | 97 | uint8_t font; |
91 | uint8_t color; | 98 | uint8_t color; |
92 | uint8_t flags; | 99 | uint8_t flags; |
100 | uint8_t mediaType; | ||
93 | iRect bounds; /* used for hit testing, may extend to edges */ | 101 | iRect bounds; /* used for hit testing, may extend to edges */ |
94 | iRect visBounds; /* actual visual bounds */ | 102 | iRect visBounds; /* actual visual bounds */ |
95 | uint16_t preId; /* preformatted block ID (sequential) */ | 103 | uint16_t preId; /* preformatted block ID (sequential) */ |
96 | iGmLinkId linkId; /* zero for non-links */ | 104 | iGmLinkId linkId; /* zero for non-links */ |
97 | uint16_t imageId; /* zero if not an image */ | 105 | uint16_t mediaId; /* zero if not an image */ |
98 | uint16_t audioId; /* zero if not audio */ | ||
99 | }; | 106 | }; |
100 | 107 | ||
101 | iDeclareType(GmRunRange) | 108 | iDeclareType(GmRunRange) |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 92966538..6b023349 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -414,7 +414,7 @@ static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) { | |||
414 | 414 | ||
415 | static void addVisible_DocumentWidget_(void *context, const iGmRun *run) { | 415 | static void addVisible_DocumentWidget_(void *context, const iGmRun *run) { |
416 | iDocumentWidget *d = context; | 416 | iDocumentWidget *d = context; |
417 | if (~run->flags & decoration_GmRunFlag && !run->imageId) { | 417 | if (~run->flags & decoration_GmRunFlag && !run->mediaId) { |
418 | if (!d->firstVisibleRun) { | 418 | if (!d->firstVisibleRun) { |
419 | d->firstVisibleRun = run; | 419 | d->firstVisibleRun = run; |
420 | } | 420 | } |
@@ -423,7 +423,8 @@ static void addVisible_DocumentWidget_(void *context, const iGmRun *run) { | |||
423 | if (run->preId && run->flags & wide_GmRunFlag) { | 423 | if (run->preId && run->flags & wide_GmRunFlag) { |
424 | pushBack_PtrArray(&d->visibleWideRuns, run); | 424 | pushBack_PtrArray(&d->visibleWideRuns, run); |
425 | } | 425 | } |
426 | if (run->audioId) { | 426 | if (run->mediaType == audio_GmRunMediaType) { |
427 | iAssert(run->mediaId); | ||
427 | pushBack_PtrArray(&d->visiblePlayers, run); | 428 | pushBack_PtrArray(&d->visiblePlayers, run); |
428 | } | 429 | } |
429 | if (run->linkId) { | 430 | if (run->linkId) { |
@@ -568,7 +569,7 @@ static uint32_t playerUpdateInterval_DocumentWidget_(const iDocumentWidget *d) { | |||
568 | uint32_t interval = 0; | 569 | uint32_t interval = 0; |
569 | iConstForEach(PtrArray, i, &d->visiblePlayers) { | 570 | iConstForEach(PtrArray, i, &d->visiblePlayers) { |
570 | const iGmRun *run = i.ptr; | 571 | const iGmRun *run = i.ptr; |
571 | iPlayer * plr = audioPlayer_Media(media_GmDocument(d->doc), run->audioId); | 572 | iPlayer * plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); |
572 | if (flags_Player(plr) & adjustingVolume_PlayerFlag || | 573 | if (flags_Player(plr) & adjustingVolume_PlayerFlag || |
573 | (isStarted_Player(plr) && !isPaused_Player(plr))) { | 574 | (isStarted_Player(plr) && !isPaused_Player(plr))) { |
574 | interval = 1000 / 15; | 575 | interval = 1000 / 15; |
@@ -589,7 +590,7 @@ static void updatePlayers_DocumentWidget_(iDocumentWidget *d) { | |||
589 | refresh_Widget(d); | 590 | refresh_Widget(d); |
590 | iConstForEach(PtrArray, i, &d->visiblePlayers) { | 591 | iConstForEach(PtrArray, i, &d->visiblePlayers) { |
591 | const iGmRun *run = i.ptr; | 592 | const iGmRun *run = i.ptr; |
592 | iPlayer * plr = audioPlayer_Media(media_GmDocument(d->doc), run->audioId); | 593 | iPlayer * plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); |
593 | if (idleTimeMs_Player(plr) > 3000 && ~flags_Player(plr) & volumeGrabbed_PlayerFlag && | 594 | if (idleTimeMs_Player(plr) > 3000 && ~flags_Player(plr) & volumeGrabbed_PlayerFlag && |
594 | flags_Player(plr) & adjustingVolume_PlayerFlag) { | 595 | flags_Player(plr) & adjustingVolume_PlayerFlag) { |
595 | setFlags_Player(plr, adjustingVolume_PlayerFlag, iFalse); | 596 | setFlags_Player(plr, adjustingVolume_PlayerFlag, iFalse); |
@@ -1464,7 +1465,8 @@ static void allocVisBuffer_DocumentWidget_(const iDocumentWidget *d) { | |||
1464 | static iBool fetchNextUnfetchedImage_DocumentWidget_(iDocumentWidget *d) { | 1465 | static iBool fetchNextUnfetchedImage_DocumentWidget_(iDocumentWidget *d) { |
1465 | iConstForEach(PtrArray, i, &d->visibleLinks) { | 1466 | iConstForEach(PtrArray, i, &d->visibleLinks) { |
1466 | const iGmRun *run = i.ptr; | 1467 | const iGmRun *run = i.ptr; |
1467 | if (run->linkId && !run->imageId && ~run->flags & decoration_GmRunFlag) { | 1468 | if (run->linkId && run->mediaType == none_GmRunMediaType && |
1469 | ~run->flags & decoration_GmRunFlag) { | ||
1468 | const int linkFlags = linkFlags_GmDocument(d->doc, run->linkId); | 1470 | const int linkFlags = linkFlags_GmDocument(d->doc, run->linkId); |
1469 | if (isMediaLink_GmDocument(d->doc, run->linkId) && | 1471 | if (isMediaLink_GmDocument(d->doc, run->linkId) && |
1470 | linkFlags & imageFileExtension_GmLinkFlag && | 1472 | linkFlags & imageFileExtension_GmLinkFlag && |
@@ -2174,8 +2176,8 @@ static iRect playerRect_DocumentWidget_(const iDocumentWidget *d, const iGmRun * | |||
2174 | } | 2176 | } |
2175 | 2177 | ||
2176 | static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) { | 2178 | static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) { |
2177 | if (run) { | 2179 | if (run && run->mediaType == audio_GmRunMediaType) { |
2178 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), run->audioId); | 2180 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); |
2179 | setFlags_Player(plr, volumeGrabbed_PlayerFlag, iTrue); | 2181 | setFlags_Player(plr, volumeGrabbed_PlayerFlag, iTrue); |
2180 | d->grabbedStartVolume = volume_Player(plr); | 2182 | d->grabbedStartVolume = volume_Player(plr); |
2181 | d->grabbedPlayer = run; | 2183 | d->grabbedPlayer = run; |
@@ -2183,7 +2185,7 @@ static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *r | |||
2183 | } | 2185 | } |
2184 | else if (d->grabbedPlayer) { | 2186 | else if (d->grabbedPlayer) { |
2185 | setFlags_Player( | 2187 | setFlags_Player( |
2186 | audioPlayer_Media(media_GmDocument(d->doc), d->grabbedPlayer->audioId), | 2188 | audioPlayer_Media(media_GmDocument(d->doc), d->grabbedPlayer->mediaId), |
2187 | volumeGrabbed_PlayerFlag, | 2189 | volumeGrabbed_PlayerFlag, |
2188 | iFalse); | 2190 | iFalse); |
2189 | d->grabbedPlayer = NULL; | 2191 | d->grabbedPlayer = NULL; |
@@ -2212,7 +2214,7 @@ static iBool processPlayerEvents_DocumentWidget_(iDocumentWidget *d, const SDL_E | |||
2212 | iConstForEach(PtrArray, i, &d->visiblePlayers) { | 2214 | iConstForEach(PtrArray, i, &d->visiblePlayers) { |
2213 | const iGmRun *run = i.ptr; | 2215 | const iGmRun *run = i.ptr; |
2214 | const iRect rect = playerRect_DocumentWidget_(d, run); | 2216 | const iRect rect = playerRect_DocumentWidget_(d, run); |
2215 | iPlayer * plr = audioPlayer_Media(media_GmDocument(d->doc), run->audioId); | 2217 | iPlayer * plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); |
2216 | if (contains_Rect(rect, mouse)) { | 2218 | if (contains_Rect(rect, mouse)) { |
2217 | iPlayerUI ui; | 2219 | iPlayerUI ui; |
2218 | init_PlayerUI(&ui, plr, rect); | 2220 | init_PlayerUI(&ui, plr, rect); |
@@ -2619,7 +2621,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2619 | case drag_ClickResult: { | 2621 | case drag_ClickResult: { |
2620 | if (d->grabbedPlayer) { | 2622 | if (d->grabbedPlayer) { |
2621 | iPlayer *plr = | 2623 | iPlayer *plr = |
2622 | audioPlayer_Media(media_GmDocument(d->doc), d->grabbedPlayer->audioId); | 2624 | audioPlayer_Media(media_GmDocument(d->doc), d->grabbedPlayer->mediaId); |
2623 | iPlayerUI ui; | 2625 | iPlayerUI ui; |
2624 | init_PlayerUI(&ui, plr, playerRect_DocumentWidget_(d, d->grabbedPlayer)); | 2626 | init_PlayerUI(&ui, plr, playerRect_DocumentWidget_(d, d->grabbedPlayer)); |
2625 | float off = (float) delta_Click(&d->click).x / (float) width_Rect(ui.volumeSlider); | 2627 | float off = (float) delta_Click(&d->click).x / (float) width_Rect(ui.volumeSlider); |
@@ -2826,7 +2828,7 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol | |||
2826 | 2828 | ||
2827 | static void drawMark_DrawContext_(void *context, const iGmRun *run) { | 2829 | static void drawMark_DrawContext_(void *context, const iGmRun *run) { |
2828 | iDrawContext *d = context; | 2830 | iDrawContext *d = context; |
2829 | if (!run->imageId) { | 2831 | if (run->mediaType == none_GmRunMediaType) { |
2830 | fillRange_DrawContext_(d, run, uiMatching_ColorId, d->widget->foundMark, &d->inFoundMark); | 2832 | fillRange_DrawContext_(d, run, uiMatching_ColorId, d->widget->foundMark, &d->inFoundMark); |
2831 | fillRange_DrawContext_(d, run, uiMarked_ColorId, d->widget->selectMark, &d->inSelectMark); | 2833 | fillRange_DrawContext_(d, run, uiMarked_ColorId, d->widget->selectMark, &d->inSelectMark); |
2832 | } | 2834 | } |
@@ -2925,8 +2927,8 @@ static void drawBannerRun_DrawContext_(iDrawContext *d, const iGmRun *run, iInt2 | |||
2925 | static void drawRun_DrawContext_(void *context, const iGmRun *run) { | 2927 | static void drawRun_DrawContext_(void *context, const iGmRun *run) { |
2926 | iDrawContext *d = context; | 2928 | iDrawContext *d = context; |
2927 | const iInt2 origin = d->viewPos; | 2929 | const iInt2 origin = d->viewPos; |
2928 | if (run->imageId) { | 2930 | if (run->mediaType == image_GmRunMediaType) { |
2929 | SDL_Texture *tex = imageTexture_Media(media_GmDocument(d->widget->doc), run->imageId); | 2931 | SDL_Texture *tex = imageTexture_Media(media_GmDocument(d->widget->doc), run->mediaId); |
2930 | if (tex) { | 2932 | if (tex) { |
2931 | const iRect dst = moved_Rect(run->visBounds, origin); | 2933 | const iRect dst = moved_Rect(run->visBounds, origin); |
2932 | fillRect_Paint(&d->paint, dst, tmBackground_ColorId); /* in case the image has alpha */ | 2934 | fillRect_Paint(&d->paint, dst, tmBackground_ColorId); /* in case the image has alpha */ |
@@ -2935,7 +2937,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
2935 | } | 2937 | } |
2936 | return; | 2938 | return; |
2937 | } | 2939 | } |
2938 | else if (run->audioId) { | 2940 | else if (run->mediaType == audio_GmRunMediaType) { |
2939 | /* Audio player UI is drawn afterwards as a dynamic overlay. */ | 2941 | /* Audio player UI is drawn afterwards as a dynamic overlay. */ |
2940 | return; | 2942 | return; |
2941 | } | 2943 | } |
@@ -3283,7 +3285,7 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | |||
3283 | static void drawPlayers_DocumentWidget_(const iDocumentWidget *d, iPaint *p) { | 3285 | static void drawPlayers_DocumentWidget_(const iDocumentWidget *d, iPaint *p) { |
3284 | iConstForEach(PtrArray, i, &d->visiblePlayers) { | 3286 | iConstForEach(PtrArray, i, &d->visiblePlayers) { |
3285 | const iGmRun * run = i.ptr; | 3287 | const iGmRun * run = i.ptr; |
3286 | const iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), run->audioId); | 3288 | const iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); |
3287 | const iRect rect = playerRect_DocumentWidget_(d, run); | 3289 | const iRect rect = playerRect_DocumentWidget_(d, run); |
3288 | iPlayerUI ui; | 3290 | iPlayerUI ui; |
3289 | init_PlayerUI(&ui, plr, rect); | 3291 | init_PlayerUI(&ui, plr, rect); |