/**********************************************************************
 
	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomoki SEKIYAMA <sekiyama@yahoo.co.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/



#include "v/v_types.h"
#include "v/v.h"

extern "C" {
#include "task.h"
#include "v.h"
#include "xl.h"
#include "init.h"
#include "memory_debug.h"

void init_vobj_function();
void init_WritingStyle(XLISP_ENV*);

#define __ASSERT__(a) if (!(a)) printf("asseertion failure at %s %d - %s\n", __FILE__, __LINE__, #a)

#include <stdio.h>

int test_main();

void init_VMacro()
{
}


VWindow *win, *win2;
VPushButton *btn1, *btn2, *btn3;
VCheckBox *chk;
VScrollView *scv;
VEditText *edit1, *edit2, *sp_fld;
VProgressBar *pbar;
VStaticText *stxt, *stxt2, *stxt3;
VDraw* draw3, *clip_draw;
VSplitView* split;
VBackColorView *bcv;
VFocusView *focusview = 0, *clip_focus;

bool btn3_alive = true;
bool anime_test_flag = true;


V_CALLBACK_D(test1)
{
	static char i=0;
	VObjectStatus sts;
	sts.padding.w = 10*(i%3);
	sts.padding.h = 10*(i%3);
	sts.alignv = sts.alignh = i%4;
	printf("---\n");
	printf("%d %d %d\n",sts.padding.w, sts.padding.h, sts.alignv);
	__ASSERT__( (object->set_status(&sts,
		VSF_PADDING | VSF_ALIGN)).code == V_ER_NO_ERR );
	i++;
}

void
test2_task()
{
	VObjectStatus s;
	char name[50];
	int c = 3;
	while ( c >= 0 ) {
		sprintf(name, "%d ...", c--);
		s.descriptor = l_string(&ascii_cm, name);
		btn3->set_status(&s,VSF_DESC);
		sleep_sec(1);
	}
	btn3->destroy();
}

V_CALLBACK_D(test2)
{
	create_task(test2_task,0,5);
}

void make_img3(VImage*, int);

void
test3_task()
{
	static int cnt = 1;
	VObjectStatus s;
	char name[50];
	for ( ; ; ) {
		if ( anime_test_flag ) {
			sprintf(name, "Count %d...", cnt++);
			s.descriptor = l_string(&sjis_cm, name);
			if ( (btn2->set_status(&s, VSF_DESC)).code < 0 )
				break;
			VImage *img3 = draw3->draw_start();
			if ( img3 ) {
				make_img3(img3, cnt%4);
				draw3->draw_end();
				draw3->redraw();
			}
		}
		sleep_sec(1);
	}
}

void
test3()
{
	create_task(test3_task,0,5);
}

V_CALLBACK_D(menu_test_1)
{
	printf("VMenuItem count = %d\n", VMenuItem::get_count());
}

V_CALLBACK_D(menu_test_sub_1)
{
	VObjectStatus sts;
	sts.size.w = sts.size.h = 300;
	object->set_status(&sts, VSF_SIZE);
}

V_CALLBACK_D(destroy_test)
{
	if ( object == btn3 )
		btn3_alive = 0;
}

V_CALLBACK_D(radio_test)
{
	VObjectStatus sts;
	object->get_status(&sts, VSF_VALUE);
	anime_test_flag = sts.value;
	sts.enabled = sts.value;
	btn1->set_status(&sts, VSF_ENABLED);
}

V_CALLBACK_D(slider_test)
{
	VObjectStatus sts;
	static int old = -1;
	object->get_status(&sts, VSF_VALUE);
	if ( old != sts.value ) {
		btn1->get_status(&sts, VSF_PARENT);
		sts.spacing.w = sts.spacing.h = sts.value;
		sts.parent->set_status(&sts, VSF_SPACING);
		old = sts.value;
	}
}

V_CALLBACK_D(popup_test)
{
	VObjectStatus sts;
	object->get_status(&sts, VSF_VALUE);
	if ( sts.value >= 0 && edit2 )
		edit2->set_status(&sts, VSF_VALUE);
	int num;
	L_CHAR **list;
	const LC_WRITING_STYLE **ws;
	((VPopupButton*)object)->get_list(&num, &list, &ws);
	sts.descriptor = list[sts.value];
	edit1->set_status(&sts, VSF_DESC);
}

V_CALLBACK_D(edit_test)
{
	VObjectStatus sts;
	object->get_status(&sts, VSF_DESC);
	if ( edit1 )
		edit1->set_status(&sts, VSF_DESC);
	if ( stxt )
		stxt->set_status(&sts, VSF_DESC);
	if ( stxt3 )
		stxt3->set_status(&sts, VSF_DESC);
}

V_CALLBACK_D(edit_test2)
{
	VObjectStatus sts;
	object->get_status(&sts, VSF_VALUE);
	printf("%s : value changed to %d\n", object->describe_self(), sts.value);
}

V_CALLBACK_D(tree_view_select_test)
{
	VTreeView *view = (VTreeView*)object;
	VTreeView::Selection *sel = view->get_selection();
	printf("%s selected =", object->describe_self());
	for ( int i = 0 ; i < sel->n ; i++ ) {
		VTreeNode *row = view->get_row(sel->keys[i]);
		printf(": %s ", n_string(std_cm, (L_CHAR*)row->data[1]));
		delete row;
	}
	delete sel;
	printf("\n");
}

V_CALLBACK_D(tree_view_row_edit_test)
{
	VTreeView::RowEdit *re = (VTreeView::RowEdit*)sys_arg;
	printf("%s row_edit : %s %d\n", object->describe_self(),
		n_string(std_cm, (L_CHAR*)re->node->data[1]), re->col);
}

unsigned char
pulse(short x, short w)
{
	return x<-w/6 ? 0 : x<=w/6 ? (x+w/6)*255/(w/3) : x<w/2 ? (w/2-x)*255/(w/3) : 0;
}

void
make_img(short w, short h, VImage *img)
{
	for ( int x = 0 ; x < w ; x++ ) {
		unsigned char r0,g0,b0;
		r0 = pulse(x,w)+pulse(x-w,w);
		g0 = pulse(x-w/3,w);
		b0 = pulse(x-w*2/3,w)+pulse(x+w/3,w);
		for ( int y = 0 ; y < h ; y++ ) {
			unsigned char r,g,b;
			r = (unsigned char)((double)r0*y/h);
			g = (unsigned char)((double)g0*y/h);
			b = (unsigned char)((double)b0*y/h);
			r = r*4 > 255 ? 255 : r*4;
			g = g*4 > 255 ? 255 : g*4;
			b = b*4 > 255 ? 255 : b*4;
			SET_RGB8_32(img->buf_32[x+img->w_border*y],r,g,b,
							RGB8_MAX);
		}
	}
}

void
make_img2(short w, short h, VImage *img)
{
	for ( int y = 0 ; y < h ; y++ )
		for ( int x = 0 ; x < w ; x++ )
			if ( (y/8%2) ^ (x/8%2) )
				SET_RGB8_32(img->buf_32[x+img->w_border*y],0xff,0xff,0xff,(y/8%2)?0x3f:RGB8_MAX);
			else
				SET_RGB8_32(img->buf_32[x+img->w_border*y],0,0,0,RGB8_MAX);
}

void
make_img3(VImage *img, int n)
{
	for ( int y = 0 ; y < 16 ; y++ )
		for ( int x = 0 ; x < 16 ; x++ )
			if ( (x >= 2+8*(n%2) && x <= 2+8*(n%2)+4) &&
				 (y >= 2+8*(n/2) && y <= 2+8*(n/2)+4) )
				SET_RGB8_32(img->buf_32[x+img->w_border*y],0,0,0,RGB8_MAX);
			else if ( x > 0 && y > 0 &&
					IS_RGB8_32(img->buf_32[(x-1)+img->w_border*(y-1)],0,0,0,RGB8_MAX) )
				SET_RGB8_32(img->buf_32[x+img->w_border*y],0,0,0,0x3f);
			else
				SET_RGB8_32(img->buf_32[x+img->w_border*y],0,0,0,0);
}

V_CALLBACK_D(resize_test)
{
VSize size = *(VSize*)sys_arg;
	printf("%s Resized : %d x %d\n", object->describe_self(), size.w, size.h);

	VImage *img = v_image_new(size.w, size.h, 32);
	v_image_draw_start(img, 0);
	make_img(size.w, size.h, img);
	v_image_draw_end(img);
	((VDraw*)object)->set_image(img);
	v_image_unref(img);
	object->redraw();
}


V_CALLBACK_D(mouse_test)
{
VMouseEvent* event = (VMouseEvent*)sys_arg;
	VObjectStatus s;
	chk->get_status(&s, VSF_VALUE);
	if ( s.value ) {
		printf("%s %3d x %3d %13s %c%c%c (mod : %x) @%8d\n",
			object->describe_self(), event->point.x, event->point.y,
			event->type==V_EV_MOUSE_DOWN ? "down" :
			event->type==V_EV_MOUSE_UP ? "up" :
			event->type==V_EV_MOUSE_MOVE ? "move" :
			event->type==V_EV_MOUSE_ENTER ? "enter" :
			event->type==V_EV_MOUSE_LEAVE ? "leave" :
			event->type==V_EV_MOUSE_DOUBLE_CLICK ? "double click" : "unknown",
			event->button & V_BUTTON_1 ? 'o' : '_',
			event->button & V_BUTTON_2 ? 'o' : '_',
			event->button & V_BUTTON_3 ? 'o' : '_',
			event->modifiers, (int)event->time);
	}
	static short x, y;
	if ( event->type == V_EV_MOUSE_DOWN && (event->button & V_BUTTON_2) ) {
		x = event->point.x;
		y = event->point.y;
	}
	if ( event->type == V_EV_MOUSE_MOVE && (event->button & V_BUTTON_2) ) {
		short xt = event->point.x;
		short yt = event->point.y;
		VImage *img = ((VDraw*)object)->draw_start();
		if ( img == 0 )
			return;
		long *buf = img->buf_32;
		short w = img->size.w;
		short h = img->size.h;
		short wb = img->w_border;
		VImage *img2 = v_image_new(w,h,32);
		v_image_draw_start(img2, 0);
		long *buf2 = img2->buf_32;

		short i,j,in;
		if ( buf ) {
			for ( i = 0 ; i < w ; i++ ) {
				in = i+xt-x;
				while ( in < 0 )
					in += w;
				while ( in >= w )
					in -= w;
				for ( j = 0 ; j < h ; j++ ) {
					buf2[in+j*wb] = buf[i+j*wb];
				}
			}
		}

		v_image_draw_end(img2);
		((VDraw*)object)->draw_end();
		((VDraw*)object)->set_image(img2);
		v_image_unref(img2);
		object->redraw();
		x = xt;
		y = yt;
	}
	if ( btn3_alive && event->type == V_EV_MOUSE_MOVE && (event->button & V_BUTTON_1) ) {
		VImage* img = ((VDraw*)object)->draw_start();
		unsigned char r,g,b,a;
		if ( event->point.x >= 0 && event->point.y >= 0 &&
				img->size.w > event->point.x && img->size.h > event->point.y ) {
			GET_RGB8_32(img->buf_32[event->point.x+img->w_border*event->point.y],r,g,b,a);
			((VDraw*)object)->draw_end();
			char buf[50];
			sprintf(buf, "R:%02x G:%02x B:%02x", r, g, b);
			VObjectStatus s;
			s.vert_desc = 0;
			s.descriptor = l_string(&ascii_cm, buf);
			if ( btn3_alive )
				btn3->set_status(&s, VSF_DESC|VSF_VERTD);
		}
		else
			((VDraw*)object)->draw_end();
	}
}

V_CALLBACK_D(progress_bar_test)
{
	static int s = 0;
	char buf[10];
	VObjectStatus sts;
	if ( ++s == 4 )
		s = 0;
	sts.value = s*50 - 70;
	sprintf(buf, "%d%%", sts.value);
	sts.descriptor = l_string(std_cm, buf);
	pbar->set_status(&sts, VSF_VALUE | VSF_DESC);
}

V_CALLBACK_D(choose_file_test)
{
	char *normalized_path = v_choose_file(l_string(std_cm,"Open File"));
	if ( normalized_path ) {
		char *machine_path = change_delim_str(normalized_path);
		VObjectStatus s;
		s.descriptor = l_string(std_cm, machine_path);
		stxt2->set_status(&s, VSF_DESC);
		d_f_ree(machine_path);
		d_f_ree(normalized_path);
	}
}

V_CALLBACK_D(split_hide_test)
{
	static int st = 0;
	if ( st ) {
		st = 0;
		split->show_pane((int)user_arg,-1);
		printf("show\n");
	}
	else {
		st = 1;
		split->hide_pane((int)user_arg,-1);
		printf("hide\n");
	}
}

V_CALLBACK_D(split_ch_value_test)
{
	VObjectStatus s;
	split->get_status(&s, VSF_VALUE);
	sp_fld->set_status(&s, VSF_VALUE);
	printf("split value : %d\n", s.value);
}

V_CALLBACK_D(split_ch_value_test_b)
{
	VObjectStatus s;
	sp_fld->get_status(&s, VSF_VALUE);
	split->set_status(&s, VSF_VALUE);
}

int back_color_cnt = 0;

V_CALLBACK_D(back_color_test)
{
	back_color_cnt = (back_color_cnt + 1) % 3;
	VObjectStatus sts;
	switch ( back_color_cnt ) {
	  case 0:
		SET_RGB8_32(sts.attr, 0xff, 0xcc, 0x99, 0xff);
		break;
	  case 1:
		SET_RGB8_32(sts.attr, 0xcc, 0x99, 0xff, 0xff);
		break;
	  case 2:
		SET_RGB8_32(sts.attr, 0x00, 0x00, 0x00, 0x00);
		break;
	}
	bcv->set_status(&sts, VSF_ATTR);

	if ( focusview )
		focusview->focus();
}

V_CALLBACK_D(focus_view_test_command_status)
{
int fflag = 0;
	if ( back_color_cnt != 2 )
		fflag = VMF_COPY;

	if ( VdataLString::clipboard_available() )
		fflag |= VMF_PASTE;

	if ( focusview )
		focusview->set_editable_flags(fflag);
}

V_CALLBACK_D(focus_view_test_obey_command)
{
int type;
	type = *(int*)sys_arg;
printf("focus_view_test_obey_command %d\n",type);
	if ( type == VMT_PASTE ) {
		VdataLString *lstr = VdataLString::new_from_clipboard();
		VObjectStatus sts;
		sts.descriptor = (const L_CHAR*)lstr->get_VdataLString();
		stxt->set_status(&sts, VSF_DESC);
	}
	if ( back_color_cnt != 2 && type == VMT_COPY ) {
		VdataLString * str = new VdataLString(back_color_cnt ? 
			l_string(std_cm,"#cc99ff") : l_string(std_cm,"#ffcc99"));
		str->store_into_clipboard();
	}
}

V_CALLBACK_D(stop_running)
{
printf("stop_running\n");
	vobject_quit();
}

int menu_test_sub2, menu_update;

V_CALLBACK_D(test_beep)
{
	vobject_beep();
}

void
register_menu_bar()
{
	VMenuItem *menu, *menus;
	menus = menu = new VMenuItem(VMT_FILE, VMF_ENABLED, "File", 0, 0, 0, 'F', 0);
	menu->append(new VMenuItem(VMT_OTHER, VMF_ENABLED, "New...", 0, V_MODKEY_CTRL, 'n', 'N', 0));
	menu->append(new VMenuItem(VMT_OTHER, VMF_ENABLED, "Open...", 0, V_MODKEY_CTRL, 'o', 'O', 0));
	menu->append(new VMenuItem(VMT_CLOSE, 0, "Close", 0, V_MODKEY_CTRL, 'w', 'C', 0));
	menu->append(new VMenuItem(VMT_SEPARATOR, 0, 0, 0, 0, 0, 0, 0));
	menu->append(new VMenuItem(VMT_OTHER, VMF_ENABLED, "Save", 0, V_MODKEY_CTRL, 's', 'S', 0));
	menu->append(new VMenuItem(VMT_OTHER, VMF_ENABLED, "Save As...", 0, V_MODKEY_SHIFT | V_MODKEY_CTRL, 's', 'A', 0));
	menu->append(new VMenuItem(VMT_SEPARATOR, 0, 0, 0, 0, 0, 0, 0));
	menu->append(new VMenuItem(VMT_QUIT, VMF_ENABLED, "Quit", 0, V_MODKEY_CTRL, 'q', 'Q', 0));

	menu = new VMenuItem(VMT_EDIT, VMF_ENABLED, "Edit", 0, 0, 0, 'E', 0);
	menus->append_to_list(menu);
	menu->append(new VMenuItem(VMT_UNDO, 0, "Undo", 0, V_MODKEY_CTRL, 'z', 0, 0));
	menu->append(new VMenuItem(VMT_REDO, 0, "Redo", 0, V_MODKEY_CTRL|V_MODKEY_SHIFT, 'z', 0, 0));
	menu->append(new VMenuItem(VMT_SEPARATOR, 0, 0, 0, 0, 0, 0, 0));
	menu->append(new VMenuItem(VMT_CUT, 0, "Cut", 0, V_MODKEY_CTRL, 'x', 'u', 0));
	menu->append(new VMenuItem(VMT_COPY, 0, "Copy", 0, V_MODKEY_CTRL, 'c', 'C', 0));
	menu->append(new VMenuItem(VMT_PASTE, 0, "Paste", 0, V_MODKEY_CTRL, 'v', 'P', 0));
	menu->append(new VMenuItem(VMT_CLEAR, 0, "Clear", 0, 0, 0, 0, 0));
	menu->append(new VMenuItem(VMT_SEL_ALL, 0, "Select All", 0, V_MODKEY_CTRL, 'a', 'A', 0));
	menu->append(new VMenuItem(VMT_SEPARATOR, 0, 0, 0, 0, 0, 0, 0));
	menu->append(new VMenuItem(VMT_SETUP, VMF_ENABLED, "Preferences...", 0, V_MODKEY_CTRL, ',', 'P', test_beep));

	menu = new VMenuItem(VMT_WINDOW, VMF_ENABLED, "Window", 0, 0, 0, 'W', 0);
	menus->append_to_list(menu);

	menu = new VMenuItem(VMT_OTHER, VMF_ENABLED, "Test", 0, 0, 0, 'x', 0);
	menus->append_to_list(menu);
	menu->append(new VMenuItem(VMT_OTHER, VMF_ENABLED, "Test1", 0, V_MODKEY_CTRL, '1', '1', menu_test_1));
	menu->append(new VMenuItem(VMT_OTHER, 0, "Test2", 0, V_MODKEY_CTRL, '2', '2', 0));

	new VMenuBar(menus, 0, true);
	
	
	menus = menu = new VMenuItem(VMT_FILE, VMF_ENABLED, "File", 0, 0, 0, 'F', 0);
	menus->append_to_list(menu);
	menu->append(new VMenuItem(VMT_CLOSE, 0, "Close", 0, V_MODKEY_CTRL, 'w', 'C', 0));
	VMenuItem *update_menu;
	menu->append(update_menu = new VMenuItem(VMT_OTHER, 0, "Update", 0, 0, V_MODKEY_CTRL, 'U', 0));
	menu_update = update_menu->get_id();

	menu = new VMenuItem(VMT_OTHER, VMF_ENABLED, "Sub", 0, 0, 0, 0, 0);
	menus->append_to_list(menu);
	menu->append(new VMenuItem(VMT_OTHER, VMF_ENABLED, "Sub1", 0, 0, 0, 0, menu_test_sub_1));
	VMenuItem *sub2;
	menu->append(sub2 = new VMenuItem(VMT_OTHER, 0, "Sub2", 0, 0, 0, 0, 0));
	menu_test_sub2 = sub2->get_id();
	sub2->append(new VMenuItem(VMT_OTHER, 0, "SEL1", 0, 0, 0, 0, 0));
	sub2->append(menu=new VMenuItem(VMT_OTHER, VMF_ENABLED, "SEL2", 0, 0, 0, 0, 0));
	menu->append(new VMenuItem(VMT_OTHER, 0, "SEL2-1", 0, 0, 0, 0, 0));
	menu->append(new VMenuItem(VMT_OTHER, VMF_ENABLED, "SEL2-2", 0, 0, 0, 0, 0));

	new VMenuBar(menus, 1, false);
}


void
make_table()
{
	VExError err;
	VObjectStatus sts;
	sts.attr = VWindow::resizable;
	sts.descriptor = l_string(&ascii_cm, "VTreeView");
	sts.spacing.w = sts.spacing.h = 0;
	sts.parent = VWindow::create(&sts, VSF_DESC | VSF_ATTR | VSF_SPACING, -1);
	sts.alignh = sts.alignv = VALIGN_FILL;
	sts.padding.w = sts.padding.h = 0;
	sts.attr = VTreeView::select_multi | VTreeView::scrollbar_v | VTreeView::size_box_area;
	char types[] = {VTT_BOOL|VTT_EDITABLE, VTT_TEXT, VTT_TEXT|VTT_EDITABLE, VTT_PERC};
	const L_CHAR *title[] = {
		l_string(&sjis_cm, "abstract"),
		l_string(&sjis_cm, "クラス"),
		l_string(&sjis_cm, "概要"),
		l_string(&sjis_cm, "%")};
	short widths[] = {20, 120, 400, 110};
	sts.min_size.w = 700;
	sts.min_size.h = 120;
	VTreeView *list = VTreeView::create(&sts, VSF_PARENT | VSF_ALIGN | VSF_ATTR 
			| VSF_PADDING | VSF_MIN_SIZE, 
		4, types, title, widths, &err);
	
	VTreeNode n(4);
	n.editable = 1;
	
	n.key = (void*)1;
	n.data[0] = VTF_TRUE;
	n.data[1] = l_string(&ascii_cm, "VObject");
	n.data[2] = l_string(&sjis_cm, "GUI部品の基底クラス");
	n.data[3] = (void*)30;
	list->add_row(&n);
	
	n.key = (void*)2;
	n.data[0] = VTF_TRUE;
	n.data[1] = l_string(&ascii_cm, "VButton");
	n.data[2] = l_string(&sjis_cm, "ボタン類の基底クラス");
	n.data[3] = (void*)45;
	list->add_row(&n, (void*)1);
	
	n.key = (void*)3;
	n.data[0] = VTF_FALSE;
	n.data[1] = l_string(&ascii_cm, "VPushButton");
	n.data[2] = l_string(&sjis_cm, "プッシュボタン");
	n.data[3] = (void*)40;
	list->add_row(&n, (void*)2);
	
	n.key = (void*)4;
	n.data[1] = l_string(&ascii_cm, "VRadioButton");
	n.data[2] = l_string(&sjis_cm, "ラジオボタン");
	n.data[3] = (void*)50;
	list->add_row(&n, (void*)2);
	
	n.key = (void*)5;
	n.data[1] = l_string(&ascii_cm, "VCheckBox");
	n.data[2] = l_string(&sjis_cm, "チェックボックス");
	n.data[3] = (void*)40;
	list->add_row(&n, (void*)2, (void*)4);
	
	n.key = (void*)6;
	n.data[1] = l_string(&ascii_cm, "VTreeView");
	list->add_row(&n, (void*)1, (void*)2);
	
	n.key = (void*)7;
	n.data[1] = l_string(&ascii_cm, "VMenuBar");
	n.data[2] = l_string(&sjis_cm, "ウィンドウカテゴリごとにメニューを管理");
	n.data[3] = (void*)80;
	list->add_row(&n, 0, (void*)1);
	
	n.key = (void*)8;
	n.data[1] = l_string(&ascii_cm, "VCustomizedMenuBar");
	n.data[2] = l_string(&sjis_cm, "各ウィンドウに対応するメニュー");
	n.data[3] = (void*)100;
	list->add_row(&n, (void*)7);
	
	VTreeNode n2(4, *list->get_row((void*)6));
	n2.editable = 0;
	n2.data[2] = l_string(&sjis_cm, "aa");
	n2.data[3] = (void*)50;
	list->set_row(&n2);
	
	list->debug_print();
	
	list->set_select_event_handler(tree_view_select_test, 0);
	list->set_row_edit_event_handler(tree_view_row_edit_test, 0);
}

V_CALLBACK_D(clip_draw_mouse)
{
VMouseEvent* event = (VMouseEvent*)sys_arg;
	if ( event->type==V_EV_MOUSE_DOWN )
		clip_focus->focus();
}

V_CALLBACK_D(clip_command_status)
{
	clip_focus->set_editable_flags(VMF_CUT | VMF_COPY | VMF_PASTE | VMF_CLEAR);
}

V_CALLBACK_D(clip_obey_command)
{
	VImage *_img;
	VdataImage *img;
	static short s = 64;
	switch ( *(int*)sys_arg ) {
	  case VMT_COPY:
		_img = clip_draw->get_image();
	  	if ( _img ) {
			img = new VdataImage(_img);
			img->store_into_clipboard();
			v_image_unref(_img);
		}
		break;
	  case VMT_CUT:
		_img = clip_draw->get_image();
	  	if ( _img ) {
			img = new VdataImage(_img);
			img->store_into_clipboard();
			v_image_unref(_img);

			s = (s==64)?128:64;
			_img = v_image_new(s, s, 32);
			v_image_draw_start(_img, 0);
			make_img2(s, s, _img);
			v_image_draw_end(_img);
			
			clip_draw->set_image(_img,_img->size);
			clip_draw->redraw();
		}
		break;
	  case VMT_PASTE:
	  	if ( VdataImage::clipboard_available() ) {
			img = VdataImage::new_from_clipboard();
			_img = img->get_VdataImage();
			__ASSERT__( clip_draw->set_image(_img, _img->size) == V_ER_NO_ERR );
			clip_draw->redraw();
		}
		break;
	  case VMT_CLEAR:
		s = (s==64)?128:64;
		_img = v_image_new(s, s, 32);
		v_image_draw_start(_img, 0);
		make_img2(s, s, _img);
		v_image_draw_end(_img);
		
		clip_draw->set_image(_img,_img->size);
		clip_draw->redraw();
		break;
	}

}

VWindow *
make_image_clip_window()
{
	VWindow *win;
	VObjectStatus sts;
	VExError err;
	sts.descriptor = l_string(&sjis_cm, "Image Clip");
	sts.spacing.w = sts.spacing.h = 10;
	sts.parent = win = VWindow::create(&sts, VSF_DESC|VSF_SPACING);
	
	sts.alignh = sts.alignv = VALIGN_FILL;
	sts.parent = clip_focus = VFocusView::create(&sts, VSF_ALIGN|VSF_PARENT);
	clip_focus->set_obey_command_handler(clip_obey_command, 0);
	clip_focus->set_command_status_handler(clip_command_status, 0);
	
	VImage *img = v_image_new(64, 64, 32);
	v_image_draw_start(img, 0);
	make_img2(64, 64, img);
	v_image_draw_end(img);
	
	sts.padding.w = sts.padding.h = 4;
	clip_draw = VDraw::create(&sts, VSF_PARENT | VSF_ALIGN | VSF_PADDING, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	__ASSERT__( clip_draw->set_image(img, img->size) == V_ER_NO_ERR );
	v_image_unref(img);
	clip_draw->redraw();
	clip_draw->set_mouse_event_handler(clip_draw_mouse, 0);
	
	return win;
}

int
test_main()
{
	register_menu_bar();
	
	VVAlignView *gv;
	VHAlignView *gh;
	
	VObjectStatus sts;
	VExError err;
	
	LC_WRITING_STYLE *default_ws = get_ws(l_string(std_cm,"DefaultStyle"));
	
	make_image_clip_window();
	
	make_table();
	sts.padding.w = sts.padding.h = 0;
	sts.spacing.w = sts.spacing.h = 0;
	sts.alignh = sts.alignv = VALIGN_FILL;
	sts.attr = VWindow::resizable;
	sts.descriptor = l_string(&ascii_cm, "Category 1 (1)");
	sts.parent = win = VWindow::create(&sts, VSF_ATTR | VSF_DESC | VSF_SPACING, 1);
	sts.parent = gv = VVAlignView::create(&sts, VSF_PARENT | VSF_ALIGN | VSF_PADDING | VSF_SPACING);
	sts.alignv = VALIGN_TOP;
	sts.parent = VHAlignView::create(&sts, VSF_PARENT | VSF_ALIGN);
	sts.alignh = VALIGN_LEFT;
	VStaticText::create(&sts, VSF_PARENT | VSF_DESC | VSF_ALIGN);
	sts.attr = VEditText::integer_only;
	sp_fld = VEditText::create(&sts, VSF_PARENT | VSF_ALIGN | VSF_ATTR, 5, 5);
	sts.value_event_handler = split_ch_value_test_b;
	sts.descriptor = l_string(&ascii_cm, "Set");
	VPushButton::create(&sts, VSF_PARENT | VSF_DESC | VSF_ALIGN | VSF_VALUE_EH);
	sts.parent = gv;
	sts.alignh = VALIGN_FILL;
	VHSeparator::create(&sts, VSF_PARENT | VSF_ALIGN | VSF_PADDING);
	sts.alignv = VALIGN_FILL;
	sts.attr = VSplitView::shrinkable0 | VSplitView::shrinkable1 | VSplitView::expand0_on_resize;
	sts.value_event_handler = split_ch_value_test;
	sts.parent = split = VHSplitView::create(&sts,
			VSF_PARENT | VSF_ALIGN | VSF_ATTR | VSF_PADDING | VSF_VALUE_EH, 140, 300);
	// pane 0
	sts.descriptor = l_string(&ascii_cm, "Pane 0");
	/*VObject* g1 = */sts.parent = VGroupBox::create(&sts, VSF_PARENT | VSF_DESC | VSF_ALIGN);
	sts.descriptor = l_string(&ascii_cm, "Show/Hide 1");
	sts.value_event_handler = split_hide_test;
	sts.value_eh_arg = (void*)1;
	VPushButton::create(&sts, VSF_PARENT | VSF_DESC | VSF_VALUE_EH);
	// pane 1
	sts.parent = split;
	sts.descriptor = l_string(&ascii_cm, "Pane 1");
	sts.parent = VGroupBox::create(&sts, VSF_PARENT | VSF_DESC);
	sts.descriptor = l_string(&ascii_cm, "Show/Hide 0");
	sts.value_event_handler = split_hide_test;
	sts.value_eh_arg = 0;
	VPushButton::create(&sts, VSF_PARENT | VSF_DESC | VSF_VALUE_EH);
	//VStaticText::create(&sts, VSF_PARENT | VSF_DESC);
	//
	//g1->destroy();
	win->get_menu_bar()->set_menu_name(menu_update, l_string(&ascii_cm, "update 1"));
	
	sts.attr = VWindow::resizable;
	sts.descriptor = l_string(&ascii_cm, "Category 1 (2)");
	sts.parent = win = VWindow::create(&sts, VSF_ATTR | VSF_DESC, 1);
	win->get_menu_bar()->set_menu_flag(menu_test_sub2, VMF_ENABLED | VMF_FLAGGED);
	win->get_menu_bar()->set_menu_name(menu_update, l_string(&ascii_cm, "update 1-2"));

	const L_CHAR *labels[] = {l_string(&ascii_cm, "Category 1"), l_string(&ascii_cm, "Window2")};
	VTabView* tab = VTabView::create(&sts, VSF_PARENT | VSF_ALIGN, 2, labels);
	
	sts.parent = tab->get_page(0);
	sts.descriptor = l_string(std_cm, "VChooseFile");
	sts.parent = VGroupBox::create(&sts, VSF_PARENT | VSF_DESC);
	
	sts.parent = VVAlignView::create(&sts, VSF_PARENT);
	
	sts.descriptor = l_string(&sjis_cm, "ファイルを選択..");
	sts.value_event_handler = choose_file_test;
	VPushButton::create(&sts, VSF_PARENT | VSF_DESC | VSF_VALUE_EH);
	
	stxt2 = VStaticText::create(&sts, VSF_PARENT); 
	
	sts.parent = tab->get_page(1);
	VEditText::create(&sts, VSF_PARENT, 10);
	
	sts.descriptor = l_string(&sjis_cm, "デフォルトでない");
	VPushButton::create(&sts, VSF_PARENT | VSF_DESC);
	
	sts.descriptor = l_string(&sjis_cm, "デフォルト");
	sts.attr = VPushButton::default_button;
	sts.attr |= VPushButton::cancel_button;
	sts.value_event_handler = progress_bar_test;
	VPushButton::create(&sts, VSF_PARENT | VSF_DESC | VSF_VALUE_EH | VSF_ATTR);

	sts.value = -1;
	sts.alignh = VALIGN_FILL;
	sts.alignv = VALIGN_EXPAND;
	pbar = VProgressBar::create(&sts, VSF_PARENT | VSF_VALUE | VSF_ALIGN, &err);



	sts.attr = VWindow::resizable;
	sts.descriptor = l_string(&sjis_cm, "VObjects テスト");
	sts.visible = false;
	sts.padding.w = 6;
	sts.padding.h = 6;
	sts.parent = win = VWindow::create(&sts, VSF_ATTR | VSF_DESC | VSF_VISIBLE | VSF_PADDING, 0);
	win->set_window_close_handler(stop_running,0);

	sts.alignh = sts.alignv = VALIGN_FILL;

	sts.parent = gh = VHAlignView::create(&sts, VSF_PARENT | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.homogeneous = 0;
	sts.alignh = VALIGN_LEFT;
	sts.parent = VVAlignView::create(&sts, VSF_PARENT | VSF_HOMOGEN | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );

	char name0[] = {0xc6,0xfc,0xcb,0xdc, 0xb8,0xec,0x0a,0xc9,0xbd,0xbc,0xa8,0};
	sts.descriptor = l_string(&euc_cm, name0);
	sts.vert_desc = 1;
	sts.value_event_handler = test1;
	btn1 = VPushButton::create(&sts, VSF_ALIGN|VSF_VALUE_EH|VSF_PARENT|VSF_DESC|VSF_VERTD, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );

	btn1 = VPushButton::create(&sts, VSF_VALUE_EH | VSF_PARENT | VSF_DESC | VSF_VERTD, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );

	sts.parent = gh;
	
	VVSeparator::create(&sts, VSF_PARENT | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.alignh = sts.alignv = VALIGN_FILL;
	sts.parent = gv = VVAlignView::create(&sts,VSF_PARENT | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );

	sts.alignv = VALIGN_TOP;
	sts.parent = VHAlignView::create(&sts,VSF_PARENT | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );

	sts.descriptor = l_string(&sjis_cm, "コピー↓");
	sts.descriptor_event_handler = edit_test;
	VEditText::create(&sts, VSF_PARENT | VSF_ALIGN | VSF_DESC_EH | VSF_DESC , 100, 10, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );

	sts.attr = VEditText::integer_only;
	sts.value = 100;
	sts.value_event_handler = edit_test2;
	edit2 = VEditText::create(&sts, VSF_PARENT | VSF_ALIGN | VSF_ATTR | VSF_VALUE | VSF_VALUE_EH, 3, 3, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );

	sts.parent = gv;

	sts.ws = default_ws;
	sts.fsize = 240;
	edit1 = VEditText::create(&sts, VSF_PARENT | VSF_ALIGN | VSF_FSIZE | VSF_WS, 1000, 10, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.descriptor = l_string(&sjis_cm,"テスト1　表\示");
	btn2 = VPushButton::create(&sts, VSF_PARENT | VSF_DESC | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.value_event_handler = test2;
	sts.destroy_handler = destroy_test;
	sts.descriptor = l_string(&sjis_cm,"TEST2");
	sts.attr = VPushButton::default_button;
	btn3 = VPushButton::create(&sts, VSF_PARENT | VSF_DESC | VSF_ALIGN | VSF_VALUE_EH | VSF_DESTROY_H | VSF_ATTR, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.descriptor = l_string(&sjis_cm,"enable button below");
	sts.attr = VGroupBox::secondary;
	sts.parent = VGroupBox::create(&sts,VSF_PARENT | VSF_ALIGN | VSF_DESC | VSF_ATTR, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	SET_RGB8_32(sts.attr, 0x66, 0x99, 0xff, 0xff);
	sts.parent = VHAlignView::create(&sts, VSF_PARENT, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	VRadioButton *radio1, *radio2;
	
	sts.descriptor = l_string(&ascii_cm,"ON");
	sts.value_event_handler = radio_test;
	radio1 = VRadioButton::create(&sts, VSF_PARENT | VSF_DESC | VSF_VALUE_EH, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );

	sts.descriptor = l_string(&ascii_cm,"OFF");
	sts.value_event_handler = radio_test;
	radio2 = VRadioButton::create(&sts, VSF_PARENT | VSF_DESC, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	radio2->set_radio_group(radio1);
	
	sts.value = 0;
	sts.value_event_handler = popup_test;
	VPopupButton* pb = VPopupButton::create(&sts, VSF_PARENT | VSF_VALUE | VSF_VALUE_EH, &err);
	const L_CHAR *list[4] = {l_string(&ascii_cm, "English"), l_string(&ascii_cm, "Deutsche"), 0, l_string(&sjis_cm, "日本語(Japanese)")};
	pb->set_list(4, list);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.parent = gv;
	
	sts.value = 128;
	sts.value_event_handler = slider_test;
	VSlider::create(&sts,
		VSF_PARENT|VSF_VALUE|VSF_VALUE_EH|VSF_ALIGN, 0, 300, 10, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.alignh = sts.alignv = VALIGN_FILL;
	sts.parent = focusview = VFocusView::create(&sts,
		VSF_PARENT | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	focusview->set_command_status_handler(focus_view_test_command_status, 0);
	focusview->set_obey_command_handler(focus_view_test_obey_command, 0);
	
	sts.alignh = sts.alignv = VALIGN_FILL;
	SET_RGB8_32(sts.attr, 0x66, 0x99, 0xff, 0xff);
	sts.value_event_handler = back_color_test;
	sts.padding.w = sts.padding.h = 0;
	sts.parent = bcv = VBackColorView::create(&sts, VSF_PARENT | VSF_ATTR | VSF_ALIGN | VSF_VALUE_EH | VSF_PADDING, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );

	VTableView *table;
	sts.parent = table = VTableView::create(&sts,
		VSF_PARENT | VSF_ALIGN, 2, 2, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	VObject *c;
	
	sts.alignh = sts.alignv = VALIGN_EXPAND;
	sts.descriptor = l_string(&sjis_cm,"<VTableView>");
	c = stxt = VStaticText::create(&sts, VSF_PARENT | VSF_DESC | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	err = table->attach_child(c, 0, 0);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.parent = table;
	sts.descriptor = l_string(&sjis_cm,"<VTableView>");
	c = VCheckBox::create(&sts, VSF_PARENT | VSF_DESC | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	err = table->attach_child(c, 1, 0);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.descriptor = l_string(&sjis_cm,"縦書き");
	c = stxt3 = VStaticText::create(&sts,
		VSF_PARENT | VSF_DESC | VSF_VERTD | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	err = table->attach_child(c, 0, 1, 2, 1);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.parent = gv;
	sts.alignh = VALIGN_FILL;
	sts.alignv = VALIGN_TOP;
	VHSeparator::create(&sts, VSF_PARENT | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.descriptor = l_string(&sjis_cm,"VImageイベントを表\示");
	chk = VCheckBox::create(&sts, VSF_PARENT | VSF_DESC | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	sts.value = true;
	__ASSERT__( chk->set_status(&sts, VSF_VALUE).code == V_ER_NO_ERR );
	
	const int w = 120, h = 50;

	sts.alignv = VALIGN_FILL;
	sts.min_size.w = sts.min_size.h = 100;
	sts.spacing.w = sts.spacing.h = 0;
	sts.attr = VScrollView::h_always + VScrollView::v_automatic;
	sts.parent = scv = VScrollView::create(&sts,
			VSF_PARENT | VSF_ATTR | VSF_ALIGN | VSF_MIN_SIZE | VSF_SPACING, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	VSize size0 = {w*2,h*3};
	scv->set_internal_size(size0);

	VImage *img = v_image_new(w, h, 32);
	v_image_draw_start(img, 0);
	make_img(w, h, img);
	v_image_draw_end(img);
	
	sts.padding.w = sts.padding.h = 0;
	VDraw* draw = VDraw::create(&sts, VSF_PARENT | VSF_ALIGN | VSF_PADDING, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	__ASSERT__( draw->set_image(img, img->size) == V_ER_NO_ERR );
	v_image_unref(img);
	draw->redraw();
	draw->set_mouse_event_handler(mouse_test, 0);
	draw->set_resize_event_handler(resize_test, 0);

	img = v_image_new(w, h, 32);
	v_image_draw_start(img, 0);
	make_img(w, h, img);
	v_image_draw_end(img);

	VImage *img2 = v_image_new(w, h, 32);
	v_image_draw_start(img2, 0);
	make_img2(w, h, img2);
	v_image_draw_end(img2);

	VImage *img3 = v_image_new(16, 16, 32);
	v_image_draw_start(img3, 0);
	make_img3(img3, 0);
	v_image_draw_end(img3);

	sts.parent = gv;
	sts.alignv = VALIGN_BOTTOM;
	sts.parent = VHAlignView::create(&sts, VSF_PARENT | VSF_ALIGN, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	
	sts.attr = VexDraw::press_img_zero | VDraw::use_alpha;
	sts.alignh = VALIGN_FILL;
	VexDraw* draw2 = VexDraw::create(&sts, VSF_PARENT | VSF_ALIGN | VSF_ATTR, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	VImage *imgs[] = {img, img2};
	__ASSERT__( draw2->set_images(2, imgs, img->size) == V_ER_NO_ERR );

	sts.attr = VDraw::use_alpha;
	sts.alignh = VALIGN_RIGHT;
	draw3 = VDraw::create(&sts, VSF_PARENT | VSF_ALIGN | VSF_ATTR, &err);
	__ASSERT__( err.code == V_ER_NO_ERR );
	__ASSERT__( draw3->set_image(img3, img3->size) == V_ER_NO_ERR );
	
	draw2->redraw();
	draw2->set_mouse_event_handler(mouse_test, 0);

	v_image_unref(img);
	
	test3();
	
	sts.visible = true;
	win->set_status(&sts, VSF_VISIBLE);
		
	return 0;
}

int
_main(int argc, char **argv)
{
XL_INTERPRETER * xli;
	init_xl(INI_DONTWAITCHI);
	init_function(
		gblisp_top_env0,
		gblisp_top_env1,
		argc,
		argv);
	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);

	vobject_init(&argc, &argv);
	init_vobj_function();
	init_WritingStyle(gblisp_top_env0);
	
	if ( argc == 1 )
		test_main();
	else if ( argc == 2 ) {
		L_CHAR * file_l;
		XLISP_ENV * e;
		XL_SEXP * ret;
		
		gc_push(0,0,"load_parameter");
		
		e = new_env(gblisp_top_env1);
		
		file_l = l_string(std_cm,argv[1]);
		ret = load_file(e,0,2,file_l,0,0,0,0,0);
		fflush(stdout);
		ss_printf("Result :: ");
		print_sexp(s_stdout,ret,0);
		ss_printf("\n");
		gc_pop(0,0);
	}
	
	printf("start vobject_main\n");
	
	return vobject_main();
}


// start up code for Macintosh
void call__main()
{
	int argc = 1;
	char *argv[2];
	argv[0] = copy_str("VApplication");

	char *path = v_choose_file(l_string(std_cm,"Open XL File"));
	if ( path ) {
		argv[1] = path;
		argc++;
	}

	_main(argc,argv);
}


} // extern "C"

