31 #include <cairo_base.h> 33 #include "noteBase.rcd" 34 #include "noteBase.xcd" 35 #include "polyRESTProcessBase.h" 40 using ecolab::cairo::CairoSave;
46 void BoundingBox::update(
const Item& x)
48 const ecolab::cairo::Surface surf
49 (cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA,NULL));
54 if (
auto parent=x.group.lock())
56 stashedZf=parent->relZoom;
61 const cairo::CairoSave cs(surf.cairo());
66 catch (
const std::exception& e)
67 {cerr<<
"illegal exception caught in draw(): "<<e.what()<<endl;}
68 catch (...) {cerr<<
"illegal exception caught in draw()";}
73 if (
auto parent=x.group.lock())
74 parent->relZoom=stashedZf;
77 cairo_recording_surface_ink_extents(surf.surface(),
86 void Item::throw_error(
const std::string& msg)
const 89 throw runtime_error(msg);
92 std::pair<double,bool> Item::rotationAsRadians()
const 96 return {rotation() *
M_PI / 180.0,
flipped(rotation())};
100 void ItemExclude::rotate(
const Point& mouse,
const Point& orig)
102 constexpr
double degrees=180.0/
M_PI;
103 m_rotation=atan2(mouse.y()-orig.y(),mouse.x()-orig.x())*degrees;
107 float Item::x()
const 109 if (
auto g=
group.lock())
110 return zoomFactor()*m_x+g->x();
114 float Item::y()
const 116 if (
auto g=
group.lock())
117 return zoomFactor()*m_y+g->y();
121 float Item::zoomFactor()
const 123 if (
auto g=
group.lock())
124 return g->zoomFactor()*g->relZoom;
128 float Item::scaleFactor()
const 133 float Item::scaleFactor(
const float& sf) {
139 void Item::deleteAttachedWires()
141 for (
auto& p: m_ports)
147 inline bool near(
float x0,
float y0,
float x1,
float y1,
float d)
149 return abs(x0-x1)<d && abs(y0-y1)<d;
153 std::vector<Point> Item::corners()
const 156 auto left=x()+bb.left()*zoomFactor(), right=x()+bb.right()*zoomFactor();
157 auto top=y()+bb.top()*zoomFactor(), bottom=y()+bb.bottom()*zoomFactor();
158 memoisedRotator.update(rotation(),x(),y());
159 return {memoisedRotator(left,top),memoisedRotator(left,bottom),
160 memoisedRotator(right,bottom),memoisedRotator(right,top)};
163 float Item::left()
const 166 for (
auto& p: corners())
167 if (p.x()<left) left=p.x();
170 float Item::right()
const 173 for (
auto& p: corners())
174 if (p.x()>right) right=p.x();
177 float Item::top()
const 180 for (
auto& p: corners())
181 if (p.y()<top) top=p.y();
184 float Item::bottom()
const 187 for (
auto& p: corners())
188 if (p.y()>bottom) bottom=p.y();
192 void Item::adjustBookmark()
const 194 if (
auto g=
group.lock())
196 auto& bookmarks=g->bookmarks;
198 g->addBookmarkXY(left(),top(),bookmarkId());
200 bookmarks.erase(bookmarkId());
205 Point BottomRightResizerItem::resizeHandleCoords()
const 209 memoisedRotator.update(rotation(),x(),y());
210 auto left=x()+bb.left()*zoomFactor(), right=x()+bb.right()*zoomFactor();
211 auto top=y()+bb.top()*zoomFactor(), bottom=y()+bb.bottom()*zoomFactor();
215 return memoisedRotator(right,bottom);
217 return memoisedRotator(right,top);
219 return memoisedRotator(left,top);
221 return memoisedRotator(left,bottom);
228 bool Item::onResizeHandle(
float x,
float y)
const 230 float rhSize=resizeHandleSize();
232 return any_of(cnrs.begin(), cnrs.end(), [&](
const Point& p)
233 {
return near(x,y,p.x(),p.y(),rhSize);});
236 bool BottomRightResizerItem::onResizeHandle(
float x,
float y)
const 238 const Point p=resizeHandleCoords();
239 return near(x,y,p.x(),p.y(),resizeHandleSize());
242 bool Item::onItem(
float x,
float y)
const 244 const Rotate r(-rotation(),this->x(),this->y());
246 (r.
x(x,y)-this->x())/zoomFactor(),
247 (r.
y(x,y)-this->y())/zoomFactor());
250 bool Item::visible()
const 253 return (!g || g->displayContents());
256 void Item::moveTo(
float x,
float y)
260 if (
auto g=
group.lock())
262 const float invZ=1/zoomFactor();
271 if (bookmark) adjustBookmark();
272 assert(abs(x-this->x())<1 && abs(y-this->y())<1);
278 if (
auto item=select(x,y))
279 return item->clickType(x,y);
282 for (
auto& p: m_ports)
284 if (hypot(x-p->x(), y-p->y()) <
portRadius*zoomFactor())
285 return ClickType::onPort;
288 if (onResizeHandle(x,y))
return ClickType::onResize;
289 if (inItem(x,y))
return ClickType::inItem;
290 if (onItem(x,y))
return ClickType::onItem;
291 return ClickType::outside;
294 void Item::drawPorts(cairo_t* cairo)
const 296 const CairoSave cs(cairo);
297 cairo_new_path(cairo);
298 for (
auto& p: m_ports)
300 cairo_new_sub_path(cairo);
301 cairo_arc(cairo, p->x()-x(), p->y()-y(),
portRadius*zoomFactor(), 0, 2*
M_PI);
303 cairo_set_source_rgb(cairo, 0,0,0);
304 cairo_set_line_width(cairo,1);
308 void Item::drawSelected(cairo_t* cairo)
311 const CairoSave cs(cairo);
312 cairo_set_source_rgba(cairo, 0.5,0.5,0.5,0.4);
316 void Item::drawResizeHandle(cairo_t* cairo,
double x,
double y,
double sf,
double angle)
318 const cairo::CairoSave cs(cairo);
319 cairo_translate(cairo,x,y);
320 cairo_rotate(cairo,angle);
321 cairo_scale(cairo,sf,sf);
322 cairo_move_to(cairo,-1,-.2);
323 cairo_line_to(cairo,-1,-1);
324 cairo_line_to(cairo,1,1);
325 cairo_line_to(cairo,1,0.2);
326 cairo_move_to(cairo,-1,-1);
327 cairo_line_to(cairo,-.2,-1);
328 cairo_move_to(cairo,.2,1);
329 cairo_line_to(cairo,1,1);
336 const float w=iWidth(width()), h=iHeight(height()), invZ=1/zoomFactor();
337 moveTo(0.5*(b.
x0+b.
x1), 0.5*(b.
y0+b.
y1));
338 iWidth(abs(b.
x1-b.
x0)*invZ);
339 iHeight(abs(b.
y1-b.
y0)*invZ);
340 scaleFactor(std::max(1.0
f,std::min(iWidth()/w,iHeight()/h)));
343 void Item::drawResizeHandles(cairo_t* cairo)
const 345 auto sf=resizeHandleSize();
346 double angle=0.5*
M_PI;
347 for (
auto& p: corners())
350 drawResizeHandle(cairo,p.x()-x(),p.y()-y(),sf,angle);
355 void BottomRightResizerItem::drawResizeHandles(cairo_t* cairo)
const 357 const Point p=resizeHandleCoords();
358 drawResizeHandle(cairo,p.x()-x(),p.y()-y(),resizeHandleSize(),0);
363 void Item::draw(cairo_t* cairo)
const 365 auto [angle,
flipped]=rotationAsRadians();
368 const float z=zoomFactor();
370 pango.setFontSize(12.0*scaleFactor()*z);
373 const float w=0.5*pango.width()+2*z;
374 const float h=0.5*pango.height()+4*z;
376 cairo_move_to(cairo,r.
x(-w+1,-h+2), r.
y(-w+1,-h+2));
380 displayTooltip(cairo,tooltip());
382 if (onResizeHandles) drawResizeHandles(cairo);
383 cairo_move_to(cairo,r.
x(-w,-h), r.
y(-w,-h));
384 cairo_line_to(cairo,r.
x(w,-h), r.
y(w,-h));
385 cairo_line_to(cairo,r.
x(w,h), r.
y(w,h));
386 cairo_line_to(cairo,r.
x(-w,h), r.
y(-w,h));
387 cairo_close_path(cairo);
389 if (selected) drawSelected(cairo);
392 void Item::dummyDraw()
const 394 const ecolab::cairo::Surface s(cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA,NULL));
398 void Item::displayTooltip(cairo_t* cairo,
const std::string& tooltip)
const 400 const string unitstr=units().latexStr();
401 if (!tooltip.empty() || !unitstr.empty())
403 const cairo::CairoSave cs(cairo);
406 if (!unitstr.empty())
408 pango.setMarkup(toolTipText);
409 const float z=zoomFactor();
410 cairo_translate(cairo,z*(0.5*bb.width())+10,
411 z*(-0.5*bb.height())-20);
412 cairo_rectangle(cairo,0,0,pango.width(),pango.height());
413 cairo_set_source_rgb(cairo,1,1,1);
414 cairo_fill_preserve(cairo);
415 cairo_set_source_rgb(cairo,0,0,0);
421 shared_ptr<Port> Item::closestOutPort(
float x,
float y)
const 423 if (
auto v=select(x,y))
424 return v->closestOutPort(x,y);
425 return portsSize()>0 && !ports(0).lock()->input()? ports(0).lock():
nullptr;
428 shared_ptr<Port> Item::closestInPort(
float x,
float y)
const 430 if (
auto v=select(x,y))
431 return v->closestInPort(x,y);
433 for (
size_t i=0; i<m_ports.size(); ++i)
434 if (m_ports[i]->
input() &&
435 (!r ||
sqr(m_ports[i]->x()-x)+
sqr(m_ports[i]->y()-y) <
436 sqr(r->x()-x)+
sqr(r->y()-y)))
441 void ItemExclude::removeControlledItems()
443 if (
auto g=
group.lock())
444 removeControlledItems(*g);
449 if (
auto g=
group.lock())
450 return g->findItem(*
this);
#define M_PI
some useful geometry types, defined from boost::geometry
std::string latexToPango(const char *s)
represents whether a mouse click is on the item, on an output port (for wiring, or is actually outsid...
void displayErrorItem(const Item &op) const
indicate operation item has error, if visible, otherwise contining group
bool onResizeHandles
set to true to indicate mouse is ovcaler resize handles
bool near(float x0, float y0, float x1, float y1, float d)
represents rectangular region of a lasso operation
float y(float x, float y) const
std::shared_ptr< Item > ItemPtr
rotate (x,y) by rot (in degrees) around the origin (x0, y0) can be used for rotating multiple points ...
virtual float zoomFactor() const
bool flipped(double rotation)
returns if the angle (in degrees) is in the second or third quadrant
int quadrant(double x)
return quadrant x is in: 0=[-45,45),1=[45,135), etc
virtual void draw(cairo_t *cairo) const
draw this item into a cairo context
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky's state cha...
double isfinite(double x)
virtual void bookmarkRefresh()
refresh the bookmark menu after changes
boost::geometry::model::d2::point_xy< float > Point
const Minsky & cminsky()
const version to help in const correctness
CLASSDESC_ACCESS_EXPLICIT_INSTANTIATION(minsky::NoteBase)
bool mouseFocus
true if target of a mouseover
constexpr float portRadius
radius of circle marking ports at zoom=1
float x(float x, float y) const