5 * Created by Toshi Nagata on 08/10/24.
6 * Copyright 2008 Toshi Nagata. All rights reserved.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation version 2 of the License.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
18 // For compilers that support precompilation, includes "wx/wx.h".
19 #include "wx/wxprec.h"
29 #if !wxUSE_DOC_VIEW_ARCHITECTURE
30 #error "You should have DocView architecture enabled in your wxWidgets installation."
33 #include "MoleculeView.h"
36 #include "MyDocument.h"
37 #include "MyGLCanvas.h"
38 #include "MyCommand.h"
40 #include "MyListCtrl.h"
41 #include "../MolLib/Missing.h"
42 #include "../MolLib/Ruby_bind/Molby_extern.h"
44 #include "MyProgressIndicator.h"
46 #include "wx/tglbtn.h"
47 #include "wx/listctrl.h"
48 #include "wx/splitter.h"
49 #include "wx/choice.h"
52 #if defined(__WXMSW__)
53 #include "OpenGL_extensions.h"
56 //#include "../MolLib/Ruby_bind/Molby_extern.h"
65 myID_RotateBondSlider,
68 myID_FrameControlPanel,
70 myID_JumpToStartButton,
71 myID_PlayBackwardButton,
73 myID_PlayForwardButton,
77 myID_StopProgressButton
80 IMPLEMENT_DYNAMIC_CLASS(MoleculeView, wxView)
82 BEGIN_EVENT_TABLE(MoleculeView, wxView)
83 EVT_TOGGLEBUTTON(myID_RotButton, MoleculeView::OnButtonPressed)
84 EVT_TOGGLEBUTTON(myID_TransButton, MoleculeView::OnButtonPressed)
85 EVT_TOGGLEBUTTON(myID_ScaleButton, MoleculeView::OnButtonPressed)
86 EVT_TOGGLEBUTTON(myID_SelectButton, MoleculeView::OnButtonPressed)
87 EVT_TOGGLEBUTTON(myID_BondButton, MoleculeView::OnButtonPressed)
88 EVT_TOGGLEBUTTON(myID_EraseButton, MoleculeView::OnButtonPressed)
89 EVT_BUTTON(myID_StopProgressButton, MoleculeView::OnStopProgressPressed)
90 EVT_COMMAND(wxID_ANY, MySliderEvent, MoleculeView::OnSliderAction)
91 EVT_COMMAND_SCROLL(myID_FrameSlider, MoleculeView::OnFrameSliderAction)
92 EVT_TEXT_ENTER(myID_FrameText, MoleculeView::OnFrameTextAction)
93 EVT_CHOICE(myID_TableMenu, MoleculeView::OnSelectTable)
94 EVT_ACTIVATE(MoleculeView::OnActivate)
96 #define ConnectMouseDownEvents(src, func, target) \
97 (src->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(func), NULL, target), \
98 src->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(func), NULL, target))
100 WX_DEFINE_ARRAY_PTR(MoleculeView *, ArrayOfMoleculeViews);
102 ArrayOfMoleculeViews sActiveViews;
104 MoleculeView::~MoleculeView()
109 MoleculeView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
113 const wxFont *ctrlFont;
115 ctrlFont = wxSMALL_FONT;
120 // Make a document frame
121 frame = new wxDocChildFrame(doc, this, GetMainFrame(), wxID_ANY, _T("New Molby Document"),
122 wxDefaultPosition, wxDefaultSize,
123 wxDEFAULT_FRAME_STYLE |
124 wxNO_FULL_REPAINT_ON_RESIZE);
125 frame->SetPosition(FromFrameDIP(frame, wxPoint(10, 24)));
126 frame->SetClientSize(FromFrameDIP(frame, wxSize(680, 400)));
131 file_history_menu = NULL;
133 memset(tbuttons, 0, sizeof(tbuttons));
135 frameControlPanel = NULL;
138 isRebuildingTable = false;
140 Molecule *mol = ((MyDocument *)doc)->GetMolecule();
143 MainView_setViewObject(mview, this);
146 wxMenuBar *menu_bar = wxGetApp().CreateMenuBar(1, &file_history_menu, &edit_menu);
148 // Associate the menu bar with the frame
149 frame->SetMenuBar(menu_bar);
151 // Associate the edit menu with the command processor
152 doc->GetCommandProcessor()->SetEditMenu(edit_menu);
154 // Create the window content
156 // A splitter window embraces a grid (left) and main screen (right)
157 wxSplitterWindow *splitter = new wxSplitterWindow(frame, -1, wxDefaultPosition, wxDefaultSize, wxSP_3D | wxSP_LIVE_UPDATE);
158 splitter->SetMinimumPaneSize(1);
160 // Create the left half
161 // A panel containing a popup menu and a list window
162 wxPanel *panel0 = new wxPanel(splitter);
166 sizer0 = new wxBoxSizer(wxVERTICAL);
167 wxArrayString choiceItems;
169 MainView_tableTitleForIndex(mview, i, buf, sizeof buf);
172 wxString itemTitle(buf, WX_DEFAULT_CONV);
173 choiceItems.Add(itemTitle);
176 listmenu = new wxChoice(panel0, myID_TableMenu, wxDefaultPosition, wxDefaultSize, choiceItems);
177 sizer0->Add(listmenu, 0, wxALL, 0);
179 listctrl = new MyListCtrl();
180 listctrl->Create(panel0, myID_Table, wxDefaultPosition, wxDefaultSize);
181 sizer0->Add(listctrl, 1, wxALL | wxEXPAND, 0);
182 panel0->SetSizer(sizer0);
185 // Create the right half
186 // A panel containing MyGLCanvas, buttons, sliders, etc.
187 wxPanel *panel1 = new wxPanel(splitter);
189 { // Vertical sizer containing [sizer2, sizer3, sizer4]
191 sizer1 = new wxBoxSizer(wxVERTICAL);
193 { // Horizontal sizer containing [button0, ..., button5, infotext, progress_indicator]
195 sizer2 = new wxBoxSizer(wxHORIZONTAL);
197 { // Button0..5 (Rot/Trans/Scale/Select/Bond/Erase)
198 wxString labels[] = {
199 wxT("Rot"), wxT("Trans"), wxT("Scale"), wxT("Select"), wxT("Bond"), wxT("Erase")
202 myID_RotButton, myID_TransButton, myID_ScaleButton,
203 myID_SelectButton, myID_BondButton, myID_EraseButton
205 for (i = 0; i < 6; i++) {
206 tbuttons[i] = new MyToggleButton(panel1, ids[i], labels[i], wxDefaultPosition, FromFrameDIP(frame, wxSize(40, 32)), wxTOGGLEBUTTON_STYLE);
208 tbuttons[i]->SetFont(*ctrlFont);
209 sizer2->Add(tbuttons[i], 0, wxALL | wxEXPAND, FromFrameDIP(frame, 3));
211 tbuttons[0]->SetValue(true);
213 { // Information text
214 infotext = new wxStaticText(panel1, -1, wxT(""), wxDefaultPosition, FromFrameDIP(frame, wxSize(80, 32)), wxST_NO_AUTORESIZE | wxBORDER_SUNKEN);
215 infotext->SetMinSize(FromFrameDIP(frame, wxSize(80, 32)));
216 #if defined(__WXMSW__)
217 infotext->SetFont(*wxSMALL_FONT);
220 infotext->SetFont(*ctrlFont);
222 sizer2->Add(infotext, 1, wxALL | wxEXPAND, 3); // Can expand horizontally
224 { // Custom progress indicator
225 progress = new MyProgressIndicator(panel1, myID_StopProgressButton, wxDefaultPosition, FromFrameDIP(frame, wxSize(12, 24)));
226 sizer2->Add(progress, 0, wxALL | wxEXPAND, 3);
228 sizer1->Add(sizer2, 0, wxALL | wxEXPAND, 0);
231 { // Horizontal sizer containing [sizer31, sizer32, sizer33]
232 wxBoxSizer *sizer3 = new wxBoxSizer(wxHORIZONTAL);
234 { // Vertical sizer containing [button, mySlider]
235 wxBoxSizer *sizer31 = new wxBoxSizer(wxVERTICAL);
236 { // "Rotate bond" button and mySlider
237 #include "../bitmaps/rotate_bond.xpm"
238 wxBitmap bmp1(rotate_bond_xpm);
239 wxBitmapButton *button1 = new wxBitmapButton(panel1, -1, bmp1, wxDefaultPosition, FromFrameDIP(frame, wxSize(21, 21)), wxTOGGLEBUTTON_STYLE);
240 sizer31->Add(button1, 0, 0, 0);
242 MySlider *slider1 = new MySlider(panel1, myID_RotateBondSlider, wxVERTICAL, wxDefaultPosition, FromFrameDIP(frame, wxSize(21, 21)));
243 sizer31->Add(slider1, 1, wxEXPAND);
245 sizer3->Add(sizer31, 0, wxALL | wxEXPAND, 0);
248 { // Vertical sizer containing [Canvas, [button, mySlider]]
249 wxBoxSizer *sizer32 = new wxBoxSizer(wxVERTICAL);
251 canvas = new MyGLCanvas(this, panel1, wxDefaultPosition, FromFrameDIP(frame, wxSize(100, 100)));
252 sizer32->Add(canvas, 1, wxALL | wxEXPAND, 0);
254 // Let the MyGLCanvas pass the keyboard event to this
255 canvas->Connect(-1, wxEVT_CHAR, wxKeyEventHandler(MoleculeView::OnChar), NULL, this);
258 wxBoxSizer *sizer321 = new wxBoxSizer(wxHORIZONTAL);
260 #include "../bitmaps/rotate_y.xpm"
261 wxBitmap bmp2(rotate_y_xpm);
262 wxBitmapButton *button2 = new wxBitmapButton(panel1, -1, bmp2, wxDefaultPosition, FromFrameDIP(frame, wxSize(21, 21)), wxTOGGLEBUTTON_STYLE);
263 sizer321->Add(button2, 0, 0, 0);
265 MySlider *slider2 = new MySlider(panel1, myID_RotateYSlider, wxHORIZONTAL, wxDefaultPosition, FromFrameDIP(frame, wxSize(21, 21)));
266 sizer321->Add(slider2, 1, wxEXPAND);
268 sizer32->Add(sizer321, 0, wxEXPAND);
270 sizer3->Add(sizer32, 1, wxEXPAND);
273 { // Vertical sizer containing [button, mySlider]
274 wxBoxSizer *sizer33 = new wxBoxSizer(wxVERTICAL);
275 { // "Rotate bond" button and mySlider
276 #include "../bitmaps/rotate_x.xpm"
277 wxBitmap bmp3(rotate_x_xpm);
278 wxBitmapButton *button3 = new wxBitmapButton(panel1, -1, bmp3, wxDefaultPosition, FromFrameDIP(frame, wxSize(21, 21)), wxTOGGLEBUTTON_STYLE);
280 sizer33->Add(button3, 0, 0, 0);
282 MySlider *slider3 = new MySlider(panel1, myID_RotateXSlider, wxVERTICAL, wxDefaultPosition, FromFrameDIP(frame, wxSize(21, 21)));
283 sizer33->Add(slider3, 1, wxEXPAND);
285 sizer3->Add(sizer33, 0, wxALL | wxEXPAND, 0);
288 sizer1->Add(sizer3, 1, wxALL | wxEXPAND, 0);
291 { // Horizontal sizer containing frame controls
293 const int height = 18;
294 frameControlPanel = new wxPanel(panel1, myID_FrameControlPanel, wxDefaultPosition, FromFrameDIP(frame, wxSize(200, height)));
295 wxBoxSizer *sizer4 = new wxBoxSizer(wxHORIZONTAL);
297 frameSlider = new wxSlider(frameControlPanel, myID_FrameSlider, 0, 0, 1, wxDefaultPosition, FromFrameDIP(frame, wxSize(40, height - 2)));
298 frameSlider->Enable(false);
299 sizer4->Add(frameSlider, 1, wxALL | wxEXPAND, 1);
301 #include "../bitmaps/jump_to_start.xpm"
302 wxBitmap bmp41(jump_to_start_xpm);
303 wxBitmapButton *button41 = new wxBitmapButton(frameControlPanel, myID_JumpToStartButton, bmp41, wxDefaultPosition, FromFrameDIP(frame, wxSize(16, height)), wxTOGGLEBUTTON_STYLE);
304 sizer4->Add(button41, 0, wxEXPAND);
305 ConnectMouseDownEvents(button41, MoleculeView::OnFrameButtonAction, this);
307 #include "../bitmaps/play_backward.xpm"
308 wxBitmap bmp42(play_backward_xpm);
309 wxBitmapButton *button42 = new wxBitmapButton(frameControlPanel, myID_PlayBackwardButton, bmp42, wxDefaultPosition, FromFrameDIP(frame, wxSize(16, height)), wxTOGGLEBUTTON_STYLE);
310 sizer4->Add(button42, 0, wxEXPAND);
311 ConnectMouseDownEvents(button42, MoleculeView::OnFrameButtonAction, this);
314 frameText = new wxTextCtrl(frameControlPanel, myID_FrameText, wxT(""), wxDefaultPosition, FromFrameDIP(frame, wxSize(40, height)));
316 wxTextAttr attr(*wxBLACK, wxNullColour, *ctrlFont);
317 frameText->SetDefaultStyle(attr);
318 frameText->SetFont(*ctrlFont);
320 sizer4->Add(frameText, 0, wxEXPAND);
323 #include "../bitmaps/play_forward.xpm"
324 wxBitmap bmp43(play_forward_xpm);
325 wxBitmapButton *button43 = new wxBitmapButton(frameControlPanel, myID_PlayForwardButton, bmp43, wxDefaultPosition, FromFrameDIP(frame, wxSize(16, height)), wxTOGGLEBUTTON_STYLE);
326 sizer4->Add(button43, 0, wxEXPAND);
327 ConnectMouseDownEvents(button43, MoleculeView::OnFrameButtonAction, this);
329 #include "../bitmaps/jump_to_end.xpm"
330 wxBitmap bmp44(jump_to_end_xpm);
331 wxBitmapButton *button44 = new wxBitmapButton(frameControlPanel, myID_JumpToEndButton, bmp44, wxDefaultPosition, FromFrameDIP(frame, wxSize(16, height)), wxTOGGLEBUTTON_STYLE);
332 sizer4->Add(button44, 0, wxEXPAND);
333 ConnectMouseDownEvents(button44, MoleculeView::OnFrameButtonAction, this);
335 wxPanel *spacer = new wxPanel(frameControlPanel, -1, wxDefaultPosition, FromFrameDIP(frame, wxSize(21, height)));
336 sizer4->Add(spacer, 0, wxEXPAND);
338 frameControlPanel->SetSizer(sizer4);
339 sizer1->Add(frameControlPanel, 0, wxALL | wxEXPAND, 0);
340 // controls->Disable();
343 panel1->SetSizer(sizer1);
346 splitter->SplitVertically(panel0, panel1);
348 wxBoxSizer *mainsizer = new wxBoxSizer(wxHORIZONTAL);
349 mainsizer->Add(splitter, 1, wxEXPAND);
350 frame->SetSizer(mainsizer);
353 splitter->SetSashPosition(FromFrameDIP(frame, 240), true);
355 // Initialize table view
356 MainView_createColumnsForTableAtIndex(mview, 0);
358 // Select table popup
359 listmenu->SetSelection(0);
361 #if defined(__X__) || defined(__WXMAC__)
362 // X seems to require a forced resize
364 frame->GetSize(&x, &y);
365 frame->SetSize(wxDefaultCoord, wxDefaultCoord, x, y);
370 // Initial keyboard focus is on the GL canvas (to accept 'S' for scale, etc.)
373 // Connect the notification handler
374 doc->Connect(MyDocumentEvent_documentModified, MyDocumentEvent, wxCommandEventHandler(MoleculeView::OnDocumentModified), NULL, this);
376 wxGetApp().Connect(MyDocumentEvent_scriptMenuModified, MyDocumentEvent, wxCommandEventHandler(MoleculeView::OnScriptMenuModified), NULL, this);
378 // Intercept the double-click handler of MyListCtrl
379 listctrl->GetScrolledWindow()->Bind(wxEVT_LEFT_DCLICK, &MoleculeView::OnLeftDClickInListCtrl, this);
381 // Set data source for the list control
382 listctrl->SetDataSource(this);
384 #if defined(__WXMSW__)
385 // Initialize OpenGL extension
387 static int openGLExtension_inited = 0;
388 if (openGLExtension_inited == 0) {
389 if (InitializeOpenGLExtensions() != 0) {
390 MyAppCallback_errorMessageBox("Fatal internal error: cannot initialize OpenGL extensions");
391 openGLExtension_inited = -1;
392 } else openGLExtension_inited = 1;
402 MoleculeView::OnDraw(wxDC *dc)
405 if (mview->isPrinting) {
407 wxImage *img = CaptureGLCanvas(scale);
409 wxBitmap bitmap(*img);
411 dc->GetUserScale(&sx, &sy);
412 dc->SetUserScale(sx / scale, sy / scale);
413 dc->DrawBitmap(bitmap, 0, 0);
416 mview->isPrinting = 0;
418 if (mview->mol != NULL) {
419 MoleculeLock(mview->mol);
420 MainView_drawModel(mview);
421 MoleculeUnlock(mview->mol);
428 MoleculeView::CaptureGLCanvas(float scale, int bg_color, int width, int height)
430 if (canvas && mview->mol != NULL) {
431 int x, y, cwidth, cheight;
432 float bgcol[4], rx, ry;
434 canvas->SetCurrent();
435 canvas->GetClientSize(&cwidth, &cheight);
440 rx = (float)width / cwidth;
441 ry = (float)height / cheight;
447 // Create OpenGL offscreen buffer
448 GLuint frame_buf, render_buf, depth_buf;
449 frame_buf = render_buf = depth_buf = 0;
450 glGenFramebuffersEXT(1, &frame_buf);
451 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frame_buf);
453 glGenRenderbuffersEXT(1, &render_buf);
454 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_buf);
455 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, width, height);
457 glGenRenderbuffersEXT(1, &depth_buf);
458 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_buf);
459 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
461 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, render_buf);
462 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_buf);
464 MainView_initializeOpenGL();
466 mview->offline_scale = 1.0; /* Scale is handled in offline_width and offline_height */
467 mview->offline_width = width;
468 mview->offline_height = height;
470 for (x = 0; x < 4; x++) {
471 bgcol[x] = mview->background_color[x];
474 mview->background_color[0] = 0;
475 mview->background_color[1] = 0;
476 mview->background_color[2] = 0;
477 mview->background_color[3] = 0;
478 } else if (bg_color == 1) {
479 mview->background_color[0] = 0;
480 mview->background_color[1] = 0;
481 mview->background_color[2] = 0;
482 mview->background_color[3] = 1;
483 } else if (bg_color == 2) {
484 mview->background_color[0] = 1;
485 mview->background_color[1] = 1;
486 mview->background_color[2] = 1;
487 mview->background_color[3] = 1;
489 MoleculeLock(mview->mol);
490 MainView_drawModel(mview);
491 MoleculeUnlock(mview->mol);
492 for (x = 0; x < 4; x++) {
493 mview->background_color[x] = bgcol[x];
495 mview->offline_scale = 0.0;
496 mview->offline_width = 0;
497 mview->offline_height = 0;
499 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
500 unsigned char *glBitmapData = (unsigned char *)malloc(4 * width * height);
501 unsigned char *glRGBData = (unsigned char *)malloc(3 * width * height);
502 unsigned char *glAlphaData = (unsigned char *)malloc(width * height);
503 glReadPixels((GLint)0, (GLint)0, (GLint)width, (GLint)height, GL_RGBA, GL_UNSIGNED_BYTE, glBitmapData);
504 for (y = 0; y < height; y++) {
505 unsigned char *p1 = glBitmapData + 4 * y * width;
506 unsigned char *p2 = glRGBData + 3 * (height - 1 - y) * width;
507 unsigned char *p3 = glAlphaData + (height - 1 - y) * width;
508 for (x = 0; x < width; x++) {
509 // Copy RGB data and Alpha data separately, with flipping vertically
516 wxImage *img = new wxImage(width, height, glRGBData, glAlphaData);
517 free(glBitmapData); // glRGBData and glAlphaData are deallocated within wxImage constructor
519 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
520 glDeleteFramebuffersEXT(1, &frame_buf);
521 glDeleteRenderbuffersEXT(1, &render_buf);
531 MoleculeView::DoExportGraphic(wxString& fname, float scale, int bg_color, int width, int height)
533 wxImage *img = CaptureGLCanvas(scale, bg_color, width, height);
536 wxString ext = fname.AfterLast('.');
537 wxBitmapType type = wxBITMAP_TYPE_PNG;
538 if (ext.CmpNoCase(_T("tif")) == 0)
539 type = wxBITMAP_TYPE_TIF;
540 img->SaveFile(fname, type);
546 MoleculeView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
551 /* Maybe necessary in some platforms (not in MacOSX and MSW) */
554 wxClientDC dc(canvas);
562 MoleculeView::OnClose(bool deleteWindow)
564 //#if !defined(__WXMAC__) && !defined(__WXOSX__)
565 // On wxOSX, this causes invocation of MyDocument::Close() twice, which
566 // apprently is not very good. However, on wxMSW this is not the case.
567 // So we need to keep this code for wxMSW but not for wxOSX.
568 if (!GetDocument()->Close())
572 // Dispose relationship between this and Molecule (MainView)
573 MainView_setViewObject(mview, NULL);
576 // Remove this from the active view list
577 sActiveViews.Remove(this);
579 // Dispose Connection between DocManager and file history menu
580 wxGetApp().DocManager()->FileHistoryRemoveMenu(file_history_menu);
582 wxGetApp().Disconnect(MyDocumentEvent_scriptMenuModified, MyDocumentEvent, wxCommandEventHandler(MoleculeView::OnScriptMenuModified), NULL, this);
588 // Check if all windows are gone
589 wxGetApp().CheckIfAllWindowsAreGone(frame);
595 MoleculeView::Activate(bool activate)
598 int i, n = sActiveViews.GetCount();
599 for (i = 0; i < n; i++) {
600 if (sActiveViews.Item(i) == this)
604 /* Remove this if existing */
605 sActiveViews.RemoveAt(i);
607 /* Insert self as the first item */
608 sActiveViews.Insert(this, 0);
610 wxView::Activate(activate);
615 MoleculeView::OnCreatePrintout()
618 mview->isPrinting = 1;
619 return wxView::OnCreatePrintout();
623 MoleculeView::UpdateFrameControlValues()
625 if (mview == NULL || mview->mol == NULL)
629 cframe = mview->mol->cframe;
630 str.Printf(_T("%d"), cframe);
631 // frameText->SetValue(str);
633 frameText->AppendText(str);
634 frameSlider->SetValue(cframe);
638 MoleculeView::UpdateFrameControls()
641 bool enabled = false;
642 if (mview != NULL && mview->mol != NULL) {
643 MoleculeLock(mview->mol);
644 nframes = MoleculeGetNumberOfFrames(mview->mol);
645 MoleculeUnlock(mview->mol);
650 frameControlPanel->Enable(enabled);
652 frameSlider->Enable(true);
653 frameSlider->SetRange(0, nframes - 1);
654 UpdateFrameControlValues();
656 frameSlider->Enable(false);
657 frameSlider->SetRange(0, 1);
658 frameText->SetValue(_T(""));
660 frameControlPanel->Update();
664 MoleculeView::InvalidateProgressIndicator()
670 MoleculeView::ProceedProgressIndicator()
672 progress->ProceedIndicatorState();
676 MoleculeView::SelectButtonForMode(int mode)
679 if (mode >= 1 && mode <= 6) {
680 for (i = 0; i < 6; i++) {
681 tbuttons[i]->SetValue((i == mode - 1));
684 MainViewCallback_setKeyboardFocus(mview);
688 MoleculeView::OnButtonPressed(wxCommandEvent& event)
690 int eventId = event.GetId();
691 int mode = eventId - myID_RotButton + kTrackballRotateMode;
692 MainView_setMode(mview, mode);
693 SelectButtonForMode(mode);
697 MoleculeView::OnSliderAction(wxCommandEvent& event)
699 int eventId = event.GetId();
700 int mode = eventId - myID_RotateBondSlider + 1;
702 MySlider *sender = (MySlider *)event.GetEventObject();
703 float angle = sender->GetFloatValue();
704 float angledeg = angle * 360.0;
705 float fixangledeg = floor(angledeg / 15.0 + 0.5) * 15.0; // Nearest multiple of 15 deg
706 if (angledeg > fixangledeg - 0.9 && angledeg < fixangledeg + 0.9) {
707 angledeg = fixangledeg; // Snap to the nearest multiple of 15 deg
708 angle = angledeg / 360.0;
710 int mouseStatus = sender->GetMouseStatus();
712 MoleculeLock(mview->mol);
713 MainView_rotateBySlider(mview, angle * 3.1415927 * 2, mode, mouseStatus, MainViewCallback_modifierFlags(NULL));
714 snprintf(buf, sizeof buf, "%.1f°", angledeg);
715 MainViewCallback_drawInfoText(mview, buf);
716 MainViewCallback_updateCanvas(mview);
717 MoleculeUnlock(mview->mol);
721 MoleculeView::OnFrameButtonAction(wxMouseEvent &event)
723 int ival, nframes, bid;
724 if (mview == NULL || mview->mol == NULL)
726 nframes = MoleculeGetNumberOfFrames(mview->mol);
730 if (bid == myID_JumpToStartButton) {
732 } else if (bid == myID_JumpToEndButton) {
734 } else if (bid == myID_PlayForwardButton) {
735 ival = (mview->mol->cframe + 1) % nframes;
736 } else if (bid == myID_PlayBackwardButton) {
737 ival = (mview->mol->cframe + nframes - 1) % nframes;
739 // TODO: implement continuous move
740 if (ival >= 0 && ival < nframes) {
741 MoleculeLock(mview->mol);
742 MoleculeSelectFrame(mview->mol, ival, 1);
743 MoleculeUnlock(mview->mol);
744 MainViewCallback_display(mview);
745 UpdateFrameControlValues();
753 MoleculeView::OnFrameSliderAction(wxScrollEvent &event)
756 if (mview == NULL || mview->mol == NULL)
758 MoleculeLock(mview->mol);
759 nframes = MoleculeGetNumberOfFrames(mview->mol);
761 ival = frameSlider->GetValue();
762 if (ival >= 0 && ival < nframes) {
763 MoleculeSelectFrame(mview->mol, ival, 1);
764 MoleculeUnlock(mview->mol);
765 MainViewCallback_display(mview);
766 UpdateFrameControlValues();
770 MoleculeUnlock(mview->mol);
774 MoleculeView::OnFrameTextAction(wxCommandEvent &event)
778 if (mview == NULL || mview->mol == NULL)
780 MoleculeLock(mview->mol);
781 nframes = MoleculeGetNumberOfFrames(mview->mol);
783 str = frameText->GetValue();
784 ival = atoi((const char *)str.mb_str(WX_DEFAULT_CONV));
785 if (ival >= 0 && ival < nframes) {
786 MoleculeSelectFrame(mview->mol, ival, 1);
787 MoleculeUnlock(mview->mol);
788 MainViewCallback_display(mview);
789 UpdateFrameControlValues();
793 MoleculeUnlock(mview->mol);
797 MoleculeView::OnStopProgressPressed(wxCommandEvent& event)
799 mview->mol->requestAbortThread = 1;
803 MoleculeView::OnDocumentModified(wxCommandEvent& event)
805 int xpos, ypos, rowindex, newypos;
806 if (!mview->freezeScreen) {
809 UpdateFrameControls();
810 MoleculeLock(mview->mol);
812 // Get the current row/column value; if the table index is the same, keep the
813 // displayed position as close as possible
814 listctrl->GetScrollPosition(&xpos, &ypos);
815 if (mview->cachedTableIndex != mview->tableIndex) {
816 xpos = ypos = 0; /* Different table is shown; should reset the view */
818 if (mview->tableIndex >= kMainViewAtomTableIndex && mview->tableIndex <= kMainViewImproperTableIndex) {
819 // Atom, Bond, Angle, Dihedral, Improper; use the cache
820 int count = IntGroupGetCount(mview->tableCache);
822 rowindex = IntGroupGetNthPoint(mview->tableCache, ypos);
824 rowindex = IntGroupGetNthPoint(mview->tableCache, count - 1);
826 } else rowindex = ypos;
828 MainView_refreshTable(mview);
829 if (mview->tableIndex >= kMainViewAtomTableIndex && mview->tableIndex <= kMainViewImproperTableIndex) {
831 ic = IntGroupGetIntervalCount(mview->tableCache);
833 for (i = 0; i < ic; i++) {
834 is = IntGroupGetStartPoint(mview->tableCache, i);
835 ie = IntGroupGetEndPoint(mview->tableCache, i);
838 newypos += (rowindex - is);
843 } else newypos = rowindex;
844 listctrl->SetScrollPosition(xpos, newypos);
845 MoleculeUnlock(mview->mol);
848 if (mview->tableIndex == kMainViewParameterTableIndex && mview->mol->parameterTableSelectionNeedsClear) {
849 /* Clear parameter selection if necessary */
850 MainViewCallback_setTableSelection(mview, NULL);
851 mview->mol->parameterTableSelectionNeedsClear = 0;
854 /* printf("MoleculeView::OnDocumentModified invoked\n"); */
855 event.Skip(); /* Continue processing of the notification */
859 MoleculeView::OnScriptMenuModified(wxCommandEvent& event)
861 wxGetApp().UpdateScriptMenu(frame->GetMenuBar());
866 MoleculeView::OnChar(wxKeyEvent &event)
868 int code = event.GetKeyCode();
870 bool noMod = ((event.GetModifiers() | wxMOD_SHIFT) == wxMOD_SHIFT);
871 // MyAppCallback_showScriptMessage("MoleculeView::OnChar invoked\n");
872 if (code == WXK_BACK || code == WXK_DELETE || code == 0x7f || code == 8) {
873 MoleculeLock(mview->mol);
874 MainView_delete(mview);
875 MoleculeUnlock(mview->mol);
876 } else if (noMod && (code == 'r' || code == 'R'))
877 mode = kTrackballRotateMode;
878 else if (noMod && (code == 't' || code == 'T'))
879 mode = kTrackballTranslateMode;
880 else if (noMod && (code == 's' || code == 'S'))
881 mode = kTrackballScaleMode;
882 else if (noMod && (code == ' '))
883 mode = kTrackballSelectionMode;
884 else if (noMod && (code == 'b' || code == 'B'))
885 mode = kTrackballCreateMode;
886 else if (noMod && (code == 'e' || code == 'E'))
887 mode = kTrackballEraseMode;
893 MainView_setMode(mview, mode);
894 MainViewCallback_selectMatrixCellForMode(mview, mode);
899 MoleculeView::SelectTable(int idx)
901 if (idx >= 0 && idx < listmenu->GetCount() && idx != mview->tableIndex) {
902 isRebuildingTable = true;
903 if (MainView_createColumnsForTableAtIndex(mview, idx) == 0) {
904 /* Invalid menu item */
905 listmenu->SetSelection(mview->tableIndex);
906 isRebuildingTable = false;
909 listmenu->SetSelection(idx);
910 isRebuildingTable = false;
911 MoleculeLock(mview->mol);
912 MainView_refreshTable(mview);
913 MoleculeUnlock(mview->mol);
914 if (idx >= kMainViewParameterTableIndex) {
915 MainViewCallback_setTableSelection(mview, NULL);
916 if (idx == kMainViewParameterTableIndex) {
917 /* Not sure whether it is appropriate rebuilding MDArena
918 *every time* the parameter table is opened... */
919 MoleculePrepareMDArena(mview->mol, 1, NULL);
926 MoleculeView::OnSelectTable(wxCommandEvent &event)
928 if (!isRebuildingTable) {
929 MoleculeLock(mview->mol);
930 SelectTable(listmenu->GetSelection());
931 MoleculeUnlock(mview->mol);
936 MoleculeView::OnLeftDClickInListCtrl(wxMouseEvent &event)
938 listctrl->OnLeftDClick(event);
939 if (mview->tableIndex >= kMainViewBondTableIndex && mview->tableIndex <= kMainViewImproperTableIndex /* && mview->mol->par != NULL */ ) {
941 char indices[64], names[64], types[64], value[20], partypes[64], params[3][20];
944 wxPoint pos = event.GetPosition();
945 if (!listctrl->FindItemAtPosition(pos, &row, &col) || col < 4)
947 /* Start editing the local parameter; open a separate dialog */
948 MainView_valueForTable(mview, 0, row, indices, sizeof indices);
949 MainView_valueForTable(mview, 1, row, names, sizeof names);
950 MainView_valueForTable(mview, 2, row, types, sizeof types);
951 MainView_valueForTable(mview, 3, row, value, sizeof value);
952 MainView_valueForTable(mview, 4, row, partypes, sizeof partypes);
953 for (i = 0; i < 3; i++) {
954 MainView_valueForTable(mview, 5 + i, row, params[i], sizeof(params[0]));
956 switch (mview->tableIndex) {
957 case kMainViewBondTableIndex: ptype = "bond"; break;
958 case kMainViewAngleTableIndex: ptype = "angle"; break;
959 case kMainViewDihedralTableIndex: ptype = "dihedral"; break;
960 case kMainViewImproperTableIndex: ptype = "improper"; break;
963 asprintf(&parstr, "%s %s %s", params[0], params[1], params[2]);
964 MolActionCreateAndPerform(mview->mol, SCRIPT_ACTION("sssssss"), "cmd_edit_local_parameter_in_mainview", ptype, indices, names, types, value, partypes, parstr);
970 MoleculeView::OnActivate(wxActivateEvent &event)
972 if (!event.GetActive()) {
973 if (listctrl != NULL)
974 listctrl->EndEditText(true);
980 MoleculeView::OnMoleculeReplaced()
982 Molecule *mol = ((MyDocument *)GetDocument())->GetMolecule();
983 if (mol == NULL && mview == NULL)
985 if (mol != NULL && mol->mview == mview) {
986 /* Clear internal cache */
987 MainView_refreshCachedInfo(mol->mview);
991 MainView_setViewObject(mview, NULL);
995 MainView_setViewObject(mview, this);
996 /* Force updating the table */
997 tableIndex = mview->tableIndex;
998 mview->tableIndex = -1;
999 SelectTable(tableIndex);
1004 MoleculeView::EnableProgressIndicator(bool flag)
1006 progress->SetEnabled(flag);
1009 #pragma mark ====== MyListCtrl data source ======
1012 MoleculeView::GetItemCount(MyListCtrl *ctrl)
1014 return MainView_numberOfRowsInTable(mview);
1018 MoleculeView::GetItemText(MyListCtrl *ctrl, long row, long column) const
1021 MainView_valueForTable(mview, column, row, buf, sizeof buf);
1022 wxString *str = new wxString(buf, WX_DEFAULT_CONV);
1027 MoleculeView::SetItemText(MyListCtrl *ctrl, long row, long column, const wxString &value)
1029 MainView_setValueForTable(mview, column, row, value.mb_str(WX_DEFAULT_CONV));
1034 MoleculeView::DragSelectionToRow(MyListCtrl *ctrl, long row)
1036 MainView_dragTableSelectionToRow(mview, row);
1040 MoleculeView::IsItemEditable(MyListCtrl *ctrl, long row, long column)
1042 return MainView_isTableItemEditable(mview, column, row);
1046 MoleculeView::IsDragAndDropEnabled(MyListCtrl *ctrl, long row)
1048 /* Only enabled for the atom table */
1049 return (MainView_tableType(mview) == 0);
1053 MoleculeView::OnSelectionChanged(MyListCtrl *ctrl)
1055 MainView_setSelectionFromTable(mview);
1059 MoleculeView::SetItemColor(MyListCtrl *ctrl, long row, long col, float *fg, float *bg)
1061 if (mview != NULL && mview->mol != NULL) {
1062 return MainView_setColorForTable(mview, col, row, fg, bg);
1064 if (mview->tableIndex == kMainViewParameterTableIndex && col == -1) {
1065 int src = ParameterTableGetItemSource(mview->mol->par, row);
1066 if (src == -2) { // separator line
1067 bg[0] = bg[1] = bg[2] = 0.6;
1069 } else if (src == -1) { // undefined parameters
1071 bg[1] = bg[2] = 0.2;
1073 } else if (src == 0) { // local parameter
1074 bg[0] = bg[1] = 1.0;
1078 } else if (mview->tableIndex > 0 && mview->tableIndex < 5) {
1079 return MainView_setColorForTable(mview, col, row, fg, bg);
1087 MoleculeView::IsRowSelectable(MyListCtrl *ctrl, long row)
1089 return MainView_isRowSelectable(mview, row);
1092 #pragma mark ====== Plain C interface ======
1095 MainViewCallback_modifierFlags(void *eventRef)
1099 wxMouseState state = ::wxGetMouseState();
1101 if (state.ShiftDown())
1102 flags |= kShiftKeyMask;
1103 if (state.AltDown())
1104 flags |= kAltKeyMask;
1109 MainViewCallback_clickCount(void *eventRef)
1111 wxMouseEvent *mevent = (wxMouseEvent *)eventRef;
1112 if (mevent != NULL) {
1113 if (mevent->LeftDClick())
1115 else if (mevent->LeftDown() || mevent->LeftUp())
1123 MainViewCallback_lockFocus(MainView *mview)
1125 if (mview != NULL && mview->ref != NULL)
1126 ((MoleculeView *)(mview->ref))->canvas->SetCurrent();
1130 MainViewCallback_unlockFocus(MainView *mview)
1132 // if (mview != NULL && mview->ref != NULL)
1133 // [[(MyWindowController *)(mview->ref) myOpenGLView] unlockFocus];
1137 MainViewCallback_frame(MainView *mview, float *rect)
1139 if (mview != NULL && mview->ref != NULL) {
1141 ((MoleculeView *)(mview->ref))->canvas->GetClientSize(&width, &height);
1142 rect[0] = rect[1] = 0.0;
1146 rect[0] = rect[1] = rect[2] = rect[3] = 0.0;
1151 MainViewCallback_getContentScaleFactor(MainView *mview)
1153 if (gUseGUI && mview != NULL && mview->ref != NULL) {
1154 return ((MoleculeView *)(mview->ref))->canvas->GetContentScaleFactor();
1160 MainViewCallback_display(MainView *mview)
1162 if (gUseGUI && mview != NULL && mview->ref != NULL) {
1163 wxWindow *canvas = ((MoleculeView *)(mview->ref))->canvas;
1170 MainViewCallback_makeFront(MainView *mview)
1172 if (gUseGUI && mview != NULL && mview->ref != NULL) {
1173 ((MoleculeView *)(mview->ref))->GetFrame()->Raise();
1178 MainViewCallback_setNeedsDisplay(MainView *mview, int flag)
1180 if (gUseGUI && mview != NULL && mview->ref != NULL) {
1182 ((MoleculeView *)(mview->ref))->canvas->Refresh();
1187 MainViewCallback_updateCanvas(MainView *mview)
1189 if (gUseGUI && mview != NULL && mview->ref != NULL) {
1190 ((MoleculeView *)(mview->ref))->canvas->Update();
1195 MainViewCallback_setKeyboardFocus(MainView *mview)
1197 if (gUseGUI && mview != NULL && mview->ref != NULL) {
1198 ((MoleculeView *)(mview->ref))->canvas->SetFocus();
1203 MainViewCallback_enableToggleButton(MainView *mview, int mode, int flag)
1205 if (mode >= kTrackballRotateMode && mode <= kTrackballEraseMode)
1206 ((MoleculeView *)(mview->ref))->GetToggleButtonAtIndex(mode - kTrackballRotateMode)->Enable(flag);
1210 MainViewCallback_clearLabels(MainView *mview)
1214 if (mview != NULL && mview->ref != NULL) {
1215 id view = [(MyWindowController *)(mview->ref) myOverlayView];
1216 NSRect bounds = [view bounds];
1218 NSEraseRect(bounds);
1219 [[NSColor cyanColor] set];
1220 bounds.origin.x = bounds.size.width / 2;
1221 NSFrameRect(bounds);
1223 [view setNeedsDisplay: YES];
1229 MainViewCallback_drawLabel(MainView *mview, const float *pos, const char *label)
1233 if (mview != NULL && mview->ref != NULL) {
1234 id view = [(MyWindowController *)(mview->ref) myOverlayView];
1235 NSString *s = [NSString stringWithUTF8String: label];
1236 NSDictionary *attr = [(MyWindowController *)(mview->ref) labelAttributes];
1238 [s drawAtPoint: NSMakePoint(pos[0], pos[1]) withAttributes: attr];
1240 [view setNeedsDisplay: YES];
1246 MainViewCallback_drawInfoText(MainView *mview, const char *label)
1248 if (gUseGUI && mview != NULL && mview->ref != NULL) {
1249 wxString labelstr(label, WX_DEFAULT_CONV);
1250 ((MoleculeView *)(mview->ref))->infotext->SetLabel(labelstr);
1255 MainViewCallback_mouseCheck(MainView *mview)
1261 MainViewCallback_selectMatrixCellForMode(MainView *mview, int mode)
1263 if (mview != NULL && mview->ref != NULL)
1264 ((MoleculeView *)(mview->ref))->SelectButtonForMode(mode);
1268 //MainViewCallback_getTag(MainView *mview)
1270 // if (mview != NULL && mview->ref != NULL)
1271 // return [(MyWindowController *)(mview->ref) myTag];
1276 MainViewCallback_viewWithTag(int tag)
1278 wxList &doclist = wxGetApp().DocManager()->GetDocuments();
1279 wxList::iterator iter;
1281 for (i = 0, iter = doclist.begin(); iter != doclist.end(); ++i, ++iter) {
1283 return ((MoleculeView *)(((MyDocument *)(*iter))->GetFirstView()))->mview;
1287 //wxList::compatibility_iterator iter = doclist.Item(tag);
1289 // return (MyDocument *)(*iter)->GetFirstView()->mview;
1293 // if (sMyWindowControllers == nil)
1295 // for (i = [sMyWindowControllers count] - 1; i >= 0; i--) {
1296 // id obj = [sMyWindowControllers objectAtIndex: i];
1297 // if ([obj myTag] == tag)
1298 // return [obj mainView];
1304 MainViewCallback_activeView(void)
1306 if (sActiveViews.GetCount() == 0)
1309 MoleculeView *aview = sActiveViews.Item(0);
1310 return aview->mview;
1312 // MoleculeView *cview = (MoleculeView *)(wxGetApp().DocManager()->GetCurrentView());
1313 // if (cview == NULL)
1316 // return cview->mview;
1321 MainViewCallback_newFromFile(const char *fname)
1324 wxDocManager *manager = wxGetApp().DocManager();
1325 if (fname == NULL || *fname == 0) {
1326 doc = manager->CreateDocument(wxT(""), wxDOC_NEW);
1328 wxString fnamestr(fname, wxConvFile);
1329 doc = manager->CreateDocument(fnamestr, wxDOC_SILENT);
1331 return MainViewCallback_activeView();
1336 MainViewCallback_importFromFile(MainView *mview, const char *fname)
1339 if (mview != NULL && mview->ref != NULL && (doc = (((MoleculeView *)(mview->ref))->MolDocument())) != NULL) {
1340 wxString fnamestr(fname, wxConvFile);
1341 // doc->importFromFile(fnamestr);
1342 MainViewCallback_setNeedsDisplay(mview, 1);
1349 MainViewCallback_getFilename(MainView *mview, char *buf, int bufsize)
1352 if (mview != NULL && mview->ref != NULL && (doc = (((MoleculeView *)(mview->ref))->MolDocument())) != NULL) {
1354 fname = doc->GetFilename();
1355 strncpy(buf, (const char*)fname.mb_str(wxConvFile), bufsize - 1);
1356 buf[bufsize - 1] = 0;
1364 MainViewCallback_moleculeReplaced(MainView *mview, struct Molecule *mol)
1366 if (mview != NULL && mview->ref != NULL) {
1367 MyDocument *doc = ((MoleculeView *)(mview->ref))->MolDocument();
1369 doc->SetMolecule(mol);
1370 MyListCtrl *listctrl = ((MoleculeView *)(mview->ref))->GetListCtrl();
1371 if (listctrl != NULL)
1372 listctrl->SetDataSource((MoleculeView *)(mview->ref));
1377 typedef struct Label {
1378 // StringTexture *tex;
1382 MainViewCallback_newLabel(MainView *mview, const char *message, float fontsize, const float *forecolor, const float *backcolor)
1387 NSColor *textColor, *boxColor;
1388 label = (Label *)malloc(sizeof(Label));
1391 memset(label, 0, sizeof(Label));
1392 // MainViewCallback_lockFocus(mview);
1393 if (forecolor != NULL)
1394 textColor = [NSColor colorWithDeviceRed: forecolor[0] green: forecolor[1] blue: forecolor[2] alpha: forecolor[3]];
1396 textColor = [NSColor whiteColor];
1397 if (backcolor != NULL)
1398 boxColor = [NSColor colorWithDeviceRed: backcolor[0] green: backcolor[1] blue: backcolor[2] alpha: backcolor[3]];
1400 boxColor = [NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:0.0f];
1401 attr = [NSDictionary dictionaryWithObjectsAndKeys: [NSFont userFontOfSize: fontsize], NSFontAttributeName, textColor, NSForegroundColorAttributeName, nil];
1402 label->tex = [[StringTexture alloc]
1403 initWithString: [NSString stringWithUTF8String: message]
1404 withAttributes: attr
1405 withTextColor: textColor
1406 withBoxColor: boxColor
1407 withBorderColor: [NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:0.0f]];
1408 // MainViewCallback_unlockFocus(mview);
1415 MainViewCallback_releaseLabel(struct Label *label)
1417 /* if (label != NULL) {
1418 [label->tex release];
1425 MainViewCallback_drawLabelAtPoint(struct Label *label, const float *pos)
1428 if (label != NULL && pos != NULL) {
1429 // GLint matrixMode;
1430 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1431 // glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
1432 // glMatrixMode(GL_MODELVIEW);
1434 // glTranslatef(0.0f, 0.0f, pos[3]);
1435 [label->tex drawAtPoint: NSMakePoint(pos[0], pos[1]) withDepth: pos[2]];
1437 // glMatrixMode (matrixMode);
1443 MainViewCallback_labelSize(struct Label *label, float *outSize)
1445 /* if (label != NULL) {
1446 NSSize size = [label->tex frameSize];
1447 if (outSize != NULL) {
1448 outSize[0] = size.width;
1449 outSize[1] = size.height;
1456 MainViewCallback_exportGraphic(MainView *mview, const char *fname, float scale, int bg_color, int width, int height)
1460 if (mview != NULL && mview->ref != NULL && ((MoleculeView *)(mview->ref))->MolDocument() != NULL) {
1461 wxString fnamestr(fname, wxConvFile);
1462 return ((MoleculeView *)(mview->ref))->DoExportGraphic(fnamestr, scale, bg_color, width, height);
1467 #pragma mark ====== Plain C Interface (MyListCtrl) ======
1469 /* These interface functions are also used for accessing MyListCtrl of GlobalParameterFrame (when mview == NULL) */
1472 s_MyListCtrlFromMainView(MainView *mview)
1475 return wxGetApp().GetGlobalParameterListCtrl();
1476 if (mview != NULL && mview->ref != NULL)
1477 return ((MoleculeView *)(mview->ref))->GetListCtrl();
1482 MainViewCallback_selectTable(MainView *mview, int idx)
1484 if (mview != NULL && mview->ref != NULL)
1485 ((MoleculeView *)(mview->ref))->SelectTable(idx);
1489 MainViewCallback_numberOfTableColumns(MainView *mview)
1491 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1492 if (listctrl != NULL)
1493 return listctrl->GetColumnCount();
1498 MainViewCallback_addTableColumn(MainView *mview, const char *name, int width, int editable)
1501 wxString nstr(name, WX_DEFAULT_CONV);
1502 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1503 if (listctrl == NULL)
1505 idx = listctrl->GetColumnCount();
1506 listctrl->InsertColumn(idx, nstr, wxLIST_FORMAT_LEFT);
1507 listctrl->SetColumnWidth(idx, FromFrameDIP(listctrl, width * 10));
1512 MainViewCallback_removeTableColumnAtIndex(MainView *mview, int idx)
1515 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1516 if (listctrl == NULL)
1518 ncolumns = listctrl->GetColumnCount();
1519 if (idx >= 0 && idx < ncolumns) {
1520 listctrl->DeleteColumn(idx);
1527 MainViewCallback_reloadTableData(MainView *mview)
1529 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1530 if (listctrl != NULL)
1531 listctrl->RefreshTable();
1533 int nrows = MainView_numberOfRowsInTable(mview);
1534 listctrl->SetItemCount(nrows);
1536 listctrl->RefreshItems(0, nrows - 1);
1541 MainViewCallback_setTableSelection(MainView *mview, IntGroup *selection)
1544 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1545 if (listctrl == NULL)
1548 listctrl->EnableSelectionChangeNotification(false);
1549 if (selection != NULL) {
1550 for (i = 0; (n1 = IntGroupGetStartPoint(selection, i)) >= 0; i++) {
1551 n2 = IntGroupGetEndPoint(selection, i);
1553 listctrl->SetItemState(n, 0, wxLIST_STATE_SELECTED);
1557 listctrl->SetItemState(n, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
1562 listctrl->RefreshTable();
1563 n1 = MainView_numberOfRowsInTable(mview);
1565 listctrl->SetItemState(n, 0, wxLIST_STATE_SELECTED);
1568 // listctrl->RefreshItems(0, n1 - 1);
1570 // EVT_LIST_ITEM_SELECTED is sent by wxPostEvent rather than ProcessEvent,
1571 // so re-enable of table selection event should also be sent by wxPostEvent.
1572 // Otherwise, the enable flag is set to true _before_ EVT_LIST_ITEM_SELECTED is sent.
1573 wxCommandEvent myEvent(MyListCtrlEvent, MyListCtrlEvent_enableTableSelectionNotification);
1574 wxPostEvent(listctrl, myEvent);
1579 MainViewCallback_getTableSelection(MainView *mview)
1583 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1584 if (listctrl == NULL)
1587 n = MainView_numberOfRowsInTable(mview);
1588 for (i = 0; i < n; i++) {
1589 if (listctrl->GetItemState(i, wxLIST_STATE_SELECTED) != 0)
1590 IntGroupAdd(ig, i, 1);
1596 MainViewCallback_showTable(MainView *mview)
1598 // if (mview != NULL && mview->ref != NULL) {
1599 // MyDocument *doc = (MyDocument *)[(id)(mview->ref) document];
1600 // [doc showTable: doc];
1605 MainViewCallback_hideTable(MainView *mview)
1607 // if (mview != NULL && mview->ref != NULL) {
1608 // MyDocument *doc = (MyDocument *)[(id)(mview->ref) document];
1609 // [doc hideTable: doc];
1614 MainViewCallback_ensureVisible(MainView *mview, int row)
1616 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1617 if (listctrl != NULL)
1618 listctrl->EnsureVisible(row);
1622 MainViewCallback_startEditText(MainView *mview, int row, int column)
1624 MyListCtrl *listctrl = s_MyListCtrlFromMainView(mview);
1625 if (listctrl != NULL)
1626 listctrl->StartEditText(row, column);