Learning to develop in KiCad (2) - Add netlist to my dialog

All my series of “Learning to Develop KiCad” posts are listed in FAQ

Index:

This is a translation from my Chinese article.

In the previous post, I added a dialog into KiCad, now I need to add something content into the dialog.

In wxWidgets, we usually ( I am actually a new learner to wxWidgets, and I learn it through DIALOG_NET_INSPECTOR as a guide ) use wxDataViewCtrl ( or subclasses ) to show a list. For using wxDataViewCtrl, it needs to associate a wxDataViewModel to it.

So first we need to define it in protected or private section of DIALOG_LENGTH_TUNING class:


class DATA_MODEL; // here is forward declaction                                                                                                             
wxObjectDataPtr<DATA_MODEL> m_dataModel; //   according to official doc, it is recommended to use wxObjectDataPtr to avoid memory leak
friend DATA_MODEL;                                                                                                                                     

Next step is defining DATA_MODEL in dialog_length_tuning.cpp. As described in [official doc](file:///home/hongbo/Developer/Engineering/wxWidgets-3.2.4-docs-html/classwx_data_view_model.html#a2c61a09270fdda6720966742f0e4f09c), you need to at least overload wxDataViewModel::IsContainer, wxDataViewModel::GetParent, wxDataViewModel::GetChildren, and wxDataViewModel::GetValue. But in fact, you still need to overload SetValue and GetColumnCount too. I don’t know whether it is because the doc is not updated.

a (not working) DATA_MODEL skeleton is following:

32 class DIALOG_LENGTH_TUNING::DATA_MODEL : public wxDataViewModel 4 refs
 33 {
 34 public:
 35     DATA_MODEL() {} 0 ref
 36     ~DATA_MODEL() {} 0 ref
 37
 38     bool IsContainer(const wxDataViewItem &item) const override { return false; }
 39
 40     wxDataViewItem GetParent(const wxDataViewItem &item) const override { return wxDataViewItem(); }
 41
 42     unsigned int GetChildren(const wxDataViewItem &item, wxDataViewItemArray &children) const override
 43     {
 44         return 0;
 45     }
 46
 47     void GetValue(wxVariant &variant, const wxDataViewItem &item, unsigned int col) const override
 48     {
 49         variant = "xxx";
 50     }
 51
 52     bool SetValue(const wxVariant &variant, const wxDataViewItem &item, unsigned int col) override { return false; }
 53
 54     unsigned int GetColumnCount() const override { return 0; } 
 55 };

In the constructor of `DIALOG_LENGTH_TUNING’, we associate the wxDataViewCtrl and wxDataViewModel:

57 DIALOG_LENGTH_TUNING::DIALOG_LENGTH_TUNING( PCB_EDIT_FRAME* aParent )
 58     DIALOG_LENGTH_TUNING_BASE( aParent ),
 59     m_frame(aParent)
 60 {
 61     m_dataModel = new DATA_MODEL();
 62     m_datactrlList->AssociateModel(&*m_dataModel);
 63 }

Now I suggest you do a build to check whether there are errors in previous steps.
Then we need to add headers to the list ( inside dialog_length_tuning.cpp ).

32 enum COLUMN_INDEX {
 33     COLUMN_NET = 0, 
 34     COLUMN_START_PAD,
 35     COLUMN_END_PAD, 
 36     COLUMN_TRACK_LENGTH, 
 37     COLUMN_VIA_COUNT, 
 38     COLUMN_TOTAL_LENGTH, 
 39     COLUMN_MAX,
 40 };
 41
 42 struct DIALOG_LENGTH_TUNING::COLUMN_DESC 
 43 {
 44     COLUMN_DESC(const COLUMN_INDEX aIdx, const wxString& aName): 
 45         idx(aIdx),
 46         name(aName) {}
 47
 48     COLUMN_INDEX idx; 
 49     wxString name; 
 50 };

add m_columns into DATA_MODEL

 71 private:
 72     std::vector<COLUMN_DESC> m_columns;

 55     DATA_MODEL() 1 ref
 56     {
 57         m_columns.emplace_back(COLUMN_NET, _("Net"));
 58         m_columns.emplace_back(COLUMN_START_PAD, _("Start Pad"));
 59         m_columns.emplace_back(COLUMN_END_PAD, _("End Pad"));
 60         m_columns.emplace_back(COLUMN_TRACK_LENGTH, _("Track Length"));
 61         m_columns.emplace_back(COLUMN_VIA_COUNT, _("Vias Count"));
 62         m_columns.emplace_back(COLUMN_TOTAL_LENGTH, _("Total Length"));
 63     }

 73     const std::vector<DIALOG_LENGTH_TUNING::COLUMN_DESC>& GetColumns() const { return m_columns; }

Add several statements into constructor of DIALOG_LENGTH_TUNING

79 DIALOG_LENGTH_TUNING::DIALOG_LENGTH_TUNING( PCB_EDIT_FRAME* aParent ) : 1 ref|2 refs
 80     DIALOG_LENGTH_TUNING_BASE( aParent ),
 81     m_frame(aParent)
 82 {
 83     m_dataModel = new DATA_MODEL();
 84     m_datactrlList->AssociateModel(&*m_dataModel);
 85
 86     for ( auto c : m_dataModel->GetColumns() ) {
 87         m_datactrlList->AppendTextColumn(c.name, c.idx);
 88     }
 89 }

Now build again and run, it shows list view with headers:
640

Next we add net names as “Dummy Data” to show in the dialog

Define DATA_ITEM, for representing a line of the data

52 class DIALOG_LENGTH_TUNING::DATA_ITEM
 53 {
 54 public:
 55     DATA_ITEM(const int aNetCode,
 56               const wxString& aNetName)
 57         m_netCode(aNetCode),
 58         m_netName(aNetName) {}
 59
 60 private:
 61     int m_netCode;
 62     wxString m_netName;
 63 };

An interface to add an item


 118     void AddItem(std::unique_ptr<DATA_ITEM> item)
 119     {
 120         m_items.emplace_back(std::move(item));
 121         std::unique_ptr<DATA_ITEM>& refItem = m_items.back();
 122         ItemAdded(wxDataViewItem(),  wxDataViewItem(refItem.get()));
 123     }

Rewrite DIALOG_LENGTH_TUNING::DATA_MODEL::GetChildren


  84     unsigned int GetChildren(const wxDataViewItem &item, wxDataViewItemArray &children) const override
  85     {
  86         if( !item.IsOk() ) { // is Root node
  87             for (auto& i : m_items) {
  88                 children.Add(wxDataViewItem(i.get()));
  89             }
  90             return m_items.size();
  91         }
  92
  93         return 0;
  94     }

Rewrite DIALOG_LENGTH_TUNING::DATA_MODEL::GetValue


  96     void GetValue(wxVariant &variant, const wxDataViewItem &item, unsigned int col) const override
  97     {
  98         DATA_ITEM* dataItem = static_cast<DATA_ITEM *>(item.GetID());
  99         if( dataItem ) {
 100             switch (col) {
 101             case COLUMN_NET:
 102                 variant = dataItem->GetNetName();
 103                 break;
 104             default:
 105                 variant = "Unhandled";
 106                 break;
 107             }
 108             return;
 109         }
 110         variant = "";
 111     }

Add Net info into our data model in constructor of DIALOG_LENGTH_TUNING


 129 DIALOG_LENGTH_TUNING::DIALOG_LENGTH_TUNING( PCB_EDIT_FRAME* aParent ) :
 130     DIALOG_LENGTH_TUNING_BASE( aParent ),
 131     m_frame(aParent)
 132 {
 133     m_dataModel = new DATA_MODEL();
 134     m_datactrlList->AssociateModel(&*m_dataModel);
 135
 136     for ( auto c : m_dataModel->GetColumns() ) {
 137         m_datactrlList->AppendTextColumn(c.name, c.idx);
 138     }
 139
 140     const BOARD* board = m_frame->GetBoard();
 141     const NETINFO_LIST& netsList = board->GetNetInfo();
 142
 143     for( auto ni : netsList.NetsByNetcode() ) {
 144         NETINFO_ITEM* netInfo = ni.second; 
 145         std::unique_ptr<DATA_ITEM> item = std::make_unique<DATA_ITEM>(
 146             netInfo->GetNetCode(),
 147             netInfo->GetNetname());
 148         m_dataModel->AddItem(std::move(item));
 149     }
 150 }

Now build again and (if no errors) run, it shows:

Working in Progress code is here

6 Likes

Very comprehensive tutorial – thanks!

Since these posts are translations from your Chinese article, are you planning to collect these into an English version? Otherwise this useful information will eventually be lost on this forum.

Worthy of placement in the FAQs???

Maybe not a FAQ, but at least it wouldn’t be lost.

1 Like

I didn’t find a good way to do that. I previously put it on Medium, but there are few visits, so I think it would be better to put it on the forum.

Maybe you can give me some suggestions ?

How many articles are there?

Certain members are able to place your articles in the FAQ (see top of forum).

For now, all two posts related to source code development are already translated here.

Because I am still learning to implement some feature, there will be more on this topic

I got two or three other posts in Chinese which are related to compiling KiCad on Debian 12 and Windows, I think there is little usage to translate them into English, so I didn’t do that yet.

I’ve placed your first post into the FAQ.
Please read my PM.

Cool. Can I still edit the post you linked in FAQ ? I think I need to append more articles links there.

A post was merged into an existing topic: Learning to Develop in Kicad

You won’t get many hits on Medium or anywhere else: your article is too specialized and only of interest to a small audience of people who want to add features to KiCad. But your article might help these people add features that make KiCad more useful to the entire user base, so your article might be very impactful. (Several years ago, Miles McCoo wrote a series of blog posts about building PCBNEW plugins. They didn’t create even a ripple on the internet as a whole, but they were significantly helpful to the KiCad community.)

Having it in the FAQ is fine, but I would also make a repository on Github that has the complete article in a readable form and the source material you used to assemble the article. This has several advantages:

  1. It makes your article indexable and findable using Google. (Search on a Discourse forum is nowhere near as good.)
  2. Readers can report errors or make suggestions for improvements by raising issues on the repository. (Make sure to place a link to your repo in the final article.)
  3. If you license your article as a Creative Commons work, then it can serve as a jumping-off point for others who want to write on the same topic.

Well, I can say the code violates the kicad code style policy so any MR would get rejected on that basis :3

I need to be familiar with wxWidgets first, then clean up the code for complying the code style

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.