Re: [sigc] conditions in libsigc



I wrote:
> > This is getting pretty pointless.  Lets end it here, as an ounce of code is 
> > worth a pound of words.
> 
> OK.  I'll try to write something.

Here is `something'.

I didn't write anything complete, therefore things are not properly optimized,
application doesn't terminate when both windows are closed etc.

Condition creation is ugly because there is no support from Gtkmm.

Probably there should be functions like `Gtk::Widget::set_sensitive (sigc::condition)'
instead of all this `SensitivityController' stuff.

Compile like this:

  g++ -g conditions.cpp -o conditions  `pkg-config --cflags --libs sigc++-2.0` `pkg-config --cflags --libs gtkmm-2.4` 

Paul


#include <sigc++/signal.h>
#include <gtkmm.h>


// sigc++ part.

class condition;


class condition_impl : public sigc::trackable
{
  friend  class condition; 


  bool				  state;
  int				  reference_counter;
  sigc::signal <void, condition>  state_changed;


  void
  reference ()
  {
    ++reference_counter;
  }

  bool
  unreference ()
  {
    if (!--reference_counter)
      delete this;
  }


protected:

  explicit
  condition_impl (bool initial_state)
    : state		(initial_state),
      reference_counter (0)
  { }

  virtual
  ~condition_impl ()
  { }

  void  set_state (bool new_state);
};


class condition
{
  condition_impl*  implementation;


public:

  explicit
  condition (condition_impl* implementation)
    : implementation (implementation)
  {
    implementation->reference ();
  }

  condition (const condition& other_condition)
    : implementation (other_condition.implementation)
  {
    implementation->reference ();
  }

  ~condition ()
  {
    implementation->unreference ();
  }


  operator bool () const
  {
    return implementation->state;
  }

  sigc::signal <void, condition>&
  signal_state_changed ()
  {
    return implementation->state_changed;
  }
};


class conjunction : public condition_impl
{
  const condition  first;
  const condition  second;


public:

  conjunction (condition first, condition second);


private:

  void  update (condition condition);
};


void
condition_impl::set_state (bool new_state)
{
  if (state != new_state)
    {
      state = new_state;
      state_changed (condition (this));
    }
}


conjunction::conjunction (condition first, condition second)
  : condition_impl (first && second),
    first	   (first),
    second	   (second)
{
  first.signal_state_changed  ().connect (sigc::mem_fun (*this, &conjunction::update));
  second.signal_state_changed ().connect (sigc::mem_fun (*this, &conjunction::update));
}


inline  condition
operator& (condition first, condition second)
{
  return condition (new conjunction (first, second));
}


void
conjunction::update (condition condition)
{
  set_state (first && second);
}


// Gtkmm part.

class EntryNotEmptyCondition : public condition_impl
{
  const Glib::RefPtr <Gtk::Entry>  entry;


public:

  explicit
  EntryNotEmptyCondition (Gtk::Entry* entry)
    : condition_impl (entry->get_text_length () > 0),
      entry	     (entry)
  {
    entry->signal_changed ().connect (sigc::mem_fun (*this, &EntryNotEmptyCondition::update_condition));
  }


  void
  update_condition ()
  {
    set_state (entry->get_text_length () > 0);
  }
};


class ToggleButtonActiveCondition : public condition_impl
{
  const Glib::RefPtr <Gtk::ToggleButton>  toggle_button;


public:

  explicit
  ToggleButtonActiveCondition (Gtk::ToggleButton* toggle_button)
    : condition_impl (toggle_button->get_active ()),
      toggle_button  (toggle_button)
  {
    toggle_button->signal_toggled ().connect (sigc::mem_fun (*this, &ToggleButtonActiveCondition::update_condition));
  }


  void
  update_condition ()
  {
    set_state (toggle_button->get_active ());
  }
};


class SensivityController
{
  Glib::RefPtr <Gtk::Widget>  widget;
  condition		      sensitivity;


public:

  SensivityController (Gtk::Widget* widget, condition sensitivity)
    : widget      (widget),
      sensitivity (sensitivity)
  {
    sensitivity.signal_state_changed ().connect
      (sigc::mem_fun (*this, &SensivityController::update_sensivity));
    update_sensivity (sensitivity);
  }


  void
  update_sensivity (condition condition)
  {
    widget->set_sensitive (condition);
  }
};


// Program part.

class Windows
{
  Gtk::Window*          window;
  Gtk::VBox*	        vbox;
  Gtk::Entry*           entry;
  Gtk::CheckButton*     check_button;
  Gtk::Button*          button;
  SensivityController*  controller;


public:

  Windows ()
  {
    window       = new Gtk::Window ();
    vbox	 = manage (new Gtk::VBox (false, 12));
    entry	 = manage (new Gtk::Entry ());
    check_button = manage (new Gtk::CheckButton ("Check me"));
    button       = manage (new Gtk::Button (Gtk::Stock::CLOSE));

    window->add (*vbox);
    vbox->add (*entry);
    vbox->add (*check_button);
    vbox->add (*button);

    window->set_title ("With Conditions");

    controller = new SensivityController (button,
					  (condition (new EntryNotEmptyCondition (entry))
					   & condition (new ToggleButtonActiveCondition (check_button))));

    window->show_all ();

    window       = new Gtk::Window ();
    vbox	 = manage (new Gtk::VBox (false, 12));
    entry	 = manage (new Gtk::Entry ());
    check_button = manage (new Gtk::CheckButton ("Check me"));
    button       = manage (new Gtk::Button (Gtk::Stock::CLOSE));

    window->add (*vbox);
    vbox->add (*entry);
    vbox->add (*check_button);
    vbox->add (*button);

    window->set_title ("Without Conditions");

    entry->signal_changed ().connect (sigc::mem_fun (*this, &Windows::update_sensitivity));
    check_button->signal_toggled ().connect (sigc::mem_fun (*this, &Windows::update_sensitivity));

    // Set initial state.
    update_sensitivity ();

    window->show_all ();
  }


private:

  void
  update_sensitivity ()
  {
    button->set_sensitive (entry->get_text_length () > 0 && check_button->get_active ());
  }
};


int
main (int argc, char** argv)
{
  Gtk::Main  main_loop (argc, argv);
  Windows    windows;

  main_loop.run ();

  return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]