//
//  RootViewController.m
//  traceWrite
//
//  Created by 今井 彰彦 on 2011/12/05
//  Copyright 2011 AIG-Soft. All rights reserved.
//

#import "AppDelegate.h"
#import "RootViewController.h"
#import "Help.h"
#import "SetupViewController.h"
#import "Setup.h"
#import "libs.h"
#import "click.h"
#import "PlaySound.h"
#import "main.h"
#import "Tegaki.h"
#import "PenWidthView.h"
#import "PenButton.h"
#import "SnapShot.h"
#import "AlertViewSub.h"
#import "Yoko2Yoko.h"	// Yoko2Tateを含む
#import "FontSelect.h"
#import "Gensho.h"
#import "GeneratePdf.h"
#import "ScrollView.h"
#import "BunshoList.h"
#import "UIActivityIndicatorView+show.h"


@interface RootViewController()
{
	UIActivityIndicatorView *activityIndicator;
	AppDelegate *app;
	Setup *setup;
}

@end

@implementation RootViewController

#pragma mark -

#define ZOOMMIN	0.2	// 最小ズーム率

//----------------------------------------------
// view*
//----------------------------------------------

#pragma mark -初期化

- (void)viewDidLoad
{
	printSelf();
	[super viewDidLoad];
	
	app=getAppDelegate();
	setup=app.setup;
	
	// 最初の1回だけでいい初期化処理
	// ボタン／ラベル名など表示(ローカライズ)
	self.title=NSLocalStr(@"PROGRAM_NAME"); // プログラム名
	//
	fpopover=POPOVER_NONE; // iPhoneの時はこれから変化しない
	//
	alertView=[[AlertViewSub alloc]init];
	//
	[_tegakiView initTegaki:self scrollView:_tegakiScrollView imageView:tegakiImageView];
	//
	// ビューを入れ替えるために、ビューの番号を得る（これは起動後変化することはないので最初だけでいい）
	[_tegakiScrollView indexSet:self.view.subviews]; // ここに現れるのは、直下のサブビューのみ(その下は出てこない)
	[ tehonScrollView  indexSet:self.view.subviews]; // ここに現れるのは、直下のサブビューのみ(その下は出てこない)
	//
	// 各ペンの初期設定
	[pencilBlack setPenButton:self	shortPressSelector:@selector(setPencil:) longPressSelector:@selector(setPencilWidth:)
					 penColor:PENCIL_COLOR_BLACK penWidth:2.0]; // ここのペン幅は仮の値でいい
	[pencilRed	 setPenButton:self	shortPressSelector:@selector(setPencil:) longPressSelector:@selector(setPencilWidth:)
					penColor:PENCIL_COLOR_RED	penWidth:2.0]; // 同上
	[self setPencilPen:PENCIL_COLOR_BLACK]; // 初期ペンは黒＋手書きモードに設定する
	[self disappearPenWidth]; // ペン幅は初期非表示
	// Undoの初期設定
	[pencilUndo	 setPenButton:self	shortPressSelector:@selector(undo:) longPressSelector:0 duration:1.5f flongOnly:NO]; // 長押しはなし
	//
	fviewDidLoad=YES;

	// Naviにボタン追加
	UIBarButtonItem *btn=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(toolButtonAction:)];
	btn.tag=BUTTON_CLEAR;
	self.navigationItem.leftBarButtonItem=btn;
}

- (void)viewWillAppear:(BOOL)animated
{
	printSelf();
	// ここはiPhoneではsetup/_help/_genshoのあとも呼び出されるので注意
	
	[super viewWillAppear:animated];
	
	if (fviewDidLoad) {
		[self bunshoSetting:setup.bunFileName];
		//
		// フォント変更処理
		setup.currentFontName=setup.fontName;
		setup.currentFontSize=setup.fontSize;
		penWidthSlider.minimumValue	=minPenWidth();
		penWidthSlider.maximumValue	=maxPenWidth();
		_tegakiView.penWidth	=	// 黒がデフォルトなので
		pencilBlack.penWidth=setup.penWidthBlack;
		pencilRed.penWidth	=setup.penWidthRed;
		//
		[self setTehon:YES];	// 手本と手書きの設定
		//
		nslog(@"縦書き時:初期スクロール位置を(最終桁,0行)に合わせる");
		nslog(@"横書き時:初期スクロール位置を(0桁,0行)に合わせる");
		[tehonScrollView homeScrollPoint:ttext.areaSize]; // これで手書き側も同期される
	}
	// windowのIBによる設定背景色を保存（初回だけ）
	if (winColor==nil) {
		winColor=app.window.backgroundColor;
		//nslog(@"window=%@",app.window);
		nslog(@"winColor=%@",winColor);
	} // 毎回やるとタイミングかなんかでclearColorになってしまうことがある
	// window背景色を消す
	app.window.backgroundColor=[UIColor clearColor];
}

-(void)viewDidAppear:(BOOL)animated
{
	printSelf();
	[super viewDidAppear:animated];
	//
	if (fviewDidLoad) {
		// 最初の描画はroot自体が行うので必要ない
//		[_tegakiView redispAll]; // これをしないと正しく描画されない
		[_tegakiView imageSnapShot]; // 画面取得しておく(最初は終了待ちする)
		if (setup.scrollPoint.x>=0) {
			_tegakiScrollView.contentOffset=setup.scrollPoint; // 初期スクロール位置
		}
	}
	fviewDidLoad=NO;
	
#if 0
	if (ffirst) {
		// 初回起動時（1回だけ）
		Alert1(@"FIRST_LAUNCH",@"FIRST_MESSAGE", nil);
		ffirst=NO;
	}
#endif
}

-(void)viewWillDisappear:(BOOL)animated
// 消える前
{
	printSelf();
	[super viewWillDisappear:animated];
	[self closePopover];
}

// popoverが開いているときは強制的に閉じる
/* popoverがpopoverControllerDidDismissPopoverで消えるときは、
 popoverControllerDidDismissPopover->MailMessgaeCtrl:viewWillDisapearの順で呼び出されてしまう
 閉じるべきビューの処理のほうが後に来るので要注意。
 */
-(void)closePopover
{
	printSelf();
	clickStop();
	switch (fpopover) {
		case POPOVER_GENSHO:
			[self genshoCloseButton:self];
			break;
		case POPOVER_HELP:
			[self helpCloseButton:self];
			break;
		case POPOVER_SETUP:
			[self setupSaveButton:self]; // ここでsetupの設定がボタンに反映される
		default: // POPOVER_NONE:iPhoneの時は常にここ
			break;
	}
	clickResume();
	fpopover=POPOVER_NONE;
}

//----------------------------------------------

-(void)startIndicator
{
	activityIndicator=[UIActivityIndicatorView show:self.view style:UIActivityIndicatorViewStyleWhiteLarge fbackground:YES];
}

-(void)stopIndicator
{
	[activityIndicator dismiss];
}

//----------------------------------------------
// 設定
//----------------------------------------------
#pragma mark -表示設定

// 縦横表示要素位置変更
-(void)setButtonY:(BOOL)ftate
{
#if 0	// 現在のtraceWriteでは使ってない
	CGRect frame;
	// xは共通
	if (ftate) {
		// 縦
	} else {
		// 横
	}
#endif
}

// ズーム関係の初期化
-(void)scrollZoomInit:(ScrollView *)scrollView size:(CGSize)size zmin:(float)zmin
{
	printSelf();
	fzoomSyncDisable=fscrollSyncDisable=YES;
	// 領域の設定
	[scrollView initWithArea:size delegate:self ftategaki:_bunsho.ftategaki]; // スクロールエリアの設定
	// ズーム設定
	scrollView.minimumZoomScale=zmin;
	scrollView.maximumZoomScale=setup.fontSizeMax/setup.fontSize;
	nslog(@"Zoom=%f〜%f",zmin,scrollView.maximumZoomScale);
	scrollView.bouncesZoom=scrollView.bounces=NO;
	[scrollView contentSizeRecalcWithZoom:1.0];
	fzoomSyncDisable=fscrollSyncDisable=NO;
}

// 手本側の設定
// ftegaki=YES : 一部手書きへも反映
// ttextは予め設定しておくこと
-(void)setTehon:(BOOL)ftegaki
{
	printSelfs(@"ftegaki=%d",ftegaki);
	[self startIndicator];
	
	// テキストをimage化する
	nslog(@"currentFontSize=%f",setup.currentFontSize);
	UIColor *col=[UIColor colorWithRed:0.4 green:0.4 blue:0.4 alpha:0.3]; // [UIColor grayColor]
	tehonImageView.image=[ttext text2Image:setup.currentFontSize
								  fontName:setup.currentFontName fscrollArea:YES color:col];
#ifdef DEBUG	//!!test!!
	{
		NSData *imgdata=UIImageJPEGRepresentation(tehonImageView.image,1.0);
		[imgdata writeToFile:makeFullPathForSaveData(@"tehon.jpg") atomically:YES];
	}
#endif
	nslog(@"手本領域の設定");
	[self scrollZoomInit:tehonScrollView size:tehonImageView.image.size zmin:ZOOMMIN];
	//
	if (ftegaki) {
		nslog(@"手書き領域内部ワークのサイズを合わせる");
		_tegakiView.contentSize=tehonImageView.image.size;
		[self scrollZoomInit:_tegakiScrollView size:tehonImageView.image.size zmin:ZOOMMIN];
	}
	nslog(@"setTehon終わり");
	//
	CGPoint initpoint={SCROLLAREA_INIT,SCROLLAREA_INIT};
	setup.scrollPoint=initpoint; // スクロール位置の初期化指示
	//
	[self stopIndicator];
}

// 文章を設定する
// ここで設定するのは文章のみで、フォントは設定してはいけない（表示=viewが確定していないので）
-(void)bunshoSetting:(NSString *)bunFileName
{
	printSelfs(@"%@",bunFileName);
	[self startIndicator];
	
	// フルパス名化してテキスト読み込み
	_bunsho =[[Bunsho alloc]init];
	[_bunsho load:[Bunsho bunFullPath:bunFileName]];
	NSString *fontName;
	setup.fontSize=readBunshoFont(bunFileName,&fontName);
	setup.fontName=fontName;
	// 文章変換
	ttext=[[Yoko2Yoko alloc]init];
	if (_bunsho.ftategaki) {
		// 縦書き
		[ttext yoko2Tate:_bunsho.text tcharMax:_bunsho.maxKetas];
	} else {
		// 横書き
		[ttext yoko2Yoko:_bunsho.text  charMax:_bunsho.maxKetas];
	}
	
	// 現在の文書に設定
	setup.currentBunFileName=bunFileName;
	//
	[self stopIndicator];
}

//----------------------------------------------
// popover表示処理(iPad)
//----------------------------------------------

#pragma mark -Popover(iPad)

// popoverが消えた後に呼び出される
// dismissPopoverAnimatedでは来ないのは仕様
// 此処に来るときはPopoverは確実に開かれているし、dissmissも自動的に行われる
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)pop
{
	printSelf();
	// 閉じる処理
	// setupではサブ画面中の時もあるが、全てsetupVireControllerを開放すれば一緒に解放されるので問題ない
	//	mailMessage;キーボードは同一画面内
	//	address;mailMessageをreleaseすれば一緒に解放される
	//	pickerView
	// →popoverControllerShouldDismissPopoverをNOにしたので、setupからはここに来ることはない
	[self closePopover];
}

// 閉じて良いかどうかの確認
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)pop
{
	printSelf();
	switch (fpopover) {
		case POPOVER_GENSHO:
		case POPOVER_HELP:
			return YES;
		case POPOVER_SETUP:
		default:
			break;
	}
	// 途中では閉じさせない（途中閉じを許すと処理が大変面倒なので）
	return NO;
}

//----------------------------------------------

-(void)hiddenScrollSymbol:(BOOL)fhidden
{
	lblScroll.hidden=fhidden;
}

// 手書き表示制御
// fhidden : NO=表示 , YES=非表示
-(void)tegakiScrollViewHidden:(BOOL)fhidden
{
	// viewはscrollViewの配下にあるのでscrollViewだけhiddenにすれば良い
	_tegakiScrollView.hidden=fhidden;
}

// 手本表示制御
// fhidden : NO=表示 , YES=非表示
-(void)	tehonScrollViewHidden:(BOOL)fhidden
{
	// viewはscrollViewの配下にあるのでscrollViewだけhiddenにすれば良い
	tehonScrollView.hidden=fhidden;
}

// 筆を置いてない状態にする
-(void)nonHudeokiMode
{
	printSelf();
	// 画面の中心座標を得る
	CGPoint point=[tehonScrollView getZoomCenter];
	//
	imgSelectHudeoki3.hidden=YES;
	imgSelectHudeoki.hidden =YES;
	[self tegakiScrollViewHidden:NO];	// 手書きを表示
	[self  tehonScrollViewHidden:NO];	// 手本も表示
	_tegakiView.fEnableTouch=YES;		// 手書きを許可する
	_tegakiScrollView.zoomScale=1.0;		// ズームを解除する(ズーム同期で手本も解除される)
	_tegakiScrollView.scrollEnabled=NO;	// 手書き領域の手動スクロールを禁止する(スクロールエリアからの制御のみ有効)
	[_tegakiView setNeedsDisplay];		// 画面内に入った部分の手書きを再描画
	_tegakiView.hidden=NO;	// 手書き領域のUIViewを有効にする
	fzoomDisable=YES;		// Zoomを禁止する
	pencilUndo.hidden=NO;	// UNDOを許可
	hudeokiMode=HUDEOKI_NONE;
	//
	// 中心座標で合わせる
	[tehonScrollView setContentOffsetWithPoint:point];
	// なぜか_tegakiScrollView.contentSizeが=frame.sizeになってしまうので、ここで再設定する
	[_tegakiScrollView resetContentSize];
}

//----------------------------------------------
// ペン幅処理
//----------------------------------------------

// ペン幅描画
-(void)dispPenWidth
{
	printSelf();
	penWidthView.penColor=_tegakiView.penColor;
	penWidthSlider.value =penWidthView.penWidth=_tegakiView.penWidth;
	[penWidthView setNeedsDisplay]; // drawRectが呼び出される
}

// ペン幅設定画面を消す
// tegakiのdelegate
-(void)disappearPenWidth
{
//	printSelf();
	penWidthSlider.hidden=penWidthView.hidden=YES;
	[penWidthView stop];
}

// ペン幅の設定:ボタンを押したときに呼び出される
// 先にpencil*を設定しておくこと
-(void)setPencilWidth:(id)sender
{
	printSelf();
	penWidthSlider.hidden=penWidthView.hidden=NO;
	[penWidthView start];
	[self dispPenWidth];
}

// ペン幅変更
// sliderから呼び出される
-(IBAction)penSlider:(UISlider *)slide
{
//	printSelf();
	_tegakiView.penWidth=slide.value;
	switch (pencilCol) {
		case PENCIL_COLOR_BLACK:
			setup.penWidthBlack=
			pencilBlack.penWidth=_tegakiView.penWidth;
			break;
		case PENCIL_COLOR_RED:
			setup.penWidthRed	=
			pencilRed.penWidth	=_tegakiView.penWidth;
			break;
	}
	// 変更した幅で再表示
	[self dispPenWidth];
}

// ペンの選択
// pen : ペン色による設定
-(void)setPencilPen:(NSInteger)pen
{
	printSelfs(@"%d",(int)pen);
	[self disappearPenWidth]; // ペン幅設定画面が表示されているときは消す
	switch (pen) {
		case PENCIL_COLOR_BLACK:
			_tegakiView.penColor=pencilBlack.penColor;
			_tegakiView.penWidth=pencilBlack.penWidth;
			imgSelectPencilBlack.hidden	=NO;
			imgSelectPencilRed.hidden	=YES;
			break;
		case PENCIL_COLOR_RED:
			_tegakiView.penColor=pencilRed.penColor;
			_tegakiView.penWidth=pencilRed.penWidth;
			imgSelectPencilBlack.hidden	=YES;
			imgSelectPencilRed.hidden	=NO;
			break;
	}
	// ペンの設定をしたときは筆置は消す
	//	imgSelectHudeoki	imgSelectHudeoki3
	//		NO						YES			手書き下、手本上
	//	他の時は上下関係は手書き上、手本下
	if (imgSelectHudeoki.hidden==NO && imgSelectHudeoki3.hidden==YES) {
		[self.view exchangeSubviewAtIndex:_tegakiScrollView.index withSubviewAtIndex:tehonScrollView.index]; // 元に戻す(手書きが上、手本が下) 
	}
	[self nonHudeokiMode]; // 筆置モードを解除
	//
	pencilCol=pen;
}

// ペンの設定
// 先にpencil*を設定しておくこと
// ペン幅選択時にも先に呼び出される
-(void)setPencil:(id)sender
{
	printSelfs(@"%@",sender);
	[self setPencilPen:[(NSNumber *)sender intValue]];
}

//----------------------------------------------
// ページ処理
//----------------------------------------------

-(void)undo:(id)sender
{
	printSelf();
	// indicatorを表示/非表示するためだけにここで受けている
	[self startIndicator];
	//
	[_tegakiView undo:nil];
	//
	[self stopIndicator];
}

// 編集系ボタンのうち、PenButtonの支配下にないもの
-(IBAction)editButtonAction:(UIButton *)btn
{
	printSelfs(@"tag=%d",(int)btn.tag);
	
	clickSound();
	[self disappearPenWidth]; // ペン幅設定画面が表示されているときは消す
#if 0
	// スクロール用の準備
	CGSize  size =tehonImageView.image.size;		// 全体サイズ
	CGPoint point=tehonScrollView.contentOffset;	// スクロール位置
	CGRect	frame=tehonScrollView.frame;			// スクロール画面サイズ
	CGFloat	wx=16,wy=16;
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
		wx*=2;
		wy*=2;
	}
#endif
	switch (btn.tag) {
		case BUTTON_HUDEOKI:
			// 筆置
			nslog(@"筆置");
			//	imgSelectHudeoki	imgSelectHudeoki3	hudeokiMode
			//		YES						YES			HUDEOKI_NONE	筆を置いてない状態
			//		NO						YES			HUDEOKI_TEHON	手書きを下にする、手本を上にする	手習い.alpha=TEHON_ALPHA
			//		YES						NO			HUDEOKI_TEGAKI	手本を消す、手書きを表示
			//		NO						NO							なし
			switch (hudeokiMode) {
				case HUDEOKI_NONE: // →手本＋手書きスクロール
					[self startIndicator];

					// 手書きを下にする、手本を上にする
					[_tegakiView save]; // 保存
					pencilUndo.hidden=YES; // スクロールモード中はUndoは禁止する(面倒なので)
					imgSelectHudeoki.hidden=NO;
					// 3はhiddenである
					// 各ペンを消す
					imgSelectPencilBlack.hidden	=YES;
					imgSelectPencilRed.hidden	=YES;
					[self.view exchangeSubviewAtIndex:_tegakiScrollView.index withSubviewAtIndex:tehonScrollView.index]; // 手書きを下にする
					// 手書きが下になっているので、手書きへのタッチは自動的に無視される(fEnableTouch=NOにする必要はない)
					//[_tegakiView imageSnapShot];	// 拡大縮小はimageでしかできないので、内容をimage化する
					nslog(@"バックグラウンドでsnapShot");
					[_tegakiView performSelectorInBackground:@selector(imageSnapShot) withObject:nil]; // snapShotを並行動作処理；操作上劇的に高速化される
					_tegakiView.hidden=YES;		// UIViewの手書き領域を無効にする
					fzoomDisable=NO;			// Zoom禁止を解除する
					tehonImageView.alpha=TEHON_ALPHA; // 薄くして重ねる
					hudeokiMode++;
					//
					[self stopIndicator];
					break;
				case HUDEOKI_TEHON: // →手書きのみスクロール
					// 手本を消す、手書きを表示
					imgSelectHudeoki3.hidden=NO;
					imgSelectHudeoki.hidden =YES;
					[self.view exchangeSubviewAtIndex:_tegakiScrollView.index withSubviewAtIndex:tehonScrollView.index]; // 元に戻す(手書きが上、手本が下) 
					[self tehonScrollViewHidden:YES];	// 手本を消す
					tehonImageView.alpha=1.0;
					_tegakiScrollView.scrollEnabled=YES; // 手書きビューからの手動スクロールを許可する
					_tegakiView.fEnableTouch=NO;			// 手書きを禁止する
					hudeokiMode++;
					break;
				case HUDEOKI_TEGAKI: // →筆を置いてない状態に戻す
					// 元の色に戻す
					[self setPencilPen:pencilCol]; // この中で筆置モードも解除される
				//	[self nonHudeokiMode]; // 筆置モードを解除
					break;
			}
			break;
	}
}

//----------------------------------------------
// ツールバーボタン押下時処理
//----------------------------------------------

// 全手書き消去
-(void)clearAll:(id)sender
{
	printSelf();
	[_tegakiView clearPage1];
	// スクロール位置をホームに戻す
	[tehonScrollView homeScrollPoint:ttext.areaSize]; // これで手書き側も同期される
}

// ツールバーのボタン用
-(IBAction)toolButtonAction:(UIBarButtonItem *)btn
{
	printSelfs(@"tag=%d",(int)btn.tag);

	// window背景色を復帰
	app.window.backgroundColor=winColor;
	// スクロール位置を保存
	tehonContentOffset=tehonScrollView.contentOffset;

	[self disappearPenWidth]; // ペン幅表示を消す
	//
	switch (btn.tag) {
		case BUTTON_HELP:
			nslog(@"BUTTON_HELP");
			[_tegakiView save]; // 念のため保存しておく
			switch (fpopover) {
				case POPOVER_HELP:
					// 同じボタンが二度押しされたときは何もしない
					nslog(@"二度押し");
					break;
				case POPOVER_SETUP:
					nslog(@"setupを開いているときは他は受け付けない");
					break;
				case POPOVER_PRINTER:
					nslog(@"AirPrintPoppver表示中");
					[self printClose];
					// 消してからHELPへ
				default:
					// iPhoneの時は常にfpopover==POPOVER_NONE
					self.help=[[Help alloc]init];
					[_help open:self selector:@selector(helpCloseButton:)];
					[self anyOpen:_help btn:btn popover:POPOVER_HELP fmodal:YES];
					 // retainされているので、実close時に開放される
					break;
			} // switch (fpopover)
			break;
			
		case BUTTON_BOOK:
			nslog(@"BUTTON_BOOK");
			[_tegakiView save]; // 念のため保存しておく
			switch (fpopover) {
				case POPOVER_GENSHO:
					// 同じボタンが二度押しされたときは何もしない
					nslog(@"二度押し");
					break;
				case POPOVER_PRINTER:
					nslog(@"AirPrintPoppver表示中");
					[self printClose];
					// 消してからGenshoへ
				default:
					// iPhoneの時は常にfpopover==POPOVER_NONE
					self.gensho =[[Gensho alloc]init];
					[_gensho open:self selector:@selector(genshoCloseButton:) bunsho:_bunsho bunName:_bunsho.bunName];
					[self anyOpen:_gensho btn:btn popover:POPOVER_GENSHO fmodal:YES];
					 // retainされているので、実close時に開放される
					break;
			} // switch (fpopover)
			break;

		case BUTTON_CLEAR:
			nslog(@"BUTTON_CLEAR");
			[alertView alertExecute:YES target:self selector:@selector(clearAll:) delay:0.0 title:@"" message:@"CLEAR_ALL"]; // ここでクリック音がなる
			break;
		
		case BUTTON_SETTING:
			[_tegakiView save]; // 念のため保存しておく
			switch (fpopover) {
				case POPOVER_SETUP:
					// 同じボタンが二度押しされたときは何もしない
					nslog(@"二度押し");
					break;
				case POPOVER_PRINTER:
					nslog(@"AirPrintPoppver表示中");
					[self printClose];
					// 消してからsetupへ
				default:
					// 設定が終わるまで、他のボタンは無効化する
					_btnHelp.enabled=
					_btnGensho.enabled=
					_btnAction.enabled=NO;
					// iPhoneの時は常にfpopover==POPOVER_NONE
					self.setupViewController =[[SetupViewController alloc]init];
					[_setupViewController open:self retSelector:@selector(setupSaveButton:)];
					[self anyOpen:_setupViewController btn:btn popover:POPOVER_SETUP fmodal:NO];
					 // retainされているので、実close時に開放される
					break;
			} // switch (fpopover)
			break;
	}
}

//-------------------------------------------------------------------

/// @param viewCtrl 開くVC
/// @param btn 押されたボタン
/// @param popover 識別子
-(void)anyOpen:(UIViewController *)vc btn:(id)btn popover:(NSInteger)popover fmodal:(BOOL)fmodal
{
	printSelfs(@"vc=%@",vc);
	nslog(@"btn:%@/poppver:%d/fmodal:%d",btn,(int)popover,fmodal);
	[self startIndicator];
	clickSound(); // クリック音
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
		nslog(@"anyOpen:iPad");
		[self closePopover]; // 他のを閉じる

		// popoverの中でnaviを使うため、naviの配下に置く
		UINavigationController *navi=[[UINavigationController alloc]initWithRootViewController:vc];
		navi.navigationBar.backgroundColor=[UIColor whiteColor]; // これをしないとiOS7で透けてしまうので
		self.popover=[[UIPopoverController alloc]initWithContentViewController:navi];
		_popover.popoverContentSize=vc.view.frame.size;	// popoverのサイズを設定
		_popover.delegate=self;
		[_popover presentPopoverFromBarButtonItem:btn permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
		fpopover=popover;
	} else { // iPod touch/iPhone
		nslog(@"anyOpen:iPod Touch/iPhone");
		if (!fmodal) {
			[self.navigationController pushViewController:vc animated:YES];
		} else { // モーダルビュー型
			// naviがないとnaviが表示されないから
			UINavigationController *navi=[[UINavigationController alloc]initWithRootViewController:vc];
			// この時は閉じるボタンが必須
			[navi setModalTransitionStyle:UIViewAnimationOptionTransitionCurlUp]; // アニメーション形式の指定
			[self presentViewController:navi animated:YES completion:NULL];
		}
	}
	[self stopIndicator]; // 画面が変わるからいらないはずだけど、一応止めておく
}

// これが呼び出されるときは、必ず対象が開いている
-(void)anyClose:(UIViewController *)vc fmodal:(BOOL)fmodal
{
	printSelfs(@"vc=%@", vc);
	//
	clickSound(); // クリック音
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { // iPad
		// popoverを消す
		[_popover dismissPopoverAnimated:YES];	// popoverは指示を出してから実際に閉じるまでに時間がある
		fpopover=POPOVER_NONE;
	} else { // iPhone
		if (!fmodal) {
			[self.navigationController popToViewController:self animated:YES];
		} else {
			[vc dismissViewControllerAnimated:YES completion:NULL];
		}
		// Naviのときは、先に画面が閉じてから先に進む
	}
	[self disappearPenWidth]; // ペン幅表示を消す
	tehonScrollView.contentOffset=tehonContentOffset; // スクロール位置を復帰
}

//------------------------

// これが呼び出されるときは、必ずHelpが開いている
-(void)helpCloseButton:(id)sender
{
	printSelf();
	[self anyClose:_help fmodal:YES];
}

// これが呼び出されるときは、必ずGenshoが開いている
-(void)genshoCloseButton:(id)sender
{
	printSelf();
	[self anyClose:_gensho fmodal:YES];
}

// 保存して閉じる
// これが呼び出されるときは、必ずSetup系が開いている
-(void)setupSaveButton:(id)sender
{
	printSelf();
	// 設定値保存
	[app.setup saveSetup];
	[self anyClose:_setupViewController fmodal:NO];
	//
	if (![setup.bunFileName isEqualToString:setup.currentBunFileName]) {
		nslog(@"手本+フォント変更確認");
		[alertView alertExecuteWithCancel:YES target:self selector:@selector(textSetup2Tehon:)
									delay:0.0
									title:NSLocalStr(@"TEHONCHANGE")
								  message:@"TEHONCHANGE_MESSAGE"
							 targetCancel:self selectorCancel:@selector(textSetup2Tehon2Cancel:)
		 ]; // ここでクリック音がなる
	} else {
		// フォント変更は即時適応する
		// 手書きと合わない部分が出るかもしれないが、それはユーザーの責任ということで
		nslog(@"fontName=%@/%@",setup.fontName,setup.currentFontName);
		nslog(@"fontsize=%f/%f",setup.fontSize,setup.currentFontSize);
		if (![setup.fontName isEqualToString:setup.currentFontName]
			||  setup.fontSize!=setup.currentFontSize
			) {
			nslog(@"フォント変更確認"); // fontSetup2Tehon
			[alertView alertExecuteWithCancel:YES target:self selector:@selector(textSetup2Tehon:)
										delay:0.0
										title:NSLocalStr(@"FONTCHANGE")
									  message:@"FONTCHANGE_MESSAGE"
								 targetCancel:self selectorCancel:@selector(textSetup2Tehon2Cancel:)
			 ]; // ここでクリック音がなる
		}
	}
	_btnHelp.enabled=
	_btnGensho.enabled=
	_btnAction.enabled=YES;
	tehonScrollView.contentOffset=tehonContentOffset; // スクロール位置を復帰
	//
	printSelfs(@"終了%@",@"");
}

//------------------------

// フォント変更付き手本変更後の手本の設定
-(void)textSetup2Tehon:(id)sender
{
	printSelf();
	
	// 手本の変更(フォントの変更も伴う)か、フォントだけの変更かを判断する
	enum {
		NO_CHANGE=0,
		TEHON_CHANGE,
		FONT_CHANGE,
	};
	int fchange=NO_CHANGE; // 変更なしの印
	if (![setup.bunFileName isEqualToString:setup.currentBunFileName]) {
		nslog(@"手本+フォント変更");
		fchange=TEHON_CHANGE;
	} else {
		// 手書きと合わない部分が出るかもしれないが、それはユーザーの責任ということで
		nslog(@"fontName=%@/%@",setup.fontName,setup.currentFontName);
		nslog(@"fontsize=%f/%f",setup.fontSize,setup.currentFontSize);
		if (  ![setup.fontName isEqualToString:setup.currentFontName]
			||  setup.fontSize!=setup.currentFontSize) {
			fchange=FONT_CHANGE;
		}
	}
	if (fchange!=NO_CHANGE) {
		setup.currentFontSize=setup.fontSize;
		//
		// フォント変更処理
		penWidthSlider.minimumValue	=minPenWidth();
		penWidthSlider.maximumValue	=maxPenWidth();
		_tegakiView.penWidth=
		setup.penWidthRed	=
		pencilRed.penWidth	=
		setup.penWidthBlack	=
		pencilBlack.penWidth=defPenWidth(setup.currentFontSize);
		//
		// 手書きの消去
		[_tegakiView clearPage1];
		
		// 文書を読み込む
		[self bunshoSetting:setup.bunFileName];
		// ここで手本指定のフォントも読み出される
		nslog(@"_bunsho.font5=%@",_bunsho.font5);
		
		if (fchange==TEHON_CHANGE) {
			// 文書指定のフォントに合わせる
			setup.currentFontName=_bunsho.font5;
		} else {
			setup.currentFontName=setup.fontName;
		}
		nslog(@"fontName=%@",setup.currentFontName);

		// imageの設定
		[self setTehon:YES];
		nslog(@"初期スクロール位置を(最終桁,0行)に合わせる");
		[tehonScrollView homeScrollPoint:ttext.areaSize]; // スクロール同期で_tegakiScrollView側も合わせられる
		[self.view setNeedsDisplay]; // drawRectが呼び出される
	}
}

// フォント変更付き手本変更後の手本の設定
-(void)textSetup2Tehon2Cancel:(id)sender
{
	printSelf();
	// 変更をキャンセルする
	setup.fontSize=setup.currentFontSize;
	setup.fontName=setup.currentFontName;
	setup.bunFileName=setup.currentBunFileName;
}

//-------------------------------------------------------------------
// メイル処理
//-------------------------------------------------------------------

#pragma mark -e-mail

- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
	nslog(@"メイル処理終了:result=%d/error=%@",result,error);
	// どの様な状態から帰ってきたとしても、画面から消す
	switch (result)
	{
		case MFMailComposeResultCancelled:
			nslog(@"MFMailComposeResultCancelled");
			break;
		case MFMailComposeResultSaved:
			nslog(@"MFMailComposeResultSaved");
			break;
		case MFMailComposeResultSent:
			nslog(@"MFMailComposeResultSent");
			break;
		case MFMailComposeResultFailed:
			nslog(@"MFMailComposeResultFailed:error=%@",error);
			break;
		default:
			nslog(@"状態不明");
			break;
	}
	[controller dismissViewControllerAnimated:YES completion:NULL];
	mail=nil;
}

// 手書きをe-mailで送信する
// attachData : 添付データ(PDF/JPEG)
-(void)eMailSend
{
	printSelf();
	
	[self startIndicator];

	[_tegakiView save]; // 念のため保存しておく
	
	// 今回はメイル用クラスを使う(UINavigationControllerの子クラス)
	mail=[[MFMailComposeViewController alloc]init];
	// 件名
	// 年月日 : 文書名
	NSString *subject=[NSString stringWithFormat:@"%@ : %@",_bunsho.bunName,makeNowDateStr()];
	[mail setSubject:subject];
	nslog(@"件名:%@",subject);
	
	if (setup.attachFile==FILE_PDF) {
		// PDFで添付するとき
		[mail setMessageBody:NSLocalStr(@"BODY_PDF") isHTML:NO]; // 本文
		NSString *filename=[NSString stringWithFormat:@"%@.pdf",_bunsho.attachName];
		NSMutableData *pdfData=[[NSMutableData alloc]init];
		[_tegakiView savePDFFileWithImage:pdfData];
		[mail addAttachmentData:pdfData mimeType:@"application/pdf" fileName:filename]; // 添付
		//
	} else {
		// JPEGで添付するとき
		[mail setMessageBody:NSLocalStr(@"BODY_JPEG") isHTML:NO]; // 本文
		NSString *filename=[NSString stringWithFormat:@"%@.jpg",_bunsho.attachName];
		NSData *attach=[_tegakiView getAttach];
		[mail addAttachmentData:attach mimeType:@"image/jpeg" fileName:filename]; // 添付
	}
	nslog(@"mail=%@",mail);
	//
	[self stopIndicator];
	
	mail.mailComposeDelegate=self; // 普通のdelegeteではないので注意
	[self presentViewController:mail animated:YES completion:NULL];
}

//-------------------------------------------------------------------
// 印刷処理
//-------------------------------------------------------------------

#pragma mark -印刷処理

-(void)printClose
{
	printSelf();
	[airPrint close];
	fpopover=POPOVER_NONE;
}

#ifdef DEBUG
// 印刷設定画面が表示された後に呼び出される
- (void)printInteractionControllerDidPresentPrinterOptions:(UIPrintInteractionController *)printInteractionController
{
	printSelf();
}
#endif

// 印刷設定画面が、印刷開始で消えるときに呼び出される
// closeでは呼び出されないので注意
- (void)printInteractionControllerDidDismissPrinterOptions:(UIPrintInteractionController *)printInteractionController
{
	printSelf();
	fpopover=POPOVER_NONE; // もう閉じたの印;他の画面は開いてないはず
}

- (void)printInteractionControllerWillStartJob:(UIPrintInteractionController *)printInteractionController
// 印刷開始時に呼び出される
{
	printSelf();
	// 設定画面はこの時点で自動的に閉じるので、通常閉じ処理は必要ない
	fpopover=POPOVER_NONE; // もう閉じたの印;他の画面は開いてないはず
}

// 印刷終了時に呼び出される
// プリンタースプーラーに処理が渡ればすぐに呼び出される（＝実印刷終了を待つわけではない）
// 印刷設定画面がcloseで消された時も呼び出される(重要）
- (void)printInteractionControllerDidFinishJob:(UIPrintInteractionController *)printInteractionController
{
	printSelf();
	/* 重要な注意
	 印刷設定が表示されているときに_helpを押すと、
		airPrint:close
		_help表示
		ここ
	  の順に呼び出される。したがって、ここでfpopoverをいじってはいけない
	 */
}

-(void)print:(BOOL)fTegaki
{
	printSelf();
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
		// iPad時のみpoppver判定が必要
		printSelfs(@"iPad%@",@"");
		fpopover=POPOVER_PRINTER;
	}
	
	airPrint=[[AirPrint alloc]init];
	[airPrint initPrint:_btnAction];
	airPrint.delegate=self;
	//
	if (fTegaki) { // 手書きの印刷
		NSString *title=[NSString stringWithFormat:@"%@(%@)",_bunsho.bunName,NSLocalStr(@"TEGAKI")];
		[_tegakiView imageSnapShot]; // 印刷用なので終了待ちする
		[airPrint setItem:tegakiImageView.image jobName:title];
	} else { // 手本の印刷
		NSString *title=[NSString stringWithFormat:@"%@(%@)",_bunsho.bunName,NSLocalStr(@"TEHON")];
		[airPrint setItem:tehonImageView.image jobName:title];
	}
	// setItemは画面表示するとすぐに戻ってきてここに来るので、ここではprintCloseで画面を閉じてはいけない
}

//-------------------------------------------------------------------
// ActionSheet
//-------------------------------------------------------------------

#pragma mark -アクションシート

// アクションシートのボタンが押された
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
	nslog(@"actionSheet:buttonIndex=%d",(int)buttonIndex);
	if (buttonIndex==actionSheet.cancelButtonIndex) { // キャンセルは印刷の有効／無効によって変わるので変数認識する
		// ActionSheet自体が画面外タップなどでキャンセルされた時もここに来る
		nslog(@"キャンセル");
		return;
	}
	//
	switch (buttonIndex) {
		case 0:
			nslog(@"メイル送信");
			[self eMailSend];
			break;
		case 1:
			nslog(@"手書き印刷");
			[self print:YES];
			break;
		case 2:
			nslog(@"手本印刷");
			[self print:NO];
			break;
	}
	clickSound();
}

-(IBAction)actionButton:(UIBarButtonItem *)btn
{
	printSelf();

	[self disappearPenWidth]; // ペン幅設定画面が表示されているときは消す

	[_tegakiView save]; // 念のため保存しておく
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
		// アクションシートを表示する前にpopoverを閉じる(Appleからの指摘)
		switch (fpopover) {
			// Setupのときはボタンが無効にされているのでここには来ない
			case POPOVER_GENSHO:
				[self genshoCloseButton:nil];
				break;
			case POPOVER_HELP:
				[self helpCloseButton:nil];
				break;
			case POPOVER_PRINTER:
				// 印刷設定画面表示中にまたアクションを押した時
				[self printClose]; // 設定画面を閉じる;この中でprintInteractionControllerDidFinishJobも呼び出される
				break;
		}
	}
	
	if (getSystemVersion()>=8.0) {
		// iOS8のiPadでActionSheetを使うと、その中からAirPrintのダイアログが開けない
		UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalStr(@"ACTION")
																				 message:@""
																		  preferredStyle:UIAlertControllerStyleActionSheet];
		[alertController addAction:[UIAlertAction actionWithTitle:NSLocalStr(@"MAIL")
															style:UIAlertActionStyleDefault
														  handler:^(UIAlertAction *action) {
																nslog(@"メイル送信");
																[self eMailSend];
																clickSound();
		}]];
		if ([UIPrintInteractionController isPrintingAvailable]) { // 印刷が使えるとき
		[alertController addAction:[UIAlertAction actionWithTitle:NSLocalStr(@"TEGAKIPRINT")
															style:UIAlertActionStyleDefault
														  handler:^(UIAlertAction *action) {
																nslog(@"手書き印刷");
																[self print:YES];
																clickSound();
		}]];
		[alertController addAction:[UIAlertAction actionWithTitle:NSLocalStr(@"TEHONPRINT")
															style:UIAlertActionStyleDefault
														  handler:^(UIAlertAction *action) {
																nslog(@"手本印刷");
																[self print:NO];
																clickSound();
														  }]];
		}
		[alertController addAction:[UIAlertAction actionWithTitle:NSLocalStr(@"CANCEL")
															style:UIAlertActionStyleDefault
														  handler:^(UIAlertAction *action) {
															  nslog(@"キャンセルが押された");
														  }]];
		if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
			// iPadのときは以下の設定によりpopover形式にしなければならない
			alertController.popoverPresentationController.sourceView=self.view;
			alertController.popoverPresentationController.barButtonItem=btn;
		}
		// 表示
		clickSound();
		[self presentViewController:alertController animated:YES completion:nil];
	} else {
		// iOS7ではActionSheetが使える
		// UIActionSheetは毎回alloc&initしないと二回目以降化けてしまう
		if (![UIPrintInteractionController isPrintingAvailable]) { // 印刷が使えないとき
			asheet = [[UIActionSheet alloc]
								initWithTitle:NSLocalStr(@"ACTION")
									 delegate:self
							cancelButtonTitle:NSLocalStr(@"CANCEL")	// ボタン番号=cancelButtonIndex
					   destructiveButtonTitle:nil
							otherButtonTitles:NSLocalStr(@"MAIL"),	// ボタン番号=firstOtherButtonIndex 
					  nil
					  ];
		} else {
			asheet = [[UIActionSheet alloc]
								initWithTitle:NSLocalStr(@"ACTION")
									 delegate:self
							cancelButtonTitle:NSLocalStr(@"CANCEL")	// ボタン番号=cancelButtonIndex
					   destructiveButtonTitle:nil
							otherButtonTitles:NSLocalStr(@"MAIL"),  // ボタン番号=firstOtherButtonIndex 
											  NSLocalStr(@"TEGAKIPRINT"),
											  NSLocalStr(@"TEHONPRINT"),
					  nil
					  ];
		}
		setActionSheetResize(asheet); // リサイズ指定
		// 表示
		clickSound();
		[asheet showInView:self.view];
	}
}

//----------------------------------------------
// ズームとスクロールの同期
//----------------------------------------------
// _tegakiScrollView/tehonScroolViewの両方で発生する

#pragma mark -ズームとスクロールの同期

// 手書きと手本のスクロール位置を合わせる
// スクロール中に呼び出される
- (void)scrollViewDidScroll:(ScrollView *)scrollView
{
	if (fscrollSyncDisable) return; // 同期禁止中
	
//	nslog(@"scrollViewDidScroll:スクロール同期");
	
	fscrollSyncDisable=YES; // 再帰呼び出し禁止
	if (scrollView==_tegakiScrollView) {
	//	nslog(@"手書き領域スクロール→手本を同期");
		tehonScrollView.contentOffset =scrollView.contentOffset; // contentOffset0で同期するとうまくいかない
	} else {
	//	nslog(@"手本領域スクロール→手書きを同期");
		_tegakiScrollView.contentOffset=scrollView.contentOffset; // 同上
	}
	fscrollSyncDisable=NO;
}

// 手書きと手本のズームを合わせる
// ズーム後に呼び出される
- (void)scrollViewDidZoom:(ScrollView *)scrollView
{
	if (fzoomSyncDisable||fzoomDisable) return; // 同期禁止中

//	nslog(@"scrollViewDidZoom:ズーム同期");
	
	fzoomSyncDisable=YES; // 再帰呼び出し禁止
	// 手書きと手本のズーム率を合わせる
	float zoom=scrollView.zoomScale;
	//
	[scrollView contentSizeRecalcAtZoom:zoom]; // 自身のズームを設定

	// 設定するときはviewForZoomingInScrollViewが有効でなければならない
	if (scrollView==_tegakiScrollView) {
		nslog(@"手書き領域ズーム→手本を同期");
//		tehonScrollView.contentOffset=point;
		[tehonScrollView contentSizeRecalcWithZoom:zoom];
	} else { // tehonScroolView
		nslog(@"手本領域ズーム→手書きを同期");
//		_tegakiScrollView.contentOffset=point;
		[_tegakiScrollView contentSizeRecalcWithZoom:zoom];
	}
	penWidthView.penWidth*=zoom;
	//
	fzoomSyncDisable=NO;
}

// UIScrollViewのデリゲート:ズーム対象のUIViewを返す
// これがないとズームしない(読み出し時はzoom=1.0になってしまい、書き込み時は無視される)
// ズーム前に呼び出される
-(UIView *)viewForZoomingInScrollView:(ScrollView *)scrollView_
{
	if (!fzoomDisable) {
	
//	nslog(@"viewForZoomingInScrollView:%@",scrollView_);
	// この中でzoom関連値をいじると再帰呼び出しになって無限ループに入ってしまうので注意
	
#if 0
	for (id subview in scrollView_.subviews) { // subviewsはUIViewのプロパティ
		// scrollView内にあるUIImageViewのみをズーム対象として返している
		// UIViewはズーム対象にしない
		if ([subview isKindOfClass:[UIImageView class]]) {
		//	nslog(@"subview=%@",subview);
			return subview;
		}
	}
#else
	if (scrollView_==tehonScrollView ) {
		return tehonImageView;
	}
	if (scrollView_==_tegakiScrollView) {
		return tegakiImageView;
	}
#endif
	} // ズーム禁止中
	return nil;
}

//----------------------------------------------
// Tegakiからデリゲート
//----------------------------------------------

#pragma mark -Tegakiからデリゲート

// 現在未使用
-(CGRect)getDisplayArea
{
	CGRect  rect={_tegakiScrollView.contentOffset,_tegakiScrollView.frame.size};
	// 表示領域の一回り大きな領域を計算する
	rect.origin.x	-=ttext.spSize.width;
	rect.origin.y	-=ttext.spSize.height;
	rect.size.width +=ttext.spSize.width *2;
	rect.size.height+=ttext.spSize.height*2;
	// ↑ここまで含めておけば、一部画面内なのに描画されない文字は激減する
	// x/yはマイナスになっても構わない(内外判定だけなので)
//	printFrame(@"getDisplayArea", rect);
	return (rect);
}

//----------------------------------------------
// TegakiScrollからデリゲート
//----------------------------------------------

#pragma mark -TegakiScrollからデリゲート

// スクロールモード途中
-(void)scrollMove:(CGFloat)dx dy:(CGFloat)dy
{
	nslog(@"_tegakiScrollView.content.size=%f,%f",_tegakiScrollView.contentSize.width,_tegakiScrollView.contentSize.height);
	//
	nslog(@"scrollMove=Δ%f,%f",dx,dy);
	// 始点から現在位置までの座標差を得る
	CGPoint offset=_tegakiScrollView.contentOffset;
	nslog(@"offset=%f,%f",offset.x,offset.y);
	offset.x+=dx;
	offset.y+=dy;
	[_tegakiScrollView setContentOffsetWithPoint:offset];
}

//----------------------------------------------

// スクロールエリア内をタッチ(point.x,y)したとき呼び出される
-(void)scrollViews:(CGPoint)point_ y:(NSInteger)y
{
	CGPoint point=point_;
	nslog(@"scrollViews:point=%f,%f/y=%d",point.x,point.y,(int)y);
	if (!_tegakiView.fEnableTouch) {
		nslog(@"自動スクロール禁止");
		return;
	}
	
	// 縦横共通処理
	if (y<0) { // 最上行処理
		nslog(@"最下行へ移動");
		point=tehonScrollView.contentOffset; // 現在位置を一旦記録
		point.y=[ttext yPoint:ttext.tlines-1 scrollView:tehonScrollView]; // 直接そこに移動
		goto L1;
	}
	// これ以降y>=0
	//
	// 文字位置算出
	NSInteger x=[ttext getCharX:point];
//	NSInteger y=[ttext getCharY:point];
	nslog(@"文字位置=(%d,%d)",(int)x,(int)y);
	point=tehonScrollView.contentOffset; // 現在位置を一旦記録
	//
	if (_bunsho.ftategaki) { // 縦書き時スクロール
		nslog(@"縦書き時スクロール");
		if ([ttext isTCharXcheck:x scrollView:tehonScrollView]>CHAR_IN_VIEW) {
			nslog(@"左右スクロール;優先");
			point.x=ttext.pointx;
			goto L1;
		}
		switch ([ttext isTCharYcheck:y scrollView:tehonScrollView]) {
			case CHAR_OUTOF_UP:
				nslog(@"上スクロール(戻し)");
				point.y=ttext.pointy;
				goto L1;
			case CHAR_IN_VIEW:
				nslog(@"y画面内スクロール");
				point.y=ttext.pointy;
				break;
		}
		y++; // １つ下
		if ([ttext isTLeftSpace:x line:y]) {
			// これより下は全部スペースである＝次の桁の先頭に戻す
			y=0;
			if (x>0) x--;
		}
		nslog(@"新しい文字位置→(%d,%d)",(int)x,(int)y);
		if (y==0) { // xが変わるのは改行時のみ
			if ([ttext isTCharXcheck:x scrollView:tehonScrollView]>CHAR_IN_VIEW) {
				nslog(@"右文字または改行");
				point.x=ttext.pointx;
			}
		}
		if ([ttext isTCharYcheck:y scrollView:tehonScrollView]>CHAR_IN_VIEW) {
			nslog(@"下文字または上スクロール(改行)");
			point.y=ttext.pointy;
		}
	} else {
		// 横書き時スクロール
		// 横は1文字毎にスクロールエリアが無いので、1文字分の左1/3を左、右2/3を右にスクロールにする
		nslog(@"横書き時スクロール");
		if ([ttext isYCharYcheck:y scrollView:tehonScrollView]>CHAR_IN_VIEW) {
			nslog(@"上下スクロール"); // (縦スクロールのように)これを優先にするとうまくスクロールしなくなる
			point.y=ttext.pointy;
			goto L1;
		}
		switch ([ttext isYCharXcheck:x scrollView:tehonScrollView point:point_]) {
			case CHAR_OUTOF_LEFT:
				nslog(@"左スクロール");
				point.x=ttext.pointx;
				goto L1;
			case CHAR_OUTOF_RIGHT:
				nslog(@"戻し左スクロール");
				point.x=ttext.pointx;
				goto L1;
			case CHAR_IN_VIEWL:
				nslog(@"x画面内左スクロール");
				point.x=ttext.pointx;
				break;
			case CHAR_IN_VIEWR:
				nslog(@"x画面内右スクロール");
				point.x=ttext.pointx; // 一旦設定
				x++; // １つ右
				if ([ttext isYLeftSpace:x line:y]) {
					// これより右は全部スペースである＝次の行の先頭に戻す
					x=0;
					if (y<ttext.tlines) y++;
					if ([ttext isYCharYcheck:y scrollView:tehonScrollView]>CHAR_IN_VIEW) {
						nslog(@"上文字または改行");
						point.y=ttext.pointy;
					}
					point.x=ttext.offset.x;
				}
				nslog(@"新しい文字位置→(%d,%d)",(int)x,(int)y);
		}
	} // ftategaki
L1:;
#define ANIMETIME	0.5
//	nslog(@"→point=(%f,%f)",point.x,point.y); // 内部座標
	nslog(@"スクロールアニメーション");
	_tegakiView.hidden=YES; // UIViewを消す
	[_tegakiView performSelectorInBackground:@selector(imageSnapShot) withObject:nil]; // snapShotを並行動作処理；操作上劇的に高速化される
	// アニメーションしながらスクロール
	[UIView animateWithDuration:ANIMETIME
					 animations:^{ // アニメーション処理
						  tehonScrollView.contentOffset=point;
						 _tegakiScrollView.contentOffset=point;
					 }
					 completion:^(BOOL finished){ // 終了時処理
						 nslog(@"アニメーション終了:%d",finished);
						 [_tegakiView setNeedsDisplay];
						 _tegakiView.hidden=NO; // UIView表示
					 }
	 ];
	EnterRunLoop(0.0); // ループに入れないと動かない
}

// fscroll : YES=スクロール処理を行う
// ここでチェックするのはy方向のみ
-(BOOL)checkScrollArea:(CGPoint)point fscroll:(BOOL)fscroll
{
//	printSelf();
//	nslog(@"point=%f,%f",point.x,point.y);

	// スクロールエリアの判定;文字付属のスクロールエリアは文字上
	NSValue *val;
	CGRect rect;
	NSInteger y=[ttext getCharY:point];
	if (y==0) { // 最上行の特別処理
		val=ttext.scrollAreaArray[y];
		[val getValue:&rect];
		//printFrame(@"対象スクロールエリア(y=0)", rect);
		if (isPointInRect(point,rect)) {
			//nslog(@"最上行スクロールエリア内:%f,%f",point.x,point.y);
			if (fscroll) [self scrollViews:point y:-1];
			return (YES);
		}
		//nslog(@"y=0だけど最上行スクロールエリア内ではない");
	}
	val=ttext.scrollAreaArray[y+1]; // スクロール対象は文字の下の分
	[val getValue:&rect];
	//printFrame(@"対象スクロールエリア", rect);
	if (isPointInRect(point,rect)) {
		// 領域内なのでスクロールする
		//nslog(@"スクロールエリア内:%f,%f",point.x,point.y);
		if (fscroll) [self scrollViews:point y:y]; // x方向の判定はここで行う
		return(YES);
	}
	return (NO);
}

#ifdef UNDO_SCROLL
// ここでチェックするのはy方向のみ
-(BOOL)checkLineArea:(CGPoint)point
{
	printSelf();
	nslog(@"point=%f,%f",point.x,point.y);
	// 行エリアの判定
	NSInteger y=[ttext getCharY:point];
	NSValue *val=ttext.lineAreaArray[y];
	CGRect rect;
	[val getValue:&rect];
	if (isPointInRect(point,rect)) {
		// 領域内なのでスクロールする
		printFrame(@"行エリア",rect);
		nslog(@"行=%d",line);
		// そのスクロールエリアを得る
		val=scrollAreaArray[y];
		[val getValue:&rect];
		printFrame(@"スクロールエリア内", rect);
		point.y=rect.origin.y; // 文字に相当するスクロールエリアに移動
		[self scrollViews:point y:y]; // x方向の判定はここで行う
		return(YES);
	}
	return (NO);
}
#endif

//----------------------------------------------
// 画面回転
//----------------------------------------------

#pragma mark -画面回転

// 回転検出：回転前
// ここに来るのはiPadのみ（shouldAutorotateToInterfaceOrientationで調整してるから）
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
	printSelfs(@"Orientation=%d",(int)interfaceOrientation);
	// interfaceOrientationは新しい方向
	switch (interfaceOrientation) {
		default: // 警告回避のため
		case UIInterfaceOrientationPortrait:
		case UIInterfaceOrientationPortraitUpsideDown:
			nslog(@"縦方向");
			[self setButtonY:YES];
			break;
		case UIInterfaceOrientationLandscapeLeft:
		case UIInterfaceOrientationLandscapeRight:
			nslog(@"横方向");
			[self setButtonY:NO];
			break;
	}
}

// 回転検出：回転後
// ここに来るのはiPadのみ（shouldAutorotateToInterfaceOrientationで調整してるから）
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
	printSelfs(@"Orientation:%d",(int)fromInterfaceOrientation); /* 現在の方向 */
}

//----------------------------------------------
// 画面を回転して良いかどうか
//----------------------------------------------
// iOS6.0

-(BOOL)shouldAutorotate
{
	return shouldAutorotateByMain();
}

- (NSUInteger)supportedInterfaceOrientations
{
	return (supportedInterfaceOrientationsByMain());
}

//--------------------------------------
// 終了・異常時処理
//--------------------------------------

#ifdef DEBUG
- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
    
    // Relinquish ownership any cached data, images, etc that aren't in use.
}
#endif


@end
