
#include <fcntl.h>
#include <IV-look/fchooser.h>
#include <IV-look/field.h>
#include <IV-look/kit.h>
#include <InterViews/input.h>
#include <InterViews/cursor.h>
#include <InterViews/event.h>
#include <InterViews/layout.h>
#include <InterViews/action.h>
#include <InterViews/dialog.h>
#include <InterViews/target.h>
#include <InterViews/resource.h>
#include <InterViews/session.h>
#include <InterViews/window.h>
#include <InterViews/monoglyph.h>
#include <InterViews/coord.h>
#include <InterViews/canvas.h>

#include <OS/string.h>
#include <OS/file.h>
#include <stdlib.h>
#include "usrprompt.h"
#include "plotdatg.h"
#include "iv_graph.h"
#include "prmpt_diag.h"
#include <X11/keysym.h>
#include "helpwin.h"
#include "txtwin.h"
#include "netdescg.h"
#include "menmgr.h"
#include "genmenu.h"

class RootMenuView ;
class StringList ;


#include "xgui.h"
#include "xdrv.h"
#include <InterViews/leave-scope.h>
#include <Dispatch/leave-scope.h>
#include "dsp_app.h"


#include <InterViews/leave-scope.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include "callback.h"
#include "help.h"
#include "menu.h"
#include "cgidbg.h"
#include "shared.h"
#include "remcom.h"
#include "hlpfil.h"
#include "mkstr.h"
#include "intfccom.h"
#include "intfccomg.h"
#include "guistate.h"
#include "menstck.h"
#include <InterViews/leave-scope.h>
#include <OS/leave-scope.h>
#include "environ.h"


void RPC_Callback(char* ) 
{
	// LogOut << "Callback(" << string << ")\n" ;
	RootMenuView * root_window = DspApplication::root_window();
	int call = 1 ;
	if (root_window) if (!root_window->check_remote()) call = 0 ;
	if (call) {
		int read = ReadSeg->CheckPacketRead();
		// if (read) for (int i = 0 ; i < 20; i++) ReadSeg->CheckPacketRead();
	}
}

static int ReadStateCommon()
{
	if (DspState->BusyAbort("read a state file")) return 1 ;
	DspState->ReadStateBusy();
	return 0 ;
}

void RootMenuView::help_info_string(const char * string)
{
	if(string) if (*string) info_strings.Append(Concatenate(string));
}


void RootMenuView::flush_help_info()
{
	char * str ;
	while (str = info_strings.Get()) delete str ;
}


void RootMenuView::write_help_info()
{
	if (!info_strings.Size()) return ;
	help_display->replace_page(info_strings);
	new_help_page();
}


const char * RootMenuView::get_file_name(const char * prompt, const char * def,
	const char * pattern, int check_suffix, ivWindow * win)
{
	if (!win) win = DspApplication::menu_window();
	if (HelpDo.All()) cpp_scroll(prompt);
	if (read_action_file_mode) {
		if (!prompt_response) if (pending_prompt_response) {
			prompt_response = pending_prompt_response ;
			pending_prompt_response = 0 ; // snarf pending to prevent async
											// read
		}
/*
 *		LogOut << "RootMenuView::get_file_name - read_file_state, prompt_response is `" <<
 *			prompt_response << "'\n" ;
 */
		disable_remote_com();
		while (!prompt_response) if (!DspApplication::action_read_line()) {
			information("No prompt response for get file name, read aborted.",
				win,1);
			enable_remote_com();
			return 0 ;
		}
		const char * str = prompt_response ;
		prompt_response = 0 ;
		DspApplication::record_prompt(str);
		enable_remote_com();
		if (str) if (*str == '\03') return 0 ;
		else if(*str == 0x1b) return 0 ;
		const char * env = Environment::expand_file_name(str);
		int f = open(env,O_RDONLY);
		if (f > 0) close(f);
		else {
			char * msg = Concatenate("Cannot read file `", env,
				"'. Read aborted.");
			information(msg,win,1);
			delete msg ;
			return 0 ;
		}
		if (env != str) str = Concatenate(env);
		return str ;
	}
	ivStyle * chooser_style = new ivStyle(ivSession::instance()->style());
	chooser_style->ref();
	if (pattern) {
		chooser_style->attribute("filterPattern",pattern);
		chooser_style->attribute("filter","on");
	}
	const char *f_name = 0 ;
	int reset_caption = 0 ;
	for(;;) {
		f_name = 0 ;
		ivFileChooser * chooser =
			ivDialogKit::instance()->file_chooser(def?def:".", chooser_style);
		chooser_style->attribute("name","File chooser");
		chooser_style->attribute("subcaption", prompt);
		if (!chooser->post_for(win)) {
			DspApplication::record_prompt("^C");
			break ;
		}
		f_name = chooser->selected()->string();
		if (!strncmp(f_name,"./$",3)) f_name += 2 ;
		// Inteviews refuses to accept absolute paths in this way

		char * to_delete_char = 0 ;
		int file_opened = 0 ;
		const char * orig_name = 0 ;
		for (;;) {
			const char * env = f_name ;
			int f = open(env,O_RDONLY);
			if (f < 1) {
				env = Environment::expand_file_name(f_name);
				f = open(env,O_RDONLY);
			}
			if (f > 0) {
				close(f);
				orig_name = f_name ;
				f_name = Concatenate(env);
				file_opened = 1 ;
				break ;
			}
			f_name = env ;
			if (check_suffix) {
				char * temp = top_version_name(f_name);
				delete to_delete_char ;
				to_delete_char = temp ;
				f_name = temp ;
				if (temp) continue ;
			}
			if (!reset_caption)
				chooser_style->attribute("caption", "Open failed!");
			reset_caption = 1 ;
			break ;
		}
		if (file_opened) {
			DspApplication::record_prompt(orig_name);
			break ;
		}
	}
	chooser_style->unref();
	return f_name ;
}

void RootMenuView::read_state(int flag, const char * name)
{
	overwrite_flag = flag ;
	if (ReadStateCommon()) return;
	const osString *string = 0 ;
	if (!name) name = get_file_name("Select a state file to read:",
		0,"*",1);
	if (name) {
		int Lines = 0 ;
		ReadStateCompletion(CallBackSuccess,Concatenate(name), Lines);
		return ;
	}
	DspState->ClearReadStateBusy();
}

void RootMenuView::no_cpp_entry()
{
	if (get_current_focus() == cpp_txt_window->get_editor())
		clear_focus();
}

int RootMenuView::input_allowed(const ivInputHandler * editor)
{
	if (!cpp_txt_window) return 1 ;
	if (editor != cpp_txt_window->get_editor()) return 1 ;
	if (DspApplication::network_manager()->clear_edit()) {
		set_active(this);
		return 1 ;
	}
	*Output + OutputCppHelp <<
"DSP++ statements cannot be entered while graphically editing a network.\n" ;
	if (HelpDo.All()) *Output <<
			"Wait for the DSP process to complete so editing can be cleared.\n" ;
	return 0 ;
}

int ReadStateCompletionCheckParse(int ReturnState)
{
	// LogOut << "ReadStateCompletionCheckParse(" << ReturnState << ")\n" ;
	CallBackStatus Status = CallBackAbort ;
	if (ReturnState < 0) {
		DspApplication::root_window()->ReadStateCompletion(
			CallBackError,0,-ReturnState);
		return ReturnState;
	}
	RemoteParseFileState TheState = (RemoteParseFileState) ReturnState ;
	switch (TheState) {
case ParseFileOpened:
		// write empty line to CppWindow to begin file read process
		// - otherwise pending read will wait forever
		{
			PacketHeader ReturnHead(PacketGraphicsStringSend,
				InputCppEntry,2);
			WriteSeg->WritePacket(ReturnHead,"");
		}
		return  0;
case ParseFileOk:
		Status = CallBackSuccess2 ;
		break ;
case ParseFileBadState:
		*Output + OutputCppEntry <<
		"The parser is waiting for the completion of " <<
		"the previous statement.\nPlease complete this statement " <<
		"before reading a state file.\n" ; 
		*Output << "(You may need to enter a `;' in the DSP++ statement area.)\n";
		Status = CallBackFailure ;
		break ;
case ParseFileBadRead:
		*Output + OutputCppEntry << "Problem reading file.\n" ;
		Status = CallBackFailure ;
		break ;
default:
		DbgError("ReatStateCompletionCheckParse","bad ReturnState");
	}
	DspApplication::root_window()->ReadStateCompletion(Status);
	return ReturnState ;
}
		

void RootMenuView::ReadStateCompletion(CallBackStatus Status, char * Name,
	int Lines)
{
/*
 *	LogOut << "RootMenuView::ReadStateCompletion(" << Status <<
 *		"," << (Name ? Name : "NULL") << ", " << Lines <<
 *		")\n" ;
 */
	static HelpLevel SaveHelpLevel = HelpLevelNone;
	// TextWindow * CppWin = GetInWindow(InputCppEntry);
	switch (Status) {
case CallBackSuccess:
		// We have succesfully read the file into the DSP++ window
		// read_file_name = strcpy(new char[strlen(Name)+1],Name) ;
		read_file_name = Name ;
		// TotalLines = Lines ;

		// save help level
		SaveHelpLevel = HelpDo.GetHelpLevel();

		// set to minimum help level
/*
 *		LogOut << "SaveHelp = " << SaveHelpLevel << ", None = " <<
 *			HelpLevelNone << "\n" ;
 */
		if (SaveHelpLevel != HelpLevelNone)
			HelpDo.SetHelpLevel(HelpLevelNone);

		// Make sure DSPpp processing is in state InParseBeginWaitRead
		// abort with message if not
		InterfaceControl.SendPacket(ReadStateCompletionCheckParse,
			ParseReadFileAction,overwrite_flag,read_file_name);
		State.ClearInteractive();

		return ;
case CallBackSuccess2:
		
		// We have read and parsed the entire file 
		HelpDo.SetHelpLevel(SaveHelpLevel);
		// LogOut << "Help level " << SaveHelpLevel << " restored\n" ;
		char * RmvDir = OpdRemoveDirectory(read_file_name);
		/* if (HelpDo.ConfirmVisible()) */ *Output + OutputCppEntry <<
			"Have succesfully read and processed file `" <<
			RmvDir << "'.\n" ;
		delete RmvDir ;
		break ;
case CallBackError:
		// int MoveBack = Lines - TotalLines - 1 ;
		// CppWin->MoveCursorLine(-MoveBack);
		// LogOut << "stopped\n" ;
		*Output + OutputCppHelp <<
			"The above error stopped processing of file `" <<
			read_file_name << 
			"'.\nThe error is at or near line " << Lines << ".\n" ;

		break ;
case CallBackAbort:
		*Output + OutputCppHelp << "State file read aborted.\n" ;
		SaveHelpLevel = HelpLevelNone ; // Do no restore
		break ;
case CallBackFailure:
		*Output + OutputCppHelp << "State file read failed.\n" ;
	}
	State.SetInteractive();
	delete read_file_name ;
	read_file_name = 0 ;
	// LogOut << "ClearingSuspend end of ReadStateCompletion\n" ;
	// CppWin->ClearSuspend() ;
	// if (CppWin->IsVisible()) CppWin->Redraw();
	if (SaveHelpLevel != HelpLevelNone) HelpDo.SetHelpLevel(SaveHelpLevel);
	// LogOut << "Help level " << SaveHelpLevel << " restored\n" ;
	if (init_return_id) InterfaceControl.SendReturnPacket(init_return_id,
		InitReadFinished, 0);
	init_return_id = 0 ;
	DspState->ClearReadStateBusy();
	process_help_strings();
}

void RootMenuView::information(const char * str, ivWindow * win,int force)
{
	if (!str) return ;
	if (!*str) return ;
	StringList strings ;
	strings.Append(Concatenate(str));
	information(strings,win,force);
}

void RootMenuView::information(StringList& strings,ivWindow* win,int force)
{
	if (!strings.Size()) return ;
	if (!force) if (read_action_file_mode) return ;
	disable_remote_com();
	info->run_dialog(&strings, win);
	enable_remote_com() ;
}

void RootMenuView::information_complete()
{
	
	if (read_action_file_mode) return ;
	disable_remote_com() ;
	info->run_dialog(&help_strings);
	enable_remote_com() ;
}

void RootMenuView::init_info()
{
	ivStyle*  info_style = new ivStyle(ivSession::instance()->style());
	info_style->attribute("name","Information");
	info = new InformationImpl(*this,*info_style) ;
	ivResource::ref(info);
}


void RootMenuView::init_prompt()
{
	ivStyle*  prompt_style = new ivStyle(ivSession::instance()->style());
	prompt_style->attribute("name","Prompt");
	prompt = new PromptImpl(*this, *prompt_style);
	ivResource::ref(prompt);
}


PromptStatus RootMenuView::InputPost(UserPrompt * Prompt,
	const char * AbortMessage, StringList* msg, ivWindow * win)
{
	if (HelpDo.All()) {
		if (msg) {
			StringListIterator Next(*msg) ;
			const char * str ;
			while (str = Next()) cpp_scroll(str);
		}
		if (Prompt->GetPrompt()) cpp_scroll(Prompt->GetPrompt());
	}
	if (read_action_file_mode) {
		if (!prompt_response) if (pending_prompt_response) {
			prompt_response = pending_prompt_response ;
			pending_prompt_response = 0 ; // snarf pending to prevent async
											// read
		}
/*
 *		LogOut << "InputPost - read_file_state, prompt_response is `" <<
 *			prompt_response << "'\n" ;
 */
		disable_remote_com();
		while (!prompt_response) if (!DspApplication::action_read_line()) {
			// LogOut << "abort - no read line\n" ;
			enable_remote_com();
			return PromptStatusAbort ;
		}
		// LogOut << "Responding to prompt `" << prompt_response << "'\n" ;
		const char * str ;
/*
 *		while (str=the_strings.Get()) LogOut << "Prompt:`"
 *				<< str << "'.\n" ;
 */
		// must clear the_strings even if debugging output is removed

		str = prompt_response ;
		prompt_response = 0 ;
		DspApplication::record_prompt(str);
		enable_remote_com();
		(Prompt->GetClient())(str,Prompt->GetType(),
			Prompt->GetObject());
		return PromptStatusOk ;
	}
	{
		StringList& pr = prompt_strings ;
		StringList & the_strings = msg ? *msg : pr ;
		if (Prompt->GetPrompt()) the_strings.Append(Concatenate(
				Prompt->GetPrompt()));
		disable_remote_com() ;
		Prompt->capture_read();
		prompt->run_dialog(Prompt, the_strings,AbortMessage,win);
		enable_remote_com();
		return PromptStatusOk ;
	}
}




static ivPropertyData props[] = {
	{ "*plot_color", "black" },
	{ "*mark_color", "black" },
	{ "*axis_color", "black" },
	{ "*tick_color", "black" },
	{ "*background", "wheat" },
	{ 0 }
};

static ivOptionDesc options[] = {
	{ "-plot", "*plot_color", OptionValueNext },
	{ "-mark", "*mark_color", OptionValueNext },
	{ "-axis", "*axis_color", OptionValueNext },
	{ "-tick", "*tick_color", OptionValueNext },
	{ 0 }
};

ivDisplay * RootMenuView::display() const
{
	return window()->display();
}

ivCanvas * RootMenuView::canvas() const
{
		return window()->canvas();
}

void RootMenuView::create_plot(DataPlot * plt)
{
	ivStyle * plot_style = new ivStyle(ivSession::instance()->style());
	const char * view = plt->transform_name();
	const char * name = plt->GetCaption();
	char * to_delete = 0 ;
	if (view) name = to_delete = Concatenate(view," view of ",name);
	plot_style->attribute("name",name);
	plot_style->attribute("iconName",name);
	delete to_delete ;
	Graph * graph = new Graph(
		500.0, 300.0, DspApplication::white(), plt, plot_style);
	ivWindow* w = new ivApplicationWindow(graph);
	graph->window(w,graph->menu_keyboard(),0);
	plt->set_window(w,graph);
	graph->menu_keyboard()->window(w,graph->menu_keyboard(),0);
	w->style(plot_style);
	w->map();
}



void RootMenuView::disable_remote_com()
{
	// LogOut << "disable_remote_com " << disallow_check_remote << "\n" ;
	disallow_check_remote++;
}

void RootMenuView::enable_remote_com()
{
	// LogOut << "enable_remote_com " << disallow_check_remote << "\n" ;
	if (!disallow_check_remote) DbgError("RootMenuView::enable_remote_com",
		"going negative");
	disallow_check_remote--;
}

void RootMenuView::not_busy() const
{
	*Output + OutputCppHelp <<
		"The DSP process is not busy. Communication NOT frozen.\n" ;
}

void RootMenuView::freeze()
{

	if (!DspState->IsBusy()) {
		not_busy();
		return ;
	}

	if (!freeze_flag) {
		disable_remote_com();
		freeze_flag = 1 ;
		new_cursor();
	}
}

void RootMenuView::clear_hard_freeze()
{
	if (hard_freeze_flag) if (DspState->WakenDsp()) {
		hard_freeze_flag = 0 ;
		new_cursor();
	}
}

void RootMenuView::hard_freeze()
{

	freeze();
	if (!freeze_flag) return ;

	if (!hard_freeze_flag) if (DspState->MakeDspSleepForever()) {
		hard_freeze_flag = 1 ;
	}
}

void RootMenuView::thaw()
{
	clear_hard_freeze();
	if (hard_freeze_flag) return ;
	if (freeze_flag) {
		enable_remote_com();
		freeze_flag = 0 ;
		new_cursor();
	}
}

int MenuView::base_keystroke(const ivEvent& e, FocusSelector * sel)
{
	if (get_current_focus()) return 0 ;
	return the_menu_keyboard->do_keystroke(e) ;
}

void MenuView::exit_window()
{
	if (init && can_delete()) {
		if (root_window.get_active() == this)
			root_window.set_active(&root_window);
		FocusSelector::exit_window();
		DspApplication::menu_manager().RemoveEntry(this);
		init = 0 ;
		// root_window.set_window_to_unmap(window());
	} else FocusSelector::exit_window();}

void RootMenuView::new_cursor()
{
	if (!cursor_window()) return ;
	cursor_window()->pop_cursor();
	cursor_window()->push_cursor() ;
	cursor_window()->cursor(DspApplication::state()->GetCursorType());
}

void RootMenuView::set_window_to_unmap(ivWindow * win)
{
/*
 *	if (win || to_unmap) LogOut << "RootMenuView::set_window_to_unmap(" <<
 *		(void *) win << "), to_unmap = " <<
 *		(void *) to_unmap << "\n root_window = " << (void *) window() << "\n" ;
 *
 *	LogOut << "RootMenuView::set_window_to_unmap(" <<
 *		(void *) win << "), to_unmap = " << (void *) to_unmap << "\n";
 */
	if (to_unmap == win) return ;
	if (to_unmap) {
		to_unmap->unmap();
		ivResource::flush();
	}
	to_unmap = win ;
	// FocusSelector::remove_window(win);
}

void RootMenuView::read_request_active()
{
	// LogOut << "RootMenuView::read_request_active\n" ;
	if (!network_edit_mode) {
		if (!help_strings.Size()) return ;
		if (DspApplication::state()->lines_queued()) return ;
		// LogOut << "about to replace page\n" ;
		if (!help_display) DbgError("RootMenuView::read_request_active",
			"no help_display");
		DocumentView * view = help_display->view();
		if (!view) DbgError("RootMenuView::read_request_active",
            "no view");
		ivWindow * w = view->window();
		if (!w) DbgError("RootMenuView::read_request_active",
            "no window");
		while (!w->is_mapped()) event_check();
		help_display->replace_page(help_strings);
		// LogOut << "after replace\n" ;
		new_help_page();
		return ;
	}
	network_edit_mode =0 ;
	if (!edit_info_strings.Size()) return ;
	help_display->replace_page(edit_info_strings);
	new_help_page();
}

void RootMenuView::network_edit_command(const char * cmd)
{
	cpp_txt_window->scroll(cmd);
	char * final_command = Concatenate("NetEditCommand:",cmd);
	DspApplication::state()->write_cpp_line(final_command);
	delete final_command ;
	network_edit_mode = 1 ;
	char * str ;
	while (str = edit_info_strings.Get()) delete str ;
}

void RootMenuView::ReadyForInitFileRead()
{
	overwrite_flag = 1 ;
}

void RootMenuView::execute_menu_command(MenuTreeTraverseObject& obj)
{
	const StackMenuBase * entry = obj.found();
/*
 *	LogOut << "RootMenuView::execute_menu_command, obj.found() = " <<
 *		(void *) entry << "\n" ;
 */
	if (!entry) return ;
	Menu * men = entry->GetMenu();
	// LogOut << "entry->GetMenu() = " << (void *) entry->GetMenu() << "\n" ;
	if (!men) return ;
	int index = obj.index();
	// LogOut << "index = " << index << "\n" ;
	MenuLine * line = men->GetIndexedMenuLine(index);
/*
 *	LogOut << "men->GetIndexedMenuLine(" << index << ") = " <<
 *		(void *) line << "\n" ;
 */
	if (!line) return ;
	if (line->TheType != MenuTypeCommand)
		DbgError("RootMenuView::execute_menu_command","bad command");
	direct_command = &(obj.get_stack());
	// LogOut << "&(obj.get_stack()) = " << (void *) direct_command << "\n" ;
	// LogOut<<"line->GetDoCommand() = "<<(void *)line->GetDoCommand()<<\n";
	// LogOut << "executing `" << line->Command << "'\n" ;
	if (line->GetDoCommand()) line->GetDoCommand()->Execute();
	direct_command = 0 ;
}

void MenuView::enter()
{
	root_window.cursor_window(window());
	window()->push_cursor() ;
	if (DspApplication::state())
		window()->cursor(DspApplication::state()->GetCursorType());
}

void MenuView::leave()
{
	root_window.cursor_window(0);
	window()->pop_cursor();
}


int MenuView::about_to_change_menu(Menu * to_change)
{
	// LogOut<<"MenuView::about_to_change_menu(" <<(void *) to_change << ")\n" ;
	// if this is top menu return 1 to delete this instance
	// Otherwise pop the stack to just above this level
	StackMenu * top = menu_stack.GetNFromTop(0);
	if (!top) DbgError("MenuView::about_to_change_menu","no top");
	// LogOut << "Top:\n" ;
	// top->Dump();

	StackMenuListIterator Next(menu_stack);
	StackMenu * to_check ;
	StackMenu * first_in_menu = 0 ;
	while (to_check = Next()) {
		// 	LogOut << "Checking:\n" ;
		// to_check->Dump();
		if (to_check->GetMenu() == to_change) {
			if (!first_in_menu) return 1 ;
			int to_pop = top->level() - to_check->level() + 1 ;
			// LogOut << "poping(" << to_pop << ")\n" ;
			pop(to_pop);
			menu_stack.GetNFromTop(0)->view_line().release_button();
			if (this != &root_window) resize();
			patch_redraw();
			break ;
		}
		if (!first_in_menu) if (to_check->is_in_menu())
			first_in_menu = to_check ;
	}
	return 0 ;
}


int RootMenuView::set_prompt_response(const char * resp)
{
	if (!resp) return 1 ;
	if (!*resp) {
		pending_prompt_response = new char[1] ;
		*(char *)pending_prompt_response = 0 ;
	} else pending_prompt_response = Concatenate(resp) ;
/*
 *	LogOut << "pending_prompt_response set to `" <<
 *		pending_prompt_response << "'\n" ;
 */
	while (prompt_response) {
		if (!DspApplication::is_busy()) return 0 ;
		// LogOut << "set_prompt_response busy loop\n" ;
		ReadSeg->ReadPacket();
		if (!pending_prompt_response) return 1 ;
	}
	// LogOut << "set_prompt_response busy loop exited\n" ;
	prompt_response = pending_prompt_response;
	pending_prompt_response = 0 ;
	return 1 ;
}

void RootMenuView::action_read_on()
{
	if (read_action_file_mode) return ;
	read_action_file_mode = 1 ;
	new_cursor();
}

void RootMenuView::action_read_off()
{
	if (!read_action_file_mode) return ;
	read_action_file_mode = 0 ;
	new_cursor();
}


void RootMenuView::statement_history()
{
	cpp_txt_window->history();
}

void RootMenuView::command_history()
{
	menu_txt_window->history();
}

void RootMenuView::append_statement_history()
{
	char buf_size = 80 ;
	char buf[buf_size+1];
	const char ** contents = help_display->window_contents();
	if (!contents) return ;
	if (!*contents) return ;
	int used = 0; 
	buf[0] = '\0' ;
	for (const char ** pt = contents ; *pt; pt++) {
		const char * base = *pt ;
		for (;;) {
			const char * last_break = 0 ;
			
			// make sure the line ends with a blank
			if (used) if (!isspace(buf[used-1])) if (used >= buf_size -1) {
				cpp_scroll(buf);
				used = 0 ;
				buf[0] = '\0' ;
			} else buf[used++] = ' ' ;

			// find a a space to break at that is less then the line width
			for (const char * p = base ; *p; p++) {
                if ((p - base) + used >= buf_size) break ;
                if (isspace(*p)) last_break = p ;
            }


			// there is enough room to finish this line
			if (!*p) {
				for (const char * sp = base; *sp; sp++) buf[used++]=*sp;
				buf[used] = '\0' ;
				break ;
			}
			if (!last_break) {
				if (buf[0]) cpp_scroll(buf);
            	used = 0 ;
            	buf[0] = '\0' ;

				// no space to break at
				if (strlen(base) >= buf_size - strlen(buf)) {

					// so break into 80 character chnks
					while (*base && used < buf_size) buf[used++] = *base++;
					if (buf[0]) cpp_scroll(buf);
					used = 0 ;
                	buf[0] = '\0' ;
					continue ;
				}
				continue ;
			} 

			// fill this line and scroll it
			for (const char * sp = base; sp < last_break ; sp++) buf[used++]=*sp;
			buf[used] = '\0' ;
			cpp_scroll(buf);
            used = 0 ;
            buf[0] = '\0' ;
			base = last_break + 1 ;
			// continue processing this line
		}
		if (buf[0]) {
			buf[used] = '\0' ;
            cpp_scroll(buf);
            used = 0 ;
            buf[0] = '\0' ;
		}
	}
	if (buf[0]) cpp_scroll(buf);
}

void RootMenuView::edit_init()
{
	static init = 0 ;
	if (init) return ;
	init = 1 ;
	// LogOut << "RootMenuView::edit_init\n" ;
	ScrollFieldEditor * e = cpp_txt_window->get_editor();
	// e->field(DspApplication::spacer());
    // e->select(0);
	// e->undraw();
	e->do_init();
	e->focus_out();
	e = menu_txt_window->get_editor();
	// e->field(DspApplication::spacer());
    // e->select(0);
	// e->undraw();
	e->do_init();
	e->focus_out();
}

PromptStringList::Append(char * str)
{
	if (HelpDo.All()) DspApplication::root_window()->cpp_scroll(str);
	StringList::Append(str);
}
