1 module dlangide.ui.stackpanel;
2 
3 import dlangui;
4 
5 import std..string : format;
6 import ddebug.common.debugger;
7 
8 interface StackFrameSelectedHandler {
9     void onStackFrameSelected(ulong threadId, int frame);
10 }
11 
12 class StackPanel : DockWindow, OnItemSelectedHandler, CellActivatedHandler {
13 
14     Signal!StackFrameSelectedHandler stackFrameSelected;
15 
16     this(string id) {
17         super(id);
18         _caption.text = "Stack"d;
19     }
20 
21     override protected Widget createBodyWidget() {
22         layoutWidth = FILL_PARENT;
23         layoutHeight = FILL_PARENT;
24         VerticalLayout root = new VerticalLayout();
25         root.layoutWidth = FILL_PARENT;
26         root.layoutHeight = FILL_PARENT;
27         _comboBox = new ComboBox("threadComboBox", ["Thread1"d]);
28         _comboBox.layoutWidth = FILL_PARENT;
29         _comboBox.selectedItemIndex = 0;
30         _comboBox.itemClick = this;
31         _grid = new StringGridWidget("stackGrid");
32         _grid.cellActivated = this;
33         _grid.resize(2, 0);
34         _grid.showColHeaders = true;
35         _grid.showRowHeaders = false;
36         _grid.layoutHeight = FILL_PARENT;
37         _grid.layoutWidth = FILL_PARENT;
38         _grid.setColTitle(0, "Function"d);
39         _grid.setColTitle(1, "Address"d);
40         _grid.layoutWidth = FILL_PARENT;
41         _grid.layoutHeight = FILL_PARENT;
42         root.addChild(_comboBox);
43         root.addChild(_grid);
44         return root;
45     }
46 
47     StringGridWidget _grid;
48     ComboBox _comboBox;
49     DebugThreadList _debugInfo;
50     DebugThread _selectedThread;
51     ulong _currentThreadId;
52     int _currentThreadIndex;
53     int _currentFrame;
54     void updateDebugInfo(DebugThreadList data, ulong currentThreadId, int currentFrame) {
55         import std.path;
56         _debugInfo = data;
57         if (currentThreadId == 0)
58             currentThreadId = data.currentThreadId;
59         _currentThreadId = currentThreadId;
60         _currentThreadIndex = -1;
61         _currentFrame = 0;
62         _selectedThread = null;
63         if (_debugInfo) {
64             _comboBox.enabled = true;
65             dstring[] threadNames;
66             for (int i = 0; i < _debugInfo.length; i++) {
67                 threadNames ~= _debugInfo[i].displayName.toUTF32;
68                 if (_debugInfo[i].id == _currentThreadId) {
69                     _currentThreadIndex = i;
70                     _selectedThread = _debugInfo[i];
71                     if (currentFrame <= _selectedThread.length)
72                         _currentFrame = currentFrame;
73                 }
74             }
75             _comboBox.items = threadNames;
76             if (_currentThreadIndex >= 0 && _selectedThread.length > 0) {
77                 _comboBox.selectedItemIndex = _currentThreadIndex;
78                 _grid.resize(2, _selectedThread.length);
79                 for (int i = 0; i < _selectedThread.length; i++) {
80                     if (_selectedThread[i].func)
81                         _grid.setCellText(0, i, _selectedThread[i].func.toUTF32);
82                     else if (_selectedThread[i].from)
83                         _grid.setCellText(0, i, baseName(_selectedThread[i].from.toUTF32));
84                     else
85                         _grid.setCellText(0, i, _selectedThread[i].file.toUTF32);
86                     _grid.setCellText(1, i, _selectedThread[i].formattedAddress.toUTF32);
87                 }
88             } else {
89                 _grid.resize(2, 1);
90                 _grid.setCellText(0, 0, "No info"d);
91                 _grid.setCellText(1, 0, ""d);
92             }
93         } else {
94             _comboBox.enabled = false;
95         }
96     }
97 
98     void onCellActivated(GridWidgetBase source, int col, int row) {
99         if (_debugInfo && _selectedThread && row < _selectedThread.length) {
100             if (stackFrameSelected.assigned)
101                 stackFrameSelected(_currentThreadId, row);
102         }
103     }
104 
105     bool onItemSelected(Widget source, int itemIndex) {
106         if (_debugInfo && itemIndex < _debugInfo.length && _currentThreadId != _debugInfo[itemIndex].id) {
107             _grid.selectCell(0, 0, true, null, false);
108             if (stackFrameSelected.assigned)
109                 stackFrameSelected(_debugInfo[itemIndex].id, 0);
110         }
111         return true;
112     }
113 
114     protected void onPopupMenuItem(MenuItem item) {
115         if (item.action)
116             handleAction(item.action);
117     }
118 
119     /// override to handle specific actions
120     override bool handleAction(const Action a) {
121         return super.handleAction(a);
122     }
123 
124     override void layout(Rect rc) {
125         if (visibility == Visibility.Gone) {
126             return;
127         }
128         super.layout(rc);
129         _grid.autoFitColumnWidth(2);
130         int w = _grid.clientRect.width - _grid.colWidth(2);
131         if (w < _grid.clientRect.width * 2 / 3)
132             w = _grid.clientRect.width * 2 / 3;
133         _grid.setColWidth(1, w);
134         _grid.layout(_grid.pos);
135     }
136 }
137