// -*- C++ -*- /* * GChemPaint bonds plugin * bondtool.cc * * Copyright (C) 2001-2007 Jean Bréfort * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA */ #include "gchempaint-config.h" #include "bondtool.h" #include "lib/settings.h" #include "lib/document.h" #include "lib/application.h" #include "lib/atom.h" #include "lib/bond.h" #include "lib/theme.h" #include "libgcpcanvas/gcp-canvas-group.h" #include #include gcpBondTool::gcpBondTool (gcpApplication *App, string ToolId, unsigned nPoints): gcpTool (App, ToolId) { points = (nPoints)? gnome_canvas_points_new (nPoints): NULL; m_pOp = NULL; } gcpBondTool::~gcpBondTool () { if (points) gnome_canvas_points_free (points); } bool gcpBondTool::OnClicked () { if (Element::GetMaxBonds (m_pApp->GetCurZ()) < 1) return false; int i; m_pAtom = NULL; m_pItem = NULL; m_bChanged = false; m_dAngle = 0.; gcpBond* pBond; gcpDocument* pDoc = m_pView->GetDoc (); if (m_pObject) { TypeId Id = m_pObject->GetType (); switch (Id) { case BondType: pBond = (gcpBond*) m_pObject; m_pAtom = (gcpAtom*) pBond->GetAtom (0); m_pAtom->GetCoords (&m_x0, &m_y0, NULL); m_pAtom = (gcpAtom*) pBond->GetAtom (1); m_pAtom->GetCoords (&m_x1, &m_y1, NULL); m_x0 *= m_dZoomFactor; m_y0 *= m_dZoomFactor; m_x1 *= m_dZoomFactor; m_y1 *= m_dZoomFactor; points->coords[0] = m_x0; points->coords[1] = m_y0; m_bChanged = true; m_pOp = pDoc->GetNewOperation (GCP_MODIFY_OPERATION); m_pOp->AddObject (m_pObjectGroup, 0); UpdateBond (); return true; case AtomType: if (!((gcpAtom*)m_pObject)->AcceptNewBonds()) return false; ((gcpAtom*)m_pObject)->GetCoords(&m_x0, &m_y0, NULL); m_x0 *= m_dZoomFactor; m_y0 *= m_dZoomFactor; points->coords[0] = m_x0; points->coords[1] = m_y0; /* search preferred orientation for new bond */ i = ((gcpAtom*) m_pObject)->GetBondsNumber (); switch (i) { case 0: break; case 1: { map::iterator i; gcpBond* bond = (gcpBond*) ((Atom*) m_pObject)->GetFirstBond (i); m_dAngle = bond->GetAngle2D ((gcpAtom*) m_pObject); m_dAngle += (m_nState & GDK_LOCK_MASK)? pDoc->GetBondAngle (): -pDoc->GetBondAngle (); break; } case 2: { double a1, a2; map::iterator i; gcpBond* bond = (gcpBond*) ((Atom*) m_pObject)->GetFirstBond (i); a1 = bond->GetAngle2D ((gcpAtom*) m_pObject); bond = (gcpBond*) ((Atom*) m_pObject)->GetNextBond (i); a2 = bond->GetAngle2D ((gcpAtom*) m_pObject); m_dAngle = (a1 + a2) / 2.; a2 = fabs (a2 - m_dAngle); if (a2 < 90.) m_dAngle += 180.; if (m_dAngle > 360.) m_dAngle -= 360.; break; } default: break; } break; default: return false; } } else if (points) { points->coords[0] = m_x0; points->coords[1] = m_y0; } double a = m_dAngle * M_PI / 180.; m_x1 = m_x0 + pDoc->GetBondLength () * m_dZoomFactor * cos (a); m_y1 = m_y0 - pDoc->GetBondLength () * m_dZoomFactor * sin (a); GnomeCanvasItem* pItem = gnome_canvas_get_item_at(GNOME_CANVAS(m_pWidget), m_x1, m_y1); if (pItem == (GnomeCanvasItem*)m_pBackground) pItem = NULL; Object* pObject = NULL; if (pItem) pObject = (Object*)g_object_get_data(G_OBJECT(pItem), "object"); m_pAtom = NULL; if (pObject && pObject != m_pObject) { if ((pObject->GetType() == BondType) || (pObject->GetType() == FragmentType)) { m_pAtom = (gcpAtom*)pObject->GetAtomAt(m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor); } else if (pObject->GetType() == AtomType) { m_pAtom = (gcpAtom*)pObject; } } if (m_pAtom) { m_pAtom->GetCoords(&m_x1, &m_y1, NULL); m_x1 *= m_dZoomFactor; m_y1 *= m_dZoomFactor; m_x = m_x1 - m_x0; m_y = m_y1 - m_y0; m_dAngle = atan(-m_y/m_x) * 90 / 1.570796326794897; if (m_x < 0) m_dAngle += 180; } char tmp[32]; snprintf(tmp, sizeof(tmp) - 1, _("Orientation: %g"), m_dAngle); m_pApp->SetStatusText(tmp); Draw(); return true; } void gcpBondTool::OnDrag() { double x1, y1, x2, y2; gcpDocument* pDoc = m_pView->GetDoc (); gcpTheme *Theme = pDoc->GetTheme (); if ((m_pObject) && (m_pObject->GetType() == BondType)) { if (((gcpBond*)m_pObject)->GetDist(m_x / m_dZoomFactor, m_y / m_dZoomFactor) < (Theme->GetPadding () + Theme->GetBondWidth () / 2) * m_dZoomFactor) { if (!m_bChanged) { gnome_canvas_item_show(m_pItem); m_bChanged = true; } } else if (m_bChanged) { gnome_canvas_item_hide(m_pItem); m_bChanged = false; } } else { if (m_pItem) { gnome_canvas_item_get_bounds(GNOME_CANVAS_ITEM(m_pItem), &x1, &y1, &x2, &y2); gtk_object_destroy(GTK_OBJECT(GNOME_CANVAS_ITEM(m_pItem))); gnome_canvas_request_redraw(GNOME_CANVAS(m_pWidget), (int)x1, (int)y1, (int)x2, (int)y2); m_pItem = NULL; } GnomeCanvasItem* pItem = gnome_canvas_get_item_at(GNOME_CANVAS(m_pWidget), m_x, m_y); if (pItem == (GnomeCanvasItem*)m_pBackground) pItem = NULL; Object* pObject = NULL; if (pItem) { pObject = (Object*) g_object_get_data(G_OBJECT (pItem), "object"); if (pObject && (pObject == m_pObject || (pObject->GetType () == FragmentType && dynamic_cast (pObject)->GetAtom () == m_pObject))) return; } double dAngle; m_pAtom = NULL; if (MergeAtoms && pObject) { if (pObject->GetType() == BondType) { m_pAtom = (gcpAtom*)pObject->GetAtomAt(m_x / m_dZoomFactor, m_y / m_dZoomFactor); } else if (pObject->GetType() == FragmentType) { m_pAtom = (gcpAtom*)pObject->GetAtomAt(m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor); } else if (pObject->GetType() == AtomType) { m_pAtom = (gcpAtom*)pObject; } } if (m_pAtom) { if ((Object*)m_pAtom == m_pObject) return; if (!m_pAtom->AcceptNewBonds()) return; m_pAtom->GetCoords(&m_x1, &m_y1, NULL); m_x1 *= m_dZoomFactor; m_y1 *= m_dZoomFactor; m_x = m_x1 - m_x0; m_y = m_y1 - m_y0; dAngle = atan(-m_y/m_x) * 90 / 1.570796326794897; if (isnan (dAngle)) dAngle = m_dAngle; else if (m_x < 0.) dAngle += 180.; } else { m_x-= m_x0; m_y -= m_y0; if (m_x == 0) { if (m_y == 0) return; dAngle = (m_y < 0) ? 90 : 270; } else { dAngle = atan(-m_y/m_x) * 180 / M_PI; if (!(m_nState & GDK_CONTROL_MASK)) dAngle = rint(dAngle / 5) * 5; if (isnan (dAngle)) dAngle = m_dAngle; else if (m_x < 0.) dAngle += 180.; } m_dAngle = dAngle; if (m_nState & GDK_SHIFT_MASK) { x1 = sqrt(square(m_x) + square(m_y)); m_x1 = m_x0 + x1 * cos(m_dAngle / 180 * M_PI); m_y1 = m_y0 - x1 * sin(m_dAngle / 180 * M_PI); } else { m_x1 = m_x0 + pDoc->GetBondLength () * m_dZoomFactor * cos(m_dAngle / 180 * M_PI); m_y1 = m_y0 - pDoc->GetBondLength () * m_dZoomFactor * sin(m_dAngle / 180 * M_PI); } } char tmp[32]; if (dAngle < 0) dAngle += 360; snprintf(tmp, sizeof(tmp) - 1, _("Orientation: %g"), dAngle); m_pApp->SetStatusText(tmp); Draw(); } } void gcpBondTool::OnRelease() { double x1, y1, x2, y2; gcpDocument* pDoc = m_pView->GetDoc(); if (m_pItem) { gnome_canvas_item_get_bounds(GNOME_CANVAS_ITEM(m_pItem), &x1, &y1, &x2, &y2); gtk_object_destroy(GTK_OBJECT(GNOME_CANVAS_ITEM(m_pItem))); gnome_canvas_request_redraw(GNOME_CANVAS(m_pWidget), (int)x1, (int)y1, (int)x2, (int)y2); m_pItem = NULL; } else { if (m_pOp) pDoc->AbortOperation(); m_pOp = NULL; return; } if ((m_pObject) && (m_pObject->GetType() == BondType)) { FinalizeBond (); gcpAtom* pAtom = (gcpAtom*) ((gcpBond*) m_pObject)->GetAtom (0); pAtom->Update (); m_pView->Update (pAtom); pAtom = (gcpAtom*) ((gcpBond*) m_pObject)->GetAtom (1); pAtom->Update (); m_pView->Update (pAtom); m_pOp->AddObject (m_pObjectGroup, 1); pDoc->FinishOperation (); m_pOp = NULL; m_pObject->EmitSignal (OnChangedSignal); return; } else { if (m_pOp) pDoc->AbortOperation(); m_pOp = NULL; } m_pApp->ClearStatus(); GnomeCanvasItem* pItem = gnome_canvas_get_item_at(GNOME_CANVAS(m_pWidget), m_x1, m_y1); if (pItem == (GnomeCanvasItem*)m_pBackground) pItem = NULL; Object* pObject = NULL; if (pItem) pObject = (Object*)g_object_get_data(G_OBJECT(pItem), "object"); m_pAtom = NULL; if (MergeAtoms && pObject) { if (pObject->GetType() == BondType) { m_pAtom = (gcpAtom*)pObject->GetAtomAt(m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor); } else if (pObject->GetType() == FragmentType) { m_pAtom = (gcpAtom*)pObject->GetAtomAt(m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor); } else if (pObject->GetType() == AtomType) { m_pAtom = (gcpAtom*)pObject; } } gcpAtom* pAtom; gcpBond* pBond; if (!m_pObject) { //Add an atom at (x0, y0) pAtom = new gcpAtom (m_pApp->GetCurZ(), m_x0 / m_dZoomFactor, m_y0 / m_dZoomFactor, 0); pDoc->AddAtom (pAtom); m_pObject = pAtom; } else { pObject = m_pObject->GetGroup (); if (pObject) ModifiedObjects.insert (pObject->GetId ()); } if (m_pObject->GetType() == AtomType) { if (m_pAtom) { if (m_pObject == m_pAtom) { ModifiedObjects.clear (); return; } pObject = m_pObject->GetGroup (); if (!pObject) throw runtime_error (_("Invalid document tree, please file a bug report")); ModifiedObjects.insert (pObject->GetId ()); pAtom = m_pAtom; } else { pAtom = new gcpAtom(m_pApp->GetCurZ(), m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor, 0); pDoc->AddAtom(pAtom); } pBond = (gcpBond*)pAtom->GetBond((gcpAtom*)m_pObject); if (pBond) { m_pOp = pDoc-> GetNewOperation(GCP_MODIFY_OPERATION); m_pOp->AddObject(pBond->GetGroup (), 0); if (pBond->GetType() == NormalBondType) pBond->IncOrder(); m_pObject = pBond; m_bChanged = true; FinalizeBond(); gcpAtom* pAtom = (gcpAtom*) ((gcpBond*)m_pObject)->GetAtom(0); pAtom->Update (); m_pView->Update(pAtom); pAtom = (gcpAtom*) ((gcpBond*)m_pObject)->GetAtom(1); pAtom->Update (); m_pView->Update(pAtom); m_pView->Update(pBond); m_pOp->AddObject(pBond->GetGroup (), 1); pDoc->FinishOperation(); m_pOp = NULL; } else { // Push modified objects in Operation if (ModifiedObjects.size ()) { m_pOp = pDoc-> GetNewOperation(GCP_MODIFY_OPERATION); set::iterator it, end = ModifiedObjects.end(); for (it = ModifiedObjects.begin(); it != end; it++) m_pOp->AddObject (pDoc->GetDescendant ((*it).c_str ()), 0); } pBond = new gcpBond((gcpAtom*)m_pObject, pAtom, 1); SetType(pBond); pDoc->AddBond(pBond); if (m_pOp) { set::iterator it, end = ModifiedObjects.end(); for (it = ModifiedObjects.begin(); it != end; it++) { pObject = pDoc->GetDescendant ((*it).c_str ()); if (pObject) m_pOp->AddObject (pObject, 1); } } else { m_pOp = pDoc-> GetNewOperation(GCP_ADD_OPERATION); m_pOp->AddObject (pBond->GetMolecule ()); } pDoc->FinishOperation(); } } ModifiedObjects.clear (); } void gcpBondTool::Draw() { double x1, y1, x2, y2; gcpTheme *pTheme = m_pView->GetDoc ()->GetTheme (); points->coords[2] = m_x1; points->coords[3] = m_y1; m_pItem = gnome_canvas_item_new( m_pGroup, gnome_canvas_line_get_type(), "points", points, "fill_color", AddColor, "width_units", pTheme->GetBondWidth (), NULL); gnome_canvas_item_get_bounds(GNOME_CANVAS_ITEM(m_pItem), &x1, &y1, &x2, &y2); gnome_canvas_request_redraw(GNOME_CANVAS(m_pWidget), (int)x1, (int)y1, (int)x2, (int)y2); } void gcpBondTool::UpdateBond() { double x1, y1, x2, y2; int i = 1; gcpTheme *pTheme = m_pView->GetDoc ()->GetTheme (); BondOrder = ((gcpBond*)m_pObject)->GetOrder(); if (((gcpBond*)m_pObject)->GetType() == NormalBondType) ((gcpBond*)m_pObject)->IncOrder(); m_pItem = gnome_canvas_item_new(m_pGroup, gnome_canvas_group_ext_get_type(), NULL); while (((gcpBond*)m_pObject)->GetLine2DCoords(i++, &x1, &y1, &x2, &y2)) { points->coords[0] = x1 * m_dZoomFactor; points->coords[1] = y1 * m_dZoomFactor; points->coords[2] = x2 * m_dZoomFactor; points->coords[3] = y2 * m_dZoomFactor; gnome_canvas_item_new( GNOME_CANVAS_GROUP(m_pItem), gnome_canvas_line_get_type(), "points", points, "fill_color", AddColor, "width_units", pTheme->GetBondWidth (), NULL); } gnome_canvas_item_get_bounds(GNOME_CANVAS_ITEM(m_pItem), &x1, &y1, &x2, &y2); gnome_canvas_request_redraw(GNOME_CANVAS(m_pWidget), (int)x1, (int)y1, (int)x2, (int)y2); } void gcpBondTool::FinalizeBond() { if (m_bChanged) { gcpBond* pBond = (gcpBond*)m_pObject; if (pBond->GetType () == NormalBondType) { pBond->Revert (); m_pView->Update (m_pObject); } else { pBond->SetType (NormalBondType); m_pView->Remove (m_pObject); m_pView->AddObject (m_pObject); } } else ((gcpBond*)m_pObject)->SetOrder(BondOrder); m_pView->Update(((gcpBond*)m_pObject)->GetAtom(0)); m_pView->Update(((gcpBond*)m_pObject)->GetAtom(1)); } void gcpBondTool::SetType(gcpBond* pBond) { pBond->SetType(NormalBondType); } static void on_length_changed (GtkSpinButton *btn, gcpBondTool *tool) { tool->SetLength (gtk_spin_button_get_value (btn)); } static void on_angle_changed (GtkSpinButton *btn, gcpBondTool *tool) { tool->SetAngle (gtk_spin_button_get_value (btn)); } static void on_merge_toggled (GtkToggleButton *btn) { MergeAtoms = gtk_toggle_button_get_active (btn); } void gcpBondTool::SetAngle (double angle) { m_pApp->GetActiveDocument ()->SetBondAngle (angle); } void gcpBondTool::SetLength (double length) { m_pApp->GetActiveDocument ()->SetBondLength (length); } GtkWidget *gcpBondTool::GetPropertyPage () { GladeXML *xml = glade_xml_new (GLADEDIR"/bond.glade", "bond", GETTEXT_PACKAGE); m_LengthBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "bond-length")); g_signal_connect (m_LengthBtn, "value-changed", G_CALLBACK (on_length_changed), this); m_AngleBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "bond-angle")); g_signal_connect (m_AngleBtn, "value-changed", G_CALLBACK (on_angle_changed), this); m_MergeBtn = GTK_TOGGLE_BUTTON (glade_xml_get_widget (xml, "merge")); g_signal_connect (m_MergeBtn, "toggled", G_CALLBACK (on_merge_toggled), NULL); return glade_xml_get_widget (xml, "bond"); } void gcpBondTool::Activate () { gcpDocument *pDoc = m_pApp->GetActiveDocument (); gtk_spin_button_set_value (m_LengthBtn, pDoc->GetBondLength ()); gtk_spin_button_set_value (m_AngleBtn, pDoc->GetBondAngle ()); gtk_toggle_button_set_active (m_MergeBtn, MergeAtoms); } gcpUpBondTool::gcpUpBondTool(gcpApplication *App): gcpBondTool(App, "UpBond", 3) { } gcpUpBondTool::~gcpUpBondTool() { } void gcpUpBondTool::Draw() { double dx, dy, x1, y1, x2, y2; gcpTheme *Theme = m_pView->GetDoc ()->GetTheme (); x1 = sqrt(square(m_x1 - m_x0) + square(m_y1 - m_y0)); if (x1 == 0) return; dx = (m_y0 - m_y1) / x1 * Theme->GetStereoBondWidth () / 2; dy = (m_x1 - m_x0) / x1 * Theme->GetStereoBondWidth () / 2; points->coords[2] = m_x1 + dx; points->coords[3] = m_y1 + dy; points->coords[4] = m_x1 - dx; points->coords[5] = m_y1 - dy; m_pItem = gnome_canvas_item_new( m_pGroup, gnome_canvas_polygon_get_type(), "points", points, "fill_color", AddColor, NULL); gnome_canvas_item_get_bounds(GNOME_CANVAS_ITEM(m_pItem), &x1, &y1, &x2, &y2); gnome_canvas_request_redraw(GNOME_CANVAS(m_pWidget), (int)x1, (int)y1, (int)x2, (int)y2); } void gcpUpBondTool::UpdateBond() { if (((gcpBond*)m_pObject)->GetType() == UpBondType) { m_x = m_x0; m_x0 = m_x1; m_x1 = m_x; m_y = m_y0; m_y0 = m_y1; m_y1 = m_y; points->coords[0] = m_x0; points->coords[1] = m_y0; } Draw(); } void gcpUpBondTool::FinalizeBond() { if (m_bChanged) { gcpBond* pBond = (gcpBond*)m_pObject; if (pBond->GetType () == UpBondType) { pBond->Revert (); m_pView->Update (m_pObject); } else { pBond->SetType (UpBondType); m_pView->Remove (m_pObject); m_pView->AddObject (m_pObject); } } } void gcpUpBondTool::SetType(gcpBond* pBond)//FIXME: Is it really useful? { pBond->SetType(UpBondType); } gcpDownBondTool::gcpDownBondTool(gcpApplication *App): gcpBondTool(App, "DownBond", 4) { } gcpDownBondTool::~gcpDownBondTool() { } void gcpDownBondTool::Draw() { double dx, dy, dx1, dy1, length; gcpTheme *pTheme = m_pView->GetDoc ()->GetTheme (); m_pItem = gnome_canvas_item_new(m_pGroup, gnome_canvas_group_ext_get_type(), NULL); length = sqrt(square(m_x1 - m_x0) + square(m_y1 - m_y0)); if (length == 0.0) return; int n = int(floor(length / (pTheme->GetHashDist () + pTheme->GetHashWidth ()))); dx1 = (m_x1 - m_x0) / length * pTheme->GetHashWidth (); dy1 = (m_y1 - m_y0) / length * pTheme->GetHashWidth (); dx = (m_y0 - m_y1) / length * pTheme->GetStereoBondWidth () / 2; dy = (m_x1 - m_x0) / length * pTheme->GetStereoBondWidth () / 2; points->coords[0] = m_x0 + dx; points->coords[1] = m_y0 + dy; points->coords[2] = m_x0 - dx; points->coords[3] = m_y0 - dy; dx *= (1 - pTheme->GetHashWidth () / length); dy *= (1 - pTheme->GetHashWidth () / length); points->coords[4] = m_x0 + dx1 - dx; points->coords[5] = m_y0 + dy1 - dy; points->coords[6] = m_x0 + dx1 + dx; points->coords[7] = m_y0 + dy1 + dy; dx = (m_x1 - m_x0) / length * (pTheme->GetHashDist () + pTheme->GetHashWidth ()) - (m_y0 - m_y1) / length * pTheme->GetStereoBondWidth () / 2 * (pTheme->GetHashDist () + pTheme->GetHashWidth ()) / length; dy = (m_y1 - m_y0) / length * (pTheme->GetHashDist () + pTheme->GetHashWidth ()) - (m_x1 - m_x0) / length * pTheme->GetStereoBondWidth () / 2 * (pTheme->GetHashDist () + pTheme->GetHashWidth ()) / length; dx1 = (m_x1 - m_x0) / length * (pTheme->GetHashDist () + pTheme->GetHashWidth ()) + (m_y0 - m_y1) / length * pTheme->GetStereoBondWidth () / 2 * (pTheme->GetHashDist () + pTheme->GetHashWidth ()) / length; dy1 = (m_y1 - m_y0) / length * (pTheme->GetHashDist () + pTheme->GetHashWidth ()) + (m_x1 - m_x0) / length * pTheme->GetStereoBondWidth () / 2 * (pTheme->GetHashDist () + pTheme->GetHashWidth ()) / length; gnome_canvas_item_new( GNOME_CANVAS_GROUP(m_pItem), gnome_canvas_polygon_get_type(), "points", points, "fill_color", AddColor, NULL); for (int i = 1; i < n; i++) { points->coords[0] += dx; points->coords[1] += dy; points->coords[2] += dx1; points->coords[3] += dy1; points->coords[6] += dx; points->coords[7] += dy; points->coords[4] += dx1; points->coords[5] += dy1; gnome_canvas_item_new( GNOME_CANVAS_GROUP(m_pItem), gnome_canvas_polygon_get_type(), "points", points, "fill_color", AddColor, NULL); } gnome_canvas_item_get_bounds(m_pItem, &dx, &dy, &dx1, &dy1); gnome_canvas_request_redraw(GNOME_CANVAS(m_pWidget), (int)dx, (int)dy, (int)dx1, (int)dy1); } void gcpDownBondTool::UpdateBond() { if (((gcpBond*)m_pObject)->GetType() == DownBondType) { m_x = m_x0; m_x0 = m_x1; m_x1 = m_x; m_y = m_y0; m_y0 = m_y1; m_y1 = m_y; } Draw(); } void gcpDownBondTool::FinalizeBond() { if (m_bChanged) { gcpBond* pBond = (gcpBond*)m_pObject; if (pBond->GetType () == DownBondType) { pBond->Revert (); m_pView->Update (m_pObject); } else { pBond->SetType (DownBondType); m_pView->Remove (m_pObject); m_pView->AddObject (m_pObject); } } } void gcpDownBondTool::SetType(gcpBond* pBond) { pBond->SetType(DownBondType); } gcpForeBondTool::gcpForeBondTool(gcpApplication *App): gcpBondTool(App, "ForeBond", 4) { } gcpForeBondTool::~gcpForeBondTool() { } void gcpForeBondTool::Draw() { double dx, dy, x1, y1, x2, y2; gcpTheme *pTheme = m_pView->GetDoc ()->GetTheme (); x1 = sqrt(square(m_x1 - m_x0) + square(m_y1 - m_y0)); if (x1 == 0) return; dx = (m_y0 - m_y1) / x1 * pTheme->GetStereoBondWidth () / 2; dy = (m_x1 - m_x0) / x1 * pTheme->GetStereoBondWidth () / 2; points->coords[0] = m_x0 + dx; points->coords[1] = m_y0 + dy; points->coords[2] = m_x1 + dx; points->coords[3] = m_y1 + dy; points->coords[4] = m_x1 - dx; points->coords[5] = m_y1 - dy; points->coords[6] = m_x0 - dx; points->coords[7] = m_y0 - dy; m_pItem = gnome_canvas_item_new( m_pGroup, gnome_canvas_polygon_get_type(), "points", points, "fill_color", AddColor, NULL); gnome_canvas_item_get_bounds(GNOME_CANVAS_ITEM(m_pItem), &x1, &y1, &x2, &y2); gnome_canvas_request_redraw(GNOME_CANVAS(m_pWidget), (int)x1, (int)y1, (int)x2, (int)y2); } void gcpForeBondTool::UpdateBond () { Draw(); } void gcpForeBondTool::FinalizeBond () { if (m_bChanged) { gcpBond* pBond = (gcpBond*) m_pObject; if (pBond->GetType () != ForeBondType) { pBond->SetType (ForeBondType); m_pView->Remove (m_pObject); m_pView->AddObject (m_pObject); } } } void gcpForeBondTool::SetType (gcpBond* pBond) { pBond->SetType (ForeBondType); } gcpSquiggleBondTool::gcpSquiggleBondTool(gcpApplication *App): gcpBondTool(App, "SquiggleBond", 4) { } gcpSquiggleBondTool::~gcpSquiggleBondTool() { } void gcpSquiggleBondTool::Draw() { GnomeCanvasPathDef *path_def; gcpTheme *pTheme = m_pView->GetDoc ()->GetTheme (); path_def = gnome_canvas_path_def_new(); gnome_canvas_path_def_moveto(path_def, m_x0, m_y0); double x = m_x0, y = m_y0, dx, dy, length, x1, x2, y1, y2; length = sqrt(square(m_x1 - m_x0) + square(m_y1 - m_y0)); int n = (int)length / 3, s = 1; dx = (m_x1 - m_x0) / n; dy = (m_y1 - m_y0) / n; for (int i = 1; i < n; i++) { x1 = x + dx / 3 + dy /1.5 * s; y1 = y + dy / 3 - dx /1.5 * s; x2 = x + dx / 1.5 + dy /1.5 * s; y2 = y + dy / 1.5 - dx /1.5 * s; x += dx; y += dy; s *= -1; gnome_canvas_path_def_curveto(path_def, x1, y1, x2, y2, x, y); } x1 = x + dx / 3 + dy /1.5 * s; y1 = y + dy / 3 - dx /1.5 * s; x2 = x + dx / 1.5 + dy /1.5 * s; y2 = y + dy / 1.5 - dx /1.5 * s; gnome_canvas_path_def_curveto(path_def, x1, y1, x2, y2, m_x1, m_y1); m_pItem = gnome_canvas_item_new( m_pGroup, gnome_canvas_bpath_get_type(), "outline_color", AddColor, "width_units", pTheme->GetBondWidth (), "bpath", path_def, NULL); gnome_canvas_path_def_unref(path_def); } void gcpSquiggleBondTool::UpdateBond() { Draw(); } void gcpSquiggleBondTool::FinalizeBond() { if (m_bChanged) { gcpBond* pBond = (gcpBond*)m_pObject; if (pBond->GetType () == UndeterminedBondType) { pBond->Revert (); m_pView->Update (m_pObject); } else { pBond->SetType (UndeterminedBondType); m_pView->Remove (m_pObject); m_pView->AddObject (m_pObject); } } } void gcpSquiggleBondTool::SetType(gcpBond* pBond) { pBond->SetType(UndeterminedBondType); }