Minsky
pubTab.cc
Go to the documentation of this file.
1 /*
2  @copyright Steve Keen 2023
3  @author Russell Standish
4  This file is part of Minsky.
5 
6  Minsky is free software: you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Minsky is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with Minsky. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "lasso.h"
21 #include "minsky.h"
22 #include "cairoItems.h"
23 #include "pubTab.h"
24 #include "publication.rcd"
25 #include "pubTab.xcd"
26 #include "pubTab.rcd"
27 #include "pannableTab.rcd"
28 #include "pannableTab.xcd"
29 #include "minsky_epilogue.h"
30 using namespace ecolab::cairo;
31 
32 namespace minsky
33 {
34  namespace {
36  {
39  bool variableDisplay=false, buttonDisplay=false;
41  float origIWidth, origIHeight;
42  double origRotation;
43  float stashedZf;
45  item(item), editorModeToggled(item.editorMode!=item.itemRef->editorMode()),
46  origIWidth(item.itemRef? item.itemRef->iWidth(): 0),
47  origIHeight(item.itemRef? item.itemRef->iHeight(): 0),
48  origRotation(item.itemRef? item.itemRef->rotation(): 0),
49  stashedZf(cminsky().canvas.model->relZoom)
50  {
51  if (!item.itemRef) return;
52  if (auto g=item.itemRef->group.lock())
53  {
54  stashedZf=g->relZoom;
55  g->relZoom=1/g->zoomFactor();
56  }
57  if (auto g=item.itemRef->godleyIconCast())
58  {
59  if ((variableDisplay=g->variableDisplay()))
60  g->toggleVariableDisplay();
61  buttonDisplay=g->editor.drawButtons;
62  g->editor.disableButtons();
63  }
64  if (editorModeToggled)
65  item.itemRef->toggleEditorMode();
66 
67  item.itemRef->iWidth(item.zoomX*origIWidth);
68  item.itemRef->iHeight(item.zoomY*origIHeight);
69  item.itemRef->rotation(item.rotation);
70  }
72  {
73  if (!item.itemRef) return;
74  if (auto g=item.itemRef->group.lock())
75  g->relZoom=stashedZf;
76 
77  if (editorModeToggled)
78  item.itemRef->toggleEditorMode();
79  if (auto g=item.itemRef->godleyIconCast())
80  {
81  if (variableDisplay)
82  g->toggleVariableDisplay();
83  if (buttonDisplay)
84  g->editor.enableButtons();
85  }
86  item.itemRef->iWidth(origIWidth);
87  item.itemRef->iHeight(origIHeight);
88  item.itemRef->rotation(origRotation);
89  }
90  };
91  }
92 
93  Point PubItem::itemCoords(float x, float y) const
94  {
95  if (!itemRef) return {0,0};
96  return {x-this->x+itemRef->x(), y-this->y+itemRef->y()};
97  }
98 
99  void PubTab::addNote(const std::string& note, float x, float y)
100  {
101  items.emplace_back(std::make_shared<Item>());
102  items.back().itemRef->detailedText(note);
103  items.back().x=x-offsx;
104  items.back().y=y-offsy;
105  minsky().pushHistory();
106  requestRedraw();
107  }
108 
109 
110  void PubTab::removeSelf()
111  {
112  auto& publicationTabs=minsky::minsky().publicationTabs;
113  for (auto i=publicationTabs.begin(); i!=publicationTabs.end(); ++i)
114  if (this==&*i) {
115  publicationTabs.erase(i);
116  minsky().pushHistory();
117  return;
118  }
119  }
120 
121  void PubTab::removeItemAt(float x, float y)
122  {
123  zoomTranslate(x,y);
124  if (auto item=m_getItemAt(x,y))
125  for (auto i=items.begin(); i!=items.end(); ++i)
126  if (&*i==item)
127  {
128  items.erase(i);
129  minsky().pushHistory();
130  requestRedraw();
131  return;
132  }
133  }
134 
135  void PubTab::rotateItemAt(float x, float y)
136  {
137  zoomTranslate(x,y);
138  item=m_getItemAt(x,y);
139  if (item) {
140  rotateOrigin=Point{x,y};
141  rotating=true;
142  }
143  }
144 
145  bool PubTab::redraw(int x0, int y0, int width, int height)
146  {
147  if (!surface.get()) {
148  return false;
149  }
150  auto cairo=surface->cairo();
151  const CairoSave cs(cairo);
152  cairo_translate(cairo, offsx, offsy);
153  cairo_scale(cairo, m_zoomFactor, m_zoomFactor);
154  cairo_set_line_width(cairo, 1);
155  for (auto& i: items)
156  {
157  const CairoSave cs(cairo);
158  cairo_translate(cairo, i.x, i.y);
159  try
160  {
161  const EnsureEditorMode ensureEditorMode(i);
162  i.itemRef->draw(cairo);
163  }
164  catch (...) {}
165  }
166  if (clickType==ClickType::onResize)
167  {
168  cairo_rectangle(cairo,std::min(lasso.x0,lasso.x1), std::min(lasso.y0,lasso.y1),
169  abs(lasso.x0-lasso.x1), abs(lasso.y0-lasso.y1));
170  cairo_stroke(cairo);
171  }
172  return !items.empty() || clickType!=ClickType::outside;
173  }
174 
175  PubItem* PubTab::m_getItemAt(float x, float y)
176  {
177  for (auto& i: items)
178  {
179  const EnsureEditorMode e(i);
180  if (i.itemRef && i.itemRef->contains(i.itemCoords(x,y)))
181  return &i;
182  }
183  return nullptr;
184  }
185 
186  void PubTab::zoomTranslate(float& x, float& y)
187  {
188  x-=offsx; y-=offsy;
189  auto scale=1.f/m_zoomFactor;
190  x*=scale; y*=scale;
191  }
192 
193  void PubTab::mouseDown(float x, float y)
194  {
195  zoomTranslate(x,y);
196  item=m_getItemAt(x,y);
197  if (item)
198  {
199  const EnsureEditorMode e(*item);
200  auto p=item->itemCoords(x,y);
201  clickType=item->itemRef->clickType(p.x(),p.y());
202  dx=dy=0;
203  switch (clickType)
204  {
205  case ClickType::onResize:
206  {
207  auto w=item->itemRef->width()/item->zoomX;
208  auto h=item->itemRef->height()/item->zoomY;
209  lasso.x0=x>item->x? x-w: x+w;
210  lasso.y0=y>item->y? y-h: y+h;
211  lasso.x1=x;
212  lasso.y1=y;
213  }
214  break;
215  case ClickType::inItem:
216  item->itemRef->onMouseDown(p.x(),p.y());
217  break;
218  default:
219  dx=item->x-x;
220  dy=item->y-y;
221  break;
222  }
223  }
224  }
225 
226  void PubTab::mouseUp(float x, float y)
227  {
228  if (panning)
229  {
231  panning=false;
232  return;
233  }
234  mouseMove(x,y);
235  if (item)
236  switch (clickType)
237  {
238  case ClickType::onResize:
239  {
240  const EnsureEditorMode e(*item);
241  item->zoomX*=abs(lasso.x1-lasso.x0)/(item->itemRef->width());
242  item->zoomY*=abs(lasso.y1-lasso.y0)/(item->itemRef->height());
243  item->x=0.5*(lasso.x0+lasso.x1);
244  item->y=0.5*(lasso.y0+lasso.y1);
245  }
246  break;
247  case ClickType::inItem:
248  {
249  zoomTranslate(x,y);
250  const EnsureEditorMode e(*item);
251  auto p=item->itemCoords(x,y);
252  item->itemRef->onMouseUp(p.x(),p.y());
253  minsky().requestReset();
254  }
255  break;
256  default: break;
257  }
258  minsky().pushHistory();
259  item=nullptr;
260  clickType=ClickType::outside;
261  rotating=false;
262  }
263 
264  void PubTab::mouseMove(float x, float y)
265  {
266  zoomTranslate(x,y);
267  if (panning)
268  {
270  return;
271  }
272  for (auto& i: items) i.itemRef->mouseFocus=false;
273  if (item)
274  {
275  if (rotating)
276  {
277  const EnsureEditorMode e(*item);
278  item->itemRef->rotate(Point{x,y},rotateOrigin);
279  item->rotation=item->itemRef->rotation();
280  }
281  else
282  switch (clickType)
283  {
284  case ClickType::onResize:
285  lasso.x1=x;
286  lasso.y1=y;
287  break;
288  case ClickType::inItem:
289  {
290  const EnsureEditorMode e(*item);
291  auto p=item->itemCoords(x,y);
292  item->itemRef->mouseFocus=true;
293  if (item->itemRef->onMouseMotion(p.x(),p.y()))
294  requestRedraw();
295  }
296  break;
297  default:
298  item->x=x+dx;
299  item->y=y+dy;
300  break;
301  }
302  requestRedraw();
303  }
304  else
305  // indicate mouse focus
306  if (auto i=m_getItemAt(x,y))
307  {
308  i->itemRef->mouseFocus=true;
309  const EnsureEditorMode e(*i);
310  auto p=i->itemCoords(x,y);
311  i->itemRef->onMouseOver(p.x(),p.y());
312  requestRedraw();
313  }
314  }
315 
316  bool PubTab::keyPress(const KeyPressArgs& args)
317  {
318  float x=args.x, y=args.y;
319  zoomTranslate(x,y);
320  if (auto item=m_getItemAt(x,y))
321  {
322  const EnsureEditorMode em(*item);
323  if (item->itemRef->onKeyPress(args.keySym,args.utf8,args.state))
324  {
325  requestRedraw();
326  return true;
327  }
328  }
329  return false;
330  }
331 }
ItemPtr itemRef
Definition: pubTab.h:39
void requestReset()
Definition: minsky.cc:467
CLASSDESC_ACCESS_EXPLICIT_INSTANTIATION(schema3::PublicationItem)
bool pushHistory()
push current model state onto history if it differs from previous
Definition: minsky.cc:1265
minsky::Minsky minsky
Definition: pyminsky.cc:28
represents rectangular region of a lasso operation
Definition: lasso.h:28
mouseDownid x y X Y
Definition: godley.tcl:137
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
std::vector< PubTab > publicationTabs
Definition: minsky.h:156
Mixin implementing common panning functionality in tabs.
Definition: pannableTab.h:36
boost::geometry::model::d2::point_xy< float > Point
Definition: geometry.h:34
const Minsky & cminsky()
const version to help in const correctness
Definition: minsky.h:549
Minsky & minsky()
global minsky object
Definition: minskyTCL.cc:51