Fraxinus  18.10
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 "cxTypeConversions.h"
16 #include "cxLogger.h"
17 #include "cxDefinitionStrings.h"
18 #include "cxView.h"
19 
20 namespace cx
21 {
22 
24 {
25  if (a.pos.col<0 || a.pos.row<0)
26  return b;
27  if (b.pos.col<0 || b.pos.row<0)
28  return a;
29 
30  int r1 = std::min(a.pos.row, b.pos.row);
31  int c1 = std::min(a.pos.col, b.pos.col);
32  int r2 = std::max(a.pos.row + a.span.row - 1, b.pos.row + b.span.row - 1);
33  int c2 = std::max(a.pos.col + a.span.col - 1, b.pos.col + b.span.col - 1);
34  return LayoutRegion(r1, c1, r2 - r1 + 1, c2 - c1 + 1);
35 }
36 
37 void LayoutViewData::addXml(QDomNode node) const
38 {
39  QDomElement elem = node.toElement();
40  elem.setAttribute("group", qstring_cast(mGroup));
41  elem.setAttribute("type", qstring_cast(mPlane));
42  elem.setAttribute("view", qstring_cast(mType));
43  elem.setAttribute("row", qstring_cast(mRegion.pos.row));
44  elem.setAttribute("col", qstring_cast(mRegion.pos.col));
45  elem.setAttribute("rowSpan", qstring_cast(mRegion.span.row));
46  elem.setAttribute("colSpan", qstring_cast(mRegion.span.col));
47 }
48 
49 void LayoutViewData::parseXml(QDomNode node)
50 {
51  QDomElement elem = node.toElement();
52  mGroup = elem.attribute("group").toInt();
53  mPlane = string2enum<PLANE_TYPE> (elem.attribute("type"));
54  // mType = string2enum<View::Type>(elem.attribute("view"));
55  mType = static_cast<View::Type> (elem.attribute("view").toInt());
56  mRegion.pos.row = elem.attribute("row").toInt();
57  mRegion.pos.col = elem.attribute("col").toInt();
58  mRegion.span.row = elem.attribute("rowSpan").toInt();
59  mRegion.span.col = elem.attribute("colSpan").toInt();
60 }
61 
62 LayoutData LayoutData::createHeader(QString uid, QString name)
63 {
64  return create(uid, name, 0, 0);
65 }
66 
67 LayoutData LayoutData::create(QString uid, QString name, int rows, int cols)
68 {
69  LayoutData retval;
70  retval.resetUid(uid);
71  retval.setName(name);
72  retval.resize(rows, cols);
73  return retval;
74 }
75 
77  mName("unnamed"),
78  mOffScreenRendering(false)
79 {
80  mSize = LayoutPosition(0, 0);
81  this->resize(0, 0);
82 }
83 
84 void LayoutData::resetUid(const QString& uid)
85 {
86  mUid = uid;
87  mName = mName + " " + uid;
88 }
89 
93 void LayoutData::setView(int group, PLANE_TYPE type, LayoutRegion region)
94 {
95  if (!this->merge(region))
96  return;
97  LayoutViewData& view = get(region.pos);
98  view.mGroup = group;
99  view.mPlane = type;
100  view.mType = View::VIEW_2D;
101 }
102 
103 void LayoutData::setView(int group, View::Type type, LayoutRegion region)
104 {
105  if (!this->merge(region))
106  return;
107  LayoutViewData& view = get(region.pos);
108  view.mGroup = group;
109  view.mPlane = ptNOPLANE;
110  view.mType = type;
111 }
112 
119 {
120  if (region.pos.row + region.span.row > mSize.row || region.pos.col + region.span.col > mSize.col)
121  {
122  reportError("Attempted to merge a region outside allocated space in LayoutData.");
123  return false;
124  }
125 
126  //std::cout << "merge views " << std::endl;
127  this->split(region); // split all existing merges in order to keep consistency
128 
129  // create new merged view based on the ul corner view.
130  LayoutViewData current = this->get(region.pos);
131  current.mRegion = region;
132 
133  // erase all views within region (all should now be 1x1)
134  for (int r = region.pos.row; r < region.pos.row + region.span.row; ++r)
135  {
136  for (int c = region.pos.col; c < region.pos.col + region.span.col; ++c)
137  {
138  iterator iter = this->find(LayoutPosition(r, c));
139  if (iter != this->end())
140  mView.erase(iter);
141  }
142  }
143 
144  // add merged view.
145  mView.push_back(current);
146  return true;
147 }
148 
153 {
154  // reset all primitives in region
155  for (int r = region.pos.row; r < region.pos.row + region.span.row; ++r)
156  {
157  for (int c = region.pos.col; c < region.pos.col + region.span.col; ++c)
158  {
159  iterator iter = this->find(LayoutPosition(r, c));
160  this->split(iter);
161  }
162  }
163 }
164 
169 {
170  if (iter == this->end())
171  return;
172  if (iter->mRegion.span.row == 1 && iter->mRegion.span.col == 1)
173  return; // nothing to split
174 
175  LayoutViewData newView = *iter;
176  LayoutRegion region = iter->mRegion;
177 
178  // erase old region
179  mView.erase(iter);
180 
181  // insert new 1x1 views in the erased region.
182  for (int r = region.pos.row; r < region.pos.row + region.span.row; ++r)
183  {
184  for (int c = region.pos.col; c < region.pos.col + region.span.col; ++c)
185  {
186  newView.mRegion = LayoutRegion(r, c, 1, 1);
187  mView.push_back(newView);
188  }
189  }
190 }
191 
195 void LayoutData::resize(int rows, int cols)
196 {
197  mSize = LayoutPosition(rows, cols);
198 
199  if (mSize.row == 0 || mSize.col == 0)
200  {
201  mView.clear();
202  return;
203  }
204 
205  // erase all views outside region
206  // TODO: also consider nontrivial regions.
207  for (iterator iter = this->begin(); iter != this->end();)
208  {
209  if (iter->mRegion.pos.row >= rows || iter->mRegion.pos.col >= cols)
210  {
211  iter = mView.erase(iter);
212  }
213  else
214  {
215  ++iter;
216  }
217  }
218 
219  // add new views (brute force: optimize if needed)
220  for (int r = 0; r < rows; ++r)
221  {
222  for (int c = 0; c < cols; ++c)
223  {
224  if (this->find(LayoutPosition(r, c)) == this->end())
225  {
226  mView.push_back(LayoutViewData(r, c, 1, 1));
227  }
228  }
229  }
230 }
231 
232 //const LayoutData::ViewData& LayoutData::get(LayoutPosition pos) const
233 //{
234 // return *(this->find(pos));
235 //}
236 
238 {
239  return *(this->find(pos));
240 }
241 
243 {
244  for (iterator iter = this->begin(); iter != this->end(); ++iter)
245  {
246  if (iter->mRegion.contains(pos))
247  return iter;
248  }
249 
250  return this->end();
251 }
252 
253 void LayoutData::addXml(QDomNode node) const
254 {
255  QDomDocument doc = node.ownerDocument();
256  QDomElement elem = node.toElement();
257 
258  elem.setAttribute("uid", mUid);
259  elem.setAttribute("name", mName);
260  elem.setAttribute("offScreenRendering", mOffScreenRendering);
261 
262  QDomElement size = doc.createElement("size");
263  size.setAttribute("row", mSize.row);
264  size.setAttribute("col", mSize.col);
265  elem.appendChild(size);
266 
267  for (const_iterator iter = this->begin(); iter != this->end(); ++iter)
268  {
269  QDomElement view = doc.createElement("view");
270  iter->addXml(view);
271  elem.appendChild(view);
272  }
273 }
274 
275 void LayoutData::parseXml(QDomNode node)
276 {
277  if (node.isNull())
278  return;
279 
280  QDomElement elem = node.toElement();
281  mUid = elem.attribute("uid");
282  mName = elem.attribute("name");
283  mOffScreenRendering = elem.attribute("offScreenRendering").toInt();
284 
285  QDomElement size = elem.namedItem("size").toElement();
286  mSize.row = size.attribute("row").toInt();
287  mSize.col = size.attribute("col").toInt();
288 
289  mView.clear();
290  // iterate over all views
291  QDomElement currentElem = elem.firstChildElement("view");
292  for (; !currentElem.isNull(); currentElem = currentElem.nextSiblingElement("view"))
293  {
294  LayoutViewData viewData;
295  viewData.parseXml(currentElem);
296  mView.push_back(viewData);
297  }
298 }
299 
300 } // 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:38
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.