static int write_padded(const char *p, size_t sz, size_t pad, char pch, bool plr, const char *prfx, re_vprintf_h *vph, void *arg) { const size_t prfx_len = str_len(prfx); int err = 0; pad -= MIN(pad, prfx_len); if (prfx && pch == '0') err |= vph(prfx, prfx_len, arg); while (!plr && (pad-- > sz)) err |= vph(&pch, 1, arg); if (prfx && pch != '0') err |= vph(prfx, prfx_len, arg); if (p && sz) err |= vph(p, sz, arg); while (plr && pad-- > sz) err |= vph(&pch, 1, arg); return err; }
/** * Snap to a coordinate in the drawing using the current snap mode. * * @param e A mouse event. * @return The coordinates of the point or an invalid vector. */ RS_Vector RS_Snapper::snapPoint(QMouseEvent* e) { RS_DEBUG->print("RS_Snapper::snapPoint"); snapSpot = RS_Vector(false); RS_Vector t(false); if (e==NULL) { RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Snapper::snapPoint: event is NULL"); return snapSpot; } RS_Vector mouseCoord = graphicView->toGraph(e->x(), e->y()); double ds2Min=RS_MAXDOUBLE*RS_MAXDOUBLE; if (snapMode.snapEndpoint) { t = snapEndpoint(mouseCoord); double&& ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; snapSpot = t; } } if (snapMode.snapCenter) { t = snapCenter(mouseCoord); double&& ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; snapSpot = t; } } if (snapMode.snapMiddle) { //this is still brutal force //todo: accept value from widget QG_SnapMiddleOptions if(RS_DIALOGFACTORY != NULL) { RS_DIALOGFACTORY->requestSnapMiddleOptions(middlePoints, snapMode.snapMiddle); } t = snapMiddle(mouseCoord); double&& ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; snapSpot = t; } } if (snapMode.snapDistance) { //this is still brutal force //todo: accept value from widget QG_SnapDistOptions if(RS_DIALOGFACTORY != NULL) { RS_DIALOGFACTORY->requestSnapDistOptions(distance, snapMode.snapDistance); } t = snapDist(mouseCoord); double&& ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; snapSpot = t; } } if (snapMode.snapIntersection) { t = snapIntersection(mouseCoord); double&& ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; snapSpot = t; } } if (snapMode.snapOnEntity && snapSpot.distanceTo(mouseCoord) > snapMode.distance) { t = snapOnEntity(mouseCoord); double&& ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; snapSpot = t; } } if (snapMode.snapGrid) { t = snapGrid(mouseCoord); double&& ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; snapSpot = t; } } if( ! snapSpot.valid ) { snapSpot=mouseCoord; //default to snapFree } else { // std::cout<<"mouseCoord.distanceTo(snapSpot)="<<mouseCoord.distanceTo(snapSpot)<<std::endl; // std::cout<<"snapRange="<<snapRange<<std::endl; //retreat to snapFree when distance is more than half grid RS_Vector&& ds=mouseCoord - snapSpot; RS_Vector&& grid=graphicView->getGrid()->getCellVector()*0.5; if( fabs(ds.x) > fabs(grid.x) || fabs(ds.y) > fabs(grid.y) ) snapSpot = mouseCoord; //another choice is to keep snapRange in GUI coordinates instead of graph coordinates // if (mouseCoord.distanceTo(snapSpot) > snapRange ) snapSpot = mouseCoord; } //if (snapSpot.distanceTo(mouseCoord) > snapMode.distance) { // handle snap restrictions that can be activated in addition // to the ones above: //apply restriction RS_Vector rz = graphicView->getRelativeZero(); RS_Vector vpv(rz.x,snapSpot.y); RS_Vector vph(snapSpot.x,rz.y); switch (snapMode.restriction) { case RS2::RestrictOrthogonal: snapCoord= ( mouseCoord.distanceTo(vpv)< mouseCoord.distanceTo(vph))? vpv:vph; break; case RS2::RestrictHorizontal: snapCoord = vph; break; case RS2::RestrictVertical: snapCoord = vpv; break; //case RS2::RestrictNothing: default: snapCoord = snapSpot; break; } //} //else snapCoord = snapSpot; drawSnapper(); if (RS_DIALOGFACTORY!=NULL) { RS_DIALOGFACTORY->updateCoordinateWidget(snapCoord, snapCoord - graphicView->getRelativeZero()); } RS_DEBUG->print("RS_Snapper::snapPoint: OK"); return snapCoord; }
/** * Print a formatted string * * @param fmt Formatted string * @param ap Variable argument * @param vph Print handler * @param arg Handler argument * * @return 0 if success, otherwise errorcode * * Extensions: * * <pre> * %b (char *, size_t) Buffer string with pointer and length * %r (struct pl) Pointer-length object * %w (uint8_t *, size_t) Binary buffer to hexadecimal format * %j (struct sa *) Socket address - address part only * %J (struct sa *) Socket address and port - like 1.2.3.4:1234 * %H (re_printf_h *, void *) Print handler with argument * %v (char *fmt, va_list *) Variable argument list * %m (int) Describe an error code * </pre> * * Reserved for the future: * * %k * %y * */ int re_vhprintf(const char *fmt, va_list ap, re_vprintf_h *vph, void *arg) { uint8_t base, *bptr; char pch, ch, num[NUM_SIZE], addr[64], msg[256]; enum length_modifier lenmod = LENMOD_NONE; struct re_printf pf; bool fm = false, plr = false; const struct pl *pl; size_t pad = 0, fpad = -1, len, i; const char *str, *p = fmt, *p0 = fmt; const struct sa *sa; re_printf_h *ph; void *ph_arg; va_list *apl; int err = 0; void *ptr; uint64_t n; int64_t sn; bool uc = false; double dbl; if (!fmt || !vph) return EINVAL; pf.vph = vph; pf.arg = arg; for (;*p && !err; p++) { if (!fm) { if (*p != '%') continue; pch = ' '; plr = false; pad = 0; fpad = -1; lenmod = LENMOD_NONE; uc = false; if (p > p0) err |= vph(p0, p - p0, arg); fm = true; continue; } fm = false; base = 10; switch (*p) { case '-': plr = true; fm = true; break; case '.': fpad = pad; pad = 0; fm = true; break; case '%': ch = '%'; err |= vph(&ch, 1, arg); break; case 'b': str = va_arg(ap, const char *); len = va_arg(ap, size_t); err |= write_padded(str, str ? len : 0, pad, ' ', plr, NULL, vph, arg); break; case 'c': ch = va_arg(ap, int); err |= write_padded(&ch, 1, pad, ' ', plr, NULL, vph, arg); break; case 'd': case 'i': switch (lenmod) { case LENMOD_SIZE: sn = va_arg(ap, ssize_t); break; default: case LENMOD_LONG_LONG: sn = va_arg(ap, signed long long); break; case LENMOD_LONG: sn = va_arg(ap, signed long); break; case LENMOD_NONE: sn = va_arg(ap, signed); break; } len = local_itoa(num, (sn < 0) ? -sn : sn, base, false); err |= write_padded(num, len, pad, plr ? ' ' : pch, plr, (sn < 0) ? prfx_neg : NULL, vph, arg); break; case 'f': case 'F': dbl = va_arg(ap, double); if (fpad == (size_t)-1) { fpad = pad; pad = 0; } if (isinf(dbl)) { err |= write_padded("inf", 3, fpad, ' ', plr, NULL, vph, arg); } else if (isnan(dbl)) { err |= write_padded("nan", 3, fpad, ' ', plr, NULL, vph, arg); } else { len = local_ftoa(num, dbl, pad ? min(pad, DEC_SIZE) : 6); err |= write_padded(num, len, fpad, plr ? ' ' : pch, plr, (dbl<0) ? prfx_neg : NULL, vph, arg); } break; case 'H': ph = va_arg(ap, re_printf_h *); ph_arg = va_arg(ap, void *); if (ph) err |= ph(&pf, ph_arg); break; case 'l': ++lenmod; fm = true; break; case 'm': str = str_error(va_arg(ap, int), msg, sizeof(msg)); err |= write_padded(str, str_len(str), pad, ' ', plr, NULL, vph, arg); break; case 'p': ptr = va_arg(ap, void *); if (ptr) { len = local_itoa(num, (unsigned long int)ptr, 16, false); err |= write_padded(num, len, pad, plr ? ' ' : pch, plr, prfx_hex, vph, arg); } else { err |= write_padded(str_nil, sizeof(str_nil) - 1, pad, ' ', plr, NULL, vph, arg); } break; case 'r': pl = va_arg(ap, const struct pl *); err |= write_padded(pl ? pl->p : NULL, (pl && pl->p) ? pl->l : 0, pad, ' ', plr, NULL, vph, arg); break; case 's': str = va_arg(ap, const char *); err |= write_padded(str, str_len(str), pad, ' ', plr, NULL, vph, arg); break; case 'X': uc = true; /*@fallthrough@*/ case 'x': base = 16; /*@fallthrough@*/ case 'u': switch (lenmod) { case LENMOD_SIZE: n = va_arg(ap, size_t); break; default: case LENMOD_LONG_LONG: n = va_arg(ap, unsigned long long); break; case LENMOD_LONG: n = va_arg(ap, unsigned long); break; case LENMOD_NONE: n = va_arg(ap, unsigned); break; } len = local_itoa(num, n, base, uc); err |= write_padded(num, len, pad, plr ? ' ' : pch, plr, NULL, vph, arg); break; case 'v': str = va_arg(ap, char *); apl = va_arg(ap, va_list *); if (!str || !apl) break; err |= re_vhprintf(str, *apl, vph, arg); break; case 'W': uc = true; /*@fallthrough@*/ case 'w': bptr = va_arg(ap, uint8_t *); len = va_arg(ap, size_t); len = bptr ? len : 0; pch = plr ? ' ' : pch; while (!plr && pad-- > (len * 2)) err |= vph(&pch, 1, arg); for (i=0; i<len; i++) { const uint8_t v = *bptr++; uint32_t l = local_itoa(num, v, 16, uc); err |= write_padded(num, l, 2, '0', false, NULL, vph, arg); } while (plr && pad-- > (len * 2)) err |= vph(&pch, 1, arg); break; case 'z': lenmod = LENMOD_SIZE; fm = true; break; case 'j': sa = va_arg(ap, struct sa *); if (!sa) break; if (sa_ntop(sa, addr, sizeof(addr))) { err |= write_padded("?", 1, pad, ' ', plr, NULL, vph, arg); break; } err |= write_padded(addr, strlen(addr), pad, ' ', plr, NULL, vph, arg); break; case 'J': sa = va_arg(ap, struct sa *); if (!sa) break; if (sa_ntop(sa, addr, sizeof(addr))) { err |= write_padded("?", 1, pad, ' ', plr, NULL, vph, arg); break; } #ifdef HAVE_INET6 if (AF_INET6 == sa_af(sa)) { ch = '['; err |= vph(&ch, 1, arg); } #endif err |= write_padded(addr, strlen(addr), pad, ' ', plr, NULL, vph, arg); #ifdef HAVE_INET6 if (AF_INET6 == sa_af(sa)) { ch = ']'; err |= vph(&ch, 1, arg); } #endif ch = ':'; err |= vph(&ch, 1, arg); len = local_itoa(num, sa_port(sa), 10, false); err |= write_padded(num, len, pad, plr ? ' ' : pch, plr, NULL, vph, arg); break; default: if (('0' <= *p) && (*p <= '9')) { if (!pad && ('0' == *p)) { pch = '0'; } else { pad *= 10; pad += *p - '0'; } fm = true; break; } ch = '?'; err |= vph(&ch, 1, arg); break; } if (!fm) p0 = p + 1; } if (!fm && p > p0) err |= vph(p0, p - p0, arg); return err; }
/** * Snap to a coordinate in the drawing using the current snap mode. * * @param e A mouse event. * @return The coordinates of the point or an invalid vector. */ RS_Vector RS_Snapper::snapPoint(QMouseEvent* e) { RS_DEBUG->print("RS_Snapper::snapPoint"); pImpData->snapSpot = RS_Vector(false); RS_Vector t(false); if (!e) { RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Snapper::snapPoint: event is nullptr"); return pImpData->snapSpot; } RS_Vector mouseCoord = graphicView->toGraph(e->x(), e->y()); double ds2Min=RS_MAXDOUBLE*RS_MAXDOUBLE; if (snapMode.snapEndpoint) { t = snapEndpoint(mouseCoord); double ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; pImpData->snapSpot = t; } } if (snapMode.snapCenter) { t = snapCenter(mouseCoord); double ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; pImpData->snapSpot = t; } } if (snapMode.snapMiddle) { //this is still brutal force //todo: accept value from widget QG_SnapMiddleOptions if(RS_DIALOGFACTORY ) { RS_DIALOGFACTORY->requestSnapMiddleOptions(middlePoints, snapMode.snapMiddle); } t = snapMiddle(mouseCoord); double ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; pImpData->snapSpot = t; } } if (snapMode.snapDistance) { //this is still brutal force //todo: accept value from widget QG_SnapDistOptions if(RS_DIALOGFACTORY ) { RS_DIALOGFACTORY->requestSnapDistOptions(m_SnapDistance, snapMode.snapDistance); } t = snapDist(mouseCoord); double ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; pImpData->snapSpot = t; } } if (snapMode.snapIntersection) { t = snapIntersection(mouseCoord); double ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; pImpData->snapSpot = t; } } if (snapMode.snapOnEntity && pImpData->snapSpot.distanceTo(mouseCoord) > snapMode.distance) { t = snapOnEntity(mouseCoord); double ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; pImpData->snapSpot = t; } } if (snapMode.snapGrid) { t = snapGrid(mouseCoord); double ds2=mouseCoord.squaredTo(t); if (ds2 < ds2Min){ ds2Min=ds2; pImpData->snapSpot = t; } } if( !pImpData->snapSpot.valid ) { pImpData->snapSpot=mouseCoord; //default to snapFree } else { // std::cout<<"mouseCoord.distanceTo(snapSpot)="<<mouseCoord.distanceTo(snapSpot)<<std::endl; // std::cout<<"snapRange="<<snapRange<<std::endl; //retreat to snapFree when distance is more than half grid if(snapMode.snapFree){ RS_Vector const& ds=mouseCoord - pImpData->snapSpot; RS_Vector const& grid=graphicView->getGrid()->getCellVector()*0.5; if( fabs(ds.x) > fabs(grid.x) || fabs(ds.y) > fabs(grid.y) ) pImpData->snapSpot = mouseCoord; } //another choice is to keep snapRange in GUI coordinates instead of graph coordinates // if (mouseCoord.distanceTo(snapSpot) > snapRange ) snapSpot = mouseCoord; } //if (snapSpot.distanceTo(mouseCoord) > snapMode.distance) { // handle snap restrictions that can be activated in addition // to the ones above: //apply restriction RS_Vector rz = graphicView->getRelativeZero(); RS_Vector vpv(rz.x, pImpData->snapSpot.y); RS_Vector vph(pImpData->snapSpot.x,rz.y); switch (snapMode.restriction) { case RS2::RestrictOrthogonal: pImpData->snapCoord= ( mouseCoord.distanceTo(vpv)< mouseCoord.distanceTo(vph))? vpv:vph; break; case RS2::RestrictHorizontal: pImpData->snapCoord = vph; break; case RS2::RestrictVertical: pImpData->snapCoord = vpv; break; //case RS2::RestrictNothing: default: pImpData->snapCoord = pImpData->snapSpot; break; } //} //else snapCoord = snapSpot; snapPoint(pImpData->snapSpot, false); //If the cursor is too-close to the snapSpot (by number of screen pixels), then hide it. if (graphicView->toGui(pImpData->snapSpot).distanceTo(graphicView->toGui(mouseCoord)) < 32 /* xenoRadius */) { graphicView->setCursor(Qt::BlankCursor); } else { graphicView->setCursor(Qt::CrossCursor); } return pImpData->snapCoord; }