Logo Search packages:      
Sourcecode: passepartout version File versions  Download package

propertiesdialog.cc

///
// Copyright (C) 2002 - 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING
///
#include "propertiesdialog.h"
#include "propbase.h"
#include "widget/subpanel.h"
#include "widget/wmisc.h"
#include "util/matrix.h"
#include "util/stringutil.h"
#include "util/warning.h"
#include <gtkmm/label.h>
#include <gtkmm/separator.h>
#include <gtkmm/entry.h>
#include <gtkmm/checkbutton.h>
#include <gtkmm/stock.h>
#include <gtkmm/sizegroup.h>
#include <sigc++/bind.h>
#include <algorithm>
#include "pptcore.h"
#include "widget/spinner.h"
#include "document/basicframe.h"
#include "lengthunits.h"
#include "config.h"


// The basic properties that apply to all Pagent's.
// Currently that means some kind of name, and the position and size of the
// object.
class PropBasic : public PropBase {
  enum ChangeId { NAME, LEFT, BOTTOM, WIDTH, HEIGHT, ROTATE,
              LOCKED, FLOWAROUND, MARGIN };
public:
  // | name:  | "name of object"             |
  // -----------------------------------------
  // | left:  | "left"  | width:  | "width"  |
  // | right: | "right" | height: | "height" |
  PropBasic(const std::string &default_unit)
    :PropBase("_Basic"), object(0),
     e_left(0, true, &length_units, default_unit),
     e_bottom(0, true, &length_units, default_unit), 
     e_width(0, true, &length_units, default_unit),
     e_height(0, true, &length_units, default_unit), 
     e_rotate(0, true, &angle_units), 
     e_margin(0, true, &length_units, default_unit),
     c_flow("Text avoids object", 0), c_locked("Locked", 0)
  {
      Gtk::Label *label;
      Gtk::Box *line = manage(new Gtk::HBox(false, double_space));
      line->pack_start(*(label = manage(new Gtk::Label("Object _name:", 
                                           0.0, 0.5, true))),
                   Gtk::PACK_SHRINK);
      label->set_mnemonic_widget(e_name);
      line->pack_start(e_name);
      // not sure if connecting to signal_activate adds anything
      e_name.signal_activate().connect
      (bind(slot(*this, &PropBasic::on_change), NAME));
      e_name.signal_focus_out_event().connect
        (SigC::hide<GdkEventFocus*>
         (bind_return(bind(slot(*this, &PropBasic::on_change), NAME), true)));
      pack_start(*line, Gtk::PACK_SHRINK);
      
      SubPanel *box = manage(new SubPanel("Geometry"));
      Glib::RefPtr<Gtk::SizeGroup>  sizegroup = 
      Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);

      line = manage(new Gtk::HBox(false, double_space));
      sizegroup->add_widget(*(label = manage(new Gtk::Label("_Left:", 
                                              0.0, 0.5, true))));
      line->pack_start(*label, Gtk::PACK_SHRINK);
      line->pack_start(e_left, Gtk::PACK_SHRINK);
      e_left.signal_value_changed().connect
      (bind(slot(*this, &PropBasic::on_change), LEFT));
      label->set_mnemonic_widget(e_left);

      sizegroup->add_widget(*(label = manage(new Gtk::Label("_Width:",
                                              0.0, 0.5, true))));
      line->pack_start(*label, Gtk::PACK_SHRINK);
      line->pack_start(e_width, Gtk::PACK_SHRINK);
      label->set_mnemonic_widget(e_width);
      e_width.signal_value_changed().connect
      (bind(slot(*this, &PropBasic::on_change), WIDTH));
      box->pack_start(*line, Gtk::PACK_SHRINK);
      
      line = manage(new Gtk::HBox(false, double_space));
      sizegroup->add_widget(*(label = manage(new Gtk::Label("_Bottom:", 
                                              0.0, 0.5, true))));
      line->pack_start(*label, Gtk::PACK_SHRINK);
      line->pack_start(e_bottom, Gtk::PACK_SHRINK);
      e_bottom.signal_value_changed().connect
      (bind(slot(*this, &PropBasic::on_change), BOTTOM));
      label->set_mnemonic_widget(e_bottom);

      sizegroup->add_widget(*(label = manage(new Gtk::Label("_Height:",
                                              0.0, 0.5, true))));
      line->pack_start(*label, Gtk::PACK_SHRINK);
      line->pack_start(e_height, Gtk::PACK_SHRINK);
      label->set_mnemonic_widget(e_height);
      e_height.signal_value_changed().connect
      (bind(slot(*this, &PropBasic::on_change), HEIGHT));
      box->pack_start(*line, Gtk::PACK_SHRINK);
      
      line = manage(new Gtk::HBox(false, double_space));
      sizegroup->add_widget(*(label = manage(new Gtk::Label("R_otate:",
                                              0.0, 0.5, true))));
      line->pack_start(*label, Gtk::PACK_SHRINK);
      line->pack_start(e_rotate, Gtk::PACK_SHRINK);
      label->set_mnemonic_widget(e_rotate);
      e_rotate.signal_value_changed().connect
      (bind(slot(*this, &PropBasic::on_change), ROTATE));
      
      box->pack_start(*line, Gtk::PACK_SHRINK);
      pack_start(*box, Gtk::PACK_SHRINK);
      
      pack_start(hsep2, Gtk::PACK_SHRINK);
      
      Gtk::HBox *flow_box = manage(new Gtk::HBox(false, double_space));
      flow_box->pack_start(c_locked, Gtk::PACK_SHRINK, triple_space);
      c_locked.signal_toggled().connect
      (bind(slot(*this, &PropBasic::on_change), LOCKED));
      flow_box->pack_start(c_flow, Gtk::PACK_SHRINK, 0);
      c_flow.signal_toggled().connect
      (bind(slot(*this, &PropBasic::on_change), FLOWAROUND));
      flow_box->pack_start(e_margin, Gtk::PACK_SHRINK, 0);
      e_margin.signal_value_changed().connect
      (bind(slot(*this, &PropBasic::on_change), MARGIN));
      pack_start(*flow_box, Gtk::PACK_SHRINK);

      set_sensitive(false);
    }
  void on_geometry_changed(Pagent* pagent) {
    update();
  }
  void on_props_changed(Pagent* pagent) {
    update();
  }
  void setObject(Pagent* pagent) {
    geometry_changed_connection.disconnect();
    props_changed_connection.disconnect();
    object = pagent;
    if(object) {
      geometry_changed_connection = object->geometry_changed_signal.connect
      (slot(*this, &PropBasic::on_geometry_changed));
      props_changed_connection = object->props_changed_signal.connect
      (slot(*this, &PropBasic::on_props_changed));
    }
    set_sensitive(object);
    if(is_visible())
      update();
  }
  void update() {
    if(!object) {
      e_name.set_text("");
    } else {
      // Todo: Use an "objecthider", so the toggle back works even if we get
      // an exception!
      Pagent* obj = object; object = 0;   // Don't apply while updating
      e_name.set_text(obj->get_name());

      c_locked.set_active(obj->get_lock());
      
      // geometry
      const Matrix &m = obj->get_matrix();
      const Vector size = obj->get_inherent_size();
      e_left.set(m.tr_x());
      e_bottom.set(m.tr_y());
      e_width.set(size.x * m.sc_x());
      e_height.set(size.y * m.sc_y());
      e_rotate.set(Matrix::rad2deg(m.rot()));

      const bool flowaround = obj->get_flow_around();
      c_flow.set_active(flowaround);
      e_margin.set_sensitive(flowaround);
      e_margin.set(obj->get_obstacle_margin());
      object = obj;
    }
  }
  void on_change(ChangeId what) {
    if(object) switch(what) {
    case NAME:
      object->set_name(e_name.get_text());
      break;
      
    case LEFT:
    case BOTTOM:
      object->set_translation(Vector(e_left.get(), e_bottom.get()));
      break;
      
    case WIDTH:
    case HEIGHT:
      if(Pagent::Resizable* o = dynamic_cast<Pagent::Resizable*>(object))
      o->set_size(e_width.get(), e_height.get());
      else {
      const Vector size = object->get_inherent_size();
      object->set_scaling(e_width.get() / size.x,
                      e_height.get() / size.y);
      }
      break;
      
    case ROTATE:
      object->set_rotation(Matrix::deg2rad(e_rotate.get()));
      break;
      
    case LOCKED:
      object->set_lock(c_locked.get_active());
      break;
      
    case FLOWAROUND: {
      const bool flow = c_flow.get_active();
      e_margin.set_sensitive(flow);
      object->set_flow_around(flow);
    } break;
      
    case MARGIN:
      object->set_obstacle_margin(e_margin.get());
      break;
    }
  }
  void set_sensitive(bool sensitive) {
    getLabel().set_sensitive(sensitive);
    Gtk::VBox::set_sensitive(sensitive);
  }
private:
  Pagent* object;
  Gtk::HSeparator hsep1, hsep2;
  Gtk::Entry e_name;
  Spinner e_left, e_bottom, e_width, e_height, e_rotate, e_margin;
  Gtk::CheckButton c_flow, c_locked;
  SigC::Connection geometry_changed_connection, props_changed_connection;
};

// - - - - back to the actual PropertiesDialog implementation - - - -

PropertiesDialog *PropertiesDialog::_instance = 0;

PropertiesDialog &PropertiesDialog::instance() {
  if(!_instance)
    _instance = new PropertiesDialog();
  return *_instance;
}

PropertiesDialog::PropertiesDialog()
  : UtilityWindow("Object properties"),
    document(0)
{
  add(book);

  book.signal_switch_page().connect
    (slot(*this, &PropertiesDialog::show_page_contents));

  PropBase* prop = new PropBasic(config.LengthUnit.values.front());
  pages.push_back(prop);
  book.append_page(*prop, prop->getLabel());
  for(PptCore::MetaMap::const_iterator
      i = core.m_begin(); i != core.m_end(); ++i) {
    if(PropBase* prop = i->second->getProp()) {
      pages.push_back(prop);
      book.append_page(*prop, prop->getLabel());
    }
  }
  
  // listen to selection change signals:
  Document::selection_changed_signal.connect
    (slot(*this, &PropertiesDialog::select_change));
}

PropertiesDialog::~PropertiesDialog() {}

void
00269 PropertiesDialog::show_raise() {
  show_all();
  UtilityWindow::show_raise();
  
  update();
}

void
PropertiesDialog::set_document(DocRef document_) {
  document = document_;
  update();
}

void
PropertiesDialog::update() {
  Document::Selection all_selected;
  if(document) 
    all_selected = document->selected();

  // Note: If there is more than one object selected, no properties are shown.
  // Maybe we should show the properties that are common
  // to all selected objects.
  Pagent* pagent = (all_selected.size()!=1 ? 0
                : all_selected.front());

  for(std::vector<PropBase*>::const_iterator i = pages.begin();
      i != pages.end(); ++i)
    (*i)->setObject(pagent);
  show_page_contents(0, book.get_current_page());
}

void
PropertiesDialog::select_change(DocRef doc) {
  if(document == doc)
    update();
}

// this is part of the workaround for the problem with Gtk::Entry and
// hidden tabs, see propbase.cc
void PropertiesDialog::show_page_contents(GtkNotebookPage*, guint index) {
  dynamic_cast<Gtk::Container*>(book.get_nth_page(index))->show_all_children();
}

Generated by  Doxygen 1.6.0   Back to index