// -*- C++ -*-
/*
* GChemPaint atoms plugin
* electrontool.cc
*
* Copyright (C) 2004-2005 Jean Bréfort <jean.brefort@normalesup.org>
*
* 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 <glib/gi18n-lib.h>
#include <cmath>
#include <stdexcept>
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);
}
syntax highlighted by Code2HTML, v. 0.9.1