void AdjustControls(SplinePoint *sp) { if ( sp->next!=NULL ) { SplineCharDefaultNextCP(sp); /* also fixes up tangents */ SplineCharDefaultPrevCP(sp->next->to); SplineRefigure(sp->next); if ( sp->next->to->pointtype==pt_tangent && sp->next->to->next!=NULL ) { SplineCharTangentNextCP(sp->next->to); SplineRefigure(sp->next->to->next); } } if ( sp->prev!=NULL ) { SplineCharDefaultPrevCP(sp); SplineCharDefaultNextCP(sp->prev->from); SplineRefigure(sp->prev); if ( sp->prev->from->pointtype==pt_tangent && sp->prev->from->prev!=NULL ) { SplineCharTangentPrevCP(sp->prev->from); SplineRefigure(sp->prev->from->prev); } } }
void SplineSetsRound2Int(SplineSet *spl,real factor, int inspiro, int onlysel) { SplinePoint *sp; for ( ; spl!=NULL; spl=spl->next ) { if ( inspiro ) { } else { for ( sp=spl->first; ; ) { if ( sp->selected || !onlysel ) SplinePointRound(sp,factor); if ( sp->prev!=NULL ) SplineRefigure(sp->prev); if ( sp->next==NULL ) break; sp = sp->next->to; if ( sp==spl->first ) break; } if ( spl->first->prev!=NULL ) SplineRefigure(spl->first->prev); } } }
static void CVMergeSPLS(CharView *cv,SplineSet *ss, SplinePoint *base,SplinePoint *sp) { int order2 = cv->b.layerheads[cv->b.drawmode]->order2; cv->joinvalid = true; cv->joinpos = *sp; cv->joinpos.selected = false; if ( sp->prev!=NULL ) SplineSetReverse(cv->p.spl); if ( sp->prev!=NULL ) IError("Base point not at start of splineset in CVMouseDownPoint"); /* remove the old spl entry from the chain */ if ( cv->p.spl==cv->b.layerheads[cv->b.drawmode]->splines ) cv->b.layerheads[cv->b.drawmode]->splines = cv->p.spl->next; else { SplineSet *temp; for ( temp = cv->b.layerheads[cv->b.drawmode]->splines; temp->next!=cv->p.spl; temp = temp->next ); temp->next = cv->p.spl->next; } if ( order2 && (!RealNear(base->nextcp.x,sp->prevcp.x) || !RealNear(base->nextcp.y,sp->prevcp.y)) ) { base->nonextcp = sp->noprevcp = true; base->nextcp = base->me; sp->prevcp = sp->me; } SplineMake(base,sp,order2); SplineCharDefaultNextCP(base); SplineCharDefaultPrevCP(sp); if ( sp->pointtype==pt_tangent ) { SplineCharTangentNextCP(sp); if ( sp->next ) SplineRefigure(sp->next ); } ss->last = cv->p.spl->last; if ( ss->spiros && cv->p.spl->spiros ) { if ( ss->spiro_cnt+cv->p.spl->spiro_cnt > ss->spiro_max ) ss->spiros = realloc(ss->spiros, (ss->spiro_max = ss->spiro_cnt+cv->p.spl->spiro_cnt)*sizeof(spiro_cp)); memcpy(ss->spiros+ss->spiro_cnt-1, cv->p.spl->spiros+1, (cv->p.spl->spiro_cnt-1)*sizeof(spiro_cp)); ss->spiro_cnt += cv->p.spl->spiro_cnt-2; } else SplineSetSpirosClear(ss); cv->p.spl->last = cv->p.spl->first = NULL; cv->p.spl->spiros = 0; SplinePointListFree(cv->p.spl); cv->p.spl = NULL; }
void CVMouseMovePen(CharView *cv, PressedOn *p, GEvent *event) { SplinePoint *active = cv->active_sp; int order2 = cv->b.layerheads[cv->b.drawmode]->order2; int order2_style = (order2 && !(event->u.mouse.state&ksm_meta)) || (!order2 && (event->u.mouse.state&ksm_meta)); if ( cv->b.sc->inspiro && hasspiro()) { CVMouseMoveSpiroPoint(cv,p); return; } if ( active==NULL ) return; if ( cv->info.x==active->nextcp.x && cv->info.y==active->nextcp.y ) return; /* In order2 fonts when the user clicks with the pen tool we'd like to */ /* leave it with the default cp (ie. the cp which makes the current point*/ /* implicit) rather than moving the cp to the base point and losing the */ /* curve */ if ( cv->info.x==active->me.x && cv->info.y==active->me.y && event->type==et_mouseup && cv->b.layerheads[cv->b.drawmode]->order2 ) return; SplineSetSpirosClear(cv->active_spl); cv->lastselpt = cv->active_sp; active->nextcp.x = cv->info.x; active->nextcp.y = cv->info.y; if ( order2_style && active->next==NULL ) { active->me.x = (active->nextcp.x + active->prevcp.x)/2; active->me.y = (active->nextcp.y + active->prevcp.y)/2; if ( active->me.x == active->nextcp.x && active->me.y == active->nextcp.y ) { active->nonextcp = active->noprevcp = true; } else { active->nonextcp = active->noprevcp = false; active->pointtype = pt_curve; } if ( active->prev!=NULL ) SplineRefigure(active->prev); SCUpdateAll(cv->b.sc); return; } else if ( active->nextcp.x==active->me.x && active->nextcp.y==active->me.y ) { active->prevcp = active->me; active->nonextcp = active->noprevcp = true; active->pointtype = pt_corner; } else { active->prevcp.x = active->me.x - (active->nextcp.x-active->me.x); active->prevcp.y = active->me.y - (active->nextcp.y-active->me.y); active->nonextcp = active->noprevcp = false; active->nextcpdef = active->prevcpdef = false; active->pointtype = pt_curve; } if ( cv->b.layerheads[cv->b.drawmode]->order2 ) { if ( active->prev!=NULL ) { if ( active->noprevcp ) active->prev->from->nonextcp = true; else { active->prev->from->nextcp = active->prevcp; active->prev->from->nonextcp = false; } SplinePointNextCPChanged2(active->prev->from); SplineRefigureFixup(active->prev); } if ( active->next!=NULL ) { if ( active->nonextcp ) active->next->to->noprevcp = true; else { active->next->to->prevcp = active->nextcp; active->next->to->noprevcp = false; } SplineRefigureFixup(active->next); } } else { if ( active->prev!=NULL ) SplineRefigure(active->prev); if ( active->next!=NULL ) SplineRefigure(active->next); } CPUpdateInfo(cv,event); SCUpdateAll(cv->b.sc); }
/* When the user tries to add a point (by doing a mouse down with a point tool selected) there are several cases to be looked at: If there is a single point selected and it is at the begining/end of an open spline set if we clicked on another point which is the begining/end of an open splineset draw a spline connecting the two spline sets and merge them (or if it's the same spline set, then close it) else create a new point where we clicked draw a spline between the selected point and the new one deselect the old point select the new one endif else if they clicked on a spline split the spline into two bits at the point where they clicked else create a new point where they clicked put it on a new splineset select it endif and, if the old point is a tangent, we may need to adjust its control pt With the introduction of spiro mode (Raph Levien's clothoid splines) we've got to worry about all the above cases for spiro points too. */ void CVMouseDownPoint(CharView *cv, GEvent *event) { SplineSet *sel, *ss; SplinePoint *sp, *base = NULL; SplineChar *sc = cv->b.sc; enum pointtype ptype = (cv->active_tool==cvt_curve?pt_curve: cv->active_tool==cvt_hvcurve?pt_hvcurve: cv->active_tool==cvt_corner?pt_corner: cv->active_tool==cvt_tangent?pt_tangent: /*cv->active_tool==cvt_pen?*/pt_corner); int order2 = cv->b.layerheads[cv->b.drawmode]->order2; int order2_style = (order2 && !(event->u.mouse.state&ksm_meta)) || (!order2 && (event->u.mouse.state&ksm_meta)); cv->active_spl = NULL; cv->active_sp = NULL; if ( cv->b.sc->inspiro && hasspiro()) { CVMouseDownSpiroPoint(cv, event); return; } sel = CVAnySelPointList(cv); if ( sel!=NULL ) { if ( sel->first->selected ) base = sel->first; else base = sel->last; if ( base==cv->p.sp ) return; /* We clicked on the active point, that's a no-op */ } CVPreserveState(&cv->b); CVClearSel(cv); if ( sel!=NULL ) { sp = cv->p.sp; cv->lastselpt = base; ss = sel; if ( base->next!=NULL ) SplineSetReverse(sel); if ( base->next!=NULL ) IError("Base point not at end of splineset in CVMouseDownPoint"); if ( sp==NULL || (sp->next!=NULL && sp->prev!=NULL) || sp==base ) { /* Add a new point */ SplineSetSpirosClear(sel); sp = SplinePointCreate( cv->p.cx, cv->p.cy ); sp->noprevcp = sp->nonextcp = 1; sp->nextcpdef = sp->prevcpdef = 1; sp->pointtype = ptype; sp->selected = true; if ( !base->nonextcp && order2_style && cv->active_tool==cvt_pen ) { sp->prevcp = base->nextcp; sp->noprevcp = false; sp->me.x = ( sp->prevcp.x + sp->nextcp.x )/2; sp->me.y = ( sp->prevcp.y + sp->nextcp.y )/2; sp->nonextcp = false; sp->pointtype = pt_curve; } else if ( order2 && !base->nonextcp ) { sp->prevcp = base->nextcp; sp->noprevcp = false; if ( cv->active_tool==cvt_pen ) { sp->nextcp.x = sp->me.x - (sp->prevcp.x-sp->me.x); sp->nextcp.y = sp->me.y - (sp->prevcp.y-sp->me.y); sp->nonextcp = false; sp->pointtype = pt_curve; } } if ( base->nonextcp ) base->nextcpdef = true; SplineMake(base,sp,order2); if ( cv->active_tool!=cvt_pen ) { SplineCharDefaultNextCP(base); SplineCharDefaultPrevCP(sp); } ss->last = sp; } else if ( cv->p.spl==sel ) { /* Close the current spline set */ SplineSetSpirosClear(sel); cv->joinvalid = true; cv->joinpos = *sp; cv->joinpos.selected = false; if ( order2 ) { if ( base->nonextcp || sp->noprevcp ) { base->nonextcp = sp->noprevcp = true; base->nextcp = base->me; sp->prevcp = sp->me; } else { base->nextcp.x = sp->prevcp.x = (base->nextcp.x+sp->prevcp.x)/2; base->nextcp.y = sp->prevcp.y = (base->nextcp.y+sp->prevcp.y)/2; } base->nextcpdef = sp->prevcpdef = true; } SplineMake(base,sp,order2); if ( cv->active_tool!=cvt_pen ) SplineCharDefaultNextCP(base); SplineCharDefaultPrevCP(sp); ss->last = sp; if ( sp->pointtype==pt_tangent ) { SplineCharTangentNextCP(sp); if ( sp->next ) SplineRefigure(sp->next ); } } else { /* Merge two spline sets */ SplineSetSpirosClear(sel); CVMergeSPLS(cv,sel, base,sp); } sp->selected = true; if ( base->pointtype==pt_tangent ) { SplineCharTangentPrevCP(base); if ( base->prev!=NULL ) SplineRefigure(base->prev); } } else if ( cv->p.spline!=NULL ) { sp = SplineBisect(cv->p.spline,cv->p.t); cv->joinvalid = true; cv->joinpos = *sp; cv->joinpos.selected = false; if ( cv->active_tool==cvt_pen ) ptype = pt_curve; sp->pointtype = ptype; if ( ptype==pt_hvcurve ) { SPHVCurveForce(sp); } sp->selected = true; ss = cv->p.spl; } else { ss = chunkalloc(sizeof(SplineSet)); sp = SplinePointCreate( cv->p.cx, cv->p.cy ); ss->first = ss->last = sp; ss->next = cv->b.layerheads[cv->b.drawmode]->splines; cv->b.layerheads[cv->b.drawmode]->splines = ss; sp->nonextcp = sp->noprevcp = 1; sp->nextcpdef = sp->prevcpdef = 1; sp->pointtype = ptype; sp->selected = true; } cv->active_spl = ss; cv->active_sp = sp; CVSetCharChanged(cv,true); CVInfoDraw(cv,cv->gw); SCUpdateAll(sc); if ( cv->active_tool == cvt_pen ) cv->p.constrain = sp->me; }
static void VaryGlyph(SplineChar *sc,int *points, int *xdeltas, int *ydeltas, int pcnt) { /* A character contains either composites or contours */ int i,j; RefChar *ref; SplineSet *ss; SplinePoint *sp; Spline *s, *first; if ( points[0]==ALL_POINTS ) { if ( sc->layers[ly_fore].refs!=NULL ) { for ( i=0, ref=sc->layers[ly_fore].refs; ref!=NULL; ++i, ref=ref->next ) { if ( xdeltas[i]!=0 || ydeltas[i]!=0 ) { ref->transform[4] += xdeltas[i]; ref->transform[5] += ydeltas[i]; SCReinstanciateRefChar(sc,ref,ly_fore); } } } else { for ( ss = sc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) { for ( sp=ss->first; sp!=NULL ; ) { if ( sp->ttfindex!=0xffff && sp->ttfindex!=0xfffe ) { sp->me.x += xdeltas[sp->ttfindex]; sp->me.y += ydeltas[sp->ttfindex]; } if ( sp->nextcpindex!=0xffff && sp->nextcpindex!=0xfffe ) { sp->nextcp.x += xdeltas[sp->nextcpindex]; sp->nextcp.y += ydeltas[sp->nextcpindex]; if ( sp->next!=NULL ) sp->next->to->prevcp = sp->nextcp; } if ( sp->next==NULL ) break; sp = sp->next->to; if ( sp == ss->first ) break; } } } SCShiftAllBy(sc,-xdeltas[pcnt-4],0); SCShiftAllBy(sc,0,-ydeltas[pcnt-2]); sc->width += xdeltas[pcnt-3]; sc->vwidth += ydeltas[pcnt-1]; } else { j = 0; if ( sc->layers[ly_fore].refs!=NULL ) { for ( i=0, ref=sc->layers[ly_fore].refs; ref!=NULL; ++i, ref=ref->next ) { if ( points[j]==i ) { if ( xdeltas[j]!=0 || ydeltas[j]!=0 ) { ref->transform[4] += xdeltas[j]; ref->transform[5] += ydeltas[j]; SCReinstanciateRefChar(sc,ref,ly_fore); } ++j; } } } else { for ( i=0, ss = sc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) { if ( ss->first->prev!=NULL && ss->first->prev->from->nextcpindex==points[j] ) { ss->first->prevcp.x += xdeltas[j]; ss->first->prevcp.y += ydeltas[j]; ss->first->prev->from->nextcp = ss->first->prevcp; ++j; } for ( sp=ss->first; sp!=NULL ; ++i ) { if ( sp->ttfindex!=0xffff && sp->ttfindex!=0xfffe ) ++i; if ( sp->ttfindex==points[j] ) { sp->me.x += xdeltas[j]; sp->me.y += ydeltas[j++]; } if ( sp->nextcpindex!=0xffff && sp->nextcpindex!=0xfffe ) ++i; if ( sp->nextcpindex==points[j] ) { sp->nextcp.x += xdeltas[j]; sp->nextcp.y += ydeltas[j++]; if ( sp->next!=NULL ) sp->next->to->prevcp = sp->nextcp; } else if ( sp->nonextcp ) { sp->nextcp = sp->me; } if ( sp->next==NULL ) break; sp = sp->next->to; if ( sp == ss->first ) break; } first = NULL; } } if ( points[j]==i ) SCShiftAllBy(sc,-xdeltas[j++],0); if ( points[j]==i+1 ) sc->width += xdeltas[j++]; if ( points[j]==i+2 ) SCShiftAllBy(sc,0,-ydeltas[j++]); if ( points[j]==i+3 ) sc->vwidth += ydeltas[j++]; } if ( sc->layers[ly_fore].refs==NULL ) { for ( ss = sc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) { for ( sp=ss->first; sp!=NULL ; ++i ) { if ( sp->ttfindex==0xffff ) { sp->me.x = ( sp->nextcp.x + sp->prevcp.x )/2; sp->me.y = ( sp->nextcp.y + sp->prevcp.y )/2; } if ( sp->next==NULL ) break; sp = sp->next->to; if ( sp == ss->first ) break; } first = NULL; for ( s=ss->first->next; s!=NULL && s!=first; s=s->to->next ) { SplineRefigure(s); if ( first==NULL ) first = s; } } } }
static void RH_MovePoints(ReviewHintData *hd,StemInfo *active,int start,int width) { SplineChar *sc = hd->cv->b.sc; SplineSet *spl; SplinePoint *sp; int which; int layer = CVLayer( (CharViewBase *) (hd->cv)); if ( !hd->undocreated ) { SCPreserveLayer(sc,layer,true); hd->undocreated = true; } for ( spl=sc->layers[layer].splines; spl!=NULL; spl=spl->next ) { for ( sp = spl->first ; ; ) { if ( hd->ishstem ) { switch ((which = OnHint(active,sp->me.y,sp->me.x)) ) { case 1: sp->nextcp.y += start-sp->me.y; sp->prevcp.y += start-sp->me.y; sp->me.y = start; break; case 2: sp->nextcp.y += start+width-sp->me.y; sp->prevcp.y += start+width-sp->me.y; sp->me.y = start+width; break; case 0: /* Not on hint */; break; } } else { switch ( (which = OnHint(active,sp->me.x,sp->me.y)) ) { case 1: sp->nextcp.x += start-sp->me.x; sp->prevcp.x += start-sp->me.x; sp->me.x = start; break; case 2: sp->nextcp.x += start+width-sp->me.x; sp->prevcp.x += start+width-sp->me.x; sp->me.x = start+width; break; case 0: /* Not on hint */; break; } } if ( which ) { if ( sp->prev ) SplineRefigure(sp->prev); if ( sp->next ) SplineRefigure(sp->next); } if ( sp->next==NULL ) break; sp = sp->next->to; if ( sp== spl->first ) break; } } }