OSDN Git Service

The separator line in the Ruby Dialog was not working correctly.
[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 #include "MyMBConv.h"
43
44 #include "wx/tglbtn.h"
45 #include "wx/listctrl.h"
46 #include "wx/splitter.h"
47 #include "wx/choice.h"
48 #include "wx/font.h"
49
50 //#include "../MolLib/Ruby_bind/Molby_extern.h"
51
52 enum {
53         myID_RotButton = 500,
54         myID_TransButton,
55         myID_ScaleButton,
56         myID_SelectButton,
57         myID_BondButton,
58         myID_EraseButton,
59         myID_RotateBondSlider,
60         myID_RotateXSlider,
61         myID_RotateYSlider,
62         myID_FrameControlPanel,
63         myID_FrameSlider,
64         myID_JumpToStartButton,
65         myID_PlayBackwardButton,
66         myID_FrameText,
67         myID_PlayForwardButton,
68         myID_JumpToEndButton,
69         myID_Table,
70         myID_TableMenu
71 };
72
73 IMPLEMENT_DYNAMIC_CLASS(MoleculeView, wxView)
74
75 BEGIN_EVENT_TABLE(MoleculeView, wxView)
76         EVT_TOGGLEBUTTON(myID_RotButton, MoleculeView::OnButtonPressed)
77         EVT_TOGGLEBUTTON(myID_TransButton, MoleculeView::OnButtonPressed)
78         EVT_TOGGLEBUTTON(myID_ScaleButton, MoleculeView::OnButtonPressed)
79         EVT_TOGGLEBUTTON(myID_SelectButton, MoleculeView::OnButtonPressed)
80         EVT_TOGGLEBUTTON(myID_BondButton, MoleculeView::OnButtonPressed)
81         EVT_TOGGLEBUTTON(myID_EraseButton, MoleculeView::OnButtonPressed)
82         EVT_COMMAND(wxID_ANY, MySliderEvent, MoleculeView::OnSliderAction)
83         EVT_COMMAND_SCROLL(myID_FrameSlider, MoleculeView::OnFrameSliderAction)
84         EVT_TEXT_ENTER(myID_FrameText, MoleculeView::OnFrameTextAction)
85         EVT_CHOICE(myID_TableMenu, MoleculeView::OnSelectTable)
86         EVT_ACTIVATE(MoleculeView::OnActivate)
87 END_EVENT_TABLE()
88 #define ConnectMouseDownEvents(src, func, target) \
89         (src->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(func), NULL, target), \
90         src->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(func), NULL, target))
91                                  
92                                  
93 bool
94 MoleculeView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
95 {
96         int i;
97
98         // Make a document frame
99         frame = new wxDocMDIChildFrame(doc, this, GetMainFrame(), wxID_ANY, _T("New Molby Document"),
100                                                    wxPoint(10, 24), wxSize(680, 400),
101                                                    wxDEFAULT_FRAME_STYLE |
102                                                    wxNO_FULL_REPAINT_ON_RESIZE);
103
104         canvas = NULL;
105         mview = NULL;
106         listmenu = NULL;
107         listctrl = NULL;
108         file_history_menu = NULL;
109         edit_menu = NULL;
110         memset(tbuttons, 0, sizeof(tbuttons));
111         infotext = NULL;
112         frameControlPanel = NULL;
113         frameSlider = NULL;
114         frameText = NULL;
115         isRebuildingTable = false;
116         
117         wxMenuBar *menu_bar = wxGetApp().CreateMenuBar(1, &file_history_menu, &edit_menu);
118         
119         // Associate the menu bar with the frame
120         frame->SetMenuBar(menu_bar);
121
122         // Associate the edit menu with the command processor
123         doc->GetCommandProcessor()->SetEditMenu(edit_menu);
124         
125     mview = MainView_newMainView(this);
126         
127         // Create the window content
128         
129         //  A splitter window embraces a grid (left) and main screen (right)
130         wxSplitterWindow *splitter = new wxSplitterWindow(frame, -1, wxDefaultPosition, wxDefaultSize, wxSP_3D | wxSP_LIVE_UPDATE);
131         
132         //  Create the left half
133         //  A panel containing a popup menu and a list window
134         wxPanel *panel0 = new wxPanel(splitter);
135         {
136                 char buf[16];
137                 wxBoxSizer *sizer0;
138                 sizer0 = new wxBoxSizer(wxVERTICAL);
139                 wxArrayString choiceItems;
140                 for (i = 0; ; i++) {
141                         MainView_tableTitleForIndex(mview, i, buf, sizeof buf);
142                         if (buf[0] == 0)
143                                 break;
144                         wxString itemTitle(buf, WX_DEFAULT_CONV);
145                         choiceItems.Add(itemTitle);
146                 }
147         /*      static wxString choiceItems[] = {
148                         wxT("atoms"), wxT("bonds"), wxT("angles"), wxT("dihedrals"), wxT("impropers"), wxT("MO info")
149                 }; */
150                 
151                 listmenu = new wxChoice(panel0, myID_TableMenu, wxDefaultPosition, wxDefaultSize, choiceItems);
152                 sizer0->Add(listmenu, 0, wxALL, 0);
153                 
154                 listctrl = new MyListCtrl();
155                 listctrl->Create(panel0, myID_Table, wxDefaultPosition, wxDefaultSize);
156                 sizer0->Add(listctrl, 1, wxALL | wxEXPAND, 0);
157                 panel0->SetSizer(sizer0);
158         }
159                 
160         //  Create the right half
161         //  A panel containing MyGLCanvas, buttons, sliders, etc.
162         wxPanel *panel1 = new wxPanel(splitter);
163         
164         {       //  Vertical sizer containing [sizer2, sizer3, sizer4]
165                 wxBoxSizer *sizer1;
166                 sizer1 = new wxBoxSizer(wxVERTICAL);
167                 
168                 {       //  Horizontal sizer containing [button0, button1, ..., button5, infotext]
169                         wxBoxSizer *sizer2;
170                         sizer2 = new wxBoxSizer(wxHORIZONTAL);
171                         
172                         {       // Button0..5 (Rot/Trans/Scale/Select/Bond/Erase)
173                                 wxString labels[] = {
174                                         wxT("Rot"), wxT("Trans"), wxT("Scale"), wxT("Select"), wxT("Bond"), wxT("Erase")
175                                 };
176                                 wxWindowID ids[] = {
177                                         myID_RotButton, myID_TransButton, myID_ScaleButton, 
178                                         myID_SelectButton, myID_BondButton, myID_EraseButton
179                                 };
180                                 for (i = 0; i < 6; i++) {
181                                         tbuttons[i] = new wxToggleButton(panel1, ids[i], labels[i], wxDefaultPosition, wxSize(40, 16));
182                                         sizer2->Add(tbuttons[i], 0, wxALL | wxEXPAND, 3);
183                                 }
184                                 tbuttons[0]->SetValue(true);
185                         }
186                         {       // Information text
187                                 infotext = new wxStaticText(panel1, -1, wxT(""), wxDefaultPosition, wxSize(40, 16), wxST_NO_AUTORESIZE | wxBORDER_SUNKEN);
188                                 infotext->SetMinSize(wxSize(80, 32));
189                                 infotext->SetFont(*wxSMALL_FONT);
190                                 sizer2->Add(infotext, 1, wxALL | wxEXPAND, 3);   // Can expand horizontally
191                         }
192                         
193                         sizer1->Add(sizer2, 0, wxALL | wxEXPAND, 0);
194                 }
195                 
196                 {       // Horizontal sizer containing [sizer31, sizer32, sizer33]
197                         wxBoxSizer *sizer3 = new wxBoxSizer(wxHORIZONTAL);
198                         
199                         {       // Vertical sizer containing [button, mySlider]
200                                 wxBoxSizer *sizer31 = new wxBoxSizer(wxVERTICAL);
201                                 {       // "Rotate bond" button and mySlider
202                                         #include "../bitmaps/rotate_bond.xpm"
203                                         wxBitmap bmp1(rotate_bond_xpm, wxBITMAP_TYPE_XPM);
204                                         wxBitmapButton *button1 = new wxBitmapButton(panel1, -1, bmp1, wxDefaultPosition, wxSize(21, 21));
205                                         sizer31->Add(button1, 0, 0, 0);
206                                         button1->Disable();
207                                         MySlider *slider1 = new MySlider(panel1, myID_RotateBondSlider, wxVERTICAL, wxDefaultPosition, wxSize(21, 21));
208                                         sizer31->Add(slider1, 1, wxEXPAND);
209                                 }
210                                 sizer3->Add(sizer31, 0, wxALL | wxEXPAND, 0);
211                         }
212                         
213                         {       // Vertical sizer containing [Canvas, [button, mySlider]]
214                                 wxBoxSizer *sizer32 = new wxBoxSizer(wxVERTICAL);
215                                 {
216                                         canvas = new MyGLCanvas(this, panel1, wxDefaultPosition, wxSize(100, 100));
217                                         sizer32->Add(canvas, 1, wxALL | wxEXPAND, 0);
218                                         
219                                         //  Let the MyGLCanvas pass the keyboard event to this
220                                         canvas->Connect(-1, wxEVT_CHAR, wxKeyEventHandler(MoleculeView::OnChar), NULL, this);
221                                 }
222                                 {
223                                         wxBoxSizer *sizer321 = new wxBoxSizer(wxHORIZONTAL);
224                                         {
225                                                 #include "../bitmaps/rotate_y.xpm"
226                                                 wxBitmap bmp2(rotate_y_xpm, wxBITMAP_TYPE_XPM);
227                                                 wxBitmapButton *button2 = new wxBitmapButton(panel1, -1, bmp2, wxDefaultPosition, wxSize(21, 21));
228                                                 sizer321->Add(button2, 0, 0, 0);
229                                                 button2->Disable();
230                                                 MySlider *slider2 = new MySlider(panel1, myID_RotateYSlider, wxHORIZONTAL, wxDefaultPosition, wxSize(21, 21));
231                                                 sizer321->Add(slider2, 1, wxEXPAND);
232                                         }
233                                         sizer32->Add(sizer321, 0, wxEXPAND);
234                                 }
235                                 sizer3->Add(sizer32, 1, wxEXPAND);
236                         }
237
238                         {       // Vertical sizer containing [button, mySlider]
239                                 wxBoxSizer *sizer33 = new wxBoxSizer(wxVERTICAL);
240                                 {       // "Rotate bond" button and mySlider
241                                         #include "../bitmaps/rotate_x.xpm"
242                                         wxBitmap bmp3(rotate_x_xpm, wxBITMAP_TYPE_XPM);
243                                         wxBitmapButton *button3 = new wxBitmapButton(panel1, -1, bmp3, wxDefaultPosition, wxSize(21, 21));
244                                         button3->Disable();
245                                         sizer33->Add(button3, 0, 0, 0);
246                                         
247                                         MySlider *slider3 = new MySlider(panel1, myID_RotateXSlider, wxVERTICAL, wxDefaultPosition, wxSize(21, 21));
248                                         sizer33->Add(slider3, 1, wxEXPAND);
249                                 }
250                                 sizer3->Add(sizer33, 0, wxALL | wxEXPAND, 0);
251                         }
252                         
253                         sizer1->Add(sizer3, 1, wxALL | wxEXPAND, 0);
254                 }
255                 
256                 {       //  Horizontal sizer containing frame controls
257                         
258                         const int height = 18;
259                         frameControlPanel = new wxPanel(panel1, myID_FrameControlPanel, wxDefaultPosition, wxSize(200, height));
260                         wxBoxSizer *sizer4 = new wxBoxSizer(wxHORIZONTAL);
261                         {
262                                 frameSlider = new wxSlider(frameControlPanel, myID_FrameSlider, 0, 0, 0, wxDefaultPosition, wxSize(40, height - 2));
263                                 sizer4->Add(frameSlider, 1, wxALL | wxEXPAND, 1);
264                         
265                                 #include "../bitmaps/jump_to_start.xpm"
266                                 wxBitmap bmp41(jump_to_start_xpm, wxBITMAP_TYPE_XPM);
267                                 wxBitmapButton *button41 = new wxBitmapButton(frameControlPanel, myID_JumpToStartButton, bmp41, wxDefaultPosition, wxSize(16, height));
268                                 sizer4->Add(button41, 0, wxEXPAND);
269                                 ConnectMouseDownEvents(button41, MoleculeView::OnFrameButtonAction, this);
270
271                                 #include "../bitmaps/play_backward.xpm"
272                                 wxBitmap bmp42(play_backward_xpm, wxBITMAP_TYPE_XPM);
273                                 wxBitmapButton *button42 = new wxBitmapButton(frameControlPanel, myID_PlayBackwardButton, bmp42, wxDefaultPosition, wxSize(16, height));
274                                 sizer4->Add(button42, 0, wxEXPAND);
275                                 ConnectMouseDownEvents(button42, MoleculeView::OnFrameButtonAction, this);
276                                 
277                                 {
278                                         frameText = new wxTextCtrl(frameControlPanel, myID_FrameText, wxT(""), wxDefaultPosition, wxSize(40, height));
279                                         wxFont font(9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
280                                         wxTextAttr attr(*wxBLACK, wxNullColour, font);
281                                         frameText->SetDefaultStyle(attr);
282                                         sizer4->Add(frameText, 0, wxEXPAND);
283                                 }
284                         
285                                 #include "../bitmaps/play_forward.xpm"
286                                 wxBitmap bmp43(play_forward_xpm, wxBITMAP_TYPE_XPM);
287                                 wxBitmapButton *button43 = new wxBitmapButton(frameControlPanel, myID_PlayForwardButton, bmp43, wxDefaultPosition, wxSize(16, height));
288                                 sizer4->Add(button43, 0, wxEXPAND);
289                                 ConnectMouseDownEvents(button43, MoleculeView::OnFrameButtonAction, this);
290
291                                 #include "../bitmaps/jump_to_end.xpm"
292                                 wxBitmap bmp44(jump_to_end_xpm, wxBITMAP_TYPE_XPM);
293                                 wxBitmapButton *button44 = new wxBitmapButton(frameControlPanel, myID_JumpToEndButton, bmp44, wxDefaultPosition, wxSize(16, height));
294                                 sizer4->Add(button44, 0, wxEXPAND);
295                                 ConnectMouseDownEvents(button44, MoleculeView::OnFrameButtonAction, this);
296                                 
297                                 wxPanel *spacer = new wxPanel(frameControlPanel, -1, wxDefaultPosition, wxSize(21, height));
298                                 sizer4->Add(spacer, 0, wxEXPAND);
299                         }
300                         frameControlPanel->SetSizer(sizer4);
301                         sizer1->Add(frameControlPanel, 0, wxALL | wxEXPAND, 0);
302                 //      controls->Disable();
303                 }
304
305                 panel1->SetSizer(sizer1);
306         }
307
308         splitter->SplitVertically(panel0, panel1);
309
310         wxBoxSizer *mainsizer = new wxBoxSizer(wxHORIZONTAL);
311         mainsizer->Add(splitter, 1, wxEXPAND);
312         frame->SetSizer(mainsizer);
313
314         mainsizer->Layout();
315         splitter->SetSashPosition(240, true);
316         
317         //  Associate the molecule with the main view
318         MainView_setMolecule(mview, ((MyDocument *)doc)->GetMolecule());
319         
320         //  Initialize table view
321         MainView_createColumnsForTableAtIndex(mview, 0);
322
323         //  Select table popup
324         listmenu->SetSelection(0);
325         
326 #if defined(__X__) || defined(__WXMAC__)
327     // X seems to require a forced resize
328     int x, y;
329     frame->GetSize(&x, &y);
330     frame->SetSize(wxDefaultCoord, wxDefaultCoord, x, y);
331 #endif
332     frame->Show(true);
333     Activate(true);
334
335         //  Initial keyboard focus is on the GL canvas (to accept 'S' for scale, etc.)
336         canvas->SetFocus();
337         
338         //  Connect the notification handler
339         doc->Connect(MyDocumentEvent_documentModified, MyDocumentEvent, wxCommandEventHandler(MoleculeView::OnDocumentModified), NULL, this);
340
341         wxGetApp().Connect(MyDocumentEvent_scriptMenuModified, MyDocumentEvent, wxCommandEventHandler(MoleculeView::OnScriptMenuModified), NULL, this);
342
343         //  Intercept the double-click handler of MyListCtrl
344         listctrl->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(MoleculeView::OnLeftDClickInListCtrl), NULL, this);
345                                         
346     return true;
347 }
348
349 void
350 MoleculeView::OnDraw(wxDC *dc)
351 {
352         if (mview != NULL && mview->mol != NULL) {
353                 MoleculeLock(mview->mol);
354                 MainView_drawModel(mview);
355                 MoleculeUnlock(mview->mol);
356         }
357 }
358
359 void
360 MoleculeView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
361 {
362         if (canvas)
363                 canvas->Refresh();
364
365 /*  Maybe necessary in some platforms (not in MacOSX and MSW)  */
366 #if 0
367   if (canvas) {
368       wxClientDC dc(canvas);
369       dc.Clear();
370       OnDraw(&dc);
371   }
372 #endif
373 }
374
375 bool
376 MoleculeView::OnClose(bool deleteWindow)
377 {
378         if (!GetDocument()->Close())
379                 return false;
380
381         //  Dispose relationship between MainView and Molecule
382         MainView_setMolecule(mview, NULL);
383         //  Release the MainView object
384         MainView_release(mview);
385         mview = NULL;
386
387         //  Dispose Connection between DocManager and file history menu
388         wxGetApp().DocManager()->FileHistoryRemoveMenu(file_history_menu);
389
390         // Clear the canvas in case we're in single-window mode,
391         // and the canvas stays.
392 /*      canvas->ClearBackground();
393         canvas->view = NULL;
394         canvas = NULL;
395
396         wxString s(wxTheApp->GetAppName());
397         if (frame)
398                 frame->SetTitle(s);
399
400         SetFrame(NULL);
401
402         Activate(false); */
403
404         if (deleteWindow) {
405                 frame->Destroy();
406         //      delete frame;
407                 return true;
408         }
409         return true;
410 }
411
412 void
413 MoleculeView::UpdateFrameControlValues()
414 {
415         if (mview == NULL || mview->mol == NULL)
416                 return;
417         wxString str;
418         int cframe;
419         cframe = mview->mol->cframe;
420         str.Printf(_T("%d"), cframe);
421         frameText->SetValue(str);
422         frameSlider->SetValue(cframe);
423 }
424
425 void
426 MoleculeView::UpdateFrameControls()
427 {
428         int nframes;
429         bool enabled = false;
430         if (mview != NULL && mview->mol != NULL) {
431                 MoleculeLock(mview->mol);
432                 nframes = MoleculeGetNumberOfFrames(mview->mol);
433                 MoleculeUnlock(mview->mol);
434                 if (nframes > 1)
435                         enabled = true;
436         }
437         
438         frameControlPanel->Enable(enabled);
439         if (enabled) {
440                 frameSlider->SetRange(0, nframes - 1);
441                 UpdateFrameControlValues();
442         } else {
443                 frameSlider->SetRange(0, 0);
444                 frameText->SetValue(_T(""));
445         }
446         frameControlPanel->Update();
447 }
448
449 void
450 MoleculeView::SelectButtonForMode(int mode)
451 {
452         int i;
453         if (mode >= 1 && mode <= 6) {
454                 for (i = 0; i < 6; i++) {
455                         tbuttons[i]->SetValue((i == mode - 1));
456                 }
457         }
458         MainViewCallback_setKeyboardFocus(mview);
459 }
460
461 void
462 MoleculeView::OnButtonPressed(wxCommandEvent& event)
463 {
464         int eventId = event.GetId();
465         int mode = eventId - myID_RotButton + kTrackballRotateMode;
466         MainView_setMode(mview, mode);
467         SelectButtonForMode(mode);
468 }
469
470 void
471 MoleculeView::OnSliderAction(wxCommandEvent& event)
472 {
473         int eventId = event.GetId();
474         int mode = eventId - myID_RotateBondSlider + 1;
475         MySlider *sender = (MySlider *)event.GetEventObject();
476         float angle = sender->GetFloatValue();
477         int mouseStatus = sender->GetMouseStatus();
478         MoleculeLock(mview->mol);
479         MainView_rotateBySlider(mview, angle * 3.1415927 * 2, mode, mouseStatus, MainViewCallback_modifierFlags(NULL));
480         MoleculeUnlock(mview->mol);
481 }
482
483 void
484 MoleculeView::OnFrameButtonAction(wxMouseEvent &event)
485 {
486         int ival, nframes, bid;
487         if (mview == NULL || mview->mol == NULL)
488                 goto skip;
489         nframes = MoleculeGetNumberOfFrames(mview->mol);
490         if (nframes == 0)
491                 goto skip;
492         bid = event.GetId();
493         if (bid == myID_JumpToStartButton) {
494                 ival = 0;
495         } else if (bid == myID_JumpToEndButton) {
496                 ival = nframes - 1;
497         } else if (bid == myID_PlayForwardButton) {
498                 ival = (mview->mol->cframe + 1) % nframes;
499         } else if (bid == myID_PlayBackwardButton) {
500                 ival = (mview->mol->cframe + nframes - 1) % nframes;
501         }
502         //  TODO: implement continuous move
503         if (ival >= 0 && ival < nframes) {
504                 MoleculeLock(mview->mol);
505                 MoleculeSelectFrame(mview->mol, ival, 1);
506                 MoleculeUnlock(mview->mol);
507                 MainViewCallback_display(mview);
508                 UpdateFrameControlValues();
509         }
510         
511 skip:
512         event.Skip();
513 }
514
515 void
516 MoleculeView::OnFrameSliderAction(wxScrollEvent &event)
517 {
518         int ival, nframes;
519         if (mview == NULL || mview->mol == NULL)
520                 return;
521         MoleculeLock(mview->mol);
522         nframes = MoleculeGetNumberOfFrames(mview->mol);
523         if (nframes != 0) {
524                 ival = frameSlider->GetValue();
525                 if (ival >= 0 && ival < nframes) {
526                         MoleculeSelectFrame(mview->mol, ival, 1);
527                         MoleculeUnlock(mview->mol);
528                         MainViewCallback_display(mview);
529                         UpdateFrameControlValues();
530                         return;
531                 }
532         }
533         MoleculeUnlock(mview->mol);
534 }
535
536 void
537 MoleculeView::OnFrameTextAction(wxCommandEvent &event)
538 {
539         int ival, nframes;
540         wxString str;
541         if (mview == NULL || mview->mol == NULL)
542                 return;
543         MoleculeLock(mview->mol);
544         nframes = MoleculeGetNumberOfFrames(mview->mol);
545         if (nframes != 0) {
546                 str = frameText->GetValue();
547                 ival = atoi((const char *)str.mb_str(WX_DEFAULT_CONV));
548                 if (ival >= 0 && ival < nframes) {
549                         MoleculeSelectFrame(mview->mol, ival, 1);
550                         MoleculeUnlock(mview->mol);
551                         MainViewCallback_display(mview);
552                         UpdateFrameControlValues();
553                         return;
554                 }
555         }
556         MoleculeUnlock(mview->mol);
557 }
558
559 void
560 MoleculeView::OnDocumentModified(wxCommandEvent& event)
561 {
562         if (!mview->freezeScreen) {
563                 if (canvas)
564                         canvas->Refresh();
565                 UpdateFrameControls();
566                 MoleculeLock(mview->mol);
567                 MainView_refreshTable(mview);
568                 MoleculeUnlock(mview->mol);
569         }
570         
571         if (mview->tableIndex == kMainViewParameterTableIndex && mview->mol->parameterTableSelectionNeedsClear) {
572                 /*  Clear parameter selection if necessary  */
573                 MainViewCallback_setTableSelection(mview, NULL);
574                 mview->mol->parameterTableSelectionNeedsClear = 0;
575         }
576         
577 /*      printf("MoleculeView::OnDocumentModified invoked\n"); */
578         event.Skip();  /*  Continue processing of the notification  */
579 }
580
581 void
582 MoleculeView::OnScriptMenuModified(wxCommandEvent& event)
583 {
584         wxGetApp().UpdateScriptMenu(frame->GetMenuBar());
585         event.Skip();
586 }
587
588 void
589 MoleculeView::OnChar(wxKeyEvent &event)
590 {
591         int code = event.GetKeyCode();
592         int mode = 0;
593         bool noMod = ((event.GetModifiers() | wxMOD_SHIFT) == wxMOD_SHIFT);
594 //      MyAppCallback_showScriptMessage("MoleculeView::OnChar invoked\n");
595         if (code == WXK_BACK || code == WXK_DELETE || code == 0x7f || code == 8) {
596                 MoleculeLock(mview->mol);
597                 MainView_delete(mview);
598                 MoleculeUnlock(mview->mol);
599         } else if (noMod && (code == 'r' || code == 'R'))
600                 mode = kTrackballRotateMode;
601         else if (noMod && (code == 't' || code == 'T'))
602                 mode = kTrackballTranslateMode;
603         else if (noMod && (code == 's' || code == 'S'))
604                 mode = kTrackballScaleMode;
605         else if (noMod && (code == ' '))
606                 mode = kTrackballSelectionMode;
607         else if (noMod && (code == 'b' || code == 'B'))
608                 mode = kTrackballCreateMode;
609         else if (noMod && (code == 'e' || code == 'E'))
610                 mode = kTrackballEraseMode;
611         else {
612                 event.Skip();
613                 return;
614         }
615         if (mode > 0) {
616                 MainView_setMode(mview, mode);
617                 MainViewCallback_selectMatrixCellForMode(mview, mode);
618         }
619 }
620
621 void
622 MoleculeView::SelectTable(int idx)
623 {
624         if (idx >= 0 && idx < listmenu->GetCount() && idx != mview->tableIndex) {
625                 isRebuildingTable = true;
626                 listmenu->SetSelection(idx);
627                 MainView_createColumnsForTableAtIndex(mview, idx);
628                 isRebuildingTable = false;
629                 MoleculeLock(mview->mol);
630                 MainView_refreshTable(mview);
631                 MoleculeUnlock(mview->mol);
632                 if (idx == kMainViewParameterTableIndex || idx == kMainViewMOTableIndex) {
633                         MainViewCallback_setTableSelection(mview, NULL);
634                 }
635         }
636 }
637
638 void
639 MoleculeView::OnSelectTable(wxCommandEvent &event)
640 {
641         if (!isRebuildingTable) {
642                 MoleculeLock(mview->mol);
643                 SelectTable(listmenu->GetSelection());
644                 MoleculeUnlock(mview->mol);
645         }
646 }
647
648 void
649 MoleculeView::OnLeftDClickInListCtrl(wxMouseEvent &event)
650 {
651         listctrl->OnLeftDClick(event);
652         if (mview->tableIndex >= kMainViewBondTableIndex && mview->tableIndex <= kMainViewImproperTableIndex && mview->mol->par != NULL) {
653                 int row, col, i;
654                 char names[64], types[64], value[20], params[3][20];
655                 char *ptype, *parstr;
656                 wxPoint pos = event.GetPosition();
657                 if (!listctrl->FindItemAtPosition(pos, &row, &col) || col < 4)
658                         return;
659                 /*  Start editing the local parameter; open a separate dialog  */
660                 MainView_valueForTable(mview, 1, row, names, sizeof names);
661                 MainView_valueForTable(mview, 2, row, types, sizeof types);
662                 MainView_valueForTable(mview, 3, row, value, sizeof value);
663                 for (i = 0; i < 3; i++) {
664                         MainView_valueForTable(mview, 4 + i, row, params[i], sizeof(params[0]));                        
665                 }
666                 switch (mview->tableIndex) {
667                         case kMainViewBondTableIndex: ptype = "bond"; break;
668                         case kMainViewAngleTableIndex: ptype = "angle"; break;
669                         case kMainViewDihedralTableIndex: ptype = "dihedral"; break;
670                         case kMainViewImproperTableIndex: ptype = "improper"; break;
671                         default: return;
672                 }
673                 asprintf(&parstr, "%s %s %s", params[0], params[1], params[2]);
674                 MolActionCreateAndPerform(mview->mol, SCRIPT_ACTION("sssss"), "cmd_edit_local_parameter_in_mainview", ptype, names, types, value, parstr);
675         }
676 }
677
678 void
679 MoleculeView::OnActivate(wxActivateEvent &event)
680 {
681         if (!event.GetActive()) {
682                 listctrl->EndEditText(true);
683         }
684         event.Skip();
685 }
686
687 #pragma mark ====== MyListCtrl data source ======
688
689 int
690 MoleculeView::GetItemCount(MyListCtrl *ctrl)
691 {
692         return MainView_numberOfRowsInTable(mview);
693 }
694
695 wxString
696 MoleculeView::GetItemText(MyListCtrl *ctrl, long row, long column) const
697 {
698         char buf[128];
699         MainView_valueForTable(mview, column, row, buf, sizeof buf);
700         wxString *str = new wxString(buf, WX_DEFAULT_CONV);
701         return *str;
702 }
703
704 int
705 MoleculeView::SetItemText(MyListCtrl *ctrl, long row, long column, const wxString &value)
706 {
707         MainView_setValueForTable(mview, column, row, value.mb_str(WX_DEFAULT_CONV));
708         return 0;
709 }
710
711 void
712 MoleculeView::DragSelectionToRow(MyListCtrl *ctrl, long row)
713 {
714         MainView_dragTableSelectionToRow(mview, row);
715 }
716
717 bool
718 MoleculeView::IsItemEditable(MyListCtrl *ctrl, long row, long column)
719 {
720         return MainView_isTableItemEditable(mview, column, row);
721 }
722
723 bool
724 MoleculeView::IsDragAndDropEnabled(MyListCtrl *ctrl)
725 {
726         /*  Only enabled for the atom table  */
727         return (MainView_tableType(mview) == 0);
728 }
729
730 void
731 MoleculeView::OnSelectionChanged(MyListCtrl *ctrl)
732 {
733         MainView_setSelectionFromTable(mview);
734 }
735
736 int
737 MoleculeView::SetItemColor(MyListCtrl *ctrl, long row, long col, float *fg, float *bg)
738 {
739         if (mview != NULL && mview->mol != NULL) {
740                 return MainView_setColorForTable(mview, col, row, fg, bg);
741         /*
742                 if (mview->tableIndex == kMainViewParameterTableIndex && col == -1) {
743                         int src = ParameterTableGetItemSource(mview->mol->par, row);
744                         if (src == -2) {  // separator line 
745                                 bg[0] = bg[1] = bg[2] = 0.6;
746                                 return 2;
747                         } else if (src == -1) { //  undefined parameters
748                                 bg[0] = 1.0;
749                                 bg[1] = bg[2] = 0.2;
750                                 return 2;
751                         } else if (src == 0) {  //  local parameter
752                                 bg[0] = bg[1] = 1.0;
753                                 bg[2] = 0.6;
754                                 return 2;
755                         }
756                 } else if (mview->tableIndex > 0 && mview->tableIndex < 5) {
757                         return MainView_setColorForTable(mview, col, row, fg, bg);
758                 }
759         */
760         }
761         return 0;
762 }
763
764 #pragma mark ====== Plain C interface ======
765
766 int
767 MainViewCallback_modifierFlags(void *eventRef)
768 {
769         int flags = 0;
770         unsigned modifiers;
771         wxMouseState state = ::wxGetMouseState();
772         modifiers = 0;
773         if (state.ShiftDown())
774           flags |= kShiftKeyMask;
775         if (state.AltDown())
776           flags |= kAltKeyMask;
777         return flags;
778 }
779
780 int
781 MainViewCallback_clickCount(void *eventRef)
782 {
783   wxMouseEvent *mevent = (wxMouseEvent *)eventRef;
784   if (mevent != NULL) {
785     if (mevent->LeftDClick())
786       return 2;
787     else if (mevent->LeftDown() || mevent->LeftUp())
788       return 1;
789     else return 0;
790   }
791   return 0;
792 }
793
794 void
795 MainViewCallback_lockFocus(MainView *mview)
796 {
797         if (mview != NULL && mview->ref != NULL)
798           ((MoleculeView *)(mview->ref))->canvas->SetCurrent();
799 }
800
801 void
802 MainViewCallback_unlockFocus(MainView *mview)
803 {
804   //    if (mview != NULL && mview->ref != NULL)
805   //  [[(MyWindowController *)(mview->ref) myOpenGLView] unlockFocus];
806 }
807
808 void
809 MainViewCallback_frame(MainView *mview, float *rect)
810 {
811         if (mview != NULL && mview->ref != NULL) {
812           int width, height;
813           ((MoleculeView *)(mview->ref))->canvas->GetClientSize(&width, &height);
814           rect[0] = rect[1] = 0.0;
815           rect[2] = width;
816           rect[3] = height;
817         } else {
818                 rect[0] = rect[1] = rect[2] = rect[3] = 0.0;
819         }
820 }
821
822 void
823 MainViewCallback_display(MainView *mview)
824 {
825         if (mview != NULL && mview->ref != NULL) {
826           wxWindow *canvas = ((MoleculeView *)(mview->ref))->canvas;
827           canvas->Refresh();
828           canvas->Update();
829         }
830 }
831
832 void
833 MainViewCallback_setNeedsDisplay(MainView *mview, int flag)
834 {
835   if (mview != NULL && mview->ref != NULL) {
836     if (flag)
837       ((MoleculeView *)(mview->ref))->canvas->Refresh();
838   }
839 }
840
841 void
842 MainViewCallback_setKeyboardFocus(MainView *mview)
843 {
844         if (mview != NULL && mview->ref != NULL) {
845                 ((MoleculeView *)(mview->ref))->canvas->SetFocus();
846         }
847 }
848
849 void
850 MainViewCallback_clearLabels(MainView *mview)
851 {
852         return;
853 /*
854         if (mview != NULL && mview->ref != NULL) {
855                 id view = [(MyWindowController *)(mview->ref) myOverlayView];
856                 NSRect bounds = [view bounds];
857                 [view lockFocus];
858                 NSEraseRect(bounds);
859                 [[NSColor cyanColor] set];
860                 bounds.origin.x = bounds.size.width / 2;
861                 NSFrameRect(bounds);
862                 [view unlockFocus];
863                 [view setNeedsDisplay: YES];
864         }
865 */
866 }
867
868 void
869 MainViewCallback_drawLabel(MainView *mview, const float *pos, const char *label)
870 {
871         return;
872 /*
873         if (mview != NULL && mview->ref != NULL) {
874                 id view = [(MyWindowController *)(mview->ref) myOverlayView];
875                 NSString *s = [NSString stringWithUTF8String: label];
876                 NSDictionary *attr = [(MyWindowController *)(mview->ref) labelAttributes];
877                 [view lockFocus];
878                 [s drawAtPoint: NSMakePoint(pos[0], pos[1]) withAttributes: attr];
879                 [view unlockFocus];
880                 [view setNeedsDisplay: YES];
881         }
882 */
883 }
884
885 void
886 MainViewCallback_drawInfoText(MainView *mview, const char *label)
887 {
888         if (mview != NULL && mview->ref != NULL) {
889                 wxString labelstr(label, WX_DEFAULT_CONV);
890                 ((MoleculeView *)(mview->ref))->infotext->SetLabel(labelstr);
891         }
892 }
893
894 int
895 MainViewCallback_mouseCheck(MainView *mview)
896 {
897         return 0;
898 }
899
900 void
901 MainViewCallback_selectMatrixCellForMode(MainView *mview, int mode)
902 {
903         if (mview != NULL && mview->ref != NULL)
904                 ((MoleculeView *)(mview->ref))->SelectButtonForMode(mode);
905 }
906
907 //int
908 //MainViewCallback_getTag(MainView *mview)
909 //{
910   //    if (mview != NULL && mview->ref != NULL)
911   //    return [(MyWindowController *)(mview->ref) myTag];
912   //else return -1;
913 //}
914
915 MainView *
916 MainViewCallback_viewWithTag(int tag)
917 {
918         wxList &doclist = wxGetApp().DocManager()->GetDocuments();
919         wxList::iterator iter;
920         int i = 0;
921         for (i = 0, iter = doclist.begin(); iter != doclist.end(); ++i, ++iter) {
922                 if (i == tag) {
923                         return ((MoleculeView *)(((MyDocument *)(*iter))->GetFirstView()))->mview;
924                 }
925         }
926         return NULL;
927   //wxList::compatibility_iterator iter = doclist.Item(tag);
928   //if (iter != NULL)
929   //  return (MyDocument *)(*iter)->GetFirstView()->mview;
930   //else
931 //    return NULL;
932   //    int i;
933   //    if (sMyWindowControllers == nil)
934   //            return NULL;
935   //    for (i = [sMyWindowControllers count] - 1; i >= 0; i--) {
936   //            id obj = [sMyWindowControllers objectAtIndex: i];
937   //    if ([obj myTag] == tag)
938   //                    return [obj mainView];
939   //    }
940   //    return NULL;
941 }
942
943 MainView *
944 MainViewCallback_activeView(void)
945 {
946         MoleculeView *cview = (MoleculeView *)(wxGetApp().DocManager()->GetCurrentView());
947         if (cview == NULL)
948                 return NULL;
949         else
950                 return cview->mview;
951 //      return ((MoleculeView *)(wxGetApp().DocManager()->GetCurrentView()))->mview;
952   //    return MainViewCallback_viewWithTag(sLastMainViewTag);
953 }
954
955 MainView *
956 MainViewCallback_newFromFile(const char *fname)
957 {
958   wxDocument *doc;
959   wxDocManager *manager = wxGetApp().DocManager();
960   if (fname == NULL || *fname == 0) {
961     doc = manager->CreateDocument(wxT(""), wxDOC_NEW);
962   } else {
963     wxString fnamestr(fname, wxConvFile);
964     doc = manager->CreateDocument(fnamestr, wxDOC_SILENT);
965   }
966   return MainViewCallback_activeView();
967 }
968
969 int
970 MainViewCallback_importFromFile(MainView *mview, const char *fname)
971 {
972   MyDocument *doc;
973   if (mview != NULL && mview->ref != NULL && (doc = (((MoleculeView *)(mview->ref))->MolDocument())) != NULL) {
974     wxString fnamestr(fname, wxConvFile);
975     // doc->importFromFile(fnamestr);
976     MainViewCallback_setNeedsDisplay(mview, 1);
977     return 1;
978   }
979   return 0;
980 }
981
982 void
983 MainViewCallback_getFilename(MainView *mview, char *buf, int bufsize)
984 {
985   MyDocument *doc;
986   if (mview != NULL && mview->ref != NULL && (doc = (((MoleculeView *)(mview->ref))->MolDocument())) != NULL) {
987     wxString fname;
988     fname = doc->GetFilename();
989     strncpy(buf, (const char*)fname.mb_str(wxConvFile), bufsize - 1);
990     buf[bufsize - 1] = 0;
991   } else {
992     buf[0] = 0;
993   }
994 }
995
996 void
997 MainViewCallback_moleculeReplaced(MainView *mview, struct Molecule *mol)
998 {
999         if (mview != NULL && mview->ref != NULL) {
1000                 MyDocument *doc = ((MoleculeView *)(mview->ref))->MolDocument();
1001                 if (doc != NULL)
1002                         doc->SetMolecule(mol);
1003                 MyListCtrl *listctrl = ((MoleculeView *)(mview->ref))->GetListCtrl();
1004                 if (listctrl != NULL)
1005                         listctrl->SetDataSource((MoleculeView *)(mview->ref));
1006         }
1007 }
1008
1009 typedef struct Label {
1010   //    StringTexture *tex;
1011 } Label;
1012
1013 struct Label *
1014 MainViewCallback_newLabel(MainView *mview, const char *message, float fontsize, const float *forecolor, const float *backcolor)
1015 {
1016   /*
1017         Label *label;
1018         NSDictionary *attr;
1019         NSColor *textColor, *boxColor;
1020         label = (Label *)malloc(sizeof(Label));
1021         if (label == NULL)
1022                 return NULL;
1023         memset(label, 0, sizeof(Label));
1024 //      MainViewCallback_lockFocus(mview);
1025         if (forecolor != NULL)
1026                 textColor = [NSColor colorWithDeviceRed: forecolor[0] green: forecolor[1] blue: forecolor[2] alpha: forecolor[3]];
1027         else
1028                 textColor = [NSColor whiteColor];
1029         if (backcolor != NULL)
1030                 boxColor = [NSColor colorWithDeviceRed: backcolor[0] green: backcolor[1] blue: backcolor[2] alpha: backcolor[3]];
1031         else
1032                 boxColor = [NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:0.0f];
1033         attr = [NSDictionary dictionaryWithObjectsAndKeys: [NSFont userFontOfSize: fontsize], NSFontAttributeName, textColor, NSForegroundColorAttributeName, nil];
1034         label->tex = [[StringTexture alloc] 
1035                 initWithString: [NSString stringWithUTF8String: message] 
1036                 withAttributes: attr
1037                 withTextColor: textColor
1038                 withBoxColor: boxColor
1039                 withBorderColor: [NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:0.0f]];
1040 //      MainViewCallback_unlockFocus(mview);
1041         return label;
1042   */
1043 }
1044
1045 void
1046 MainViewCallback_releaseLabel(struct Label *label)
1047 {
1048   /*    if (label != NULL) {
1049                 [label->tex release];
1050                 free(label);
1051         }
1052   */
1053 }
1054
1055 void
1056 MainViewCallback_drawLabelAtPoint(struct Label *label, const float *pos)
1057 {
1058   /*
1059         if (label != NULL && pos != NULL) {
1060         //      GLint matrixMode;
1061                 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1062         //      glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
1063         //      glMatrixMode(GL_MODELVIEW);
1064         //      glPushMatrix();
1065         //      glTranslatef(0.0f, 0.0f, pos[3]);
1066                 [label->tex drawAtPoint: NSMakePoint(pos[0], pos[1]) withDepth: pos[2]];
1067         //      glPopMatrix();
1068         //      glMatrixMode (matrixMode);
1069         }
1070   */
1071 }
1072
1073 void
1074 MainViewCallback_labelSize(struct Label *label, float *outSize)
1075 {
1076   /*    if (label != NULL) {
1077                 NSSize size = [label->tex frameSize];
1078                 if (outSize != NULL) {
1079                         outSize[0] = size.width;
1080                         outSize[1] = size.height;
1081                 }
1082         }
1083   */
1084 }
1085
1086 #pragma mark ====== Plain C Interface (MyListCtrl) ======
1087
1088 /*  These interface functions are also used for accessing MyListCtrl of GlobalParameterFrame (when mview == NULL) */
1089
1090 static MyListCtrl *
1091 s_MyListCtrlFromMainView(MainView *mview)
1092 {
1093         if (mview == NULL)
1094                 return wxGetApp().GetGlobalParameterListCtrl();
1095         if (mview != NULL && mview->ref != NULL)
1096                 return ((MoleculeView *)(mview->ref))->GetListCtrl();
1097         else return NULL;
1098 }
1099
1100 void
1101 MainViewCallback_selectTable(MainView *mview, int idx)
1102 {
1103         if (mview != NULL && mview->ref != NULL)
1104                 ((MoleculeView *)(mview->ref))->SelectTable(idx);
1105 }
1106
1107 int
1108 MainViewCallback_numberOfTableColumns(MainView *mview)
1109 {
1110         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1111         if (listctrl != NULL)
1112                 return listctrl->GetColumnCount();
1113         else return 0;
1114 }
1115
1116 int
1117 MainViewCallback_addTableColumn(MainView *mview, const char *name, int width, int editable)
1118 {
1119         int idx;
1120         wxString nstr(name, WX_DEFAULT_CONV);
1121         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1122         if (listctrl == NULL)
1123                 return 0;
1124         idx = listctrl->GetColumnCount();
1125         listctrl->InsertColumn(idx, nstr, wxLIST_FORMAT_LEFT);
1126         listctrl->SetColumnWidth(idx, width * 10);
1127         return idx;
1128 }
1129
1130 int
1131 MainViewCallback_removeTableColumnAtIndex(MainView *mview, int idx)
1132 {
1133         int ncolumns;
1134         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1135         if (listctrl == NULL)
1136                 return 0;
1137         ncolumns = listctrl->GetColumnCount();
1138         if (idx >= 0 && idx < ncolumns) {
1139                 listctrl->DeleteColumn(idx);
1140                 ncolumns--;
1141         }
1142         return ncolumns;
1143 }
1144
1145 void
1146 MainViewCallback_reloadTableData(MainView *mview)
1147 {
1148         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1149         if (listctrl != NULL)
1150                 listctrl->RefreshTable();
1151 /*      
1152         int nrows = MainView_numberOfRowsInTable(mview);
1153         listctrl->SetItemCount(nrows);
1154         if (nrows > 0)
1155                 listctrl->RefreshItems(0, nrows - 1);
1156 */
1157 }
1158
1159 void
1160 MainViewCallback_setTableSelection(MainView *mview, IntGroup *selection)
1161 {
1162         int i, n, n1, n2;
1163         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1164         if (listctrl == NULL)
1165                 return;
1166         n = 0;
1167         listctrl->EnableSelectionChangeNotification(false);
1168         if (selection != NULL) {
1169                 for (i = 0; (n1 = IntGroupGetStartPoint(selection, i)) >= 0; i++) {
1170                         n2 = IntGroupGetEndPoint(selection, i);
1171                         while (n < n1) {
1172                                 listctrl->SetItemState(n, 0, wxLIST_STATE_SELECTED);
1173                                 n++;
1174                         }
1175                         while (n < n2) {
1176                                 listctrl->SetItemState(n, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
1177                                 n++;
1178                         }
1179                 }
1180         }
1181         listctrl->RefreshTable();
1182         n1 = MainView_numberOfRowsInTable(mview);
1183         while (n < n1) {
1184                 listctrl->SetItemState(n, 0, wxLIST_STATE_SELECTED);
1185                 n++;
1186         }
1187 //      listctrl->RefreshItems(0, n1 - 1);
1188         {
1189                 //  EVT_LIST_ITEM_SELECTED is sent by wxPostEvent rather than ProcessEvent,
1190                 //  so re-enable of table selection event should also be sent by wxPostEvent.
1191                 //  Otherwise, the enable flag is set to true _before_ EVT_LIST_ITEM_SELECTED is sent.
1192                 wxCommandEvent myEvent(MyListCtrlEvent, MyListCtrlEvent_enableTableSelectionNotification);
1193                 wxPostEvent(listctrl, myEvent);
1194         }
1195 }
1196
1197 IntGroup *
1198 MainViewCallback_getTableSelection(MainView *mview)
1199 {
1200         int i, n;
1201         IntGroup *ig;
1202         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1203         if (listctrl == NULL)
1204                 return NULL;
1205         ig = IntGroupNew();
1206         n = MainView_numberOfRowsInTable(mview);
1207         for (i = 0; i < n; i++) {
1208                 if (listctrl->GetItemState(i, wxLIST_STATE_SELECTED) != 0)
1209                         IntGroupAdd(ig, i, 1);
1210         }
1211         return ig;
1212 }
1213
1214 void
1215 MainViewCallback_showTable(MainView *mview)
1216 {
1217   //    if (mview != NULL && mview->ref != NULL) {
1218   //    MyDocument *doc = (MyDocument *)[(id)(mview->ref) document];
1219   //    [doc showTable: doc];
1220   //}
1221 }
1222
1223 void
1224 MainViewCallback_hideTable(MainView *mview)
1225 {
1226   //    if (mview != NULL && mview->ref != NULL) {
1227   //    MyDocument *doc = (MyDocument *)[(id)(mview->ref) document];
1228   //            [doc hideTable: doc];
1229   //    }
1230 }
1231
1232 void
1233 MainViewCallback_ensureVisible(MainView *mview, int row)
1234 {
1235         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1236         if (listctrl != NULL)
1237                 listctrl->EnsureVisible(row);
1238 }
1239
1240 void
1241 MainViewCallback_startEditText(MainView *mview, int row, int column)
1242 {
1243         MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1244         if (listctrl != NULL)
1245                 listctrl->StartEditText(row, column);
1246 }
1247