source: src/UIElements/Views/Qt4/Qt3D/GLWorldView.cpp@ d5521e

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since d5521e was 4d6662, checked in by Frederik Heber <heber@…>, 12 years ago

FIX: Using signal/slots to notify other thread of new or removed shapes.

  • Property mode set to 100644
File size: 58.5 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * GLWorldView.cpp
26 *
27 * Created on: Aug 1, 2010
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "GLWorldView.hpp"
37
38#include <Qt/qevent.h>
39#include <Qt/qaction.h>
40#include <QtGui/QMenu>
41#include <QtGui/QToolBar>
42#include <QtGui/QToolButton>
43#include <Qt/qtimer.h>
44#include <Qt/qsettings.h>
45#include <Qt3D/qglbuilder.h>
46#include <Qt3D/qglscenenode.h>
47#include <Qt3D/qglsphere.h>
48#include <Qt3D/qglcylinder.h>
49#include <Qt3D/qglcube.h>
50
51#include "GLWorldScene.hpp"
52
53#include "CodePatterns/MemDebug.hpp"
54
55#include "Atom/AtomObserver.hpp"
56#include "Atom/atom_observable.hpp"
57#include "Box.hpp"
58#include "CodePatterns/Log.hpp"
59#include "CodePatterns/Observer/Notification.hpp"
60#include "CodePatterns/Observer/ObserverLog.hpp"
61#include "molecule.hpp"
62#include "Shapes/ShapeRegistry.hpp"
63#include "World.hpp"
64#include "WorldTime.hpp"
65
66GLWorldView::GLWorldView(QWidget *parent)
67 : QGLView(parent), Observer("GLWorldView"), worldscene(NULL), changesPresent(false), needsRedraw(false)
68{
69 worldscene = new GLWorldScene(this);
70
71 setOption(QGLView::ObjectPicking, true);
72 setOption(QGLView::CameraNavigation, false);
73 setCameraControlMode(Rotate);
74 defaultEyeSeparation = 4.0;
75
76 createDomainBox();
77 createDreiBein();
78 //changeMaterials(false);
79
80 connect(worldscene, SIGNAL(changeOccured()), this, SLOT(changeSignalled()));
81 connect(worldscene, SIGNAL(changed()), this, SIGNAL(changed()));
82 connect(worldscene, SIGNAL(hoverChanged(const atom *)), this, SLOT(sceneHoverSignalled(const atom *)));
83 connect(this, SIGNAL(atomInserted(const atom *)), worldscene, SLOT(atomInserted(const atom *)));
84 connect(this, SIGNAL(atomRemoved(const atom *)), worldscene, SLOT(atomRemoved(const atom *)));
85 connect(this, SIGNAL(worldSelectionChanged()), worldscene, SLOT(worldSelectionChanged()));
86 connect(this, SIGNAL(moleculeRemoved(const molecule *)), worldscene, SLOT(moleculeRemoved(const molecule *)));
87 //connect(this, SIGNAL(moleculeInserted(const molecule *)), worldscene, SLOT(moleculeInserted(const molecule *)));
88 //connect(this, SIGNAL(changed()), this, SLOT(updateGL()));
89 connect(this, SIGNAL(changed()), this, SLOT(sceneChangeSignalled()));
90
91 // sign on to changes in the world
92 World::getInstance().signOn(this);
93 World::getInstance().signOn(this, World::AtomInserted);
94 World::getInstance().signOn(this, World::AtomRemoved);
95 World::getInstance().signOn(this, World::MoleculeInserted);
96 World::getInstance().signOn(this, World::MoleculeRemoved);
97 World::getInstance().signOn(this, World::SelectionChanged);
98 WorldTime::getInstance().signOn(this, WorldTime::TimeChanged);
99 AtomObserver::getInstance().signOn(this, AtomObservable::PositionChanged);
100
101 ShapeRegistry::getInstance().signOn(this);
102 ShapeRegistry::getInstance().signOn(this, ShapeRegistry::ShapeInserted);
103 ShapeRegistry::getInstance().signOn(this, ShapeRegistry::ShapeRemoved);
104 ShapeRegistry::getInstance().signOn(this, ShapeRegistry::SelectionChanged);
105
106 redrawTimer = new QTimer(this);
107}
108
109GLWorldView::~GLWorldView()
110{
111 World::getInstance().signOff(this);
112 World::getInstance().signOff(this, World::AtomInserted);
113 World::getInstance().signOff(this, World::AtomRemoved);
114 World::getInstance().signOff(this, World::MoleculeInserted);
115 World::getInstance().signOff(this, World::MoleculeRemoved);
116 World::getInstance().signOff(this, World::SelectionChanged);
117 WorldTime::getInstance().signOff(this, WorldTime::TimeChanged);
118 AtomObserver::getInstance().signOff(this, AtomObservable::PositionChanged);
119 ShapeRegistry::getInstance().signOff(this);
120 ShapeRegistry::getInstance().signOff(this, ShapeRegistry::ShapeInserted);
121 ShapeRegistry::getInstance().signOff(this, ShapeRegistry::ShapeRemoved);
122 ShapeRegistry::getInstance().signOff(this, ShapeRegistry::SelectionChanged);
123 delete worldscene;
124
125 delete(domainBoxMaterial);
126 for (int i=0;i<3;i++)
127 delete(dreiBeinMaterial[i]);
128}
129
130
131/**
132 * Add some widget specific actions to the toolbar:
133 * - camera rotation/translation mode
134 * - camera fit to domain
135 */
136void GLWorldView::addToolBarActions(QToolBar *toolbar)
137{
138 // camera control mode
139 toolbar->addSeparator();
140 QAction *transAction = new QAction(QIcon::fromTheme("forward"), tr("camera translation mode"), this);
141 connect(transAction, SIGNAL(triggered()), this, SLOT(setCameraControlModeTranslation()));
142 toolbar->addAction(transAction);
143 QAction *rotAction = new QAction(QIcon::fromTheme("object-rotate-left"), tr("camera rotation mode"), this);
144 connect(rotAction, SIGNAL(triggered()), this, SLOT(setCameraControlModeRotation()));
145 toolbar->addAction(rotAction);
146 QAction *fitAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("camera fit to domain"), this);
147 connect(fitAction, SIGNAL(triggered()), this, SLOT(fitCameraToDomain()));
148 toolbar->addAction(fitAction);
149
150 // stereo mode
151 QToolButton *stereoButton = new QToolButton(toolbar);
152 QMenu *stereoMenu = new QMenu();
153 QAction *stereoDisableAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("disable"), this);
154 connect(stereoDisableAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeDisable()));
155 stereoMenu->addAction(stereoDisableAction);
156 QAction *stereoHardwareAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("hardware"), this);
157 connect(stereoHardwareAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeHardware()));
158 stereoMenu->addAction(stereoHardwareAction);
159 QAction *stereoLeftRightAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("left right"), this);
160 connect(stereoLeftRightAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeLeftRight()));
161 stereoMenu->addAction(stereoLeftRightAction);
162 QAction *stereoRightLeftAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("right left"), this);
163 connect(stereoRightLeftAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeRightLeft()));
164 stereoMenu->addAction(stereoRightLeftAction);
165 QAction *stereoTopBottomAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("top bottom"), this);
166 connect(stereoTopBottomAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeTopBottom()));
167 stereoMenu->addAction(stereoTopBottomAction);
168 QAction *stereoBottomTopAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("bottom top"), this);
169 connect(stereoBottomTopAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeBottomTop()));
170 stereoMenu->addAction(stereoBottomTopAction);
171 QAction *stereoAnaglyphAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("anaglyph"), this);
172 connect(stereoAnaglyphAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeAnaglyph()));
173 stereoMenu->addAction(stereoAnaglyphAction);
174 stereoButton->setMenu(stereoMenu);
175 stereoButton->setIcon(QIcon(QPixmap(":/icon_view_stereo.png")));
176 stereoButton->setPopupMode(QToolButton::InstantPopup);
177 toolbar->addWidget(stereoButton);
178
179 // selection mode
180 toolbar->addSeparator();
181 QAction *selAtomAction = new QAction(QIcon(QPixmap(":/icon_select_atom.png")), tr("select atom by clicking"), this);
182 connect(selAtomAction, SIGNAL(triggered()), worldscene, SLOT(setSelectionModeAtom()));
183 toolbar->addAction(selAtomAction);
184 QAction *selMolAction = new QAction(QIcon(QPixmap(":/icon_select_molecule.png")), tr("select molecule by clicking"), this);
185 connect(selMolAction, SIGNAL(triggered()), worldscene, SLOT(setSelectionModeMolecule()));
186 toolbar->addAction(selMolAction);
187}
188
189void GLWorldView::createDomainBox()
190{
191 QSettings settings;
192 settings.beginGroup("WorldView");
193 QColor colorFrame = settings.value("domainBoxColorFrame", QColor(150,160,200,255)).value<QColor>();
194 QColor colorAmbient = settings.value("domainBoxColorAmbient", QColor(50,60,100,255)).value<QColor>();
195 QColor colorDiffuse = settings.value("domainBoxColorDiffuse", QColor(150,160,200,180)).value<QColor>();
196 settings.setValue("domainBoxColorFrame", colorFrame);
197 settings.setValue("domainBoxColorAmbient", colorAmbient);
198 settings.setValue("domainBoxColorDiffuse", colorDiffuse);
199 settings.endGroup();
200
201 domainBoxMaterial = new QGLMaterial;
202 domainBoxMaterial->setAmbientColor(QColor(0,0,0,255));
203 domainBoxMaterial->setDiffuseColor(QColor(0,0,0,255));
204 domainBoxMaterial->setEmittedLight(colorFrame);
205
206
207 QGLMaterial *material = new QGLMaterial;
208 material->setAmbientColor(colorAmbient);
209 material->setDiffuseColor(colorDiffuse);
210
211 QGLBuilder builder;
212 builder << QGL::Faceted;
213 builder << QGLCube(-1.0); // "inverted" => inside faces are used as front.
214 meshDomainBox = builder.finalizedSceneNode();
215 QMatrix4x4 mat;
216 mat.translate(0.5f, 0.5f, 0.5f);
217 meshDomainBox->setLocalTransform(mat);
218 meshDomainBox->setMaterial(material);
219}
220
221void GLWorldView::createDreiBein()
222{
223 QSettings settings;
224 settings.beginGroup("WorldView");
225 QColor colorX = settings.value("dreiBeinColorX", QColor(255,50,50,255)).value<QColor>();
226 QColor colorY = settings.value("dreiBeinColorY", QColor(50,255,50,255)).value<QColor>();
227 QColor colorZ = settings.value("dreiBeinColorZ", QColor(50,50,255,255)).value<QColor>();
228 settings.setValue("dreiBeinColorX", colorX);
229 settings.setValue("dreiBeinColorY", colorY);
230 settings.setValue("dreiBeinColorZ", colorZ);
231 settings.setValue("dreiBeinEnabled", true);
232 settings.endGroup();
233
234 // Create 3 color for the 3 axes.
235 dreiBeinMaterial[0] = new QGLMaterial;
236 dreiBeinMaterial[0]->setColor(colorX);
237 dreiBeinMaterial[1] = new QGLMaterial;
238 dreiBeinMaterial[1]->setColor(colorY);
239 dreiBeinMaterial[2] = new QGLMaterial;
240 dreiBeinMaterial[2]->setColor(colorZ);
241
242 // Create the basic meshes (cylinder and cone).
243 QGLBuilder builderCyl;
244 builderCyl << QGLCylinder(.15,.15,1.6,16);
245 QGLSceneNode *cyl = builderCyl.finalizedSceneNode();
246
247 QGLBuilder builderCone;
248 builderCone << QGLCylinder(0,.4,0.4,16);
249 QGLSceneNode *cone = builderCone.finalizedSceneNode();
250 {
251 QMatrix4x4 mat;
252 mat.translate(0.0f, 0.0f, 1.0f);
253 cone->setLocalTransform(mat);
254 }
255
256 // Create a scene node from the 3 axes.
257 meshDreiBein = new QGLSceneNode(this);
258
259 // X-direction
260 QGLSceneNode *node = new QGLSceneNode(meshDreiBein);
261 node->setMaterial(dreiBeinMaterial[0]);
262 node->addNode(cyl);
263 node->setPosition(QVector3D(.8f, 0.f, 0.f));
264 node->addNode(cone);
265 {
266 QMatrix4x4 mat;
267 mat.rotate(90, 0.0f, 1.0f, 0.0f);
268 node->setLocalTransform(mat);
269 }
270
271 // Y-direction
272 node = new QGLSceneNode(meshDreiBein);
273 node->setMaterial(dreiBeinMaterial[1]);
274 node->addNode(cyl);
275 node->addNode(cone);
276 {
277 QMatrix4x4 mat;
278 mat.rotate(-90, 1.0f, 0.0f, 0.0f);
279 node->setLocalTransform(mat);
280 }
281 node->setPosition(QVector3D(0.f, .8f, 0.f));
282
283 // Z-direction
284 node = new QGLSceneNode(meshDreiBein);
285 node->setMaterial(dreiBeinMaterial[2]);
286 node->addNode(cyl);
287 node->addNode(cone);
288 node->setPosition(QVector3D(0.f, 0.f, .8f));
289}
290
291/**
292 * Update operation which can be invoked by the observable (which should be the
293 * change tracker here).
294 */
295void GLWorldView::update(Observable *publisher)
296{
297 emit changed();
298}
299
300/**
301 * The observable can tell when it dies.
302 */
303void GLWorldView::subjectKilled(Observable *publisher) {}
304
305/** Listen to specific changes to the world.
306 *
307 * @param publisher ref to observable.
308 * @param notification type of notification
309 */
310void GLWorldView::recieveNotification(Observable *publisher, Notification_ptr notification)
311{
312 if (static_cast<World *>(publisher) == World::getPointer()) {
313 switch (notification->getChannelNo()) {
314 case World::AtomInserted:
315 {
316 const atom *_atom = World::getInstance().lastChanged<atom>();
317 #ifdef LOG_OBSERVER
318 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_atom->getId())+" has been inserted.";
319 #endif
320 emit atomInserted(_atom);
321 break;
322 }
323 case World::AtomRemoved:
324 {
325 const atom *_atom = World::getInstance().lastChanged<atom>();
326 #ifdef LOG_OBSERVER
327 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_atom->getId())+" has been removed.";
328 #endif
329 emit atomRemoved(_atom);
330 break;
331 }
332 case World::SelectionChanged:
333 {
334 #ifdef LOG_OBSERVER
335 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that selection has changed.";
336 #endif
337 emit worldSelectionChanged();
338 break;
339 }
340 case World::MoleculeInserted:
341 {
342 const molecule *_molecule = World::getInstance().lastChanged<molecule>();
343 #ifdef LOG_OBSERVER
344 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that molecule "+toString(_molecule->getId())+" has been removed.";
345 #endif
346 emit moleculeInserted(_molecule);
347 break;
348 }
349 case World::MoleculeRemoved:
350 {
351 const molecule *_molecule = World::getInstance().lastChanged<molecule>();
352 #ifdef LOG_OBSERVER
353 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that molecule "+toString(_molecule->getId())+" has been removed.";
354 #endif
355 emit moleculeRemoved(_molecule);
356 break;
357 }
358 default:
359 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for World.");
360 break;
361 }
362 } else if (static_cast<WorldTime *>(publisher) == WorldTime::getPointer()) {
363 switch (notification->getChannelNo()) {
364 case WorldTime::TimeChanged:
365 {
366#ifdef LOG_OBSERVER
367 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that WorldTime's time has changed.";
368#endif
369 emit changed();
370 break;
371 }
372 default:
373 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for WorldTime.");
374 break;
375 }
376} else if (dynamic_cast<AtomObservable *>(publisher) != NULL) {
377 switch (notification->getChannelNo()) {
378 case AtomObservable::PositionChanged:
379 {
380 #ifdef LOG_OBSERVER
381 const atom *_atom = dynamic_cast<const atom *>(publisher);
382 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_atom->getId())+" has changed its position.";
383 #endif
384 emit changed();
385 break;
386 }
387 default:
388 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for AtomObservable.");
389 break;
390 }
391 } else if (static_cast<ShapeRegistry*>(publisher) == ShapeRegistry::getPointer()) {
392 switch (notification->getChannelNo()) {
393 case ShapeRegistry::ShapeInserted:
394 {
395 emit ShapeAdded();
396 break;
397 }
398 case ShapeRegistry::ShapeRemoved:
399 {
400 emit ShapeRemoved();
401 break;
402 }
403 case ShapeRegistry::SelectionChanged:
404 {
405 worldscene->updateSelectedShapes();
406 break;
407 }
408 default:
409 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for ShapeRegistry.");
410 break;
411 }
412 } else
413 ASSERT(0, "GLWorldView::recieveNotification() - received notification from unknown source.");
414}
415
416void GLWorldView::checkChanges()
417{
418 updateGL();
419 needsRedraw = false;
420}
421
422void GLWorldView::sceneChangeSignalled()
423{
424 if (!needsRedraw){
425 redrawTimer->singleShot(0, this, SLOT(checkChanges()));
426 needsRedraw = true;
427 redrawTimer->start();
428 }
429}
430
431void GLWorldView::initializeGL(QGLPainter *painter)
432{
433 worldscene->initialize(this, painter);
434 changesPresent = false;
435}
436
437void GLWorldView::paintGL(QGLPainter *painter)
438{
439 if (changesPresent) {
440 initializeGL(painter);
441 changesPresent = false;
442 }
443
444 QVector3D cameraDir = camera()->center() - camera()->eye();
445 cameraDir.normalize();
446 QVector4D cameraPlane(cameraDir, QVector3D::dotProduct(cameraDir, camera()->eye()));
447 worldscene->draw(painter, cameraPlane);
448
449 drawDreiBein(painter);
450
451 // Domain box has to be last because of its transparency.
452 drawDomainBox(painter);
453}
454
455void GLWorldView::keyPressEvent(QKeyEvent *e)
456{
457 if (e->key() == Qt::Key_Tab) {
458 // The Tab key turns the ShowPicking option on and off,
459 // which helps show what the pick buffer looks like.
460 setOption(QGLView::ShowPicking, ((options() & QGLView::ShowPicking) == 0));
461 updateGL();
462 }
463 QGLView::keyPressEvent(e);
464}
465
466void GLWorldView::changeSignalled()
467{
468 changesPresent = true;
469}
470
471
472/**
473 * Set the current camera control mode.
474 */
475void GLWorldView::setCameraControlMode(GLWorldView::CameraControlModeType mode)
476{
477 cameraControlMode = mode;
478}
479
480void GLWorldView::setCameraControlModeRotation()
481{
482 setCameraControlMode(Rotate);
483}
484
485void GLWorldView::setCameraControlModeTranslation()
486{
487 setCameraControlMode(Translate);
488}
489
490/**
491 * Returns the current camera control mode.
492 * This needs to be invertable (rotation - translation), if the shift key is pressed.
493 */
494GLWorldView::CameraControlModeType GLWorldView::getCameraControlMode(bool inverted)
495{
496 if (inverted){
497 if (cameraControlMode == Rotate)
498 return Translate;
499 if (cameraControlMode == Translate)
500 return Rotate;
501 return Rotate;
502 }else
503 return cameraControlMode;
504}
505
506/**
507 * Set the camera so it can oversee the whole domain.
508 */
509void GLWorldView::fitCameraToDomain()
510{
511 // Move the camera focus point to the center of the domain box.
512 Vector v = World::getInstance().getDomain().translateIn(Vector(0.5, 0.5, 0.5));
513 camera()->setCenter(QVector3D(v[0], v[1], v[2]));
514
515 // Guess some eye distance.
516 double dist = v.Norm() * 3;
517 camera()->setEye(QVector3D(v[0], v[1], v[2] + dist));
518 camera()->setUpVector(QVector3D(0, 1, 0));
519}
520
521void GLWorldView::setCameraStereoModeDisable()
522{
523 setStereoType(QGLView::Hardware);
524 camera()->setEyeSeparation(0.0);
525 updateGL();
526}
527
528void GLWorldView::setCameraStereoModeHardware()
529{
530 setStereoType(QGLView::Hardware);
531 camera()->setEyeSeparation(defaultEyeSeparation);
532 updateGL();
533}
534
535void GLWorldView::setCameraStereoModeLeftRight()
536{
537 setStereoType(QGLView::LeftRight);
538 camera()->setEyeSeparation(defaultEyeSeparation);
539 updateGL();
540}
541
542void GLWorldView::setCameraStereoModeRightLeft()
543{
544 setStereoType(QGLView::RightLeft);
545 camera()->setEyeSeparation(defaultEyeSeparation);
546 updateGL();
547}
548
549void GLWorldView::setCameraStereoModeTopBottom()
550{
551 setStereoType(QGLView::TopBottom);
552 camera()->setEyeSeparation(defaultEyeSeparation);
553 updateGL();
554}
555
556void GLWorldView::setCameraStereoModeBottomTop()
557{
558 setStereoType(QGLView::BottomTop);
559 camera()->setEyeSeparation(defaultEyeSeparation);
560 updateGL();
561}
562
563void GLWorldView::setCameraStereoModeAnaglyph()
564{
565 setStereoType(QGLView::RedCyanAnaglyph);
566 camera()->setEyeSeparation(defaultEyeSeparation);
567 updateGL();
568}
569
570void GLWorldView::mousePressEvent(QMouseEvent *event)
571{
572 QGLView::mousePressEvent(event);
573
574 // Reset the saved mouse position.
575 lastMousePos = event->posF();
576}
577
578/**
579 * Handle a mouse move event.
580 * This is used to control the camera (rotation and translation) when the left button is being pressed.
581 */
582void GLWorldView::mouseMoveEvent(QMouseEvent *event)
583{
584 if (event->buttons() & Qt::LeftButton){
585 // Find the mouse distance since the last event.
586 QPointF d = event->posF() - lastMousePos;
587 lastMousePos = event->posF();
588
589 // Rotate or translate? (inverted by shift key)
590 CameraControlModeType mode = getCameraControlMode(event->modifiers() & Qt::ShiftModifier);
591
592 if (mode == Rotate){
593 // Rotate the camera.
594 d *= 0.3;
595 camera()->tiltPanRollCenter(- d.y(), - d.x(), 0);
596 }else if (mode == Translate){
597 // Translate the camera.
598 d *= 0.02;
599 camera()->translateCenter(- d.x(), d.y(), 0);
600 camera()->translateEye(- d.x(), d.y(), 0);
601 }
602 }else{
603 // Without this Qt would not test for hover events (i.e. mouse over an atom).
604 QGLView::mouseMoveEvent(event);
605 }
606}
607
608/**
609 * When the mouse wheel is used, zoom in or out.
610 */
611void GLWorldView::wheelEvent(QWheelEvent *event)
612{
613 // Find the distance between the eye and focus point.
614 QVector3D d = camera()->eye() - camera()->center();
615
616 // Scale the distance.
617 if (event->delta() < 0)
618 d *= 1.2;
619 else if (event->delta() > 0)
620 d /= 1.2;
621
622 // Set new eye position.
623 camera()->setEye(camera()->center() + d);
624}
625
626/**
627 * Draw a transparent cube representing the domain.
628 */
629void GLWorldView::drawDomainBox(QGLPainter *painter) const
630{
631 // Apply the domain matrix.
632 RealSpaceMatrix m = World::getInstance().getDomain().getM();
633 painter->modelViewMatrix().push();
634 painter->modelViewMatrix() *= QMatrix4x4(m.at(0,0), m.at(0,1), m.at(0,2), 0.0,
635 m.at(1,0), m.at(1,1), m.at(1,2), 0.0,
636 m.at(2,0), m.at(2,1), m.at(2,2), 0.0,
637 0.0, 0.0, 0.0, 1.0);
638
639 // Draw the transparent cube.
640 painter->setStandardEffect(QGL::LitMaterial);
641 glCullFace(GL_BACK);
642 glEnable(GL_CULL_FACE);
643 glEnable(GL_BLEND);
644 glDepthMask(0);
645 //glDisable(GL_DEPTH_TEST);
646 meshDomainBox->draw(painter);
647 //glEnable(GL_DEPTH_TEST);
648 glDepthMask(1);
649 glDisable(GL_BLEND);
650 glDisable(GL_CULL_FACE);
651
652 // Draw the outlines.
653 painter->setFaceMaterial(QGL::AllFaces, domainBoxMaterial);
654 //glEnable(GL_LINE_SMOOTH);
655 QVector3DArray array;
656 array.append(0, 0, 0); array.append(1, 0, 0);
657 array.append(1, 0, 0); array.append(1, 1, 0);
658 array.append(1, 1, 0); array.append(0, 1, 0);
659 array.append(0, 1, 0); array.append(0, 0, 0);
660
661 array.append(0, 0, 1); array.append(1, 0, 1);
662 array.append(1, 0, 1); array.append(1, 1, 1);
663 array.append(1, 1, 1); array.append(0, 1, 1);
664 array.append(0, 1, 1); array.append(0, 0, 1);
665
666 array.append(0, 0, 0); array.append(0, 0, 1);
667 array.append(1, 0, 0); array.append(1, 0, 1);
668 array.append(0, 1, 0); array.append(0, 1, 1);
669 array.append(1, 1, 0); array.append(1, 1, 1);
670 painter->clearAttributes();
671 painter->setVertexAttribute(QGL::Position, array);
672 painter->draw(QGL::Lines, 24);
673
674 painter->modelViewMatrix().pop();
675}
676
677void GLWorldView::drawDreiBein(QGLPainter *painter)
678{
679 painter->modelViewMatrix().push();
680 painter->modelViewMatrix().translate(camera()->center());
681 painter->setStandardEffect(QGL::LitMaterial);
682 painter->setFaceMaterial(QGL::FrontFaces, NULL);
683 meshDreiBein->draw(painter);
684 painter->modelViewMatrix().pop();
685}
686
687void GLWorldView::sceneHoverSignalled(const atom *_atom)
688{
689 emit hoverChanged(_atom);
690}
691
692
693//#include <GL/glu.h>
694//#include <QtGui/qslider.h>
695//#include <QtGui/qevent.h>
696//
697//#include "ui_dialoglight.h"
698//
699//#include "CodePatterns/MemDebug.hpp"
700//
701//#include <iostream>
702//#include <boost/shared_ptr.hpp>
703//
704//#include "LinearAlgebra/Line.hpp"
705//#include "Atom/atom.hpp"
706//#include "Bond/bond.hpp"
707//#include "Element/element.hpp"
708//#include "molecule.hpp"
709//#include "Element/periodentafel.hpp"
710//#include "World.hpp"
711//
712//#if defined(Q_CC_MSVC)
713//#pragma warning(disable:4305) // init: truncation from const double to float
714//#endif
715//
716//
717//GLMoleculeView::GLMoleculeView(QWidget *parent) :
718// QGLWidget(parent), Observer("GLMoleculeView"), X(Vector(1,0,0)), Y(Vector(0,1,0)), Z(Vector(0,0,1))
719//{
720// xRot = yRot = zRot = 0.0; // default object rotation
721// scale = 5.; // default object scale
722// object = 0;
723// LightPosition[0] = 0.0f;
724// LightPosition[1] = 2.0f;
725// LightPosition[2] = 2.0f;
726// LightPosition[3] = 0.0f;
727// LightDiffuse[0] = 0.5f;
728// LightDiffuse[1] = 0.5f;
729// LightDiffuse[2] = 0.5f;
730// LightDiffuse[3] = 0.0f;
731// LightAmbient[0] = 0.0f;
732// LightAmbient[1] = 0.0f;
733// LightAmbient[2] = 0.0f;
734// LightAmbient[3] = 0.0f;
735//
736// SelectionColor[0] = 0;
737// SelectionColor[1] = 128;
738// SelectionColor[2] = 128;
739//
740// MultiViewEnabled = true;
741//
742// isSignaller = false;
743//
744// World::getInstance().signOn(this);
745//}
746//
747///** Destructor of GLMoleculeView.
748// * Free's the CallList.
749// */
750//GLMoleculeView::~GLMoleculeView()
751//{
752// makeCurrent();
753// glDeleteLists( object, 1 );
754//
755// World::getInstance().signOff(this);
756//}
757//
758///** Paints the conents of the OpenGL window.
759// * Clears the GL buffers, enables lighting and depth.
760// * Window is either quartered (if GLMoleculeView::MultiViewEnabled) and xy, xz, yz planar views
761// * are added. Uses the CallList, constructed during InitializeGL().
762// */
763//void GLMoleculeView::paintGL()
764//{
765// Vector spot;
766//
767// glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
768// glShadeModel(GL_SMOOTH); // Enable Smooth Shading
769// glEnable(GL_LIGHTING); // Enable Light One
770// glEnable(GL_DEPTH_TEST); // Enables Depth Testing
771// glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
772// glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
773//
774// // 3d viewport
775// if (MultiViewEnabled)
776// glViewport( 0, 0, (GLint)width/2, (GLint)height/2 );
777// else
778// glViewport( 0, 0, (GLint)width, (GLint)height );
779// glMatrixMode( GL_PROJECTION );
780// glLoadIdentity();
781// glFrustum( -1.0, 1.0, -1.0, 1.0, 1.0, 50.0 );
782// glMatrixMode( GL_MODELVIEW );
783// glLoadIdentity();
784//
785// // calculate point of view and direction
786// glTranslated(position[0],position[1],position[2]);
787// glTranslated(0.0, 0.0, -scale);
788// glRotated(xRot, 1.0, 0.0, 0.0);
789// glRotated(yRot, 0.0, 1.0, 0.0);
790// glRotated(zRot, 0.0, 0.0, 1.0);
791//
792// // render scene
793// glCallList(object);
794//
795// // enable light
796// glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
797// glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
798// glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light
799// glEnable(GL_LIGHT1); // Enable Light One
800//
801// if (MultiViewEnabled) {
802// // xy view port
803// glViewport( (GLint)width/2, 0, (GLint)width/2, (GLint)height/2 );
804// glMatrixMode( GL_PROJECTION );
805// glLoadIdentity();
806// glScalef(1./scale, 1./scale,1./scale);
807// glOrtho(0, width/2, 0, height/2, 0,0);
808// glMatrixMode( GL_MODELVIEW );
809// glLoadIdentity();
810//
811// // calculate point of view and direction
812// view = position;
813// spot = Vector(0.,0.,scale);
814// top = Vector(0.,1.,0.);
815// gluLookAt(
816// spot[0], spot[1], spot[2],
817// view[0], view[1], view[2],
818// top[0], top[1], top[2]);
819//
820// // enable light
821// glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
822// glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
823// glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light
824// glEnable(GL_LIGHT1); // Enable Light One
825//
826// // render scene
827// glCallList(object);
828//
829// // xz viewport
830// glViewport( 0, (GLint)height/2, (GLint)width/2, (GLint)height/2 );
831// glMatrixMode( GL_PROJECTION );
832// glLoadIdentity();
833// glScalef(1./scale, 1./scale,1./scale);
834// glOrtho(0, width/2, 0, height/2, 0,0);
835// glMatrixMode( GL_MODELVIEW );
836// glLoadIdentity();
837//
838// // calculate point of view and direction
839// view = position;
840// spot = Vector(0.,scale,0.);
841// top = Vector(1.,0.,0.);
842// gluLookAt(
843// spot[0], spot[1], spot[2],
844// view[0], view[1], view[2],
845// top[0], top[1], top[2]);
846//
847// // enable light
848// glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
849// glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
850// glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light
851// glEnable(GL_LIGHT1); // Enable Light One
852//
853// // render scene
854// glCallList(object);
855//
856// //yz viewport
857// glViewport( (GLint)width/2, (GLint)height/2, (GLint)width/2, (GLint)height/2 );
858// glMatrixMode( GL_PROJECTION );
859// glLoadIdentity();
860// glScalef(1./scale, 1./scale,1./scale);
861// glOrtho(0, width/2, 0, height/2, 0,0);
862// glMatrixMode( GL_MODELVIEW );
863// glLoadIdentity();
864//
865// // calculate point of view and direction
866// view= position;
867// spot = Vector(scale,0.,0.);
868// top = Vector(0.,1.,0.);
869// gluLookAt(
870// spot[0], spot[1], spot[2],
871// view[0], view[1], view[2],
872// top[0], top[1], top[2]);
873//
874// // enable light
875// glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
876// glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
877// glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light
878// glEnable(GL_LIGHT1); // Enable Light One
879//
880// // render scene
881// glCallList(object);
882// }
883// //CoordinatesBar->setText( QString ("X: %1, Y: %2, Z: %3").arg(position[0]).arg(position[1]).arg(position[2]) );
884//}
885//
886////void polarView{GLdouble distance, GLdouble twist,
887//// GLdouble elevation, GLdouble azimuth)
888////{
889//// glTranslated(0.0, 0.0, -distance);
890//// glRotated(-twist, 0.0, 0.0, 1.0);
891//// glRotated(-elevation, 1.0, 0.0, 0.0);
892//// glRotated(azimuth, 0.0, 0.0, 1.0);
893////}
894//
895///** Make a sphere.
896// * \param x position
897// * \param radius radius
898// * \param color[3] color rgb values
899// */
900//void GLMoleculeView::makeSphere(const Vector &x, double radius, const unsigned char color[3])
901//{
902// float blueMaterial[] = { 255./(float)color[0], 255./(float)color[1], 255./(float)color[2], 1 }; // need to recast from [0,255] with integers into [0,1] with floats
903// GLUquadricObj* q = gluNewQuadric ();
904// gluQuadricOrientation(q, GLU_OUTSIDE);
905//
906// std::cout << "Setting sphere at " << x << " with color r"
907// << (int)color[0] << ",g" << (int)color[1] << ",b" << (int)color[2] << "." << endl;
908//
909// glPushMatrix();
910// glTranslatef( x[0], x[1], x[2]);
911//// glRotatef( xRot, 1.0, 0.0, 0.0);
912//// glRotatef( yRot, 0.0, 1.0, 0.0);
913//// glRotatef( zRot, 0.0, 0.0, 1.0);
914// glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blueMaterial);
915// gluSphere (q, (GLdouble)radius, 10, 10);
916// glPopMatrix();
917//}
918//
919///** Make a cylinder.
920// * \param x origin
921// * \param y direction
922// * \param radius thickness
923// * \param height length
924// * \color[3] color rgb values
925// */
926//void GLMoleculeView::makeCylinder(const Vector &x, const Vector &y, double radius, double height, const unsigned char color[3])
927//{
928// float blueMaterial[] = { 255./(float)color[0], 255./(float)color[1], 255./(float)color[2], 1 };
929// GLUquadricObj* q = gluNewQuadric ();
930// gluQuadricOrientation(q, GLU_OUTSIDE);
931// Vector a,b;
932// Vector OtherAxis;
933// double alpha;
934// a = x - y;
935// // construct rotation axis
936// b = a;
937// b.VectorProduct(Z);
938// Line axis(zeroVec, b);
939// // calculate rotation angle
940// alpha = a.Angle(Z);
941// // construct other axis to check right-hand rule
942// OtherAxis = b;
943// OtherAxis.VectorProduct(Z);
944// // assure right-hand rule for the rotation
945// if (a.ScalarProduct(OtherAxis) < MYEPSILON)
946// alpha = M_PI-alpha;
947// // check
948// Vector a_rotated = axis.rotateVector(a, alpha);
949// std::cout << "Setting cylinder from "// << x << " to " << y
950// << a << " to " << a_rotated << " around " << b << " by " << alpha/M_PI*180. << ", respectively, "
951// << " with color r"
952// << (int)color[0] << ",g" << (int)color[1] << ",b" << (int)color[2] << "." << endl;
953//
954// glPushMatrix();
955// glTranslatef( x[0], x[1], x[2]);
956// glRotatef( alpha/M_PI*180., b[0], b[1], b[2]);
957// glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blueMaterial);
958// gluCylinder (q, (GLdouble)radius, (GLdouble)radius, (GLdouble)height, 10, 10);
959// glPopMatrix();
960//}
961//
962///** Defines the display CallList.
963// * Goes through all molecules and their atoms and adds spheres for atoms and cylinders
964// * for bonds. Heeds GLMoleculeView::SelectedAtom and GLMoleculeView::SelectedMolecule.
965// */
966//void GLMoleculeView::initializeGL()
967//{
968// double x[3] = {-1, 0, -10};
969// unsigned char white[3] = {255,255,255};
970// Vector Position, OtherPosition;
971// QSize window = size();
972// width = window.width();
973// height = window.height();
974// std::cout << "Setting width to " << width << " and height to " << height << std::endl;
975// GLfloat shininess[] = { 0.0 };
976// GLfloat specular[] = { 0, 0, 0, 1 };
977// glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Let OpenGL clear to black
978// object = glGenLists(1);
979// glNewList( object, GL_COMPILE );
980// glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
981// glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
982//
983// const std::vector<molecule*> &molecules = World::getInstance().getAllMolecules();
984//
985// if (molecules.size() > 0) {
986// for (std::vector<molecule*>::const_iterator Runner = molecules.begin();
987// Runner != molecules.end();
988// Runner++) {
989// for (molecule::const_iterator atomiter = (*Runner)->begin();
990// atomiter != (*Runner)->end();
991// ++atomiter) {
992// // create atom
993// const element *ptr = (*atomiter)->getType();
994// boost::shared_ptr<Vector> MolCenter((*Runner)->DetermineCenterOfGravity());
995// Position = (*atomiter)->getPosition() - *MolCenter;
996// const unsigned char* color = NULL;
997// if ((World::getInstance().isSelected(*atomiter)) || (World::getInstance().isSelected((*Runner))))
998// color = SelectionColor;
999// else
1000// color = ptr->getColor();
1001// makeSphere(Position, ptr->getVanDerWaalsRadius()*0.25, color);
1002//
1003// // create bonds
1004// const BondList &bonds = (*atomiter)->getListOfBonds();
1005// for (BondList::const_iterator bonditer = bonds.begin();
1006// bonditer != bonds.end();
1007// ++bonditer) {
1008// if ((*bonditer)->leftatom->getId() == (*atomiter)->getId()) {
1009// Position = (*bonditer)->leftatom->getPosition() - *MolCenter;
1010// OtherPosition = (*bonditer)->rightatom->getPosition() - *MolCenter;
1011// const double distance = sqrt(Position.DistanceSquared(OtherPosition))/2.;
1012// const unsigned char *color1 = (*bonditer)->leftatom->getType()->getColor();
1013// const unsigned char *color2 = (*bonditer)->rightatom->getType()->getColor();
1014// makeCylinder(Position, OtherPosition, 0.1, distance, color1);
1015// makeCylinder(OtherPosition, Position, 0.1, distance, color2);
1016// }
1017// }
1018// }
1019// }
1020// } else {
1021// makeSphere( x,1, white);
1022// }
1023// glEndList();
1024//}
1025//
1026//
1027///* ================================== SLOTS ============================== */
1028//
1029///** Initializes some public variables.
1030// * \param *ptr pointer to QLabel statusbar
1031// */
1032//void GLMoleculeView::init(QLabel *ptr)
1033//{
1034// StatusBar = ptr;
1035//}
1036//
1037///** Initializes the viewport statusbar.
1038// * \param *ptr pointer to QLabel for showing view pointcoordinates.
1039// */
1040//void GLMoleculeView::initCoordinates(QLabel *ptr)
1041//{
1042// CoordinatesBar = ptr;
1043//}
1044//
1045///** Slot to be called when to initialize GLMoleculeView::MolData.
1046// */
1047//void GLMoleculeView::createView( )
1048//{
1049// initializeGL();
1050// updateGL();
1051//}
1052//
1053///** Slot of window is resized.
1054// * Copies new width and height to GLMoleculeView::width and GLMoleculeView::height and calls updateGL().
1055// * \param w new width of window
1056// * \param h new height of window
1057// */
1058//void GLMoleculeView::resizeGL( int w, int h )
1059//{
1060// width = w;
1061// height = h;
1062// updateGL();
1063//}
1064//
1065///** Sets x rotation angle.
1066// * sets GLMoleculeView::xRot and calls updateGL().
1067// * \param degrees new rotation angle in degrees
1068// */
1069//void GLMoleculeView::setXRotation( int degrees )
1070//{
1071// xRot = (GLfloat)(degrees % 360);
1072// updateGL();
1073//}
1074//
1075//
1076///** Sets y rotation angle.
1077// * sets GLMoleculeView::yRot and calls updateGL().
1078// * \param degrees new rotation angle in degrees
1079// */
1080//void GLMoleculeView::setYRotation( int degrees )
1081//{
1082// yRot = (GLfloat)(degrees % 360);
1083// updateGL();
1084//}
1085//
1086//
1087///** Sets z rotation angle.
1088// * sets GLMoleculeView::zRot and calls updateGL().
1089// * \param degrees new rotation angle in degrees
1090// */
1091//void GLMoleculeView::setZRotation( int degrees )
1092//{
1093// zRot = (GLfloat)(degrees % 360);
1094// updateGL();
1095//}
1096//
1097///** Sets the scale of the scene.
1098// * sets GLMoleculeView::scale and calls updateGL().
1099// * \param distance distance divided by 100 is the new scale
1100// */
1101//void GLMoleculeView::setScale( int distance )
1102//{
1103// scale = (GLfloat)(distance / 100.);
1104// updateGL();
1105//}
1106//
1107///** Update the ambient light.
1108// * \param light[4] light strength per axis and position (w)
1109// */
1110//void GLMoleculeView::setLightAmbient( int *light )
1111//{
1112// for(int i=0;i<4;i++)
1113// LightAmbient[i] = light[i];
1114// updateGL();
1115//}
1116//
1117///** Update the diffuse light.
1118// * \param light[4] light strength per axis and position (w)
1119// */
1120//void GLMoleculeView::setLightDiffuse( int *light )
1121//{
1122// for(int i=0;i<4;i++)
1123// LightDiffuse[i] = light[i];
1124// updateGL();
1125//}
1126//
1127///** Update the position of light.
1128// * \param light[4] light strength per axis and position (w)
1129// */
1130//void GLMoleculeView::setLightPosition( int *light )
1131//{
1132// for(int i=0;i<4;i++)
1133// LightPosition[i] = light[i];
1134// updateGL();
1135//}
1136//
1137///** Toggles the boolean GLMoleculeView::MultiViewEnabled.
1138// * Flips the boolean and calls updateGL().
1139// */
1140//void GLMoleculeView::toggleMultiViewEnabled ( )
1141//{
1142// MultiViewEnabled = !MultiViewEnabled;
1143// cout << "Setting MultiView to " << MultiViewEnabled << "." << endl;
1144// updateGL();
1145//}
1146//
1147///** Launch a dialog to configure the lights.
1148// */
1149//void GLMoleculeView::createDialogLight()
1150//{
1151//// Ui_DialogLight *Lights = new Ui_DialogLight();
1152//// if (Lights == NULL)
1153//// return;
1154//// // Set up the dynamic dialog here
1155//// QLineEdit *Field = NULL;
1156//// Field = Lights->findChild<QLineEdit *>("LightPositionX");
1157//// if (Field) Field->setText( QString("%1").arg(LightPosition[0]) );
1158//// Field = Lights->findChild<QLineEdit *>("LightPositionY");
1159//// if (Field) Field->setText( QString("%1").arg(LightPosition[1]) );
1160//// Field = Lights->findChild<QLineEdit *>("LightPositionZ");
1161//// if (Field) Field->setText( QString("%1").arg(LightPosition[2]) );
1162//// Field = Lights->findChild<QLineEdit *>("LightPositionW");
1163//// if (Field) Field->setText( QString("%1").arg(LightPosition[3]) );
1164////
1165//// Field = Lights->findChild<QLineEdit *>("LightDiffuseX");
1166//// if (Field) Field->setText( QString("%1").arg(LightDiffuse[0]) );
1167//// Field = Lights->findChild<QLineEdit *>("LightDiffuseY");
1168//// if (Field) Field->setText( QString("%1").arg(LightDiffuse[1]) );
1169//// Field = Lights->findChild<QLineEdit *>("LightDiffuseZ");
1170//// if (Field) Field->setText( QString("%1").arg(LightDiffuse[2]) );
1171//// Field = Lights->findChild<QLineEdit *>("LightDiffuseW");
1172//// if (Field) Field->setText( QString("%1").arg(LightDiffuse[3]) );
1173////
1174//// Field = Lights->findChild<QLineEdit *>("LightAmbientX");
1175//// if (Field) Field->setText( QString("%1").arg(LightAmbient[0]) );
1176//// Field = Lights->findChild<QLineEdit *>("LightAmbientY");
1177//// if (Field) Field->setText( QString("%1").arg(LightAmbient[1]) );
1178//// Field = Lights->findChild<QLineEdit *>("LightAmbientZ");
1179//// if (Field) Field->setText( QString("%1").arg(LightAmbient[2]) );
1180//// Field = Lights->findChild<QLineEdit *>("LightAmbientW");
1181//// if (Field) Field->setText( QString("%1").arg(LightAmbient[3]) );
1182////
1183//// if ( Lights->exec() ) {
1184//// //cout << "User accepted.\n";
1185//// // The user accepted, act accordingly
1186//// Field = Lights->findChild<QLineEdit *>("LightPositionX");
1187//// if (Field) LightPosition[0] = Field->text().toDouble();
1188//// Field = Lights->findChild<QLineEdit *>("LightPositionY");
1189//// if (Field) LightPosition[1] = Field->text().toDouble();
1190//// Field = Lights->findChild<QLineEdit *>("LightPositionZ");
1191//// if (Field) LightPosition[2] = Field->text().toDouble();
1192//// Field = Lights->findChild<QLineEdit *>("LightPositionW");
1193//// if (Field) LightPosition[3] = Field->text().toDouble();
1194////
1195//// Field = Lights->findChild<QLineEdit *>("LightDiffuseX");
1196//// if (Field) LightDiffuse[0] = Field->text().toDouble();
1197//// Field = Lights->findChild<QLineEdit *>("LightDiffuseY");
1198//// if (Field) LightDiffuse[1] = Field->text().toDouble();
1199//// Field = Lights->findChild<QLineEdit *>("LightDiffuseZ");
1200//// if (Field) LightDiffuse[2] = Field->text().toDouble();
1201//// Field = Lights->findChild<QLineEdit *>("LightDiffuseW");
1202//// if (Field) LightDiffuse[3] = Field->text().toDouble();
1203////
1204//// Field = Lights->findChild<QLineEdit *>("LightAmbientX");
1205//// if (Field) LightAmbient[0] = Field->text().toDouble();
1206//// Field = Lights->findChild<QLineEdit *>("LightAmbientY");
1207//// if (Field) LightAmbient[1] = Field->text().toDouble();
1208//// Field = Lights->findChild<QLineEdit *>("LightAmbientZ");
1209//// if (Field) LightAmbient[2] = Field->text().toDouble();
1210//// Field = Lights->findChild<QLineEdit *>("LightAmbientW");
1211//// if (Field) LightAmbient[3] = Field->text().toDouble();
1212//// updateGL();
1213//// } else {
1214//// //cout << "User reclined.\n";
1215//// }
1216//// delete(Lights);
1217//}
1218//
1219///** Slot for event of pressed mouse button.
1220// * Switch discerns between buttons and stores position of event in GLMoleculeView::LeftButtonPos,
1221// * GLMoleculeView::MiddleButtonPos or GLMoleculeView::RightButtonPos.
1222// * \param *event structure containing information of the event
1223// */
1224//void GLMoleculeView::mousePressEvent(QMouseEvent *event)
1225//{
1226// std::cout << "MousePressEvent." << endl;
1227// QPoint *pos = NULL;
1228// switch (event->button()) { // get the right array
1229// case Qt::LeftButton:
1230// pos = &LeftButtonPos;
1231// std::cout << "Left Button" << endl;
1232// break;
1233// case Qt::MidButton:
1234// pos = &MiddleButtonPos;
1235// std::cout << "Middle Button" << endl;
1236// break;
1237// case Qt::RightButton:
1238// pos = &RightButtonPos;
1239// std::cout << "Right Button" << endl;
1240// break;
1241// default:
1242// break;
1243// }
1244// if (pos) { // store the position
1245// pos->setX(event->pos().x());
1246// pos->setY(event->pos().y());
1247// std::cout << "Stored src position is (" << pos->x() << "," << pos->y() << ")." << endl;
1248// } else {
1249// std::cout << "pos is NULL." << endl;
1250// }
1251//}
1252//
1253///** Slot for event of pressed mouse button.
1254// * Switch discerns between buttons:
1255// * -# Left Button: Rotates the view of the GLMoleculeView, relative to GLMoleculeView::LeftButtonPos.
1256// * -# Middle Button: nothing
1257// * -# Right Button: Shifts the selected molecule or atom, relative to GLMoleculeView::RightButtonPos.
1258// * \param *event structure containing information of the event
1259// */
1260//void GLMoleculeView::mouseReleaseEvent(QMouseEvent *event)
1261//{
1262// std::cout << "MouseReleaseEvent." << endl;
1263// QPoint *srcpos = NULL;
1264// QPoint destpos = event->pos();
1265// int Width = (MultiViewEnabled) ? width/2 : width;
1266// int Height = (MultiViewEnabled) ? height/2 : height;
1267// std::cout << "Received dest position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
1268// switch (event->button()) { // get the right array
1269// case Qt::LeftButton: // LeftButton rotates the view
1270// srcpos = &LeftButtonPos;
1271// std::cout << "Left Button" << endl;
1272// if (srcpos) { // subtract the position and act
1273// std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl;
1274// destpos -= *srcpos;
1275// std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
1276// std::cout << "Width and Height are " << Width << "," << Height << "." << endl;
1277//
1278// int pos = (int)floor((double)srcpos->x()/(double)Width) + ((int)floor((double)srcpos->y()/(double)Height))*2;
1279// if ((MultiViewEnabled) && (pos != 2)) { // means four regions, and we are in a shifting one
1280// // switch between three regions
1281// // decide into which of the four screens the initial click has been made
1282// std::cout << "Position is " << pos << "." << endl;
1283// switch(pos) {
1284// case 0: // lower left = xz
1285// position[0] += -destpos.y()/100.;
1286// position[2] += destpos.x()/100.;
1287// break;
1288// case 1: // lower right = yz
1289// position[1] += -destpos.y()/100.;
1290// position[2] += -destpos.x()/100.;
1291// break;
1292// case 2: // upper left = projected
1293// std::cout << "This is impossible: Shifting in the projected region, we should rotate!." << endl;
1294// break;
1295// case 3: // upper right = xy
1296// position[0] += destpos.x()/100.;
1297// position[1] += -destpos.y()/100.;
1298// break;
1299// default:
1300// std::cout << "click was not in any of the four regions." << endl;
1301// break;
1302// }
1303// updateGL();
1304// } else { // we are in rotation region
1305// QWidget *Parent = parentWidget();
1306// QSlider *sliderX = Parent->findChild<QSlider *>("sliderX");
1307// QSlider *sliderY = Parent->findChild<QSlider *>("sliderY");
1308// std::cout << sliderX << " and " << sliderY << endl;
1309// if (sliderX) {
1310// int xrange = sliderX->maximum() - sliderX->minimum();
1311// double xValue = ((destpos.x() + Width) % Width);
1312// xValue *= (double)xrange/(double)Width;
1313// xValue += sliderX->value();
1314// int xvalue = (int) xValue % xrange;
1315// std::cout << "Setting x to " << xvalue << " within range " << xrange << "." << endl;
1316// setXRotation(xvalue);
1317// sliderX->setValue(xvalue);
1318// } else {
1319// std::cout << "sliderX is NULL." << endl;
1320// }
1321// if (sliderY) {
1322// int yrange = sliderY->maximum() - sliderY->minimum();
1323// double yValue = ((destpos.y() + Height) % Height);
1324// yValue *= (double)yrange/(double)Height;
1325// yValue += sliderY->value();
1326// int yvalue = (int) yValue % yrange;
1327// std::cout << "Setting y to " << yvalue << " within range " << yrange << "." << endl;
1328// setYRotation(yvalue);
1329// sliderY->setValue(yvalue);
1330// } else {
1331// std::cout << "sliderY is NULL." << endl;
1332// }
1333// }
1334// } else {
1335// std::cout << "srcpos is NULL." << endl;
1336// }
1337// break;
1338//
1339// case Qt::MidButton: // MiddleButton has no function so far
1340// srcpos = &MiddleButtonPos;
1341// std::cout << "Middle Button" << endl;
1342// if (srcpos) { // subtract the position and act
1343// QWidget *Parent = parentWidget();
1344// QSlider *sliderZ = Parent->findChild<QSlider *>("sliderZ");
1345// QSlider *sliderScale = Parent->findChild<QSlider *>("sliderScale");
1346// std::cout << sliderZ << " and " << sliderScale << endl;
1347// std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl;
1348// destpos -= *srcpos;
1349// std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
1350// std::cout << "Width and Height are " << Width << "," << Height << "." << endl;
1351// if (sliderZ) {
1352// int xrange = sliderZ->maximum() - sliderZ->minimum();
1353// double xValue = ((destpos.x() + Width) % Width);
1354// xValue *= (double)xrange/(double)Width;
1355// xValue += sliderZ->value();
1356// int xvalue = (int) xValue % xrange;
1357// std::cout << "Setting x to " << xvalue << " within range " << xrange << "." << endl;
1358// setZRotation(xvalue);
1359// sliderZ->setValue(xvalue);
1360// } else {
1361// std::cout << "sliderZ is NULL." << endl;
1362// }
1363// if (sliderScale) {
1364// int yrange = sliderScale->maximum() - sliderScale->minimum();
1365// double yValue = ((destpos.y() + Height) % Height);
1366// yValue *= (double)yrange/(double)Height;
1367// yValue += sliderScale->value();
1368// int yvalue = (int) yValue % yrange;
1369// std::cout << "Setting y to " << yvalue << " within range " << yrange << "." << endl;
1370// setScale(yvalue);
1371// sliderScale->setValue(yvalue);
1372// } else {
1373// std::cout << "sliderScale is NULL." << endl;
1374// }
1375// } else {
1376// std::cout << "srcpos is NULL." << endl;
1377// }
1378// break;
1379// break;
1380//
1381// case Qt::RightButton: // RightButton moves eitstdher the selected molecule or atom
1382// srcpos = &RightButtonPos;
1383// std::cout << "Right Button" << endl;
1384// if (srcpos) { // subtract the position and act
1385// std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl;
1386// destpos -= *srcpos;
1387// std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
1388// std::cout << "Width and Height are " << Width << "," << Height << "." << endl;
1389// if (MultiViewEnabled) {
1390// // which vector to change
1391// Vector SelectedPosition;
1392// const std::vector<atom*> &SelectedAtoms = World::getInstance().getSelectedAtoms();
1393// const std::vector<molecule*> &SelectedMolecules = World::getInstance().getSelectedMolecules();
1394// if (SelectedMolecules.size()) {
1395// if (SelectedAtoms.size())
1396// SelectedPosition = (*SelectedAtoms.begin())->getPosition();
1397// else
1398// SelectedPosition = (*(*SelectedMolecules.begin())->begin())->getPosition();
1399// }
1400// // decide into which of the four screens the initial click has been made
1401// int pos = (int)floor((double)srcpos->x()/(double)Width) + ((int)floor((double)srcpos->y()/(double)Height))*2;
1402// if (!SelectedPosition.IsZero()) {
1403// std::cout << "Position is " << pos << "." << endl;
1404// switch(pos) {
1405// case 0: // lower left = xz
1406// SelectedPosition[0] += -destpos.y()/100.;
1407// SelectedPosition[2] += destpos.x()/100.;
1408// break;
1409// case 1: // lower right = yz
1410// SelectedPosition[1] += -destpos.y()/100.;
1411// SelectedPosition[2] += -destpos.x()/100.;
1412// break;
1413// case 2: // upper left = projected
1414// SelectedPosition[0] += destpos.x()/100.;
1415// SelectedPosition[1] += destpos.y()/100.;
1416// SelectedPosition[2] += destpos.y()/100.;
1417// break;
1418// case 3: // upper right = xy
1419// SelectedPosition[0] += destpos.x()/100.;
1420// SelectedPosition[1] += -destpos.y()/100.;
1421// break;
1422// default:
1423// std::cout << "click was not in any of the four regions." << endl;
1424// break;
1425// }
1426// } else {
1427// std::cout << "Nothing selected." << endl;
1428// }
1429// // update Tables
1430// if (SelectedMolecules.size()) {
1431// isSignaller = true;
1432// if (SelectedAtoms.size())
1433// emit notifyAtomChanged( (*SelectedMolecules.begin()), (*SelectedAtoms.begin()), AtomPosition);
1434// else
1435// emit notifyMoleculeChanged( (*SelectedMolecules.begin()), MoleculePosition );
1436// }
1437// // update graphic
1438// initializeGL();
1439// updateGL();
1440// } else {
1441// cout << "MultiView is not enabled." << endl;
1442// }
1443// } else {
1444// cout << "srcpos is NULL." << endl;
1445// }
1446// break;
1447//
1448// default:
1449// break;
1450// }
1451//}
1452//
1453///* ======================================== SLOTS ================================ */
1454//
1455///** Hear announcement of selected molecule.
1456// * \param *mol pointer to selected molecule
1457// */
1458//void GLMoleculeView::hearMoleculeSelected(molecule *mol)
1459//{
1460// if (isSignaller) { // if we emitted the signal, return
1461// isSignaller = false;
1462// return;
1463// }
1464// initializeGL();
1465// updateGL();
1466//};
1467//
1468///** Hear announcement of selected atom.
1469// * \param *mol pointer to molecule containing atom
1470// * \param *Walker pointer to selected atom
1471// */
1472//void GLMoleculeView::hearAtomSelected(molecule *mol, atom *Walker)
1473//{
1474// if (isSignaller) { // if we emitted the signal, return
1475// isSignaller = false;
1476// return;
1477// }
1478// initializeGL();
1479// updateGL();
1480//};
1481//
1482///** Hear announcement of changed molecule.
1483// * \param *mol pointer to changed molecule
1484// * \param type of change
1485// */
1486//void GLMoleculeView::hearMoleculeChanged(molecule *mol, enum ChangesinMolecule type)
1487//{
1488// if (isSignaller) { // if we emitted the signal, return
1489// isSignaller = false;
1490// return;
1491// }
1492// initializeGL();
1493// updateGL();
1494//};
1495//
1496///** Hear announcement of changed atom.
1497// * \param *mol pointer to molecule containing atom
1498// * \param *Walker pointer to changed atom
1499// * \param type type of change
1500// */
1501//void GLMoleculeView::hearAtomChanged(molecule *mol, atom *Walker, enum ChangesinAtom type)
1502//{
1503// if (isSignaller) { // if we emitted the signal, return
1504// isSignaller = false;
1505// return;
1506// }
1507// initializeGL();
1508// updateGL();
1509//};
1510//
1511///** Hear announcement of changed element.
1512// * \param *Runner pointer to changed element
1513// * \param type of change
1514// */
1515//void GLMoleculeView::hearElementChanged(element *Runner, enum ChangesinElement type)
1516//{
1517// if (isSignaller) { // if we emitted the signal, return
1518// isSignaller = false;
1519// return;
1520// }
1521// switch(type) {
1522// default:
1523// case ElementName:
1524// case ElementSymbol:
1525// case ElementMass:
1526// case ElementValence:
1527// case ElementZ:
1528// break;
1529// case ElementCovalent:
1530// case ElementVanderWaals:
1531// initializeGL();
1532// updateGL();
1533// break;
1534// }
1535//};
1536//
1537///** Hear announcement of added molecule.
1538// * \param *mol pointer to added molecule
1539// */
1540//void GLMoleculeView::hearMoleculeAdded(molecule *mol)
1541//{
1542// if (isSignaller) { // if we emitted the signal, return
1543// isSignaller = false;
1544// return;
1545// }
1546// initializeGL();
1547// updateGL();
1548//};
1549//
1550///** Hear announcement of added atom.
1551// * \param *mol pointer to molecule containing atom
1552// * \param *Walker pointer to added atom
1553// */
1554//void GLMoleculeView::hearAtomAdded(molecule *mol, atom *Walker)
1555//{
1556// if (isSignaller) { // if we emitted the signal, return
1557// isSignaller = false;
1558// return;
1559// }
1560// initializeGL();
1561// updateGL();
1562//};
1563//
1564///** Hear announcement of removed molecule.
1565// * \param *mol pointer to removed molecule
1566// */
1567//void GLMoleculeView::hearMoleculeRemoved(molecule *mol)
1568//{
1569// if (isSignaller) { // if we emitted the signal, return
1570// isSignaller = false;
1571// return;
1572// }
1573// initializeGL();
1574// updateGL();
1575//};
1576//
1577///** Hear announcement of removed atom.
1578// * \param *mol pointer to molecule containing atom
1579// * \param *Walker pointer to removed atom
1580// */
1581//void GLMoleculeView::hearAtomRemoved(molecule *mol, atom *Walker)
1582//{
1583// if (isSignaller) { // if we emitted the signal, return
1584// isSignaller = false;
1585// return;
1586// }
1587// initializeGL();
1588// updateGL();
1589//};
1590//
1591//void GLMoleculeView::update(Observable *publisher)
1592//{
1593// initializeGL();
1594// updateGL();
1595//}
1596//
1597///**
1598// * This method is called when a special named change
1599// * of the Observable occured
1600// */
1601//void GLMoleculeView::recieveNotification(Observable *publisher, Notification_ptr notification)
1602//{
1603// initializeGL();
1604// updateGL();
1605//}
1606//
1607///**
1608// * This method is called when the observed object is destroyed.
1609// */
1610//void GLMoleculeView::subjectKilled(Observable *publisher)
1611//{
1612//
1613//}
1614//
1615//
1616//// new stuff
1617//
1618///** Returns the ref to the Material for element No \a from the map.
1619// *
1620// * \note We create a new one if the element is missing.
1621// *
1622// * @param no element no
1623// * @return ref to QGLMaterial
1624// */
1625//QGLMaterial* GLMoleculeView::getMaterial(size_t no)
1626//{
1627// if (ElementNoMaterialMap.find(no) != ElementNoMaterialMap.end()){
1628// // get present one
1629//
1630// } else {
1631// ASSERT( (no >= 0) && (no < MAX_ELEMENTS),
1632// "GLMoleculeView::getMaterial() - Element no "+toString(no)+" is invalid.");
1633// // create new one
1634// LOG(1, "Creating new material for element "+toString(no)+".");
1635// QGLMaterial *newmaterial = new QGLMaterial(this);
1636// periodentafel *periode = World::getInstance().getPeriode();
1637// element *desiredelement = periode->FindElement(no);
1638// ASSERT(desiredelement != NULL,
1639// "GLMoleculeView::getMaterial() - desired element "+toString(no)+" not present in periodentafel.");
1640// const unsigned char* color = desiredelement->getColor();
1641// newmaterial->setAmbientColor( QColor(color[0], color[1], color[2]) );
1642// newmaterial->setSpecularColor( QColor(60, 60, 60) );
1643// newmaterial->setShininess( QColor(128) );
1644// ElementNoMaterialMap.insert( no, newmaterial);
1645// }
1646//}
1647//
1648//QGLSceneNode* GLMoleculeView::getAtom(size_t no)
1649//{
1650// // first some sensibility checks
1651// ASSERT(World::getInstance().getAtom(AtomById(no)) != NULL,
1652// "GLMoleculeView::getAtom() - desired atom "
1653// +toString(no)+" not present in the World.");
1654// ASSERT(AtomsinSceneMap.find(no) != AtomsinSceneMap.end(),
1655// "GLMoleculeView::getAtom() - desired atom "
1656// +toString(no)+" not present in the AtomsinSceneMap.");
1657//
1658// return AtomsinSceneMap[no];
1659//}
1660//
1661//QGLSceneNode* GLMoleculeView::getBond(size_t leftno, size_t rightno)
1662//{
1663// // first some sensibility checks
1664// ASSERT(World::getInstance().getAtom(AtomById(leftno)) != NULL,
1665// "GLMoleculeView::getAtom() - desired atom "
1666// +toString(leftno)+" of bond not present in the World.");
1667// ASSERT(World::getInstance().getAtom(AtomById(rightno)) != NULL,
1668// "GLMoleculeView::getAtom() - desired atom "
1669// +toString(rightno)+" of bond not present in the World.");
1670// ASSERT(AtomsinSceneMap.find(leftno) != AtomsinSceneMap.end(),
1671// "GLMoleculeView::getAtom() - desired atom "
1672// +toString(leftno)+" of bond not present in the AtomsinSceneMap.");
1673// ASSERT(AtomsinSceneMap.find(rightno) != AtomsinSceneMap.end(),
1674// "GLMoleculeView::getAtom() - desired atom "
1675// +toString(rightno)+" of bond not present in the AtomsinSceneMap.");
1676// ASSERT(leftno == rightno,
1677// "GLMoleculeView::getAtom() - bond must not be between the same atom: "
1678// +toString(leftno)+" == "+toString(rightno)+".");
1679//
1680// // then return with smaller index first
1681// if (leftno > rightno)
1682// return AtomsinSceneMap[ make_pair(rightno, leftno) ];
1683// else
1684// return AtomsinSceneMap[ make_pair(leftno, rightno) ];
1685//}
1686//
Note: See TracBrowser for help on using the repository browser.