1 // -*- C++ -*-
2
3 /*
4 * GChemPaint bonds plugin
5 * bondtool.cc
6 *
7 * Copyright (C) 2001-2011 Jean Bréfort <jean.brefort@normalesup.org>
8 *
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.
13 *
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.
18 *
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
22 * USA
23 */
24
25 #include "config.h"
26 #include "bondtool.h"
27 #include <gcp/application.h>
28 #include <gcp/atom.h>
29 #include <gcp/bond.h>
30 #include <gcp/document.h>
31 #include <gcp/fragment.h>
32 #include <gcp/settings.h>
33 #include <gcp/theme.h>
34 #include <gcp/view.h>
35 #include <gccv/canvas.h>
36 #include <gccv/group.h>
37 #include <gccv/hash.h>
38 #include <gccv/line.h>
39 #include <gccv/squiggle.h>
40 #include <gccv/wedge.h>
41 #include <gcugtk/ui-builder.h>
42 #include <glib/gi18n-lib.h>
43 #include <cmath>
44
45 using namespace gcu;
46 using namespace gccv;
47 using namespace std;
48
gcpBondTool(gcp::Application * App,string ToolId,G_GNUC_UNUSED unsigned nPoints)49 gcpBondTool::gcpBondTool (gcp::Application *App, string ToolId, G_GNUC_UNUSED unsigned nPoints): gcp::Tool (App, ToolId)
50 {
51 m_pOp = NULL;
52 m_AutoDir = false;
53 }
54
~gcpBondTool()55 gcpBondTool::~gcpBondTool ()
56 {
57 }
58
OnClicked()59 bool gcpBondTool::OnClicked ()
60 {
61 if (Element::GetMaxBonds (m_pApp->GetCurZ()) < 1)
62 return false;
63 int i;
64 m_pAtom = NULL;
65 m_bChanged = false;
66 m_dAngle = 0.;
67 gcp::Bond* pBond;
68 gcp::Document* pDoc = m_pView->GetDoc ();
69 if (m_pObject)
70 {
71 TypeId Id = m_pObject->GetType ();
72 switch (Id)
73 {
74 case BondType:
75 pBond = static_cast<gcp::Bond*> (m_pObject);
76 if (pBond->IsLocked ())
77 return false;
78 m_pAtom = static_cast<gcp::Atom*> (pBond->GetAtom (0));
79 m_pAtom->GetCoords (&m_x0, &m_y0, NULL);
80 m_pAtom = static_cast<gcp::Atom*> (pBond->GetAtom (1));
81 m_pAtom->GetCoords (&m_x1, &m_y1, NULL);
82 m_x0 *= m_dZoomFactor;
83 m_y0 *= m_dZoomFactor;
84 m_x1 *= m_dZoomFactor;
85 m_y1 *= m_dZoomFactor;
86 m_bChanged = true;
87 m_pOp = pDoc->GetNewOperation (gcp::GCP_MODIFY_OPERATION);
88 m_pOp->AddObject (m_pObjectGroup, 0);
89 UpdateBond ();
90 return true;
91 case FragmentType:
92 m_pObject = static_cast <gcp::Fragment *> (m_pObject)->GetAtom ();
93 case AtomType:
94 if (!((gcp::Atom*) m_pObject)->AcceptNewBonds ())
95 return false;
96 ((gcp::Atom*) m_pObject)->GetCoords (&m_x0, &m_y0, NULL);
97 m_x0 *= m_dZoomFactor;
98 m_y0 *= m_dZoomFactor;
99 /* search preferred orientation for new bond */
100 i = ((gcp::Atom*) m_pObject)->GetBondsNumber ();
101 switch (i) {
102 case 0:
103 break;
104 case 1: {
105 map<Atom*, Bond*>::iterator i;
106 gcp::Bond* bond = (gcp::Bond*) ((Atom*) m_pObject)->GetFirstBond (i);
107 m_RefAngle = m_dAngle = bond->GetAngle2D ((gcp::Atom*) m_pObject);
108 m_dAngle += (((m_nState & GDK_LOCK_MASK && (!(m_nState & GDK_MOD5_MASK))) ||
109 ((!(m_nState & GDK_LOCK_MASK)) && m_nState & GDK_MOD5_MASK)))?
110 pDoc->GetBondAngle (): -pDoc->GetBondAngle ();
111 m_AutoDir = true;
112 break;
113 }
114 case 2: {
115 double a1, a2;
116 map<Atom*, Bond*>::iterator i;
117 gcp::Bond* bond = (gcp::Bond*) ((Atom*) m_pObject)->GetFirstBond (i);
118 a1 = bond->GetAngle2D ((gcp::Atom*) m_pObject);
119 bond = (gcp::Bond*) ((Atom*) m_pObject)->GetNextBond (i);
120 a2 = bond->GetAngle2D ((gcp::Atom*) m_pObject);
121 m_dAngle = (a1 + a2) / 2.;
122 a2 = fabs (a2 - m_dAngle);
123 if (a2 < 90.)
124 m_dAngle += 180.;
125 if (m_dAngle > 360.)
126 m_dAngle -= 360.;
127 break;
128 }
129 default:
130 break;
131 }
132 break;
133 default:
134 return false;
135 }
136 }
137 double a = m_dAngle * M_PI / 180.;
138 m_x1 = m_x0 + pDoc->GetBondLength () * m_dZoomFactor * cos (a);
139 m_y1 = m_y0 - pDoc->GetBondLength () * m_dZoomFactor * sin (a);
140 // TODO: reimplement
141 Item *pItem = m_pView->GetCanvas ()->GetItemAt (m_x1, m_y1);
142 Object* pObject = NULL;
143 if (pItem)
144 pObject = dynamic_cast <Object *> (pItem->GetClient ());
145 m_pAtom = NULL;
146 if (pObject && pObject != m_pObject) {
147 if ((pObject->GetType () == BondType) || (pObject->GetType () == FragmentType))
148 {
149 m_pAtom = (gcp::Atom*) pObject->GetAtomAt (m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor);
150 } else if (pObject->GetType() == AtomType) {
151 m_pAtom = (gcp::Atom*)pObject;
152 }
153 }
154 if (m_pAtom) {
155 if (m_pObject) {
156 Object *group = m_pObject->GetMolecule ()->GetParent ();
157 if (group != pDoc) {
158 Object *other = m_pAtom->GetMolecule ()->GetParent ();
159 if (other != pDoc && group != other)
160 return true;
161 }
162 }
163 m_pAtom->GetCoords(&m_x1, &m_y1, NULL);
164 m_x1 *= m_dZoomFactor;
165 m_y1 *= m_dZoomFactor;
166 m_x = m_x1 - m_x0;
167 m_y = m_y1 - m_y0;
168 m_dAngle = atan(-m_y/m_x) * 90 / 1.570796326794897;
169 if (m_x < 0) m_dAngle += 180;
170 }
171 char tmp[32];
172 snprintf (tmp, sizeof (tmp) - 1, _("Orientation: %g"), m_dAngle);
173 m_pApp->SetStatusText (tmp);
174 Draw ();
175 return true;
176 }
177
OnDrag()178 void gcpBondTool::OnDrag ()
179 {
180 gcp::Document* pDoc = m_pView->GetDoc ();
181 gcp::Theme *Theme = pDoc->GetTheme ();
182 if ((m_pObject) && (m_pObject->GetType () == BondType)) {
183 if (((gcp::Bond*) m_pObject)->GetDist (m_x / m_dZoomFactor, m_y / m_dZoomFactor) < (Theme->GetPadding () + Theme->GetBondWidth () / 2) * m_dZoomFactor) {
184 if (!m_bChanged) {
185 m_Item->SetVisible (true);
186 m_bChanged = true;
187 }
188 } else if (m_bChanged) {
189 m_Item->SetVisible (false);
190 m_bChanged = false;
191 }
192 } else {
193 Item *pItem = m_pView->GetCanvas ()->GetItemAt (m_x, m_y);
194 Object* pObject = NULL;
195 if (pItem) {
196 pObject = dynamic_cast <Object *> (pItem->GetClient ());
197 if (pObject && (pObject == m_pObject || ((pObject->GetType () == FragmentType) && dynamic_cast<gcp::Fragment*> (pObject)->GetAtom () == m_pObject))) {
198 if (!m_AutoDir)
199 return;
200 } else
201 m_AutoDir = false;
202 } else
203 m_AutoDir = false;
204 double dAngle = 0.;
205 if (m_AutoDir) {
206 dAngle = m_dAngle = m_RefAngle +
207 ((((m_nState & GDK_LOCK_MASK && (!(m_nState & GDK_MOD5_MASK))) ||
208 ((!(m_nState & GDK_LOCK_MASK)) && m_nState & GDK_MOD5_MASK)))?
209 pDoc->GetBondAngle (): -pDoc->GetBondAngle ());
210 m_x = m_x1 = m_x0 + pDoc->GetBondLength () * m_dZoomFactor * cos (m_dAngle / 180 * M_PI);
211 m_y = m_y1 = m_y0 - pDoc->GetBondLength () * m_dZoomFactor * sin (m_dAngle / 180 * M_PI);
212 pItem = m_pView->GetCanvas ()->GetItemAt (m_x, m_y);
213 pObject = NULL;
214 if (pItem)
215 pObject = dynamic_cast <Object *> (pItem->GetClient ());
216 }
217 m_pAtom = NULL;
218 if (gcp::MergeAtoms && pObject) {
219 if (pObject->GetType () == BondType)
220 m_pAtom = (gcp::Atom*) pObject->GetAtomAt (m_x / m_dZoomFactor, m_y / m_dZoomFactor);
221 else if (pObject->GetType () == FragmentType)
222 m_pAtom = (gcp::Atom*)pObject->GetAtomAt (m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor);
223 else if (pObject->GetType () == AtomType)
224 m_pAtom = (gcp::Atom*) pObject;
225 }
226 if (m_pAtom) {
227 if (m_pObject) {
228 Object *group = m_pObject->GetMolecule ()->GetParent ();
229 if (group != pDoc) {
230 Object *other = m_pAtom->GetMolecule ()->GetParent ();
231 if (other != pDoc && group != other)
232 return;
233 }
234 }
235 if ((Object*) m_pAtom == m_pObject)
236 return;
237 if (!m_pAtom->AcceptNewBonds ())
238 return;
239 m_pAtom->GetCoords (&m_x1, &m_y1, NULL);
240 m_x1 *= m_dZoomFactor;
241 m_y1 *= m_dZoomFactor;
242 m_x = m_x1 - m_x0;
243 m_y = m_y1 - m_y0;
244 dAngle = atan (-m_y / m_x) * 180. / M_PI;
245 if (isnan (dAngle))
246 dAngle = m_dAngle;
247 else if (m_x < 0.)
248 dAngle += 180.;
249 } else if (!m_AutoDir) {
250 m_x -= m_x0;
251 m_y -= m_y0;
252 if (m_x == 0) {
253 if (m_y == 0)
254 return;
255 dAngle = (m_y < 0) ? 90 : 270;
256 } else {
257 dAngle = atan (-m_y/m_x) * 180. / M_PI;
258 if (!(m_nState & GDK_CONTROL_MASK))
259 dAngle = rint (dAngle / 5) * 5;
260 if (isnan (dAngle))
261 dAngle = m_dAngle;
262 else if (m_x < 0.)
263 dAngle += 180.;
264 }
265 m_dAngle = dAngle;
266 if (m_nState & GDK_SHIFT_MASK) {
267 double x1 = sqrt (square (m_x) + square (m_y));
268 m_x1 = m_x0 + x1 * cos (m_dAngle / 180 * M_PI);
269 m_y1 = m_y0 - x1 * sin (m_dAngle / 180 * M_PI);
270 } else {
271 m_x1 = m_x0 + pDoc->GetBondLength () * m_dZoomFactor * cos (m_dAngle / 180 * M_PI);
272 m_y1 = m_y0 - pDoc->GetBondLength () * m_dZoomFactor * sin (m_dAngle / 180 * M_PI);
273 }
274 }
275 char tmp[32];
276 if (dAngle < 0)
277 dAngle += 360.;
278 snprintf (tmp, sizeof (tmp) - 1, _("Orientation: %g"), dAngle);
279 m_pApp->SetStatusText (tmp);
280 Draw ();
281 }
282 }
283
OnRelease()284 void gcpBondTool::OnRelease ()
285 {
286 gcp::Document* pDoc = m_pView->GetDoc ();
287 if (m_Item) {
288 delete m_Item;
289 m_Item = NULL;
290 } else {
291 if (m_pOp)
292 pDoc->AbortOperation ();
293 m_pOp = NULL;
294 return;
295 }
296 if ((m_pObject) && (m_pObject->GetType () == BondType)) {
297 FinalizeBond ();
298 gcp::Atom* pAtom = (gcp::Atom*) ((gcp::Bond*) m_pObject)->GetAtom (0);
299 pAtom->Update ();
300 m_pView->Update (pAtom);
301 pAtom = (gcp::Atom*) ((gcp::Bond*) m_pObject)->GetAtom (1);
302 pAtom->Update ();
303 m_pView->Update (pAtom);
304 m_pOp->AddObject (m_pObjectGroup, 1);
305 pDoc->FinishOperation ();
306 m_pOp = NULL;
307 m_pObject->EmitSignal (gcp::OnChangedSignal);
308 return;
309 } else {
310 if (m_pOp)
311 pDoc->AbortOperation();
312 m_pOp = NULL;
313 }
314 m_pApp->ClearStatus ();
315 Item *pItem = m_pView->GetCanvas ()->GetItemAt (m_x1, m_y1);
316 Object* pObject = NULL;
317 if (pItem)
318 pObject = dynamic_cast <Object *> (pItem->GetClient ());
319 m_pAtom = NULL;
320 if (gcp::MergeAtoms && pObject) {
321 if (pObject->GetType () == BondType)
322 m_pAtom = (gcp::Atom*) pObject->GetAtomAt (m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor);
323 else if (pObject->GetType() == FragmentType)
324 m_pAtom = (gcp::Atom*) pObject->GetAtomAt (m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor);
325 else if (pObject->GetType() == AtomType)
326 m_pAtom = (gcp::Atom*) pObject;
327 }
328 gcp::Atom* pAtom;
329 gcp::Bond* pBond;
330 if (!m_pObject) {
331 //Add an atom at (x0, y0)
332 pAtom = new gcp::Atom (m_pApp->GetCurZ(), m_x0 / m_dZoomFactor, m_y0 / m_dZoomFactor, 0);
333 pDoc->AddAtom (pAtom);
334 m_pObject = pAtom;
335 } else {
336 pObject = m_pObject->GetGroup ();
337 if (pObject)
338 ModifiedObjects.insert (pObject->GetId ());
339 }
340 if (m_pObject->GetType () == AtomType) {
341 if (m_pAtom) {
342 if (m_pObject == m_pAtom) {
343 ModifiedObjects.clear ();
344 return;
345 }
346 pObject = m_pAtom->GetGroup ();
347 if (!pObject)
348 throw runtime_error (_("Invalid document tree, please file a bug report"));
349 ModifiedObjects.insert (pObject->GetId ());
350 pAtom = m_pAtom;
351 } else {
352 pAtom = new gcp::Atom (m_pApp->GetCurZ (), m_x1 / m_dZoomFactor, m_y1 / m_dZoomFactor, 0);
353 pDoc->AddAtom (pAtom);
354 }
355 pBond = (gcp::Bond*) pAtom->GetBond ((gcp::Atom*) m_pObject);
356 if (pBond) {
357 m_pOp = pDoc-> GetNewOperation (gcp::GCP_MODIFY_OPERATION);
358 m_pOp->AddObject (pBond->GetGroup (), 0);
359 if (pBond->GetType () == gcp::NormalBondType)
360 pBond->IncOrder ();
361 m_pObject = pBond;
362 m_bChanged = true;
363 FinalizeBond ();
364 gcp::Atom* pAtom = (gcp::Atom*) ((gcp::Bond*) m_pObject)->GetAtom (0);
365 pAtom->Update ();
366 m_pView->Update (pAtom);
367 pAtom = (gcp::Atom*) ((gcp::Bond*) m_pObject)->GetAtom (1);
368 pAtom->Update ();
369 m_pView->Update (pAtom);
370 m_pView->Update (pBond);
371 m_pOp->AddObject (pBond->GetGroup (), 1);
372 pDoc->FinishOperation ();
373 m_pOp = NULL;
374 } else {
375 // Push modified objects in Operation
376 if (ModifiedObjects.size ()) {
377 m_pOp = pDoc-> GetNewOperation (gcp::GCP_MODIFY_OPERATION);
378 set<string>::iterator it, end = ModifiedObjects.end ();
379 for (it = ModifiedObjects.begin (); it != end; it++)
380 m_pOp->AddObject (pDoc->GetDescendant ((*it).c_str ()), 0);
381 }
382 pBond = new gcp::Bond ((gcp::Atom*) m_pObject, pAtom, 1);
383 SetType (pBond);
384 pDoc->AddBond (pBond);
385 if (m_pOp) {
386 set<string>::iterator it, end = ModifiedObjects.end ();
387 for (it = ModifiedObjects.begin (); it != end; it++) {
388 pObject = pDoc->GetDescendant ((*it).c_str ());
389 if (pObject)
390 m_pOp->AddObject (pObject, 1);
391 }
392 } else {
393 m_pOp = pDoc-> GetNewOperation (gcp::GCP_ADD_OPERATION);
394 m_pOp->AddObject (pBond->GetMolecule ());
395 }
396 pDoc->FinishOperation ();
397 }
398 }
399 ModifiedObjects.clear ();
400 }
401
Draw()402 void gcpBondTool::Draw ()
403 {
404 gcp::Theme *pTheme = m_pView->GetDoc ()->GetTheme ();
405 if (m_Item) {
406 static_cast <Line *> (m_Item)->SetPosition (m_x0, m_y0, m_x1, m_y1);
407 } else {
408 m_Item = new gccv::Line (m_pView->GetCanvas (), m_x0, m_y0, m_x1, m_y1);
409 static_cast <LineItem *> (m_Item)->SetLineColor (gcp::AddColor);
410 static_cast <LineItem *> (m_Item)->SetLineWidth (pTheme->GetBondWidth ());
411 }
412 }
413
UpdateBond()414 void gcpBondTool::UpdateBond()
415 {
416 double x1, y1, x2, y2;
417 gcp::Theme *pTheme = m_pView->GetDoc ()->GetTheme ();
418 gcp::Bond *bond = static_cast <gcp::Bond *> (m_pObject);
419 BondOrder = bond->GetOrder ();
420 if (bond->GetType () == gcp::NormalBondType)
421 bond->IncOrder ();
422 if (m_Item)
423 delete m_Item;
424 if (bond->GetOrder () == 1) {
425 bond->GetLine2DCoords (1, &x1, &y1, &x2, &y2);
426 m_Item = new gccv::Line (m_pView->GetCanvas (),
427 x1 * m_dZoomFactor, y1 * m_dZoomFactor,
428 x2 * m_dZoomFactor, y2 * m_dZoomFactor);
429 static_cast <LineItem *> (m_Item)->SetLineColor (gcp::AddColor);
430 static_cast <LineItem *> (m_Item)->SetLineWidth (pTheme->GetBondWidth ());
431 } else {
432 int i = 1;
433 m_Item = new gccv::Group (m_pView->GetCanvas ());
434 while (((gcp::Bond*) m_pObject)->GetLine2DCoords (i++, &x1, &y1, &x2, &y2)) {
435 gccv::LineItem *item = new gccv::Line (static_cast <gccv::Group *> (m_Item),
436 x1 * m_dZoomFactor, y1 * m_dZoomFactor,
437 x2 * m_dZoomFactor, y2 * m_dZoomFactor);
438 item->SetLineColor (gcp::AddColor);
439 item->SetLineWidth (pTheme->GetBondWidth ());
440 }
441 }
442 }
443
FinalizeBond()444 void gcpBondTool::FinalizeBond ()
445 {
446 if (m_bChanged) {
447 gcp::Bond* pBond = (gcp::Bond*) m_pObject;
448 if (pBond->GetType () == gcp::NormalBondType)
449 m_pView->Update (m_pObject);
450 else {
451 pBond->SetType (gcp::NormalBondType);
452 m_pView->Update (m_pObject);
453 }
454 }
455 else ((gcp::Bond*) m_pObject)->SetOrder (BondOrder);
456 m_pView->Update(((gcp::Bond*) m_pObject)->GetAtom (0));
457 m_pView->Update(((gcp::Bond*) m_pObject)->GetAtom (1));
458 }
459
SetType(gcp::Bond * pBond)460 void gcpBondTool::SetType (gcp::Bond* pBond)
461 {
462 pBond->SetType (gcp::NormalBondType);
463 }
464
on_length_changed(GtkSpinButton * btn,gcpBondTool * tool)465 static void on_length_changed (GtkSpinButton *btn, gcpBondTool *tool)
466 {
467 tool->SetLength (gtk_spin_button_get_value (btn));
468 }
469
on_angle_changed(GtkSpinButton * btn,gcpBondTool * tool)470 static void on_angle_changed (GtkSpinButton *btn, gcpBondTool *tool)
471 {
472 tool->SetAngle (gtk_spin_button_get_value (btn));
473 }
474
on_merge_toggled(GtkToggleButton * btn)475 static void on_merge_toggled (GtkToggleButton *btn)
476 {
477 gcp::MergeAtoms = gtk_toggle_button_get_active (btn);
478 }
479
SetAngle(double angle)480 void gcpBondTool::SetAngle (double angle)
481 {
482 m_pApp->GetActiveDocument ()->SetBondAngle (angle);
483 }
484
SetLength(double length)485 void gcpBondTool::SetLength (double length)
486 {
487 m_pApp->GetActiveDocument ()->SetBondLength (length);
488 }
489
GetPropertyPage()490 GtkWidget *gcpBondTool::GetPropertyPage ()
491 {
492 gcugtk::UIBuilder *builder = new gcugtk::UIBuilder (UIDIR"/bond.ui", GETTEXT_PACKAGE);
493 m_LengthBtn = GTK_SPIN_BUTTON (builder->GetWidget ("bond-length"));
494 g_signal_connect (m_LengthBtn, "value-changed", G_CALLBACK (on_length_changed), this);
495 m_AngleBtn = GTK_SPIN_BUTTON (builder->GetWidget ("bond-angle"));
496 g_signal_connect (m_AngleBtn, "value-changed", G_CALLBACK (on_angle_changed), this);
497 m_MergeBtn = GTK_TOGGLE_BUTTON (builder->GetWidget ("merge"));
498 g_signal_connect (m_MergeBtn, "toggled", G_CALLBACK (on_merge_toggled), NULL);
499 GtkWidget *res = builder->GetRefdWidget ("bond");
500 delete builder;
501 return res;
502 }
503
Activate()504 void gcpBondTool::Activate ()
505 {
506 gcp::Document *pDoc = m_pApp->GetActiveDocument ();
507 gtk_spin_button_set_value (m_LengthBtn, pDoc->GetBondLength ());
508 gtk_spin_button_set_value (m_AngleBtn, pDoc->GetBondAngle ());
509 gtk_toggle_button_set_active (m_MergeBtn, gcp::MergeAtoms);
510 }
511
gcpUpBondTool(gcp::Application * App)512 gcpUpBondTool::gcpUpBondTool (gcp::Application *App): gcpBondTool (App, "UpBond", 3)
513 {
514 }
515
~gcpUpBondTool()516 gcpUpBondTool::~gcpUpBondTool ()
517 {
518 }
519
Draw()520 void gcpUpBondTool::Draw ()
521 {
522 gcp::Theme *pTheme = m_pView->GetDoc ()->GetTheme ();
523 if (m_Item) {
524 static_cast <Wedge *> (m_Item)->SetPosition (m_x0, m_y0, m_x1, m_y1);
525 } else {
526 m_Item = new Wedge (m_pView->GetCanvas (), m_x0, m_y0, m_x1, m_y1, pTheme->GetStereoBondWidth ());
527 static_cast <Wedge *> (m_Item)->SetFillColor (gcp::AddColor);
528 }
529 }
530
UpdateBond()531 void gcpUpBondTool::UpdateBond ()
532 {
533 if (((gcp::Bond*) m_pObject)->GetType () == gcp::UpBondType) {
534 m_x = m_x0;
535 m_x0 = m_x1;
536 m_x1 = m_x;
537 m_y = m_y0;
538 m_y0 = m_y1;
539 m_y1 = m_y;
540 }
541 Draw ();
542 }
543
FinalizeBond()544 void gcpUpBondTool::FinalizeBond()
545 {
546 if (m_bChanged) {
547 gcp::Bond* pBond = (gcp::Bond*) m_pObject;
548 if (pBond->GetType () == gcp::UpBondType) {
549 pBond->Revert ();
550 m_pView->Update (m_pObject);
551 } else {
552 pBond->SetType (gcp::UpBondType);
553 m_pView->Remove (m_pObject);
554 m_pView->AddObject (m_pObject);
555 }
556 }
557 }
558
SetType(gcp::Bond * pBond)559 void gcpUpBondTool::SetType (gcp::Bond* pBond)//FIXME: Is it really useful?
560 {
561 pBond->SetType (gcp::UpBondType);
562 }
563
on_config_changed(GOConfNode * node,gchar const *,gcpDownBondTool * tool)564 static void on_config_changed (GOConfNode *node, gchar const *, gcpDownBondTool *tool)
565 {
566 tool->UpdateItem (go_conf_get_bool (node, "invert-wedge-hashes"));
567 }
568
gcpDownBondTool(gcp::Application * App,gccv::Wedge * item)569 gcpDownBondTool::gcpDownBondTool (gcp::Application *App, gccv::Wedge *item):
570 gcpBondTool (App, "DownBond", 4),
571 m_Wedge (item)
572 {
573 m_ConfNode = go_conf_get_node (App->GetConfDir (), GCP_CONF_DIR_SETTINGS);
574 m_NotificationId = go_conf_add_monitor (m_ConfNode, NULL, (GOConfMonitorFunc) on_config_changed, GetApplication ());
575 }
576
~gcpDownBondTool()577 gcpDownBondTool::~gcpDownBondTool ()
578 {
579 go_conf_remove_monitor (m_NotificationId);
580 go_conf_free_node (m_ConfNode);
581 }
582
UpdateItem(bool inverted)583 void gcpDownBondTool::UpdateItem (bool inverted)
584 {
585 if (inverted)
586 m_Wedge->SetPosition (2., 22., 19., 5.);
587 else
588 m_Wedge->SetPosition (19., 5., 2., 22.);
589 }
590
Draw()591 void gcpDownBondTool::Draw()
592 {
593 gcp::Theme *pTheme = m_pView->GetDoc ()->GetTheme ();
594 if (m_Item) {
595 if (gcp::InvertWedgeHashes)
596 static_cast <Hash *> (m_Item)->SetPosition (m_x0, m_y0, m_x1, m_y1);
597 else
598 static_cast <Hash *> (m_Item)->SetPosition (m_x1, m_y1, m_x0, m_y0);
599 } else {
600 gccv::Hash *hash = gcp::InvertWedgeHashes?
601 new Hash (m_pView->GetCanvas (), m_x0, m_y0, m_x1, m_y1, pTheme->GetStereoBondWidth ()):
602 new Hash (m_pView->GetCanvas (), m_x1, m_y1, m_x0, m_y0, pTheme->GetStereoBondWidth ());
603 hash->SetFillColor (gcp::AddColor);
604 hash->SetLineWidth (pTheme->GetHashWidth ());
605 hash->SetLineDist (pTheme->GetHashDist ());
606 m_Item = hash;
607 }
608 }
609
UpdateBond()610 void gcpDownBondTool::UpdateBond ()
611 {
612 if (((gcp::Bond*) m_pObject)->GetType() == gcp::DownBondType) {
613 m_x = m_x0;
614 m_x0 = m_x1;
615 m_x1 = m_x;
616 m_y = m_y0;
617 m_y0 = m_y1;
618 m_y1 = m_y;
619 }
620 Draw ();
621 }
622
FinalizeBond()623 void gcpDownBondTool::FinalizeBond ()
624 {
625 if (m_bChanged) {
626 gcp::Bond* pBond = (gcp::Bond*)m_pObject;
627 if (pBond->GetType () == gcp::DownBondType) {
628 pBond->Revert ();
629 m_pView->Update (m_pObject);
630 } else {
631 pBond->SetType (gcp::DownBondType);
632 m_pView->Remove (m_pObject);
633 m_pView->AddObject (m_pObject);
634 }
635 }
636 }
637
SetType(gcp::Bond * pBond)638 void gcpDownBondTool::SetType (gcp::Bond* pBond)
639 {
640 pBond->SetType (gcp::DownBondType);
641 }
642
gcpForeBondTool(gcp::Application * App)643 gcpForeBondTool::gcpForeBondTool (gcp::Application *App): gcpBondTool (App, "ForeBond", 4)
644 {
645 }
646
~gcpForeBondTool()647 gcpForeBondTool::~gcpForeBondTool ()
648 {
649 }
650
Draw()651 void gcpForeBondTool::Draw ()
652 {
653 gcp::Theme *pTheme = m_pView->GetDoc ()->GetTheme ();
654 if (m_Item) {
655 static_cast <Line *> (m_Item)->SetPosition (m_x0, m_y0, m_x1, m_y1);
656 } else {
657 m_Item = new gccv::Line (m_pView->GetCanvas (), m_x0, m_y0, m_x1, m_y1);
658 static_cast <LineItem *> (m_Item)->SetLineColor (gcp::AddColor);
659 static_cast <LineItem *> (m_Item)->SetLineWidth (pTheme->GetStereoBondWidth ());
660 }
661 }
662
UpdateBond()663 void gcpForeBondTool::UpdateBond ()
664 {
665 Draw ();
666 }
667
FinalizeBond()668 void gcpForeBondTool::FinalizeBond ()
669 {
670 if (m_bChanged) {
671 gcp::Bond* pBond = (gcp::Bond*) m_pObject;
672 if (pBond->GetType () != gcp::ForeBondType) {
673 pBond->SetType (gcp::ForeBondType);
674 m_pView->Remove (m_pObject);
675 m_pView->AddObject (m_pObject);
676 }
677 }
678 }
679
SetType(gcp::Bond * pBond)680 void gcpForeBondTool::SetType (gcp::Bond* pBond)
681 {
682 pBond->SetType (gcp::ForeBondType);
683 }
684
gcpSquiggleBondTool(gcp::Application * App)685 gcpSquiggleBondTool::gcpSquiggleBondTool (gcp::Application *App): gcpBondTool (App, "SquiggleBond", 4)
686 {
687 }
688
~gcpSquiggleBondTool()689 gcpSquiggleBondTool::~gcpSquiggleBondTool ()
690 {
691 }
692
Draw()693 void gcpSquiggleBondTool::Draw ()
694 {
695 gcp::Theme *pTheme = m_pView->GetDoc ()->GetTheme ();
696 if (m_Item) {
697 static_cast <Squiggle *> (m_Item)->SetPosition (m_x0, m_y0, m_x1, m_y1);
698 } else {
699 Squiggle *squiggle = new Squiggle (m_pView->GetCanvas (), m_x0, m_y0, m_x1, m_y1);
700 squiggle->SetLineColor (gcp::AddColor);
701 squiggle->SetLineWidth (pTheme->GetBondWidth ());
702 squiggle->SetWidth (pTheme->GetStereoBondWidth () - pTheme->GetBondWidth () / 2.);
703 squiggle->SetStep (pTheme->GetStereoBondWidth () / 2.);
704 m_Item = squiggle;
705 }
706 }
707
UpdateBond()708 void gcpSquiggleBondTool::UpdateBond ()
709 {
710 Draw ();
711 }
712
FinalizeBond()713 void gcpSquiggleBondTool::FinalizeBond ()
714 {
715 if (m_bChanged) {
716 gcp::Bond* pBond = (gcp::Bond*) m_pObject;
717 if (pBond->GetType () == gcp::UndeterminedBondType) {
718 pBond->Revert ();
719 m_pView->Update (m_pObject);
720 } else {
721 pBond->SetType (gcp::UndeterminedBondType);
722 m_pView->Remove (m_pObject);
723 m_pView->AddObject (m_pObject);
724 }
725 }
726 }
727
SetType(gcp::Bond * pBond)728 void gcpSquiggleBondTool::SetType (gcp::Bond* pBond)
729 {
730 pBond->SetType (gcp::UndeterminedBondType);
731 }
732