5 * Created by Toshi Nagata on 08/10/24.
6 * Copyright 2008 Toshi Nagata. All rights reserved.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation version 2 of the License.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
18 // For compilers that support precompilation, includes "wx/wx.h".
19 #include "wx/wxprec.h"
29 #if !wxUSE_DOC_VIEW_ARCHITECTURE
30 #error "You should have DocView architecture enabled in your wxWidgets installation."
33 #include "MoleculeView.h"
36 #include "MyDocument.h"
37 #include "MyGLCanvas.h"
38 #include "MyCommand.h"
40 #include "MyListCtrl.h"
41 #include "../MolLib/Missing.h"
43 #include "wx/tglbtn.h"
44 #include "wx/listctrl.h"
45 #include "wx/splitter.h"
46 #include "wx/choice.h"
49 //#include "../MolLib/Ruby_bind/Molby_extern.h"
58 myID_RotateBondSlider,
61 myID_FrameControlPanel,
63 myID_JumpToStartButton,
64 myID_PlayBackwardButton,
66 myID_PlayForwardButton,
72 IMPLEMENT_DYNAMIC_CLASS(MoleculeView, wxView)
74 BEGIN_EVENT_TABLE(MoleculeView, wxView)
75 EVT_TOGGLEBUTTON(myID_RotButton, MoleculeView::OnButtonPressed)
76 EVT_TOGGLEBUTTON(myID_TransButton, MoleculeView::OnButtonPressed)
77 EVT_TOGGLEBUTTON(myID_ScaleButton, MoleculeView::OnButtonPressed)
78 EVT_TOGGLEBUTTON(myID_SelectButton, MoleculeView::OnButtonPressed)
79 EVT_TOGGLEBUTTON(myID_BondButton, MoleculeView::OnButtonPressed)
80 EVT_TOGGLEBUTTON(myID_EraseButton, MoleculeView::OnButtonPressed)
81 EVT_COMMAND(wxID_ANY, MySliderEvent, MoleculeView::OnSliderAction)
82 EVT_COMMAND_SCROLL(myID_FrameSlider, MoleculeView::OnFrameSliderAction)
83 EVT_TEXT_ENTER(myID_FrameText, MoleculeView::OnFrameTextAction)
84 EVT_CHOICE(myID_TableMenu, MoleculeView::OnSelectTable)
85 EVT_ACTIVATE(MoleculeView::OnActivate)
87 #define ConnectMouseDownEvents(src, func, target) \
88 (src->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(func), NULL, target), \
89 src->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(func), NULL, target))
93 MoleculeView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
97 // Make a document frame
98 frame = new wxDocMDIChildFrame(doc, this, GetMainFrame(), wxID_ANY, _T("New Molby Document"),
99 wxPoint(10, 24), wxSize(680, 400),
100 wxDEFAULT_FRAME_STYLE |
101 wxNO_FULL_REPAINT_ON_RESIZE);
107 file_history_menu = NULL;
109 memset(tbuttons, 0, sizeof(tbuttons));
111 frameControlPanel = NULL;
114 isRebuildingTable = false;
116 wxMenuBar *menu_bar = wxGetApp().CreateMenuBar(1, &file_history_menu, &edit_menu);
118 // Associate the menu bar with the frame
119 frame->SetMenuBar(menu_bar);
121 // Associate the edit menu with the command processor
122 doc->GetCommandProcessor()->SetEditMenu(edit_menu);
124 mview = MainView_newMainView(this);
126 // Create the window content
128 // A splitter window embraces a grid (left) and main screen (right)
129 wxSplitterWindow *splitter = new wxSplitterWindow(frame, -1, wxDefaultPosition, wxDefaultSize, wxSP_3D | wxSP_LIVE_UPDATE);
131 // Create the left half
132 // A panel containing a popup menu and a list window
133 wxPanel *panel0 = new wxPanel(splitter);
137 sizer0 = new wxBoxSizer(wxVERTICAL);
138 wxArrayString choiceItems;
140 MainView_tableTitleForIndex(mview, i, buf, sizeof buf);
143 wxString itemTitle(buf, wxConvUTF8);
144 choiceItems.Add(itemTitle);
146 /* static wxString choiceItems[] = {
147 wxT("atoms"), wxT("bonds"), wxT("angles"), wxT("dihedrals"), wxT("impropers"), wxT("MO info")
150 listmenu = new wxChoice(panel0, myID_TableMenu, wxDefaultPosition, wxDefaultSize, choiceItems);
151 sizer0->Add(listmenu, 0, wxALL, 0);
153 listctrl = new MyListCtrl();
154 listctrl->Create(panel0, myID_Table, wxDefaultPosition, wxDefaultSize);
155 sizer0->Add(listctrl, 1, wxALL | wxEXPAND, 0);
156 panel0->SetSizer(sizer0);
159 // Create the right half
160 // A panel containing MyGLCanvas, buttons, sliders, etc.
161 wxPanel *panel1 = new wxPanel(splitter);
163 { // Vertical sizer containing [sizer2, sizer3, sizer4]
165 sizer1 = new wxBoxSizer(wxVERTICAL);
167 { // Horizontal sizer containing [button0, button1, ..., button5, infotext]
169 sizer2 = new wxBoxSizer(wxHORIZONTAL);
171 { // Button0..5 (Rot/Trans/Scale/Select/Bond/Erase)
172 wxString labels[] = {
173 wxT("Rot"), wxT("Trans"), wxT("Scale"), wxT("Select"), wxT("Bond"), wxT("Erase")
176 myID_RotButton, myID_TransButton, myID_ScaleButton,
177 myID_SelectButton, myID_BondButton, myID_EraseButton
179 for (i = 0; i < 6; i++) {
180 tbuttons[i] = new wxToggleButton(panel1, ids[i], labels[i], wxDefaultPosition, wxSize(40, 16));
181 sizer2->Add(tbuttons[i], 0, wxALL | wxEXPAND, 3);
183 tbuttons[0]->SetValue(true);
185 { // Information text
186 infotext = new wxStaticText(panel1, -1, wxT(""), wxDefaultPosition, wxSize(40, 16), wxST_NO_AUTORESIZE | wxBORDER_SUNKEN);
187 infotext->SetMinSize(wxSize(80, 32));
188 infotext->SetFont(*wxSMALL_FONT);
189 sizer2->Add(infotext, 1, wxALL | wxEXPAND, 3); // Can expand horizontally
192 sizer1->Add(sizer2, 0, wxALL | wxEXPAND, 0);
195 { // Horizontal sizer containing [sizer31, sizer32, sizer33]
196 wxBoxSizer *sizer3 = new wxBoxSizer(wxHORIZONTAL);
198 { // Vertical sizer containing [button, mySlider]
199 wxBoxSizer *sizer31 = new wxBoxSizer(wxVERTICAL);
200 { // "Rotate bond" button and mySlider
201 #include "../bitmaps/rotate_bond.xpm"
202 wxBitmap bmp1(rotate_bond_xpm, wxBITMAP_TYPE_XPM);
203 wxBitmapButton *button1 = new wxBitmapButton(panel1, -1, bmp1, wxDefaultPosition, wxSize(21, 21));
204 sizer31->Add(button1, 0, 0, 0);
206 MySlider *slider1 = new MySlider(panel1, myID_RotateBondSlider, wxVERTICAL, wxDefaultPosition, wxSize(21, 21));
207 sizer31->Add(slider1, 1, wxEXPAND);
209 sizer3->Add(sizer31, 0, wxALL | wxEXPAND, 0);
212 { // Vertical sizer containing [Canvas, [button, mySlider]]
213 wxBoxSizer *sizer32 = new wxBoxSizer(wxVERTICAL);
215 canvas = new MyGLCanvas(this, panel1, wxDefaultPosition, wxSize(100, 100));
216 sizer32->Add(canvas, 1, wxALL | wxEXPAND, 0);
218 // Let the MyGLCanvas pass the keyboard event to this
219 canvas->Connect(-1, wxEVT_CHAR, wxKeyEventHandler(MoleculeView::OnChar), NULL, this);
222 wxBoxSizer *sizer321 = new wxBoxSizer(wxHORIZONTAL);
224 #include "../bitmaps/rotate_y.xpm"
225 wxBitmap bmp2(rotate_y_xpm, wxBITMAP_TYPE_XPM);
226 wxBitmapButton *button2 = new wxBitmapButton(panel1, -1, bmp2, wxDefaultPosition, wxSize(21, 21));
227 sizer321->Add(button2, 0, 0, 0);
229 MySlider *slider2 = new MySlider(panel1, myID_RotateYSlider, wxHORIZONTAL, wxDefaultPosition, wxSize(21, 21));
230 sizer321->Add(slider2, 1, wxEXPAND);
232 sizer32->Add(sizer321, 0, wxEXPAND);
234 sizer3->Add(sizer32, 1, wxEXPAND);
237 { // Vertical sizer containing [button, mySlider]
238 wxBoxSizer *sizer33 = new wxBoxSizer(wxVERTICAL);
239 { // "Rotate bond" button and mySlider
240 #include "../bitmaps/rotate_x.xpm"
241 wxBitmap bmp3(rotate_x_xpm, wxBITMAP_TYPE_XPM);
242 wxBitmapButton *button3 = new wxBitmapButton(panel1, -1, bmp3, wxDefaultPosition, wxSize(21, 21));
244 sizer33->Add(button3, 0, 0, 0);
246 MySlider *slider3 = new MySlider(panel1, myID_RotateXSlider, wxVERTICAL, wxDefaultPosition, wxSize(21, 21));
247 sizer33->Add(slider3, 1, wxEXPAND);
249 sizer3->Add(sizer33, 0, wxALL | wxEXPAND, 0);
252 sizer1->Add(sizer3, 1, wxALL | wxEXPAND, 0);
255 { // Horizontal sizer containing frame controls
257 const int height = 18;
258 frameControlPanel = new wxPanel(panel1, myID_FrameControlPanel, wxDefaultPosition, wxSize(200, height));
259 wxBoxSizer *sizer4 = new wxBoxSizer(wxHORIZONTAL);
261 frameSlider = new wxSlider(frameControlPanel, myID_FrameSlider, 0, 0, 0, wxDefaultPosition, wxSize(40, height - 2));
262 sizer4->Add(frameSlider, 1, wxALL | wxEXPAND, 1);
264 #include "../bitmaps/jump_to_start.xpm"
265 wxBitmap bmp41(jump_to_start_xpm, wxBITMAP_TYPE_XPM);
266 wxBitmapButton *button41 = new wxBitmapButton(frameControlPanel, myID_JumpToStartButton, bmp41, wxDefaultPosition, wxSize(16, height));
267 sizer4->Add(button41, 0, wxEXPAND);
268 ConnectMouseDownEvents(button41, MoleculeView::OnFrameButtonAction, this);
270 #include "../bitmaps/play_backward.xpm"
271 wxBitmap bmp42(play_backward_xpm, wxBITMAP_TYPE_XPM);
272 wxBitmapButton *button42 = new wxBitmapButton(frameControlPanel, myID_PlayBackwardButton, bmp42, wxDefaultPosition, wxSize(16, height));
273 sizer4->Add(button42, 0, wxEXPAND);
274 ConnectMouseDownEvents(button42, MoleculeView::OnFrameButtonAction, this);
277 frameText = new wxTextCtrl(frameControlPanel, myID_FrameText, wxT(""), wxDefaultPosition, wxSize(40, height));
278 wxFont font(9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
279 wxTextAttr attr(*wxBLACK, wxNullColour, font);
280 frameText->SetDefaultStyle(attr);
281 sizer4->Add(frameText, 0, wxEXPAND);
284 #include "../bitmaps/play_forward.xpm"
285 wxBitmap bmp43(play_forward_xpm, wxBITMAP_TYPE_XPM);
286 wxBitmapButton *button43 = new wxBitmapButton(frameControlPanel, myID_PlayForwardButton, bmp43, wxDefaultPosition, wxSize(16, height));
287 sizer4->Add(button43, 0, wxEXPAND);
288 ConnectMouseDownEvents(button43, MoleculeView::OnFrameButtonAction, this);
290 #include "../bitmaps/jump_to_end.xpm"
291 wxBitmap bmp44(jump_to_end_xpm, wxBITMAP_TYPE_XPM);
292 wxBitmapButton *button44 = new wxBitmapButton(frameControlPanel, myID_JumpToEndButton, bmp44, wxDefaultPosition, wxSize(16, height));
293 sizer4->Add(button44, 0, wxEXPAND);
294 ConnectMouseDownEvents(button44, MoleculeView::OnFrameButtonAction, this);
296 wxPanel *spacer = new wxPanel(frameControlPanel, -1, wxDefaultPosition, wxSize(21, height));
297 sizer4->Add(spacer, 0, wxEXPAND);
299 frameControlPanel->SetSizer(sizer4);
300 sizer1->Add(frameControlPanel, 0, wxALL | wxEXPAND, 0);
301 // controls->Disable();
304 panel1->SetSizer(sizer1);
307 splitter->SplitVertically(panel0, panel1);
309 wxBoxSizer *mainsizer = new wxBoxSizer(wxHORIZONTAL);
310 mainsizer->Add(splitter, 1, wxEXPAND);
311 frame->SetSizer(mainsizer);
314 splitter->SetSashPosition(240, true);
316 // Associate the molecule with the main view
317 MainView_setMolecule(mview, ((MyDocument *)doc)->GetMolecule());
319 // Initialize table view
320 MainView_createColumnsForTableAtIndex(mview, 0);
322 // Select table popup
323 listmenu->SetSelection(0);
325 #if defined(__X__) || defined(__WXMAC__)
326 // X seems to require a forced resize
328 frame->GetSize(&x, &y);
329 frame->SetSize(wxDefaultCoord, wxDefaultCoord, x, y);
334 // Initial keyboard focus is on the GL canvas (to accept 'S' for scale, etc.)
337 // Connect the notification handler
338 doc->Connect(MyDocumentEvent_documentModified, MyDocumentEvent, wxCommandEventHandler(MoleculeView::OnDocumentModified), NULL, this);
340 wxGetApp().Connect(MyDocumentEvent_scriptMenuModified, MyDocumentEvent, wxCommandEventHandler(MoleculeView::OnScriptMenuModified), NULL, this);
342 // Intercept the double-click handler of MyListCtrl
343 listctrl->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(MoleculeView::OnLeftDClickInListCtrl), NULL, this);
349 MoleculeView::OnDraw(wxDC *dc)
351 if (mview != NULL && mview->mol != NULL) {
352 MoleculeLock(mview->mol);
353 MainView_drawModel(mview);
354 MoleculeUnlock(mview->mol);
359 MoleculeView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
364 /* Maybe necessary in some platforms (not in MacOSX and MSW) */
367 wxClientDC dc(canvas);
375 MoleculeView::OnClose(bool deleteWindow)
377 if (!GetDocument()->Close())
380 // Dispose relationship between MainView and Molecule
381 MainView_setMolecule(mview, NULL);
382 // Release the MainView object
383 MainView_release(mview);
386 // Dispose Connection between DocManager and file history menu
387 wxGetApp().DocManager()->FileHistoryRemoveMenu(file_history_menu);
389 // Clear the canvas in case we're in single-window mode,
390 // and the canvas stays.
391 /* canvas->ClearBackground();
395 wxString s(wxTheApp->GetAppName());
412 MoleculeView::UpdateFrameControlValues()
414 if (mview == NULL || mview->mol == NULL)
418 cframe = mview->mol->cframe;
419 str.Printf(_T("%d"), cframe);
420 frameText->SetValue(str);
421 frameSlider->SetValue(cframe);
425 MoleculeView::UpdateFrameControls()
428 bool enabled = false;
429 if (mview != NULL && mview->mol != NULL) {
430 MoleculeLock(mview->mol);
431 nframes = MoleculeGetNumberOfFrames(mview->mol);
432 MoleculeUnlock(mview->mol);
437 frameControlPanel->Enable(enabled);
439 frameSlider->SetRange(0, nframes - 1);
440 UpdateFrameControlValues();
442 frameSlider->SetRange(0, 0);
443 frameText->SetValue(_T(""));
445 frameControlPanel->Update();
449 MoleculeView::SelectButtonForMode(int mode)
452 if (mode >= 1 && mode <= 6) {
453 for (i = 0; i < 6; i++) {
454 tbuttons[i]->SetValue((i == mode - 1));
457 MainViewCallback_setKeyboardFocus(mview);
461 MoleculeView::OnButtonPressed(wxCommandEvent& event)
463 int eventId = event.GetId();
464 int mode = eventId - myID_RotButton + kTrackballRotateMode;
465 MainView_setMode(mview, mode);
466 SelectButtonForMode(mode);
470 MoleculeView::OnSliderAction(wxCommandEvent& event)
472 int eventId = event.GetId();
473 int mode = eventId - myID_RotateBondSlider + 1;
474 MySlider *sender = (MySlider *)event.GetEventObject();
475 float angle = sender->GetFloatValue();
476 int mouseStatus = sender->GetMouseStatus();
477 MoleculeLock(mview->mol);
478 MainView_rotateBySlider(mview, angle * 3.1415927 * 2, mode, mouseStatus, MainViewCallback_modifierFlags(NULL));
479 MoleculeUnlock(mview->mol);
483 MoleculeView::OnFrameButtonAction(wxMouseEvent &event)
485 int ival, nframes, bid;
486 if (mview == NULL || mview->mol == NULL)
488 nframes = MoleculeGetNumberOfFrames(mview->mol);
492 if (bid == myID_JumpToStartButton) {
494 } else if (bid == myID_JumpToEndButton) {
496 } else if (bid == myID_PlayForwardButton) {
497 ival = (mview->mol->cframe + 1) % nframes;
498 } else if (bid == myID_PlayBackwardButton) {
499 ival = (mview->mol->cframe + nframes - 1) % nframes;
501 // TODO: implement continuous move
502 if (ival >= 0 && ival < nframes) {
503 MoleculeLock(mview->mol);
504 MoleculeSelectFrame(mview->mol, ival, 1);
505 MoleculeUnlock(mview->mol);
506 MainViewCallback_display(mview);
507 UpdateFrameControlValues();
515 MoleculeView::OnFrameSliderAction(wxScrollEvent &event)
518 if (mview == NULL || mview->mol == NULL)
520 MoleculeLock(mview->mol);
521 nframes = MoleculeGetNumberOfFrames(mview->mol);
523 ival = frameSlider->GetValue();
524 if (ival >= 0 && ival < nframes) {
525 MoleculeSelectFrame(mview->mol, ival, 1);
526 MoleculeUnlock(mview->mol);
527 MainViewCallback_display(mview);
528 UpdateFrameControlValues();
532 MoleculeUnlock(mview->mol);
536 MoleculeView::OnFrameTextAction(wxCommandEvent &event)
540 if (mview == NULL || mview->mol == NULL)
542 MoleculeLock(mview->mol);
543 nframes = MoleculeGetNumberOfFrames(mview->mol);
545 str = frameText->GetValue();
546 ival = atoi((const char *)str.mb_str(wxConvUTF8));
547 if (ival >= 0 && ival < nframes) {
548 MoleculeSelectFrame(mview->mol, ival, 1);
549 MoleculeUnlock(mview->mol);
550 MainViewCallback_display(mview);
551 UpdateFrameControlValues();
555 MoleculeUnlock(mview->mol);
559 MoleculeView::OnDocumentModified(wxCommandEvent& event)
561 if (!mview->freezeScreen) {
564 UpdateFrameControls();
565 MoleculeLock(mview->mol);
566 MainView_refreshTable(mview);
567 MoleculeUnlock(mview->mol);
570 if (mview->tableIndex == kMainViewParameterTableIndex && mview->mol->parameterTableSelectionNeedsClear) {
571 /* Clear parameter selection if necessary */
572 MainViewCallback_setTableSelection(mview, NULL);
573 mview->mol->parameterTableSelectionNeedsClear = 0;
576 /* printf("MoleculeView::OnDocumentModified invoked\n"); */
577 event.Skip(); /* Continue processing of the notification */
581 MoleculeView::OnScriptMenuModified(wxCommandEvent& event)
583 wxGetApp().UpdateScriptMenu(frame->GetMenuBar());
588 MoleculeView::OnChar(wxKeyEvent &event)
590 int code = event.GetKeyCode();
592 bool noMod = ((event.GetModifiers() | wxMOD_SHIFT) == wxMOD_SHIFT);
593 // MyAppCallback_showScriptMessage("MoleculeView::OnChar invoked\n");
594 if (code == WXK_BACK || code == WXK_DELETE || code == 0x7f || code == 8) {
595 MoleculeLock(mview->mol);
596 MainView_delete(mview);
597 MoleculeUnlock(mview->mol);
598 } else if (noMod && (code == 'r' || code == 'R'))
599 mode = kTrackballRotateMode;
600 else if (noMod && (code == 't' || code == 'T'))
601 mode = kTrackballTranslateMode;
602 else if (noMod && (code == 's' || code == 'S'))
603 mode = kTrackballScaleMode;
604 else if (noMod && (code == ' '))
605 mode = kTrackballSelectionMode;
606 else if (noMod && (code == 'b' || code == 'B'))
607 mode = kTrackballCreateMode;
608 else if (noMod && (code == 'e' || code == 'E'))
609 mode = kTrackballEraseMode;
615 MainView_setMode(mview, mode);
616 MainViewCallback_selectMatrixCellForMode(mview, mode);
621 MoleculeView::SelectTable(int idx)
623 if (idx >= 0 && idx < listmenu->GetCount() && idx != mview->tableIndex) {
624 isRebuildingTable = true;
625 listmenu->SetSelection(idx);
626 MainView_createColumnsForTableAtIndex(mview, idx);
627 isRebuildingTable = false;
628 MoleculeLock(mview->mol);
629 MainView_refreshTable(mview);
630 MoleculeUnlock(mview->mol);
631 if (idx == kMainViewParameterTableIndex || idx == kMainViewMOTableIndex) {
632 MainViewCallback_setTableSelection(mview, NULL);
638 MoleculeView::OnSelectTable(wxCommandEvent &event)
640 if (!isRebuildingTable) {
641 MoleculeLock(mview->mol);
642 SelectTable(listmenu->GetSelection());
643 MoleculeUnlock(mview->mol);
648 MoleculeView::OnLeftDClickInListCtrl(wxMouseEvent &event)
650 listctrl->OnLeftDClick(event);
651 if (mview->tableIndex >= kMainViewBondTableIndex && mview->tableIndex <= kMainViewImproperTableIndex && mview->mol->par != NULL) {
653 char names[64], types[64], value[20], params[3][20];
654 char *ptype, *parstr;
655 wxPoint pos = event.GetPosition();
656 if (!listctrl->FindItemAtPosition(pos, &row, &col) || col < 4)
658 /* Start editing the local parameter; open a separate dialog */
659 MainView_valueForTable(mview, 1, row, names, sizeof names);
660 MainView_valueForTable(mview, 2, row, types, sizeof types);
661 MainView_valueForTable(mview, 3, row, value, sizeof value);
662 for (i = 0; i < 3; i++) {
663 MainView_valueForTable(mview, 4 + i, row, params[i], sizeof(params[0]));
665 switch (mview->tableIndex) {
666 case kMainViewBondTableIndex: ptype = "bond"; break;
667 case kMainViewAngleTableIndex: ptype = "angle"; break;
668 case kMainViewDihedralTableIndex: ptype = "dihedral"; break;
669 case kMainViewImproperTableIndex: ptype = "improper"; break;
672 asprintf(&parstr, "%s %s %s", params[0], params[1], params[2]);
673 MolActionCreateAndPerform(mview->mol, SCRIPT_ACTION("sssss"), "cmd_edit_local_parameter_in_mainview", ptype, names, types, value, parstr);
678 MoleculeView::OnActivate(wxActivateEvent &event)
680 if (!event.GetActive()) {
681 listctrl->EndEditText(true);
686 #pragma mark ====== MyListCtrl data source ======
689 MoleculeView::GetItemCount(MyListCtrl *ctrl)
691 return MainView_numberOfRowsInTable(mview);
695 MoleculeView::GetItemText(MyListCtrl *ctrl, long row, long column) const
698 MainView_valueForTable(mview, column, row, buf, sizeof buf);
699 wxString *str = new wxString(buf, wxConvUTF8);
704 MoleculeView::SetItemText(MyListCtrl *ctrl, long row, long column, const wxString &value)
706 MainView_setValueForTable(mview, column, row, value.mb_str(wxConvUTF8));
711 MoleculeView::DragSelectionToRow(MyListCtrl *ctrl, long row)
713 MainView_dragTableSelectionToRow(mview, row);
717 MoleculeView::IsItemEditable(MyListCtrl *ctrl, long row, long column)
719 return MainView_isTableItemEditable(mview, column, row);
723 MoleculeView::IsDragAndDropEnabled(MyListCtrl *ctrl)
725 /* Only enabled for the atom table */
726 return (MainView_tableType(mview) == 0);
730 MoleculeView::OnSelectionChanged(MyListCtrl *ctrl)
732 MainView_setSelectionFromTable(mview);
736 MoleculeView::SetItemColor(MyListCtrl *ctrl, long row, long col, float *fg, float *bg)
738 if (mview != NULL && mview->mol != NULL) {
739 return MainView_setColorForTable(mview, col, row, fg, bg);
741 if (mview->tableIndex == kMainViewParameterTableIndex && col == -1) {
742 int src = ParameterTableGetItemSource(mview->mol->par, row);
743 if (src == -2) { // separator line
744 bg[0] = bg[1] = bg[2] = 0.6;
746 } else if (src == -1) { // undefined parameters
750 } else if (src == 0) { // local parameter
755 } else if (mview->tableIndex > 0 && mview->tableIndex < 5) {
756 return MainView_setColorForTable(mview, col, row, fg, bg);
763 #pragma mark ====== Plain C interface ======
766 MainViewCallback_modifierFlags(void *eventRef)
770 wxMouseState state = ::wxGetMouseState();
772 if (state.ShiftDown())
773 flags |= kShiftKeyMask;
775 flags |= kAltKeyMask;
780 MainViewCallback_clickCount(void *eventRef)
782 wxMouseEvent *mevent = (wxMouseEvent *)eventRef;
783 if (mevent != NULL) {
784 if (mevent->LeftDClick())
786 else if (mevent->LeftDown() || mevent->LeftUp())
794 MainViewCallback_lockFocus(MainView *mview)
796 if (mview != NULL && mview->ref != NULL)
797 ((MoleculeView *)(mview->ref))->canvas->SetCurrent();
801 MainViewCallback_unlockFocus(MainView *mview)
803 // if (mview != NULL && mview->ref != NULL)
804 // [[(MyWindowController *)(mview->ref) myOpenGLView] unlockFocus];
808 MainViewCallback_frame(MainView *mview, float *rect)
810 if (mview != NULL && mview->ref != NULL) {
812 ((MoleculeView *)(mview->ref))->canvas->GetClientSize(&width, &height);
813 rect[0] = rect[1] = 0.0;
817 rect[0] = rect[1] = rect[2] = rect[3] = 0.0;
822 MainViewCallback_display(MainView *mview)
824 if (mview != NULL && mview->ref != NULL) {
825 wxWindow *canvas = ((MoleculeView *)(mview->ref))->canvas;
832 MainViewCallback_setNeedsDisplay(MainView *mview, int flag)
834 if (mview != NULL && mview->ref != NULL) {
836 ((MoleculeView *)(mview->ref))->canvas->Refresh();
841 MainViewCallback_setKeyboardFocus(MainView *mview)
843 if (mview != NULL && mview->ref != NULL) {
844 ((MoleculeView *)(mview->ref))->canvas->SetFocus();
849 MainViewCallback_clearLabels(MainView *mview)
853 if (mview != NULL && mview->ref != NULL) {
854 id view = [(MyWindowController *)(mview->ref) myOverlayView];
855 NSRect bounds = [view bounds];
858 [[NSColor cyanColor] set];
859 bounds.origin.x = bounds.size.width / 2;
862 [view setNeedsDisplay: YES];
868 MainViewCallback_drawLabel(MainView *mview, const float *pos, const char *label)
872 if (mview != NULL && mview->ref != NULL) {
873 id view = [(MyWindowController *)(mview->ref) myOverlayView];
874 NSString *s = [NSString stringWithUTF8String: label];
875 NSDictionary *attr = [(MyWindowController *)(mview->ref) labelAttributes];
877 [s drawAtPoint: NSMakePoint(pos[0], pos[1]) withAttributes: attr];
879 [view setNeedsDisplay: YES];
885 MainViewCallback_drawInfoText(MainView *mview, const char *label)
887 if (mview != NULL && mview->ref != NULL) {
888 wxString labelstr(label, wxConvUTF8);
889 ((MoleculeView *)(mview->ref))->infotext->SetLabel(labelstr);
894 MainViewCallback_mouseCheck(MainView *mview)
900 MainViewCallback_selectMatrixCellForMode(MainView *mview, int mode)
902 if (mview != NULL && mview->ref != NULL)
903 ((MoleculeView *)(mview->ref))->SelectButtonForMode(mode);
907 //MainViewCallback_getTag(MainView *mview)
909 // if (mview != NULL && mview->ref != NULL)
910 // return [(MyWindowController *)(mview->ref) myTag];
915 MainViewCallback_viewWithTag(int tag)
917 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
918 wxList::iterator iter;
920 for (i = 0, iter = doclist.begin(); iter != doclist.end(); ++i, ++iter) {
922 return ((MoleculeView *)(((MyDocument *)(*iter))->GetFirstView()))->mview;
926 //wxList::compatibility_iterator iter = doclist.Item(tag);
928 // return (MyDocument *)(*iter)->GetFirstView()->mview;
932 // if (sMyWindowControllers == nil)
934 // for (i = [sMyWindowControllers count] - 1; i >= 0; i--) {
935 // id obj = [sMyWindowControllers objectAtIndex: i];
936 // if ([obj myTag] == tag)
937 // return [obj mainView];
943 MainViewCallback_activeView(void)
945 MoleculeView *cview = (MoleculeView *)(wxGetApp().DocManager()->GetCurrentView());
950 // return ((MoleculeView *)(wxGetApp().DocManager()->GetCurrentView()))->mview;
951 // return MainViewCallback_viewWithTag(sLastMainViewTag);
955 MainViewCallback_newFromFile(const char *fname)
958 wxDocManager *manager = wxGetApp().DocManager();
959 if (fname == NULL || *fname == 0) {
960 doc = manager->CreateDocument(wxT(""), wxDOC_NEW);
962 wxString fnamestr(fname, wxConvUTF8); /* UTF8 -> wxString */
963 doc = manager->CreateDocument(fnamestr, wxDOC_SILENT);
965 return MainViewCallback_activeView();
969 MainViewCallback_importFromFile(MainView *mview, const char *fname)
972 if (mview != NULL && mview->ref != NULL && (doc = (((MoleculeView *)(mview->ref))->MolDocument())) != NULL) {
973 wxString fnamestr(fname, wxConvUTF8); /* UTF8 -> wxString */
974 // doc->importFromFile(fnamestr);
975 MainViewCallback_setNeedsDisplay(mview, 1);
982 MainViewCallback_getFilename(MainView *mview, char *buf, int bufsize)
985 if (mview != NULL && mview->ref != NULL && (doc = (((MoleculeView *)(mview->ref))->MolDocument())) != NULL) {
987 fname = doc->GetFilename();
988 strncpy(buf, (const char*)fname.mb_str(wxConvUTF8), bufsize - 1); /* wxString -> UTF8 */
989 buf[bufsize - 1] = 0;
996 MainViewCallback_moleculeReplaced(MainView *mview, struct Molecule *mol)
998 if (mview != NULL && mview->ref != NULL) {
999 MyDocument *doc = ((MoleculeView *)(mview->ref))->MolDocument();
1001 doc->SetMolecule(mol);
1002 MyListCtrl *listctrl = ((MoleculeView *)(mview->ref))->GetListCtrl();
1003 if (listctrl != NULL)
1004 listctrl->SetDataSource((MoleculeView *)(mview->ref));
1008 typedef struct Label {
1009 // StringTexture *tex;
1013 MainViewCallback_newLabel(MainView *mview, const char *message, float fontsize, const float *forecolor, const float *backcolor)
1018 NSColor *textColor, *boxColor;
1019 label = (Label *)malloc(sizeof(Label));
1022 memset(label, 0, sizeof(Label));
1023 // MainViewCallback_lockFocus(mview);
1024 if (forecolor != NULL)
1025 textColor = [NSColor colorWithDeviceRed: forecolor[0] green: forecolor[1] blue: forecolor[2] alpha: forecolor[3]];
1027 textColor = [NSColor whiteColor];
1028 if (backcolor != NULL)
1029 boxColor = [NSColor colorWithDeviceRed: backcolor[0] green: backcolor[1] blue: backcolor[2] alpha: backcolor[3]];
1031 boxColor = [NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:0.0f];
1032 attr = [NSDictionary dictionaryWithObjectsAndKeys: [NSFont userFontOfSize: fontsize], NSFontAttributeName, textColor, NSForegroundColorAttributeName, nil];
1033 label->tex = [[StringTexture alloc]
1034 initWithString: [NSString stringWithUTF8String: message]
1035 withAttributes: attr
1036 withTextColor: textColor
1037 withBoxColor: boxColor
1038 withBorderColor: [NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:0.0f]];
1039 // MainViewCallback_unlockFocus(mview);
1045 MainViewCallback_releaseLabel(struct Label *label)
1047 /* if (label != NULL) {
1048 [label->tex release];
1055 MainViewCallback_drawLabelAtPoint(struct Label *label, const float *pos)
1058 if (label != NULL && pos != NULL) {
1059 // GLint matrixMode;
1060 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1061 // glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
1062 // glMatrixMode(GL_MODELVIEW);
1064 // glTranslatef(0.0f, 0.0f, pos[3]);
1065 [label->tex drawAtPoint: NSMakePoint(pos[0], pos[1]) withDepth: pos[2]];
1067 // glMatrixMode (matrixMode);
1073 MainViewCallback_labelSize(struct Label *label, float *outSize)
1075 /* if (label != NULL) {
1076 NSSize size = [label->tex frameSize];
1077 if (outSize != NULL) {
1078 outSize[0] = size.width;
1079 outSize[1] = size.height;
1085 #pragma mark ====== Plain C Interface (MyListCtrl) ======
1087 /* These interface functions are also used for accessing MyListCtrl of GlobalParameterFrame (when mview == NULL) */
1090 s_MyListCtrlFromMainView(MainView *mview)
1093 return wxGetApp().GetGlobalParameterListCtrl();
1094 if (mview != NULL && mview->ref != NULL)
1095 return ((MoleculeView *)(mview->ref))->GetListCtrl();
1100 MainViewCallback_selectTable(MainView *mview, int idx)
1102 if (mview != NULL && mview->ref != NULL)
1103 ((MoleculeView *)(mview->ref))->SelectTable(idx);
1107 MainViewCallback_numberOfTableColumns(MainView *mview)
1109 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1110 if (listctrl != NULL)
1111 return listctrl->GetColumnCount();
1116 MainViewCallback_addTableColumn(MainView *mview, const char *name, int width, int editable)
1119 wxString nstr(name, wxConvUTF8);
1120 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1121 if (listctrl == NULL)
1123 idx = listctrl->GetColumnCount();
1124 listctrl->InsertColumn(idx, nstr, wxLIST_FORMAT_LEFT);
1125 listctrl->SetColumnWidth(idx, width * 10);
1130 MainViewCallback_removeTableColumnAtIndex(MainView *mview, int idx)
1133 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1134 if (listctrl == NULL)
1136 ncolumns = listctrl->GetColumnCount();
1137 if (idx >= 0 && idx < ncolumns) {
1138 listctrl->DeleteColumn(idx);
1145 MainViewCallback_reloadTableData(MainView *mview)
1147 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1148 if (listctrl != NULL)
1149 listctrl->RefreshTable();
1151 int nrows = MainView_numberOfRowsInTable(mview);
1152 listctrl->SetItemCount(nrows);
1154 listctrl->RefreshItems(0, nrows - 1);
1159 MainViewCallback_setTableSelection(MainView *mview, IntGroup *selection)
1162 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1163 if (listctrl == NULL)
1166 listctrl->EnableSelectionChangeNotification(false);
1167 if (selection != NULL) {
1168 for (i = 0; (n1 = IntGroupGetStartPoint(selection, i)) >= 0; i++) {
1169 n2 = IntGroupGetEndPoint(selection, i);
1171 listctrl->SetItemState(n, 0, wxLIST_STATE_SELECTED);
1175 listctrl->SetItemState(n, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
1180 listctrl->RefreshTable();
1181 n1 = MainView_numberOfRowsInTable(mview);
1183 listctrl->SetItemState(n, 0, wxLIST_STATE_SELECTED);
1186 // listctrl->RefreshItems(0, n1 - 1);
1188 // EVT_LIST_ITEM_SELECTED is sent by wxPostEvent rather than ProcessEvent,
1189 // so re-enable of table selection event should also be sent by wxPostEvent.
1190 // Otherwise, the enable flag is set to true _before_ EVT_LIST_ITEM_SELECTED is sent.
1191 wxCommandEvent myEvent(MyListCtrlEvent, MyListCtrlEvent_enableTableSelectionNotification);
1192 wxPostEvent(listctrl, myEvent);
1197 MainViewCallback_getTableSelection(MainView *mview)
1201 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1202 if (listctrl == NULL)
1205 n = MainView_numberOfRowsInTable(mview);
1206 for (i = 0; i < n; i++) {
1207 if (listctrl->GetItemState(i, wxLIST_STATE_SELECTED) != 0)
1208 IntGroupAdd(ig, i, 1);
1214 MainViewCallback_showTable(MainView *mview)
1216 // if (mview != NULL && mview->ref != NULL) {
1217 // MyDocument *doc = (MyDocument *)[(id)(mview->ref) document];
1218 // [doc showTable: doc];
1223 MainViewCallback_hideTable(MainView *mview)
1225 // if (mview != NULL && mview->ref != NULL) {
1226 // MyDocument *doc = (MyDocument *)[(id)(mview->ref) document];
1227 // [doc hideTable: doc];
1232 MainViewCallback_ensureVisible(MainView *mview, int row)
1234 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1235 if (listctrl != NULL)
1236 listctrl->EnsureVisible(row);
1240 MainViewCallback_startEditText(MainView *mview, int row, int column)
1242 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1243 if (listctrl != NULL)
1244 listctrl->StartEditText(row, column);