# HG changeset patch # User koda # Date 1286640053 -7200 # Node ID 5ca27a0e9a636e852a432fd4b5f7d49a2369031c # Parent 1a873262f5ddb097ebf8b60c95bc20dc6901f460 made the new menu toggable diff -r 1a873262f5dd -r 5ca27a0e9a63 hedgewars/CCHandlers.inc --- a/hedgewars/CCHandlers.inc Sat Oct 09 05:57:46 2010 +0200 +++ b/hedgewars/CCHandlers.inc Sat Oct 09 18:00:53 2010 +0200 @@ -458,6 +458,7 @@ {$IFDEF DEBUGFILE} AddFileLog('Doing SwitchHedgehog: time '+inttostr(GameTicks)); {$ENDIF} + perfExt_NewTurnBeginning(); end; procedure chSay(var s: shortstring); diff -r 1a873262f5dd -r 5ca27a0e9a63 hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Sat Oct 09 05:57:46 2010 +0200 +++ b/hedgewars/hwengine.pas Sat Oct 09 18:00:53 2010 +0200 @@ -285,7 +285,7 @@ else begin LoadRecordFromFile(recordFileName); - doSomethingWhen_SaveBeganSynching(); + perfExt_SaveBeganSynching(); end; ScriptOnGameInit; diff -r 1a873262f5dd -r 5ca27a0e9a63 hedgewars/uAmmos.pas --- a/hedgewars/uAmmos.pas Sat Oct 09 05:57:46 2010 +0200 +++ b/hedgewars/uAmmos.pas Sat Oct 09 18:00:53 2010 +0200 @@ -47,7 +47,7 @@ var shoppa: boolean; implementation -uses uMisc, uGears, uWorld, uLocale, uConsole; +uses uMisc, uGears, uWorld, uLocale, uConsole, uMobile; type TAmmoCounts = array[TAmmoType] of Longword; var StoresList: array[0..Pred(cMaxHHs)] of PHHAmmo; @@ -246,7 +246,8 @@ SwitchNotHeldAmmo(Hedgehog) end end - end + end; +perfExt_NewTurnBeginning; end; function HHHasAmmo(var Hedgehog: THedgehog; Ammo: TAmmoType): boolean; @@ -354,7 +355,8 @@ else ShowCrosshair:= (Propz and ammoprop_NoCrosshair) = 0; end - end + end; +perfExt_NewTurnBeginning; end; procedure SwitchNotHeldAmmo(var Hedgehog: THedgehog); diff -r 1a873262f5dd -r 5ca27a0e9a63 hedgewars/uConsole.pas --- a/hedgewars/uConsole.pas Sat Oct 09 05:57:46 2010 +0200 +++ b/hedgewars/uConsole.pas Sat Oct 09 18:00:53 2010 +0200 @@ -37,7 +37,7 @@ procedure doPut(putX, putY: LongInt; fromAI: boolean); implementation -uses uMisc, uStore, Types, uConsts, uGears, uTeams, uIO, uKeys, uWorld, +uses uMisc, uStore, Types, uConsts, uGears, uTeams, uIO, uKeys, uWorld, uMobile, uRandom, uAmmos, uStats, uChat, SDLh, uSound, uVisualGears, uScript; const cLineWidth: LongInt = 0; diff -r 1a873262f5dd -r 5ca27a0e9a63 hedgewars/uGame.pas --- a/hedgewars/uGame.pas Sat Oct 09 05:57:46 2010 +0200 +++ b/hedgewars/uGame.pas Sat Oct 09 18:00:53 2010 +0200 @@ -68,7 +68,7 @@ if isSoundEnabled then playMusic; GameType:= gmtLocal; InitIPC; - doSomethingWhen_SaveFinishedSynching(); + perfExt_SaveFinishedSynching(); end; end else ProcessGears diff -r 1a873262f5dd -r 5ca27a0e9a63 hedgewars/uMobile.pas --- a/hedgewars/uMobile.pas Sat Oct 09 05:57:46 2010 +0200 +++ b/hedgewars/uMobile.pas Sat Oct 09 18:00:53 2010 +0200 @@ -33,11 +33,12 @@ {$ENDIF} function isPhone: Boolean; procedure doRumble; -procedure doSomethingWhen_AddProgress; -procedure doSomethingWhen_FinishProgress; -procedure doSomethingWhen_NewTurnBeginning; -procedure doSomethingWhen_SaveBeganSynching; -procedure doSomethingWhen_SaveFinishedSynching; +procedure perfExt_AddProgress; +procedure perfExt_FinishProgress; +procedure perfExt_AmmoUpdate; +procedure perfExt_NewTurnBeginning; +procedure perfExt_SaveBeganSynching; +procedure perfExt_SaveFinishedSynching; implementation @@ -54,21 +55,28 @@ // fill me! end; -procedure doSomethingWhen_AddProgress; +procedure perfExt_AddProgress; begin {$IFDEF IPHONEOS} startSpinning(); {$ENDIF} end; -procedure doSomethingWhen_FinishProgress; +procedure perfExt_FinishProgress; begin {$IFDEF IPHONEOS} stopSpinning(); {$ENDIF} end; -procedure doSomethingWhen_NewTurnBeginning; +procedure perfExt_AmmoUpdate; +begin +{$IFDEF IPHONEOS} + updateVisualsNewTurn(); +{$ENDIF} +end; + +procedure perfExt_NewTurnBeginning; begin {$IFDEF IPHONEOS} clearView(); @@ -76,14 +84,14 @@ {$ENDIF} end; -procedure doSomethingWhen_SaveBeganSynching; +procedure perfExt_SaveBeganSynching; begin {$IFDEF IPHONEOS} replayBegan(); {$ENDIF} end; -procedure doSomethingWhen_SaveFinishedSynching; +procedure perfExt_SaveFinishedSynching; begin {$IFDEF IPHONEOS} replayFinished(); diff -r 1a873262f5dd -r 5ca27a0e9a63 hedgewars/uStore.pas --- a/hedgewars/uStore.pas Sat Oct 09 05:57:46 2010 +0200 +++ b/hedgewars/uStore.pas Sat Oct 09 18:00:53 2010 +0200 @@ -1271,7 +1271,7 @@ numsquares:= texsurf^.h div squaresize; SDL_FreeSurface(texsurf); - doSomethingWhen_AddProgress(); + perfExt_AddProgress(); end; TryDo(ProgrTex <> nil, 'Error - Progress Texure is nil!', true); @@ -1298,7 +1298,7 @@ begin WriteLnToConsole('Freeing progress surface... '); FreeTexture(ProgrTex); - doSomethingWhen_FinishProgress(); + perfExt_FinishProgress(); end; procedure flipSurface(Surface: PSDL_Surface; Vertical: Boolean); diff -r 1a873262f5dd -r 5ca27a0e9a63 hedgewars/uTeams.pas --- a/hedgewars/uTeams.pas Sat Oct 09 05:57:46 2010 +0200 +++ b/hedgewars/uTeams.pas Sat Oct 09 18:00:53 2010 +0200 @@ -225,7 +225,7 @@ until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil); CurrentHedgehog:= @(CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog]); -doSomethingWhen_NewTurnBeginning(); +perfExt_AmmoUpdate end; procedure AfterSwitchHedgehog; diff -r 1a873262f5dd -r 5ca27a0e9a63 project_files/HedgewarsMobile/Classes/AmmoMenuViewController.h --- a/project_files/HedgewarsMobile/Classes/AmmoMenuViewController.h Sat Oct 09 05:57:46 2010 +0200 +++ b/project_files/HedgewarsMobile/Classes/AmmoMenuViewController.h Sat Oct 09 18:00:53 2010 +0200 @@ -36,7 +36,7 @@ @property (assign) BOOL isVisible; -(void) buttonPressed:(id)sender; --(void) updateVisuals:(NSNotification *)object; +-(void) updateAmmoVisuals; -(void) appearInView:(UIView *)container; -(void) disappear; diff -r 1a873262f5dd -r 5ca27a0e9a63 project_files/HedgewarsMobile/Classes/AmmoMenuViewController.m --- a/project_files/HedgewarsMobile/Classes/AmmoMenuViewController.m Sat Oct 09 05:57:46 2010 +0200 +++ b/project_files/HedgewarsMobile/Classes/AmmoMenuViewController.m Sat Oct 09 18:00:53 2010 +0200 @@ -33,7 +33,7 @@ [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(updateVisuals:) + selector:@selector(updateAmmoVisuals) name:@"updateAmmoVisuals" object:nil]; @@ -59,7 +59,7 @@ -(void) viewWillAppear:(BOOL)animated { if (self.buttonsArray != nil) - [self updateVisuals:nil]; + [self updateAmmoVisuals]; [super viewWillAppear:animated]; } @@ -105,7 +105,7 @@ [button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; [button setTitleColor:UICOLOR_HW_YELLOW_TEXT forState:UIControlStateNormal]; button.titleLabel.backgroundColor = [UIColor blackColor]; - button.titleLabel.font = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]]; + button.titleLabel.font = [UIFont boldSystemFontOfSize:[UIFont smallSystemFontSize]]; [button.titleLabel.layer setCornerRadius:3]; [button.titleLabel.layer setMasksToBounds:YES]; button.titleLabel.layer.borderColor = [[UIColor whiteColor] CGColor]; @@ -127,10 +127,10 @@ [[dict objectForKey:@"spinner"] stopAnimating]; self.weaponsImage = [dict objectForKey:@"image"]; self.buttonsArray = [dict objectForKey:@"array"]; - [self updateVisuals:nil]; + [self updateAmmoVisuals]; } --(void) updateVisuals:(NSNotification *) object { +-(void) updateAmmoVisuals { unsigned char *loadout = HW_getAmmoCounts(); int turns = HW_getTurnsForCurrentTeam(); @@ -153,35 +153,40 @@ for (int i = 0; i < HW_getNumberOfWeapons(); i++) { UIButton *button = [self.buttonsArray objectAtIndex:i]; if (loadout[i] > 0) { - /*if (button.enabled == NO) { - int x_src = ((i*32)/(int)self.weaponsImage.size.height)*32; - int y_src = (i*32)%(int)self.weaponsImage.size.height; - UIImage *img = [self.weaponsImage cutAt:CGRectMake(x_src, y_src, 32, 32)]; - [button setBackgroundImage:img forState:UIControlStateNormal]; - }*/ - button.enabled = YES; - button.layer.borderColor = [UICOLOR_HW_YELLOW_TEXT CGColor]; - } else { - /*if (button.enabled == YES) { + if (button.enabled == NO) { int x_src = ((i*32)/(int)self.weaponsImage.size.height)*32; int y_src = (i*32)%(int)self.weaponsImage.size.height; UIImage *img = [self.weaponsImage cutAt:CGRectMake(x_src, y_src, 32, 32)]; [button setBackgroundImage:img forState:UIControlStateNormal]; - }*/ + } + button.enabled = YES; + button.layer.borderColor = [UICOLOR_HW_YELLOW_TEXT CGColor]; + } else { + if (button.enabled == YES) + [button setBackgroundImage:nil forState:UIControlStateNormal]; button.enabled = NO; button.layer.borderColor = [[UIColor darkGrayColor] CGColor]; - //NSLog(@"disabled: %d",button.tag); } if (button.enabled == YES) { if (delay[i]-turns >= 0) { - // NSLog(@"delayed(%d) %d",delay[i], button.tag); button.layer.borderColor = [[UIColor lightGrayColor] CGColor]; [button setTitle:[NSString stringWithFormat:@" %d ",delay[i]-turns+1] forState:UIControlStateNormal]; + if (button.enabled == YES) { + int x_src = ((i*32)/(int)self.weaponsImage.size.height)*32; + int y_src = (i*32)%(int)self.weaponsImage.size.height; + UIImage *img = [self.weaponsImage cutAt:CGRectMake(x_src, y_src, 32, 32)]; + [button setBackgroundImage:[img convertToGrayScale] forState:UIControlStateNormal]; + } } else { - // NSLog(@"enabled %d",button.tag); button.layer.borderColor = [UICOLOR_HW_YELLOW_TEXT CGColor]; [button setTitle:@"" forState:UIControlStateNormal]; + if (button.enabled == YES) { + int x_src = ((i*32)/(int)self.weaponsImage.size.height)*32; + int y_src = (i*32)%(int)self.weaponsImage.size.height; + UIImage *img = [self.weaponsImage cutAt:CGRectMake(x_src, y_src, 32, 32)]; + [button setBackgroundImage:img forState:UIControlStateNormal]; + } } } } diff -r 1a873262f5dd -r 5ca27a0e9a63 project_files/HedgewarsMobile/Classes/GameSetup.h --- a/project_files/HedgewarsMobile/Classes/GameSetup.h Sat Oct 09 05:57:46 2010 +0200 +++ b/project_files/HedgewarsMobile/Classes/GameSetup.h Sat Oct 09 18:00:53 2010 +0200 @@ -31,11 +31,13 @@ NSString *savePath; BOOL isNetGame; + BOOL menuStyle; } @property (nonatomic, retain) NSDictionary *systemSettings; @property (nonatomic, retain) NSDictionary *gameConfig; @property (nonatomic, retain) NSString *savePath; +@property (assign) BOOL menuStyle; -(id) initWithDictionary:(NSDictionary *)gameDictionary; -(void) engineProtocol; diff -r 1a873262f5dd -r 5ca27a0e9a63 project_files/HedgewarsMobile/Classes/GameSetup.m --- a/project_files/HedgewarsMobile/Classes/GameSetup.m Sat Oct 09 05:57:46 2010 +0200 +++ b/project_files/HedgewarsMobile/Classes/GameSetup.m Sat Oct 09 18:00:53 2010 +0200 @@ -29,7 +29,7 @@ #define BUFFER_SIZE 255 // like in original frontend @implementation GameSetup -@synthesize systemSettings, gameConfig, savePath; +@synthesize systemSettings, gameConfig, savePath, menuStyle; -(id) initWithDictionary:(NSDictionary *)gameDictionary { if (self = [super init]) { @@ -38,6 +38,7 @@ // should check they exist and throw and exection if not NSDictionary *dictSett = [[NSDictionary alloc] initWithContentsOfFile:SETTINGS_FILE()]; self.systemSettings = dictSett; + self.menuStyle = [[dictSett objectForKey:@"menu"] boolValue]; [dictSett release]; self.gameConfig = [gameDictionary objectForKey:@"game_dictionary"]; diff -r 1a873262f5dd -r 5ca27a0e9a63 project_files/HedgewarsMobile/Classes/GeneralSettingsViewController.m --- a/project_files/HedgewarsMobile/Classes/GeneralSettingsViewController.m Sat Oct 09 05:57:46 2010 +0200 +++ b/project_files/HedgewarsMobile/Classes/GeneralSettingsViewController.m Sat Oct 09 18:00:53 2010 +0200 @@ -77,7 +77,7 @@ [self.settingsDictionary setObject:[NSNumber numberWithBool:theSwitch.on] forKey:@"alternate"]; break; case 60: //getReady - [self.settingsDictionary setObject:[NSNumber numberWithBool:theSwitch.on] forKey:@"ready"]; + [self.settingsDictionary setObject:[NSNumber numberWithBool:theSwitch.on] forKey:@"menu"]; break; default: DLog(@"Wrong tag"); @@ -107,9 +107,10 @@ return 2; break; case 2: // other stuff - return 1; + return 2; break; default: + DLog(@"Nope"); break; } return 0; @@ -210,12 +211,10 @@ switchContent.on = [[self.settingsDictionary objectForKey:@"alternate"] boolValue]; switchContent.tag = 30; } else { - /* - cell.textLabel.text = NSLocalizedString(@"Get Ready Dialogue", @""); - cell.detailTextLabel.text = NSLocalizedString(@"Pause for 5 seconds between turns",@""); - switchContent.on = [[self.settingsDictionary objectForKey:@"ready"] boolValue]; + cell.textLabel.text = NSLocalizedString(@"Classic Ammo Menu", @""); + cell.detailTextLabel.text = NSLocalizedString(@"Select which style of ammo menu you prefer",@""); + switchContent.on = [[self.settingsDictionary objectForKey:@"menu"] boolValue]; switchContent.tag = 60; - */ } break; default: diff -r 1a873262f5dd -r 5ca27a0e9a63 project_files/HedgewarsMobile/Classes/OverlayViewController.h --- a/project_files/HedgewarsMobile/Classes/OverlayViewController.h Sat Oct 09 05:57:46 2010 +0200 +++ b/project_files/HedgewarsMobile/Classes/OverlayViewController.h Sat Oct 09 18:00:53 2010 +0200 @@ -46,12 +46,18 @@ CGPoint startingPoint; BOOL isSegmentVisible; BOOL isAttacking; + + // stuff initialized externally + BOOL isNetGame; + BOOL useClassicMenu; } @property (nonatomic,retain) id popoverController; @property (nonatomic,retain) InGameMenuViewController *popupMenu; @property (nonatomic,retain) HelpPageViewController *helpPage; @property (nonatomic,retain) AmmoMenuViewController *amvc; +@property (assign) BOOL isNetGame; +@property (assign) BOOL useClassicMenu; -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; -(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; diff -r 1a873262f5dd -r 5ca27a0e9a63 project_files/HedgewarsMobile/Classes/OverlayViewController.m --- a/project_files/HedgewarsMobile/Classes/OverlayViewController.m Sat Oct 09 05:57:46 2010 +0200 +++ b/project_files/HedgewarsMobile/Classes/OverlayViewController.m Sat Oct 09 18:00:53 2010 +0200 @@ -43,7 +43,7 @@ #define removeConfirmationInput() [[self.view viewWithTag:CONFIRMATION_TAG] removeFromSuperview]; @implementation OverlayViewController -@synthesize popoverController, popupMenu, helpPage, amvc; +@synthesize popoverController, popupMenu, helpPage, amvc, isNetGame, useClassicMenu; -(BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation { return rotationManager(interfaceOrientation); @@ -307,9 +307,9 @@ case 10: playSound(@"clickSound"); HW_pause(); - if (amvc.isVisible) { + if (self.amvc.isVisible) { doDim(); - [amvc disappear]; + [self.amvc disappear]; } removeConfirmationInput(); [self showPopover]; @@ -317,20 +317,22 @@ case 11: playSound(@"clickSound"); removeConfirmationInput(); - HW_ammoMenu(); - // TODO: removal and multimonitor experience - if (self.amvc == nil) - self.amvc = [[AmmoMenuViewController alloc] init]; - - if (self.amvc.isVisible) { - doDim(); - [self.amvc disappear]; - } else { - doNotDim(); - [self.amvc appearInView:self.view]; + if (self.useClassicMenu) + HW_ammoMenu(); + else { + // TODO: removal and multimonitor experience + if (self.amvc == nil) + self.amvc = [[AmmoMenuViewController alloc] init]; + + if (self.amvc.isVisible) { + doDim(); + [self.amvc disappear]; + } else { + doNotDim(); + [self.amvc appearInView:self.view]; + } } - break; default: DLog(@"Nope"); diff -r 1a873262f5dd -r 5ca27a0e9a63 project_files/HedgewarsMobile/Classes/SDL_uikitappdelegate.h --- a/project_files/HedgewarsMobile/Classes/SDL_uikitappdelegate.h Sat Oct 09 05:57:46 2010 +0200 +++ b/project_files/HedgewarsMobile/Classes/SDL_uikitappdelegate.h Sat Oct 09 18:00:53 2010 +0200 @@ -37,7 +37,7 @@ +(SDLUIKitDelegate *)sharedAppDelegate; -(void) startSDLgame:(NSDictionary *)gameDictionary; --(void) displayOverlayLater:(NSNumber *)isNetGame ; +-(void) displayOverlayLater:(id) object; @end diff -r 1a873262f5dd -r 5ca27a0e9a63 project_files/HedgewarsMobile/Classes/SDL_uikitappdelegate.m --- a/project_files/HedgewarsMobile/Classes/SDL_uikitappdelegate.m Sat Oct 09 05:57:46 2010 +0200 +++ b/project_files/HedgewarsMobile/Classes/SDL_uikitappdelegate.m Sat Oct 09 18:00:53 2010 +0200 @@ -118,10 +118,12 @@ if ([isNetGameNum boolValue] == NO) [setup startThread:@"engineProtocol"]; const char **gameArgs = [setup getSettings:[gameDictionary objectForKey:@"savefile"]]; + NSNumber *menuStyle = [NSNumber numberWithBool:setup.menuStyle]; [setup release]; // since the sdlwindow is not yet created, we add the overlayController with a delay - [self performSelector:@selector(displayOverlayLater:) withObject:isNetGameNum afterDelay:0.1]; + NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:isNetGameNum,@"net",menuStyle,@"menu",nil]; + [self performSelector:@selector(displayOverlayLater:) withObject:dict afterDelay:0.1]; // this is the pascal fuction that starts the game (wrapped around isInGame) isInGame = YES; @@ -129,7 +131,8 @@ isInGame = NO; free(gameArgs); - [uiwindow makeKeyAndVisible]; + [self.uiwindow makeKeyAndVisible]; + [self.uiwindow bringSubviewToFront:self.mainViewController.view]; UIView *refBlackView = [gameWindow viewWithTag:BLACKVIEW_TAG]; UIView *refSecondBlackView = [self.uiwindow viewWithTag:SECONDBLACKVIEW_TAG]; @@ -143,9 +146,12 @@ } // overlay with controls, become visible later, with a transparency effect --(void) displayOverlayLater:(NSNumber *)isNetGame { +-(void) displayOverlayLater:(id) object { + NSDictionary *dict = (NSDictionary *)object; OverlayViewController *overlayController = [[OverlayViewController alloc] initWithNibName:@"OverlayViewController" bundle:nil]; - + overlayController.isNetGame = [[dict objectForKey:@"net"] boolValue]; + overlayController.useClassicMenu = [[dict objectForKey:@"menu"] boolValue]; + UIWindow *gameWindow; if ([[UIScreen screens] count] > 1) gameWindow = self.uiwindow; @@ -171,31 +177,22 @@ self.uiwindow.backgroundColor = [UIColor blackColor]; [self.uiwindow makeKeyAndVisible]; - if ([[UIScreen screens]count] > 1) { - /* - CGSize maxSize = CGSizeZero; - UIScreenMode *screenMode = nil; - for (UIScreenMode *mode in [[[UIScreen screens] objectAtIndex:1] availableModes]) { - if (mode.size.width > maxSize.width) { - maxSize = mode.size; - screenMode = mode; - } - } - */ + // set working directory to resource path + [[NSFileManager defaultManager] changeCurrentDirectoryPath:[[NSBundle mainBundle] resourcePath]]; + + // check for dual monitor support + if ([[UIScreen screens] count] > 1) { DLog(@"dual head mode ftw"); self.secondWindow = [[UIWindow alloc] initWithFrame:[[[UIScreen screens] objectAtIndex:1] bounds]]; self.secondWindow.backgroundColor = [UIColor blackColor]; self.secondWindow.screen = [[UIScreen screens] objectAtIndex:1]; - UIImage *titleImage = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"title.png"]]; + UIImage *titleImage = [UIImage imageWithContentsOfFile:@"title.png"]; UIImageView *titleView = [[UIImageView alloc] initWithImage:titleImage]; titleView.center = self.secondWindow.center; [self.secondWindow addSubview:titleView]; [titleView release]; [self.secondWindow makeKeyAndVisible]; } - - // set working directory to resource path - [[NSFileManager defaultManager] changeCurrentDirectoryPath:[[NSBundle mainBundle] resourcePath]]; } -(void) applicationWillTerminate:(UIApplication *)application { diff -r 1a873262f5dd -r 5ca27a0e9a63 project_files/HedgewarsMobile/Resources/Settings/settings.plist --- a/project_files/HedgewarsMobile/Resources/Settings/settings.plist Sat Oct 09 05:57:46 2010 +0200 +++ b/project_files/HedgewarsMobile/Resources/Settings/settings.plist Sat Oct 09 18:00:53 2010 +0200 @@ -12,5 +12,7 @@ username + menu +