
/*
 * CINELERRA
 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
 * Copyright (C) 2003-2016 Cinelerra CV contributors
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "bcsignals.h"
#include "clip.h"
#include "edl.h"
#include "edlsession.h"
#include "formattools.h"
#include "language.h"
#include "mwindow.h"
#include "performanceprefs.h"
#include "preferences.h"
#include <ctype.h>
#include <string.h>
#include "theme.h"

#define MASTER_NODE_FRAMERATE_TEXT "Master node framerate: %0.3f"
#if 0
N_(MASTER_NODE_FRAMERATE_TEXT)
#endif

PerformancePrefs::PerformancePrefs(MWindow *mwindow, PreferencesWindow *pwindow)
 : PreferencesDialog(mwindow, pwindow)
{
	hot_node = -1;
// *** CONTEXT_HELP ***
	context_help_set_keyword("Performance");
}

PerformancePrefs::~PerformancePrefs()
{
	delete brender_tools;
	nodes[0].remove_all_objects();
	nodes[1].remove_all_objects();
	nodes[2].remove_all_objects();
	nodes[3].remove_all_objects();
}

void PerformancePrefs::create_objects()
{
	int xs5 = xS(5), xs10 = xS(10);
	int ys5 = yS(5), ys10 = yS(10), ys20 = yS(20), ys30 = yS(30), ys35 = yS(35);
	int x, y;
	int xmargin2 = xS(180);
	int xmargin3 = xS(260);
	int xmargin4 = xS(420);
	char string[BCTEXTLEN];
	BC_Resources *resources = BC_WindowBase::get_resources();
	BC_WindowBase *win;
	BC_Title *title;

	node_list = 0;
	generate_node_list();

	int xmargin1 = x = mwindow->theme->preferencesoptions_x;
	y = mwindow->theme->preferencesoptions_y;

	int y0 = y;
	win = add_subwindow(new BC_Title(x, y + ys5, _("Cache size (MB):"), MEDIUMFONT, resources->text_default));
	win->context_help_set_keyword("Performance section");
	int maxw = win->get_w();
	int y1 = y += ys30;
	win = add_subwindow(new BC_Title(x, y1 + ys5, _("Seconds to preroll renders:")));
	win->context_help_set_keyword("Performance section");
	maxw = bmax(win->get_w(), maxw);
	int x2 = x + maxw + xs5;
	int y2 = y += ys30;
	cache_size = new CICacheSize(x2, y0, pwindow, this);
	cache_size->create_objects();
	PrefsRenderPreroll *preroll = new PrefsRenderPreroll(pwindow, this, x2, y1);
	preroll->create_objects();
	add_subwindow(new PrefsForceUniprocessor(pwindow, x, y2));
	y += ys30;

	int x1 = x + xmargin4;
	add_subwindow(cache_transitions = new CacheTransitions(x1, y0, pwindow, this));
	cache_transitions->context_help_set_keyword("Performance section");
	win = add_subwindow(new BC_Title(x1, y1, _("Use HW Device:")));
	win->context_help_set_keyword("Performance section");
	maxw = win->get_w();
	win = add_subwindow(new BC_Title(x1, y2, _("Project SMP cpus:")));
	win->context_help_set_keyword("Performance section");
	maxw = bmax(win->get_w(), maxw);
	x2 = x1 + maxw + xs5;
	PrefsUseHWDev *use_hw_dev = new PrefsUseHWDev(pwindow, this, x2, y1);
	use_hw_dev->create_objects();
	PrefsProjectSMP *proj_smp = new PrefsProjectSMP(pwindow, this, x2, y2);
	proj_smp->create_objects();

// Background rendering
	add_subwindow(new BC_Bar(xs5, y, get_w() - xs10));
	y += ys5;


	add_subwindow(title = new BC_Title(x, y, _("Background Rendering (Video only)"), LARGEFONT, resources->text_default));
	title->context_help_set_keyword("Background Rendering");
	y1 = y += ys30;

	win = add_subwindow(new PrefsUseBRender(pwindow, x, y));
	win->context_help_set_keyword("Background Rendering");

	y += win->get_h() + ys10;
	win = add_subwindow(new BC_Title(x, y, _("Frames per background rendering job:")));
	win->context_help_set_keyword("Background Rendering");
	y += win->get_h() + ys5;
	PrefsBRenderFragment *brender_fragment = new PrefsBRenderFragment(pwindow, this,
		x + xmargin3, y);
	brender_fragment->create_objects();
	y += brender_fragment->get_h() + ys5;
	win = add_subwindow(new BC_Title(x, y, _("Frames to preroll background:")));
	win->context_help_set_keyword("Background Rendering");
	y += win->get_h() + ys5;
	PrefsBRenderPreroll *bpreroll = new PrefsBRenderPreroll(pwindow, this,
		x + xmargin3, y + ys5);
	bpreroll->create_objects();
	y += bpreroll->get_h() + ys20;

	x += xmargin4;
	add_subwindow(title = new BC_Title(x, y1, _("Output for background rendering:")));
	title->context_help_set_keyword("Background Rendering");
	y1 += ys20;
	brender_tools = new FormatTools(mwindow, this,
			pwindow->thread->preferences->brender_asset);
	brender_tools->create_objects(x, y1,
		0,  // Include tools for audio
		1,  // Include tools for video
		0,  // Include checkbox for audio
		0,  // Include checkbox for video
		0,
		1,
		0,  // Select compressors to be offered
		0,  // Prompt for recording options
		0,  // prompt for use labels
		1); // Supply file formats for background rendering
	x = xmargin1;


// Renderfarm
	add_subwindow(new BC_Bar(xs5, y, get_w() - xs10));
	y += ys5;
	add_subwindow(title = new BC_Title(x, y, _("Render Farm"), LARGEFONT, resources->text_default));
	title->context_help_set_keyword("Render Farm Menu");
	x1 = get_w() - BC_GenericButton::calculate_w(this, _("Reset rates")) - x;
	add_subwindow(new PrefsRenderFarmReset(pwindow, this, x1, y));
	x1 = x + xmargin4;
	BC_Title *node_title = new BC_Title(x1, y, _("Nodes:"));
	add_subwindow(node_title);
	node_title->context_help_set_keyword("Render Farm Menu");
	x1 += node_title->get_w() + xS(15);
	sprintf(string, _(MASTER_NODE_FRAMERATE_TEXT),
		pwindow->thread->preferences->local_rate);
	add_subwindow(master_rate = new BC_Title(x1, y, string));
	master_rate->context_help_set_keyword("Render Farm Menu");
	add_subwindow(node_list = new PrefsRenderFarmNodes(pwindow, this, x + xmargin4, y+=yS(25)));
	node_list->context_help_set_keyword("Render Farm Menu");
	add_subwindow(new PrefsRenderFarm(pwindow, x, y+=ys5));
	add_subwindow(title = new BC_Title(x, y+=ys30, _("Hostname:")));
	title->context_help_set_keyword("Render Farm Menu");
	add_subwindow(title = new BC_Title(x + xmargin3, y, _("Port:")));
	title->context_help_set_keyword("Render Farm Menu");
	add_subwindow(edit_node = new PrefsRenderFarmEditNode(pwindow, this, x, y+=yS(25)));
	edit_node->context_help_set_keyword("Render Farm Menu");
	edit_port = new PrefsRenderFarmPort(pwindow, this, x+xmargin3, y);
	edit_port->create_objects();

	add_subwindow(new PrefsRenderFarmReplaceNode(pwindow, this, x, y+=ys30));
	add_subwindow(new PrefsRenderFarmNewNode(pwindow, this, x+xmargin2, y));
	add_subwindow(new PrefsRenderFarmSortNodes(pwindow, this, x, y+=ys30));
	add_subwindow(new PrefsRenderFarmDelNode(pwindow, this, x+xmargin2, y));
	add_subwindow(title = new BC_Title(x, y+=ys35, _("Client Watchdog Timeout:")));
	title->context_help_set_keyword("Render Farm Menu");
	renderfarm_watchdog = new PrefsRenderFarmWatchdog(pwindow, this, x+xmargin3, y-ys5);
	renderfarm_watchdog->create_objects();
	add_subwindow(title = new BC_Title(x, y+=ys35, _("Total jobs to create:")));
	title->context_help_set_keyword("Render Farm Menu");
	PrefsRenderFarmJobs *jobs = new PrefsRenderFarmJobs(pwindow, this,
		x + xmargin3, y-ys5);
	jobs->create_objects();
	y += jobs->get_h() + ys5;
	win = add_subwindow(new BC_Title(x, y,
		_("(overridden if new file at each label is checked)")));
	win->context_help_set_keyword("Render Farm Menu");
//	y += win->get_h() + ys5;
// 	add_subwindow(new PrefsRenderFarmVFS(pwindow, this, x, y));
// 	add_subwindow(new BC_Title(x, y,
// 		_("Filesystem prefix on remote nodes:")));
// 	add_subwindow(new PrefsRenderFarmMountpoint(pwindow, this, x + xmargin3, y));
// 	y += ys30;
}

void PerformancePrefs::generate_node_list()
{
	int selected_row = node_list ? node_list->get_selection_number(0, 0) : -1;

	for(int i = 0; i < TOTAL_COLUMNS; i++)
		nodes[i].remove_all_objects();

	for(int i = 0;
		i < pwindow->thread->preferences->renderfarm_nodes.size();
		i++)
	{
		BC_ListBoxItem *item;
		nodes[ENABLED_COLUMN].append(item = new BC_ListBoxItem(
			(char*)(pwindow->thread->preferences->renderfarm_enabled.get(i) ? "X" : " ")));
		if(i == selected_row) item->set_selected(1);

		nodes[HOSTNAME_COLUMN].append(item = new BC_ListBoxItem(
			pwindow->thread->preferences->renderfarm_nodes.get(i)));
		if(i == selected_row) item->set_selected(1);

		char string[BCTEXTLEN];
		sprintf(string, "%d", pwindow->thread->preferences->renderfarm_ports.get(i));
		nodes[PORT_COLUMN].append(item = new BC_ListBoxItem(string));
		if(i == selected_row) item->set_selected(1);

		sprintf(string, "%0.3f", pwindow->thread->preferences->renderfarm_rate.get(i));
		nodes[RATE_COLUMN].append(item = new BC_ListBoxItem(string));
		if(i == selected_row) item->set_selected(1);
	}
}


static const char *default_titles[] = {
	N_("On"), N_("Hostname"), N_("Port"), N_("Framerate")
};

static int default_widths[] = {
	30, 150, 50, 50
};


void PerformancePrefs::update_node_list()
{
	node_list->update_list();
}

void PrefsRenderFarmNodes::update_list()
{
	update(subwindow->nodes, titles, widths, PerformancePrefs::TOTAL_COLUMNS,
		get_xposition(), get_yposition(), get_selection_number(0, 0));
}


void PerformancePrefs::update_rates()
{
//printf("PerformancePrefs::update_rates %d\n", __LINE__);
	char string[BCTEXTLEN];
	for(int i = 0;
		i < mwindow->preferences->renderfarm_rate.size();
		i++)
	{
		if(i < nodes[RATE_COLUMN].size())
		{
			sprintf(string, "%0.3f", mwindow->preferences->renderfarm_rate.get(i));
			nodes[RATE_COLUMN].get(i)->set_text(string);
		}
	}

	sprintf(string, _(MASTER_NODE_FRAMERATE_TEXT),
		mwindow->preferences->local_rate);
	master_rate->update(string);

	update_node_list();
}


PrefsUseBRender::PrefsUseBRender(PreferencesWindow *pwindow,
	int x,
	int y)
 : BC_CheckBox(x,
 	y,
	pwindow->thread->preferences->use_brender,
	_("Use background rendering"))
{
	this->pwindow = pwindow;
}

int PrefsUseBRender::handle_event()
{
	pwindow->thread->redraw_overlays = 1;
	pwindow->thread->redraw_times = 1;
	pwindow->thread->preferences->use_brender = get_value();
	return 1;
}


PrefsBRenderFragment::PrefsBRenderFragment(PreferencesWindow *pwindow,
	PerformancePrefs *subwindow, int x, int y)
 : BC_TumbleTextBox(subwindow,
 	(int64_t)pwindow->thread->preferences->brender_fragment,
	(int64_t)1, (int64_t)65535, x, y, xS(100))
{
	this->pwindow = pwindow;
}
int PrefsBRenderFragment::handle_event()
{
	pwindow->thread->preferences->brender_fragment = atol(get_text());
	return 1;
}

CICacheSize::CICacheSize(int x, int y,
	PreferencesWindow *pwindow, PerformancePrefs *subwindow)
 : BC_TumbleTextBox(subwindow,
 	(int64_t)pwindow->thread->preferences->cache_size / 0x100000,
	(int64_t)MIN_CACHE_SIZE / 0x100000,
	(int64_t)MAX_CACHE_SIZE / 0x100000,
	x, y, xS(100))
{
	this->pwindow = pwindow;
	set_increment(1);
}

int CICacheSize::handle_event()
{
	int64_t result;
	result = (int64_t)atol(get_text()) * 0x100000;
	CLAMP(result, MIN_CACHE_SIZE, MAX_CACHE_SIZE);
	pwindow->thread->preferences->cache_size = result;
	return 0;
}

CacheTransitions::CacheTransitions(int x, int y,
	PreferencesWindow *pwindow, PerformancePrefs *subwindow)
 : BC_CheckBox(x, y, pwindow->thread->preferences->cache_transitions,
	_("Cache Transitions"))
{
	this->pwindow = pwindow;
}

int CacheTransitions::handle_event()
{
	pwindow->thread->preferences->cache_transitions = get_value();
	return 0;
}


PrefsUseHWDev::PrefsUseHWDev(PreferencesWindow *pwindow,
		PerformancePrefs *subwindow, int x, int y)
 : BC_PopupTextBox(subwindow,0,0,x,y,xS(100),yS(80),LISTBOX_TEXT)
{
	this->pwindow = pwindow;
}

void PrefsUseHWDev::create_objects()
{
	BC_PopupTextBox::create_objects();
	set_tooltip(_("vdpau - Nvidia, Nouveau, AMD (mesa)\n"
		"vaapi - Broadcom, Intel HD graphics, Amdgpu, Radeon\n"
		"cuda  - Nvidia + Cuda SDK\n"
		"vulkan testing - AMDGPU"));
	hw_dev_names.append(new BC_ListBoxItem(_("none")));
#ifdef HAVE_VAAPI
	hw_dev_names.append(new BC_ListBoxItem("vaapi"));
#endif
#ifdef HAVE_VDPAU
	hw_dev_names.append(new BC_ListBoxItem("vdpau"));
#endif
#ifdef HAVE_NV
	hw_dev_names.append(new BC_ListBoxItem("cuda"));
#endif
	hw_dev_names.append(new BC_ListBoxItem("vulkan"));
	update_list(&hw_dev_names);
	update(&pwindow->thread->preferences->use_hw_dev[0]);
}

int PrefsUseHWDev::handle_event()
{
	strncpy(&pwindow->thread->preferences->use_hw_dev[0],
		get_text(), sizeof(pwindow->thread->preferences->use_hw_dev));
	return 1;
}

PrefsRenderPreroll::PrefsRenderPreroll(PreferencesWindow *pwindow,
		PerformancePrefs *subwindow, int x, int y)
 : BC_TumbleTextBox(subwindow,
 	(float)pwindow->thread->preferences->render_preroll,
	0.f, 100.f, x, y, xS(100))
{
	this->pwindow = pwindow;
	set_increment(0.1);
}
PrefsRenderPreroll::~PrefsRenderPreroll()
{
}
int PrefsRenderPreroll::handle_event()
{
	pwindow->thread->preferences->render_preroll = atof(get_text());
	return 1;
}


PrefsBRenderPreroll::PrefsBRenderPreroll(PreferencesWindow *pwindow,
		PerformancePrefs *subwindow,
		int x,
		int y)
 : BC_TumbleTextBox(subwindow,
 	(int64_t)pwindow->thread->preferences->brender_preroll,
	(int64_t)0, (int64_t)100, x, y, xS(100))
{
	this->pwindow = pwindow;
}
int PrefsBRenderPreroll::handle_event()
{
	pwindow->thread->preferences->brender_preroll = atol(get_text());
	return 1;
}


PrefsRenderFarm::PrefsRenderFarm(PreferencesWindow *pwindow, int x, int y)
 : BC_CheckBox(x,
 	y,
	pwindow->thread->preferences->use_renderfarm,
	_("Use render farm"))
{
	this->pwindow = pwindow;
// *** CONTEXT_HELP ***
	context_help_set_keyword("Render Farm section");
}
PrefsRenderFarm::~PrefsRenderFarm()
{
}
int PrefsRenderFarm::handle_event()
{
	pwindow->thread->preferences->use_renderfarm = get_value();
	return 1;
}


PrefsForceUniprocessor::PrefsForceUniprocessor(PreferencesWindow *pwindow, int x, int y)
 : BC_CheckBox(x,
 	y,
	pwindow->thread->preferences->force_uniprocessor,
	_("Force single processor use"))
{
	this->pwindow = pwindow;
// *** CONTEXT_HELP ***
	context_help_set_keyword("Performance section");
}
PrefsForceUniprocessor::~PrefsForceUniprocessor()
{
}
int PrefsForceUniprocessor::handle_event()
{
	pwindow->thread->preferences->force_uniprocessor = get_value();
	return 1;
}



PrefsRenderFarmConsolidate::PrefsRenderFarmConsolidate(PreferencesWindow *pwindow, int x, int y)
 : BC_CheckBox(x,
 	y,
	pwindow->thread->preferences->renderfarm_consolidate,
	_("Consolidate output files on completion"))
{
	this->pwindow = pwindow;
}
PrefsRenderFarmConsolidate::~PrefsRenderFarmConsolidate()
{
}
int PrefsRenderFarmConsolidate::handle_event()
{
	pwindow->thread->preferences->renderfarm_consolidate = get_value();
	return 1;
}


PrefsRenderFarmPort::PrefsRenderFarmPort(PreferencesWindow *pwindow,
	PerformancePrefs *subwindow,
	int x,
	int y)
 : BC_TumbleTextBox(subwindow,
 	(int64_t)pwindow->thread->preferences->renderfarm_port,
	(int64_t)1, (int64_t)65535, x, y, xS(100))
{
	this->pwindow = pwindow;
}

PrefsRenderFarmPort::~PrefsRenderFarmPort()
{
}

int PrefsRenderFarmPort::handle_event()
{
	pwindow->thread->preferences->renderfarm_port = atol(get_text());
	return 1;
}



PrefsRenderFarmNodes::PrefsRenderFarmNodes(PreferencesWindow *pwindow,
	PerformancePrefs *subwindow, int x, int y)
 : BC_ListBox(x, y, xS(340), yS(230), LISTBOX_TEXT, 0,0,0,1, 0,0, LISTBOX_MULTIPLE)
{
	for( int i=0; i<PerformancePrefs::TOTAL_COLUMNS; ++i ) {
		titles[i] = _(default_titles[i]);
		widths[i] = xS(default_widths[i]);
	}
	update(subwindow->nodes, titles, widths, PerformancePrefs::TOTAL_COLUMNS,
		0, 0, -1, 0, 0);
	this->subwindow = subwindow;
	this->pwindow = pwindow;
}
PrefsRenderFarmNodes::~PrefsRenderFarmNodes()
{
}

int PrefsRenderFarmNodes::column_resize_event()
{
	for( int i=0; i<PerformancePrefs::TOTAL_COLUMNS; ++i )
		widths[i] = get_column_width(i);
	return 1;
}

int PrefsRenderFarmNodes::handle_event()
{
SET_TRACE
	if(get_selection_number(0, 0) >= 0)
	{
		subwindow->hot_node = get_selection_number(1, 0);
		subwindow->edit_node->update(get_selection(1, 0)->get_text());
		const char *text = get_selection(2, 0)->get_text();
		subwindow->edit_port->update(text);
		pwindow->thread->preferences->renderfarm_port = atol(text);
		if(get_cursor_x() < widths[0])
		{
			pwindow->thread->preferences->renderfarm_enabled.values[subwindow->hot_node] =
				!pwindow->thread->preferences->renderfarm_enabled.values[subwindow->hot_node];
			subwindow->generate_node_list();
			subwindow->update_node_list();
		}
	}
	else
	{
		subwindow->hot_node = -1;
		subwindow->edit_node->update("");
	}
SET_TRACE
	return 1;
}
int PrefsRenderFarmNodes::selection_changed()
{
	handle_event();
	return 1;
}


PrefsRenderFarmEditNode::PrefsRenderFarmEditNode(PreferencesWindow *pwindow, PerformancePrefs *subwindow, int x, int y)
 : BC_TextBox(x, y, xS(240), 1, "")
{
	this->pwindow = pwindow;
	this->subwindow = subwindow;
}

PrefsRenderFarmEditNode::~PrefsRenderFarmEditNode()
{
}

int PrefsRenderFarmEditNode::handle_event()
{
	return 1;
}


PrefsRenderFarmNewNode::PrefsRenderFarmNewNode(PreferencesWindow *pwindow, PerformancePrefs *subwindow, int x, int y)
 : BC_GenericButton(x, y, _("Add Nodes"))
{
	this->pwindow = pwindow;
	this->subwindow = subwindow;
// *** CONTEXT_HELP ***
	context_help_set_keyword("Render Farm Menu");
}
PrefsRenderFarmNewNode::~PrefsRenderFarmNewNode()
{
}
int PrefsRenderFarmNewNode::handle_event()
{
	const char *name = subwindow->edit_node->get_text();
	char *cp = (char*)subwindow->edit_port->get_text();
	int64_t start_port = strtol(cp, &cp, 0), end_port = start_port;
	while( isspace(*cp) ) ++cp;
	if( *cp++ == '-' )
		end_port = strtol(cp, &cp, 0);
	for( int port=start_port; port<=end_port; ++port ) {
		pwindow->thread->preferences->add_node(name, port, 1, 0.0);
	}
	pwindow->thread->preferences->renderfarm_port = end_port;
	subwindow->edit_port->update(end_port);
	pwindow->thread->preferences->reset_rates();
	subwindow->generate_node_list();
	subwindow->update_node_list();
	subwindow->hot_node = -1;
	return 1;
}


PrefsRenderFarmReplaceNode::PrefsRenderFarmReplaceNode(PreferencesWindow *pwindow, PerformancePrefs *subwindow, int x, int y)
 : BC_GenericButton(x, y, _("Apply Changes"))
{
	this->pwindow = pwindow;
	this->subwindow = subwindow;
// *** CONTEXT_HELP ***
	context_help_set_keyword("Render Farm Menu");
}
PrefsRenderFarmReplaceNode::~PrefsRenderFarmReplaceNode()
{
}
int PrefsRenderFarmReplaceNode::handle_event()
{
	if(subwindow->hot_node >= 0)
	{
		pwindow->thread->preferences->edit_node(subwindow->hot_node,
			subwindow->edit_node->get_text(),
			pwindow->thread->preferences->renderfarm_port,
			pwindow->thread->preferences->renderfarm_enabled.values[subwindow->hot_node]);
		subwindow->generate_node_list();
		subwindow->update_node_list();
	}
	return 1;
}


PrefsRenderFarmDelNode::PrefsRenderFarmDelNode(PreferencesWindow *pwindow, PerformancePrefs *subwindow, int x, int y)
 : BC_GenericButton(x, y, _("Delete Nodes"))
{
	this->pwindow = pwindow;
	this->subwindow = subwindow;
// *** CONTEXT_HELP ***
	context_help_set_keyword("Render Farm Menu");
}
PrefsRenderFarmDelNode::~PrefsRenderFarmDelNode()
{
}
int PrefsRenderFarmDelNode::handle_event()
{
	ArrayList<BC_ListBoxItem *> &item_list = subwindow->nodes[0];
	for( int i=item_list.size(); --i>=0; ) {
		if( !item_list[i]->get_selected() ) continue;
		pwindow->thread->preferences->delete_node(i);
	}
	subwindow->generate_node_list();
	subwindow->update_node_list();
	subwindow->hot_node = -1;
	return 1;
}


PrefsRenderFarmSortNodes::PrefsRenderFarmSortNodes(PreferencesWindow *pwindow,
	PerformancePrefs *subwindow,
	int x,
	int y)
 : BC_GenericButton(x, y, _("Sort nodes"))
{
	this->pwindow = pwindow;
	this->subwindow = subwindow;
// *** CONTEXT_HELP ***
	context_help_set_keyword("Render Farm Menu");
}

PrefsRenderFarmSortNodes::~PrefsRenderFarmSortNodes()
{
}

int PrefsRenderFarmSortNodes::handle_event()
{
	pwindow->thread->preferences->sort_nodes();
	subwindow->generate_node_list();
	subwindow->update_node_list();
	subwindow->hot_node = -1;
	return 1;
}


PrefsRenderFarmReset::PrefsRenderFarmReset(PreferencesWindow *pwindow,
	PerformancePrefs *subwindow, int x, int y)
 : BC_GenericButton(x, y, _("Reset rates"))
{
	this->pwindow = pwindow;
	this->subwindow = subwindow;
// *** CONTEXT_HELP ***
	context_help_set_keyword("Render Farm Menu");
}

int PrefsRenderFarmReset::handle_event()
{
	pwindow->thread->preferences->reset_rates();
	subwindow->generate_node_list();
	subwindow->update_node_list();

	char string[BCTEXTLEN];
	sprintf(string,
		_(MASTER_NODE_FRAMERATE_TEXT),
		pwindow->thread->preferences->local_rate);
	subwindow->master_rate->update(string);
	subwindow->hot_node = -1;
	return 1;
}


PrefsProjectSMP::PrefsProjectSMP(PreferencesWindow *pwindow,
		PerformancePrefs *subwindow, int x, int y)
 : BC_TumbleTextBox(subwindow,
	(int64_t)pwindow->thread->preferences->project_smp,
	(int64_t)1, (int64_t)100, x, y, xS(100))
{
	this->pwindow = pwindow;
}
PrefsProjectSMP::~PrefsProjectSMP()
{
}
int PrefsProjectSMP::handle_event()
{
	pwindow->thread->preferences->project_smp = atol(get_text());
	return 1;
}


PrefsRenderFarmJobs::PrefsRenderFarmJobs(PreferencesWindow *pwindow,
		PerformancePrefs *subwindow,
		int x,
		int y)
 : BC_TumbleTextBox(subwindow,
 	(int64_t)pwindow->thread->preferences->renderfarm_job_count,
	(int64_t)1, (int64_t)100, x, y, xS(100))
{
	this->pwindow = pwindow;
}
PrefsRenderFarmJobs::~PrefsRenderFarmJobs()
{
}
int PrefsRenderFarmJobs::handle_event()
{
	pwindow->thread->preferences->renderfarm_job_count = atol(get_text());
	return 1;
}


PrefsRenderFarmMountpoint::PrefsRenderFarmMountpoint(PreferencesWindow *pwindow,
		PerformancePrefs *subwindow, int x, int y)
 : BC_TextBox(x, y, xS(100), 1,
	pwindow->thread->preferences->renderfarm_mountpoint)
{
	this->pwindow = pwindow;
	this->subwindow = subwindow;
}
PrefsRenderFarmMountpoint::~PrefsRenderFarmMountpoint()
{
}
int PrefsRenderFarmMountpoint::handle_event()
{
	strcpy(pwindow->thread->preferences->renderfarm_mountpoint, get_text());
	return 1;
}


PrefsRenderFarmVFS::PrefsRenderFarmVFS(PreferencesWindow *pwindow,
	PerformancePrefs *subwindow, int x, int y)
 : BC_CheckBox(x, y, pwindow->thread->preferences->renderfarm_vfs,
	_("Use virtual filesystem"))
{
	this->pwindow = pwindow;
	this->subwindow = subwindow;
}

int PrefsRenderFarmVFS::handle_event()
{
	pwindow->thread->preferences->renderfarm_vfs = get_value();
	return 1;
}


PrefsRenderFarmWatchdog::PrefsRenderFarmWatchdog(PreferencesWindow *pwindow,
		PerformancePrefs *subwindow, int x, int y)
 : BC_TumbleTextBox(subwindow,
	(int64_t)pwindow->thread->preferences->renderfarm_watchdog_timeout,
	(int64_t)0, (int64_t)1000, x, y, xS(100))
{
	this->pwindow = pwindow;
	set_increment(15);
}

int PrefsRenderFarmWatchdog::handle_event()
{
	pwindow->thread->preferences->renderfarm_watchdog_timeout = atol(get_text());
	return 1;
}


