// // XTGameWindowController_vmThreadBannerApi.m // XTads // // Created by Rune Berg on 15/12/15. // Copyright © 2015 Rune Berg. All rights reserved. // // // IMPORTANT NOTE: This is not a standalone .m file, and so should // *not* be member of any build targets. Instead, it's #included by // XTGameWindowController.m proper. // - (void)createRootBanner { XT_DEF_SELNAME; XT_TRACE_0(@"ENTER"); XTBannerHandler *banner = [XTBannerHandler handlerForMainOutputArea]; banner.gameWindowController = self; if (banner.bannerIndex != 0) { XT_ERROR_1(@"banner.bannerIndex should be 0, was %lu", banner.bannerIndex); } NSUInteger handle = banner.bannerIndex; NSNumber *handleObj = [NSNumber numberWithUnsignedInteger:handle]; [self.bannersByHandle setObject:banner forKey:handleObj]; [self traceBannerHierarchy]; [banner performSelectorOnMainThread:@selector(mainThread_createTextViewForMainOutputArea) withObject:nil waitUntilDone:YES]; banner.rootBannerContainerView = self.gameOutputContainerView; self.outputTextView = banner.outputTextView; self.outputTextScrollView = banner.scrollView; [self layoutAllBannerViews]; } /*TODO rm - (void)removeRootBanner { [self performSelectorOnMainThread:@selector(mainThread_removeMain...) withObject:nil waitUntilDone:YES]; rm main view etc. ... ... }*/ - (void *)bannerCreate:(void *)parent where:(NSInteger)where other:(void *)other wintype:(NSInteger)wintype align:(NSInteger)align size:(NSInteger)size sizeUnits:(NSInteger)sizeUnits style:(NSUInteger)style { XT_DEF_SELNAME; XT_TRACE_0(@"ENTER"); if (_shuttingDownTadsEventLoopThread) { XT_TRACE_0(@"(thread is cancelled on entry)"); return (void *)0; } XTBannerHandler *parentBanner = [self getBanner:parent]; XTBannerHandler *otherBanner = nil; if (other != nil) { otherBanner = [self getBanner:other]; } XTBannerHandler *banner = [XTBannerHandler handlerWithParent:parentBanner where:where other:otherBanner wintype:wintype align:align size:size sizeUnits:sizeUnits style:style]; [banner setIsForT3:self.gameIsT3]; banner.isBeingCreated = YES; NSUInteger handle = banner.bannerIndex; NSNumber *handleObj = [NSNumber numberWithUnsignedInteger:handle]; [self.bannersByHandle setObject:banner forKey:handleObj]; [self traceBannerHierarchy]; XT_TRACE_1(@" %lu", handle); if (_shuttingDownTadsEventLoopThread) { return (void *)handle; } [banner performSelectorOnMainThread:@selector(mainThread_createTextViewForBanner) withObject:nil waitUntilDone:YES]; [self layoutAllBannerViews]; return (void *)handle; } - (void *)bannerCreate:(void *)parent tagId:(NSString *)tagId where:(NSInteger)where other:(void *)other wintype:(NSInteger)wintype //TODO unsigned align:(NSInteger)align //TODO unsigned size:(NSInteger)size //TODO unsigned sizeUnits:(NSInteger)sizeUnits //TODO unsigned style:(NSUInteger)style { XT_DEF_SELNAME; void *handle = nil; if ([self handleForTagId:tagId] == nil) { handle = [self bannerCreate:parent where:where other:other wintype:wintype align:align size:size sizeUnits:sizeUnits style:style]; if (handle != nil) { XTBannerHandler *banner = [self getBanner:handle]; banner.tagId = tagId; [self.bannersByTagId setObject:banner forKey:tagId]; } } else { XT_ERROR_1(@"banner with tagId %@ already exists", tagId); } return handle; } //TODO ren tagBanner... only used for T2 / - (void)bannerReconfigure:(void *)handle align:(NSUInteger)align sizeToContents:(BOOL)sizeToContents sizeAsPrevious:(BOOL)sizeAsPrevious size:(NSUInteger)size sizeUnits:(NSUInteger)sizeUnits style:(NSUInteger)style { XT_DEF_SELNAME; XTBannerHandler *banner = [self getBanner:handle]; BOOL wasSizedToContent = banner.isSizedToContent; banner.isSizedToContent = NO; banner.tagBannerNeedsSizeToContent = NO; banner.alignment = align; if (sizeAsPrevious) { //TODO this logic (and the state it uses) is probably much more complicated than it needs to be :-( if (banner.initialSize != nil) { if (banner.hadUnspecifiedSizeLastTime && banner.wasInitiallySizedToPrevious) { // Keep current size banner.isSizedToContent = YES; //XT_WARN_0(@"hadUnspecifiedSizeLastTime && wasInitiallySizedToPrevious --> no change"); int brkpt = 1; } else if (banner.hadPreviousSizeLastTime && banner.wasInitiallySizedToPrevious) { // Keep current size banner.isSizedToContent = wasSizedToContent; //XT_WARN_0(@"hadPreviousSizeLastTime && wasInitiallySizedToPrevious --> no change"); int brkpt = 1; } else { if (banner.wasInitiallySizedToPrevious) { // Keep current size int brkpt = 1; } else if (banner.wasInitiallySizedToContents) { banner.size = [banner.initialSize unsignedIntegerValue]; banner.sizeOfContents = banner.initialSizeOfContents; banner.isSizedToContent = YES; banner.sizeUnits = banner.initialSizeUnits; } else if (banner.initialSizeUnits == OS_BANNER_SIZE_ABS) { banner.size = (NSUInteger)[banner.initialSize doubleValue]; banner.sizeUnits = banner.initialSizeUnits; } else { banner.size = [banner.initialSize unsignedIntegerValue]; banner.sizeUnits = banner.initialSizeUnits; } } } else { XT_ERROR_0(@"sizeAsPrevious && banner.initialSize == nil"); int brkpt = 1; } } else if (sizeToContents) { //XT_WARN_0(@"tagBannerNeedsSizeToContent set to YES"); banner.tagBannerNeedsSizeToContent = YES; } else { banner.size = size; banner.sizeUnits = sizeUnits; } banner.style = style; } //TODO ren bannerHandleForTagId - (void *)handleForTagId:(NSString *)tagId { XT_DEF_SELNAME; void *handle = nil; if (tagId == nil || [tagId length] == 0) { XT_ERROR_0(@"tagId is nil or blank"); } else { XTBannerHandler *banner = [self.bannersByTagId valueForKey:tagId]; handle = (void *)banner.bannerIndex; } return handle; } - (XTBannerHandler *)bannerHandlerForHandle:(void *)handle { XTBannerHandler *banner = [self getBanner:handle]; return banner; } - (void)bannerDelete:(void *)banner_handle { XT_DEF_SELNAME; NSUInteger bhUint = (NSUInteger)banner_handle; //XT_TRACE_1(@"%lu", bhUint); if (_shuttingDownTadsEventLoopThread) { //XT_TRACE_0("_shuttingDownTadsEventLoopThread == YES, return"); return; } XTBannerHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { [banner performSelectorOnMainThread:@selector(mainThread_removeHandler) withObject:nil waitUntilDone:YES]; NSNumber *handleObj = [NSNumber numberWithUnsignedInteger:(NSUInteger)banner_handle]; [self.bannersByHandle removeObjectForKey:handleObj]; // ...but not children - it's up to the caller to do that if (banner.tagId != nil) { [self.bannersByTagId removeObjectForKey:banner.tagId]; } if (bhUint == [self.bannerHandleForTradStatusLine unsignedIntegerValue]) { self.bannerHandleForTradStatusLine = nil; } [self layoutAllBannerViews]; } } - (void)bannerDeleteAll { NSArray * allKeys = [self.bannersByHandle allKeys]; for (NSNumber *handleObj in allKeys) { NSUInteger bannerIndex = handleObj.unsignedIntegerValue; if (bannerIndex >= 1) { void *bannerHandle = (void *)bannerIndex; [self bannerDelete:bannerHandle]; } } } - (void)bannerOrphan:(void *)banner_handle { XT_DEF_SELNAME; XT_TRACE_1(@"%lu", (NSUInteger)banner_handle); // Do nothing - leave the screen as is } - (BOOL)bannerInfo:(void *)banner_handle info:(os_banner_info_t *)info { BOOL res = NO; XTBannerHandler *banner = [self getBanner:banner_handle]; if (banner == nil) { return res; } res = YES; info->align = (int)banner.alignment; info->style = banner.style; info->style |= OS_BANNER_STYLE_TAB_ALIGN; // because MJR's terp and QTads behave that way info->rows = (int)[banner usableHeightInRows]; info->columns = (int)[banner usableWidthInColumns]; info->pix_width = (int)[banner usableWidthInPoints]; info->pix_height = (int)[banner usableHeightInPoints]; info->os_line_wrap = 1; //NSUInteger w = [self bannerWidthInChars:banner_handle]; //NSUInteger h = [self bannerHeightInChars:banner_handle]; return res; } - (NSUInteger)bannerWidthInChars:(void *)banner_handle { NSUInteger res = 0; if (_shuttingDownTadsEventLoopThread) { return res; } XTBannerHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { if (banner.type & OS_BANNER_TYPE_TEXTGRID) { res = [banner usableWidthInColumns]; } } return res; } - (NSUInteger)bannerHeightInChars:(void *)banner_handle { NSUInteger res = 0; if (_shuttingDownTadsEventLoopThread) { return res; } XTBannerHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { if (banner.type & OS_BANNER_TYPE_TEXTGRID) { res = [banner usableHeightInRows]; } } return res; } - (void)bannerDisplay:(void *)banner_handle text:(NSString *)string { XT_DEF_SELNAME; XT_TRACE_1(@"\"%@\"", string); if (_shuttingDownTadsEventLoopThread) { return; } XTBannerHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { [banner display:string]; } } - (void)bannerDisplayTradStatusLineScoreString:(void *)banner_handle text:(NSString *)string { if (_shuttingDownTadsEventLoopThread) { return; } self.tradStatusLineScoreString = string; XTBannerHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { [banner displayTradStatusLineScoreString:self.tradStatusLineScoreString]; } } - (void)bannerFlush:(void *)banner_handle { if (_shuttingDownTadsEventLoopThread) { return; } XTBannerHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { [banner performSelectorOnMainThread:@selector(mainThread_flush) withObject:nil waitUntilDone:YES]; } } - (void)bannerSetHtmlMode:(void *)banner_handle on:(BOOL)on { if (_shuttingDownTadsEventLoopThread) { return; } XTBannerHandler *banner = [self getBanner:banner_handle]; banner.htmlMode = on; } - (void)bannerClear:(void *)banner_handle { XT_DEF_SELNAME; XT_TRACE_0(@""); if (_shuttingDownTadsEventLoopThread) { return; } XTBannerHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { [banner clear]; } } - (void)bannerSetSize:(void *)banner_handle size:(NSUInteger)size sizeUnits:(NSUInteger)sizUnits isAdvisory:(BOOL)isAdvisory { if (_shuttingDownTadsEventLoopThread) { return; } XTBannerHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { //TODO to avoid flicker, skip if isAdvisory==YES or size/sizUnits unchanged if (isAdvisory || ((size == banner.size) && (sizUnits == banner.sizeUnits))) { return; } NSArray *args = @[[NSNumber numberWithUnsignedInteger:size], [NSNumber numberWithUnsignedInteger:sizUnits], [NSNumber numberWithBool:isAdvisory]]; [banner performSelectorOnMainThread:@selector(mainThread_setSize:) withObject:args waitUntilDone:YES]; [self layoutAllBannerViews]; } } - (void)bannerSizeToContentsNoLayout:(void *)banner_handle { [self bannerSizeToContents:banner_handle doLayout:NO]; } - (void)bannerSizeToContents:(void *)banner_handle { [self bannerSizeToContents:banner_handle doLayout:YES]; } - (void)bannerSizeToContents:(void *)banner_handle doLayout:(BOOL)doLayout { XT_DEF_SELNAME; XT_TRACE_1(@"banner_handle=%ld", banner_handle); if (_shuttingDownTadsEventLoopThread) { return; } XTBannerHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { CGFloat oldSizeOfContents = banner.sizeOfContents; NSUInteger oldSize = banner.size; NSUInteger oldSizeUnits = banner.sizeUnits; [banner performSelectorOnMainThread:@selector(mainThread_sizeToContents) withObject:nil waitUntilDone:YES]; if (doLayout) { BOOL sizeHasChanged = ((banner.sizeOfContents != oldSizeOfContents) || (banner.size != oldSize) || (banner.sizeUnits != oldSizeUnits)); if (sizeHasChanged) { [self layoutAllBannerViews]; } } } } - (void)bannerGoto:(void *)banner_handle row:(NSUInteger)row column:(NSUInteger)column { if (_shuttingDownTadsEventLoopThread) { return; } XTBannerHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { [banner gotoRow:row column:column]; } } //--------------- - (XTBannerHandler *)getBanner:(void *)handle { XT_DEF_SELNAME; NSNumber *handleObj = [NSNumber numberWithUnsignedInteger:(NSUInteger)handle]; XTBannerHandler *banner = [self.bannersByHandle objectForKey:handleObj]; if (banner == nil) { XT_WARN_1(@"No banner with handle %lu", (NSUInteger)handle); } return banner; } - (void)traceBannerHierarchy { if (! XT_TRACE_ON) { return; } XTBannerHandler *mainAreaBanner = [self getBanner:0]; [mainAreaBanner traceWithIndentLevel:0]; } - (void)layoutAllBannerViews { if (_shuttingDownTadsEventLoopThread) { return; } [self.outputTextHandler performSelectorOnMainThread:@selector(mainThread_noteStartOfLayoutOfViews) withObject:nil waitUntilDone:YES]; if (_shuttingDownTadsEventLoopThread) { return; } XTBannerHandler *rootBanner = [self getBanner:0]; [rootBanner performSelectorOnMainThread:@selector(mainThread_configureViews) withObject:nil waitUntilDone:YES]; //[self.outputTextHandler noteStartOfPagination]; //TODO exp rm'd (contributes to broken pagination) if (_shuttingDownTadsEventLoopThread) { return; } [self.outputTextHandler performSelectorOnMainThread:@selector(mainThread_noteEndOfLayoutOfViews) withObject:nil waitUntilDone:YES]; }