OSDN Git Service

Memo update for version 0.5.6.2
[molby/Molby.git] / wxSources / MoleculeView.cpp
1 /*
2  *  MoleculeView.cpp
3  *  Molby
4  *
5  *  Created by Toshi Nagata on 08/10/24.
6  *  Copyright 2008 Toshi Nagata. All rights reserved.
7  *
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.
11  
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.
16  */
17
18 // For compilers that support precompilation, includes "wx/wx.h".
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 #ifndef WX_PRECOMP
26 #include "wx/wx.h"
27 #endif
28
29 #if !wxUSE_DOC_VIEW_ARCHITECTURE
30 #error "You should have DocView architecture enabled in your wxWidgets installation."
31 #endif
32
33 #include "MoleculeView.h"
34
35 #include "MyApp.h"
36 #include "MyDocument.h"
37 #include "MyGLCanvas.h"
38 #include "MyCommand.h"
39 #include "MySlider.h"
40 #include "MyListCtrl.h"
41 #include "../MolLib/Missing.h"
42
43 #include "wx/tglbtn.h"
44 #include "wx/listctrl.h"
45 #include "wx/splitter.h"
46 #include "wx/choice.h"
47 #include "wx/font.h"
48
49 //#include "../MolLib/Ruby_bind/Molby_extern.h"
50
51 enum {
52         myID_RotButton = 500,
53         myID_TransButton,
54         myID_ScaleButton,
55         myID_SelectButton,
56         myID_BondButton,
57         myID_EraseButton,
58         myID_RotateBondSlider,
59         myID_RotateXSlider,
60         myID_RotateYSlider,
61         myID_FrameControlPanel,
62         myID_FrameSlider,
63         myID_JumpToStartButton,
64         myID_PlayBackwardButton,
65         myID_FrameText,
66         myID_PlayForwardButton,
67         myID_JumpToEndButton,
68         myID_Table,
69         myID_TableMenu
70 };
71
72 IMPLEMENT_DYNAMIC_CLASS(MoleculeView, wxView)
73
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)
86 END_EVENT_TABLE()
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))
90                                  
91                                  
92 bool
93 MoleculeView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
94 {
95         int i;
96
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);
102
103         canvas = NULL;
104         mview = NULL;
105         listmenu = NULL;
106         listctrl = NULL;
107         file_history_menu = NULL;
108         edit_menu = NULL;
109         memset(tbuttons, 0, sizeof(tbuttons));
110         infotext = NULL;
111         frameControlPanel = NULL;
112         frameSlider = NULL;
113         frameText = NULL;
114         isRebuildingTable = false;
115         
116         wxMenuBar *menu_bar = wxGetApp().CreateMenuBar(1, &file_history_menu, &edit_menu);
117         
118         // Associate the menu bar with the frame
119         frame->SetMenuBar(menu_bar);
120
121         // Associate the edit menu with the command processor
122         doc->GetCommandProcessor()->SetEditMenu(edit_menu);
123         
124     mview = MainView_newMainView(this);
125         
126         // Create the window content
127         
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);
130         
131         //  Create the left half
132         //  A panel containing a popup menu and a list window
133         wxPanel *panel0 = new wxPanel(splitter);
134         {
135                 char buf[16];
136                 wxBoxSizer *sizer0;
137                 sizer0 = new wxBoxSizer(wxVERTICAL);
138                 wxArrayString choiceItems;
139                 for (i = 0; ; i++) {
140                         MainView_tableTitleForIndex(mview, i, buf, sizeof buf);
141                         if (buf[0] == 0)
142                                 break;
143                         wxString itemTitle(buf, wxConvUTF8);
144                         choiceItems.Add(itemTitle);
145                 }
146         /*      static wxString choiceItems[] = {
147                         wxT("atoms"), wxT("bonds"), wxT("angles"), wxT("dihedrals"), wxT("impropers"), wxT("MO info")
148                 }; */
149                 
150                 listmenu = new wxChoice(panel0, myID_TableMenu, wxDefaultPosition, wxDefaultSize, choiceItems);
151                 sizer0->Add(listmenu, 0, wxALL, 0);
152                 
153                 listctrl = new MyListCtrl();
154                 listctrl->Create(panel0, myID_Table, wxDefaultPosition, wxDefaultSize);
155                 sizer0->Add(listctrl, 1, wxALL | wxEXPAND, 0);
156                 panel0->SetSizer(sizer0);
157         }
158                 
159         //  Create the right half
160         //  A panel containing MyGLCanvas, buttons, sliders, etc.
161         wxPanel *panel1 = new wxPanel(splitter);
162         
163         {       //  Vertical sizer containing [sizer2, sizer3, sizer4]
164                 wxBoxSizer *sizer1;
165                 sizer1 = new wxBoxSizer(wxVERTICAL);
166                 
167                 {       //  Horizontal sizer containing [button0, button1, ..., button5, infotext]
168                         wxBoxSizer *sizer2;
169                         sizer2 = new wxBoxSizer(wxHORIZONTAL);
170                         
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")
174                                 };
175                                 wxWindowID ids[] = {
176                                         myID_RotButton, myID_TransButton, myID_ScaleButton, 
177                                         myID_SelectButton, myID_BondButton, myID_EraseButton
178                                 };
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);
182                                 }
183                                 tbuttons[0]->SetValue(true);
184                         }
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
190                         }
191                         
192                         sizer1->Add(sizer2, 0, wxALL | wxEXPAND, 0);
193                 }
194                 
195                 {       // Horizontal sizer containing [sizer31, sizer32, sizer33]
196                         wxBoxSizer *sizer3 = new wxBoxSizer(wxHORIZONTAL);
197                         
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);
205                                         button1->Disable();
206                                         MySlider *slider1 = new MySlider(panel1, myID_RotateBondSlider, wxVERTICAL, wxDefaultPosition, wxSize(21, 21));
207                                         sizer31->Add(slider1, 1, wxEXPAND);
208                                 }
209                                 sizer3->Add(sizer31, 0, wxALL | wxEXPAND, 0);
210                         }
211                         
212                         {       // Vertical sizer containing [Canvas, [button, mySlider]]
213                                 wxBoxSizer *sizer32 = new wxBoxSizer(wxVERTICAL);
214                                 {
215                                         canvas = new MyGLCanvas(this, panel1, wxDefaultPosition, wxSize(100, 100));
216                                         sizer32->Add(canvas, 1, wxALL | wxEXPAND, 0);
217                                         
218                                         //  Let the MyGLCanvas pass the keyboard event to this
219                                         canvas->Connect(-1, wxEVT_CHAR, wxKeyEventHandler(MoleculeView::OnChar), NULL, this);
220                                 }
221                                 {
222                                         wxBoxSizer *sizer321 = new wxBoxSizer(wxHORIZONTAL);
223                                         {
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);
228                                                 button2->Disable();
229                                                 MySlider *slider2 = new MySlider(panel1, myID_RotateYSlider, wxHORIZONTAL, wxDefaultPosition, wxSize(21, 21));
230                                                 sizer321->Add(slider2, 1, wxEXPAND);
231                                         }
232                                         sizer32->Add(sizer321, 0, wxEXPAND);
233                                 }
234                                 sizer3->Add(sizer32, 1, wxEXPAND);
235                         }
236
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));
243                                         button3->Disable();
244                                         sizer33->Add(button3, 0, 0, 0);
245                                         
246                                         MySlider *slider3 = new MySlider(panel1, myID_RotateXSlider, wxVERTICAL, wxDefaultPosition, wxSize(21, 21));
247                                         sizer33->Add(slider3, 1, wxEXPAND);
248                                 }
249                                 sizer3->Add(sizer33, 0, wxALL | wxEXPAND, 0);
250                         }
251                         
252                         sizer1->Add(sizer3, 1, wxALL | wxEXPAND, 0);
253                 }
254                 
255                 {       //  Horizontal sizer containing frame controls
256                         
257                         const int height = 18;
258                         frameControlPanel = new wxPanel(panel1, myID_FrameControlPanel, wxDefaultPosition, wxSize(200, height));
259                         wxBoxSizer *sizer4 = new wxBoxSizer(wxHORIZONTAL);
260                         {
261                                 frameSlider = new wxSlider(frameControlPanel, myID_FrameSlider, 0, 0, 0, wxDefaultPosition, wxSize(40, height - 2));
262                                 sizer4->Add(frameSlider, 1, wxALL | wxEXPAND, 1);
263                         
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);
269
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);
275                                 
276                                 {
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);
282                                 }
283                         
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);
289
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);
295                                 
296                                 wxPanel *spacer = new wxPanel(frameControlPanel, -1, wxDefaultPosition, wxSize(21, height));
297                                 sizer4->Add(spacer, 0, wxEXPAND);
298                         }
299                         frameControlPanel->SetSizer(sizer4);
300                         sizer1->Add(frameControlPanel, 0, wxALL | wxEXPAND, 0);
301                 //      controls->Disable();
302                 }
303
304                 panel1->SetSizer(sizer1);
305         }
306
307         splitter->SplitVertically(panel0, panel1);
308
309         wxBoxSizer *mainsizer = new wxBoxSizer(wxHORIZONTAL);
310         mainsizer->Add(splitter, 1, wxEXPAND);
311         frame->SetSizer(mainsizer);
312
313         mainsizer->Layout();
314         splitter->SetSashPosition(240, true);
315         
316         //  Associate the molecule with the main view
317         MainView_setMolecule(mview, ((MyDocument *)doc)->GetMolecule());
318         
319         //  Initialize table view
320         MainView_createColumnsForTableAtIndex(mview, 0);
321
322         //  Select table popup
323         listmenu->SetSelection(0);
324         
325 #if defined(__X__) || defined(__WXMAC__)
326     // X seems to require a forced resize
327     int x, y;
328     frame->GetSize(&x, &y);
329     frame->SetSize(wxDefaultCoord, wxDefaultCoord, x, y);
330 #endif
331     frame->Show(true);
332     Activate(true);
333
334         //  Initial keyboard focus is on the GL canvas (to accept 'S' for scale, etc.)
335         canvas->SetFocus();
336         
337         //  Connect the notification handler
338         doc->Connect(MyDocumentEvent_documentModified, MyDocumentEvent, wxCommandEventHandler(MoleculeView::OnDocumentModified), NULL, this);
339
340         wxGetApp().Connect(MyDocumentEvent_scriptMenuModified, MyDocumentEvent, wxCommandEventHandler(MoleculeView::OnScriptMenuModified), NULL, this);
341
342         //  Intercept the double-click handler of MyListCtrl
343         listctrl->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(MoleculeView::OnLeftDClickInListCtrl), NULL, this);
344                                         
345     return true;
346 }
347
348 void
349 MoleculeView::OnDraw(wxDC *dc)
350 {
351         if (mview != NULL && mview->mol != NULL) {
352                 MoleculeLock(mview->mol);
353                 MainView_drawModel(mview);
354                 MoleculeUnlock(mview->mol);
355         }
356 }
357
358 void
359 MoleculeView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
360 {
361         if (canvas)
362                 canvas->Refresh();
363
364 /*  Maybe necessary in some platforms (not in MacOSX and MSW)  */
365 #if 0
366   if (canvas) {
367       wxClientDC dc(canvas);
368       dc.Clear();
369       OnDraw(&dc);
370   }
371 #endif
372 }
373
374 bool
375 MoleculeView::OnClose(bool deleteWindow)
376 {
377         if (!GetDocument()->Close())
378                 return false;
379
380         //  Dispose relationship between MainView and Molecule
381         MainView_setMolecule(mview, NULL);
382         //  Release the MainView object
383         MainView_release(mview);
384         mview = NULL;
385
386         //  Dispose Connection between DocManager and file history menu
387         wxGetApp().DocManager()->FileHistoryRemoveMenu(file_history_menu);
388
389         // Clear the canvas in case we're in single-window mode,
390         // and the canvas stays.
391 /*      canvas->ClearBackground();
392         canvas->view = NULL;
393         canvas = NULL;
394
395         wxString s(wxTheApp->GetAppName());
396         if (frame)
397                 frame->SetTitle(s);
398
399         SetFrame(NULL);
400
401         Activate(false); */
402
403         if (deleteWindow) {
404                 frame->Destroy();
405         //      delete frame;
406                 return true;
407         }
408         return true;
409 }
410
411 void
412 MoleculeView::UpdateFrameControlValues()
413 {
414         if (mview == NULL || mview->mol == NULL)
415                 return;
416         wxString str;
417         int cframe;
418         cframe = mview->mol->cframe;
419         str.Printf(_T("%d"), cframe);
420         frameText->SetValue(str);
421         frameSlider->SetValue(cframe);
422 }
423
424 void
425 MoleculeView::UpdateFrameControls()
426 {
427         int nframes;
428         bool enabled = false;
429         if (mview != NULL && mview->mol != NULL) {
430                 MoleculeLock(mview->mol);
431                 nframes = MoleculeGetNumberOfFrames(mview->mol);
432                 MoleculeUnlock(mview->mol);
433                 if (nframes > 0)
434                         enabled = true;
435         }
436         
437         frameControlPanel->Enable(enabled);
438         if (enabled) {
439                 frameSlider->SetRange(0, nframes - 1);
440                 UpdateFrameControlValues();
441         } else {
442                 frameSlider->SetRange(0, 0);
443                 frameText->SetValue(_T(""));
444         }
445         frameControlPanel->Update();
446 }
447
448 void
449 MoleculeView::SelectButtonForMode(int mode)
450 {
451         int i;
452         if (mode >= 1 && mode <= 6) {
453                 for (i = 0; i < 6; i++) {
454                         tbuttons[i]->SetValue((i == mode - 1));
455                 }
456         }
457         MainViewCallback_setKeyboardFocus(mview);
458 }
459
460 void
461 MoleculeView::OnButtonPressed(wxCommandEvent& event)
462 {
463         int eventId = event.GetId();
464         int mode = eventId - myID_RotButton + kTrackballRotateMode;
465         MainView_setMode(mview, mode);
466         SelectButtonForMode(mode);
467 }
468
469 void
470 MoleculeView::OnSliderAction(wxCommandEvent& event)
471 {
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);
480 }
481
482 void
483 MoleculeView::OnFrameButtonAction(wxMouseEvent &event)
484 {
485         int ival, nframes, bid;
486         if (mview == NULL || mview->mol == NULL)
487                 goto skip;
488         nframes = MoleculeGetNumberOfFrames(mview->mol);
489         if (nframes == 0)
490                 goto skip;
491         bid = event.GetId();
492         if (bid == myID_JumpToStartButton) {
493                 ival = 0;
494         } else if (bid == myID_JumpToEndButton) {
495                 ival = nframes - 1;
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;
500         }
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();
508         }
509         
510 skip:
511         event.Skip();
512 }
513
514 void
515 MoleculeView::OnFrameSliderAction(wxScrollEvent &event)
516 {
517         int ival, nframes;
518         if (mview == NULL || mview->mol == NULL)
519                 return;
520         MoleculeLock(mview->mol);
521         nframes = MoleculeGetNumberOfFrames(mview->mol);
522         if (nframes != 0) {
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();
529                         return;
530                 }
531         }
532         MoleculeUnlock(mview->mol);
533 }
534
535 void
536 MoleculeView::OnFrameTextAction(wxCommandEvent &event)
537 {
538         int ival, nframes;
539         wxString str;
540         if (mview == NULL || mview->mol == NULL)
541                 return;
542         MoleculeLock(mview->mol);
543         nframes = MoleculeGetNumberOfFrames(mview->mol);
544         if (nframes != 0) {
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();
552                         return;
553                 }
554         }
555         MoleculeUnlock(mview->mol);
556 }
557
558 void
559 MoleculeView::OnDocumentModified(wxCommandEvent& event)
560 {
561         if (!mview->freezeScreen) {
562                 if (canvas)
563                         canvas->Refresh();
564                 UpdateFrameControls();
565                 MoleculeLock(mview->mol);
566                 MainView_refreshTable(mview);
567                 MoleculeUnlock(mview->mol);
568         }
569         
570         if (mview->tableIndex == kMainViewParameterTableIndex && mview->mol->parameterTableSelectionNeedsClear) {
571                 /*  Clear parameter selection if necessary  */
572                 MainViewCallback_setTableSelection(mview, NULL);
573                 mview->mol->parameterTableSelectionNeedsClear = 0;
574         }
575         
576 /*      printf("MoleculeView::OnDocumentModified invoked\n"); */
577         event.Skip();  /*  Continue processing of the notification  */
578 }
579
580 void
581 MoleculeView::OnScriptMenuModified(wxCommandEvent& event)
582 {
583         wxGetApp().UpdateScriptMenu(frame->GetMenuBar());
584         event.Skip();
585 }
586
587 void
588 MoleculeView::OnChar(wxKeyEvent &event)
589 {
590         int code = event.GetKeyCode();
591         int mode = 0;
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;
610         else {
611                 event.Skip();
612                 return;
613         }
614         if (mode > 0) {
615                 MainView_setMode(mview, mode);
616                 MainViewCallback_selectMatrixCellForMode(mview, mode);
617         }
618 }
619
620 void
621 MoleculeView::SelectTable(int idx)
622 {
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);
633                 }
634         }
635 }
636
637 void
638 MoleculeView::OnSelectTable(wxCommandEvent &event)
639 {
640         if (!isRebuildingTable) {
641                 MoleculeLock(mview->mol);
642                 SelectTable(listmenu->GetSelection());
643                 MoleculeUnlock(mview->mol);
644         }
645 }
646
647 void
648 MoleculeView::OnLeftDClickInListCtrl(wxMouseEvent &event)
649 {
650         listctrl->OnLeftDClick(event);
651         if (mview->tableIndex >= kMainViewBondTableIndex && mview->tableIndex <= kMainViewImproperTableIndex && mview->mol->par != NULL) {
652                 int row, col, i;
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)
657                         return;
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]));                        
664                 }
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;
670                         default: return;
671                 }
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);
674         }
675 }
676
677 void
678 MoleculeView::OnActivate(wxActivateEvent &event)
679 {
680         if (!event.GetActive()) {
681                 listctrl->EndEditText(true);
682         }
683         event.Skip();
684 }
685
686 #pragma mark ====== MyListCtrl data source ======
687
688 int
689 MoleculeView::GetItemCount(MyListCtrl *ctrl)
690 {
691         return MainView_numberOfRowsInTable(mview);
692 }
693
694 wxString
695 MoleculeView::GetItemText(MyListCtrl *ctrl, long row, long column) const
696 {
697         char buf[128];
698         MainView_valueForTable(mview, column, row, buf, sizeof buf);
699         wxString *str = new wxString(buf, wxConvUTF8);
700         return *str;
701 }
702
703 int
704 MoleculeView::SetItemText(MyListCtrl *ctrl, long row, long column, const wxString &value)
705 {
706         MainView_setValueForTable(mview, column, row, value.mb_str(wxConvUTF8));
707         return 0;
708 }
709
710 void
711 MoleculeView::DragSelectionToRow(MyListCtrl *ctrl, long row)
712 {
713         MainView_dragTableSelectionToRow(mview, row);
714 }
715
716 bool
717 MoleculeView::IsItemEditable(MyListCtrl *ctrl, long row, long column)
718 {
719         return MainView_isTableItemEditable(mview, column, row);
720 }
721
722 bool
723 MoleculeView::IsDragAndDropEnabled(MyListCtrl *ctrl)
724 {
725         /*  Only enabled for the atom table  */
726         return (MainView_tableType(mview) == 0);
727 }
728
729 void
730 MoleculeView::OnSelectionChanged(MyListCtrl *ctrl)
731 {
732         MainView_setSelectionFromTable(mview);
733 }
734
735 int
736 MoleculeView::SetItemColor(MyListCtrl *ctrl, long row, long col, float *fg, float *bg)
737 {
738         if (mview != NULL && mview->mol != NULL) {
739                 return MainView_setColorForTable(mview, col, row, fg, bg);
740         /*
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;
745                                 return 2;
746                         } else if (src == -1) { //  undefined parameters
747                                 bg[0] = 1.0;
748                                 bg[1] = bg[2] = 0.2;
749                                 return 2;
750                         } else if (src == 0) {  //  local parameter
751                                 bg[0] = bg[1] = 1.0;
752                                 bg[2] = 0.6;
753                                 return 2;
754                         }
755                 } else if (mview->tableIndex > 0 && mview->tableIndex < 5) {
756                         return MainView_setColorForTable(mview, col, row, fg, bg);
757                 }
758         */
759         }
760         return 0;
761 }
762
763 #pragma mark ====== Plain C interface ======
764
765 int
766 MainViewCallback_modifierFlags(void *eventRef)
767 {
768         int flags = 0;
769         unsigned modifiers;
770         wxMouseState state = ::wxGetMouseState();
771         modifiers = 0;
772         if (state.ShiftDown())
773           flags |= kShiftKeyMask;
774         if (state.AltDown())
775           flags |= kAltKeyMask;
776         return flags;
777 }
778
779 int
780 MainViewCallback_clickCount(void *eventRef)
781 {
782   wxMouseEvent *mevent = (wxMouseEvent *)eventRef;
783   if (mevent != NULL) {
784     if (mevent->LeftDClick())
785       return 2;
786     else if (mevent->LeftDown() || mevent->LeftUp())
787       return 1;
788     else return 0;
789   }
790   return 0;
791 }
792
793 void
794 MainViewCallback_lockFocus(MainView *mview)
795 {
796         if (mview != NULL && mview->ref != NULL)
797           ((MoleculeView *)(mview->ref))->canvas->SetCurrent();
798 }
799
800 void
801 MainViewCallback_unlockFocus(MainView *mview)
802 {
803   //    if (mview != NULL && mview->ref != NULL)
804   //  [[(MyWindowController *)(mview->ref) myOpenGLView] unlockFocus];
805 }
806
807 void
808 MainViewCallback_frame(MainView *mview, float *rect)
809 {
810         if (mview != NULL && mview->ref != NULL) {
811           int width, height;
812           ((MoleculeView *)(mview->ref))->canvas->GetClientSize(&width, &height);
813           rect[0] = rect[1] = 0.0;
814           rect[2] = width;
815           rect[3] = height;
816         } else {
817                 rect[0] = rect[1] = rect[2] = rect[3] = 0.0;
818         }
819 }
820
821 void
822 MainViewCallback_display(MainView *mview)
823 {
824         if (mview != NULL && mview->ref != NULL) {
825           wxWindow *canvas = ((MoleculeView *)(mview->ref))->canvas;
826           canvas->Refresh();
827           canvas->Update();
828         }
829 }
830
831 void
832 MainViewCallback_setNeedsDisplay(MainView *mview, int flag)
833 {
834   if (mview != NULL && mview->ref != NULL) {
835     if (flag)
836       ((MoleculeView *)(mview->ref))->canvas->Refresh();
837   }
838 }
839
840 void
841 MainViewCallback_setKeyboardFocus(MainView *mview)
842 {
843         if (mview != NULL && mview->ref != NULL) {
844                 ((MoleculeView *)(mview->ref))->canvas->SetFocus();
845         }
846 }
847
848 void
849 MainViewCallback_clearLabels(MainView *mview)
850 {
851         return;
852 /*
853         if (mview != NULL && mview->ref != NULL) {
854                 id view = [(MyWindowController *)(mview->ref) myOverlayView];
855                 NSRect bounds = [view bounds];
856                 [view lockFocus];
857                 NSEraseRect(bounds);
858                 [[NSColor cyanColor] set];
859                 bounds.origin.x = bounds.size.width / 2;
860                 NSFrameRect(bounds);
861                 [view unlockFocus];
862                 [view setNeedsDisplay: YES];
863         }
864 */
865 }
866
867 void
868 MainViewCallback_drawLabel(MainView *mview, const float *pos, const char *label)
869 {
870         return;
871 /*
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];
876                 [view lockFocus];
877                 [s drawAtPoint: NSMakePoint(pos[0], pos[1]) withAttributes: attr];
878                 [view unlockFocus];
879                 [view setNeedsDisplay: YES];
880         }
881 */
882 }
883
884 void
885 MainViewCallback_drawInfoText(MainView *mview, const char *label)
886 {
887         if (mview != NULL && mview->ref != NULL) {
888                 wxString labelstr(label, wxConvUTF8);
889                 ((MoleculeView *)(mview->ref))->infotext->SetLabel(labelstr);
890         }
891 }
892
893 int
894 MainViewCallback_mouseCheck(MainView *mview)
895 {
896         return 0;
897 }
898
899 void
900 MainViewCallback_selectMatrixCellForMode(MainView *mview, int mode)
901 {
902         if (mview != NULL && mview->ref != NULL)
903                 ((MoleculeView *)(mview->ref))->SelectButtonForMode(mode);
904 }
905
906 //int
907 //MainViewCallback_getTag(MainView *mview)
908 //{
909   //    if (mview != NULL && mview->ref != NULL)
910   //    return [(MyWindowController *)(mview->ref) myTag];
911   //else return -1;
912 //}
913
914 MainView *
915 MainViewCallback_viewWithTag(int tag)
916 {
917         wxList &doclist = wxGetApp().DocManager()->GetDocuments();
918         wxList::iterator iter;
919         int i = 0;
920         for (i = 0, iter = doclist.begin(); iter != doclist.end(); ++i, ++iter) {
921                 if (i == tag) {
922                         return ((MoleculeView *)(((MyDocument *)(*iter))->GetFirstView()))->mview;
923                 }
924         }
925         return NULL;
926   //wxList::compatibility_iterator iter = doclist.Item(tag);
927   //if (iter != NULL)
928   //  return (MyDocument *)(*iter)->GetFirstView()->mview;
929   //else
930 //    return NULL;
931   //    int i;
932   //    if (sMyWindowControllers == nil)
933   //            return NULL;
934   //    for (i = [sMyWindowControllers count] - 1; i >= 0; i--) {
935   //            id obj = [sMyWindowControllers objectAtIndex: i];
936   //    if ([obj myTag] == tag)
937   //                    return [obj mainView];
938   //    }
939   //    return NULL;
940 }
941
942 MainView *
943 MainViewCallback_activeView(void)
944 {
945         MoleculeView *cview = (MoleculeView *)(wxGetApp().DocManager()->GetCurrentView());
946         if (cview == NULL)
947                 return NULL;
948         else
949                 return cview->mview;
950 //      return ((MoleculeView *)(wxGetApp().DocManager()->GetCurrentView()))->mview;
951   //    return MainViewCallback_viewWithTag(sLastMainViewTag);
952 }
953
954 MainView *
955 MainViewCallback_newFromFile(const char *fname)
956 {
957   wxDocument *doc;
958   wxDocManager *manager = wxGetApp().DocManager();
959   if (fname == NULL || *fname == 0) {
960     doc = manager->CreateDocument(wxT(""), wxDOC_NEW);
961   } else {
962     wxString fnamestr(fname, wxConvUTF8);  /*  UTF8 -> wxString  */
963     doc = manager->CreateDocument(fnamestr, wxDOC_SILENT);
964   }
965   return MainViewCallback_activeView();
966 }
967
968 int
969 MainViewCallback_importFromFile(MainView *mview, const char *fname)
970 {
971   MyDocument *doc;
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);
976     return 1;
977   }
978   return 0;
979 }
980
981 void
982 MainViewCallback_getFilename(MainView *mview, char *buf, int bufsize)
983 {
984   MyDocument *doc;
985   if (mview != NULL && mview->ref != NULL && (doc = (((MoleculeView *)(mview->ref))->MolDocument())) != NULL) {
986     wxString fname;
987     fname = doc->GetFilename();
988     strncpy(buf, (const char*)fname.mb_str(wxConvUTF8), bufsize - 1);  /*  wxString -> UTF8  */
989     buf[bufsize - 1] = 0;
990   } else {
991     buf[0] = 0;
992   }
993 }
994
995 void
996 MainViewCallback_moleculeReplaced(MainView *mview, struct Molecule *mol)
997 {
998         if (mview != NULL && mview->ref != NULL) {
999                 MyDocument *doc = ((MoleculeView *)(mview->ref))->MolDocument();
1000                 if (doc != NULL)
1001                         doc->SetMolecule(mol);
1002                 MyListCtrl *listctrl = ((MoleculeView *)(mview->ref))->GetListCtrl();
1003                 if (listctrl != NULL)
1004                         listctrl->SetDataSource((MoleculeView *)(mview->ref));
1005         }
1006 }
1007
1008 typedef struct Label {
1009   //    StringTexture *tex;
1010 } Label;
1011
1012 struct Label *
1013 MainViewCallback_newLabel(MainView *mview, const char *message, float fontsize, const float *forecolor, const float *backcolor)
1014 {
1015   /*
1016         Label *label;
1017         NSDictionary *attr;
1018         NSColor *textColor, *boxColor;
1019         label = (Label *)malloc(sizeof(Label));
1020         if (label == NULL)
1021                 return NULL;
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]];
1026         else
1027                 textColor = [NSColor whiteColor];
1028         if (backcolor != NULL)
1029                 boxColor = [NSColor colorWithDeviceRed: backcolor[0] green: backcolor[1] blue: backcolor[2] alpha: backcolor[3]];
1030         else
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);
1040         return label;
1041   */
1042 }
1043
1044 void
1045 MainViewCallback_releaseLabel(struct Label *label)
1046 {
1047   /*    if (label != NULL) {
1048                 [label->tex release];
1049                 free(label);
1050         }
1051   */
1052 }
1053
1054 void
1055 MainViewCallback_drawLabelAtPoint(struct Label *label, const float *pos)
1056 {
1057   /*
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);
1063         //      glPushMatrix();
1064         //      glTranslatef(0.0f, 0.0f, pos[3]);
1065                 [label->tex drawAtPoint: NSMakePoint(pos[0], pos[1]) withDepth: pos[2]];
1066         //      glPopMatrix();
1067         //      glMatrixMode (matrixMode);
1068         }
1069   */
1070 }
1071
1072 void
1073 MainViewCallback_labelSize(struct Label *label, float *outSize)
1074 {
1075   /*    if (label != NULL) {
1076                 NSSize size = [label->tex frameSize];
1077                 if (outSize != NULL) {
1078                         outSize[0] = size.width;
1079                         outSize[1] = size.height;
1080                 }
1081         }
1082   */
1083 }
1084
1085 #pragma mark ====== Plain C Interface (MyListCtrl) ======
1086
1087 /*  These interface functions are also used for accessing MyListCtrl of GlobalParameterFrame (when mview == NULL) */
1088
1089 static MyListCtrl *
1090 s_MyListCtrlFromMainView(MainView *mview)
1091 {
1092         if (mview == NULL)
1093                 return wxGetApp().GetGlobalParameterListCtrl();
1094         if (mview != NULL && mview->ref != NULL)
1095                 return ((MoleculeView *)(mview->ref))->GetListCtrl();
1096         else return NULL;
1097 }
1098
1099 void
1100 MainViewCallback_selectTable(MainView *mview, int idx)
1101 {
1102         if (mview != NULL && mview->ref != NULL)
1103                 ((MoleculeView *)(mview->ref))->SelectTable(idx);
1104 }
1105
1106 int
1107 MainViewCallback_numberOfTableColumns(MainView *mview)
1108 {
1109         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1110         if (listctrl != NULL)
1111                 return listctrl->GetColumnCount();
1112         else return 0;
1113 }
1114
1115 int
1116 MainViewCallback_addTableColumn(MainView *mview, const char *name, int width, int editable)
1117 {
1118         int idx;
1119         wxString nstr(name, wxConvUTF8);
1120         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1121         if (listctrl == NULL)
1122                 return 0;
1123         idx = listctrl->GetColumnCount();
1124         listctrl->InsertColumn(idx, nstr, wxLIST_FORMAT_LEFT);
1125         listctrl->SetColumnWidth(idx, width * 10);
1126         return idx;
1127 }
1128
1129 int
1130 MainViewCallback_removeTableColumnAtIndex(MainView *mview, int idx)
1131 {
1132         int ncolumns;
1133         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1134         if (listctrl == NULL)
1135                 return 0;
1136         ncolumns = listctrl->GetColumnCount();
1137         if (idx >= 0 && idx < ncolumns) {
1138                 listctrl->DeleteColumn(idx);
1139                 ncolumns--;
1140         }
1141         return ncolumns;
1142 }
1143
1144 void
1145 MainViewCallback_reloadTableData(MainView *mview)
1146 {
1147         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1148         if (listctrl != NULL)
1149                 listctrl->RefreshTable();
1150 /*      
1151         int nrows = MainView_numberOfRowsInTable(mview);
1152         listctrl->SetItemCount(nrows);
1153         if (nrows > 0)
1154                 listctrl->RefreshItems(0, nrows - 1);
1155 */
1156 }
1157
1158 void
1159 MainViewCallback_setTableSelection(MainView *mview, IntGroup *selection)
1160 {
1161         int i, n, n1, n2;
1162         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1163         if (listctrl == NULL)
1164                 return;
1165         n = 0;
1166         listctrl->EnableSelectionChangeNotification(false);
1167         if (selection != NULL) {
1168                 for (i = 0; (n1 = IntGroupGetStartPoint(selection, i)) >= 0; i++) {
1169                         n2 = IntGroupGetEndPoint(selection, i);
1170                         while (n < n1) {
1171                                 listctrl->SetItemState(n, 0, wxLIST_STATE_SELECTED);
1172                                 n++;
1173                         }
1174                         while (n < n2) {
1175                                 listctrl->SetItemState(n, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
1176                                 n++;
1177                         }
1178                 }
1179         }
1180         listctrl->RefreshTable();
1181         n1 = MainView_numberOfRowsInTable(mview);
1182         while (n < n1) {
1183                 listctrl->SetItemState(n, 0, wxLIST_STATE_SELECTED);
1184                 n++;
1185         }
1186 //      listctrl->RefreshItems(0, n1 - 1);
1187         {
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);
1193         }
1194 }
1195
1196 IntGroup *
1197 MainViewCallback_getTableSelection(MainView *mview)
1198 {
1199         int i, n;
1200         IntGroup *ig;
1201         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1202         if (listctrl == NULL)
1203                 return NULL;
1204         ig = IntGroupNew();
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);
1209         }
1210         return ig;
1211 }
1212
1213 void
1214 MainViewCallback_showTable(MainView *mview)
1215 {
1216   //    if (mview != NULL && mview->ref != NULL) {
1217   //    MyDocument *doc = (MyDocument *)[(id)(mview->ref) document];
1218   //    [doc showTable: doc];
1219   //}
1220 }
1221
1222 void
1223 MainViewCallback_hideTable(MainView *mview)
1224 {
1225   //    if (mview != NULL && mview->ref != NULL) {
1226   //    MyDocument *doc = (MyDocument *)[(id)(mview->ref) document];
1227   //            [doc hideTable: doc];
1228   //    }
1229 }
1230
1231 void
1232 MainViewCallback_ensureVisible(MainView *mview, int row)
1233 {
1234         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1235         if (listctrl != NULL)
1236                 listctrl->EnsureVisible(row);
1237 }
1238
1239 void
1240 MainViewCallback_startEditText(MainView *mview, int row, int column)
1241 {
1242         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1243         if (listctrl != NULL)
1244                 listctrl->StartEditText(row, column);
1245 }
1246