// // 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 *)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"); void *res; if (_shuttingDownTadsEventLoopThread) { XT_TRACE_0(@"(thread is cancelled on entry)"); res = 0; } else { XTBannerCreateParams *params = [XTBannerCreateParams new]; params.parent = parent; params.where = where; params.other = other; params.wintype = wintype; params.align = align; params.size = size; params.sizeUnits = sizeUnits; params.style = style; XT_COUNT_CALL_ON_VM_THREAD; [self performSelectorOnMainThread:@selector(mainThread_bannerCreate:) withObject:params waitUntilDone:YES]; res = params.bannerHandle; } return res; } - (void)tagBannerReconfigure:(void *)handle align:(NSUInteger)align sizeToContents:(BOOL)sizeToContents sizeAsPrevious:(BOOL)sizeAsPrevious size:(NSUInteger)size sizeUnits:(NSUInteger)sizeUnits style:(NSUInteger)style { XT_DEF_SELNAME; XTBannerTextHandler *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"); } } else if (sizeToContents) { //XT_WARN_0(@"tagBannerNeedsSizeToContent set to YES"); banner.tagBannerNeedsSizeToContent = YES; } else { banner.size = size; banner.sizeUnits = sizeUnits; } banner.style = style; } - (void *)bannerHandleForTagId:(NSString *)tagId { XT_DEF_SELNAME; void *handle = nil; if (tagId == nil || [tagId length] == 0) { XT_ERROR_0(@"tagId is nil or blank"); } else { XTBannerTextHandler *banner = [self.bannersByTagId valueForKey:tagId]; handle = (void *)banner.bannerIndex; } return handle; } - (XTBannerTextHandler *)bannerHandlerForHandle:(void *)handle { XTBannerTextHandler *banner = [self getBanner:handle]; return banner; } - (void)bannerDelete:(void *)banner_handle { //XT_DEF_SELNAME; if (_shuttingDownTadsEventLoopThread) { //XT_TRACE_0("_shuttingDownTadsEventLoopThread == YES, return"); return; } XTBannerTextHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { XT_COUNT_CALL_ON_VM_THREAD; [self performSelectorOnMainThread:@selector(mainThread_bannerDelete:) withObject:banner waitUntilDone:YES]; } } - (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; XTBannerTextHandler *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 if (_shuttingDownTadsEventLoopThread) { return res; } NSArray *usableSizes = [self childThread_getUsableSizes:banner]; NSNumber *usableHeightInRows = usableSizes[0]; info->rows = usableHeightInRows.intValue; NSNumber *usableWidthInColumns = usableSizes[1]; info->columns = usableWidthInColumns.intValue; NSNumber *usableHeightInPoints = usableSizes[2]; info->pix_height = usableHeightInPoints.intValue; NSNumber *usableWidthInPoints = usableSizes[3]; info->pix_width = usableWidthInPoints.intValue; info->os_line_wrap = 1; return res; } - (NSUInteger)bannerWidthInChars:(void *)banner_handle { NSUInteger res = 0; if (_shuttingDownTadsEventLoopThread) { return res; } XTBannerTextHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { if (banner.type & OS_BANNER_TYPE_TEXTGRID) { NSArray *usableSizes = [self childThread_getUsableSizes:banner]; NSNumber *usableWidthInColumns = usableSizes[1]; res = usableWidthInColumns.intValue; } } return res; } - (NSUInteger)bannerHeightInChars:(void *)banner_handle { NSUInteger res = 0; if (_shuttingDownTadsEventLoopThread) { return res; } XTBannerTextHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { if (banner.type & OS_BANNER_TYPE_TEXTGRID) { NSArray *usableSizes = [self childThread_getUsableSizes:banner]; NSNumber *usableHeightInRows = usableSizes[0]; res = usableHeightInRows.intValue; } } return res; } - (NSArray *)childThread_getUsableSizes:(XTBannerTextHandler *)banner { NSMutableArray *results = [NSMutableArray arrayWithCapacity:4]; XT_COUNT_CALL_ON_VM_THREAD; [banner performSelectorOnMainThread:@selector(mainThread_getUsableSizes:) withObject:results waitUntilDone:YES]; return results; } - (void)bannerDisplay:(void *)banner_handle text:(NSString *)string { XT_DEF_SELNAME; XT_TRACE_1(@"\"%@\"", string); if (_shuttingDownTadsEventLoopThread) { return; } XTBannerTextHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { [banner display:string]; } } - (void)bannerDisplayTradStatusLineScoreString:(void *)banner_handle text:(NSString *)string { if (_shuttingDownTadsEventLoopThread) { return; } XTBannerTextHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { [banner displayTradStatusLineScoreString:string]; } } - (void)bannerFlush:(void *)banner_handle { if (_shuttingDownTadsEventLoopThread) { return; } XTBannerTextHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { XT_COUNT_CALL_ON_VM_THREAD; [banner performSelectorOnMainThread:@selector(mainThread_flush) withObject:nil waitUntilDone:YES]; } } - (void)bannerSetHtmlMode:(void *)banner_handle on:(BOOL)on { if (_shuttingDownTadsEventLoopThread) { return; } XTBannerTextHandler *banner = [self getBanner:banner_handle]; banner.htmlMode = on; } - (void)bannerClear:(void *)banner_handle { XT_DEF_SELNAME; XT_TRACE_0(@""); if (_shuttingDownTadsEventLoopThread) { return; } XTBannerTextHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { XT_COUNT_CALL_ON_VM_THREAD; [banner performSelectorOnMainThread:@selector(mainThread_clear) withObject:nil waitUntilDone:YES]; } } - (void)bannerSetSize:(void *)banner_handle size:(NSUInteger)size sizeUnits:(NSUInteger)sizUnits isAdvisory:(BOOL)isAdvisory { if (_shuttingDownTadsEventLoopThread) { return; } XTBannerTextHandler *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]]; XT_COUNT_CALL_ON_VM_THREAD; [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; } XTBannerTextHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { CGFloat oldSizeOfContents = banner.sizeOfContents; NSUInteger oldSize = banner.size; NSUInteger oldSizeUnits = banner.sizeUnits; XT_COUNT_CALL_ON_VM_THREAD; [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; } XTBannerTextHandler *banner = [self getBanner:banner_handle]; if (banner != nil) { [banner gotoRow:row column:column]; } } //--------------- - (XTBannerTextHandler *)getBanner:(void *)handle { XT_DEF_SELNAME; NSNumber *handleObj = [NSNumber numberWithUnsignedInteger:(NSUInteger)handle]; XTBannerTextHandler *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; } XTBannerTextHandler *mainAreaBanner = [self getBanner:0]; [mainAreaBanner traceWithIndentLevel:0]; } - (void)layoutAllBannerViews { XT_DEF_SELNAME; if (_shuttingDownTadsEventLoopThread) { return; } if ([NSThread isMainThread]) { XT_WARN_0(@"should not be called on main thread"); int brkpt = 1; } XT_COUNT_CALL_ON_VM_THREAD; [self performSelectorOnMainThread:@selector(mainThread_layoutAllBannerViews) withObject:nil waitUntilDone:YES]; }