|
| 1 | +function [myMriAcquisition_node, reconFoV] = correctMetadataInteractive(myMriAcquisition_node, reconFoV) |
| 2 | +%CORRECTMETADATAINTERACTIVE |
| 3 | +% Opens the metadata editing window for user correction. |
| 4 | +% Standalone version — only displays the parameter table. |
| 5 | +% |
| 6 | +% Authors: |
| 7 | +% Dominik Helbing |
| 8 | +% adapted and simplified by Mauro Leidi, 2024 |
| 9 | +% |
| 10 | +% ------------------------------------------------------------------------- |
| 11 | + |
| 12 | + %% --- Input check ----------------------------------------------------- |
| 13 | + if ~isa(myMriAcquisition_node, 'bmMriAcquisitionParam') |
| 14 | + error("First argument must be an object of class bmMriAcquisitionParam."); |
| 15 | + end |
| 16 | + |
| 17 | + %% --- Parameter setup ------------------------------------------------- |
| 18 | + paramNames = {'N', 'nLine', 'nShot', 'nSeg', 'nCh', 'nEcho', ... |
| 19 | + 'nShotOff', 'FoV (acq)', 'FoV (recon)'}; |
| 20 | + |
| 21 | + automatedValues = [myMriAcquisition_node.N, ... |
| 22 | + myMriAcquisition_node.nLine, ... |
| 23 | + myMriAcquisition_node.nShot, ... |
| 24 | + myMriAcquisition_node.nSeg, ... |
| 25 | + myMriAcquisition_node.nCh, ... |
| 26 | + myMriAcquisition_node.nEcho, ... |
| 27 | + myMriAcquisition_node.nShot_off, ... |
| 28 | + mode(myMriAcquisition_node.FoV), ... |
| 29 | + mode(reconFoV)]; |
| 30 | + |
| 31 | + %% --- Create main UI figure ------------------------------------------ |
| 32 | + fig = uifigure('Name', 'Manual Parameter Adjustment', ... |
| 33 | + 'Position', [100 100 650 285]); |
| 34 | + movegui(fig, 'center'); |
| 35 | + |
| 36 | + g = uigridlayout(fig, ... |
| 37 | + 'RowHeight', {'fit','fit','1x'}, ... |
| 38 | + 'ColumnWidth', {'1x','fit'}); |
| 39 | + |
| 40 | + g2 = uigridlayout(g, [5,1], ... |
| 41 | + 'RowHeight', {'fit', 'fit', 'fit', 30, 30}); |
| 42 | + g2.Layout.Row = 2; |
| 43 | + g2.Layout.Column = 2; |
| 44 | + |
| 45 | + % Title label |
| 46 | + t = uilabel(g, ... |
| 47 | + 'Text', 'Adjust Acquisition Parameters', ... |
| 48 | + 'FontSize', 14, ... |
| 49 | + 'FontWeight', 'bold', ... |
| 50 | + 'HorizontalAlignment', 'center'); |
| 51 | + t.Layout.Row = 1; |
| 52 | + t.Layout.Column = [1,2]; |
| 53 | + |
| 54 | + %% --- Table ----------------------------------------------------------- |
| 55 | + s = uistyle('BackgroundColor', [0.9290 0.6940 0.1250]); % orange highlight |
| 56 | + data = [paramNames', num2cell(automatedValues)', num2cell(automatedValues)']; |
| 57 | + |
| 58 | + uit = uitable(g, ... |
| 59 | + 'Data', data, ... |
| 60 | + 'ColumnEditable', [false false true], ... |
| 61 | + 'ColumnName', {'Acquisition Parameters', 'Extracted Value', 'User Value'}, ... |
| 62 | + 'ColumnWidth', '1x'); |
| 63 | + uit.Layout.Row = 2; |
| 64 | + uit.Layout.Column = 1; |
| 65 | + addStyle(uit, s, "column", 3); |
| 66 | + |
| 67 | + %% --- Controls (dropdowns, checkbox, buttons) ------------------------- |
| 68 | + % Add dropdown for different cases, maybe table changes depending on case |
| 69 | + dd = uidropdown(g2, 'Items', {'Non-Cartesian', 'Cartesian', 'Case 3'}, ... |
| 70 | + "ValueChangedFcn",@(src,event) updateTable(src, uit)); |
| 71 | + dropDown = dd.Value; |
| 72 | + |
| 73 | + % Add dropdown for navigation |
| 74 | + dd_self = uidropdown(g2, 'Items', {'SI Navigation', ... |
| 75 | + 'Pilot Tone Navigation', ... |
| 76 | + 'Other'}); |
| 77 | + |
| 78 | + % If self nav is not used atm |
| 79 | + if ~myMriAcquisition_node.selfNav_flag |
| 80 | + dd_self.Value = 'Other'; |
| 81 | + end |
| 82 | + |
| 83 | + % Add a checkbox for roosk_flag |
| 84 | + cbx_rooks = uicheckbox(g2, 'Text', 'Remove oversampling', 'Value', ... |
| 85 | + myMriAcquisition_node.roosk_flag); |
| 86 | + |
| 87 | + % Add a button to confirm changes |
| 88 | + uibutton(g2, 'Text', 'Confirm', ... |
| 89 | + 'ButtonPushedFcn', @(btn,event) confirmCallback(fig)); |
| 90 | + |
| 91 | + % Add a button to cancel |
| 92 | + uibutton(g2, 'Text', 'Cancel', 'BackgroundColor', '#d0d0d0', ... |
| 93 | + 'ButtonPushedFcn', @(btn,event) closeFigure(fig)); |
| 94 | + |
| 95 | + % Handle figure close request to resume execution |
| 96 | + fig.CloseRequestFcn = @(src, event) closeFigure(fig); |
| 97 | + |
| 98 | + |
| 99 | + %% --- Wait for user interaction -------------------------------------- |
| 100 | + uiwait(fig); |
| 101 | + |
| 102 | + %% --- Retrieve values after closing ---------------------------------- |
| 103 | + % Only update the values if figure was closed using "Confirm" |
| 104 | + if ishandle(fig) |
| 105 | + % Table values |
| 106 | + automatedValues = cell2mat(uit.Data(:,3))'; |
| 107 | + |
| 108 | + % Checkbox values |
| 109 | + selfNav = strcmp(dd_self.Value, 'SI Navigation'); |
| 110 | + myMriAcquisition_node.selfNav_flag = selfNav; |
| 111 | + myMriAcquisition_node.roosk_flag = cbx_rooks.Value; |
| 112 | + |
| 113 | + % Dropdown value |
| 114 | + dropDown = dd.Value; |
| 115 | + |
| 116 | + % Close the figure |
| 117 | + close(fig); |
| 118 | + end |
| 119 | + |
| 120 | + %% Return values |
| 121 | + % Update values in myMriAcquisition_node |
| 122 | + if strcmp(dropDown, 'Non-Cartesian') |
| 123 | + % Table values |
| 124 | + myMriAcquisition_node.N = automatedValues(1); |
| 125 | + myMriAcquisition_node.nLine = automatedValues(2); |
| 126 | + myMriAcquisition_node.nShot = automatedValues(3); |
| 127 | + myMriAcquisition_node.nSeg = automatedValues(4); |
| 128 | + myMriAcquisition_node.nCh = automatedValues(5); |
| 129 | + myMriAcquisition_node.nEcho = automatedValues(6); |
| 130 | + myMriAcquisition_node.nShot_off = automatedValues(7); |
| 131 | + newFoV = ones(size(myMriAcquisition_node.FoV)).*automatedValues(8); |
| 132 | + myMriAcquisition_node.FoV = newFoV; |
| 133 | + reconFoV = ones(size(myMriAcquisition_node.FoV)).*automatedValues(9); |
| 134 | + end |
| 135 | + |
| 136 | + if strcmp(dropDown, 'Cartesian') |
| 137 | + error("Case not implemented yet"); |
| 138 | + end |
| 139 | + |
| 140 | + if strcmp(dropDown, 'Case 3') |
| 141 | + error("Case not implemented yet"); |
| 142 | + end |
| 143 | + % End of function |
| 144 | + |
| 145 | + %% --- Nested callback functions -------------------------------------- |
| 146 | + function confirmCallback(fig) |
| 147 | + uiresume(fig); |
| 148 | + end |
| 149 | + |
| 150 | + function updateTable(src, uit) |
| 151 | + % Callback function to handle a dropdown change NOT IN USE YET |
| 152 | + % Change the background color of the columns depending on the drop |
| 153 | + % down. This is only as an example on how to use it. |
| 154 | + cols = uistyle('BackgroundColor', [0.9290 0.6940 0.1250]); |
| 155 | + removeStyle(uit); |
| 156 | + switch src.Value |
| 157 | + case 'Non-Cartesian' |
| 158 | + col = 3; |
| 159 | + case 'Cartesian' |
| 160 | + col = 2; |
| 161 | + case 'Case 3' |
| 162 | + col = 1; |
| 163 | + otherwise |
| 164 | + col = 1; |
| 165 | + end |
| 166 | + addStyle(uit, cols, "column", col); |
| 167 | + end |
| 168 | + |
| 169 | + |
| 170 | + function closeFigure(fig) |
| 171 | + % Callback function to handle figure close event |
| 172 | + |
| 173 | + % Resume execution and close the figure |
| 174 | + uiresume(fig); |
| 175 | + delete(fig); |
| 176 | + end |
| 177 | + |
| 178 | +end |
0 commit comments