4
* GChemPaint bonds plugin
7
* Copyright (C) 2012 Jean Bréfort <jean.brefort@normalesup.org>
9
* This program is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU General Public License as
11
* published by the Free Software Foundation; either version 3 of the
12
* License, or (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
27
#include <gcp/application.h>
30
#include <gcp/document.h>
31
#include <gcp/theme.h>
33
#include <gcugtk/ui-builder.h>
34
#include <gccv/canvas.h>
35
#include <gccv/circle.h>
36
#include <gccv/group.h>
37
#include <gccv/line.h>
39
class gcpNewmanToolPrivate
42
static void OnLengthChanged (GtkSpinButton *btn, gcpNewmanTool *tool);
43
static void OnOrderChanged (GtkSpinButton *btn, gcpNewmanTool *tool);
44
static void OnForeBondsChanged (GtkSpinButton *btn, gcpNewmanTool *tool);
45
static void OnRearBondsChanged (GtkSpinButton *btn, gcpNewmanTool *tool);
46
static void OnForeFirstAngleChanged (GtkSpinButton *btn, gcpNewmanTool *tool);
47
static void OnRearFirstAngleChanged (GtkSpinButton *btn, gcpNewmanTool *tool);
48
static void OnForeBondAngleChanged (GtkSpinButton *btn, gcpNewmanTool *tool);
49
static void OnRearBondAngleChanged (GtkSpinButton *btn, gcpNewmanTool *tool);
52
void gcpNewmanToolPrivate::OnLengthChanged (GtkSpinButton *btn, gcpNewmanTool *tool)
54
tool->m_pApp->GetActiveDocument ()->SetBondLength (gtk_spin_button_get_value (btn));
57
void gcpNewmanToolPrivate::OnOrderChanged (GtkSpinButton *btn, gcpNewmanTool *tool)
59
tool->m_Order = gtk_spin_button_get_value_as_int (btn);
60
switch (tool->m_Order) {
62
gtk_spin_button_set_value (tool->m_ForeBondsBtn, 3);
63
gtk_spin_button_set_value (tool->m_RearBondsBtn, 3);
64
gtk_spin_button_set_value (tool->m_RearFirstAngleBtn, tool->m_ForeFirstAngle * 180. / M_PI - 180.);
67
gtk_spin_button_set_value (tool->m_ForeBondsBtn, 2);
68
gtk_spin_button_set_value (tool->m_RearBondsBtn, 2);
69
gtk_spin_button_set_value (tool->m_RearFirstAngleBtn, tool->m_ForeFirstAngle * 180. / M_PI);
74
void gcpNewmanToolPrivate::OnForeBondsChanged (GtkSpinButton *btn, gcpNewmanTool *tool)
76
tool->m_ForeBonds = gtk_spin_button_get_value_as_int (btn);
77
switch (tool->m_ForeBonds) {
79
gtk_spin_button_set_value (tool->m_ForeBondAngleBtn, 180.);
82
gtk_spin_button_set_value (tool->m_ForeBondAngleBtn, 120.);
87
void gcpNewmanToolPrivate::OnRearBondsChanged (GtkSpinButton *btn, gcpNewmanTool *tool)
89
tool->m_RearBonds = gtk_spin_button_get_value_as_int (btn);
90
switch (tool->m_RearBonds) {
92
gtk_spin_button_set_value (tool->m_RearBondAngleBtn, 180.);
95
gtk_spin_button_set_value (tool->m_RearBondAngleBtn, 120.);
100
void gcpNewmanToolPrivate::OnForeFirstAngleChanged (GtkSpinButton *btn, gcpNewmanTool *tool)
102
tool->m_ForeFirstAngle = gtk_spin_button_get_value_as_int (btn) * M_PI / 180.;
105
void gcpNewmanToolPrivate::OnForeBondAngleChanged (GtkSpinButton *btn, gcpNewmanTool *tool)
107
tool->m_ForeBondAngle = gtk_spin_button_get_value_as_int (btn) * M_PI / 180.;
110
void gcpNewmanToolPrivate::OnRearFirstAngleChanged (GtkSpinButton *btn, gcpNewmanTool *tool)
112
tool->m_RearFirstAngle = gtk_spin_button_get_value_as_int (btn) * M_PI / 180.;
115
void gcpNewmanToolPrivate::OnRearBondAngleChanged (GtkSpinButton *btn, gcpNewmanTool *tool)
117
tool->m_RearBondAngle = gtk_spin_button_get_value_as_int (btn) * M_PI / 180.;
120
gcpNewmanTool::gcpNewmanTool (gcp::Application *App): gcp::Tool (App, "Newman")
122
m_ForeBonds = m_RearBonds = 3;
123
m_ForeFirstAngle = M_PI / 2.;
124
m_RearFirstAngle = -M_PI / 2.;
125
m_ForeBondAngle = m_RearBondAngle = M_PI / 1.5;
129
gcpNewmanTool::~gcpNewmanTool ()
133
bool gcpNewmanTool::OnClicked ()
135
if (m_pObject != NULL)
138
gcp::Document* doc = m_pView->GetDoc ();
139
double length = doc->GetBondLength () * m_dZoomFactor;
143
gccv::Group *group = new gccv::Group (m_pView->GetCanvas ());
145
gccv::Circle *circle = new gccv::Circle (group, m_x0, m_y0, length / 3., NULL);
146
circle->SetFillColor (0);
147
circle->SetLineColor (GO_COLOR_BLACK);
148
angle = m_ForeFirstAngle;
149
for (i = 0; i < m_ForeBonds; i++) {
150
line = new gccv::Line (group, m_x0, m_y0, m_x0 + length * cos (angle), m_y0 - length * sin (angle), NULL);
151
line->SetLineColor (GO_COLOR_BLACK);
152
angle += m_ForeBondAngle;
154
angle = m_RearFirstAngle;
155
for (i = 0; i < m_RearBonds; i++) {
156
line = new gccv::Line (group, m_x0 + length / 3. * cos (angle),
157
m_y0 - length / 3. * sin (angle),
158
m_x0 + length * cos (angle),
159
m_y0 - length * sin (angle), NULL);
160
line->SetLineColor (GO_COLOR_BLACK);
161
angle += m_RearBondAngle;
166
void gcpNewmanTool::OnDrag ()
169
gcp::Document* doc = m_pView->GetDoc ();
170
double length = doc->GetBondLength () * m_dZoomFactor;
174
gccv::Group *group = new gccv::Group (m_pView->GetCanvas ());
176
gccv::Circle *circle = new gccv::Circle (group, m_x, m_y, length / 3., NULL);
177
circle->SetFillColor (0);
178
circle->SetLineColor (GO_COLOR_BLACK);
179
angle = m_ForeFirstAngle;
180
for (i = 0; i < m_ForeBonds; i++) {
181
line = new gccv::Line (group, m_x, m_y, m_x + length * cos (angle), m_y - length * sin (angle), NULL);
182
line->SetLineColor (GO_COLOR_BLACK);
183
angle += m_ForeBondAngle;
185
angle = m_RearFirstAngle;
186
for (i = 0; i < m_RearBonds; i++) {
187
line = new gccv::Line (group, m_x + length / 3. * cos (angle),
188
m_y - length / 3. * sin (angle),
189
m_x + length * cos (angle),
190
m_y - length * sin (angle), NULL);
191
line->SetLineColor (GO_COLOR_BLACK);
192
angle += m_RearBondAngle;
196
void gcpNewmanTool::OnRelease ()
200
gcp::Document* doc = m_pView->GetDoc ();
201
double bl = doc->GetBondLength (), dz = bl / 2.;
204
// add the atoms and bonds
205
// for now, we only add carbon atoms, and never merge with existing atoms
206
// using 3d coordinates, front atoms at +bond_length/2 rear atoms at -bond_length/2
207
m_x /= m_dZoomFactor;
208
m_y /= m_dZoomFactor;
209
gcp::Atom *atom = new gcp::Atom (6, m_x, m_y, -bl / 2.), *atom0;
211
angle = m_RearFirstAngle;
212
for (i = 0; i < m_RearBonds; i++) {
213
atom0 = new gcp::Atom (6, m_x + bl * cos (angle), m_y - bl * sin (angle), -dz);
214
doc->AddAtom (atom0);
215
doc->AddBond (new gcp::Bond (atom, atom0, 1));
216
angle += m_RearBondAngle;
218
atom0 = new gcp::Atom (6, m_x, m_y, dz);
219
doc->AddAtom (atom0);
220
gcp::Bond *bond = new gcp::Bond (atom, atom0, 1);
221
doc->AddBond (bond); // add to doc before setting the type so that the radius will be correct
222
bond->SetType (gcp::NewmanBondType);
223
angle = m_ForeFirstAngle;
224
for (i = 0; i < m_ForeBonds; i++) {
225
atom = new gcp::Atom (6, m_x + bl * cos (angle), m_y - bl * sin (angle), -dz);
227
doc->AddBond (new gcp::Bond (atom0, atom, 1));
228
angle += m_ForeBondAngle;
230
gcp::Operation *op = doc-> GetNewOperation (gcp::GCP_ADD_OPERATION);
231
op->AddObject (bond->GetMolecule ());
232
doc->FinishOperation ();
233
// ensure that rear bonds don't go up to the center
234
m_pView->Update (bond->GetMolecule ());
237
GtkWidget *gcpNewmanTool::GetPropertyPage ()
239
gcugtk::UIBuilder *builder = new gcugtk::UIBuilder (UIDIR"/newman.ui", GETTEXT_PACKAGE);
240
m_LengthBtn = GTK_SPIN_BUTTON (builder->GetWidget ("bond-length-btn"));
241
g_signal_connect (m_LengthBtn, "value-changed", G_CALLBACK (gcpNewmanToolPrivate::OnLengthChanged), this);
242
m_OrderBtn = GTK_SPIN_BUTTON (builder->GetWidget ("order-btn"));
243
gtk_spin_button_set_value (m_OrderBtn, m_Order);
244
g_signal_connect (m_OrderBtn, "value-changed", G_CALLBACK (gcpNewmanToolPrivate::OnOrderChanged), this);
245
m_ForeBondsBtn = GTK_SPIN_BUTTON (builder->GetWidget ("fore-bonds-btn"));
246
gtk_spin_button_set_value (m_ForeBondsBtn, m_ForeBonds);
247
g_signal_connect (m_ForeBondsBtn, "value-changed", G_CALLBACK (gcpNewmanToolPrivate::OnForeBondsChanged), this);
248
m_RearBondsBtn = GTK_SPIN_BUTTON (builder->GetWidget ("rear-bonds-btn"));
249
gtk_spin_button_set_value (m_RearBondsBtn, m_RearBonds);
250
g_signal_connect (m_RearBondsBtn, "value-changed", G_CALLBACK (gcpNewmanToolPrivate::OnRearBondsChanged), this);
251
m_ForeFirstAngleBtn = GTK_SPIN_BUTTON (builder->GetWidget ("fore-first-angle-btn"));
252
gtk_spin_button_set_value (m_ForeFirstAngleBtn, m_ForeFirstAngle * 180. / M_PI);
253
g_signal_connect (m_ForeFirstAngleBtn, "value-changed", G_CALLBACK (gcpNewmanToolPrivate::OnForeFirstAngleChanged), this);
254
m_RearFirstAngleBtn = GTK_SPIN_BUTTON (builder->GetWidget ("rear-first-angle-btn"));
255
gtk_spin_button_set_value (m_RearFirstAngleBtn, m_RearFirstAngle * 180. / M_PI);
256
g_signal_connect (m_RearFirstAngleBtn, "value-changed", G_CALLBACK (gcpNewmanToolPrivate::OnRearFirstAngleChanged), this);
257
m_ForeBondAngleBtn = GTK_SPIN_BUTTON (builder->GetWidget ("fore-angle-btn"));
258
gtk_spin_button_set_value (m_ForeBondAngleBtn, m_ForeBondAngle * 180. / M_PI);
259
g_signal_connect (m_ForeBondAngleBtn, "value-changed", G_CALLBACK (gcpNewmanToolPrivate::OnForeBondAngleChanged), this);
260
m_RearBondAngleBtn = GTK_SPIN_BUTTON (builder->GetWidget ("rear-angle-btn"));
261
gtk_spin_button_set_value (m_RearBondAngleBtn, m_RearBondAngle * 180. / M_PI);
262
g_signal_connect (m_RearBondAngleBtn, "value-changed", G_CALLBACK (gcpNewmanToolPrivate::OnRearBondAngleChanged), this);
264
GtkWidget *res = builder->GetRefdWidget ("newman");
269
void gcpNewmanTool::Activate ()
271
gcp::Document *pDoc = m_pApp->GetActiveDocument ();
272
gtk_spin_button_set_value (m_LengthBtn, pDoc->GetBondLength ());