150 const unsigned m_size;
151 const fs::path m_svg_dir;
155 static unsigned GetSize(
const wxWindow* parent) {
156 double size = parent->GetCharHeight() * (IsWindows() ? 1.3 : 1.0);
157#if wxCHECK_VERSION(3, 1, 2)
160 size *=
static_cast<double>(parent->ToDIP(100)) / 100.;
164 double pixel_per_mm =
166 size = std::max(size, 7.0 * pixel_per_mm);
168 return static_cast<unsigned>(size);
171 [[nodiscard]] wxBitmap LoadIcon(
const std::string& filename)
const {
172 fs::path path = m_svg_dir / filename;
173 return LoadSVG(path.string(), m_size, m_size);
176 [[nodiscard]] wxBitmap IconApplyColorScheme(
const wxBitmap& proto)
const {
177 if (!proto.IsOk())
return wxNullBitmap;
178 if ((m_cs != GLOBAL_COLOR_SCHEME_DAY) &&
179 (m_cs != GLOBAL_COLOR_SCHEME_RGB)) {
181 const wxImage image = proto.ConvertToImage();
182 unsigned char* data = image.GetData();
183 unsigned char* p_idata = data;
184 for (
int i = 0; i < image.GetSize().y; i++) {
185 for (
int j = 0; j < image.GetSize().x; j++) {
186 unsigned char v = *p_idata;
203 explicit StdIcons(
const wxWindow* parent)
204 : m_size(GetSize(parent)),
205 m_svg_dir(fs::path(g_Platform->GetSharedDataDir().ToStdString()) /
206 "uidata" /
"MUI_flat"),
207 m_cs(GLOBAL_COLOR_SCHEME_RGB),
208 trash_bin_proto(LoadIcon(
"trash_bin.svg")),
209 settings_proto(LoadIcon(
"setting_gear.svg")),
210 filled_circle_proto(LoadIcon(
"circle-on.svg")),
211 open_circle_proto(LoadIcon(
"circle-off.svg")),
212 exclaim_mark_proto(LoadIcon(
"exclaim_mark.svg")),
213 x_mult_proto(LoadIcon(
"X_mult.svg")),
214 check_mark_proto(LoadIcon(
"check_mark.svg")) {
215 trash_bin = trash_bin_proto;
216 settings = settings_proto;
217 filled_circle = filled_circle_proto;
218 open_circle = open_circle_proto;
219 exclaim_mark = exclaim_mark_proto;
220 x_mult = x_mult_proto;
221 check_mark = check_mark_proto;
224 void SetColorScheme(
const ColorScheme cs) {
227 trash_bin = IconApplyColorScheme(trash_bin_proto);
228 settings = IconApplyColorScheme(settings_proto);
229 filled_circle = IconApplyColorScheme(filled_circle_proto);
230 open_circle = IconApplyColorScheme(open_circle_proto);
231 exclaim_mark = IconApplyColorScheme(exclaim_mark_proto);
232 x_mult = IconApplyColorScheme(x_mult_proto);
233 check_mark = IconApplyColorScheme(check_mark_proto);
237 const wxBitmap trash_bin_proto;
238 const wxBitmap settings_proto;
239 const wxBitmap filled_circle_proto;
240 const wxBitmap open_circle_proto;
241 const wxBitmap exclaim_mark_proto;
242 const wxBitmap x_mult_proto;
243 const wxBitmap check_mark_proto;
247 wxBitmap filled_circle;
248 wxBitmap open_circle;
249 wxBitmap exclaim_mark;
384 const std::vector<ConnectionParams*>& connections,
388 : wxGrid(parent, wxID_ANY),
389 m_connections(connections),
390 m_header_column_widths({0, 0, 0, 0, 0, 0, 0}),
391 m_last_tooltip_cell(100),
392 m_cs(GLOBAL_COLOR_SCHEME_DAY),
393 m_on_conn_delete(on_conn_update),
395 m_on_edit_conn(on_edit_conn) {
396 ShowScrollbars(wxSHOW_SB_NEVER, wxSHOW_SB_NEVER);
397 SetTable(
new wxGridStringTable(),
true);
398 GetTable()->AppendCols(8);
401 SetDefaultRowSize(wxWindow::GetCharHeight() * 2);
402 SetColLabelSize(wxWindow::GetCharHeight() * 2);
404 static const std::array<wxString, 7> headers = {
405 "", _(
"Protocol") +
" ", _(
"In/Out"), _(
"Data port"), _(
"Status"),
"",
408 for (
auto hdr = headers.begin(); hdr != headers.end(); hdr++, ic++) {
409 SetColLabelValue(
static_cast<int>(hdr - headers.begin()), *hdr);
410 unsigned col_width = hdr->Length() * wxWindow::GetCharWidth();
411 col_width = wxMax(col_width, 6 * wxWindow::GetCharWidth());
412 m_header_column_widths[ic] =
static_cast<int>(col_width);
413 SetColSize(ic,
static_cast<int>(col_width));
417 SetLabelBackgroundColour(GetGlobalColor(
"DILG1"));
418 SetLabelTextColour(GetGlobalColor(
"DILG3"));
421 SetColAttributes(parent);
424 DisableDragColSize();
425 DisableDragRowSize();
426 wxWindow::Show(GetNumberRows() > 0);
428 GetGridWindow()->Bind(wxEVT_MOTION, [&](wxMouseEvent& ev) {
432 GetGridWindow()->Bind(wxEVT_MOUSEWHEEL,
433 [&](
const wxMouseEvent& ev) {
OnWheel(ev); });
435 Bind(wxEVT_GRID_LABEL_LEFT_CLICK,
436 [&](wxGridEvent& ev) { HandleSort(ev.GetCol()); });
437 Bind(wxEVT_GRID_CELL_LEFT_CLICK,
438 [&](wxGridEvent& ev) { OnClickCell(ev.GetRow(), ev.GetCol()); });
439 Bind(wxEVT_PAINT, [&](wxPaintEvent& ev) {
440 SetColAttributes(
dynamic_cast<const wxWindow*
>(ev.GetEventObject()));
443 conn_change_lstnr.Init(
445 [&](
ObservedEvt&) { OnConnectionChange(m_connections); });
447 void SetColorScheme(
const ColorScheme cs) {
449 m_icons.SetColorScheme(cs);
453 wxSize GetEstimatedSize()
const {
455 for (
auto s : m_header_column_widths) rs += s;
456 return {
static_cast<int>(rs), -1};
462 dynamic_cast<wxScrolledWindow*
>(FindWindowByName(TopScrollWindowName));
463 assert(w &&
"No TopScroll window found");
466 w->GetViewStart(&xpos, &ypos);
469 w->GetScrollPixelsPerUnit(&x, &y);
471 const int dir = ev.GetWheelRotation();
472 w->Scroll(-1, ypos - dir / y / 4);
476 void ReloadGrid(
const std::vector<ConnectionParams*>& connections) {
478 m_renderer_status_vector.clear();
480 for (
auto it = connections.begin(); it != connections.end(); ++it) {
481 const auto row =
static_cast<int>(it - connections.begin());
483 SetCellValue(row, 0, (*it)->is_enabled ?
"1" :
"");
484 if ((*it)->is_enabled)
485 m_tooltips[row][0] = _(
"Enabled, click to disable");
487 m_tooltips[row][0] = _(
"Disabled, click to enable");
488 std::string protocol = NavAddr::BusToString((*it)->GetCommProtocol());
489 SetCellValue(row, 1, protocol);
490 SetCellValue(row, 2, (*it)->GetPortDirectionValueStr());
491 SetCellValue(row, 3, (*it)->GetStrippedDSPort());
492 m_tooltips[row][3] = (*it)->user_comment;
494 m_tooltips[row][5] = _(
"Edit connection");
496 m_tooltips[row][6] = _(
"Delete connection");
497 SetCellValue(row, 7, (*it)->GetKey());
500 stat_renderer->status = ConnState::Disabled;
501 m_renderer_status_vector.push_back(stat_renderer);
502 SetCellRenderer(row, 4, stat_renderer);
504 wxString sp(protocol);
505 unsigned size = sp.Length() * wxWindow::GetCharWidth();
506 m_header_column_widths[1] = std::max(m_header_column_widths[1], size);
507 size = (*it)->GetPortDirectionValueStr().Length() *
508 wxWindow::GetCharWidth();
509 m_header_column_widths[2] = std::max(m_header_column_widths[2], size);
510 sp = wxString((*it)->GetStrippedDSPort());
511 size = sp.Length() * wxWindow::GetCharWidth();
512 m_header_column_widths[3] = std::max(m_header_column_widths[3], size);
515 OnConnectionChange(m_connections);
519 for (
auto val : m_header_column_widths) {
520 SetColSize(ic,
static_cast<int>(val));
531 : m_conns(connections) {}
536 if (row1 == -1 && row2 == -1)
return false;
537 if (row1 == -1)
return false;
538 if (row2 == -1)
return true;
539 const int v1 = m_conns->GetCellValue(row1, 4)[0];
540 const int v2 = m_conns->GetCellValue(row2, 4)[0];
553 auto found = find_if(
554 m_connections.begin(), m_connections.end(),
556 if (found == m_connections.end())
return -1;
557 return static_cast<int>(found - m_connections.begin());
566 auto found = find_if(m_connections.begin(), m_connections.end(),
568 return GetCellValue(row, 7) == p->GetKey();
570 return found != m_connections.end() ? *found :
nullptr;
577 void EnsureRows(
size_t rows) {
578 for (
unsigned i = m_tooltips.size(); i <= rows; i++)
579 m_tooltips.emplace_back(std::vector<std::string>(7));
580 for (
unsigned i = GetNumberRows(); i <= rows; i++) AppendRows(1,
false);
584 void SetColAttributes(
const wxWindow* parent) {
587 SetDefaultCellBackgroundColour(GetGlobalColor(
"DILG1"));
589 auto enable_attr =
new wxGridCellAttr();
590 enable_attr->SetAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE);
593 enable_attr->SetRenderer(
596 enable_attr->SetRenderer(
new wxGridCellBoolRenderer());
598 enable_attr->SetEditor(
new wxGridCellBoolEditor());
599 if (IsWindows()) enable_attr->SetBackgroundColour(GetGlobalColor(
"DILG1"));
600 SetColAttr(0, enable_attr);
602 auto protocol_attr =
new wxGridCellAttr();
603 protocol_attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTRE);
604 protocol_attr->SetReadOnly(
true);
606 protocol_attr->SetBackgroundColour(GetGlobalColor(
"DILG1"));
607 SetColAttr(1, protocol_attr);
609 auto in_out_attr =
new wxGridCellAttr();
610 in_out_attr->SetAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE);
611 in_out_attr->SetReadOnly(
true);
612 if (IsWindows()) in_out_attr->SetBackgroundColour(GetGlobalColor(
"DILG1"));
613 SetColAttr(2, in_out_attr);
615 auto port_attr =
new wxGridCellAttr();
616 port_attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTRE);
617 port_attr->SetReadOnly(
true);
618 if (IsWindows()) port_attr->SetBackgroundColour(GetGlobalColor(
"DILG1"));
619 SetColAttr(3, port_attr);
621 auto status_attr =
new wxGridCellAttr();
622 status_attr->SetAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE);
623 status_attr->SetReadOnly(
true);
624 status_attr->SetFont(parent->GetFont().Scale(1.3));
625 if (IsWindows()) status_attr->SetBackgroundColour(GetGlobalColor(
"DILG1"));
626 SetColAttr(4, status_attr);
628 auto edit_attr =
new wxGridCellAttr();
629 edit_attr->SetAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE);
630 edit_attr->SetFont(parent->GetFont().Scale(1.3));
631 edit_attr->SetReadOnly(
true);
632 if (IsWindows()) edit_attr->SetBackgroundColour(GetGlobalColor(
"DILG1"));
633 SetColAttr(5, edit_attr);
635 auto delete_attr =
new wxGridCellAttr();
636 delete_attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTRE);
637 delete_attr->SetFont(parent->GetFont().Scale(1.3));
638 delete_attr->SetTextColour(*wxRED);
639 delete_attr->SetReadOnly(
true);
640 if (IsWindows()) delete_attr->SetBackgroundColour(GetGlobalColor(
"DILG1"));
641 SetColAttr(6, delete_attr);
645 void OnClickCell(
int row,
int col) {
650 }
else if (col == 6) {
656 void OnMouseMove(
const wxMouseEvent& ev) {
657 const wxPoint pt = ev.GetPosition();
658 int row = YToRow(pt.y);
659 int col = XToCol(pt.x);
660 if (col < 0 || col >= 7 || row < 0 || row >= GetNumberRows())
return;
661 if (row * 7 + col == m_last_tooltip_cell)
return;
662 m_last_tooltip_cell = row * 7 + col;
663 GetGridWindow()->SetToolTip(m_tooltips[row][col]);
667 void OnConnectionChange(
const std::vector<ConnectionParams*>& connections) {
668 bool refresh_needed =
false;
669 for (
auto it = connections.begin(); it != connections.end(); ++it) {
670 ConnState state = m_conn_states.GetDriverState(
671 (*it)->GetCommProtocol(), (*it)->GetStrippedDSPort());
672 if (!(*it)->is_enabled) state = ConnState::Disabled;
673 auto row =
static_cast<int>(it - connections.begin());
675 if (
static_cast<int>(m_renderer_status_vector.size()) < row + 1)
continue;
677 case ConnState::Disabled:
678 if (m_renderer_status_vector[row]->status != ConnState::Disabled) {
679 m_renderer_status_vector[row]->SetBitmap(m_icons.filled_circle);
680 m_renderer_status_vector[row]->status = ConnState::Disabled;
681 refresh_needed =
true;
683 m_tooltips[row][4] = _(
"Disabled");
685 case ConnState::NoStats:
686 if (m_renderer_status_vector[row]->status != ConnState::NoStats) {
687 m_renderer_status_vector[row]->SetBitmap(m_icons.open_circle);
688 m_renderer_status_vector[row]->status = ConnState::NoStats;
689 refresh_needed =
true;
691 m_tooltips[row][4] = _(
"No driver statistics available");
693 case ConnState::NoData:
694 if (m_renderer_status_vector[row]->status != ConnState::NoData) {
695 m_renderer_status_vector[row]->SetBitmap(m_icons.exclaim_mark);
696 m_renderer_status_vector[row]->status = ConnState::NoData;
697 refresh_needed =
true;
699 m_tooltips[row][4] = _(
"No data flowing through connection");
701 case ConnState::Unavailable:
702 if (m_renderer_status_vector[row]->status != ConnState::Unavailable) {
703 m_renderer_status_vector[row]->SetBitmap(m_icons.x_mult);
704 m_renderer_status_vector[row]->status = ConnState::Unavailable;
705 refresh_needed =
true;
707 m_tooltips[row][4] = _(
"The device is unavailable");
710 if (m_renderer_status_vector[row]->status != ConnState::Ok) {
711 m_renderer_status_vector[row]->SetBitmap(m_icons.check_mark);
712 m_renderer_status_vector[row]->status = ConnState::Ok;
713 refresh_needed =
true;
715 m_tooltips[row][4] = _(
"Data is flowing");
719 if (refresh_needed) ForceRefresh();
723 void SetSortingColumn(
int col) {
724 if (GetSortingColumn() != wxNOT_FOUND) {
725 int old_col = GetSortingColumn();
726 auto label = GetColLabelValue(old_col);
727 if (label[0] == UtfArrowDown()[0])
728 SetColLabelValue(old_col, label.substr(2));
730 auto label = GetColLabelValue(col);
731 if (label[0] != UtfArrowDown()[0])
732 SetColLabelValue(col, UtfArrowDown() +
" " + label);
733 wxGrid::SetSortingColumn(col);
738 void HandleSort(
int col) {
742 std::sort(params.begin(), params.end(),
ConnCompare(col));
744 std::sort(params.begin(), params.end(), ConnStateCompare(
this));
746 SetSortingColumn(col);
750 void HandleEnable(
int row) {
753 cp->is_enabled = !cp->is_enabled;
754 cp->is_setup = FALSE;
755 SetCellValue(row, 0, cp->is_enabled ?
"1" :
"");
757 m_tooltips[row][0] = _(
"Enabled, click to disable");
759 m_tooltips[row][0] = _(
"Disabled, click to enable");
763 m_conn_states.HandleDriverStats(stats);
767 if (!cp->is_enabled) {
768 SetCellValue(row, 4, UtfFilledCircle());
775 void HandleEdit(
int row) {
777 Show(GetNumberRows() > 0);
778 m_on_edit_conn(cp,
true);
783 void HandleDelete(
int row) {
785 auto found = std::find(m_connections.begin(), m_connections.end(), cp);
786 if (found != m_connections.end()) {
787 std::stringstream ss;
788 ss << _(
"Ok to delete connection on ") << (*found)->GetStrippedDSPort();
789 int rcode = OCPNMessageBox(
this, ss.str(), _(
"Delete connection?"),
791 if (rcode != wxID_OK && rcode != wxID_YES)
return;
792 delete (*found)->options_panel;
793 StopAndRemoveCommDriver((*found)->GetStrippedDSPort(),
794 (*found)->GetCommProtocol());
796 if (GetNumberRows() >
static_cast<int>(m_connections.size()))
797 DeleteRows(GetNumberRows() - 1);
798 m_on_conn_delete.
Notify();
802 obs::Listener conn_change_lstnr;
803 std::vector<std::vector<std::string>> m_tooltips;
805 const std::vector<ConnectionParams*>& m_connections;
806 std::array<unsigned, 7> m_header_column_widths;
807 int m_last_tooltip_cell;
811 std::vector<BitmapCellRenderer*> m_renderer_status_vector;
922 : wxPanel(parent, wxID_ANY) {
923 auto sizer =
new wxStaticBoxSizer(wxVERTICAL,
this,
"");
924 sizer->Add(
new BearingsCheckbox(
this), wxSizerFlags().Expand());
925 sizer->Add(
new ExtraRmbRmcLine(
this), wxSizerFlags().Expand());
926 sizer->Add(
new NmeaFilterRow(
this), wxSizerFlags().Expand());
927 sizer->Add(
new TalkerIdRow(
this), wxSizerFlags().Expand());
928 sizer->Add(
new NetmaskRow(
this), wxSizerFlags().Expand());
930 wxWindow::SetMaxSize(max_size);
935 class BearingsCheckbox :
public wxCheckBox,
public ApplyCancel {
937 explicit BearingsCheckbox(wxWindow* parent)
938 : wxCheckBox(parent, wxID_ANY,
939 _(
"Use magnetic bearing in output sentence APB")) {
940 wxCheckBox::SetValue(g_bMagneticAPB);
943 void Apply()
override { g_bMagneticAPB = GetValue(); }
944 void Cancel()
override { SetValue(g_bMagneticAPB); }
947 class ExtraRmbRmcLine :
public wxPanel {
948 class RmbRmcCheckbox :
public wxCheckBox,
public ApplyCancel {
950 explicit RmbRmcCheckbox(wxWindow* parent)
951 : wxCheckBox(parent, wxID_ANY,
952 _(
"Always send RMB and RMC NMEA0183 data")) {
961 explicit ExtraRmbRmcLine(wxWindow* parent) : wxPanel(parent, wxID_ANY) {
962 auto hbox =
new wxBoxSizer(wxHORIZONTAL);
963 hbox->Add(
new RmbRmcCheckbox(
this), wxSizerFlags().Expand());
964 hbox->Add(1, 1, 1, wxEXPAND);
965 hbox->Add(
new InfoButton(
this, g_btouch, kInfoHeader, kInfo),
966 wxSizerFlags().Border());
972 class ExtraRmbRmcCheckbox final :
public wxCheckBox,
public ApplyCancel {
974 explicit ExtraRmbRmcCheckbox(wxWindow* parent)
975 : wxCheckBox(parent, wxID_ANY,
976 _(
"Always send RMB and RMC NMEA0183 data")) {
985 class NmeaFilterRow :
public wxPanel,
public ApplyCancel {
986 wxCheckBox* checkbox;
987 wxTextCtrl* filter_period;
990 explicit NmeaFilterRow(wxWindow* parent) : wxPanel(parent) {
991 auto hbox =
new wxBoxSizer(wxHORIZONTAL);
992 checkbox =
new wxCheckBox(
994 _(
"Filter NMEA course and speed data. Filter period: "));
995 checkbox->SetValue(g_bfilter_cogsog);
996 hbox->Add(checkbox, wxSizerFlags().Align(wxALIGN_CENTRE));
998 new wxTextCtrl(
this, wxID_ANY,
"", wxDefaultPosition,
999 wxSize(50, 3 * wxWindow::GetCharWidth()), 0);
1000 filter_period->SetValue(std::to_string(g_COGFilterSec));
1001 hbox->Add(filter_period, wxSizerFlags().Border());
1003 NmeaFilterRow::Cancel();
1006 void Apply()
override {
1007 std::stringstream ss;
1008 ss << filter_period->GetValue();
1009 ss >> g_COGFilterSec;
1010 g_bfilter_cogsog = checkbox->GetValue();
1013 void Cancel()
override {
1014 std::stringstream ss;
1015 ss << g_COGFilterSec;
1016 filter_period->SetValue(ss.str());
1017 checkbox->SetValue(g_bfilter_cogsog);
1022 class TalkerIdRow :
public wxPanel,
public ApplyCancel {
1023 wxTextCtrl* text_ctrl;
1026 explicit TalkerIdRow(wxWindow* parent) : wxPanel(parent) {
1027 auto hbox =
new wxBoxSizer(wxHORIZONTAL);
1028 hbox->Add(
new wxStaticText(
this, wxID_ANY, _(
"NMEA 0183 Talker Id: ")),
1029 wxSizerFlags().Align(wxALIGN_CENTRE_VERTICAL).Border());
1030 text_ctrl =
new wxTextCtrl(
1031 this, wxID_ANY,
"", wxDefaultPosition,
1032 wxSize(4 * wxWindow::GetCharWidth(), 3 * wxWindow::GetCharWidth()));
1033 text_ctrl->SetToolTip(
1034 _(
"Enter a two-letter talker ID to override the default ID in NMEA "
1035 "sentences generated by OpenCPN (e.g., GP, HC, EC). This affects "
1036 "only sentences created by OpenCPN, not those forwarded from other "
1038 text_ctrl->SetValue(g_TalkerIdText);
1039 hbox->Add(text_ctrl, wxSizerFlags().Border());
1041 TalkerIdRow::Cancel();
1044 void Apply()
override { g_TalkerIdText = text_ctrl->GetValue(); }
1045 void Cancel()
override { text_ctrl->SetValue(g_TalkerIdText); }
1049 class NetmaskRow :
public wxPanel,
public ApplyCancel {
1051 explicit NetmaskRow(wxWindow* parent)
1053 m_spin_ctrl(
new wxSpinCtrl(
this, wxID_ANY)),
1054 m_text(
new wxStaticText(
this, wxID_ANY,
"")) {
1055 m_spin_ctrl->SetRange(8, 32);
1056 auto hbox =
new wxBoxSizer(wxHORIZONTAL);
1057 auto flags = wxSizerFlags().Align(wxALIGN_CENTRE_VERTICAL).Border();
1058 hbox->Add(
new wxStaticText(
this, wxID_ANY, _(
"Netmask: ")), flags);
1059 hbox->Add(m_text, flags);
1060 hbox->Add(
new wxStaticText(
this, wxID_ANY, _(
"length (bits): ")), flags);
1061 hbox->Add(m_spin_ctrl, flags);
1063 NetmaskRow::Cancel();
1065 Bind(wxEVT_SPINCTRL, [&](wxSpinEvent&) {
1066 m_text->SetLabel(BitsToDottedMask(m_spin_ctrl->GetValue()));
1071 void Apply()
override { g_netmask_bits = m_spin_ctrl->GetValue(); }
1073 void Cancel()
override {
1074 m_spin_ctrl->SetValue(g_netmask_bits);
1075 m_text->SetLabel(BitsToDottedMask(m_spin_ctrl->GetValue()));
1080 wxSpinCtrl* m_spin_ctrl;
1081 wxStaticText* m_text;
1088 TopPanel(wxWindow* parent,
const std::vector<ConnectionParams*>& connections,
1092 : wxPanel(parent, wxID_ANY),
1093 m_evt_add_connection(evt_add_connection),
1094 m_connections(connections) {
1095 auto vbox =
new wxBoxSizer(wxVERTICAL);
1096 auto conn_grid =
new Connections(
this, m_connections, m_evt_add_connection,
1098 wxSize panel_max_size(conn_grid->GetEstimatedSize());
1099 vbox->AddSpacer(wxWindow::GetCharHeight());
1100 auto conn_flags = wxSizerFlags().Border();
1101 if (IsAndroid()) conn_flags = wxSizerFlags().Border().Expand();
1102 vbox->Add(conn_grid, conn_flags);
1104 wxSizerFlags().Border());
1105 vbox->Add(0, wxWindow::GetCharHeight());
1107 wxSizerFlags().Border(wxLEFT | wxDOWN | wxRIGHT).Expand();
1108 m_general_panel =
new GeneralPanel(
this, panel_max_size);
1109 vbox->Add(m_general_panel, panel_flags);
1111 auto advanced_panel =
new AdvancedPanel(
this, panel_max_size);
1112 m_advanced_panel = advanced_panel;
1113 auto on_toggle = [&, advanced_panel, vbox](
bool show) {
1115 advanced_panel->Show(show);
1116 vbox->SetSizeHints(
this);
1119 vbox->Add(
new ShowAdvanced(
this, on_toggle), panel_flags);
1120 vbox->Add(advanced_panel, panel_flags.ReserveSpaceEvenIfHidden());
1123 vbox->SetSizeHints(
this);
1128 auto on_evt_update_connections = [&, conn_grid](
ObservedEvt&) {
1130 conn_grid->Show(conn_grid->GetNumberRows() > 0);
1133 m_add_connection_lstnr.Init(m_evt_add_connection,
1134 on_evt_update_connections);
1135 m_conn_grid = conn_grid;
1138 void SetColorScheme(
const ColorScheme cs)
const {
1139 m_conn_grid->SetColorScheme(cs);
1140 m_general_panel->SetColorScheme(cs);
1142 [[nodiscard]]
Connections* GetConnectionsGrid()
const {
return m_conn_grid; }
1147 const std::vector<ConnectionParams*>& m_connections;
1148 obs::Listener m_add_connection_lstnr;
1157 TopScroll(wxWindow* parent,
const std::vector<ConnectionParams*>& connections,
1159 : wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1160 wxVSCROLL | wxHSCROLL, TopScrollWindowName) {
1161 ShowScrollbars(wxSHOW_SB_NEVER, wxSHOW_SB_ALWAYS);
1162 auto vbox =
new wxBoxSizer(wxVERTICAL);
1173 new TopPanel(
this, connections, evt_add_connection, on_edit_connection);
1174 vbox->Add(top_panel, wxSizerFlags(1).Expand());
1178 HandleEditFinish(p, new_mode, ok_cancel);
1182 m_edit_panel->SetPropsLabel(_(
"Edit Selected Connection"));
1183 wxWindow*
options = FindWindowByName(
"Options");
1184 assert(
options &&
"Null Options window!");
1189 m_edit_panel->SetSize(
1190 wxSize(
options->GetSize().x,
options->GetSize().y * fraction / 10));
1191 vbox->Add(m_edit_panel, wxSizerFlags(0).Expand());
1192 m_edit_panel->Hide();
1194 SetScrollRate(0, 10);
1195 if (IsAndroid()) SetScrollRate(1, 1);
1197 SetScrollRate(0, 10);
1198 if (IsAndroid()) SetScrollRate(1, 1);
1201 void SetColorScheme(ColorScheme cs)
const {
1202 if (top_panel) top_panel->SetColorScheme(cs);
1206 m_edit_panel->SetPropsLabel(_(
"Edit Selected Connection"));
1207 m_edit_panel->SetNewMode(
false);
1208 m_edit_panel->PreloadControls(p);
1209 m_edit_panel->AddOKCancelButtons();
1214 m_edit_panel->SetPropsLabel(_(
"Configure new connection"));
1215 m_edit_panel->SetDefaultConnectionParams();
1216 m_edit_panel->SetNewMode(
true);
1217 m_edit_panel->AddOKCancelButtons();
1218 m_edit_panel->InitiateNewConnection();
1222 void SwitchToEditor() {
1225 DimeControl(m_edit_panel);
1226 m_edit_panel->Show();
1231 void SwitchToGrid() {
1233 m_edit_panel->Hide();
1249 delete cp_orig->options_panel;
1253 assert(index != -1 &&
"Cannot look up connection index");
1255 cp_edited->is_setup =
false;
1261 if (FindConnectionByIface(cp)) {
1262 wxMessageDialog dialog(
this, kInterfaceExistsMessage,
1263 _(
"Driver creation warning"),
1264 wxOK | wxCENTRE | wxICON_WARNING);
1269 cp->is_setup =
false;
1274 _(
"Unable to create a connection as configured. "
1275 "Connected port or address was missing.");
1276 auto& noteman = NotificationManager::GetInstance();
1277 noteman.AddNotification(NotificationSeverity::kWarning,
1278 msg.ToStdString(), 60);
1282 UpdateDatastreams();
1283 top_panel->m_evt_add_connection.
Notify();
1287 UpdateDatastreams();