mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2026-04-27 13:55:05 -06:00
688 lines
21 KiB
Plaintext
Executable File
688 lines
21 KiB
Plaintext
Executable File
#import <UIKit/UIKit.h>
|
|
#import "game/sdl/ios/chatview.h"
|
|
#import "game/sdl/ios/chatcell.h"
|
|
#import "game/sdl/ios/iphone.h"
|
|
|
|
@implementation ChatView
|
|
|
|
#define TEXTFIELDWIDTH_LANDSCAPE self.bounds.size.width - 81
|
|
// #define TEXTFIELDWIDTH_PORTRAIT 238
|
|
|
|
#define TEXTFIELDHEIGHT_LANDSCAPE 24
|
|
// #define TEXTFIELDHEIGHT_PORTRAIT 29
|
|
|
|
#define TEXTFIELDFONTSIZE_LANDSCAPE 16
|
|
// #define TEXTFIELDFONTSIZE_PORTRAIT 20
|
|
|
|
#define TITLELABELWIDTH_LANDSCAPE 100
|
|
|
|
#define CHAT_HISTORY 100
|
|
#define CHAT_QUEUE 100
|
|
|
|
#define DEVICE_OS [[[UIDevice currentDevice] systemVersion] intValue]
|
|
|
|
- (id)init {
|
|
if (!(self == [super init])) {
|
|
return nil;
|
|
}
|
|
tableView_ = nil;
|
|
toolbar_ = nil;
|
|
textField_ = nil;
|
|
chatQueue_ = [[NSMutableArray alloc] initWithCapacity:CHAT_QUEUE];
|
|
suspended_ = NO;
|
|
chatEntries_ = [[NSMutableArray alloc] initWithCapacity:CHAT_HISTORY];
|
|
entryFont_ = [UIFont systemFontOfSize:12];
|
|
CGSize size10Spaces = [@" " sizeWithFont:entryFont_];
|
|
width10Spaces_ = size10Spaces.width;
|
|
chatc_ = NULL;
|
|
title_ = @"Chat";
|
|
titleLabel_ = nil;
|
|
toolbar2_ = nil;
|
|
clear_ = YES;
|
|
|
|
[self loadView];
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
}
|
|
|
|
- (void)registerNotifications
|
|
{
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(keyboardShown:)
|
|
name:UIKeyboardDidShowNotification
|
|
object:nil];
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(keyboardHidden:)
|
|
name:UIKeyboardDidHideNotification
|
|
object:nil];
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(keyboardWillChangeFrame:)
|
|
name:UIKeyboardWillChangeFrameNotification
|
|
object:nil];
|
|
}
|
|
|
|
- (void)loadView
|
|
{
|
|
// Create parent view that subviews go into
|
|
CGRect frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
|
|
[self setFrame:frame];
|
|
self.autoresizesSubviews = YES;
|
|
self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
|
|
|
|
// Create toolbar, add to parent
|
|
|
|
toolbar_ = [[UIToolbar alloc] initWithFrame:CGRectZero];
|
|
toolbar_.autoresizingMask = UIViewAutoresizingFlexibleTopMargin |
|
|
UIViewAutoresizingFlexibleWidth;
|
|
toolbar_.autoresizesSubviews = YES;
|
|
toolbar_.backgroundColor = [UIColor darkGrayColor];
|
|
[self addSubview: toolbar_];
|
|
|
|
// Create text field - will be added to toolbar in layout because
|
|
// it is the only way the size custom toolbar views
|
|
|
|
textField_ = [[UITextField alloc] initWithFrame:CGRectZero];
|
|
textField_.borderStyle = UITextBorderStyleRoundedRect;
|
|
textField_.textColor = [UIColor blackColor];
|
|
textField_.placeholder = @"";
|
|
textField_.autocorrectionType = UITextAutocorrectionTypeDefault;
|
|
textField_.keyboardType = UIKeyboardTypeDefault;
|
|
textField_.returnKeyType = UIReturnKeySend;
|
|
textField_.clearButtonMode = UITextFieldViewModeWhileEditing;
|
|
textField_.delegate = self;
|
|
|
|
// toolbar2 is the navigation header
|
|
|
|
toolbar2_ = [[UIToolbar alloc] initWithFrame:CGRectZero];
|
|
toolbar2_.autoresizingMask = UIViewAutoresizingFlexibleTopMargin |
|
|
UIViewAutoresizingFlexibleWidth;
|
|
toolbar2_.autoresizesSubviews = YES;
|
|
toolbar2_.backgroundColor = [UIColor darkGrayColor];
|
|
[self addSubview: toolbar2_];
|
|
|
|
// titleLabel that will be added to toolbar2 later
|
|
|
|
titleLabel_ = [[UILabel alloc] initWithFrame:CGRectZero];
|
|
titleLabel_.font = [UIFont boldSystemFontOfSize:18];
|
|
titleLabel_.textAlignment = NSTextAlignmentCenter;
|
|
titleLabel_.textColor = [UIColor whiteColor];
|
|
titleLabel_.backgroundColor = [UIColor clearColor];
|
|
//titleLabel_.shadowColor = [UIColor darkGrayColor];
|
|
titleLabel_.opaque = NO;
|
|
titleLabel_.text = title_;
|
|
|
|
// Layout views. Repositions and resizes appropriately.
|
|
|
|
[self layoutViews];
|
|
[self registerNotifications];
|
|
}
|
|
|
|
- (void)reCreateTableView {
|
|
[tableView_ removeFromSuperview];
|
|
tableView_ = nil;
|
|
|
|
// Create tableview and add to parent
|
|
|
|
tableView_ = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
|
tableView_.delegate = self;
|
|
tableView_.dataSource = self;
|
|
tableView_.autoresizesSubviews = YES;
|
|
tableView_.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
|
|
tableView_.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
[self layoutTableView];
|
|
[self addSubview: tableView_];
|
|
}
|
|
|
|
- (void)layoutTableView {
|
|
CGRect rcToolbar = toolbar_.frame;
|
|
CGRect rcToolbar2 = toolbar2_.frame;
|
|
CGRect rcTableView = tableView_.frame;
|
|
rcTableView.origin.y = rcToolbar2.size.height;
|
|
rcTableView.size.height = rcToolbar.origin.y - rcTableView.origin.y;
|
|
rcTableView.size.width = rcToolbar.size.width;
|
|
tableView_.frame = rcTableView;
|
|
}
|
|
|
|
- (void)layoutViews
|
|
{
|
|
// Resize the textField appropriately. Note the toolbar is a different
|
|
// height in portrait vs. landscape. Also note, custom view button
|
|
// bar items can only be resized by re-added them to the toolbar.
|
|
|
|
CGRect rcTextField = textField_.frame;
|
|
rcTextField.size.height = TEXTFIELDHEIGHT_LANDSCAPE;
|
|
rcTextField.size.width = TEXTFIELDWIDTH_LANDSCAPE;
|
|
textField_.font = [UIFont systemFontOfSize: TEXTFIELDFONTSIZE_LANDSCAPE];
|
|
textField_.frame = rcTextField;
|
|
|
|
UIBarButtonItem *textFieldButton = [[UIBarButtonItem alloc]
|
|
initWithCustomView:textField_];
|
|
UIBarButtonItem *sendButton = [[UIBarButtonItem alloc]
|
|
initWithTitle:@"Send" style:UIBarButtonItemStyleBordered
|
|
target:self action:@selector(onSend)];
|
|
NSArray *array = [NSArray arrayWithObjects: textFieldButton, sendButton,
|
|
(char *)NULL];
|
|
[toolbar_ setItems:nil];
|
|
[toolbar_ setItems:array animated:NO];
|
|
[toolbar_ sizeToFit];
|
|
|
|
// The toolbar is taller when in portrait mode, so other things
|
|
// need to be layed out.
|
|
|
|
int cyToolbar = rcTextField.size.height + 8;
|
|
|
|
CGRect rcToolbar = toolbar_.frame;
|
|
CGRect rcParent = self.bounds;
|
|
rcToolbar.size.height = cyToolbar;
|
|
rcToolbar.origin.y = rcParent.size.height - rcToolbar.size.height;
|
|
toolbar_.frame = rcToolbar;
|
|
|
|
// Size the label width
|
|
[titleLabel_ sizeToFit];
|
|
CGRect frame = titleLabel_.frame;
|
|
frame.size.width = TITLELABELWIDTH_LANDSCAPE;
|
|
titleLabel_.frame = frame;
|
|
|
|
// Toolbar2 goes at the top
|
|
UIBarButtonItem *playersButton = [[UIBarButtonItem alloc]
|
|
initWithTitle:@"Players"
|
|
style:UIBarButtonItemStyleDone
|
|
target:self action:@selector(onPlayers)];
|
|
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc]
|
|
initWithTitle:@"Done"
|
|
style:UIBarButtonItemStyleDone
|
|
target:self action:@selector(onDone)];
|
|
keyboardButton_ = [[UIBarButtonItem alloc]
|
|
initWithTitle:@"Keyboard"
|
|
style:UIBarButtonItemStyleDone
|
|
target:self action:@selector(onKeyboard)];
|
|
[keyboardButton_ setEnabled:NO];
|
|
UIBarButtonItem *titleItem = [[UIBarButtonItem alloc]
|
|
initWithCustomView:titleLabel_];
|
|
UIBarButtonItem *sizingItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
|
|
array = [NSArray arrayWithObjects: doneButton, sizingItem, titleItem, sizingItem,
|
|
keyboardButton_, playersButton, (char *)NULL];
|
|
[toolbar2_ setItems:nil];
|
|
[toolbar2_ setItems:array animated:NO];
|
|
[toolbar2_ sizeToFit];
|
|
|
|
// Toolbar2 goes at the top
|
|
|
|
CGRect rcToolbar2 = toolbar2_.frame;
|
|
rcToolbar2.origin.y = 0;
|
|
rcToolbar2.size.height = cyToolbar;
|
|
toolbar2_.frame = rcToolbar2;
|
|
|
|
// TableView
|
|
//[self layoutTableView];
|
|
}
|
|
|
|
- (void)onSend {
|
|
if (chatc_ == NULL) {
|
|
return;
|
|
}
|
|
|
|
// For some currently unknown reason, sometimes there are leading zeros
|
|
// in this UITextField text. Remove them, and remove whitespace.
|
|
|
|
NSString *text = textField_.text;
|
|
int count = text.length;
|
|
int index = 0;
|
|
for (; index < count; index++) {
|
|
unichar ch = [text characterAtIndex:index];
|
|
if (ch != 0) {
|
|
break;
|
|
}
|
|
}
|
|
text = [[text substringFromIndex:index] stringByTrimmingCharactersInSet:
|
|
[NSCharacterSet whitespaceCharacterSet]];
|
|
|
|
if (text.length != 0) {
|
|
NSData *data = [text
|
|
dataUsingEncoding:[NSString defaultCStringEncoding]
|
|
allowLossyConversion:YES];
|
|
std::string s((const char *)[data bytes], [data length]);
|
|
wi::ChatParams *params = new wi::ChatParams(s);
|
|
chatc_->thread().Post(kidmOnSend, chatc_, params);
|
|
}
|
|
textField_.text = nil;
|
|
}
|
|
|
|
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
|
[self onSend];
|
|
return NO;
|
|
}
|
|
|
|
- (void)scrollToBottom {
|
|
[tableView_ beginUpdates];
|
|
|
|
// Scroll to the bottom
|
|
int index = [chatEntries_ count] - 1;
|
|
if (index >= 0) {
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index
|
|
inSection:0];
|
|
[tableView_ scrollToRowAtIndexPath:indexPath
|
|
atScrollPosition:UITableViewScrollPositionBottom
|
|
animated:NO];
|
|
}
|
|
|
|
[tableView_ endUpdates];
|
|
}
|
|
|
|
- (void)onPlayers
|
|
{
|
|
if (chatc_ != NULL) {
|
|
chatc_->thread().Post(kidmOnPlayers, chatc_);
|
|
}
|
|
}
|
|
|
|
- (void)show {
|
|
BOOL created = NO;
|
|
if (clear_ || tableView_ == nil) {
|
|
// Put queued up chat into the model
|
|
suspended_ = NO;
|
|
[self updateChatModel];
|
|
|
|
// Create the table view. It will automagically reload the model
|
|
[self reCreateTableView];
|
|
clear_ = NO;
|
|
created = YES;
|
|
}
|
|
|
|
[IPhone presentView:self];
|
|
[tableView_ setSeparatorStyle:UITableViewCellSeparatorStyleNone];
|
|
|
|
[textField_ becomeFirstResponder];
|
|
|
|
// Only scroll to the bottom if the table view existed already.
|
|
// Otherwise it will crash, because data model loading is
|
|
// asynchronous.
|
|
if (created == NO) {
|
|
[self scrollToBottom];
|
|
}
|
|
}
|
|
|
|
- (void)onDone
|
|
{
|
|
[textField_ resignFirstResponder];
|
|
[self removeFromSuperview];
|
|
|
|
if (chatc_ != NULL) {
|
|
chatc_->thread().Post(kidmOnDismissed, chatc_);
|
|
}
|
|
}
|
|
|
|
- (void)onKeyboard
|
|
{
|
|
[keyboardButton_ setEnabled:NO];
|
|
if (textField_.isFirstResponder) {
|
|
[textField_ resignFirstResponder];
|
|
} else {
|
|
[textField_ becomeFirstResponder];
|
|
}
|
|
|
|
}
|
|
|
|
- (void)keyboardShown:(NSNotification *)notification {
|
|
if (!self.superview) {
|
|
return;
|
|
}
|
|
[self scrollToBottom];
|
|
[keyboardButton_ setEnabled:YES];
|
|
}
|
|
|
|
- (void)keyboardHidden:(NSNotification *)notification {
|
|
if (!self.superview) {
|
|
return;
|
|
}
|
|
[self scrollToBottom];
|
|
[keyboardButton_ setEnabled:YES];
|
|
}
|
|
|
|
- (void)keyboardWillChangeFrame:(NSNotification *)notification {
|
|
NSDictionary *info = [notification userInfo];
|
|
CGRect keyboardFrameEnd = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
|
// Move the toolbar
|
|
CGRect rcToolbar = [toolbar_ frame];
|
|
if (DEVICE_OS <= 7) {
|
|
// Don't ask... you dont even want to know about this calculation...
|
|
// The keyboardFrameEnd rect is based on portrait, but self.frame and its subviews' frames
|
|
// are landscape. So calculating there toolbar_ should be based on keyboardFrameEnd is a pain.
|
|
// Lets hope we don't ever need to modify/maintain this <= iOS 7 code.
|
|
if ([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationLandscapeRight) {
|
|
// Strangely enough, this seems to fire when my device is physically in landscapeLeft mode
|
|
rcToolbar.origin.y = keyboardFrameEnd.origin.x - toolbar_.frame.size.height;
|
|
}
|
|
if ([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationLandscapeLeft) {
|
|
// Strangely enough, this seems to fire when my device is physically in landscapeRight mode
|
|
rcToolbar.origin.y = self.frame.size.height - keyboardFrameEnd.origin.x - keyboardFrameEnd.size.width - toolbar_.frame.size.height;
|
|
}
|
|
} else { // DEVICE_OS <= 8
|
|
rcToolbar.origin.y = keyboardFrameEnd.origin.y - rcToolbar.size.height;
|
|
}
|
|
[toolbar_ setFrame:rcToolbar];
|
|
[self bringSubviewToFront:toolbar_];
|
|
|
|
// Resize the table view
|
|
[self layoutTableView];
|
|
}
|
|
|
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
|
return 1;
|
|
}
|
|
|
|
- (NSInteger)tableView:(UITableView *)tableView
|
|
numberOfRowsInSection:(NSInteger)section {
|
|
return [chatEntries_ count];
|
|
}
|
|
|
|
- (void)initializeChatCell:(int)rowIndex cell:(ChatCell *)cell
|
|
{
|
|
CGSize size;
|
|
size.width = self.bounds.size.width;
|
|
size.height = [self getRowHeight:rowIndex forWidth:size.width];
|
|
|
|
NSMutableDictionary *entry = (NSMutableDictionary *)
|
|
[chatEntries_ objectAtIndex:rowIndex];
|
|
if (entry == nil) {
|
|
[cell setup:@"error" user:@"error" size:size];
|
|
return;
|
|
}
|
|
NSString *user = [entry objectForKey:@"user"];
|
|
NSString *chat = [entry objectForKey:@"chat"];
|
|
[cell setup:chat user:user size:size];
|
|
}
|
|
|
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
|
|
(NSIndexPath *)indexPath {
|
|
ChatCell *cell = (ChatCell *)[tableView_ dequeueReusableCellWithIdentifier:@"chatcell"];
|
|
if (cell == nil) {
|
|
cell = [[ChatCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"chatcell"];
|
|
}
|
|
[self initializeChatCell:indexPath.row cell:cell];
|
|
return cell;
|
|
}
|
|
|
|
- (CGFloat)tableView:(UITableView *)tableView
|
|
heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
NSMutableDictionary *entry = (NSMutableDictionary *)
|
|
[chatEntries_ objectAtIndex:indexPath.row];
|
|
if (entry == nil) {
|
|
return 0;
|
|
}
|
|
return [self getRowHeight:indexPath.row forWidth:self.bounds.size.width];
|
|
}
|
|
|
|
- (NSArray *)updateChatModel {
|
|
NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:10];
|
|
while ([chatQueue_ count] != 0) {
|
|
NSDictionary *dict = (NSDictionary *)[chatQueue_ objectAtIndex:0];
|
|
NSString *chat = [dict objectForKey:@"chat"];
|
|
NSString *user = [dict objectForKey:@"player"];
|
|
|
|
if ([user length] == 0) {
|
|
// System message.
|
|
NSMutableDictionary *entry = [NSMutableDictionary
|
|
dictionaryWithObjectsAndKeys: @"", @"user",
|
|
chat, @"chat", (char *)NULL];
|
|
[chatEntries_ addObject:entry];
|
|
} else {
|
|
// Regular chat message. Add ':' to the end of user
|
|
NSString *newUser = [NSString stringWithFormat:@"%@:", user];
|
|
|
|
// Insert spaces into chat so that user's name can draw into that
|
|
// space with a different UILabel. Hack-o-rama.
|
|
|
|
CGSize sizeUser = [newUser sizeWithFont:entryFont_];
|
|
CGFloat ratio = sizeUser.width / width10Spaces_;
|
|
int countSpaces = ceil(ratio * 10.0) + 2;
|
|
|
|
char szSpaces[256];
|
|
if (countSpaces > sizeof(szSpaces)) {
|
|
countSpaces = sizeof(szSpaces);
|
|
}
|
|
memset(szSpaces, ' ', sizeof(szSpaces));
|
|
szSpaces[countSpaces - 1] = 0;
|
|
NSString *newChat = [NSString stringWithFormat:@"%s%@", szSpaces,
|
|
chat];
|
|
NSMutableDictionary *entry = [NSMutableDictionary
|
|
dictionaryWithObjectsAndKeys: newUser, @"user",
|
|
newChat, @"chat", (char *)NULL];
|
|
[chatEntries_ addObject:entry];
|
|
}
|
|
[chatQueue_ removeObjectAtIndex:0];
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:
|
|
[chatEntries_ count] - 1 inSection:0];
|
|
[indexPaths addObject:indexPath];
|
|
}
|
|
return indexPaths;
|
|
}
|
|
|
|
- (void)updateChatRows {
|
|
if (suspended_ == YES) {
|
|
return;
|
|
}
|
|
NSArray *indexPaths = [self updateChatModel];
|
|
if ([indexPaths count] != 0) {
|
|
[tableView_ beginUpdates];
|
|
[tableView_ insertRowsAtIndexPaths:indexPaths
|
|
withRowAnimation:UITableViewRowAnimationBottom];
|
|
[tableView_ endUpdates];
|
|
}
|
|
}
|
|
|
|
- (void)suspendUpdates:(BOOL)suspend {
|
|
if (suspend == suspended_) {
|
|
return;
|
|
}
|
|
if (suspended_ == NO & suspend == YES) {
|
|
suspended_ = suspend;
|
|
return;
|
|
}
|
|
if (suspended_ == YES && suspend == NO) {
|
|
suspended_ = suspend;
|
|
[self updateChatRows];
|
|
}
|
|
}
|
|
|
|
- (int)getRowHeight:(int)rowIndex forWidth:(int)width
|
|
{
|
|
NSMutableDictionary *entry = (NSMutableDictionary *)
|
|
[chatEntries_ objectAtIndex:rowIndex];
|
|
if (entry == nil) {
|
|
return 0;
|
|
}
|
|
|
|
// See if the height is cached; if so return it
|
|
NSString *key = [NSString stringWithFormat:@"%d", width];
|
|
NSString *value = [entry objectForKey:key];
|
|
if (value != nil) {
|
|
return [value intValue];
|
|
}
|
|
|
|
// Calculate what the height is, cache it, return it
|
|
NSString *chat = (NSString *)[entry objectForKey:@"chat"];
|
|
|
|
CGSize sizeBox = CGSizeMake(width, 2800);
|
|
CGSize size = [chat sizeWithFont:entryFont_ constrainedToSize:sizeBox
|
|
lineBreakMode:NSLineBreakByWordWrapping];
|
|
value = [NSString stringWithFormat:@"%d", (int)ceilf(size.height)];
|
|
[entry setObject:value forKey:key];
|
|
return size.height;
|
|
}
|
|
|
|
- (void)doClear
|
|
{
|
|
[chatEntries_ removeAllObjects];
|
|
[chatQueue_ removeAllObjects];
|
|
|
|
// Clear occurs when switching between chat contexts (room, game, etc).
|
|
// It would be nice to be able to call reloadData here. Unfortunately,
|
|
// it causes "stuck chat cells" when the TableView isn't visible. As
|
|
// a hack workaround, destroy the tableView_ and re-created it when
|
|
// showing. During this period, queue up chat.
|
|
[tableView_ removeFromSuperview];
|
|
tableView_ = nil;
|
|
clear_ = YES;
|
|
[self suspendUpdates:YES];
|
|
}
|
|
|
|
- (void)doAddChat:(NSDictionary *)dict
|
|
{
|
|
[chatQueue_ addObject:dict];
|
|
[self updateChatRows];
|
|
[self scrollToBottom];
|
|
}
|
|
|
|
- (void)doShow
|
|
{
|
|
[self show];
|
|
titleLabel_.text = title_;
|
|
}
|
|
|
|
- (void)doHide
|
|
{
|
|
if ([self superview])
|
|
[self onDone];
|
|
}
|
|
|
|
- (void)doSetTitle:(NSString *)title
|
|
{
|
|
title_ = title;
|
|
}
|
|
|
|
- (void)setController:(wi::ChatController *)chatc
|
|
{
|
|
chatc_ = chatc;
|
|
}
|
|
|
|
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)way {
|
|
return UIInterfaceOrientationLandscapeRight;
|
|
}
|
|
|
|
// UIScrollViewDelegate
|
|
// Inserting items while scrolling causes UITableView to crash. Track
|
|
// when scrolling happens an cache inserts until scrolling stops.
|
|
|
|
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {
|
|
[self suspendUpdates:YES];
|
|
return YES;
|
|
}
|
|
|
|
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {
|
|
[self suspendUpdates:NO];
|
|
}
|
|
|
|
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
|
|
[self suspendUpdates:YES];
|
|
}
|
|
|
|
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
|
|
willDecelerate:(BOOL)decelerate {
|
|
if (decelerate == NO) {
|
|
[self suspendUpdates:NO];
|
|
}
|
|
}
|
|
|
|
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
|
|
[self suspendUpdates:NO];
|
|
}
|
|
|
|
- (void)setFrame:(CGRect)frame {
|
|
[super setFrame:frame];
|
|
[self layoutViews];
|
|
[self layoutTableView];
|
|
}
|
|
@end
|
|
|
|
// ++++
|
|
// This is the game thread callable class for controlling chat
|
|
|
|
namespace wi {
|
|
|
|
// These get called on the game thread, and do the real work on the main
|
|
// thread.
|
|
|
|
ChatController::ChatController(ChatView *vcchat) {
|
|
vcchat_ = vcchat;
|
|
[vcchat_ setController: this];
|
|
}
|
|
|
|
void ChatController::Clear() {
|
|
[vcchat_ performSelectorOnMainThread:@selector(doClear)
|
|
withObject:nil waitUntilDone: NO];
|
|
}
|
|
|
|
void ChatController::AddChat(const char *player, const char *chat) {
|
|
NSString *player_s = [NSString stringWithCString:player
|
|
encoding:[NSString defaultCStringEncoding]];
|
|
NSString *chat_s = [NSString stringWithCString:chat
|
|
encoding:[NSString defaultCStringEncoding]];
|
|
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
player_s, @"player", chat_s, @"chat", (char *)NULL];
|
|
[vcchat_ performSelectorOnMainThread:@selector(doAddChat:)
|
|
withObject:dict waitUntilDone: NO];
|
|
}
|
|
|
|
void ChatController::Show(bool fShow) {
|
|
if (fShow) {
|
|
[vcchat_ performSelectorOnMainThread:@selector(doShow) withObject:nil waitUntilDone: NO];
|
|
} else {
|
|
[vcchat_ performSelectorOnMainThread:@selector(doHide)
|
|
withObject:nil waitUntilDone: NO];
|
|
}
|
|
}
|
|
|
|
void ChatController::SetTitle(const char *title) {
|
|
title_ = title;
|
|
NSString *title_s = [NSString stringWithCString:title
|
|
encoding:[NSString defaultCStringEncoding]];
|
|
[vcchat_ performSelectorOnMainThread:@selector(doSetTitle:)
|
|
withObject:title_s waitUntilDone: NO];
|
|
}
|
|
|
|
const char *ChatController::GetTitle() {
|
|
return title_.c_str();
|
|
}
|
|
|
|
IChatControllerCallback *ChatController::SetCallback(
|
|
IChatControllerCallback *pcccb) {
|
|
IChatControllerCallback *old = pcccb_;
|
|
pcccb_ = pcccb;
|
|
return old;
|
|
}
|
|
|
|
void ChatController::OnMessage(base::Message *pmsg) {
|
|
switch (pmsg->id) {
|
|
case kidmOnDismissed:
|
|
if (pcccb_ != NULL) {
|
|
pcccb_->OnChatDismissed();
|
|
}
|
|
break;
|
|
|
|
case kidmOnSend:
|
|
if (pcccb_ != NULL) {
|
|
ChatParams *params = (ChatParams *)pmsg->data;
|
|
pcccb_->OnChatSend(params->chat.c_str());
|
|
delete params;
|
|
}
|
|
break;
|
|
|
|
case kidmOnPlayers:
|
|
if (pcccb_ != NULL) {
|
|
pcccb_->OnPlayers();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // namespace wi
|