1 /*
2 * indi_gui.cpp
3 * PHD Guiding
4 *
5 * Copyright(c) 2009 Geoffrey Hausheer. All rights reserved.
6 *
7 * Redraw for libindi/baseclient by Patrick Chevalley
8 * Copyright (c) 2014 Patrick Chevalley
9 * All rights reserved.
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 * Contact Information: gcx@phracturedblue.com <Geoffrey Hausheer>
26 *******************************************************************************/
27
28 #ifdef _WIN32
29 #pragma warning(disable: 4996)
30 #endif
31
32 #include "phd.h"
33 #include "indi_gui.h"
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <wx/progdlg.h>
39
40 /*
41 * Status LED
42 */
43 class IndiStatus : public wxLed
44 {
45 public:
IndiStatus(wxWindow * parent,wxWindowID id,IPState state)46 IndiStatus(wxWindow *parent, wxWindowID id, IPState state) : wxLed(parent, id)
47 {
48 SetState(state);
49 Enable();
50 }
51
SetState(int state)52 void SetState(int state)
53 {
54 static const char indi_state[4][6] = {
55 "Idle",
56 "Ok",
57 "Busy",
58 "Alert",
59 };
60 switch(state) {
61 case IPS_IDLE: SetColor("808080"); break;
62 case IPS_OK: SetColor("008000"); break;
63 case IPS_BUSY: SetColor("FFFF00"); break;
64 case IPS_ALERT: SetColor("FF0000"); break;
65 }
66 SetToolTip(wxString::FromAscii(indi_state[state]));
67 }
68 };
69
70 /*
71 * A device page and related properties
72 */
73 class IndiDev
74 {
75 public:
76 wxNotebook *page;
77 INDI::BaseDevice *dp;
78 PtrHash groups;
79 PtrHash properties;
80 };
81
82 /*
83 * Property Information
84 */
85 class IndiProp
86 {
87 public:
88 wxString PropName;
89 PtrHash ctrl;
90 PtrHash entry;
91 IndiStatus *state;
92 wxStaticText *name;
93 wxPanel *page;
94 wxPanel *panel;
95 wxGridBagSizer *gbs;
96 INDI::Property *property;
97 IndiDev *idev;
98 };
99
100 enum
101 {
102 SWITCH_CHECKBOX,
103 SWITCH_BUTTON,
104 SWITCH_COMBOBOX,
105 };
106
107 #define POS(r, c) wxGBPosition(r,c)
108 #define SPAN(r, c) wxGBSpan(r,c)
109
110 wxDEFINE_EVENT(INDIGUI_THREAD_NEWDEVICE_EVENT, wxThreadEvent);
111 wxDEFINE_EVENT(INDIGUI_THREAD_NEWPROPERTY_EVENT, wxThreadEvent);
112 wxDEFINE_EVENT(INDIGUI_THREAD_NEWNUMBER_EVENT, wxThreadEvent);
113 wxDEFINE_EVENT(INDIGUI_THREAD_NEWTEXT_EVENT, wxThreadEvent);
114 wxDEFINE_EVENT(INDIGUI_THREAD_NEWSWITCH_EVENT, wxThreadEvent);
115 wxDEFINE_EVENT(INDIGUI_THREAD_NEWMESSAGE_EVENT, wxThreadEvent);
116 wxDEFINE_EVENT(INDIGUI_THREAD_REMOVEPROPERTY_EVENT, wxThreadEvent);
117
wxBEGIN_EVENT_TABLE(IndiGui,wxDialog)118 wxBEGIN_EVENT_TABLE(IndiGui, wxDialog)
119 EVT_CLOSE(IndiGui::OnQuit)
120 EVT_THREAD(INDIGUI_THREAD_NEWDEVICE_EVENT, IndiGui::OnNewDeviceFromThread)
121 EVT_THREAD(INDIGUI_THREAD_NEWPROPERTY_EVENT, IndiGui::OnNewPropertyFromThread)
122 EVT_THREAD(INDIGUI_THREAD_NEWNUMBER_EVENT, IndiGui::OnNewNumberFromThread)
123 EVT_THREAD(INDIGUI_THREAD_NEWTEXT_EVENT, IndiGui::OnNewTextFromThread)
124 EVT_THREAD(INDIGUI_THREAD_NEWSWITCH_EVENT, IndiGui::OnNewSwitchFromThread)
125 EVT_THREAD(INDIGUI_THREAD_NEWMESSAGE_EVENT, IndiGui::OnNewMessageFromThread)
126 EVT_THREAD(INDIGUI_THREAD_REMOVEPROPERTY_EVENT, IndiGui::OnRemovePropertyFromThread)
127 wxEND_EVENT_TABLE()
128
129 //////////////////////////////////////////////////////////////////////
130 // Functions running in the INDI client thread
131 //////////////////////////////////////////////////////////////////////
132
133 void IndiGui::newDevice(INDI::BaseDevice *dp)
134 {
135 wxThreadEvent *event = new wxThreadEvent(wxEVT_THREAD, INDIGUI_THREAD_NEWDEVICE_EVENT);
136 event->SetExtraLong((long) dp);
137 wxQueueEvent(this, event);
138 }
139
newProperty(INDI::Property * property)140 void IndiGui::newProperty(INDI::Property *property)
141 {
142 wxThreadEvent *event = new wxThreadEvent(wxEVT_THREAD, INDIGUI_THREAD_NEWPROPERTY_EVENT);
143 event->SetExtraLong((long) property);
144 wxQueueEvent(this, event);
145 }
146
newNumber(INumberVectorProperty * nvp)147 void IndiGui::newNumber(INumberVectorProperty *nvp)
148 {
149 wxThreadEvent *event = new wxThreadEvent(wxEVT_THREAD, INDIGUI_THREAD_NEWNUMBER_EVENT);
150 event->SetExtraLong((long) nvp);
151 wxQueueEvent(this, event);
152 }
153
newSwitch(ISwitchVectorProperty * svp)154 void IndiGui::newSwitch(ISwitchVectorProperty *svp)
155 {
156 wxThreadEvent *event = new wxThreadEvent(wxEVT_THREAD, INDIGUI_THREAD_NEWSWITCH_EVENT);
157 event->SetExtraLong((long) svp);
158 wxQueueEvent(this, event);
159 }
160
newText(ITextVectorProperty * tvp)161 void IndiGui::newText(ITextVectorProperty *tvp)
162 {
163 wxThreadEvent *event = new wxThreadEvent(wxEVT_THREAD, INDIGUI_THREAD_NEWTEXT_EVENT);
164 event->SetExtraLong((long) tvp);
165 wxQueueEvent(this, event);
166 }
167
newMessage(INDI::BaseDevice * dp,int messageID)168 void IndiGui::newMessage(INDI::BaseDevice *dp, int messageID)
169 {
170 wxThreadEvent *event = new wxThreadEvent(wxEVT_THREAD, INDIGUI_THREAD_NEWMESSAGE_EVENT);
171 event->SetString(dp->messageQueue(messageID));
172 wxQueueEvent(this, event);
173 }
174
removeProperty(INDI::Property * property)175 void IndiGui::removeProperty(INDI::Property *property)
176 {
177 if (property)
178 {
179 wxString devname = wxString::FromAscii(property->getDeviceName());
180 wxString groupname = wxString::FromAscii(property->getGroupName());
181 wxString propname = wxString::FromAscii(property->getName());
182 IndiDev *indiDev = (IndiDev *)devlist[devname];
183 if (!indiDev) return;
184 IndiProp *indiProp = (IndiProp *)indiDev->properties[propname];
185 if (!indiProp) return;
186
187 wxThreadEvent *event = new wxThreadEvent(wxEVT_THREAD, INDIGUI_THREAD_REMOVEPROPERTY_EVENT);
188 event->SetExtraLong((long) indiProp);
189 wxQueueEvent(this, event);
190 }
191 }
192
193 //////////////////////////////////////////////////////////////////////
194
ConnectServer(const wxString & INDIhost,long INDIport)195 void IndiGui::ConnectServer(const wxString& INDIhost, long INDIport)
196 {
197 setServer(INDIhost.mb_str(wxConvUTF8), INDIport);
198 connectServer();
199 }
200
serverConnected()201 void IndiGui::serverConnected()
202 {
203 setBLOBMode(B_NEVER, "", nullptr);
204 m_lastUpdate = wxGetUTCTimeMillis();
205 }
206
IndiServerDisconnected(int exit_code)207 void IndiGui::IndiServerDisconnected(int exit_code)
208 {
209 if (m_deleted)
210 {
211 // nothing to do if we're getting the notification via the
212 // disconnectServer() call from the destructor
213 return;
214 }
215
216 if (wxThread::IsMain())
217 {
218 Destroy();
219 }
220 else
221 {
222 wxCloseEvent *event = new wxCloseEvent(wxEVT_CLOSE_WINDOW, GetId());
223 event->SetEventObject(this);
224 event->SetCanVeto(false);
225 wxQueueEvent(this, event);
226 }
227 }
228
OnNewDeviceFromThread(wxThreadEvent & event)229 void IndiGui::OnNewDeviceFromThread(wxThreadEvent& event)
230 {
231 INDI::BaseDevice *dp = (INDI::BaseDevice *) event.GetExtraLong();
232 //printf("newdevice from thread %s \n",dp->getDeviceName());
233 wxString devname = wxString::FromAscii(dp->getDeviceName());
234 IndiDev *indiDev = new IndiDev();
235 wxPanel *panel = new wxPanel(parent_notebook);
236 indiDev->page = new wxNotebook(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP);
237 wxBoxSizer *nb_sizer = new wxBoxSizer(wxVERTICAL);
238 panel->SetSizer(nb_sizer);
239 nb_sizer->Add(indiDev->page, 1, wxEXPAND | wxALL);
240 parent_notebook->AddPage(panel, devname);
241 indiDev->dp = dp;
242 devlist[devname] = indiDev;
243 panel->Fit();
244 sizer->Layout();
245 Fit();
246 m_lastUpdate = wxGetUTCTimeMillis();
247 }
248
OnNewPropertyFromThread(wxThreadEvent & event)249 void IndiGui::OnNewPropertyFromThread(wxThreadEvent& event)
250 {
251 INDI::Property *property = (INDI::Property *) event.GetExtraLong();
252 //printf("newproperty from thread %s %s %s\n",property->getDeviceName(),property->getGroupName(),property->getName());
253 wxString devname = wxString::FromAscii(property->getDeviceName());
254 wxString groupname = wxString::FromAscii(property->getGroupName());
255 wxString propname = wxString::FromAscii(property->getName());
256
257 IndiProp *indiProp = new IndiProp();
258 wxPanel *page;
259 wxGridBagSizer *gbs;
260 int next_free_row;
261 IndiDev *indiDev = (IndiDev *)devlist[devname];
262 if (! indiDev) return;
263 indiProp->idev = indiDev;
264
265 page = (wxPanel *)indiDev->groups[groupname];
266 if (!page)
267 {
268 page = new wxPanel(indiDev->page);
269 indiDev->page->AddPage(page, groupname);
270 page->SetSizer(new wxGridBagSizer(0, 20));
271 indiDev->groups[groupname] = page;
272 }
273
274 gbs = (wxGridBagSizer *)page->GetSizer();
275 gbs->Layout();
276 next_free_row = gbs->GetRows();
277 BuildPropWidget(property, page, indiProp);
278
279 gbs->Add(indiProp->state, POS(next_free_row, 0), SPAN(1, 1), wxALIGN_LEFT | wxALL);
280 gbs->Add(indiProp->name, POS(next_free_row, 1), SPAN(1, 1), wxALIGN_LEFT | wxALL);
281 gbs->Add(indiProp->panel,POS(next_free_row, 2), SPAN(1, 1), wxALIGN_LEFT | wxEXPAND | wxALL);
282 gbs->Layout();
283 page->Fit();
284 panel->Fit();
285 indiDev->properties[propname] = indiProp;
286 indiDev->page->Fit();
287 indiDev->page->Layout();
288 indiDev->page->Show();
289 sizer->Layout();
290 Fit();
291 m_lastUpdate = wxGetUTCTimeMillis();
292 }
293
BuildPropWidget(INDI::Property * property,wxPanel * parent,IndiProp * indiProp)294 void IndiGui::BuildPropWidget(INDI::Property *property, wxPanel *parent, IndiProp *indiProp)
295 {
296 wxString propname = wxString::FromAscii(property->getName());
297 wxString proplbl = wxString::FromAscii(property->getLabel());
298 if (! proplbl) proplbl = propname;
299 #ifdef INDI_PRE_1_1_0
300 INDI_TYPE proptype = property->getType();
301 #else
302 INDI_PROPERTY_TYPE proptype = property->getType();
303 #endif
304
305 indiProp->page = parent;
306 indiProp->panel = new wxPanel(parent);
307 indiProp->gbs = new wxGridBagSizer(0, 20);
308 indiProp->panel->SetSizer(indiProp->gbs);
309
310 indiProp->state = new IndiStatus(parent, wxID_ANY, property->getState());
311 indiProp->name = new wxStaticText(parent, wxID_ANY,proplbl);
312 indiProp->PropName = propname;
313 indiProp->property = property;
314
315 switch (proptype) {
316 case INDI_TEXT:
317 CreateTextWidget(property, indiProp);
318 break;
319 case INDI_SWITCH:
320 CreateSwitchWidget(property, indiProp);
321 break;
322 case INDI_NUMBER:
323 CreateNumberWidget(property, indiProp);
324 break;
325 case INDI_LIGHT:
326 CreateLightWidget(property, indiProp);
327 break;
328 case INDI_BLOB:
329 CreateBlobWidget(property, indiProp);
330 break;
331 case INDI_UNKNOWN:
332 CreateUnknowWidget(property, indiProp);
333 break;
334 }
335 indiProp->gbs->Layout();
336 }
337
GetSwitchType(ISwitchVectorProperty * svp)338 int IndiGui::GetSwitchType(ISwitchVectorProperty *svp)
339 {
340 int num_props = svp->nsp;
341
342 if (svp->r == ISR_NOFMANY)
343 return SWITCH_CHECKBOX;
344
345 if (num_props <= 4)
346 return SWITCH_BUTTON;
347
348 return SWITCH_COMBOBOX;
349 }
350
CreateSwitchWidget(INDI::Property * property,IndiProp * indiProp)351 void IndiGui::CreateSwitchWidget(INDI::Property *property, IndiProp *indiProp)
352 {
353 //printf("CreateSwitchWidget\n");
354 int guitype = GetSwitchType(property->getSwitch());
355
356 switch (guitype) {
357 case SWITCH_COMBOBOX: CreateSwitchCombobox(property->getSwitch(), indiProp); break;
358 case SWITCH_CHECKBOX: CreateSwitchCheckbox(property->getSwitch(), indiProp); break;
359 case SWITCH_BUTTON: CreateSwitchButton(property->getSwitch(), indiProp); break;
360 }
361 }
362
CreateSwitchCombobox(ISwitchVectorProperty * svp,IndiProp * indiProp)363 void IndiGui::CreateSwitchCombobox(ISwitchVectorProperty *svp, IndiProp *indiProp)
364 {
365 wxString *choices = new wxString[svp->nsp];
366 wxPanel *p = indiProp->panel;
367 wxGridBagSizer *gbs = indiProp->gbs;
368
369 int idx = 0;
370 for (int i = 0; i < svp->nsp; i++)
371 {
372 if(svp->sp[i].s == ISS_ON)
373 idx = i;
374 indiProp->ctrl[wxString::FromAscii(svp->sp[i].name)] = (void *) (intptr_t) i;
375 wxString swlbl = wxString::FromAscii(svp->sp[i].label);
376 if (swlbl.empty())
377 swlbl = wxString::FromAscii(svp->sp[i].name);
378 choices[i] = swlbl;
379 }
380 wxChoice *combo = new wxChoice(p, wxID_ANY, wxDefaultPosition, wxDefaultSize, svp->nsp, choices);
381 combo->SetSelection(idx);
382 combo->SetClientData(indiProp);
383 Connect(combo->GetId(), wxEVT_COMMAND_CHOICE_SELECTED,
384 wxCommandEventHandler(IndiGui::SetComboboxEvent));
385 gbs->Add(combo, POS(0, 0), SPAN(1, 1), wxALIGN_LEFT | wxALL);
386 indiProp->ctrl[wxString::FromAscii(svp->name)] = (void *) combo;
387 delete [] choices;
388 }
389
CreateSwitchCheckbox(ISwitchVectorProperty * svp,IndiProp * indiProp)390 void IndiGui::CreateSwitchCheckbox(ISwitchVectorProperty *svp, IndiProp *indiProp)
391 {
392 wxPanel *p = indiProp->panel;
393 wxGridBagSizer *gbs = indiProp->gbs;
394 for (int pos = 0; pos < svp->nsp; pos++)
395 {
396 wxString swlbl = wxString::FromAscii(svp->sp[pos].label);
397 if (swlbl.empty())
398 swlbl = wxString::FromAscii(svp->sp[pos].name);
399 wxCheckBox *button = new wxCheckBox(p, wxID_ANY, swlbl);
400 indiProp->ctrl[wxString::FromAscii(svp->sp[pos].name)] = button;
401 if (svp->sp[pos].s == ISS_ON)
402 button->SetValue(true);
403 button->SetClientData(indiProp);
404 Connect(button->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED,
405 wxCommandEventHandler(IndiGui::SetCheckboxEvent));
406 gbs->Add(button, POS(pos / 4, pos % 4), SPAN(1, 1), wxALIGN_LEFT | wxALL);
407 }
408 }
409
CreateSwitchButton(ISwitchVectorProperty * svp,IndiProp * indiProp)410 void IndiGui::CreateSwitchButton(ISwitchVectorProperty *svp, IndiProp *indiProp)
411 {
412 wxPanel *p = indiProp->panel;
413 wxGridBagSizer *gbs = indiProp->gbs;
414 for (int pos = 0; pos < svp->nsp; pos++)
415 {
416 wxString swlbl = wxString::FromAscii(svp->sp[pos].label);
417 if (swlbl.empty())
418 swlbl = wxString::FromAscii(svp->sp[pos].name);
419 wxToggleButton *button = new wxToggleButton(p, wxID_ANY, swlbl);
420 indiProp->ctrl[wxString::FromAscii(svp->sp[pos].name)] = button;
421 if (svp->sp[pos].s == ISS_ON)
422 button->SetValue(true);
423 button->SetClientData(indiProp);
424 Connect(button->GetId(), wxEVT_COMMAND_TOGGLEBUTTON_CLICKED,
425 wxCommandEventHandler(IndiGui::SetToggleButtonEvent));
426 if (!allow_connect_disconnect && strcmp(svp->name,"CONNECTION") == 0)
427 {
428 button->Enable(false);
429 }
430 gbs->Add(button, POS(0, pos), SPAN(1, 1), wxALIGN_LEFT | wxALL);
431 }
432 }
433
CreateTextWidget(INDI::Property * property,IndiProp * indiProp)434 void IndiGui::CreateTextWidget(INDI::Property *property, IndiProp *indiProp)
435 {
436 ITextVectorProperty *tvp = property->getText();
437 wxPanel *p = indiProp->panel;
438 wxGridBagSizer *gbs = indiProp->gbs;
439
440 int pos;
441 for (pos = 0; pos < tvp->ntp; pos++)
442 {
443 gbs->Add(new wxStaticText(p, wxID_ANY, wxString::FromAscii(tvp->tp[pos].label)),
444 POS(pos, 0), SPAN(1, 1), wxALIGN_LEFT | wxALL);
445
446 wxStaticText *value = new wxStaticText(p, wxID_ANY, wxString::FromAscii(tvp->tp[pos].text));
447 indiProp->ctrl[wxString::FromAscii(tvp->tp[pos].name)] = value;
448 gbs->Add(value, POS(pos, 1), SPAN(1, 1), wxALIGN_LEFT | wxALL);
449 if (tvp->p != IP_RO)
450 {
451 wxTextCtrl *entry = new wxTextCtrl(p, wxID_ANY);
452 indiProp->entry[wxString::FromAscii(tvp->tp[pos].name)] = entry;
453 gbs->Add(entry, POS(pos, 2), SPAN(1, 1), wxALIGN_LEFT | wxEXPAND | wxALL);
454 }
455 }
456 if (tvp->p != IP_RO)
457 {
458 wxButton *button = new wxButton(p, wxID_ANY, _("Set"));
459 button->SetClientData(indiProp);
460 Connect(button->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(IndiGui::SetButtonEvent));
461 gbs->Add(button, POS(0, 3), SPAN(pos, 1), wxALIGN_LEFT | wxALL);
462 }
463 }
464
CreateNumberWidget(INDI::Property * property,IndiProp * indiProp)465 void IndiGui::CreateNumberWidget(INDI::Property *property, IndiProp *indiProp)
466 {
467 INumberVectorProperty *nvp = property->getNumber();
468 wxPanel *p = indiProp->panel;
469 wxGridBagSizer *gbs = indiProp->gbs;
470
471 int pos;
472 for (pos = 0; pos < nvp->nnp; pos++)
473 {
474 gbs->Add(new wxStaticText(p, wxID_ANY, wxString::FromAscii(nvp->np[pos].label)),
475 POS(pos, 0), SPAN(1, 1), wxALIGN_LEFT | wxALL);
476
477 wxStaticText *value = new wxStaticText(p, wxID_ANY, wxString::Format(_T("%f"), nvp->np[pos].value));
478 indiProp->ctrl[wxString::FromAscii(nvp->np[pos].name)] = value;
479 gbs->Add(value, POS(pos, 1), SPAN(1, 1), wxALIGN_LEFT | wxALL);
480 if (nvp->p != IP_RO)
481 {
482 wxTextCtrl *entry = new wxTextCtrl(p, wxID_ANY);
483 indiProp->entry[wxString::FromAscii(nvp->np[pos].name)] = entry;
484 gbs->Add(entry, POS(pos, 2), SPAN(1, 1), wxALIGN_LEFT | wxEXPAND | wxALL);
485 }
486 }
487 if (nvp->p != IP_RO)
488 {
489 wxButton *button = new wxButton(p, wxID_ANY, _("Set"));
490 button->SetClientData(indiProp);
491 Connect(button->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(IndiGui::SetButtonEvent));
492 gbs->Add(button, POS(0, 3), SPAN(pos, 1), wxALIGN_LEFT | wxALL);
493 }
494 }
495
CreateLightWidget(INDI::Property * property,IndiProp * indiProp)496 void IndiGui::CreateLightWidget(INDI::Property *property, IndiProp *indiProp)
497 {
498 //printf("IndiGui: Unimplemented CreateLightWidget\n");
499 }
500
CreateBlobWidget(INDI::Property * property,IndiProp * indiProp)501 void IndiGui::CreateBlobWidget(INDI::Property *property, IndiProp *indiProp)
502 {
503 //printf("IndiGui: Unimplemented CreateBlobWidget\n");
504 }
505
CreateUnknowWidget(INDI::Property * property,IndiProp * indiProp)506 void IndiGui::CreateUnknowWidget(INDI::Property *property, IndiProp *indiProp)
507 {
508 //printf("IndiGui: Unimplemented CreateUnknowWidget\n");
509 }
510
OnNewNumberFromThread(wxThreadEvent & event)511 void IndiGui::OnNewNumberFromThread(wxThreadEvent& event)
512 {
513 INumberVectorProperty *nvp = (INumberVectorProperty *) event.GetExtraLong();
514 wxString devname = wxString::FromAscii(nvp->device);
515 wxString propname = wxString::FromAscii(nvp->name);
516 IndiDev *indiDev = (IndiDev *) devlist[devname];
517 IndiProp *indiProp = (IndiProp *) indiDev->properties[propname];
518 for (int i = 0; i < nvp->nnp; i++)
519 {
520 void *st = indiProp->ctrl[wxString::FromAscii(nvp->np[i].name)];
521 wxStaticText *ctrl = (wxStaticText *)st;
522 ctrl->SetLabel(wxString::Format(wxT("%f"), nvp->np[i].value));
523 }
524 indiProp->state->SetState(nvp->s);
525 }
526
OnNewTextFromThread(wxThreadEvent & event)527 void IndiGui::OnNewTextFromThread(wxThreadEvent& event)
528 {
529 ITextVectorProperty *tvp = (ITextVectorProperty *) event.GetExtraLong();
530 //printf("newtext from thread %s \n",tvp->name);
531 wxString devname = wxString::FromAscii(tvp->device);
532 wxString propname = wxString::FromAscii(tvp->name);
533 IndiDev *indiDev = (IndiDev *) devlist[devname];
534 IndiProp *indiProp = (IndiProp *) indiDev->properties[propname];
535 for (int i = 0; i < tvp->ntp; i++)
536 {
537 void *st = indiProp->ctrl[wxString::FromAscii(tvp->tp[i].name)];
538 wxStaticText *ctrl = (wxStaticText *)st;
539 ctrl->SetLabel(wxString::Format(wxT("%s"), tvp->tp[i].text));
540 }
541 indiProp->state->SetState(tvp->s);
542 }
543
OnNewSwitchFromThread(wxThreadEvent & event)544 void IndiGui::OnNewSwitchFromThread(wxThreadEvent& event)
545 {
546 ISwitchVectorProperty *svp = (ISwitchVectorProperty *) event.GetExtraLong();
547 wxString devname = wxString::FromAscii(svp->device);
548 wxString propname = wxString::FromAscii(svp->name);
549 int swtype = GetSwitchType(svp);
550 IndiDev *indiDev = (IndiDev *) devlist[devname];
551 IndiProp *indiProp = (IndiProp *) indiDev->properties[propname];
552 switch (swtype) {
553 case SWITCH_COMBOBOX: {
554 int idx=0;
555 for (int i = 0; i < svp->nsp; i++)
556 {
557 if (svp->sp[i].s == ISS_ON)
558 idx = i;
559 }
560 void *st = indiProp->ctrl[wxString::FromAscii(svp->name)];
561 wxChoice *combo = (wxChoice *)st;
562 combo->SetSelection(idx);
563 break;
564 }
565 case SWITCH_CHECKBOX:{
566 for (int i = 0; i < svp->nsp; i++)
567 {
568 void *st = indiProp->ctrl[wxString::FromAscii(svp->sp[i].name)];
569 wxCheckBox *button = (wxCheckBox *) st;
570 button->SetValue(svp->sp[i].s ? true : false);
571 }
572 break;
573 }
574 case SWITCH_BUTTON:{
575 for (int i = 0; i < svp->nsp; i++)
576 {
577 void *st = indiProp->ctrl[wxString::FromAscii(svp->sp[i].name)];
578 wxToggleButton *button = (wxToggleButton *) st;
579 button->SetValue(svp->sp[i].s ? true : false);
580 }
581 break;
582 }
583 }
584 }
585
OnNewMessageFromThread(wxThreadEvent & event)586 void IndiGui::OnNewMessageFromThread(wxThreadEvent& event)
587 {
588 textbuffer->SetInsertionPoint(0);
589 textbuffer->WriteText(event.GetString());
590 textbuffer->WriteText(_T("\n"));
591 }
592
SetButtonEvent(wxCommandEvent & event)593 void IndiGui::SetButtonEvent(wxCommandEvent& event)
594 {
595 wxButton *button = (wxButton *)event.GetEventObject();
596 if (!button) return;
597 IndiProp *indiProp = (IndiProp *) button->GetClientData();
598 if (!indiProp) return;
599
600 switch (indiProp->property->getType()) {
601 case INDI_TEXT: {
602 ITextVectorProperty *tvp = indiProp->property->getText();
603 for (int i = 0; i < tvp->ntp; i++)
604 {
605 if (tvp->p != IP_RO)
606 {
607 wxTextCtrl *entry = (wxTextCtrl *)(indiProp->entry[wxString::FromAscii(tvp->tp[i].name)]);
608 sprintf(tvp->tp[i].text, "%s", entry->GetLineText(0).mb_str().data());
609 }
610 }
611 sendNewText(tvp);
612 break;
613 }
614 case INDI_NUMBER:{
615 INumberVectorProperty *nvp = indiProp->property->getNumber();
616 for (int i = 0; i < nvp->nnp; i++)
617 {
618 if (nvp->p != IP_RO)
619 {
620 wxTextCtrl *entry = (wxTextCtrl *)(indiProp->entry[wxString::FromAscii(nvp->np[i].name)]);
621 entry->GetLineText(0).ToDouble(&nvp->np[i].value);
622 }
623 }
624 sendNewNumber(nvp);
625 break;
626 }
627 default:
628 break;
629 }
630 }
631
SetToggleButtonEvent(wxCommandEvent & event)632 void IndiGui::SetToggleButtonEvent(wxCommandEvent& event)
633 {
634 wxToggleButton *button = (wxToggleButton *)event.GetEventObject();
635 if (!button) return;
636 IndiProp *indiProp = (IndiProp *) button->GetClientData();
637 if (!indiProp) return;
638 ISwitchVectorProperty *svp = indiProp->property->getSwitch();
639
640 if (!allow_connect_disconnect && strcmp(svp->name, "CONNECTION") ==0 )
641 {
642 // Prevent device disconnection from this window.
643 // Use Gear manager instead.
644 return;
645 }
646
647 wxString b_name;
648 for (auto it = indiProp->ctrl.begin(); it !=indiProp->ctrl.end(); ++it)
649 {
650 wxString key = it->first;
651 wxToggleButton *value = (wxToggleButton *) it->second;
652 if (value == button)
653 {
654 b_name = key;
655 break;
656 }
657 }
658 if (svp->r == ISR_1OFMANY)
659 {
660 for (int i = 0; i < svp->nsp; i++)
661 {
662 if (svp->sp[i].name == b_name)
663 svp->sp[i].s = ISS_ON;
664 else
665 svp->sp[i].s = ISS_OFF;
666 }
667 }
668 else
669 {
670 for (int i = 0; i < svp->nsp; i++)
671 {
672 if (svp->sp[i].name == b_name)
673 {
674 svp->sp[i].s = button->GetValue() ? ISS_ON : ISS_OFF;
675 break;
676 }
677 }
678 }
679 sendNewSwitch(svp);
680 }
681
682
SetComboboxEvent(wxCommandEvent & event)683 void IndiGui::SetComboboxEvent(wxCommandEvent& event)
684 {
685 wxChoice *combo = (wxChoice *)event.GetEventObject();
686 if (!combo) return;
687 IndiProp *indiProp = (IndiProp *) combo->GetClientData();
688 if (!indiProp) return;
689 ISwitchVectorProperty *svp = indiProp->property->getSwitch();
690 int choice = combo->GetSelection();
691 for (int i = 0; i < svp->nsp; i++)
692 {
693 if (i == choice)
694 svp->sp[i].s = ISS_ON;
695 else
696 svp->sp[i].s = ISS_OFF;
697 }
698 sendNewSwitch(svp);
699 }
700
SetCheckboxEvent(wxCommandEvent & event)701 void IndiGui::SetCheckboxEvent(wxCommandEvent& event)
702 {
703 wxCheckBox *button = (wxCheckBox *)event.GetEventObject();
704 if (!button) return;
705 IndiProp *indiProp = (IndiProp *) button->GetClientData();
706 if (!indiProp) return;
707 ISwitchVectorProperty *svp = indiProp->property->getSwitch();
708
709 wxString b_name;
710 for (auto it = indiProp->ctrl.begin(); it !=indiProp->ctrl.end(); ++it)
711 {
712 wxString key = it->first;
713 wxCheckBox *value = (wxCheckBox *) it->second;
714 if (value == button)
715 {
716 b_name = key;
717 break;
718 }
719 }
720 for (int i = 0; i < svp->nsp; i++)
721 {
722 if (svp->sp[i].name == b_name)
723 {
724 svp->sp[i].s = button->GetValue() ? ISS_ON : ISS_OFF;
725 break;
726 }
727 }
728 sendNewSwitch(svp);
729 }
730
OnRemovePropertyFromThread(wxThreadEvent & event)731 void IndiGui::OnRemovePropertyFromThread(wxThreadEvent& event)
732 {
733 IndiProp *indiProp = (IndiProp *)event.GetExtraLong();
734 if (!indiProp) return;
735 IndiDev *indiDev = (IndiDev *) indiProp->idev;
736 if (!indiDev) return;
737 wxString propname = indiProp->PropName;
738
739 for (int y = 0; y < indiProp->gbs->GetRows(); y++)
740 {
741 for (int x = 0; x < indiProp->gbs->GetCols(); x++)
742 {
743 wxGBSizerItem *item = indiProp->gbs->FindItemAtPosition(POS(y, x));
744 if (item)
745 {
746 indiProp->gbs->Remove(item->GetId());
747 item->GetWindow()->Destroy();
748 }
749 }
750 }
751 indiProp->gbs->Layout();
752 if (indiProp->name)
753 indiProp->name->Destroy();
754 if (indiProp->state)
755 indiProp->state->Destroy();
756 if (indiProp->panel)
757 indiProp->panel->Destroy();
758 if (indiProp->page->GetChildren().GetCount() == 0)
759 {
760 for (unsigned int i = 0; i < indiDev->page->GetPageCount(); i++)
761 {
762 if (indiProp->page == indiDev->page->GetPage(i))
763 {
764 indiDev->groups.erase(indiDev->page->GetPageText(i));
765 indiDev->page->DeletePage(i);
766 break;
767 }
768 }
769 }
770 delete indiProp;
771 indiDev->properties.erase(propname);
772 indiDev->page->Layout();
773 indiDev->page->Fit();
774 sizer->Layout();
775 Fit();
776 m_lastUpdate = wxGetUTCTimeMillis();
777 }
778
ShowIndiGui(IndiGui ** ret,const wxString & host,long port,bool allow_connect_disconnect_,bool modal)779 void IndiGui::ShowIndiGui(IndiGui **ret, const wxString& host, long port, bool allow_connect_disconnect_, bool modal)
780 {
781 IndiGui *gui = new IndiGui();
782 gui->allow_connect_disconnect = allow_connect_disconnect_;
783 gui->ConnectServer(host, port);
784
785 {
786 wxProgressDialog dlg(_("INDI"), _("Loading INDI properties..."), 0, nullptr, wxPD_APP_MODAL | wxPD_CAN_ABORT);
787
788 enum { IDLE_TIME_MS = 500 };
789
790 unsigned int i = 0;
791 while (wxGetUTCTimeMillis().GetValue() - gui->m_lastUpdate.GetValue() < IDLE_TIME_MS)
792 {
793 wxSafeYield();
794 wxMilliSleep(10);
795 if (dlg.WasCancelled())
796 {
797 gui->Destroy();
798 *ret = nullptr;
799 return;
800 }
801 if (++i % 10 == 0)
802 dlg.Pulse();
803 }
804 }
805
806 gui->m_holder = ret;
807 *ret = gui;
808
809 if (modal)
810 gui->ShowModal();
811 else
812 gui->Show();
813 }
814
IndiGui()815 IndiGui::IndiGui()
816 :
817 wxDialog(wxGetApp().GetTopWindow(), wxID_ANY,
818 _("INDI Options"),
819 wxDefaultPosition, wxSize(640, 400), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
820 m_deleted(false),
821 m_holder(nullptr)
822 {
823 panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_DOUBLE | wxTAB_TRAVERSAL);
824 sizer = new wxBoxSizer(wxVERTICAL);
825 panel->SetSizer(sizer);
826 parent_notebook = new wxNotebook(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP);
827 sizer->Add(parent_notebook, 0, wxEXPAND | wxALL);
828 textbuffer = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
829 sizer->Add(textbuffer, 1, wxFIXED_MINSIZE | wxEXPAND | wxALL);
830 }
831
OnQuit(wxCloseEvent & WXUNUSED (event))832 void IndiGui::OnQuit(wxCloseEvent& WXUNUSED(event))
833 {
834 if (isServerConnected())
835 Show(false);
836 else
837 Destroy();
838 }
839
DestroyIndiGui(IndiGui ** holder)840 void IndiGui::DestroyIndiGui(IndiGui **holder)
841 {
842 IndiGui *gui = *holder;
843
844 // disconnect gui from owner
845 assert(holder == gui->m_holder);
846 *gui->m_holder = nullptr;
847 gui->m_holder = nullptr;
848
849 gui->Destroy();
850 }
851
~IndiGui()852 IndiGui::~IndiGui()
853 {
854 // prevent recursive destruction when DisconnectIndiServer() calls
855 // serverDisconnected() which calls Destroy()
856 m_deleted = true;
857
858 if (m_holder)
859 *m_holder = nullptr;
860
861 DisconnectIndiServer();
862
863 for (auto itdev = devlist.begin(); itdev != devlist.end(); ++itdev)
864 {
865 IndiDev *indiDev = (IndiDev *) itdev->second;
866 if (indiDev)
867 {
868 for (auto itprop = indiDev->properties.begin(); itprop != indiDev->properties.end(); ++itprop)
869 {
870 IndiProp *indiProp = (IndiProp *) itprop->second;
871 indiProp->ctrl.clear();
872 indiProp->entry.clear();
873 delete indiProp;
874 }
875 indiDev->properties.clear();
876 indiDev->groups.clear();
877 delete indiDev;
878 }
879 }
880 }
881