// -*- C++ -*- /* * GChemPaint cycles plugin * cycletool.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 "cycletool.h" #include "lib/settings.h" #include "lib/document.h" #include "lib/application.h" #include "lib/theme.h" #include #include #include #include using namespace std; static char* ToolNames [] = { (char*) "Cycle3", (char*) "Cycle4", (char*) "Cycle5", (char*) "Cycle6", (char*) "Cycle7", (char*) "Cycle8", (char*) "CycleN", }; gcpCycleTool::gcpCycleTool(gcpApplication *App, unsigned char size): gcpTool(App, ToolNames[size - 3]) { if ((m_size = size)) Init(); else m_xn = NULL; m_Chain = NULL; } gcpCycleTool::~gcpCycleTool() { if (m_size) { delete [] m_xn; gnome_canvas_points_free(points); } if (m_Chain) delete m_Chain; } bool gcpCycleTool::OnClicked() { if (!m_size) return false; double x1, y1, x2, y2; double a0, a1, a2, b1, b2, m1, m2; gcpAtom* pAtom, *pAtom1; gcpBond* pBond, *pBond1; gcpDocument *pDoc = m_pView->GetDoc (); gcpTheme *pTheme = pDoc->GetTheme (); m_dLength = pDoc->GetBondLength () * m_dZoomFactor; map::iterator j; int i; bool bDone = false; m_dDefAngle = 0.0; if (m_pObject) { bDone = true; switch (m_pObject->GetType()) { case BondType: pBond = (gcpBond*) m_pObject; pAtom = (gcpAtom*)pBond->GetAtom(0); pAtom->GetCoords(&x1, &y1); x1 *= m_dZoomFactor; y1 *= m_dZoomFactor; pAtom1 = (gcpAtom*)pBond->GetAtom(1); pAtom1->GetCoords(&x2, &y2); x2 *= m_dZoomFactor; y2 *= m_dZoomFactor; m_dLength = sqrt(square(x2 - x1) + square(y2 - y1)); if (pBond->IsCyclic() == 1) { gcpCycle *pCycle = NULL; list::iterator i; pCycle = pBond->GetFirstCycle(i, pCycle); a0 = atan2(y1 - y2, x2 - x1); pCycle->GetAngles2D(pBond, &a1, &a2); if (sin(a0 - a1) * sin (a0 - a2) > 0) { if (sin(a0 - a1) < 0.0) { points->coords[0] = m_xn[0] = m_x0 = x1; points->coords[1] = m_xn[1] = m_y0 = y1; m_dAngle = a0; m_Start = pAtom; m_End = pAtom1; m_Direct = true; } else { points->coords[0] = m_xn[0] = m_x0 = x1 = x2; points->coords[1] = m_xn[1] = m_y0 = y1 = y2; m_dAngle = a0 - M_PI; m_Start = pAtom1; m_End = pAtom; m_Direct = false; } } } else { m_Start = pAtom; m_End = pAtom1; a0 = pBond->GetAngle2DRad(pAtom); b1 = a0 + m_dDev; b2 = a0 - m_dDev; m1 = m2 = M_PI; pBond1 = (gcpBond*)pAtom->GetFirstBond(j); while (pBond1) { if (pBond == pBond1) { pBond1 = (gcpBond*)pAtom->GetNextBond(j); continue; } a1 = pBond1->GetAngle2DRad(pAtom); a2 = fabs(b2 - a1); if (a2 > M_PI) a2 = 2 * M_PI - a2; if (m2 > a2) m2 = a2; a1 = fabs(a1 - b1); if (a1 > M_PI) a1 = 2 * M_PI - a1; if (m1 > a1) m1 = a1; pBond1 = (gcpBond*)pAtom->GetNextBond(j); } pBond1 = (gcpBond*)pAtom1->GetFirstBond(j); a2 = b2; b2 = - b1; b1 = - b2; while (pBond1) { if (pBond == pBond1) { pBond1 = (gcpBond*)pAtom1->GetNextBond(j); continue; } a1 = pBond1->GetAngle2DRad(pAtom1); a2 = fabs(b2 - a1); if (a2 > M_PI) a2 = 2 * M_PI - a2; if (m2 > a2) m2 = a2; a1 = fabs(a1 - b1); if (a1 > M_PI) a1 = 2 * M_PI - a1; if (m1 > a1) m1 = a1; pBond1 = (gcpBond*)pAtom1->GetNextBond(j); } if (m2 > m1) { points->coords[0] = m_xn[0] = m_x0 = x1; points->coords[1] = m_xn[1] = m_y0 = y1; m_dAngle = a0; m_Direct = true; } else { points->coords[0] = m_xn[0] = m_x0 = x1 = x2; points->coords[1] = m_xn[1] = m_y0 = y1 = y2; m_dAngle = a0 - M_PI; m_Direct = false; } } if (m_Chain) delete m_Chain; if (m_nState & GDK_SHIFT_MASK) m_Chain = new gcpChain(pBond, m_Start); break; case AtomType: pAtom = (gcpAtom*) m_pObject; pAtom->GetCoords(&x1, &y1); x1 *= m_dZoomFactor; y1 *= m_dZoomFactor; i = pAtom->GetBondsNumber(); switch (i) { case 0: m_x0 = x1; m_y0 = y1; bDone = false; break; case 1: pBond = (gcpBond*)pAtom->GetFirstBond(j); pAtom1 = (gcpAtom*)pBond->GetAtom(pAtom); a0 = pBond->GetAngle2DRad(pAtom); points->coords[0] = m_xn[0] = m_x0 = x1; points->coords[1] = m_xn[1] = m_y0 = y1; m_dDefAngle = m_dAngle = - M_PI / 2 + a0 - m_dDev / 2; break; case 2: pBond = (gcpBond*)pAtom->GetFirstBond(j); pBond1 = (gcpBond*)pAtom->GetNextBond(j); a1 = pBond->GetAngle2DRad(pAtom); a2 = pBond1->GetAngle2DRad(pAtom); a0 = (a1 + a2) / 2; if (fabs(a1 - a2) > M_PI) a0 += M_PI; points->coords[0] = m_xn[0] = m_x0 = x1; points->coords[1] = m_xn[1] = m_y0 = y1; m_dDefAngle = m_dAngle = - M_PI / 2 + a0 - m_dDev / 2; break; default: vector orientations; orientations.reserve(i); pBond = (gcpBond*)pAtom->GetFirstBond(j); orientations.push_back(pBond->GetAngle2DRad(pAtom)); unsigned k; while ((pBond = (gcpBond*)pAtom->GetNextBond(j))) { k = 0; a0 = pBond->GetAngle2DRad(pAtom); while ((a0 > orientations[k]) && (k < orientations.size())) k++; orientations.insert(orientations.begin() + k, a0); } a0 = 2 * M_PI - orientations[i - 1] + orientations[0]; i = 0; for (k = 1; k < orientations.size(); k++) { a1 = orientations[k] - orientations[k - 1]; if (a0 < a1) { a0 = a1; i = k; } } if (a0 < M_PI - m_dDev + M_PI / 18) { bDone = false; break; } m_dAngle = (orientations[(i)? i - 1: orientations.size() - 1] + orientations[i] + M_PI - m_dDev) / 2; if (!i) m_dAngle += M_PI; m_dDefAngle = m_dAngle; points->coords[0] = m_xn[0] = m_x0 = x1; points->coords[1] = m_xn[1] = m_y0 = y1; orientations.clear(); } break; default: m_pObject = NULL; return false; } } if (!bDone) { m_dAngle = M_PI / 2; points->coords[0] = m_xn[0] = x1 = m_x0; points->coords[1] = m_xn[1] = y1 = m_y0; } for (i = 2; i < m_size * 2; i+= 2) { m_xn[i] = x1 += m_dLength * cos(m_dAngle - m_dDev * (i / 2 - 1)); m_xn[i + 1] = y1 -= m_dLength * sin(m_dAngle - m_dDev * (i / 2 - 1)); points->coords[i] = x1; points->coords[i + 1] = y1; } m_bAllowed = CheckIfAllowed(); m_pItem = gnome_canvas_item_new( m_pGroup, gnome_canvas_polygon_get_type(), "points", points, "outline_color", (m_bAllowed)? AddColor: DeleteColor, "width_units", pTheme->GetBondWidth (), NULL); return true; } void gcpCycleTool::OnDrag() { if (!m_size) return; int i; double x1, y1, x2, y2; bool bDone = false; GnomeCanvasItem* pItem = gnome_canvas_get_item_at(GNOME_CANVAS(m_pWidget), m_x, m_y); gcpDocument *pDoc = m_pView->GetDoc (); gcpTheme *pTheme = pDoc->GetTheme (); if (pItem == (GnomeCanvasItem*)m_pBackground) pItem = NULL; Object* pObject = NULL; if (pItem) pObject = (Object*)g_object_get_data(G_OBJECT(pItem), "object"); if (m_pObject) { if (m_pObject->GetType() == BondType) { if (((gcpBond*)m_pObject)->GetDist(m_x / m_dZoomFactor, m_y / m_dZoomFactor) < (pTheme->GetPadding () + pTheme->GetBondWidth () / 2) * m_dZoomFactor) { if (m_pItem) { gtk_object_destroy(GTK_OBJECT(GNOME_CANVAS_ITEM(m_pItem))); m_pItem = NULL; } return; } x1 = (m_x - m_xn[0]) * (m_xn[3] - m_xn[1]) + (m_xn[1] - m_y) * (m_xn[2] - m_xn[0]); if (m_nState & GDK_SHIFT_MASK) { if (m_Chain->GetLength() == (unsigned) m_size - 2) return; gcpBond* pBond; if (pObject) { if (pObject->GetType() == AtomType) { if (m_Chain->Contains((gcpAtom*)pObject))return; pBond = (gcpBond*)m_Start->GetBond((gcpAtom*)pObject); if (pBond) { m_Chain->AddBond((gcpAtom*)pObject, m_Start); m_Start = (gcpAtom*)pObject; } else { pBond = (gcpBond*)m_End->GetBond((gcpAtom*)pObject); if (pBond) { m_Chain->AddBond(m_End, (gcpAtom*)pObject); m_End = (gcpAtom*)pObject; } } if (pBond) bDone = true; } else if (pObject->GetType() == BondType) { m_pAtom = (gcpAtom*)((gcpBond*)pObject)->GetAtom(m_Start); if (m_pAtom) { if (m_Chain->Contains(m_pAtom))return; m_Chain->AddBond(m_pAtom, m_Start); m_Start = m_pAtom; } else { m_pAtom = (gcpAtom*)((gcpBond*)pObject)->GetAtom(m_End); if (m_pAtom) { if (m_Chain->Contains(m_pAtom))return; m_Chain->AddBond(m_End, m_pAtom); m_End = m_pAtom; } } if (m_pAtom) bDone = true; } if (!bDone) return; m_Start->GetCoords(&x1, &y1); x1 *= m_dZoomFactor; y1 *= m_dZoomFactor; m_End->GetCoords(&x2, &y2); x2 *= m_dZoomFactor; y2 *= m_dZoomFactor; double d = sqrt(square(x2 - x1) + square(y2 - y1)), L = pDoc->GetBondLength () * m_dZoomFactor, t; unsigned n = m_size - m_Chain->GetLength(); if (d < L * n) {//FIXME: this algorithm is far from optimal!!! double t1, k = d/L, p = M_PI /n; t = 0; while(1) { t1 = t + (p - t) * (1 - k / ((t != 0.0)? (sin(t * n) / sin(t)): n)); if (fabs(t1 - t) < 1e-15) break; //An infinite loop might be possible here! t = t1; } } else t = 0; if (t < fabs(m_dDev) / 4) //too large, change the bond length { t = fabs(m_dDev) / 4; } //Find center double dx, dy; if (m_dDev > 0) { dx = ((y1 - y2) / tan(M_PI - t * n) + x2 + x1) / 2; dy = ((x1 - x2) / tan(t * n) + y1 + y2) / 2; t = - t; } else { dx = ((y2 - y1) / tan(M_PI - t * n) + x2 + x1) / 2; dy = ((x2 - x1) / tan(t * n) + y1 + y2) / 2; } double a0 = atan2(dy - y2, x2 - dx); d = sqrt(square(dy - y2) + square(dx - x2)); i = 0; m_pAtom = m_Start; do { m_pAtom->GetCoords(&x1, &y1); m_xn[i] = points->coords[i] = x1 * m_dZoomFactor; i++; m_xn[i] = points->coords[i] = y1 * m_dZoomFactor; i++; } while ((m_pAtom != m_End) && (m_pAtom = m_Chain->GetNextAtom(m_pAtom))); while (i < m_size * 2) { a0 += 2 * t; m_xn[i] = points->coords[i] = dx + d * cos(a0); i++; m_xn[i] = points->coords[i] = dy - d * sin(a0); i++; } } bDone = true; } else if (x1 * m_dDev > 0) { m_dDev = - m_dDev; x1 = m_xn[2]; y1 = m_xn[3]; for (i = 4; i < m_size * 2; i+= 2) { m_xn[i] = x1 += (pDoc->GetBondLength () * m_dZoomFactor) * cos (m_dAngle - m_dDev * (i / 2 - 1)); m_xn[i + 1] = y1 -= (pDoc->GetBondLength () * m_dZoomFactor) * sin (m_dAngle - m_dDev * (i / 2 - 1)); points->coords[i] = x1; points->coords[i + 1] = y1; } bDone = true; } else if (m_pItem) return; else bDone = true; } } if (m_pItem) { gtk_object_destroy(GTK_OBJECT(GNOME_CANVAS_ITEM(m_pItem))); m_pItem = NULL; } if (!bDone) { double dAngle; m_pAtom = NULL; if (pObject) { if (pObject->GetType() == BondType) { m_pAtom = (gcpAtom*)pObject->GetAtomAt(m_x / m_dZoomFactor, m_y / m_dZoomFactor); } else if (pObject->GetType() == AtomType) { m_pAtom = (gcpAtom*)pObject; } } if (m_pAtom) { if (m_pAtom == m_pObject) return; m_pAtom->GetCoords(&m_x, &m_y); m_x *= m_dZoomFactor; m_y *= m_dZoomFactor; m_x -= m_x0; m_y -= m_y0; double BondLength = sqrt(square(m_x) + square(m_y)); if (m_x == 0) { if (m_y == 0) return; dAngle = (m_y < 0) ? 90 : 270; } else { m_dAngle = atan(-m_y/m_x); if (m_x < 0) m_dAngle += M_PI; } x1 = m_x0; y1 = m_y0; for (i = 2; i < m_size * 2; i+= 2) { m_xn[i] = x1 += (BondLength) * cos(m_dAngle - m_dDev * (i / 2 - 1)); m_xn[i + 1] = y1 -= (BondLength) * sin(m_dAngle - m_dDev * (i / 2 - 1)); points->coords[i] = x1; points->coords[i + 1] = y1; } } 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 (m_x < 0) dAngle += 180; } m_dAngle = dAngle * M_PI / 180; x1 = m_x0; y1 = m_y0; double d = (m_nState & GDK_SHIFT_MASK)? sqrt (square (m_x) + square (m_y)): pDoc->GetBondLength () * m_dZoomFactor; for (i = 2; i < m_size * 2; i+= 2) { m_xn[i] = x1 += d * cos(m_dAngle - m_dDev * (i / 2 - 1)); m_xn[i + 1] = y1 -= d * sin(m_dAngle - m_dDev * (i / 2 - 1)); points->coords[i] = x1; points->coords[i + 1] = y1; } char tmp[32]; if (dAngle < 0) dAngle += 360; snprintf(tmp, sizeof(tmp) - 1, _("Orientation: %g"), dAngle); m_pApp->SetStatusText(tmp); } } m_bAllowed = CheckIfAllowed(); m_pItem = gnome_canvas_item_new( m_pGroup, gnome_canvas_polygon_get_type(), "points", points, "outline_color", (m_bAllowed)? AddColor: DeleteColor, "width_units", pTheme->GetBondWidth (), NULL); } void gcpCycleTool::OnRelease() { if (!m_size) return; if (m_Chain) { delete m_Chain; m_Chain = NULL; } if (m_pItem) { gtk_object_destroy (GTK_OBJECT (GNOME_CANVAS_ITEM (m_pItem))); m_pItem = NULL; } else return; if (!m_bAllowed) return; m_pApp->ClearStatus (); gcpAtom* pAtom[m_size]; gcpBond* pBond; Object *pObject; char const *Id; GnomeCanvasItem* pItem; gcpDocument *pDoc = m_pView->GetDoc (); gcpOperation *pOp = NULL; gcpMolecule *pMol = NULL; char const *MolId = NULL; int i; for (i = 0; i < m_size; i++) { m_x = m_xn[2 * i]; m_y = m_xn[2 * i + 1]; pAtom[i] = NULL; pItem = gnome_canvas_get_item_at(GNOME_CANVAS(m_pWidget), m_x, m_y); if (pItem == (GnomeCanvasItem*)m_pBackground) pItem = NULL; m_pObject = (pItem)? (Object*)g_object_get_data(G_OBJECT(pItem), "object"): NULL; if (MergeAtoms && m_pObject) { if (m_pObject->GetType() == BondType) { pAtom[i] = (gcpAtom*)m_pObject->GetAtomAt(m_x / m_dZoomFactor, m_y / m_dZoomFactor); } else if (m_pObject->GetType() == AtomType) { pAtom[i] = (gcpAtom*)m_pObject; } if (pAtom[i]) { if (pMol == NULL) { pMol = reinterpret_cast (pAtom[i]->GetMolecule ()); pMol->Lock (true); // we must store the id, the molecule might be destroyed // FIXME! what happens to the parent in such a case? MolId = pMol->GetId (); } // if group not in ModifiedObjects, add it and save it pObject = pAtom[i]->GetGroup (); Id = pObject->GetId (); if (ModifiedObjects.find (Id) == ModifiedObjects.end ()) { if (!pOp) pOp = pDoc->GetNewOperation (GCP_MODIFY_OPERATION); pOp->AddObject (pObject); ModifiedObjects.insert (Id); } } } if (!pAtom[i]) { pAtom[i] = new gcpAtom(m_pApp->GetCurZ(), m_xn[2 * i] / m_dZoomFactor, m_xn[2 * i + 1] / m_dZoomFactor, 0); pDoc->AddAtom(pAtom[i]); } if (i) { pBond = (gcpBond*)pAtom[i]->GetBond(pAtom[i - 1]); if (!pBond) { pBond = new gcpBond(pAtom[i - 1], pAtom[i], 1); pDoc->AddBond(pBond); } } } pBond = (gcpBond*)pAtom[m_size - 1]->GetBond(pAtom[0]); if (!pBond) { pBond = new gcpBond(pAtom[m_size - 1], pAtom[0], 1); pDoc->AddBond(pBond); } pObject = pBond->GetGroup (); if (pOp) { ModifiedObjects.insert (pObject->GetId ()); set::iterator it, end = ModifiedObjects.end(); for (it = ModifiedObjects.begin(); it != end; it++) { pObject = pDoc->GetDescendant ((*it).c_str ()); if (pObject) pOp->AddObject (pObject, 1); } } else { pOp = pDoc->GetNewOperation (GCP_ADD_OPERATION); pOp->AddObject (pObject); } pDoc->FinishOperation (); if (pMol) pMol = static_cast (pDoc->GetDescendant (MolId)); if (pMol) { pMol->Lock (false); pMol->EmitSignal (OnChangedSignal); } ModifiedObjects.clear (); } void gcpCycleTool::OnChangeState() { if (m_pObject && (m_pObject->GetType() == BondType)) { if (m_nState & GDK_SHIFT_MASK) { if (!m_Chain) { if (m_Direct) { m_Start = (gcpAtom*)((gcpBond*)m_pObject)->GetAtom(0); m_End = (gcpAtom*)((gcpBond*)m_pObject)->GetAtom(1); } else { m_Start = (gcpAtom*)((gcpBond*)m_pObject)->GetAtom(1); m_End = (gcpAtom*)((gcpBond*)m_pObject)->GetAtom(0); } m_Chain = new gcpChain((gcpBond*)m_pObject, m_Start); } } else { double x1, y1, x2, y2; if (m_pItem) { gtk_object_destroy(GTK_OBJECT(GNOME_CANVAS_ITEM(m_pItem))); m_pItem = NULL; } if (m_Direct) { m_Start = (gcpAtom*)((gcpBond*)m_pObject)->GetAtom(0); m_End = (gcpAtom*)((gcpBond*)m_pObject)->GetAtom(1); } else { m_Start = (gcpAtom*)((gcpBond*)m_pObject)->GetAtom(1); m_End = (gcpAtom*)((gcpBond*)m_pObject)->GetAtom(0); } m_Start->GetCoords(&x1, &y1); m_End->GetCoords(&x2, &y2); points->coords[0] = m_xn[0] = x1 * m_dZoomFactor; points->coords[1] = m_xn[1] = y1 * m_dZoomFactor; points->coords[2] = m_xn[2] = x1 = x2 * m_dZoomFactor; points->coords[3] = m_xn[3] = y1 = y2 * m_dZoomFactor; for (int i = 4; i < m_size * 2; i+= 2) { gcpDocument *pDoc = m_pView->GetDoc (); m_xn[i] = x1 += (pDoc->GetBondLength () * m_dZoomFactor) * cos(m_dAngle - m_dDev * (i / 2 - 1)); m_xn[i + 1] = y1 -= (pDoc->GetBondLength () * m_dZoomFactor) * sin(m_dAngle - m_dDev * (i / 2 - 1)); points->coords[i] = x1; points->coords[i + 1] = y1; } if (m_Chain) { delete m_Chain; m_Chain = NULL; } } } m_bAllowed = CheckIfAllowed(); gcpTool::OnChangeState(); } void gcpCycleTool::Init() { m_xn = new double[m_size * 2]; m_dDev = 2 * M_PI / m_size; points = gnome_canvas_points_new(m_size); } bool gcpCycleTool::CheckIfAllowed() { //Search atoms at the positions of the vertices and check if adding bonds to them is allowed gcpAtom* pAtom[m_size]; GnomeCanvasItem* pItem; Object* pObject; int i, n; for (i = 0; i < m_size; i++) { m_x = m_xn[2 * i]; m_y = m_xn[2 * i + 1]; pItem = gnome_canvas_get_item_at(GNOME_CANVAS(m_pWidget), m_x, m_y); if (pItem == (GnomeCanvasItem*)m_pBackground) pItem = NULL; pObject = (pItem)? (Object*)g_object_get_data(G_OBJECT(pItem), "object"): NULL; if (MergeAtoms && pObject) { TypeId Id = pObject->GetType(); switch (Id) { case BondType: case FragmentType: pAtom[i] = (gcpAtom*)pObject->GetAtomAt(m_x / m_dZoomFactor, m_y / m_dZoomFactor); break; case AtomType: pAtom[i] = (gcpAtom*)pObject; break; default: pAtom[i] = NULL; } } else pAtom[i] = NULL; } for (i = 0; i < m_size; i++) { if (!pAtom[i]) continue; n = 0; if (!pAtom[i]->GetBond(pAtom[(i)? i - 1: m_size -1])) n++; if (!pAtom[i]->GetBond(pAtom[(i < m_size - 1)? i + 1: 0])) n++; if (n && (!pAtom[i]->AcceptNewBonds(n))) return false; } return true; } static void on_length_changed (GtkSpinButton *btn, gcpCycleTool *tool) { tool->SetLength (gtk_spin_button_get_value (btn)); } static void on_merge_toggled (GtkToggleButton *btn) { MergeAtoms = gtk_toggle_button_get_active (btn); } void gcpCycleTool::SetLength (double length) { m_pApp->GetActiveDocument ()->SetBondLength (length); } GtkWidget *gcpCycleTool::GetPropertyPage () { GladeXML *xml = glade_xml_new (GLADEDIR"/cycle.glade", "cycle", 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_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, "cycle"); } void gcpCycleTool::Activate () { gcpDocument *pDoc = m_pApp->GetActiveDocument (); gtk_spin_button_set_value (m_LengthBtn, pDoc->GetBondLength ()); gtk_toggle_button_set_active (m_MergeBtn, MergeAtoms); } gcpNCycleTool::gcpNCycleTool(gcpApplication* App, unsigned char size): gcpCycleTool(App, 9) { SetSize(size); } gcpNCycleTool::~gcpNCycleTool() { } void gcpNCycleTool::SetSize(unsigned char size) { if (m_size) { delete [] m_xn; gnome_canvas_points_free(points); } if ((m_size = size)) Init(); } static void on_size_changed (GtkSpinButton *button, gcpNCycleTool *tool) { tool->SetSize ((unsigned char) gtk_spin_button_get_value_as_int (button)); } GtkWidget *gcpNCycleTool::GetPropertyPage () { GladeXML *xml = glade_xml_new (GLADEDIR"/cyclen.glade", "cycle", 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_MergeBtn = GTK_TOGGLE_BUTTON (glade_xml_get_widget (xml, "merge")); g_signal_connect (m_MergeBtn, "toggled", G_CALLBACK (on_merge_toggled), NULL); m_SizeBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "sizebtn")); gtk_spin_button_set_value (m_SizeBtn, m_size); g_signal_connect (m_SizeBtn, "value-changed", G_CALLBACK (on_size_changed), this); return glade_xml_get_widget (xml, "cycle"); }