~cypheon/elfelli

3254968e9641915ca4f0433b888c5720160716d3 — Johann Rudloff 14 years ago 8564e24
Now there is a convenient GUI element to change a body's charge.
4 files changed, 136 insertions(+), 23 deletions(-)

M src/Application.cpp
M src/Application.h
M src/SimulationCanvas.cpp
M src/SimulationCanvas.h
M src/Application.cpp => src/Application.cpp +38 -4
@@ 273,6 273,31 @@ void Application::on_about_activate()
  dlg.run();
}

void Application::on_sim_selection_changed()
{
  bool sel = sim_canvas.has_selection();
  object_toolbar->set_sensitive(sel);
  object_actions->set_sensitive(sel);

  update_charge_spin();
}

void Application::on_sim_selected_charge_changed()
{
  update_charge_spin();
}

void Application::on_charge_value_changed()
{
  sim_canvas.set_selected_charge(charge_spin->get_value());
}

void Application::update_charge_spin()
{
  float charge = sim_canvas.get_selected_charge();
  charge_spin->set_value(charge);
}

void Application::quit()
{
  Main::quit();


@@ 413,8 438,6 @@ Widget *Application::build_object_toolbar()
  HBox *tb = new HBox;
  al->add(*manage(tb));
  al->set_padding(2, 2, 0, 0);
  al->set_sensitive(false);


  Tooltips *tips = new Tooltips;
  Button *btn;


@@ 425,6 448,7 @@ Widget *Application::build_object_toolbar()
  btn->unset_flags(CAN_FOCUS);
  btn->set_image(*manage(img));
  btn->set_relief(RELIEF_NONE);
  btn->signal_clicked().connect(sigc::mem_fun(*this, &Application::on_remove_selected_activate));
  tips->set_tip(*btn, _("Remove this object"));
  tb->pack_start(*btn, false, false);



@@ 435,7 459,14 @@ Widget *Application::build_object_toolbar()

  HBox *charge_box = manage(new HBox);
  charge_box->pack_start(*manage(new Label(_("Charge:"))));
  SpinButton *charge_spin = manage(new SpinButton);

  charge_spin = manage(new SpinButton);
  charge_spin->set_digits(1);
  charge_spin->signal_value_changed().connect(sigc::mem_fun(*this, &Application::on_charge_value_changed));
  charge_spin->set_range(SimulationCanvas::MIN_CHARGE, SimulationCanvas::MAX_CHARGE);
  charge_spin->set_increments(SimulationCanvas::CHARGE_STEP_SMALL, SimulationCanvas::CHARGE_STEP);
  tips->set_tip(*charge_spin, _("Change the absolute value of this object's charge"));

  charge_box->pack_start(*charge_spin);
  Alignment *charge_al = manage(new Alignment);
  charge_al->add(*charge_box);


@@ 464,13 495,16 @@ bool Application::build_gui()
  Toolbox *main_toolbox = manage(new Toolbox(main_toolbar));
  vbox1->pack_start(*main_toolbox, false, false);

  Gtk::Widget *object_toolbar = manage(build_object_toolbar());
  object_toolbar = manage(build_object_toolbar());
  object_toolbar->set_sensitive(false);
  HandleBox *object_toolbox = manage(new HandleBox);
  object_toolbox->add(*object_toolbar);
  vbox1->pack_start(*object_toolbox, false, false);

  vbox1->pack_start(sim_canvas);
  sim_canvas.set_size_request(640, 480);
  sim_canvas.signal_selection_changed().connect(sigc::mem_fun(*this, &Application::on_sim_selection_changed));
  sim_canvas.signal_selected_charge_changed().connect(sigc::mem_fun(*this, &Application::on_sim_selected_charge_changed));

  vbox1->pack_start(sbar, false, false);


M src/Application.h => src/Application.h +7 -0
@@ 67,6 67,7 @@ private:
  void setup_stock_items();

  void reset_simulation();
  void update_charge_spin();

  bool on_expose(GdkEventExpose *event);
  void on_remove_selected_activate();


@@ 81,9 82,15 @@ private:
  void on_open_activate();
  void on_save_activate();

  void on_sim_selection_changed();
  void on_sim_selected_charge_changed();
  void on_charge_value_changed();

  Gtk::Main gtk_main;
  Gtk::Window main_win;
  Gtk::Statusbar sbar;
  Gtk::Widget *object_toolbar;
  Gtk::SpinButton *charge_spin;

  Gtk::FileChooserDialog export_png_dlg, save_dlg, open_dlg;
  Gtk::FileFilter elfelli_xml, all;

M src/SimulationCanvas.cpp => src/SimulationCanvas.cpp +70 -16
@@ 35,13 35,10 @@ char *SimulationCanvas::color_names[] = {
  "#ffcccc",
  "#660000"};

const float SimulationCanvas::MAX_CHARGE = 10.0;

inline float sign(float f)
{
  if(f<0) return -1;
  return 1;
}
const float SimulationCanvas::MAX_CHARGE(10.0);
const float SimulationCanvas::MIN_CHARGE(1.0);
const float SimulationCanvas::CHARGE_STEP(1.0);
const float SimulationCanvas::CHARGE_STEP_SMALL(0.1);

SimulationCanvas::SimulationCanvas():
  mouse_pressed(false), body_radius(10), plate_radius(5),


@@ 63,6 60,8 @@ void SimulationCanvas::operator=(const Simulation& sim)
  mouse_pressed = false;
  mouse_over = -1;
  active = -1;

  sig_selection_changed.emit();
}

void SimulationCanvas::refresh()


@@ 80,9 79,32 @@ void SimulationCanvas::clear()
  mouse_over = active = -1;
  drag_state = DRAG_STATE_NONE;

  sig_selection_changed.emit();

  refresh();
}

bool SimulationCanvas::has_selection()
{
  if(active < 0)
    return false;

  if(active < 1024)
  {
    if(active < bodies.size())
      return true;
    else
      return false;
  }
  else
  {
    if((active-1024) < plates.size())
      return true;
    else
      return false;
  }
}

bool SimulationCanvas::delete_body(int n)
{
  if(!((n < bodies.size())


@@ 143,6 165,7 @@ bool SimulationCanvas::delete_selected()
  }

  active = -1;
  sig_selection_changed.emit();
  return r;
}



@@ 158,7 181,7 @@ float SimulationCanvas::get_selected_charge()
    n = active;
    if(n < bodies.size())
    {
      return bodies[n].charge;
      return fabs(bodies[n].charge);
    }
  }
  else


@@ 166,7 189,7 @@ float SimulationCanvas::get_selected_charge()
    n = active-1024;
    if(n < plates.size())
    {
      return plates[n].charge;
      return fabs(plates[n].charge);
    }
  }



@@ 178,6 201,7 @@ float SimulationCanvas::get_selected_charge()
bool SimulationCanvas::set_selected_charge(float value)
{
  int n;
  float delta = 0;

  if(active < 0)
    return false;


@@ 187,7 211,8 @@ bool SimulationCanvas::set_selected_charge(float value)
    n = active;
    if(n < bodies.size())
    {
      bodies[n].charge = value;
      delta = fabs(fabs(bodies[n].charge) - value);
      bodies[n].charge = sign(bodies[n].charge)*value;
    }
  }
  else


@@ 195,11 220,16 @@ bool SimulationCanvas::set_selected_charge(float value)
    n = active-1024;
    if(n < plates.size())
    {
      plates[n].charge = value;
      delta = fabs(fabs(plates[n].charge) - value);
      plates[n].charge = sign(plates[n].charge)*value;
    }
  }

  refresh();
  if(delta > 0.01)
  {
    refresh();
    sig_selected_charge_changed.emit();
  }

  return true;
}


@@ 210,7 240,7 @@ bool SimulationCanvas::change_selected_charge(float delta)

  float charge = get_selected_charge();
  new_charge = charge + sign(charge)*delta;
  if((fabs(new_charge) > 0.01)
  if((fabs(new_charge) >= (MIN_CHARGE - 0.01))
     && (fabs(new_charge) <= MAX_CHARGE)
     && (sign(new_charge) == sign(charge)))
  {


@@ 220,6 250,26 @@ bool SimulationCanvas::change_selected_charge(float delta)
  return true;
}

bool SimulationCanvas::increase_selected_charge(bool small)
{
  return change_selected_charge(small ? CHARGE_STEP_SMALL : CHARGE_STEP);
}

bool SimulationCanvas::decrease_selected_charge(bool small)
{
  return change_selected_charge(small ? -CHARGE_STEP_SMALL : -CHARGE_STEP);
}

sigc::signal<void> SimulationCanvas::signal_selected_charge_changed()
{
  return sig_selected_charge_changed;
}

sigc::signal<void> SimulationCanvas::signal_selection_changed()
{
  return sig_selection_changed;
}

void SimulationCanvas::run()
{
  profile_func_start(__PRETTY_FUNCTION__);


@@ 668,7 718,11 @@ bool SimulationCanvas::on_button_press_event(GdkEventButton *event)
                            2*plate_radius+4, 2*plate_radius+4);
    }

    active = mouse_over;
    if(active != mouse_over)
    {
      active = mouse_over;
      sig_selection_changed.emit();
    }
    draw_plates();
    draw_bodies();
  }


@@ 725,11 779,11 @@ bool SimulationCanvas::on_key_press_event(GdkEventKey *event)
  }
  else if(event->keyval == GDK_Up)
  {
    increase_selected_charge();
    increase_selected_charge(event->state & GDK_SHIFT_MASK);
  }
  else if(event->keyval == GDK_Down)
  {
    decrease_selected_charge();
    decrease_selected_charge(event->state & GDK_SHIFT_MASK);
  }
}


M src/SimulationCanvas.h => src/SimulationCanvas.h +21 -3
@@ 29,6 29,12 @@
namespace Elfelli
{

inline float sign(float f)
{
  if(f<0) return -1;
  return 1;
}

enum BodyState
  {
    BODY_STATE_NORMAL = 0,


@@ 54,6 60,8 @@ public:

  void operator=(const Simulation& sim);

  bool has_selection();

  void refresh();
  void clear();
  bool delete_body(int n);


@@ 64,8 72,16 @@ public:
  float get_selected_charge();

  bool change_selected_charge(float delta);
  bool increase_selected_charge(){return change_selected_charge(1);};
  bool decrease_selected_charge(){return change_selected_charge(-1);};
  bool increase_selected_charge(bool small=false);
  bool decrease_selected_charge(bool small=false);

  sigc::signal<void> signal_selected_charge_changed();
  sigc::signal<void> signal_selection_changed();

  static const float MAX_CHARGE;
  static const float MIN_CHARGE;
  static const float CHARGE_STEP;
  static const float CHARGE_STEP_SMALL;

private:
  void draw_flux_lines();


@@ 81,7 97,6 @@ private:
  int object_at(int x, int y);

  static char *color_names[];
  static const float MAX_CHARGE;

  int body_radius, plate_radius;



@@ 97,6 112,9 @@ private:
  Glib::RefPtr<Gdk::Pixmap> lines_pixmap;
  std::vector<Path> paths;

  sigc::signal<void> sig_selected_charge_changed;
  sigc::signal<void> sig_selection_changed;

protected:
  virtual void run();
  void plot();