static void CVMouseMoveSpiroPoint(CharView *cv, PressedOn *p) { spiro_cp *active = cv->active_cp, *merge = p->spiro; SplineSet *activess = cv->active_spl; int active_index; if ( active==NULL ) return; if ( cv->info.x==active->x && cv->info.y==active->y ) return; if ( !cv->recentchange ) CVPreserveState(&cv->b); active->x = cv->info.x; active->y = cv->info.y; CVSetCharChanged(cv,true); active_index = active-activess->spiros; if ( active!=merge && merge!=NULL && p->spl!=NULL && SPIRO_SPL_OPEN(activess) && SPIRO_SPL_OPEN(p->spl) && (active_index==0 || active_index==activess->spiro_cnt-2) && ((merge-p->spl->spiros)==0 || (merge-p->spl->spiros)==p->spl->spiro_cnt-2) ) { SplinePoint *activesp = active_index==0 ? activess->first : activess->last; SplinePoint *mergesp = (merge-p->spl->spiros)==0 ? p->spl->first : p->spl->last; CVMergeSplineSets(cv,activesp,activess,mergesp,p->spl); } SSRegenerateFromSpiros(activess); SCUpdateAll(cv->b.sc); }
/* spline set... */ void CVMouseMovePoint(CharView *cv, PressedOn *p) { SplinePoint *active = cv->active_sp, *merge = p->sp; SplineSet *activess = cv->active_spl; if ( cv->b.sc->inspiro && hasspiro()) { CVMouseMoveSpiroPoint(cv,p); return; } if ( active==NULL ) return; if ( cv->info.x==active->me.x && cv->info.y==active->me.y ) return; if ( !cv->recentchange ) CVPreserveState(&cv->b); CVAdjustPoint(cv,active); SplineSetSpirosClear(activess); if (( active->next==NULL || active->prev==NULL ) && merge!=NULL && p->spl!=NULL && merge!=active && (merge->next==NULL || merge->prev==NULL )) { CVMergeSplineSets(cv,active,activess,merge,p->spl); } SCUpdateAll(cv->b.sc); }
static void Do_OKRegen(ReviewHintData *hd) { SplineChar *sc = hd->cv->b.sc; StemInfo *curh = sc->hstem, *curv = sc->vstem; int do_regen = GGadgetIsChecked(GWidgetGetControl(hd->gw,CID_RegenHM)); /* We go backwards here, but not for long. The point is to go back to */ /* the original hint state so we can preserve it, now that we know we*/ /* are going to modify it */ sc->hstem = hd->oldh; sc->vstem = hd->oldv; SCPreserveHints(sc,CVLayer((CharViewBase *) hd->cv)); sc->hstem = curh; sc->vstem = curv; StemInfosFree(hd->oldh); StemInfosFree(hd->oldv); if ( hd->lastactive!=NULL ) hd->lastactive->active = false; if ( hd->changed ) { SCClearHintMasks(hd->cv->b.sc,CVLayer((CharViewBase *) (hd->cv)),true); if ( do_regen ) SCFigureHintMasks(hd->cv->b.sc,CVLayer((CharViewBase *) (hd->cv))); } /* Everything else got done as we went along... */ SCOutOfDateBackground(hd->cv->b.sc); SCUpdateAll(hd->cv->b.sc); SCHintsChanged(hd->cv->b.sc); hd->done = true; }
void CVMouseUpTransform(CharView *cv) { if ( cv->info.x == cv->p.cx && cv->info.y == cv->p.cy ) { /* Nothing happened */ cv->needsrasterize = cv->recentchange = false; CVRemoveTopUndo(&cv->b); SCUpdateAll(cv->b.sc); } else CVUndoCleanup(cv); }
static void SVSelectSC(SearchView *sv) { SplineChar *sc = sv->sd.curchar; SplinePointList *spl; SplinePoint *sp; RefChar *rf; int i; int layer = sv->sd.fv->active_layer; /* Deselect all */; for ( spl = sc->layers[layer].splines; spl!=NULL; spl = spl->next ) { for ( sp=spl->first ;; ) { sp->selected = false; if ( sp->next == NULL ) break; sp = sp->next->to; if ( sp==spl->first ) break; } } for ( rf=sc->layers[layer].refs; rf!=NULL; rf = rf->next ) if ( rf->selected ) rf->selected = false; if ( sv->sd.subpatternsearch ) { spl = sv->sd.matched_spl; for ( sp = sv->sd.matched_sp; ; ) { sp->selected = true; if ( sp->next == NULL || sv->sd.last_sp==NULL || sp==sv->sd.last_sp ) break; sp = sp->next->to; /* Ok to wrap back to first */ } } else { for ( rf=sc->layers[layer].refs, i=0; rf!=NULL; rf=rf->next, ++i ) if ( sv->sd.matched_refs&(1<<i) ) rf->selected = true; for ( spl = sc->layers[layer].splines,i=0; spl!=NULL; spl = spl->next, ++i ) { if ( sv->sd.matched_ss&(1<<i) ) { for ( sp=spl->first ;; ) { sp->selected = true; if ( sp->next == NULL ) break; sp = sp->next->to; if ( sp==spl->first ) break; } } } } SCUpdateAll(sc); sc->changed_since_search = false; }
static void DoCancel(ReviewHintData *hd) { StemInfosFree(hd->cv->b.sc->hstem); StemInfosFree(hd->cv->b.sc->vstem); hd->cv->b.sc->hstem = hd->oldh; hd->cv->b.sc->vstem = hd->oldv; hd->cv->b.sc->hconflicts = StemListAnyConflicts(hd->cv->b.sc->hstem); hd->cv->b.sc->vconflicts = StemListAnyConflicts(hd->cv->b.sc->vstem); hd->cv->b.sc->manualhints = hd->oldmanual; if ( hd->undocreated ) SCDoUndo(hd->cv->b.sc,ly_fore); SCOutOfDateBackground(hd->cv->b.sc); SCUpdateAll(hd->cv->b.sc); hd->done = true; }
static void RH_SetupHint(ReviewHintData *hd) { char buffer[20]; unichar_t ubuf[20]; static unichar_t nullstr[] = {'\0'}; StemInfo *h; int pos,cnt; if ( hd->lastactive!=NULL ) hd->lastactive->active = false; pos = cnt = 0; for ( h=hd->ishstem ? hd->cv->b.sc->hstem : hd->cv->b.sc->vstem; h!=NULL; h=h->next ) { ++cnt; if ( h==hd->active ) pos=cnt; } sprintf( buffer,"%d/%d", pos, cnt ); if ( cnt==3 ) { StemInfo *h2, *h3; h = hd->ishstem ? hd->cv->b.sc->hstem : hd->cv->b.sc->vstem; h2 = h->next; h3 = h2->next; if ( h->width == h2->width && h2->width==h3->width && h2->start-h->start == h3->start-h2->start ) strcat( buffer, hd->ishstem ? " hstem3" : " vstem3" ); } uc_strcpy(ubuf,buffer); GGadgetSetTitle(GWidgetGetControl(hd->gw,CID_Count),ubuf); if ( hd->active==NULL ) { GGadgetSetTitle(GWidgetGetControl(hd->gw,CID_Base),nullstr); GGadgetSetTitle(GWidgetGetControl(hd->gw,CID_Width),nullstr); GGadgetSetVisible(GWidgetGetControl(hd->gw,CID_Overlap),false); } else { hd->active->active = true; sprintf( buffer,"%g", (double) (!hd->active->ghost ? hd->active->start : hd->active->start+hd->active->width) ); uc_strcpy(ubuf,buffer); GGadgetSetTitle(GWidgetGetControl(hd->gw,CID_Base),ubuf); GTextFieldShow(GWidgetGetControl(hd->gw,CID_Base),0); sprintf( buffer,"%g", (double) (!hd->active->ghost ? hd->active->width : -hd->active->width) ); uc_strcpy(ubuf,buffer); GGadgetSetTitle(GWidgetGetControl(hd->gw,CID_Width),ubuf); GTextFieldShow(GWidgetGetControl(hd->gw,CID_Width),0); GGadgetSetVisible(GWidgetGetControl(hd->gw,CID_Overlap),hd->active->hasconflicts); } if ( hd->lastactive!=hd->active ) { hd->lastactive = hd->active; SCOutOfDateBackground(hd->cv->b.sc); SCUpdateAll(hd->cv->b.sc); /* Changing the active Hint means we should redraw everything */ } RH_SetNextPrev(hd); }
/* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pfaeditui.h" #include <math.h> #if defined(KNIFE_CONTINUOUS) /* Use this code to do cuts as we move along. Probably a bad idea, let's wait till the end */ static void ProcessKnife(CharView *cv, PressedOn *p) { real dx, dy; SplinePoint *n; /* If we've already made a cut, don't make another cut too close to it */ /* ie. if the hand shakes over a cut let's not get about six tiny cut */ /* segments adjacent to one another */ if ( (dx=cv->info.x-cv->lastknife.x)<0 ) dx=-dx; if ( (dy=cv->info.y-cv->lastknife.y)<0 ) dy=-dy; if ( (dx+dy)/cv->scale <= 6 ) return; if ( p->sp==NULL && p->spline==NULL ) return; /* Nothing to cut */ if ( p->spline!=NULL ) p->sp = SplineBisect(p->spline,p->t); if ( p->spl==NULL ) /* Kanou says this can happen. It doesn't hurt to check for it */ return; if ( p->spl->first!=p->spl->last ) if ( p->sp==p->spl->first || p->sp==p->spl->last ) return; /* Already cut here */ n = chunkalloc(sizeof(SplinePoint)); p->sp->pointtype = pt_corner; *n = *p->sp; n->hintmask = NULL; p->sp->next = NULL; n->prev = NULL; n->next->from = n; if ( p->spl->first==p->spl->last ) { p->spl->first = n; p->spl->last = p->sp; } else { SplinePointList *nspl = chunkalloc(sizeof(SplinePointList)); nspl->next = p->spl->next; p->spl->next = nspl; nspl->first = n; nspl->last = p->spl->last; p->spl->last = p->sp; } cv->lastknife.x = cv->info.x; cv->lastknife.y = cv->info.y; CVSetCharChanged(cv,true); SCUpdateAll(cv->b.sc); }
static int RH_TextChanged(GGadget *g, GEvent *e) { int wasconflict; if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) { ReviewHintData *hd = GDrawGetUserData(GGadgetGetWindow(g)); if ( hd->active!=NULL ) { int cid = GGadgetGetCid(g); int err=0; real start = GetCalmReal8(hd->gw,CID_Base,_("Base:"),&err); real width = GetCalmReal8(hd->gw,CID_Width,_("Size:"),&err); if ( err ) return( true ); if ( GGadgetIsChecked(GWidgetGetControl(GGadgetGetWindow(g),CID_MovePoints)) ) { if ( width<0 ) RH_MovePoints(hd,hd->active,start+width,-width); else RH_MovePoints(hd,hd->active,start,width); } if ( cid==CID_Base ) hd->active->start = start; else hd->active->width = width; if ( width<0 ) { hd->active->ghost = true; hd->active->width = -width; hd->active->start = start+width; } else hd->active->ghost = false; wasconflict = hd->active->hasconflicts; if ( hd->ishstem ) hd->cv->b.sc->hconflicts = StemListAnyConflicts(hd->cv->b.sc->hstem); else hd->cv->b.sc->vconflicts = StemListAnyConflicts(hd->cv->b.sc->vstem); hd->cv->b.sc->manualhints = true; hd->changed = true; if ( wasconflict!=hd->active->hasconflicts ) { GGadgetSetVisible(GWidgetGetControl(hd->gw,CID_Overlap),hd->active->hasconflicts); if ( hd->active->hasconflicts ) GHVBoxFitWindow(GWidgetGetControl(hd->gw,CID_TopBox)); } SCOutOfDateBackground(hd->cv->b.sc); SCUpdateAll(hd->cv->b.sc); } } return( true ); }
static int CH_OK(GGadget *g, GEvent *e) { if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) { CreateHintData *hd = GDrawGetUserData(GGadgetGetWindow(g)); real base, width; int err = 0; StemInfo *h; int layer = CVLayer((CharViewBase *) hd->cv); base = GetReal8(hd->gw,CID_Base,_("Base:"),&err); width = GetReal8(hd->gw,CID_Width,_("Size:"),&err); if ( err ) return(true); if ( hd->preservehints ) { SCPreserveHints(hd->cv->b.sc,layer); SCHintsChanged(hd->cv->b.sc); } h = chunkalloc(sizeof(StemInfo)); if ( width==-21 || width==-20 ) { base += width; width = -width; h->ghost = true; } h->start = base; h->width = width; if ( hd->ishstem ) { SCGuessHHintInstancesAndAdd(hd->cv->b.sc,layer,h,0x80000000,0x80000000); hd->cv->b.sc->hconflicts = StemListAnyConflicts(hd->cv->b.sc->hstem); } else { SCGuessVHintInstancesAndAdd(hd->cv->b.sc,layer,h,0x80000000,0x80000000); hd->cv->b.sc->vconflicts = StemListAnyConflicts(hd->cv->b.sc->vstem); } hd->cv->b.sc->manualhints = true; if ( h!=NULL && hd->cv->b.sc->parent->mm==NULL ) SCModifyHintMasksAdd(hd->cv->b.sc,layer,h); else SCClearHintMasks(hd->cv->b.sc,layer,true); SCOutOfDateBackground(hd->cv->b.sc); SCUpdateAll(hd->cv->b.sc); hd->done = true; } return( true ); }
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 CVMouseDownSpiroPoint(CharView *cv, GEvent *event) { SplineSet *sel, *ss; SplineChar *sc = cv->b.sc; spiro_cp *base, *cp; int base_index, cp_index, i; char ty = (cv->active_tool==cvt_curve?SPIRO_G4: cv->active_tool==cvt_hvcurve?SPIRO_G2: cv->active_tool==cvt_corner?SPIRO_CORNER: cv->active_tool==cvt_tangent?SPIRO_LEFT: /*cv->active_tool==cvt_pen?*/SPIRO_RIGHT); cv->active_spl = NULL; cv->active_sp = NULL; sel = CVAnySelPointList(cv); if ( sel!=NULL ) { if ( SPIRO_SELECTED(&sel->spiros[0]) ) base_index = 0; else base_index = sel->spiro_cnt-2; base = &sel->spiros[base_index]; if ( base==cv->p.spiro ) return; /* We clicked on the active point, that's a no-op */ } CVPreserveState(&cv->b); CVClearSel(cv); if ( sel!=NULL ) { if ( (cp = cv->p.spiro)!=NULL ) cp_index = cp-cv->p.spl->spiros; cv->lastselcp = base; ss = sel; if ( base_index!=sel->spiro_cnt-2 ) { SplineSetReverse(sel); base = &sel->spiros[sel->spiro_cnt-2]; if ( cv->p.spl==sel ) { cp_index = sel->spiro_cnt-2-cp_index; cp = &sel->spiros[cp_index]; } } if ( cp==NULL || (cp_index!=0 && cp_index!=cv->p.spl->spiro_cnt-2) || cp==base || !SPIRO_SPL_OPEN(cv->p.spl)) { /* Add a new point */ if ( sel->spiro_cnt>=sel->spiro_max ) sel->spiros = realloc(sel->spiros,(sel->spiro_max += 10)*sizeof(spiro_cp)); cp = &sel->spiros[sel->spiro_cnt-1]; cp[1] = cp[0]; /* Move the final 'z' */ cp->x = cv->p.cx; cp->y = cv->p.cy; cp->ty = ty; SPIRO_DESELECT(cp-1); ++sel->spiro_cnt; } else if ( cv->p.spl==sel ) { /* Close the current spline set */ sel->spiros[0].ty = ty; cv->joinvalid = true; cv->joincp = *cp; SPIRO_DESELECT(&cv->joincp); } else { /* Merge two spline sets */ SplinePoint *sp = cp_index==0 ? cv->p.spl->first : cv->p.spl->last; SplinePoint *basesp = base_index==0 ? sel->first : sel->last; cv->joincp = *cp; SPIRO_DESELECT(&cv->joincp); CVMergeSPLS(cv,ss,basesp,sp); } } else if ( cv->p.spline!=NULL ) { /* Add an intermediate point on an already existing spline */ ss = cv->p.spl; if ( ss->spiro_cnt>=ss->spiro_max ) ss->spiros = realloc(ss->spiros,(ss->spiro_max += 10)*sizeof(spiro_cp)); for ( i=ss->spiro_cnt-1; i>cv->p.spiro_index; --i ) ss->spiros[i+1] = ss->spiros[i]; ++ss->spiro_cnt; cp = &ss->spiros[cv->p.spiro_index+1]; cp->x = cv->p.cx; cp->y = cv->p.cy; cp->ty = ty; ss = cv->p.spl; cv->joinvalid = true; cv->joincp = *cp; SPIRO_DESELECT(&cv->joincp); } else { /* A new point on a new (open) contour */ ss = chunkalloc(sizeof(SplineSet)); ss->next = cv->b.layerheads[cv->b.drawmode]->splines; cv->b.layerheads[cv->b.drawmode]->splines = ss; ss->spiros = malloc((ss->spiro_max=10)*sizeof(spiro_cp)); cp = &ss->spiros[0]; cp->x = cv->p.cx; cp->y = cv->p.cy; cp->ty = SPIRO_OPEN_CONTOUR; cp[1].x = cp[1].y = 0; cp[1].ty = 'z'; ss->spiro_cnt = 2; } SPIRO_SELECT(cp); SSRegenerateFromSpiros(ss); cv->active_spl = ss; cv->active_cp = cp; CVSetCharChanged(cv,true); CVInfoDraw(cv,cv->gw); SCUpdateAll(sc); }
void CVMouseMoveTransform(CharView *cv) { real transform[6]; CVRestoreTOriginalState(cv); if ( cv->info.x != cv->p.cx || cv->info.y != cv->p.cy ) { transform[0] = transform[3] = 1; transform[1] = transform[2] = 0; switch ( cv->active_tool ) { case cvt_rotate: { real angle = atan2(cv->info.y-cv->p.cy,cv->info.x-cv->p.cx); transform[0] = transform[3] = cos(angle); transform[2] = -(transform[1] = sin(angle)); } break; case cvt_flip: { real dx,dy; if (( dx = cv->info.x-cv->p.cx)<0 ) dx=-dx; if (( dy = cv->info.y-cv->p.cy)<0 ) dy=-dy; if ( dy>2*dx ) transform[0] = -1; else if ( dx>2*dy ) transform[3] = -1; else if ( (cv->info.x-cv->p.cx)*(cv->info.y-cv->p.cy)>0 ) { transform[0] = transform[3] = 0; transform[1] = transform[2] = -1; } else { transform[0] = transform[3] = 0; transform[1] = transform[2] = 1; } } break; case cvt_scale: { transform[0] = 1.0+(cv->info.x-cv->p.cx)/(400*cv->scale); transform[3] = 1.0+(cv->info.y-cv->p.cy)/(400*cv->scale); } break; case cvt_skew: { real angle = atan2(cv->info.y-cv->p.cy,cv->info.x-cv->p.cx); transform[2] = sin(angle); } break; case cvt_3d_rotate: { real angle = atan2(cv->info.y-cv->p.cy,cv->info.x-cv->p.cx); /* Allow one pixel per degree */ real zangle = sqrt( (cv->info.x-cv->p.cx)*(cv->info.x-cv->p.cx) + (cv->info.y-cv->p.cy)*(cv->info.y-cv->p.cy) ) * cv->scale * 3.1415926535897932/180; real s = sin(angle), c = cos(angle); real cz = cos(zangle); transform[0] = c*c + s*s*cz; transform[3] = s*s + c*c*cz; transform[2] = transform[1] = c*s * (cz-1); } break; /* Perspective takes three points: origin, start point, cur point */ /* first rotate so that orig/start are the x axis */ /* then define perspective so that: */ /* y' = y */ /* x' = cur.x + (cur.y - y)/cur.y * (x - cur.x) */ /* then rotate back */ case cvt_perspective: { real angle = atan2(cv->p.cy,cv->p.cx); real s = sin(angle), c = cos(angle); transform[0] = transform[3] = c; transform[2] = -(transform[1] = -s); transform[4] = transform[5] = 0; CVTransFunc(cv,transform,false); CVYPerspective((CharViewBase *) cv, c*cv->info.x + s*cv->info.y, -s*cv->info.x + c*cv->info.y); transform[2] = -(transform[1] = s); } break; default: break; } /* Make the pressed point be the center of the transformation */ if ( cv->active_tool!=cvt_perspective ) { transform[4] = -cv->p.cx*transform[0] - cv->p.cy*transform[2] + cv->p.cx; transform[5] = -cv->p.cy*transform[3] - cv->p.cx*transform[1] + cv->p.cy; } CVSetCharChanged(cv,true); CVTransFunc(cv,transform,false); } SCUpdateAll(cv->b.sc); }