From 2619a97a74eb1b758263b7eca6e3968e9b05888b Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Wed, 15 Dec 2021 12:38:21 +0200 Subject: macOS: Newlines in native menus Other formatting besides line breaks is ignored for now, although attributed strings could be used here. --- src/gmdocument.c | 6 +++--- src/gmutil.h | 6 ++++++ src/macos.m | 44 ++++++++++++++++++++++++++++++++++++-------- src/ui/text.c | 6 +++++- src/ui/text.h | 4 ++++ 5 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/gmdocument.c b/src/gmdocument.c index 56b2f06d..bec89ca0 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c @@ -1899,9 +1899,9 @@ void setUrl_GmDocument(iGmDocument *d, const iString *url) { } } -static int replaceRegExp_String(iString *d, const iRegExp *regexp, const char *replacement, - void (*matchHandler)(void *, const iRegExpMatch *), - void *context) { +int replaceRegExp_String(iString *d, const iRegExp *regexp, const char *replacement, + void (*matchHandler)(void *, const iRegExpMatch *), + void *context) { iRegExpMatch m; iString result; int numMatches = 0; diff --git a/src/gmutil.h b/src/gmutil.h index 35a7ee0d..6d337eeb 100644 --- a/src/gmutil.h +++ b/src/gmutil.h @@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ iDeclareType(GmError) iDeclareType(RegExp) +iDeclareType(RegExpMatch) iDeclareType(Url) /* Response status codes. */ @@ -145,3 +146,8 @@ const iString * findContainerArchive_Path (const iString *path); const iString * feedEntryOpenCommand_String (const iString *url, int newTab); /* checks fragment */ + +/* TODO: Consider adding this to the_Foundation. */ +int replaceRegExp_String (iString *, const iRegExp *regexp, const char *replacement, + void (*matchHandler)(void *, const iRegExpMatch *), + void *context); diff --git a/src/macos.m b/src/macos.m index cfbca488..5fd76bb9 100644 --- a/src/macos.m +++ b/src/macos.m @@ -110,7 +110,7 @@ static void ignoreImmediateKeyDownEvents_(void) { - (id)initWithIdentifier:(NSTouchBarItemIdentifier)identifier title:(NSString *)title command:(NSString *)cmd { - [super initWithIdentifier:identifier]; + self = [super initWithIdentifier:identifier]; self.view = [NSButton buttonWithTitle:title target:self action:@selector(buttonPressed)]; command = cmd; return self; @@ -120,7 +120,7 @@ static void ignoreImmediateKeyDownEvents_(void) { image:(NSImage *)image widget:(iWidget *)widget command:(NSString *)cmd { - [super initWithIdentifier:identifier]; + self = [super initWithIdentifier:identifier]; self.view = [NSButton buttonWithImage:image target:self action:@selector(buttonPressed)]; command = cmd; return self; @@ -163,12 +163,13 @@ static void ignoreImmediateKeyDownEvents_(void) { @implementation MenuCommands - (id)init { + self = [super init]; commands = [[NSMutableDictionary alloc] init]; source = NULL; return self; } -- (void)setCommand:(NSString *)command forMenuItem:(NSMenuItem *)menuItem { +- (void)setCommand:(NSString * __nonnull)command forMenuItem:(NSMenuItem * __nonnull)menuItem { [commands setObject:command forKey:[menuItem title]]; } @@ -220,7 +221,7 @@ static void ignoreImmediateKeyDownEvents_(void) { @implementation MyDelegate - (id)initWithSDLDelegate:(NSObject *)sdl { - [super init]; + self = [super init]; currentAppearanceName = nil; menuCommands = [[MenuCommands alloc] init]; touchBarVariant = default_TouchBarVariant; @@ -541,6 +542,29 @@ enum iColorId removeColorEscapes_String(iString *d) { return color; } +static NSString *cleanString_(const iString *ansiEscapedText) { + iString mod; + initCopy_String(&mod, ansiEscapedText); + iRegExp *ansi = makeAnsiEscapePattern_Text(); + replaceRegExp_String(&mod, ansi, "", NULL, NULL); + iRelease(ansi); + NSString *clean = [NSString stringWithUTF8String:cstr_String(&mod)]; + deinit_String(&mod); + return clean; +} + +#if 0 +static NSAttributedString *makeAttributedString_(const iString *ansiEscapedText) { + iString mod; + initCopy_String(&mod, ansiEscapedText); + NSData *data = [NSData dataWithBytesNoCopy:data_Block(&mod.chars) length:size_String(&mod)]; + NSAttributedString *as = [[NSAttributedString alloc] initWithHTML:data + documentAttributes:nil]; + deinit_String(&mod); + return as; +} +#endif + /* returns the selected item, if any */ static NSMenuItem *makeMenuItems_(NSMenu *menu, MenuCommands *commands, const iMenuItem *items, size_t n) { NSMenuItem *selectedItem = nil; @@ -557,7 +581,7 @@ static NSMenuItem *makeMenuItems_(NSMenu *menu, MenuCommands *commands, const iM isChecked = iTrue; label += 3; } - else if (startsWith_CStr(label, "///")) { + else if (startsWith_CStr(label, "///") || startsWith_CStr(label, "```")) { isDisabled = iTrue; label += 3; } @@ -567,9 +591,13 @@ static NSMenuItem *makeMenuItems_(NSMenu *menu, MenuCommands *commands, const iM if (removeColorEscapes_String(&itemTitle) == uiTextCaution_ColorId) { // prependCStr_String(&itemTitle, "\u26a0\ufe0f "); } - NSMenuItem *item = [menu addItemWithTitle:[NSString stringWithUTF8String:cstr_String(&itemTitle)] - action:(hasCommand ? @selector(postMenuItemCommand:) : nil) - keyEquivalent:@""]; + NSMenuItem *item = [[NSMenuItem alloc] init]; + /* Use attributed string to allow newlines. */ + NSAttributedString *title = [[NSAttributedString alloc] initWithString:cleanString_(&itemTitle)]; + item.attributedTitle = title; + [title release]; + item.action = (hasCommand ? @selector(postMenuItemCommand:) : nil); + [menu addItem:item]; deinit_String(&itemTitle); [item setTarget:commands]; if (isChecked) { diff --git a/src/ui/text.c b/src/ui/text.c index 7367e6c0..f3d945e4 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -390,12 +390,16 @@ static void deinitCache_Text_(iText *d) { SDL_DestroyTexture(d->cache); } +iRegExp *makeAnsiEscapePattern_Text(void) { + return new_RegExp("[[()][?]?([0-9;AB]*?)([ABCDEFGHJKSTfhilmn])", 0); +} + void init_Text(iText *d, SDL_Renderer *render) { iText *oldActive = activeText_; activeText_ = d; init_Array(&d->fonts, sizeof(iFont)); d->contentFontSize = contentScale_Text_; - d->ansiEscape = new_RegExp("[[()][?]?([0-9;AB]*?)([ABCDEFGHJKSTfhilmn])", 0); + d->ansiEscape = makeAnsiEscapePattern_Text(); d->baseFontId = -1; d->baseFgColorId = -1; d->missingGlyphs = iFalse; diff --git a/src/ui/text.h b/src/ui/text.h index b7934855..cb29adad 100644 --- a/src/ui/text.h +++ b/src/ui/text.h @@ -29,6 +29,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "fontpack.h" +iDeclareType(RegExp) + /* Content sizes: regular (1x) -> medium (1.2x) -> big (1.33x) -> large (1.67x) -> huge (2x) */ #define FONT_ID(name, style, size) ((name) + ((style) * max_FontSize) + (size)) @@ -230,6 +232,8 @@ enum iTextBlockMode { quadrants_TextBlockMode, shading_TextBlockMode }; iString * renderBlockChars_Text (const iBlock *fontData, int height, enum iTextBlockMode, const iString *text); +iRegExp * makeAnsiEscapePattern_Text (void); + /*-----------------------------------------------------------------------------------------------*/ iDeclareType(TextBuf) -- cgit v1.2.3