/*
* Author: Andrew Mann
*
* Copyright (C) 2004 PlaneShift Team (info@planeshift.it,
* http://www.planeshift.it)
*
* 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 (version 2 of the License)
* 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 <psconfig.h>

#include "pv_resmgr.h"

#include "paws/pawsmanager.h"
#include "paws/pawsbutton.h"
#include "paws/pawstextbox.h"
#include "paws/pawslistbox.h"
#include "paws/pawsspinbox.h"

#include "gui_colorrow.h"
#include "gui_pslist.h"
#include "gui_particlesystem.h"
#include "partview.h"


guiParticleSystem::guiParticleSystem(PawsManager* manager )
            :pawsCollapsableWidget( manager )
{
    button_destroy=NULL;
    button_save=NULL;
    button_runningstate=NULL;
    editbox_name=NULL;
    spinbox_pps=NULL;
    spinbox_particle_count=NULL;
    spinbox_force_amount=NULL;
    spinbox_diffusion=NULL;
    spinbox_emitter_duration=NULL;
    spinbox_particle_duration=NULL;
    spinbox_particle_duration_variance=NULL;
    spinbox_particle_radius=NULL;
    spinbox_viscosity=NULL;
    spinbox_particle_mass=NULL;
    spinbox_particle_mass_variance=NULL;
    listbox_material=NULL;
    listbox_emit_type=NULL;
    listbox_force_type=NULL;

    editbox_gravity_x=NULL;
    editbox_gravity_y=NULL;
    editbox_gravity_z=NULL;


    textbox_emit_prop1=NULL;
    textbox_emit_prop2=NULL;
    textbox_emit_prop3=NULL;
    textbox_emit_prop4=NULL;

    spinbox_emit_prop1=NULL;
    spinbox_emit_prop2=NULL;
    spinbox_emit_prop3=NULL;
    spinbox_emit_prop4=NULL;
    
    spinbox_force_radius=NULL;
    spinbox_force_range=NULL;

    editbox_force_direction_x=NULL;
    editbox_force_direction_y=NULL;
    editbox_force_direction_z=NULL;

    listbox_force_range_falloff=NULL;
    listbox_force_radius_falloff=NULL;

    textbox_force_direction=NULL;
    textbox_force_direction_x=NULL;
    textbox_force_direction_y=NULL;
    textbox_force_direction_z=NULL;
    textbox_force_radius=NULL;
    textbox_force_radius_falloff=NULL;

    listbox_color_method=NULL;
    listbox_color_list=NULL;
    button_color_add=NULL;
    button_color_insert=NULL;
    button_color_delete=NULL;
    spinbox_color_prop1=NULL;
    textbox_color_prop1=NULL;
    button_path=NULL;
    button_movetocamera=NULL;

    path=NULL;
    path_type=PARTSYS_PATH_NONE;
    path_time=0;

    pstracker=NULL;
    resource_manager=NULL;

}

guiParticleSystem::~guiParticleSystem()
{
    delete path;
}

void guiParticleSystem::InitializeParticleSystem(PartSystemTracker *tracker,PVResourceManager *resmgr,guiPSList *managing_list)
{
    resource_manager=resmgr;
    pstracker=tracker;
    managing_pslist=managing_list;
    MatchSystem();
}



bool guiParticleSystem::PostSetup()
{
    bool result=pawsCollapsableWidget::PostSetup();

    button_destroy=(pawsButton *)FindWidget("state_destroy_button");
    button_save=(pawsButton *)FindWidget("state_save_button");

    button_runningstate=(pawsButton *)FindWidget("state_running_button");
    editbox_name=(pawsEditTextBox *)FindWidget("state_name_edit");

    spinbox_pps=(pawsSpinBox *)FindWidget("systemprops_pps_spinbox");
    spinbox_particle_count=(pawsSpinBox *)FindWidget("systemprops_initparts_spinbox");
    spinbox_emitter_duration=(pawsSpinBox *)FindWidget("systemprops_emitter_duration_spinbox");


    listbox_emit_type=(pawsListBox *)FindWidget("emit_emitter_type");
    textbox_emit_prop1=(pawsTextBox *)FindWidget("emit_emitprop_1_label");
    textbox_emit_prop2=(pawsTextBox *)FindWidget("emit_emitprop_2_label");
    textbox_emit_prop3=(pawsTextBox *)FindWidget("emit_emitprop_3_label");
    textbox_emit_prop4=(pawsTextBox *)FindWidget("emit_emitprop_4_label");
    spinbox_emit_prop1=(pawsSpinBox *)FindWidget("emit_emitprop_1_spinbox");
    spinbox_emit_prop2=(pawsSpinBox *)FindWidget("emit_emitprop_2_spinbox");
    spinbox_emit_prop3=(pawsSpinBox *)FindWidget("emit_emitprop_3_spinbox");
    spinbox_emit_prop4=(pawsSpinBox *)FindWidget("emit_emitprop_4_spinbox");


    spinbox_force_amount=(pawsSpinBox *)FindWidget("force_amount_spinbox");
    spinbox_diffusion=(pawsSpinBox *)FindWidget("force_diffusion_spinbox");
    listbox_force_type=(pawsListBox *)FindWidget("force_type");
    spinbox_force_radius=(pawsSpinBox *)FindWidget("force_radius_spinbox");
    spinbox_force_range=(pawsSpinBox *)FindWidget("force_range_spinbox");
    editbox_force_direction_x=(pawsEditTextBox *)FindWidget("force_direction_x_edit");
    editbox_force_direction_y=(pawsEditTextBox *)FindWidget("force_direction_y_edit");
    editbox_force_direction_z=(pawsEditTextBox *)FindWidget("force_direction_z_edit");
    listbox_force_range_falloff=(pawsListBox *)FindWidget("force_range_falloff_listbox");
    listbox_force_radius_falloff=(pawsListBox *)FindWidget("force_radius_falloff_listbox");
    textbox_force_direction=(pawsTextBox *)FindWidget("force_direction_label");
    textbox_force_direction_x=(pawsTextBox *)FindWidget("force_direction_x_label");
    textbox_force_direction_y=(pawsTextBox *)FindWidget("force_direction_y_label");
    textbox_force_direction_z=(pawsTextBox *)FindWidget("force_direction_z_label");
    textbox_force_radius=(pawsTextBox *)FindWidget("force_radius_label");
    textbox_force_radius_falloff=(pawsTextBox *)FindWidget("force_radius_falloff_label");

    spinbox_particle_duration=(pawsSpinBox *)FindWidget("particleprops_particle_duration_spinbox");
    spinbox_particle_duration_variance=(pawsSpinBox *)FindWidget("particleprops_particle_duration_variance_spinbox");
    spinbox_particle_radius=(pawsSpinBox *)FindWidget("particleprops_particle_radius_spinbox");
    spinbox_particle_mass=(pawsSpinBox *)FindWidget("particleprops_particle_mass_spinbox");
    spinbox_particle_mass_variance=(pawsSpinBox *)FindWidget("particleprops_particle_mass_variance_spinbox");

    spinbox_viscosity=(pawsSpinBox *)FindWidget("env_viscosity_spinbox");
    editbox_gravity_x=(pawsEditTextBox *)FindWidget("env_gravity_x_edit");
    editbox_gravity_y=(pawsEditTextBox *)FindWidget("env_gravity_y_edit");
    editbox_gravity_z=(pawsEditTextBox *)FindWidget("env_gravity_z_edit");

    listbox_material=(pawsListBox *)FindWidget("material_listbox");

    button_orient_arrows=(pawsButton *)FindWidget("other_orient_button");

    textbox_color_prop1=(pawsTextBox *)FindWidget("color_prop_1_label");
    spinbox_color_prop1=(pawsSpinBox *)FindWidget("color_prop_1_spinbox");
    button_color_add=(pawsButton *)FindWidget("color_add_button");
    button_color_insert=(pawsButton *)FindWidget("color_insert_button");
    button_color_delete=(pawsButton *)FindWidget("color_delete_button");
    listbox_color_method=(pawsListBox *)FindWidget("color_method_listbox");
    listbox_color_list=(pawsListBox *)FindWidget("color_list_listbox");

    button_path=(pawsButton *)FindWidget("other_path_button");
    button_movetocamera=(pawsButton *)FindWidget("other_movetocamera_button");

    if (listbox_emit_type)
    {
        pawsListBoxRow *row;
        pawsTextBox *tb_col0;

        row=listbox_emit_type->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Sphere");
        }
        row=listbox_emit_type->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Plane");
        }
        row=listbox_emit_type->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Box");
        }
        row=listbox_emit_type->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Cylinder");
        }
    }
    if (listbox_force_type)
    {
        pawsListBoxRow *row;
        pawsTextBox *tb_col0;

        row=listbox_force_type->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Radial");
        }
        row=listbox_force_type->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Linear");
        }
        row=listbox_force_type->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Cone");
        }
    }
    if (listbox_force_range_falloff)
    {
        pawsListBoxRow *row;
        pawsTextBox *tb_col0;

        row=listbox_force_range_falloff->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Constant");
        }
        row=listbox_force_range_falloff->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Linear");
        }
        row=listbox_force_range_falloff->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Parabolic");
        }
    }
    if (listbox_force_radius_falloff)
    {
        pawsListBoxRow *row;
        pawsTextBox *tb_col0;

        row=listbox_force_radius_falloff->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Constant");
        }
        row=listbox_force_radius_falloff->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Linear");
        }
        row=listbox_force_radius_falloff->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Parabolic");
        }
    }

    if (listbox_color_method)
    {
        pawsListBoxRow *row;
        pawsTextBox *tb_col0;

        row=listbox_color_method->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Constant");
        }
        row=listbox_color_method->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Linear");
        }
        row=listbox_color_method->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Looping");
        }
        row=listbox_color_method->NewRow();
        if (row)
        {
            tb_col0=(pawsTextBox *)row->GetColumn(0);
            if (tb_col0) tb_col0->SetText("Heat");
        }
    }


    return result;
}


bool guiParticleSystem::OnButtonPressed(int mouseButton, int keyModifier, pawsWidget* widget)
{
    if (!widget)
        return false;
    if (widget == button_destroy)
    {
        if (PartViewApp::g_pApp)
            PartViewApp::g_pApp->RemoveParticleSystem(pstracker);
        return true;
    }
    if (widget == button_save)
    {
        if (managing_pslist)
            managing_pslist->PromptForSave(this);
        return true;
    }
    if (widget == button_runningstate)
    {
        csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();

        if (!ps_obj_state)
            return true;

        if (ps_obj_state->IsRunning())
        {
            if (!pstracker->system_stopping)
            {
                ps_obj_state->Stop();
                button_runningstate->SetText("Stopping");
                pstracker->system_stopping=true;
            }
        }
        else
        {
            if (pstracker->system_stopping)
                pstracker->system_stopping=false;
            ps_obj_state->Start();
            button_runningstate->SetText("Running");
        }
        return true;
    }
    if (widget == button_orient_arrows)
    {
        if (!pstracker)
            return true;

        if (pstracker->OrientationArrowsVisible())
        {
            pstracker->ShowOrientationArrows(false);
            button_orient_arrows->SetText("Hidden");
        }
        else
        {
            pstracker->ShowOrientationArrows(true);
            button_orient_arrows->SetText("Shown");
        }
        return true;
    }
    if (widget==spinbox_pps)
    {
        UpdateSystemFromInput(PARTSYS_PPS);
        return true;
    }
    if (widget==spinbox_particle_count)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_COUNT);
        return true;
    }
    if (widget==spinbox_force_amount)
    {
        UpdateSystemFromInput(PARTSYS_FORCE_AMOUNT);
        return true;
    }
    if (widget==spinbox_diffusion)
    {
        UpdateSystemFromInput(PARTSYS_DIFFUSION);
        return true;
    }
    if (widget==spinbox_emitter_duration)
    {
        UpdateSystemFromInput(PARTSYS_EMITTER_DURATION);
        return true;
    }
    if (widget==spinbox_particle_duration)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_DURATION);
        return true;
    }
    if (widget==spinbox_particle_duration_variance)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_DURATION_VARIANCE);
        return true;
    }
    if (widget==spinbox_particle_radius)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_RADIUS);
        return true;
    }
    if (widget==spinbox_viscosity)
    {
        UpdateSystemFromInput(PARTSYS_VISCOSITY);
        return true;
    }
    if (widget==spinbox_particle_mass)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_MASS);
        return true;
    }
    if (widget==spinbox_particle_mass_variance)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_MASS_VARIANCE);
        return true;
    }
    if (widget==spinbox_emit_prop1)
    {
        UpdateSystemFromInput(PARTSYS_EMITTER);
        return true;
    }
    if (widget==spinbox_emit_prop2)
    {
        UpdateSystemFromInput(PARTSYS_EMITTER);
        return true;
    }
    if (widget==spinbox_emit_prop3)
    {
        UpdateSystemFromInput(PARTSYS_EMITTER);
        return true;
    }
    if (widget==spinbox_emit_prop4)
    {
        UpdateSystemFromInput(PARTSYS_EMITTER);
        return true;
    }
    if (widget==spinbox_force_radius)
    {
        UpdateSystemFromInput(PARTSYS_FORCE);
        return true;
    }
    if (widget==spinbox_force_range)
    {
        UpdateSystemFromInput(PARTSYS_FORCE);
        return true;
    }
    
    if (widget == button_color_add)
    {
        csColor newcolor(1.0f,1.0f,1.0f);
        if (listbox_color_list)
        {
            pawsListBoxRow *row;
            guiColorRow *colorrow=NULL;
            row=listbox_color_list->NewRow();
            if (row) colorrow=(guiColorRow *)row->GetColumn(0);
            if (colorrow)
            {
                colorrow->SetParentParticleSystem(this);
                colorrow->SetColor(newcolor);
            }
            UpdateColorFromInput();
        }
        return true;
    }
    if (widget == button_color_insert)
    {
        csColor newcolor(1.0f,1.0f,1.0f);
        if (listbox_color_list)
        {
            pawsListBoxRow *row;
            guiColorRow *colorrow=NULL;
            int position=listbox_color_list->GetSelectedRowNum();
            if (position<0)
                position=0;
            row=listbox_color_list->NewRow(position);
            if (row) colorrow=(guiColorRow *)row->GetColumn(0);
            if (colorrow)
            {
                colorrow->SetParentParticleSystem(this);
                colorrow->SetColor(newcolor);
            }
            UpdateColorFromInput();
        }
        return true;
    }
    if (widget == button_color_delete)
    {
        if (listbox_color_list)
        {
            pawsListBoxRow *row;
            row=listbox_color_list->RemoveSelected();
            UpdateColorFromInput();
        }
        return true;
    }

    if (widget == button_path)
    {
        path_type = (path_type +1) % PARTSYS_PATH_MAX;
        SetupPath();
        return true;
    }
    if (widget == button_movetocamera)
    {
        iMovable *partsys_movable=pstracker->particle_system_wrapper->GetMovable();

        if (partsys_movable && PartViewApp::g_pApp)
        {
            csVector3 point;
            PartViewApp::g_pApp->PointFromCenterOfCamera(1.0f,point);
            partsys_movable->SetPosition(point);
            partsys_movable->UpdateMove();
            psposition=point;
            if (path_type != PARTSYS_PATH_NONE)
                SetupPath();
        }
        return true;
    }


    return pawsCollapsableWidget::OnButtonPressed(mouseButton,keyModifier,widget);
}

void guiParticleSystem::SetupPath()
{
    iMovable *partsys_movable=pstracker->particle_system_wrapper->GetMovable();

    if (!partsys_movable)
        return;

    csReversibleTransform trans=partsys_movable->GetFullTransform();
    csMatrix3 trans_mat=trans.GetO2T();
    
    delete path;
    path=NULL;

    switch (path_type)
    {
        case PARTSYS_PATH_NONE:
            button_path->SetText("None");
            partsys_movable->SetPosition(psposition);
            partsys_movable->UpdateMove();
        break;
        case PARTSYS_PATH_LINE:
        {
            csVector3 work_vector;
            path_full_cycle=5000;

            psposition=partsys_movable->GetFullPosition();

            button_path->SetText("Line");
            // Create a line path
            path=new csPath(2);
            path->SetTime(0,0.0f);
            path->SetTime(1,1.0f);
            path->SetPositionVector(0,psposition);
            work_vector=psposition+csVector3(3.0f,0.0f,0.0f);
            path->SetPositionVector(1,work_vector);
            path->SetUpVector(0,trans_mat.Row2());
            path->SetForwardVector(0,csVector3(1.0f,0.0f,0.0f));
            path->SetUpVector(1,trans_mat.Row2());
            path->SetForwardVector(1,csVector3(1.0f,0.0f,0.0f));
        }
        break;
        case PARTSYS_PATH_CIRCLE:
        {
            csVector3 work_vector;
            int i;
            path_full_cycle=5000;

            button_path->SetText("Circle");
            // Create a circle path on the x,z plane
            path=new csPath(10);

            for (i=0;i<10;i++)
            {
                float angle=((3.14159 * 2)  / 9) * ((float)i);
                csVector3 tangent_vector;
                path->SetTime(i,((float)i)/9.0f );
                work_vector.y=0.0f;
                work_vector.x=2.0 * cosf(angle);
                work_vector.z=2.0 * sinf(angle);
                tangent_vector.Cross(work_vector,trans_mat.Row2());
                work_vector+=psposition;
                path->SetPositionVector(i,work_vector);
                path->SetUpVector(i,trans_mat.Row2());
                path->SetForwardVector(i,tangent_vector);
            }


        }
        break;
        case PARTSYS_PATH_SPIRAL:
        {
            float radius=0.0f;
            csVector3 work_vector;
            int i;
            int num_pts=50;
            path_full_cycle=15000;

            button_path->SetText("Spiral");
            // Create a spiral path on the x,z plane
            path=new csPath(num_pts);

            for (i=0;i<num_pts;i++)
            {
                // 9 = pts per cycle
                float angle=((3.14159 * 2)  / ((float)(9))) * ((float)i);
                csVector3 tangent_vector;
                path->SetTime(i,((float)i)/((float)(num_pts-1)) );
                work_vector.y=0.0f;
                work_vector.x=radius * cosf(angle);
                work_vector.z=radius * sinf(angle);
                tangent_vector.Cross(work_vector,trans_mat.Row2());
                work_vector+=psposition;
                path->SetPositionVector(i,work_vector);
                path->SetUpVector(i,trans_mat.Row2());
                path->SetForwardVector(i,tangent_vector);
                radius+=0.05f;
            }


        }
        break;
    }


}

void guiParticleSystem::UpdatePathPosition(csTicks elapsed)
{
    csVector3 position,up_vec,forward_vec,perp_vec;
    float float_path_time;
    if (!path)
        return;

    
    iMovable *partsys_movable=pstracker->particle_system_wrapper->GetMovable();

    if (!partsys_movable)
        return;

    path_time+=elapsed;
    path_time=path_time % path_full_cycle;

    float_path_time=((float)path_time) / ((float)path_full_cycle);

    path->CalculateAtTime(float_path_time);
    path->GetInterpolatedPosition(position);
    path->GetInterpolatedUp(up_vec);
    path->GetInterpolatedForward(forward_vec);

    partsys_movable->SetPosition(position);

    up_vec.Normalize();
    forward_vec.Normalize();
    perp_vec.Cross(up_vec,forward_vec);
    perp_vec.Normalize();


    csMatrix3 rot_matrix(
        perp_vec.x,up_vec.x,forward_vec.x,
        perp_vec.y,up_vec.y,forward_vec.y,
        perp_vec.z,up_vec.z,forward_vec.z
        );
    partsys_movable->SetTransform(rot_matrix);

    partsys_movable->UpdateMove();
}



bool guiParticleSystem::OnChange(pawsWidget * widget)
{
    if (!widget)
        return false;
    if (widget == editbox_name)
    {
        if (!pstracker)
            return false;
        // Update the pstrack
        pstracker->name=editbox_name->GetText();

        // Update the button
        expanded_title="-";
        expanded_title.Append(editbox_name->GetText());
        collapsed_title="+";
        collapsed_title.Append(editbox_name->GetText());

        if (expand_collapse_button)
        {
            if (collapsed)
                expand_collapse_button->SetText(collapsed_title);
            else
                expand_collapse_button->SetText(expanded_title);
        }
        return true;
    }
    if (widget == editbox_force_direction_x || widget == editbox_force_direction_y || widget == editbox_force_direction_z)
    {
        UpdateForceFromInput();
        return true;
    }
    if (widget==spinbox_emit_prop1)
    {
        UpdateSystemFromInput(PARTSYS_EMITTER);
        return true;
    }
    if (widget==spinbox_emit_prop2)
    {
        UpdateSystemFromInput(PARTSYS_EMITTER);
        return true;
    }
    if (widget==spinbox_emit_prop3)
    {
        UpdateSystemFromInput(PARTSYS_EMITTER);
        return true;
    }
    if (widget==spinbox_emit_prop4)
    {
        UpdateSystemFromInput(PARTSYS_EMITTER);
        return true;
    }
    if (widget==spinbox_force_radius)
    {
        UpdateSystemFromInput(PARTSYS_FORCE);
        return true;
    }
    if (widget==spinbox_force_range)
    {
        UpdateSystemFromInput(PARTSYS_FORCE);
        return true;
    }
    if (widget==editbox_gravity_x)
    {
        UpdateSystemFromInput(PARTSYS_GRAVITY);
        return true;
    }
    if (widget==editbox_gravity_y)
    {
        UpdateSystemFromInput(PARTSYS_GRAVITY);
        return true;
    }
    if (widget==editbox_gravity_z)
    {
        UpdateSystemFromInput(PARTSYS_GRAVITY);
        return true;
    }

    if (widget == spinbox_pps)
    {
        UpdateSystemFromInput(PARTSYS_PPS);
        return true;
    }
    if (widget == spinbox_particle_count)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_COUNT);
        return true;
    }
    if (widget == spinbox_force_amount)
    {
        UpdateSystemFromInput(PARTSYS_FORCE_AMOUNT);
        return true;
    }
    if (widget == spinbox_diffusion)
    {
        UpdateSystemFromInput(PARTSYS_DIFFUSION);
        return true;
    }
    if (widget == spinbox_emitter_duration)
    {
        UpdateSystemFromInput(PARTSYS_EMITTER_DURATION);
        return true;
    }
    if (widget == spinbox_particle_duration)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_DURATION);
        return true;
    }
    if (widget == spinbox_particle_duration_variance)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_DURATION_VARIANCE);
        return true;
    }
    if (widget == spinbox_particle_radius)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_RADIUS);
        return true;
    }
    if (widget == spinbox_viscosity)
    {
        UpdateSystemFromInput(PARTSYS_VISCOSITY);
        return true;
    }
    if (widget == spinbox_particle_mass)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_MASS);
        return true;
    }
    if (widget == spinbox_particle_mass_variance)
    {
        UpdateSystemFromInput(PARTSYS_PARTICLE_MASS_VARIANCE);
        return true;
    }

    if (parent)
        return parent->OnChange(widget);
    return false;
}

void guiParticleSystem::OnListAction( pawsListBox* selected, int status )
{
    if (!selected)
        return;

    if (selected == listbox_material)
    {
        if (status == LISTBOX_HIGHLIGHTED)
        {
            PVMaterialTracker *mat_tracker;
            iMeshObject *ps_obj;
            int rownum=listbox_material->GetSelectedRowNum();
            
            if (!resource_manager)
                return;

            mat_tracker=resource_manager->Material_GetMaterialTracker(rownum);
            if (!mat_tracker)
                return;

            if (!pstracker->particle_system_wrapper)
                return;
            ps_obj=pstracker->particle_system_wrapper->GetMeshObject();
            if (!ps_obj)
                return;

            if (!mat_tracker->material_wrapper)
                return;
            ps_obj->SetMaterialWrapper(mat_tracker->material_wrapper);
        }
    }
    if (selected == listbox_emit_type)
    {
        if (status == LISTBOX_HIGHLIGHTED)
        {
            csParticleEmitType e_type;
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();

            if (!ps_obj_state)
                return;

            e_type=(csParticleEmitType)listbox_emit_type->GetSelectedRowNum();
            if (e_type != emitter_type)
            {
                switch (e_type)
                {
                    case CS_PART_EMIT_SPHERE:
                        ps_obj_state->SetSphereEmitType(0.0015f,0.001f);
                    break;
                    case CS_PART_EMIT_PLANE:
                        ps_obj_state->SetPlaneEmitType(0.1f,0.1f);
                    break;
                    case CS_PART_EMIT_BOX:
                        ps_obj_state->SetBoxEmitType(0.1f,0.1f,0.1f);
                    break;
                    case CS_PART_EMIT_CYLINDER:
                        ps_obj_state->SetCylinderEmitType(0.03f,0.3f);
                    break;
                }
                MatchEmitter();
            }
            return;
        }
    }
    if (selected == listbox_force_type)
    {
        if (status == LISTBOX_HIGHLIGHTED)
        {
            csParticleForceType f_type;
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();

            if (!ps_obj_state)
                return;

            f_type=(csParticleForceType)listbox_force_type->GetSelectedRowNum();
            if (f_type != force_type)
            {
                switch (f_type)
                {
                    case CS_PART_FORCE_RADIAL:
                        ps_obj_state->SetRadialForceType(1.0f,CS_PART_FALLOFF_CONSTANT);
                    break;
                    case CS_PART_FORCE_LINEAR:
                    {
                        csVector3 direction(0.0f,1.0f,0.0f);
                        ps_obj_state->SetLinearForceType(direction,1.0f,CS_PART_FALLOFF_CONSTANT);
                    }
                    break;
                    case CS_PART_FORCE_CONE:
                    {
                        csVector3 direction(0.0f,1.0f,0.0f);
                        ps_obj_state->SetConeForceType(direction,1.0f,CS_PART_FALLOFF_CONSTANT,1.0f,CS_PART_FALLOFF_CONSTANT);
                    }
                    break;
                }
                MatchForce();
            }
            return;
        }
    }

    if (selected == listbox_color_method)
    {
        if (status == LISTBOX_HIGHLIGHTED)
        {
            UpdateColorFromInput();
            MatchColor();
            return;
        }
    }

    if (parent)
        parent->OnListAction(selected,status);
}




csRef<iParticlesObjectState> guiParticleSystem::GetPSObjectState()
{
    iMeshObject *ps_meshobj;
    if (!pstracker)
        return NULL;

    ps_meshobj=pstracker->particle_system_wrapper->GetMeshObject();

    if (!ps_meshobj)
        return NULL;

    csRef<iParticlesObjectState> ps_obj_state=SCF_QUERY_INTERFACE(ps_meshobj,iParticlesObjectState);

    return ps_obj_state;
}

csRef<iParticlesFactoryState> guiParticleSystem::GetPSFactoryState()
{
    iMeshObjectFactory *ps_meshfact;
    if (!pstracker)
        return NULL;

    ps_meshfact=pstracker->ps_factory_wrapper->GetMeshObjectFactory();

    if (!ps_meshfact)
        return NULL;

    csRef<iParticlesFactoryState> ps_fact_state=SCF_QUERY_INTERFACE(ps_meshfact,iParticlesFactoryState);

    return ps_fact_state;
}


bool guiParticleSystem::MatchSystem()
{
    if (!pstracker)
        return false;

    csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
    if (!ps_obj_state)
        return false;

    // Initialize name
    if (editbox_name)
        editbox_name->SetText(pstracker->name);
    collapsed_title="+";
    collapsed_title.Append(pstracker->name);
    expanded_title="-";
    expanded_title.Append(pstracker->name);
    if (expand_collapse_button)
    {
        if (collapsed)
            expand_collapse_button->SetText(collapsed_title);
        else
            expand_collapse_button->SetText(expanded_title);
    }

    // Running state
    if (button_runningstate)
    {
        if (ps_obj_state->IsRunning())
        {
            if (pstracker->system_stopping)
                button_runningstate->SetText("Stopping");
            else
                button_runningstate->SetText("Running");
        }
        else
        {
            pstracker->system_stopping=false;
            button_runningstate->SetText("Stopped");
        }
    }
    
    // Particles per second
    if (spinbox_pps)
        spinbox_pps->SetValue((float)ps_obj_state->GetParticlesPerSecond());
    // Initial Particle count
    if (spinbox_particle_count)
        spinbox_particle_count->SetValue((float)ps_obj_state->GetInitialParticleCount());
    // Emitter Type
    MatchEmitter();

    // Force Type
    MatchForce();

    // Force Amount
    if (spinbox_force_amount)
        spinbox_force_amount->SetValue((float)ps_obj_state->GetForce());
    // Diffusion
    if (spinbox_diffusion)
        spinbox_diffusion->SetValue((float)ps_obj_state->GetDiffusion());
    // Gravity
    {
        csVector3 gravity;
        char textbuffer[256];
        ps_obj_state->GetGravity(gravity);

        if (editbox_gravity_x)
        {
            sprintf(textbuffer,"%.2f",gravity.x);
            editbox_gravity_x->SetText(textbuffer);
        }
        if (editbox_gravity_y)
        {
            sprintf(textbuffer,"%.2f",gravity.y);
            editbox_gravity_y->SetText(textbuffer);
        }
        if (editbox_gravity_z)
        {
            sprintf(textbuffer,"%.2f",gravity.z);
            editbox_gravity_z->SetText(textbuffer);
        }
    }

    // Emitter Duration
    if (spinbox_emitter_duration)
        spinbox_emitter_duration->SetValue((float)ps_obj_state->GetEmitTime());
    // Particle Duration
    if (spinbox_particle_duration)
        spinbox_particle_duration->SetValue((float)ps_obj_state->GetTimeToLive());
    // Particle Duration Variance
    if (spinbox_particle_duration_variance)
        spinbox_particle_duration_variance->SetValue((float)ps_obj_state->GetTimeVariation());
    // Color Method

    // Particle radius
    if (spinbox_particle_radius)
        spinbox_particle_radius->SetValue((float)ps_obj_state->GetParticleRadius());
    // Dampener (viscosity)
    if (spinbox_viscosity)
        spinbox_viscosity->SetValue((float)ps_obj_state->GetDampener());
    // Mass
    if (spinbox_particle_mass)
        spinbox_particle_mass->SetValue((float)ps_obj_state->GetMass());
    // Mass Variation
    if (spinbox_particle_mass_variance)
        spinbox_particle_mass_variance->SetValue((float)ps_obj_state->GetMassVariation());

    // Orientation arrows state
    if (button_orient_arrows)
    {
        if (pstracker->OrientationArrowsVisible())
            button_orient_arrows->SetText("Shown");
        else
            button_orient_arrows->SetText("Hidden");
    }

    MatchMaterial();
    MatchColor();

    return true;
}


// This function checks just the running state, since the system can change running states
//  without notification and without user prompting due to timing
void guiParticleSystem::MatchSystemRunningState()
{
    if (!pstracker)
        return;
    csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
    if (!ps_obj_state)
        return;

    // Running state
    if (button_runningstate)
    {
        if (ps_obj_state->IsRunning())
        {
            if (pstracker->system_stopping)
                button_runningstate->SetText("Stopping");
            else
                button_runningstate->SetText("Running");
        }
        else
        {
            pstracker->system_stopping=false;
            button_runningstate->SetText("Stopped");
        }
    }
}

// The logic here is broken out separately since it's rather extensive
bool guiParticleSystem::MatchMaterial()
{
    iMeshObject *ps_obj;
    int i,l;
    iMaterialWrapper *in_use_mat,*compare_mat;
    pawsListBoxRow *selected_row=NULL;

    if (!pstracker)
        return false;
    if (!resource_manager)
        return false;
    if (!listbox_material)
        return false;
    if (!pstracker->particle_system_wrapper)
        return false;

    ps_obj=pstracker->particle_system_wrapper->GetMeshObject();
    if (!ps_obj)
        return false;

    in_use_mat=ps_obj->GetMaterialWrapper();
    if (!in_use_mat)
        return false;


    listbox_material->Clear();
    
    l=resource_manager->Material_GetMaterialCount();
    for (i=0;i<l;i++)
    {
        const char *mat_name;
        iObject *mat_obj;
        pawsListBoxRow *row;
        pawsTextBox *name_column;

        PVMaterialTracker *mat_tracker=resource_manager->Material_GetMaterialTracker(i);
        if (!mat_tracker)
            continue;
        compare_mat=mat_tracker->material_wrapper;
        if (!compare_mat)
            continue;

        mat_obj=compare_mat->QueryObject();
        if (!mat_obj)
            continue;
        mat_name=mat_obj->GetName();
        if (!mat_name)
            continue;

        row=listbox_material->NewRow();
        if (!row)
            continue;
        name_column=(pawsTextBox *)row->GetColumn(0);
        if (!name_column)
            continue;

        name_column->SetText(mat_name);

        if (compare_mat == in_use_mat)
            selected_row=row;
    }

    if (selected_row)
    {
        listbox_material->Select(selected_row);
        return true;
    }
    return false;
}

bool guiParticleSystem::MatchEmitter()
{
    csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
    if (!ps_obj_state)
        return false;

    emitter_type=ps_obj_state->GetEmitType();

    if (listbox_emit_type)
    {
        pawsListBoxRow *row=listbox_emit_type->GetRow((int)emitter_type);
        if (row && (listbox_emit_type->GetSelectedRow()!=row))
            listbox_emit_type->Select(row);
    }

    switch (emitter_type)
    {
        case CS_PART_EMIT_SPHERE:
            if (textbox_emit_prop1)
            {
                textbox_emit_prop1->SetText("In Rad:");
                textbox_emit_prop1->Show();
            }
            if (textbox_emit_prop2)
            {
                textbox_emit_prop2->SetText("Out Rad:");
                textbox_emit_prop2->Show();
            }
            if (textbox_emit_prop3)
                textbox_emit_prop3->Hide();
            if (textbox_emit_prop4)
                textbox_emit_prop4->Hide();
            if (spinbox_emit_prop3)
                spinbox_emit_prop3->Hide();
            if (spinbox_emit_prop4)
                spinbox_emit_prop4->Hide();
            if (spinbox_emit_prop1)
            {
                spinbox_emit_prop1->SetValue(ps_obj_state->GetSphereEmitInnerRadius());
                spinbox_emit_prop1->Show();
            }
            if (spinbox_emit_prop2)
            {
                spinbox_emit_prop2->SetValue(ps_obj_state->GetSphereEmitOuterRadius());
                spinbox_emit_prop2->Show();
            }
        break;
        case CS_PART_EMIT_PLANE:
            if (textbox_emit_prop1)
            {
                textbox_emit_prop1->SetText("X Size:");
                textbox_emit_prop1->Show();
            }
            if (textbox_emit_prop2)
            {
                textbox_emit_prop2->SetText("Y Size:");
                textbox_emit_prop2->Show();
            }
            if (textbox_emit_prop3)
                textbox_emit_prop3->Hide();
            if (textbox_emit_prop4)
                textbox_emit_prop4->Hide();
            if (spinbox_emit_prop3)
                spinbox_emit_prop3->Hide();
            if (spinbox_emit_prop4)
                spinbox_emit_prop4->Hide();
            if (spinbox_emit_prop1)
            {
                spinbox_emit_prop1->SetValue(ps_obj_state->GetEmitXSize());
                spinbox_emit_prop1->Show();
            }
            if (spinbox_emit_prop2)
            {
                spinbox_emit_prop2->SetValue(ps_obj_state->GetEmitYSize());
                spinbox_emit_prop2->Show();
            }
        break;
        case CS_PART_EMIT_BOX:
            if (textbox_emit_prop1)
            {
                textbox_emit_prop1->SetText("X Size:");
                textbox_emit_prop1->Show();
            }
            if (textbox_emit_prop2)
            {
                textbox_emit_prop2->SetText("Y Size:");
                textbox_emit_prop2->Show();
            }
            if (textbox_emit_prop3)
            {
                textbox_emit_prop3->SetText("Z Size:");
                textbox_emit_prop3->Show();
            }
            if (textbox_emit_prop4)
                textbox_emit_prop4->Hide();
            if (spinbox_emit_prop4)
                spinbox_emit_prop4->Hide();
            if (spinbox_emit_prop1)
            {
                spinbox_emit_prop1->SetValue(ps_obj_state->GetEmitXSize());
                spinbox_emit_prop1->Show();
            }
            if (spinbox_emit_prop2)
            {
                spinbox_emit_prop2->SetValue(ps_obj_state->GetEmitYSize());
                spinbox_emit_prop2->Show();
            }
            if (spinbox_emit_prop3)
            {
                spinbox_emit_prop3->SetValue(ps_obj_state->GetEmitZSize());
                spinbox_emit_prop3->Show();
            }
        break;
        case CS_PART_EMIT_CYLINDER:
            if (textbox_emit_prop1)
            {
                textbox_emit_prop1->SetText("Radius:");
                textbox_emit_prop1->Show();
            }
            if (textbox_emit_prop2)
            {
                textbox_emit_prop2->SetText("Height:");
                textbox_emit_prop2->Show();
            }
            if (textbox_emit_prop3)
                textbox_emit_prop3->Hide();
            if (textbox_emit_prop4)
                textbox_emit_prop4->Hide();
            if (spinbox_emit_prop3)
                spinbox_emit_prop3->Hide();
            if (spinbox_emit_prop4)
                spinbox_emit_prop4->Hide();
            if (spinbox_emit_prop1)
            {
                // Hack:  The iParticleObjectState interface is missing retrieval functions for EMIT_CYLINDER!!
                spinbox_emit_prop1->SetValue(ps_obj_state->GetSphereEmitInnerRadius());
                spinbox_emit_prop1->Show();
            }
            if (spinbox_emit_prop2)
            {
                // Hack:  The iParticleObjectState interface is missing retrieval functions for EMIT_CYLINDER!!
                spinbox_emit_prop2->SetValue(ps_obj_state->GetSphereEmitOuterRadius());
                spinbox_emit_prop2->Show();
            }

        default:
            break;
    }
 


    return true;
}

bool guiParticleSystem::MatchForce()
{
    csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
    if (!ps_obj_state)
        return false;

    force_type=ps_obj_state->GetForceType();

    if (listbox_force_type)
    {
        pawsListBoxRow *row=listbox_force_type->GetRow((int)force_type);
        if (row && (listbox_force_type->GetSelectedRow()!=row))
            listbox_force_type->Select(row);
    }

    switch (force_type)
    {
        case CS_PART_FORCE_RADIAL: 
            {
                csParticleFalloffType range,radius;
                ps_obj_state->GetFalloffType(range,radius);
                // range and range falloff
                if (spinbox_force_range)
                {
                    spinbox_force_range->SetValue(ps_obj_state->GetForceRange());
                    spinbox_force_range->Show();
                }

                if (listbox_force_range_falloff)
                {

                    pawsListBoxRow *row=listbox_force_range_falloff->GetRow((int)range);
                    if (row)
                        listbox_force_range_falloff->Select(row);
                    listbox_force_range_falloff->Show();
                }


                if (spinbox_force_radius)
                    spinbox_force_radius->Hide();
                if (editbox_force_direction_x)
                    editbox_force_direction_x->Hide();
                if (editbox_force_direction_y)
                    editbox_force_direction_y->Hide();
                if (editbox_force_direction_z)
                    editbox_force_direction_z->Hide();
                if (listbox_force_radius_falloff)
                    listbox_force_radius_falloff->Hide();
                if (textbox_force_direction)
                    textbox_force_direction->Hide();
                if (textbox_force_direction_x)
                    textbox_force_direction_x->Hide();
                if (textbox_force_direction_y)
                    textbox_force_direction_y->Hide();
                if (textbox_force_direction_z)
                    textbox_force_direction_z->Hide();
                if (textbox_force_radius)
                    textbox_force_radius->Hide();
                if (textbox_force_radius_falloff)
                    textbox_force_radius_falloff->Hide();

            }
        break;
        case CS_PART_FORCE_LINEAR:
            {
                char textbuf[256];
                csParticleFalloffType range,radius;
                csVector3 direction;
                ps_obj_state->GetForceDirection(direction);
                ps_obj_state->GetFalloffType(range,radius);
                // direction, range and range falloff
                if (spinbox_force_range)
                {
                    spinbox_force_range->SetValue(ps_obj_state->GetForceRange());
                    spinbox_force_range->Show();
                }

                if (listbox_force_range_falloff)
                {

                    pawsListBoxRow *row=listbox_force_range_falloff->GetRow((int)range);
                    if (row)
                        listbox_force_range_falloff->Select(row);
                    listbox_force_range_falloff->Show();
                }
                if (textbox_force_direction)
                    textbox_force_direction->Show();
                if (textbox_force_direction_x)
                    textbox_force_direction_x->Show();
                if (textbox_force_direction_y)
                    textbox_force_direction_y->Show();
                if (textbox_force_direction_z)
                    textbox_force_direction_z->Show();

                if (editbox_force_direction_x)
                {
                    sprintf(textbuf,"%.2f",direction.x);
                    editbox_force_direction_x->SetText(textbuf);
                    editbox_force_direction_x->Show();
                }
                if (editbox_force_direction_y)
                {
                    sprintf(textbuf,"%.2f",direction.y);
                    editbox_force_direction_y->SetText(textbuf);
                    editbox_force_direction_y->Show();
                }
                if (editbox_force_direction_z)
                {
                    sprintf(textbuf,"%.2f",direction.z);
                    editbox_force_direction_z->SetText(textbuf);
                    editbox_force_direction_z->Show();
                }

                if (spinbox_force_radius)
                    spinbox_force_radius->Hide();
                if (listbox_force_radius_falloff)
                    listbox_force_radius_falloff->Hide();
                if (textbox_force_radius)
                    textbox_force_radius->Hide();
                if (textbox_force_radius_falloff)
                    textbox_force_radius_falloff->Hide();

            }

        break;
        case CS_PART_FORCE_CONE:
            {
                char textbuf[256];
                csParticleFalloffType range,radius;
                csVector3 direction;
                ps_obj_state->GetForceDirection(direction);
                ps_obj_state->GetFalloffType(range,radius);
                // direction, range and range falloff, radius and radius falloff
                if (spinbox_force_range)
                {
                    spinbox_force_range->SetValue(ps_obj_state->GetForceRange());
                    spinbox_force_range->Show();
                }

                if (listbox_force_range_falloff)
                {

                    pawsListBoxRow *row=listbox_force_range_falloff->GetRow((int)range);
                    if (row)
                        listbox_force_range_falloff->Select(row);
                    listbox_force_range_falloff->Show();
                }
                if (textbox_force_radius)
                    textbox_force_radius->Show();
                if (textbox_force_radius_falloff)
                    textbox_force_radius_falloff->Show();

                if (spinbox_force_radius)
                {
                    spinbox_force_radius->SetValue(ps_obj_state->GetForceConeRadius());
                    spinbox_force_radius->Show();
                }
                if (listbox_force_radius_falloff)
                {
                    pawsListBoxRow *row=listbox_force_range_falloff->GetRow((int)radius);
                    if (row)
                        listbox_force_radius_falloff->Select(row);
                    listbox_force_radius_falloff->Show();
                }

                if (textbox_force_direction)
                    textbox_force_direction->Show();
                if (textbox_force_direction_x)
                    textbox_force_direction_x->Show();
                if (textbox_force_direction_y)
                    textbox_force_direction_y->Show();
                if (textbox_force_direction_z)
                    textbox_force_direction_z->Show();

                if (editbox_force_direction_x)
                {
                    sprintf(textbuf,"%.2f",direction.x);
                    editbox_force_direction_x->SetText(textbuf);
                    editbox_force_direction_x->Show();
                }
                if (editbox_force_direction_y)
                {
                    sprintf(textbuf,"%.2f",direction.y);
                    editbox_force_direction_y->SetText(textbuf);
                    editbox_force_direction_y->Show();
                }
                if (editbox_force_direction_z)
                {
                    sprintf(textbuf,"%.2f",direction.z);
                    editbox_force_direction_z->SetText(textbuf);
                    editbox_force_direction_z->Show();
                }

            }

        break;
        default:
        break;
    }

    return true;
}

bool guiParticleSystem::MatchColor()
{
    csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
    if (!ps_obj_state)
        return false;

    color_method=ps_obj_state->GetParticleColorMethod();

    if (listbox_color_method)
    {
        pawsListBoxRow *row=listbox_color_method->GetRow((int)color_method);
        if (row && (listbox_color_method->GetSelectedRow()!=row))
            listbox_color_method->Select(row);
    }

    switch (color_method)
    {
        case CS_PART_COLOR_CONSTANT:
        case CS_PART_COLOR_LINEAR:
            if (textbox_color_prop1)
                textbox_color_prop1->Hide();
            if (spinbox_color_prop1)
                spinbox_color_prop1->Hide();
        break;
        case CS_PART_COLOR_LOOPING:
            if (textbox_color_prop1)
            {
                textbox_color_prop1->SetText("Cycle Time:");
                textbox_color_prop1->Show();
            }
            if (spinbox_color_prop1)
            {
                spinbox_color_prop1->SetValue(ps_obj_state->GetColorLoopTime());
                spinbox_color_prop1->Show();
            }
        break;
        case CS_PART_COLOR_HEAT:
            if (textbox_color_prop1)
            {
                textbox_color_prop1->SetText("Base Temperature:");
                textbox_color_prop1->Show();
            }
            if (spinbox_color_prop1)
            {
                spinbox_color_prop1->SetValue(ps_obj_state->GetBaseHeat());
                spinbox_color_prop1->Show();
            }
        break;
        default:
        break;
    }

    if (!listbox_color_list)
        return false;

    // Determine if the colors already match
    bool colors_match=true;
    csArray<csColor4> gradient=ps_obj_state->GetGradient();
    if (gradient.Length() != listbox_color_method->GetRowCount())
        colors_match=false;
    if (colors_match)
    {
        int i,l;
        pawsListBoxRow *row;
        guiColorRow *colorrow;

        l=listbox_color_list->GetRowCount();
        for (i=0;i<l;i++)
        {
            row=listbox_color_list->GetRow(i);
            if (!row)
                continue;
            colorrow=(guiColorRow *)row->GetColumn(0);
            if (!colorrow)
                continue;

            csColor obj_color,gui_color;
            obj_color=gradient[i];
            gui_color=colorrow->GetColor();
            if (obj_color.red != gui_color.red ||
                obj_color.green != gui_color.green ||
                obj_color.blue != gui_color.blue)
            {
                colors_match=false;
                break;
            }
        }
    }

    // Need to update colors
    if (!colors_match)
    {
        int i,l;
        pawsListBoxRow *row;
        guiColorRow *colorrow;

        listbox_color_list->Clear();
        l=gradient.Length();
        for (i=0;i<l;i++)
        {
            row=listbox_color_list->NewRow();
            if (!row)
                continue;
            colorrow=(guiColorRow *)row->GetColumn(0);
            if (!colorrow)
                continue;
            colorrow->SetColor(gradient[i]);
            colorrow->SetParentParticleSystem(this);
        }
    }


    return true;
}





void guiParticleSystem::UpdateEmitterFromInput()
{
    csParticleEmitType e_type;
    csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();

    if (!ps_obj_state)
        return;

    e_type=(csParticleEmitType)listbox_emit_type->GetSelectedRowNum();
    switch (e_type)
    {
        case CS_PART_EMIT_SPHERE:
        {
            float radius_inner,radius_outer;

            if (!spinbox_emit_prop1 || !spinbox_emit_prop2)
                return;
            radius_inner=spinbox_emit_prop1->GetValue();
            radius_outer=spinbox_emit_prop2->GetValue();

            ps_obj_state->SetSphereEmitType(radius_outer,radius_inner);
        }
        break;
        case CS_PART_EMIT_PLANE:
        {
            float x_size,y_size;

            if (!spinbox_emit_prop1 || !spinbox_emit_prop2)
                return;
            x_size=spinbox_emit_prop1->GetValue();
            y_size=spinbox_emit_prop2->GetValue();

            ps_obj_state->SetPlaneEmitType(x_size,y_size);
        }
        break;
        case CS_PART_EMIT_BOX:
        {
            float x_size,y_size,z_size;

            if (!spinbox_emit_prop1 || !spinbox_emit_prop2 || !spinbox_emit_prop3)
                return;
            x_size=spinbox_emit_prop1->GetValue();
            y_size=spinbox_emit_prop2->GetValue();
            z_size=spinbox_emit_prop3->GetValue();

            ps_obj_state->SetBoxEmitType(x_size,y_size,z_size);
        }
        break;
        case CS_PART_EMIT_CYLINDER:
        {
            float radius,height;

            if (!spinbox_emit_prop1 || !spinbox_emit_prop2)
                return;
            radius=spinbox_emit_prop1->GetValue();
            height=spinbox_emit_prop2->GetValue();

            ps_obj_state->SetCylinderEmitType(radius,height);
        }
        break;
    }

}

void guiParticleSystem::UpdateForceFromInput()
{
    csParticleForceType f_type;
    csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();

    if (!ps_obj_state)
        return;

    f_type=(csParticleForceType)listbox_force_type->GetSelectedRowNum();
    switch (f_type)
    {
        case CS_PART_FORCE_RADIAL:
        {
            float range;
            csParticleFalloffType fallofftype;

            if (!listbox_force_range_falloff || !spinbox_force_range)
                return;
            fallofftype=(csParticleFalloffType)listbox_force_range_falloff->GetSelectedRowNum();
            range=spinbox_force_range->GetValue();

            ps_obj_state->SetRadialForceType(range,fallofftype);
        }
        break;
        case CS_PART_FORCE_LINEAR:
        {
            float range;
            csVector3 direction;
            csParticleFalloffType fallofftype;

            if (!listbox_force_range_falloff || !spinbox_force_range ||
                !editbox_force_direction_x || !editbox_force_direction_y ||
                !editbox_force_direction_z)
                return;
            fallofftype=(csParticleFalloffType)listbox_force_range_falloff->GetSelectedRowNum();
            range=spinbox_force_range->GetValue();
            direction.x=atof(editbox_force_direction_x->GetText());
            direction.y=atof(editbox_force_direction_y->GetText());
            direction.z=atof(editbox_force_direction_z->GetText());

            ps_obj_state->SetLinearForceType(direction,range,fallofftype);
        }
        break;
        case CS_PART_FORCE_CONE:
        {
            float range,radius;
            csVector3 direction;
            csParticleFalloffType fallofftype,radius_fallofftype;

            if (!listbox_force_range_falloff || !spinbox_force_range ||
                !editbox_force_direction_x || !editbox_force_direction_y ||
                !editbox_force_direction_z || !spinbox_force_radius |
                !listbox_force_radius_falloff)
                return;
            fallofftype=(csParticleFalloffType)listbox_force_range_falloff->GetSelectedRowNum();
            radius_fallofftype=(csParticleFalloffType)listbox_force_radius_falloff->GetSelectedRowNum();
            range=spinbox_force_range->GetValue();
            radius=spinbox_force_radius->GetValue();
            direction.x=atof(editbox_force_direction_x->GetText());
            direction.y=atof(editbox_force_direction_y->GetText());
            direction.z=atof(editbox_force_direction_z->GetText());

            ps_obj_state->SetConeForceType(direction,range,fallofftype,radius,radius_fallofftype);
        }
        break;
    }

}

void guiParticleSystem::UpdateColorFromInput()
{
    csParticleColorMethod c_method;
    csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();

    if (!ps_obj_state)
        return;
    if (!listbox_color_method)
        return;

    c_method=(csParticleColorMethod)listbox_color_method->GetSelectedRowNum();
    switch (c_method)
    {
        case CS_PART_COLOR_CONSTANT:
        {
            // Use the first color list entry, or white if there is none
            csColor4 constcolor(1.0f,1.0f,1.0f);
            if (listbox_color_list && listbox_color_list->GetRowCount()>0)
            {
                pawsListBoxRow *row;
                guiColorRow *colorrow=NULL;

                row=listbox_color_list->GetRow(0);
                if (row) colorrow=(guiColorRow *)row->GetColumn(0);
                if (colorrow) constcolor.Set (colorrow->GetColor ());
            }

            ps_obj_state->SetConstantColorMethod(constcolor);
        }
        break;
        case CS_PART_COLOR_LINEAR:
            ps_obj_state->SetLinearColorMethod();
        break;
        case CS_PART_COLOR_LOOPING:
        {
            float looptime=1.0f;

            if (spinbox_color_prop1)
                looptime=spinbox_color_prop1->GetValue();
            ps_obj_state->SetLoopingColorMethod(looptime);
        }
        break;
        case CS_PART_COLOR_HEAT:
        {
            float baseheat=1.0f;

            if (spinbox_color_prop1)
                baseheat=spinbox_color_prop1->GetValue();
            ps_obj_state->SetHeatColorMethod(baseheat);
        }
        break;
    }

    // Update colors if they differ
    if (listbox_color_list)
    {
        int i,l;
        pawsListBoxRow *row;
        guiColorRow *colorrow=NULL;
        
        ps_obj_state->ClearColors();

        l=listbox_color_list->GetRowCount();
        for (i=0;i<l;i++)
        {
            row=listbox_color_list->GetRow(i);
            if (!row)
                continue;
            colorrow=(guiColorRow *)row->GetColumn(0);
            if (!colorrow)
                continue;

        csColor4 c4 (colorrow->GetColor ());
            ps_obj_state->AddColor(c4);
        }
    }



}



void guiParticleSystem::UpdateSystemFromInput(int system_component)
{
    switch (system_component)
    {
        case PARTSYS_RUNNINGSTATE:
            // Buttons are not handled through this function
        break;
        case PARTSYS_NAME:
        break;
        case PARTSYS_PPS:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && spinbox_pps)
            {
                int pps;
                pps=spinbox_pps->GetValue();

                if (pps != ps_obj_state->GetParticlesPerSecond())
                    ps_obj_state->SetParticlesPerSecond(pps);
            }
        }
        break;
        case PARTSYS_PARTICLE_COUNT:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && spinbox_particle_count)
            {
                int count;
                count=spinbox_particle_count->GetValue();

                if (count != ps_obj_state->GetInitialParticleCount())
                    ps_obj_state->SetInitialParticleCount(count);
            }
        }
        break;
        case PARTSYS_FORCE_AMOUNT:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && spinbox_force_amount)
            {
                float force;
                force=spinbox_force_amount->GetValue();

                if (force != ps_obj_state->GetForce())
                    ps_obj_state->SetForce(force);
            }
        }
        break;
        case PARTSYS_DIFFUSION:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && spinbox_diffusion)
            {
                float diffusion;
                diffusion=spinbox_diffusion->GetValue();

                if (diffusion != ps_obj_state->GetDiffusion())
                    ps_obj_state->SetDiffusion(diffusion);
            }
        }
        break;
        case PARTSYS_EMITTER_DURATION:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && spinbox_emitter_duration)
            {
                float duration;
                duration=spinbox_emitter_duration->GetValue();

                if (duration != ps_obj_state->GetEmitTime())
                    ps_obj_state->SetEmitTime(duration);
            }
        }
        break;
        case PARTSYS_PARTICLE_DURATION:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && spinbox_particle_duration)
            {
                float duration;
                duration=spinbox_particle_duration->GetValue();

                if (duration != ps_obj_state->GetTimeToLive())
                    ps_obj_state->SetTimeToLive(duration);
            }
        }
        break;
        case PARTSYS_PARTICLE_DURATION_VARIANCE:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && spinbox_particle_duration_variance)
            {
                float variance;
                variance=spinbox_particle_duration_variance->GetValue();

                if (variance != ps_obj_state->GetTimeVariation())
                    ps_obj_state->SetTimeVariation(variance);
            }
        }
        break;
        case PARTSYS_PARTICLE_RADIUS:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && spinbox_particle_radius)
            {
                float radius;
                radius=spinbox_particle_radius->GetValue();

                if (radius != ps_obj_state->GetParticleRadius())
                    ps_obj_state->SetParticleRadius(radius);
            }
        }
        break;
        case PARTSYS_VISCOSITY:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && spinbox_viscosity)
            {
                float viscosity;
                viscosity=spinbox_viscosity->GetValue();

                if (viscosity != ps_obj_state->GetDampener())
                    ps_obj_state->SetDampener(viscosity);
            }
        }
        break;
        case PARTSYS_PARTICLE_MASS:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && spinbox_particle_mass)
            {
                float mass;
                mass=spinbox_particle_mass->GetValue();

                if (mass != ps_obj_state->GetMass())
                    ps_obj_state->SetMass(mass);
            }
        }
        break;
        case PARTSYS_PARTICLE_MASS_VARIANCE:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && spinbox_particle_mass_variance)
            {
                float variation;
                variation=spinbox_particle_mass_variance->GetValue();

                if (variation != ps_obj_state->GetMassVariation())
                    ps_obj_state->SetMassVariation(variation);
            }
        }
        break;
        case PARTSYS_EMITTER:
            UpdateEmitterFromInput();
        break;
        case PARTSYS_FORCE:
            UpdateForceFromInput();
        break;
        case PARTSYS_GRAVITY:
        {
            csRef<iParticlesObjectState> ps_obj_state=GetPSObjectState();
            if (ps_obj_state.IsValid() && editbox_gravity_x && editbox_gravity_y && editbox_gravity_z)
            {
                csVector3 gravity;

                gravity.x=atof(editbox_gravity_x->GetText());
                gravity.y=atof(editbox_gravity_y->GetText());
                gravity.z=atof(editbox_gravity_z->GetText());

                ps_obj_state->SetGravity(gravity);
            }
        }
        break;
        case PARTSYS_COLOR:
            UpdateColorFromInput();
        default:
        break;
    }
}

void guiParticleSystem::DeleteColorRow(guiColorRow *target)
{
    int i,l;
    pawsListBoxRow *row;
    guiColorRow *colorrow;

    if (!listbox_color_list)
        return;
    l=listbox_color_list->GetRowCount();

    for (i=0;i<l;i++)
    {
        row=listbox_color_list->GetRow(i);
        if (!row)
            continue;
        colorrow=(guiColorRow *)row->GetColumn(i);
        if ( colorrow==target)
        {
            listbox_color_list->Remove(row->GetID());
            break;
        }
    }
    UpdateColorFromInput();
}

void guiParticleSystem::ChangedColorRow(guiColorRow *target)
{
    UpdateColorFromInput();
}


