This commit is contained in:
John 2024-05-09 20:23:54 -06:00 committed by GitHub
commit a428cb9ee8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 271 additions and 8 deletions

View File

@ -119,6 +119,7 @@ Appreciation for contributors who have provided substantial work, but are no lon
* Tiago Reul (reul) - Misc.
* Fredrik Tegnell (fredriktegnell) - Misc.
* Alex Parisi (alex-parisi) - Added API for returning metadata from all registered plugins.
* John Dolph (johnwdolph) - Ride music UI, misc.
## Bug fixes & Refactors
* Claudio Tiecher (janclod)

View File

@ -194,6 +194,8 @@ enum {
WIDX_PLAY_MUSIC = 14,
WIDX_MUSIC,
WIDX_MUSIC_DROPDOWN,
WIDX_MUSIC_IMAGE,
WIDX_MUSIC_DATA,
WIDX_SAVE_TRACK_DESIGN = 14,
WIDX_SELECT_NEARBY_SCENERY,
@ -336,9 +338,11 @@ static Widget _colourWidgets[] = {
// 0x009AE4C8
static Widget _musicWidgets[] = {
MAIN_RIDE_WIDGETS,
MakeWidget({ 7, 47}, {302, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_PLAY_MUSIC, STR_SELECT_MUSIC_TIP ),
MakeWidget({ 7, 62}, {302, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_EMPTY ),
MakeWidget({297, 63}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_MUSIC_STYLE_TIP),
MakeWidget({ 7, 47}, {302, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_PLAY_MUSIC, STR_SELECT_MUSIC_TIP ),
MakeWidget({ 7, 62}, {302, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_EMPTY ),
MakeWidget({297, 63}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_MUSIC_STYLE_TIP),
MakeWidget({154, 62}, {114, 114}, WindowWidgetType::FlatBtn, WindowColour::Secondary ),
MakeWidget({ 7, 90}, {500, 450}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_BOTH ),
kWidgetsEnd,
};
@ -961,6 +965,8 @@ static_assert(std::size(RatingNames) == 6);
{
case WINDOW_RIDE_PAGE_GRAPHS:
return GraphsScrollGetSize(scrollIndex);
case WINDOW_RIDE_PAGE_MUSIC:
return MusicScrollGetSize(scrollIndex);
}
return {};
}
@ -986,6 +992,9 @@ static_assert(std::size(RatingNames) == 6);
case WINDOW_RIDE_PAGE_GRAPHS:
GraphsOnScrollDraw(dpi, scrollIndex);
break;
case WINDOW_RIDE_PAGE_MUSIC:
MusicOnScrollDraw(dpi, scrollIndex);
break;
}
}
virtual void OnToolDown(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) override
@ -4830,6 +4839,7 @@ static_assert(std::size(RatingNames) == 6);
{
int32_t activateMusic = (ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC) ? 0 : 1;
SetOperatingSetting(rideId, RideSetSetting::Music, activateMusic);
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MUSIC;
}
}
@ -4860,8 +4870,21 @@ static_assert(std::size(RatingNames) == 6);
void MusicResize()
{
flags |= WF_RESIZABLE;
WindowSetResize(*this, 316, 81, 316, 81);
if (auto ride = GetRide(rideId); ride != nullptr)
{
// Expand the window when music is playing
auto isMusicActivated = (ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC) != 0;
if (isMusicActivated)
{
WindowSetResize(*this, 316, 207, 500, 450);
}
else
{
height = 81;
width = 316;
WindowSetResize(*this, 316, 81, 500, 450);
}
}
}
static std::string GetMusicString(ObjectEntryIndex musicObjectIndex)
@ -4965,6 +4988,92 @@ static_assert(std::size(RatingNames) == 6);
frame_no++;
OnPrepareDraw();
WidgetInvalidate(*this, WIDX_TAB_6);
if (auto ride = GetRide(rideId); ride != nullptr && ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_MUSIC)
{
ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_MUSIC;
Invalidate();
OnResize();
OnPrepareDraw();
Invalidate();
}
WidgetScrollUpdateThumbs(*this, WIDX_MUSIC_DATA);
}
ScreenSize MusicScrollGetSize(int32_t scrollIndex)
{
OnPrepareDraw();
ScreenSize size{};
// Set minimum size
size.height = widgets[WIDX_MUSIC_DATA].height() - 2;
size.width = widgets[WIDX_MUSIC_DATA].width() - 2;
auto ride = GetRide(rideId);
if (ride != nullptr)
{
auto musicObj = ride->GetMusicObject();
if (musicObj != nullptr)
{
// scroll width (based on characters in longest row)
int32_t newWidth = 0;
for (size_t i = 0; i < musicObj->GetTrackCount(); i++)
{
const auto* track = musicObj->GetTrack(i);
if (track->Name.empty())
continue;
int32_t rowLength = static_cast<int32_t>(track->Name.size() + track->Composer.size());
if (rowLength > newWidth)
{
newWidth = rowLength;
}
}
newWidth = newWidth * (SCROLLABLE_ROW_HEIGHT - 6) + 10;
auto left = newWidth - widgets[WIDX_MUSIC_DATA].right + widgets[WIDX_MUSIC_DATA].left + 13;
if (left < 0)
{
scrolls[0].flags &= ~HSCROLLBAR_VISIBLE;
left = 0;
}
else
{
scrolls[0].flags |= HSCROLLBAR_VISIBLE;
}
if (left < scrolls[0].h_left)
{
scrolls[0].h_left = left;
Invalidate();
}
// scroll height (based on number of rows)
const auto newHeight = static_cast<int32_t>(musicObj->GetTrackCount() * SCROLLABLE_ROW_HEIGHT);
auto top = newHeight - widgets[WIDX_MUSIC_DATA].bottom + widgets[WIDX_MUSIC_DATA].top + 13;
if (top < 0)
{
top = 0;
scrolls[0].flags &= ~VSCROLLBAR_VISIBLE;
}
else
{
scrolls[0].flags |= VSCROLLBAR_VISIBLE;
}
if (top < scrolls[0].v_top)
{
scrolls[0].v_top = top;
Invalidate();
}
size = { newWidth, newHeight };
}
}
return size;
}
void MusicOnPrepareDraw()
@ -4987,27 +5096,68 @@ static_assert(std::size(RatingNames) == 6);
// Set selected music
StringId musicName = STR_NONE;
auto& objManager = GetContext()->GetObjectManager();
auto musicObj = static_cast<MusicObject*>(objManager.GetLoadedObject(ObjectType::Music, ride->music));
auto musicObj = ride->GetMusicObject();
if (musicObj != nullptr)
{
musicName = musicObj->NameStringId;
}
widgets[WIDX_MUSIC].text = musicName;
// Set music activated
auto isMusicActivated = (ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC) != 0;
if (isMusicActivated)
{
// resize widgets
widgets[WIDX_MUSIC_DATA].bottom = height - 32;
bool hasPreview = musicObj->HasPreview();
if (hasPreview)
{
WidgetSetVisible(*this, WIDX_MUSIC_IMAGE, true);
widgets[WIDX_MUSIC_DATA].right = width - 129;
widgets[WIDX_MUSIC_IMAGE].left = width - 121;
widgets[WIDX_MUSIC_IMAGE].right = width - 8;
}
else
{
widgets[WIDX_MUSIC_DATA].right = width - 8;
WidgetSetVisible(*this, WIDX_MUSIC_IMAGE, false);
}
// enable window resize
flags |= WF_RESIZABLE;
widgets[WIDX_MUSIC].right = widgets[WIDX_MUSIC_DATA].right;
widgets[WIDX_MUSIC_DROPDOWN].right = widgets[WIDX_MUSIC_DATA].right - 1;
widgets[WIDX_MUSIC_DROPDOWN].left = widgets[WIDX_MUSIC_DATA].right - 11;
pressed_widgets |= (1uLL << WIDX_PLAY_MUSIC);
pressed_widgets |= (1uLL << WIDX_MUSIC_IMAGE);
disabled_widgets &= ~(1uLL << WIDX_MUSIC);
disabled_widgets &= ~(1uLL << WIDX_MUSIC_DROPDOWN);
disabled_widgets |= (1uLL << WIDX_MUSIC_IMAGE);
disabled_widgets &= ~(1uLL << WIDX_MUSIC_DATA);
WidgetSetVisible(*this, WIDX_MUSIC_DATA, true);
}
else
{
// hide widgets not applicable
WidgetSetVisible(*this, WIDX_MUSIC_IMAGE, false);
WidgetSetVisible(*this, WIDX_MUSIC_DATA, false);
// disable resizing
flags &= ~WF_RESIZABLE;
widgets[WIDX_MUSIC].right = width - 8;
widgets[WIDX_MUSIC_DROPDOWN].right = width - 9;
widgets[WIDX_MUSIC_DROPDOWN].left = width - 19;
pressed_widgets &= ~(1uLL << WIDX_PLAY_MUSIC);
pressed_widgets |= (1uLL << WIDX_MUSIC_IMAGE);
disabled_widgets |= (1uLL << WIDX_MUSIC);
disabled_widgets |= (1uLL << WIDX_MUSIC_DROPDOWN);
disabled_widgets |= (1uLL << WIDX_MUSIC_IMAGE);
disabled_widgets |= (1uLL << WIDX_MUSIC_DATA);
}
AnchorBorderWidgets();
@ -5018,6 +5168,111 @@ static_assert(std::size(RatingNames) == 6);
{
DrawWidgets(dpi);
DrawTabImages(dpi);
auto ride = GetRide(rideId);
if (ride == nullptr)
return;
// draw music data only when music is activated
auto isMusicActivated = (ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC) != 0;
if (isMusicActivated)
{
auto screenPos = windowPos
+ ScreenCoordsXY{ widgets[WIDX_PAGE_BACKGROUND].left, widgets[WIDX_PAGE_BACKGROUND].top + 1 };
screenPos.y += DrawTextWrapped(
dpi, screenPos + ScreenCoordsXY{ widgets[WIDX_MUSIC_DATA].left, 33 }, width,
STR_MUSIC_OBJECT_TRACK_HEADER)
+ 2;
auto musicObj = ride->GetMusicObject();
bool hasPreview = musicObj->HasPreview();
if (hasPreview)
{
const auto& previewWidget = widgets[WIDX_MUSIC_IMAGE];
int32_t _width = previewWidget.width() - 1;
int32_t _height = previewWidget.height() - 1;
// draw background rectangle for image preview
GfxFillRect(
dpi,
{ windowPos + ScreenCoordsXY{ previewWidget.left + 1, previewWidget.top + 1 },
windowPos + ScreenCoordsXY{ previewWidget.right - 1, previewWidget.bottom - 1 } },
ColourMapA[colours[1]].darkest);
// Draw preview image
DrawPixelInfo clipDPI;
screenPos = windowPos + ScreenCoordsXY{ previewWidget.left + 1, previewWidget.top + 1 };
if (ClipDrawPixelInfo(clipDPI, dpi, screenPos, _width, _height))
{
musicObj->DrawPreview(clipDPI, _width, _height);
}
}
// Draw object author (will be blank space if no author in file or a non JSON object)
{
auto ft = Formatter();
std::string authorsString;
for (size_t i = 0; i < musicObj->GetAuthors().size(); i++)
{
if (i > 0)
{
authorsString.append(", ");
}
authorsString.append(musicObj->GetAuthors()[i]);
}
ft.Add<StringId>(STR_STRING);
ft.Add<const char*>(authorsString.c_str());
screenPos = windowPos
+ ScreenCoordsXY{ widgets[WIDX_PAGE_BACKGROUND].left + 1, widgets[WIDX_PAGE_BACKGROUND].top + 1 };
DrawTextEllipsised(
dpi,
{ windowPos.x + widgets[WIDX_PAGE_BACKGROUND].left + widgets[WIDX_MUSIC_DATA].left,
screenPos.y + height - 72 },
widgets[WIDX_MUSIC_DATA].right - widgets[WIDX_MUSIC_DATA].left + 127, STR_WINDOW_COLOUR_2_STRINGID, ft,
{ TextAlignment::LEFT });
}
}
}
void MusicOnScrollDraw(DrawPixelInfo& dpi, int32_t scrollIndex)
{
GfxClear(dpi, ColourMapA[colours[1]].mid_light);
auto ride = GetRide(rideId);
if (ride == nullptr)
return;
// draw music data only when music is activated
auto isMusicActivated = (ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC) != 0;
if (isMusicActivated)
{
auto dpiCoords = ScreenCoordsXY{ dpi.x, dpi.y };
GfxFillRect(
dpi, { dpiCoords, dpiCoords + ScreenCoordsXY{ dpi.width, dpi.height } }, ColourMapA[colours[1]].mid_light);
auto musicObj = ride->GetMusicObject();
auto y = 0;
for (size_t i = 0; i < musicObj->GetTrackCount(); i++)
{
const auto* track = musicObj->GetTrack(i);
if (track->Name.empty())
continue;
auto stringId = track->Composer.empty() ? STR_MUSIC_OBJECT_TRACK_LIST_ITEM
: STR_MUSIC_OBJECT_TRACK_LIST_ITEM_WITH_COMPOSER;
auto ft = Formatter();
ft.Add<const char*>(track->Name.c_str());
ft.Add<const char*>(track->Composer.c_str());
DrawTextBasic(dpi, { 0, y }, stringId, ft);
y += SCROLLABLE_ROW_HEIGHT;
}
}
}
#pragma endregion

View File

@ -98,6 +98,11 @@ void MusicObject::DrawPreview(DrawPixelInfo& dpi, int32_t width, int32_t height)
DrawTextBasic(dpi, { x, y }, STR_WINDOW_NO_IMAGE, {}, { TextAlignment::CENTRE });
}
bool MusicObject::HasPreview() const
{
return _hasPreview;
}
void MusicObject::ReadJson(IReadObjectContext* context, json_t& root)
{
_originalStyleId = {};

View File

@ -60,6 +60,7 @@ public:
void Unload() override;
void DrawPreview(DrawPixelInfo& dpi, int32_t width, int32_t height) const override;
bool HasPreview() const;
std::optional<uint8_t> GetOriginalStyleId() const;
bool SupportsRideType(ride_type_t rideType);

View File

@ -812,6 +812,7 @@ enum
RIDE_INVALIDATE_RIDE_LIST = 1 << 3,
RIDE_INVALIDATE_RIDE_OPERATING = 1 << 4,
RIDE_INVALIDATE_RIDE_MAINTENANCE = 1 << 5,
RIDE_INVALIDATE_RIDE_MUSIC = 1 << 6,
};
enum