mirror of
https://github.com/LNH-team/pico-launcher.git
synced 2026-06-02 00:56:55 +02:00
Add marquee for long cheat names
This commit is contained in:
@@ -28,24 +28,28 @@ int nft2_findGlyphIdxForCharacter(const nft2_header_t* font, u16 character)
|
||||
}
|
||||
|
||||
static inline void renderGlyph(const nft2_header_t* font, const nft2_glyph_t* glyph,
|
||||
int xPos, int yPos, int width, int height, u8* dst, u32 stride, bool a5i3)
|
||||
int xPos, int yPos, const nft2_string_render_params_t* renderParams, u8* dst, u32 stride, bool a5i3)
|
||||
{
|
||||
int yOffset = glyph->spacingTop;
|
||||
u32 xStart = xPos < 0 ? -xPos : 0;
|
||||
u32 yStart = yPos + yOffset < 0 ? -(yPos + yOffset) : 0;
|
||||
|
||||
int xEnd = glyph->glyphWidth;
|
||||
if (xPos + xEnd > width)
|
||||
if (xPos + xEnd > (int)renderParams->width)
|
||||
{
|
||||
if (renderParams->onlyRenderWholeGlyphs)
|
||||
{
|
||||
// by returning we only render complete glyphs
|
||||
return;
|
||||
// old code for rendering partial glyphs
|
||||
// xEnd = width - xPos;
|
||||
}
|
||||
|
||||
xEnd = renderParams->width - xPos;
|
||||
}
|
||||
|
||||
int yEnd = glyph->glyphHeight;
|
||||
if (yPos + yOffset + yEnd > height)
|
||||
yEnd = height - (yPos + yOffset); // allow partial glyphs in the vertical direction
|
||||
if (yPos + yOffset + yEnd > (int)renderParams->height)
|
||||
{
|
||||
yEnd = renderParams->height - (yPos + yOffset); // allow partial glyphs in the vertical direction
|
||||
}
|
||||
|
||||
const u8* glyphData = &font->glyphDataPtr[glyph->dataOffset];
|
||||
glyphData += yStart * ((glyph->glyphWidth + 1) >> 1);
|
||||
@@ -97,15 +101,15 @@ static inline void renderGlyph(const nft2_header_t* font, const nft2_glyph_t* gl
|
||||
}
|
||||
|
||||
static ITCM_CODE void renderGlyphTiled(const nft2_header_t* font, const nft2_glyph_t* glyph,
|
||||
int xPos, int yPos, int width, int height, u8* dst, u32 stride)
|
||||
int xPos, int yPos, const nft2_string_render_params_t* renderParams, u8* dst, u32 stride)
|
||||
{
|
||||
renderGlyph(font, glyph, xPos, yPos, width, height, dst, stride, false);
|
||||
renderGlyph(font, glyph, xPos, yPos, renderParams, dst, stride, false);
|
||||
}
|
||||
|
||||
static ITCM_CODE void renderGlyphA5I3(const nft2_header_t* font, const nft2_glyph_t* glyph,
|
||||
int xPos, int yPos, int width, int height, u8* dst, u32 stride)
|
||||
int xPos, int yPos, const nft2_string_render_params_t* renderParams, u8* dst, u32 stride)
|
||||
{
|
||||
renderGlyph(font, glyph, xPos, yPos, width, height, dst, stride, true);
|
||||
renderGlyph(font, glyph, xPos, yPos, renderParams, dst, stride, true);
|
||||
}
|
||||
|
||||
ITCM_CODE void nft2_renderString(const nft2_header_t* font, const char16_t* string, u8* dst, u32 stride,
|
||||
@@ -134,18 +138,18 @@ ITCM_CODE void nft2_renderString(const nft2_header_t* font, const char16_t* stri
|
||||
xPos += glyph->spacingLeft;
|
||||
if (a5i3)
|
||||
{
|
||||
renderGlyphA5I3(font, glyph, xPos, yPos, renderParams->width, renderParams->height, dst, stride);
|
||||
renderGlyphA5I3(font, glyph, xPos, yPos, renderParams, dst, stride);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderGlyphTiled(font, glyph, xPos, yPos, renderParams->width, renderParams->height, dst, stride);
|
||||
renderGlyphTiled(font, glyph, xPos, yPos, renderParams, dst, stride);
|
||||
}
|
||||
xPos += glyph->glyphWidth;
|
||||
if (xPos > (int)textWidth)
|
||||
textWidth = xPos;
|
||||
xPos += glyph->spacingRight;
|
||||
}
|
||||
renderParams->textWidth = textWidth;
|
||||
renderParams->textWidth = textWidth - renderParams->x;
|
||||
}
|
||||
|
||||
ITCM_CODE void nft2_measureString(const nft2_header_t* font, const char16_t* string, u32& width, u32& height)
|
||||
@@ -265,11 +269,11 @@ ITCM_CODE void nft2_renderStringEllipsis(const nft2_header_t* font, const char16
|
||||
xPos += glyph->spacingLeft;
|
||||
if (a5i3)
|
||||
{
|
||||
renderGlyphA5I3(font, glyph, xPos, yPos, renderParams->width, renderParams->height, dst, stride);
|
||||
renderGlyphA5I3(font, glyph, xPos, yPos, renderParams, dst, stride);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderGlyphTiled(font, glyph, xPos, yPos, renderParams->width, renderParams->height, dst, stride);
|
||||
renderGlyphTiled(font, glyph, xPos, yPos, renderParams, dst, stride);
|
||||
}
|
||||
xPos += glyph->glyphWidth;
|
||||
if (xPos > (int)textWidth)
|
||||
@@ -287,11 +291,11 @@ ITCM_CODE void nft2_renderStringEllipsis(const nft2_header_t* font, const char16
|
||||
xPos += glyph->spacingLeft;
|
||||
if (a5i3)
|
||||
{
|
||||
renderGlyphA5I3(font, glyph, xPos, yPos, renderParams->width, renderParams->height, dst, stride);
|
||||
renderGlyphA5I3(font, glyph, xPos, yPos, renderParams, dst, stride);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderGlyphTiled(font, glyph, xPos, yPos, renderParams->width, renderParams->height, dst, stride);
|
||||
renderGlyphTiled(font, glyph, xPos, yPos, renderParams, dst, stride);
|
||||
}
|
||||
xPos += glyph->glyphWidth;
|
||||
if (xPos > (int)textWidth)
|
||||
@@ -309,16 +313,16 @@ ITCM_CODE void nft2_renderStringEllipsis(const nft2_header_t* font, const char16
|
||||
xPos += glyph->spacingLeft;
|
||||
if (a5i3)
|
||||
{
|
||||
renderGlyphA5I3(font, glyph, xPos, yPos, renderParams->width, renderParams->height, dst, stride);
|
||||
renderGlyphA5I3(font, glyph, xPos, yPos, renderParams, dst, stride);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderGlyphTiled(font, glyph, xPos, yPos, renderParams->width, renderParams->height, dst, stride);
|
||||
renderGlyphTiled(font, glyph, xPos, yPos, renderParams, dst, stride);
|
||||
}
|
||||
xPos += glyph->glyphWidth;
|
||||
if (xPos > (int)textWidth)
|
||||
textWidth = xPos;
|
||||
xPos += glyph->spacingRight;
|
||||
}
|
||||
renderParams->textWidth = textWidth;
|
||||
renderParams->textWidth = textWidth - renderParams->x;
|
||||
}
|
||||
@@ -39,6 +39,7 @@ struct nft2_string_render_params_t
|
||||
u32 textWidth;
|
||||
// u32 textHeight;
|
||||
bool a5i3;
|
||||
bool onlyRenderWholeGlyphs = true;
|
||||
};
|
||||
|
||||
/// @brief Prepares the ntf2 data of the given \p font for runtime use.
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "gui/palette/GradientPalette.h"
|
||||
#include "LabelView.h"
|
||||
|
||||
#define MARQUEE_START_FRAMES 60
|
||||
#define MARQUEE_STEP_FRAMES 3
|
||||
#define MARQUEE_END_FRAMES 90
|
||||
|
||||
LabelView::LabelView(u32 width, u32 height, u32 maxStringLength, const nft2_header_t* font, bool a5i3)
|
||||
: _width(width), _height(height)
|
||||
, _maxStringLength(maxStringLength), _font(font)
|
||||
@@ -34,14 +38,30 @@ LabelView::LabelView(u32 width, u32 height, u32 maxStringLength, const nft2_head
|
||||
SetText(u"");
|
||||
}
|
||||
|
||||
void LabelView::Update()
|
||||
{
|
||||
if (_ellipsisStyleChanged)
|
||||
{
|
||||
RestartMarquee();
|
||||
UpdateTileBuffer();
|
||||
_ellipsisStyleChanged = false;
|
||||
}
|
||||
else if (_ellipsisStyle == EllipsisStyle::Marquee)
|
||||
{
|
||||
UpdateMarquee();
|
||||
}
|
||||
}
|
||||
|
||||
void LabelView::SetTextBuffer(const char* text)
|
||||
{
|
||||
StringUtil::Copy(_textBuffer.get(), text, _maxStringLength + 1);
|
||||
RestartMarquee();
|
||||
}
|
||||
|
||||
void LabelView::SetTextBuffer(const char16_t* text)
|
||||
{
|
||||
StringUtil::Copy(_textBuffer.get(), text, _maxStringLength + 1);
|
||||
RestartMarquee();
|
||||
}
|
||||
|
||||
void LabelView::SetTextBuffer(const char16_t* text, u32 length)
|
||||
@@ -50,6 +70,7 @@ void LabelView::SetTextBuffer(const char16_t* text, u32 length)
|
||||
if (copyLength > 0)
|
||||
memcpy(_textBuffer.get(), text, copyLength * 2);
|
||||
_textBuffer[copyLength] = 0;
|
||||
RestartMarquee();
|
||||
}
|
||||
|
||||
void LabelView::UpdateTileBuffer()
|
||||
@@ -63,10 +84,19 @@ void LabelView::UpdateTileBuffer()
|
||||
renderParams.width = _width;
|
||||
renderParams.height = _height;
|
||||
renderParams.a5i3 = _a5i3;
|
||||
if (_ellipsis)
|
||||
if (_ellipsisStyle == EllipsisStyle::Ellipsis)
|
||||
{
|
||||
nft2_renderStringEllipsis(_font, _textBuffer.get(), _tileBuffer.get(), _actualWidth, &renderParams, u" ... ");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_ellipsisStyle == EllipsisStyle::Marquee)
|
||||
{
|
||||
renderParams.x = -_marqueeOffset;
|
||||
renderParams.onlyRenderWholeGlyphs = false;
|
||||
}
|
||||
nft2_renderString(_font, _textBuffer.get(), _tileBuffer.get(), _actualWidth, &renderParams);
|
||||
}
|
||||
_newStringWidth = renderParams.textWidth;
|
||||
}
|
||||
else
|
||||
@@ -119,3 +149,54 @@ QueueTask<void> LabelView::SetTextAsync(TaskQueueBase* taskQueue, const char16_t
|
||||
SetTextBuffer(text, length);
|
||||
return UpdateTileBufferAsync(taskQueue);
|
||||
}
|
||||
|
||||
void LabelView::RestartMarquee()
|
||||
{
|
||||
_marqueeOffset = 0;
|
||||
_marqueeCounter = MARQUEE_START_FRAMES;
|
||||
_marqueeState = MarqueeState::StartWait;
|
||||
}
|
||||
|
||||
void LabelView::UpdateMarquee()
|
||||
{
|
||||
UpdateTileBuffer();
|
||||
if (_newStringWidth <= _width)
|
||||
{
|
||||
_marqueeOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (_marqueeState)
|
||||
{
|
||||
case MarqueeState::StartWait:
|
||||
{
|
||||
if (--_marqueeCounter <= 0)
|
||||
{
|
||||
_marqueeState = MarqueeState::Moving;
|
||||
_marqueeOffset = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MarqueeState::Moving:
|
||||
{
|
||||
_marqueeOffset++;
|
||||
if (_newStringWidth - _marqueeOffset < _width)
|
||||
{
|
||||
_marqueeState = MarqueeState::EndWait;
|
||||
_marqueeCounter = MARQUEE_END_FRAMES;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MarqueeState::EndWait:
|
||||
{
|
||||
if (--_marqueeCounter <= 0)
|
||||
{
|
||||
_marqueeState = MarqueeState::StartWait;
|
||||
_marqueeCounter = MARQUEE_START_FRAMES;
|
||||
_marqueeOffset = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,15 @@ class MaterialGraphicsContext;
|
||||
class LabelView : public View
|
||||
{
|
||||
public:
|
||||
enum class EllipsisStyle
|
||||
{
|
||||
None,
|
||||
Ellipsis,
|
||||
Marquee
|
||||
};
|
||||
|
||||
void Update() override;
|
||||
|
||||
void SetText(const char* text);
|
||||
void SetText(const char16_t* text);
|
||||
void SetText(const char16_t* text, u32 length);
|
||||
@@ -43,7 +52,14 @@ public:
|
||||
return Rectangle(_position, _width, _height);
|
||||
}
|
||||
|
||||
void SetEllipsis(bool ellipsis) { _ellipsis = ellipsis; }
|
||||
void SetEllipsisStyle(EllipsisStyle ellipsisStyle)
|
||||
{
|
||||
if (_ellipsisStyle != ellipsisStyle)
|
||||
{
|
||||
_ellipsisStyle = ellipsisStyle;
|
||||
_ellipsisStyleChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
u32 _width;
|
||||
@@ -61,14 +77,30 @@ protected:
|
||||
Rgb<8, 8, 8> _backgroundColor;
|
||||
Rgb<8, 8, 8> _foregroundColor;
|
||||
int _paletteRow = -1;
|
||||
bool _ellipsis = false;
|
||||
EllipsisStyle _ellipsisStyle = EllipsisStyle::None;
|
||||
bool _a5i3;
|
||||
|
||||
LabelView(u32 width, u32 height, u32 maxStringLength, const nft2_header_t* font, bool a5i3);
|
||||
|
||||
void SetTextBuffer(const char* text);
|
||||
void SetTextBuffer(const char16_t* text);
|
||||
void SetTextBuffer(const char16_t* text, u32 length);
|
||||
virtual void UpdateTileBuffer();
|
||||
QueueTask<void> UpdateTileBufferAsync(TaskQueueBase* taskQueue);
|
||||
|
||||
LabelView(u32 width, u32 height, u32 maxStringLength, const nft2_header_t* font, bool a5i3);
|
||||
private:
|
||||
enum class MarqueeState
|
||||
{
|
||||
StartWait,
|
||||
Moving,
|
||||
EndWait
|
||||
};
|
||||
|
||||
MarqueeState _marqueeState = MarqueeState::StartWait;
|
||||
int _marqueeOffset = 0;
|
||||
int _marqueeCounter = 0;
|
||||
bool _ellipsisStyleChanged = false;
|
||||
|
||||
void RestartMarquee();
|
||||
void UpdateMarquee();
|
||||
};
|
||||
@@ -22,7 +22,7 @@ MaterialFileInfoCardView::MaterialFileInfoCardView(const MaterialColorScheme* ma
|
||||
AddChildTail(&_firstLine);
|
||||
AddChildTail(&_secondLine);
|
||||
AddChildTail(&_thirdLine);
|
||||
_filenameLabelView.SetEllipsis(true);
|
||||
_filenameLabelView.SetEllipsisStyle(LabelView::EllipsisStyle::Ellipsis);
|
||||
AddChildTail(&_filenameLabelView);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
|
||||
void SetFirstLineAsync(TaskQueueBase* taskQueue, const char* firstLine, bool ellipsis) override
|
||||
{
|
||||
_firstLine.SetEllipsis(ellipsis);
|
||||
_firstLine.SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None);
|
||||
if (taskQueue)
|
||||
_firstLine.SetTextAsync(taskQueue, firstLine);
|
||||
else
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
|
||||
void SetFirstLineAsync(TaskQueueBase* taskQueue, const char16_t* firstLine, u32 length, bool ellipsis) override
|
||||
{
|
||||
_firstLine.SetEllipsis(ellipsis);
|
||||
_firstLine.SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None);
|
||||
if (taskQueue)
|
||||
_firstLine.SetTextAsync(taskQueue, firstLine, length);
|
||||
else
|
||||
|
||||
@@ -14,7 +14,7 @@ CustomFileInfoView::CustomFileInfoView(const IFontRepository* fontRepository)
|
||||
AddChildTail(&_firstLine);
|
||||
AddChildTail(&_secondLine);
|
||||
AddChildTail(&_thirdLine);
|
||||
_filenameLabelView.SetEllipsis(true);
|
||||
_filenameLabelView.SetEllipsisStyle(LabelView::EllipsisStyle::Ellipsis);
|
||||
AddChildTail(&_filenameLabelView);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
|
||||
void SetFirstLineAsync(TaskQueueBase* taskQueue, const char* firstLine, bool ellipsis) override
|
||||
{
|
||||
_firstLine.SetEllipsis(ellipsis);
|
||||
_firstLine.SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None);
|
||||
if (taskQueue)
|
||||
_firstLine.SetTextAsync(taskQueue, firstLine);
|
||||
else
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
|
||||
void SetFirstLineAsync(TaskQueueBase* taskQueue, const char16_t* firstLine, u32 length, bool ellipsis) override
|
||||
{
|
||||
_firstLine.SetEllipsis(ellipsis);
|
||||
_firstLine.SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None);
|
||||
if (taskQueue)
|
||||
_firstLine.SetTextAsync(taskQueue, firstLine, length);
|
||||
else
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
|
||||
void SetFirstLineAsync(TaskQueueBase* taskQueue, const char* firstLine, bool ellipsis) override
|
||||
{
|
||||
_firstLine->SetEllipsis(ellipsis);
|
||||
_firstLine->SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None);
|
||||
if (taskQueue)
|
||||
_firstLine->SetTextAsync(taskQueue, firstLine);
|
||||
else
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
|
||||
void SetFirstLineAsync(TaskQueueBase* taskQueue, const char16_t* firstLine, u32 length, bool ellipsis) override
|
||||
{
|
||||
_firstLine->SetEllipsis(ellipsis);
|
||||
_firstLine->SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None);
|
||||
if (taskQueue)
|
||||
_firstLine->SetTextAsync(taskQueue, firstLine, length);
|
||||
else
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
|
||||
CheatListItemView::CheatListItemView(const VramOffsets& vramOffsets,
|
||||
const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository)
|
||||
: _nameLabel(200, 16, 64, fontRepository->GetFont(FontType::Regular10))
|
||||
: _nameLabel(196, 16, 256, fontRepository->GetFont(FontType::Regular10))
|
||||
, _vramOffsets(vramOffsets)
|
||||
, _materialColorScheme(materialColorScheme)
|
||||
{
|
||||
_nameLabel.SetEllipsis(true);
|
||||
_nameLabel.SetEllipsisStyle(LabelView::EllipsisStyle::Ellipsis);
|
||||
AddChildTail(&_nameLabel);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,14 @@ void CheatListItemView::Update()
|
||||
? _vramOffsets.checkboxCheckedIconVramOffset
|
||||
: _vramOffsets.checkboxUncheckedIconVramOffset;
|
||||
}
|
||||
if (IsFocused())
|
||||
{
|
||||
_nameLabel.SetEllipsisStyle(LabelView::EllipsisStyle::Marquee);
|
||||
}
|
||||
else
|
||||
{
|
||||
_nameLabel.SetEllipsisStyle(LabelView::EllipsisStyle::Ellipsis);
|
||||
}
|
||||
ViewContainer::Update();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user