// -*- C++ -*- /* * GChemPaint atoms plugin * electrontool.cc * * Copyright (C) 2004-2005 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 "electrontool.h" #include "lib/application.h" #include "lib/document.h" #include "lib/electron.h" #include "lib/molecule.h" #include "lib/operation.h" #include "lib/settings.h" #include "libgcpcanvas/gcp-canvas-bpath.h" #include #include #include gcpElectronTool::gcpElectronTool (gcpApplication *App, string Id): gcpTool (App, Id) { if (Id == string ("ElectronPair")) m_bIsPair = true; else if (Id == string ("UnpairedElectron")) m_bIsPair = false; else throw logic_error ("Unknown tool Id!"); // This should not happen. } gcpElectronTool::~gcpElectronTool () { } bool gcpElectronTool::OnClicked () { if (!m_pObject || (m_pObject->GetType () != AtomType)) return false; /* explicit electrons will be authorized in fragments only when they will be fully implemented */ if (m_pObject->GetParent ()->GetType () == FragmentType) return false; double x, y; gcpAtom *pAtom = (gcpAtom*) m_pObject; if (m_bIsPair) { if (!pAtom->HasImplicitElectronPairs ()) return false; } else { if (!pAtom->MayHaveImplicitUnpairedElectrons ()) return false; } pAtom->GetCoords (&m_x0, &m_y0); m_Pos = pAtom->GetAvailablePosition (x, y); m_x = x - m_x0; m_y = y - m_y0; ArtDRect rect; m_pData->GetObjectBounds (m_pObject, &rect); m_x0 *= m_dZoomFactor; m_y0 *= m_dZoomFactor; m_dDistMax = min (sqrt (square (rect.x0 - m_x0) + square (rect.y0 - m_y0)), sqrt (square (rect.x1 - m_x0) + square (rect.y0 - m_y0))); m_dAngle = atan (- m_y / m_x); if (m_x < 0) m_dAngle += M_PI; x *= m_dZoomFactor; y *= m_dZoomFactor; x += 2. * cos (m_dAngle); y -= 2. * sin (m_dAngle); if (m_bIsPair) { double deltax = 3. * sin (m_dAngle); double deltay = 3. * cos (m_dAngle); m_pItem = gnome_canvas_item_new( m_pGroup, gnome_canvas_group_get_type (), NULL); gnome_canvas_item_new( GNOME_CANVAS_GROUP (m_pItem), gnome_canvas_ellipse_get_type(), "width_units", 0.0, "fill_color", AddColor, "x1", x + deltax - 2. , "x2", x + deltax + 2., "y1", y + deltay - 2., "y2", y + deltay + 2., NULL); gnome_canvas_item_new( GNOME_CANVAS_GROUP (m_pItem), gnome_canvas_ellipse_get_type(), "width_units", 0.0, "fill_color", AddColor, "x1", x - deltax - 2. , "x2", x - deltax + 2., "y1", y - deltay - 2., "y2", y - deltay + 2., NULL); } else { m_pItem = gnome_canvas_item_new( m_pGroup, gnome_canvas_ellipse_get_type(), "width_units", 0.0, "fill_color", AddColor, "x1", x - 2. , "x2", x + 2., "y1", y - 2., "y2", y + 2., NULL); } char tmp[32]; snprintf(tmp, sizeof(tmp) - 1, _("Orientation: %g"), m_dAngle * 180. / M_PI); m_pApp->SetStatusText(tmp); m_bChanged = true; return true; } void gcpElectronTool::OnDrag () { if (!m_pItem) return; int old_pos = m_Pos; m_x -= m_x0; m_y -= m_y0; m_dDist = sqrt (square (m_x) + square (m_y)); double Angle = atan (- m_y / m_x); if (isnan (Angle)) Angle = m_dAngle; else if (m_x < 0) Angle += M_PI; if (!(m_nState & GDK_CONTROL_MASK)) { int pos = (int) rint (Angle * 4. / M_PI); Angle = (double) pos * M_PI / 4.; if (m_nState & GDK_SHIFT_MASK) pos = 8; else if (pos < 0) pos += 8; switch (pos) { case 0: m_Pos = POSITION_E; break; case 1: m_Pos = POSITION_NE; break; case 2: m_Pos = POSITION_N; break; case 3: m_Pos = POSITION_NW; break; case 4: m_Pos = POSITION_W; break; case 5: m_Pos = POSITION_SW; break; case 6: m_Pos = POSITION_S; break; case 7: m_Pos = POSITION_SE; break; default: m_Pos = 0; } } else m_Pos = 0; if ((Angle == m_dAngle) && !(m_nState & GDK_SHIFT_MASK)) { if (m_dDist < m_dDistMax) { 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 { double x, y, x1, y1, x2, y2; gcpAtom *pAtom = (gcpAtom*)m_pObject; if (!(m_nState & GDK_SHIFT_MASK) && (m_dDist >= m_dDistMax) && m_bChanged) { gnome_canvas_item_hide (m_pItem); m_bChanged = false; } else if (pAtom->GetPosition (Angle * 180. / M_PI, x, y)) { m_dAngle = Angle; 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; } if (m_nState & GDK_SHIFT_MASK) { x = m_x0 + m_dDist * cos (m_dAngle); y = m_y0 - m_dDist * sin (m_dAngle); } else { x = x * m_dZoomFactor; y = y * m_dZoomFactor; x += 2. * cos (m_dAngle); y -= 2. * sin (m_dAngle); } if (m_bIsPair) { double deltax = 3. * sin (m_dAngle); double deltay = 3. * cos (m_dAngle); m_pItem = gnome_canvas_item_new( m_pGroup, gnome_canvas_group_get_type (), NULL); gnome_canvas_item_new( GNOME_CANVAS_GROUP (m_pItem), gnome_canvas_ellipse_get_type(), "width_units", 0.0, "fill_color", AddColor, "x1", x + deltax - 2. , "x2", x + deltax + 2., "y1", y + deltay - 2., "y2", y + deltay + 2., NULL); gnome_canvas_item_new( GNOME_CANVAS_GROUP (m_pItem), gnome_canvas_ellipse_get_type(), "width_units", 0.0, "fill_color", AddColor, "x1", x - deltax - 2. , "x2", x - deltax + 2., "y1", y - deltay - 2., "y2", y - deltay + 2., NULL); } else { m_pItem = gnome_canvas_item_new( m_pGroup, gnome_canvas_ellipse_get_type(), "width_units", 0.0, "fill_color", AddColor, "x1", x - 2. , "x2", x + 2., "y1", y - 2., "y2", y + 2., NULL); } m_bChanged = true; } else m_Pos = old_pos; } char tmp[32]; snprintf(tmp, sizeof(tmp) - 1, _("Orientation: %g"), m_dAngle * 180. / M_PI); m_pApp->SetStatusText(tmp); } void gcpElectronTool::OnRelease () { if (!m_bChanged) return; gcpAtom *pAtom = (gcpAtom*) m_pObject; Object* pObj = m_pObject->GetGroup (); gcpDocument* pDoc = m_pView->GetDoc (); gcpOperation* pOp = pDoc-> GetNewOperation (GCP_MODIFY_OPERATION); pOp->AddObject (pObj, 0); gcpElectron *electron = new gcpElectron (pAtom, m_bIsPair); double Angle = m_dAngle * 180. / M_PI; if (!(m_nState & GDK_SHIFT_MASK)) m_dDist = 0.; electron->SetPosition (m_Pos, Angle, m_dDist); m_pObject->EmitSignal (OnChangedSignal); pOp->AddObject(pObj, 1); pDoc->FinishOperation(); m_pView->AddObject (electron); m_pView->Update (pAtom); }