CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxLayoutData.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 #include "cxLayoutData.h"
13 #include <iostream>
14 #include <QDomElement>
15 #include "cxLogger.h"
16 #include "cxView.h"
17 #include "cxEnumConversion.h"
18 
19 namespace cx
20 {
21 
23 {
24  if (a.pos.col<0 || a.pos.row<0)
25  return b;
26  if (b.pos.col<0 || b.pos.row<0)
27  return a;
28 
29  int r1 = std::min(a.pos.row, b.pos.row);
30  int c1 = std::min(a.pos.col, b.pos.col);
31  int r2 = std::max(a.pos.row + a.span.row - 1, b.pos.row + b.span.row - 1);
32  int c2 = std::max(a.pos.col + a.span.col - 1, b.pos.col + b.span.col - 1);
33  return LayoutRegion(r1, c1, r2 - r1 + 1, c2 - c1 + 1);
34 }
35 
36 void LayoutViewData::addXml(QDomNode node) const
37 {
38  QDomElement elem = node.toElement();
39  elem.setAttribute("group", qstring_cast(mGroup));
40  elem.setAttribute("type", qstring_cast(mPlane));
41  elem.setAttribute("view", qstring_cast(mType));
42  elem.setAttribute("row", qstring_cast(mRegion.pos.row));
43  elem.setAttribute("col", qstring_cast(mRegion.pos.col));
44  elem.setAttribute("rowSpan", qstring_cast(mRegion.span.row));
45  elem.setAttribute("colSpan", qstring_cast(mRegion.span.col));
46 }
47 
48 void LayoutViewData::parseXml(QDomNode node)
49 {
50  QDomElement elem = node.toElement();
51  mGroup = elem.attribute("group").toInt();
52  mPlane = string2enum<PLANE_TYPE> (elem.attribute("type"));
53  // mType = string2enum<View::Type>(elem.attribute("view"));
54  mType = static_cast<View::Type> (elem.attribute("view").toInt());
55  mRegion.pos.row = elem.attribute("row").toInt();
56  mRegion.pos.col = elem.attribute("col").toInt();
57  mRegion.span.row = elem.attribute("rowSpan").toInt();
58  mRegion.span.col = elem.attribute("colSpan").toInt();
59 }
60 
61 LayoutData LayoutData::createHeader(QString uid, QString name)
62 {
63  return create(uid, name, 0, 0);
64 }
65 
66 LayoutData LayoutData::create(QString uid, QString name, int rows, int cols)
67 {
68  LayoutData retval;
69  retval.resetUid(uid);
70  retval.setName(name);
71  retval.resize(rows, cols);
72  return retval;
73 }
74 
76  mName("unnamed"),
77  mOffScreenRendering(false)
78 {
79  mSize = LayoutPosition(0, 0);
80  this->resize(0, 0);
81 }
82 
83 void LayoutData::resetUid(const QString& uid)
84 {
85  mUid = uid;
86  mName = mName + " " + uid;
87 }
88 
92 void LayoutData::setView(int group, PLANE_TYPE type, LayoutRegion region)
93 {
94  if (!this->merge(region))
95  return;
96  LayoutViewData& view = get(region.pos);
97  view.mGroup = group;
98  view.mPlane = type;
99  view.mType = View::VIEW_2D;
100 }
101 
102 void LayoutData::setView(int group, View::Type type, LayoutRegion region)
103 {
104  if (!this->merge(region))
105  return;
106  LayoutViewData& view = get(region.pos);
107  view.mGroup = group;
108  view.mPlane = ptNOPLANE;
109  view.mType = type;
110 }
111 
118 {
119  if (region.pos.row + region.span.row > mSize.row || region.pos.col + region.span.col > mSize.col)
120  {
121  reportError("Attempted to merge a region outside allocated space in LayoutData.");
122  return false;
123  }
124 
125  //std::cout << "merge views " << std::endl;
126  this->split(region); // split all existing merges in order to keep consistency
127 
128  // create new merged view based on the ul corner view.
129  LayoutViewData current = this->get(region.pos);
130  current.mRegion = region;
131 
132  // erase all views within region (all should now be 1x1)
133  for (int r = region.pos.row; r < region.pos.row + region.span.row; ++r)
134  {
135  for (int c = region.pos.col; c < region.pos.col + region.span.col; ++c)
136  {
137  iterator iter = this->find(LayoutPosition(r, c));
138  if (iter != this->end())
139  mView.erase(iter);
140  }
141  }
142 
143  // add merged view.
144  mView.push_back(current);
145  return true;
146 }
147 
152 {
153  // reset all primitives in region
154  for (int r = region.pos.row; r < region.pos.row + region.span.row; ++r)
155  {
156  for (int c = region.pos.col; c < region.pos.col + region.span.col; ++c)
157  {
158  iterator iter = this->find(LayoutPosition(r, c));
159  this->split(iter);
160  }
161  }
162 }
163 
168 {
169  if (iter == this->end())
170  return;
171  if (iter->mRegion.span.row == 1 && iter->mRegion.span.col == 1)
172  return; // nothing to split
173 
174  LayoutViewData newView = *iter;
175  LayoutRegion region = iter->mRegion;
176 
177  // erase old region
178  mView.erase(iter);
179 
180  // insert new 1x1 views in the erased region.
181  for (int r = region.pos.row; r < region.pos.row + region.span.row; ++r)
182  {
183  for (int c = region.pos.col; c < region.pos.col + region.span.col; ++c)
184  {
185  newView.mRegion = LayoutRegion(r, c, 1, 1);
186  mView.push_back(newView);
187  }
188  }
189 }
190 
194 void LayoutData::resize(int rows, int cols)
195 {
196  mSize = LayoutPosition(rows, cols);
197 
198  if (mSize.row == 0 || mSize.col == 0)
199  {
200  mView.clear();
201  return;
202  }
203 
204  // erase all views outside region
205  // TODO: also consider nontrivial regions.
206  for (iterator iter = this->begin(); iter != this->end();)
207  {
208  if (iter->mRegion.pos.row >= rows || iter->mRegion.pos.col >= cols)
209  {
210  iter = mView.erase(iter);
211  }
212  else
213  {
214  ++iter;
215  }
216  }
217 
218  // add new views (brute force: optimize if needed)
219  for (int r = 0; r < rows; ++r)
220  {
221  for (int c = 0; c < cols; ++c)
222  {
223  if (this->find(LayoutPosition(r, c)) == this->end())
224  {
225  mView.push_back(LayoutViewData(r, c, 1, 1));
226  }
227  }
228  }
229 }
230 
231 //const LayoutData::ViewData& LayoutData::get(LayoutPosition pos) const
232 //{
233 // return *(this->find(pos));
234 //}
235 
237 {
238  return *(this->find(pos));
239 }
240 
242 {
243  for (iterator iter = this->begin(); iter != this->end(); ++iter)
244  {
245  if (iter->mRegion.contains(pos))
246  return iter;
247  }
248 
249  return this->end();
250 }
251 
252 void LayoutData::addXml(QDomNode node) const
253 {
254  QDomDocument doc = node.ownerDocument();
255  QDomElement elem = node.toElement();
256 
257  elem.setAttribute("uid", mUid);
258  elem.setAttribute("name", mName);
259  elem.setAttribute("offScreenRendering", mOffScreenRendering);
260 
261  QDomElement size = doc.createElement("size");
262  size.setAttribute("row", mSize.row);
263  size.setAttribute("col", mSize.col);
264  elem.appendChild(size);
265 
266  for (const_iterator iter = this->begin(); iter != this->end(); ++iter)
267  {
268  QDomElement view = doc.createElement("view");
269  iter->addXml(view);
270  elem.appendChild(view);
271  }
272 }
273 
274 void LayoutData::parseXml(QDomNode node)
275 {
276  if (node.isNull())
277  return;
278 
279  QDomElement elem = node.toElement();
280  mUid = elem.attribute("uid");
281  mName = elem.attribute("name");
282  mOffScreenRendering = elem.attribute("offScreenRendering").toInt();
283 
284  QDomElement size = elem.namedItem("size").toElement();
285  mSize.row = size.attribute("row").toInt();
286  mSize.col = size.attribute("col").toInt();
287 
288  mView.clear();
289  // iterate over all views
290  QDomElement currentElem = elem.firstChildElement("view");
291  for (; !currentElem.isNull(); currentElem = currentElem.nextSiblingElement("view"))
292  {
293  LayoutViewData viewData;
294  viewData.parseXml(currentElem);
295  mView.push_back(viewData);
296  }
297 }
298 
299 } // namespace cx
QString qstring_cast(const T &val)
int mGroup
what group to connect to. -1 means not set.
Definition: cxLayoutData.h:63
void reportError(QString msg)
Definition: cxLogger.cpp:71
static LayoutData createHeader(QString uid, QString name)
ViewDataContainer::iterator iterator
Definition: cxLayoutData.h:80
LayoutPosition span
size of region
Definition: cxLayoutData.h:46
bool merge(LayoutRegion region)
iterator begin()
Definition: cxLayoutData.h:97
void setName(const QString &name)
Definition: cxLayoutData.h:92
void parseXml(QDomNode node)
load state from xml
PLANE_TYPE mPlane
ptNOPLANE means 3D
Definition: cxLayoutData.h:64
LayoutRegion mRegion
Definition: cxLayoutData.h:66
LayoutViewData & get(LayoutPosition pos)
iterator find(LayoutPosition pos)
void split(iterator iter)
void resize(int rows, int cols)
void setView(int group, PLANE_TYPE type, LayoutRegion region)
void parseXml(QDomNode node)
load state from xml
LayoutPosition size() const
Definition: cxLayoutData.h:108
ptNOPLANE
a initial plane, if no yet set
Definition: cxDefinitions.h:39
LayoutPosition pos
start position of region
Definition: cxLayoutData.h:45
void resetUid(const QString &uid)
ViewDataContainer::const_iterator const_iterator
Definition: cxLayoutData.h:81
void addXml(QDomNode node) const
save state to xml
iterator end()
Definition: cxLayoutData.h:98
View::Type mType
Definition: cxLayoutData.h:65
void addXml(QDomNode node) const
save state to xml
LayoutRegion merge(LayoutRegion a, LayoutRegion b)
static LayoutData create(QString uid, QString name, int rows, int cols)
Namespace for all CustusX production code.