3 // Copyright (C) INRIA - METALAU Project <scicos@inria.fr>
4 // - Alan Layec <alan.layec@inria.fr>
5 // - Simone Mannori <simone.mannori@scilab.org>
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 // See the file ../license.txt
24 function [scs_m, needcompile] = getlink(%pt, scs_m, needcompile,smart)
25 //** Edition of a link from an output block to an input block
27 //** 28/11/08: Preparation of the "SL" operation
28 //** 24/07/07: Al@n's patch for rotation of blocks
30 //** N.B : Please set %scicos_debug_gr="%t" to activate the debug mode
31 //** BEWARE: "d9" state is not yet tested after Replot removal
32 if argn(2)<4 then smart=%f,end
35 //----------- get link origin --------------------------------------
36 //------------------------------------------------------------------
41 [kfrom, wh] = getblocklink(scs_m,[xc1;yc1]); //** recover information
42 //** about the starting point
43 //** kfrom is the id of the selected block or link
45 if kfrom<>[] then //** check for the presence of a valid output
46 o1 = scs_m.objs(kfrom) ; //** acquire the object
48 return ; //** EXIT if no valid output is found
53 nc_save = needcompile;
56 gh_curwin = scf(%win) ;
57 gh_axes = gca(); //** acquire the current window handler
60 if typeof(o1)=="Link" then //** add a split block
61 //** ------------------- start from a LINK ------------------------------
63 [xx,yy,ct,from,to] = (o1.xx,o1.yy,o1.ct,o1.from,o1.to);
64 if (-wh==size(xx,'*')) then
65 wh = -(wh+1) //** avoid with clicking at the end-point of link
69 [xout,yout,typout] = getoutputports(scs_m.objs(from(1)));
71 [m,kp1] = mini((yc1-yout)^2+(xc1-xout)^2);
75 if typo==-1 then //** old link comes from an event output port
77 else //** old link comes from an regular output or input (implicit) port
78 typp = outin(from(3)+1)
82 szout = getportsiz(scs_m.objs(from(1)),from(2),typp)
83 //** get port data type
84 if typp=='out'|typp=='in' then
85 szouttyp = getporttyp(scs_m.objs(from(1)),from(2),typp)
88 //** get initial split position
91 d = projaff(xx(wh:wh+1), yy(wh:wh+1),pt)
96 // Note : creation of the split block and modifications of links are
97 // done later, the sequel assumes that the split block is added
98 // at the end of scs_m
99 ks = kfrom; // selected link number
100 kfrom = size(scs_m.objs)+1;
101 port_number = 2; // to be created split block number
104 // to be created link from origin
106 from = [kfrom,port_number,0]
110 else // connection comes from a block
111 //** ------------------- start from a BLOCK ------------------------------
112 graphics1 = o1.graphics
113 orig = graphics1.orig
115 theta = graphics1.theta
119 cop = graphics1.peout
120 [xout,yout,typout] = getoutputports(o1)
122 i_ImplIndx = find(graphics1.in_implicit=='I');
126 message("This block has no output port");
131 //** geometrical conversion for rotated block
132 xxx = rotate([xout;yout],...
134 [orig(1)+sz(1)/2; orig(2)+sz(2)/2]);
138 [m,kp1] = mini((yc1-yout)^2+(xc1-xout)^2) ;
140 xo = xout(k); yo = yout(k);
143 //** ---------------------- Checking -------------------------------------------
144 //** Check if the new requested link creation is compatible with the diagram
145 // Check if selected port is already connected and get port type ('in' or 'out')
147 if typo==1 then // regular output port
149 if op(port_number)<>0 then
151 message(["Selected port is already connected.";..
152 "To start a link off another link, place the cursor";..
153 "on the split point and double click, or type l."])
158 elseif (typo==2 & k<=size(op,'*')) then // implicit output port
160 if op(port_number)<>0 then
162 message(["Selected port is already connected.";..
163 "To start a link off another link, place the cursor";..
164 "on the split point and double click, or type l."])
169 elseif (typo==2 & k>size(op,'*')+size(cop,'*')) then // implicit input port
171 k = k-size(op,'*')-size(cop,'*');
172 port_number = i_ImplIndx(k)
173 if impi(port_number)<>0 then
175 message(["Selected port is already connected.";..
176 "To start a link off another link, place the cursor";..
177 "on the split point and double click, or type l."])
178 unhilite_obj(kfrom) ;
182 else // event output port
183 port_number = k - size(op,'*') ;
184 if cop(port_number)<>0 then
186 message(["Selected port is already connected.";..
187 "To start a link off another link, place the cursor";..
188 "on the split point and double click, or type l."])
192 typpfrom = 'evtout' ;
195 clr = default_color(typo) ;
198 szout=getportsiz(o1,port_number,typpfrom)
199 // get port data type
200 if typpfrom=='out'|typpfrom=='in' then
201 szouttyp = getporttyp(o1,port_number,typpfrom);
204 // to be created link from origin
205 from = [kfrom,port_number, bool2s(typpfrom=='in'|typpfrom=='evtin')] ;
210 //** ---------------------- Checking Ends ----------------------------------------
212 //----------- get link path ----------------------------------------
213 //------------------------------------------------------------------
215 drawlater(); //** draw later mode
217 //** These indexes will be used to destroy the intermediate objects created below
218 //** during the "interactive" section
220 o_size = size(gh_axes.children) ; //** o_size(1) is the number of compound object
223 //** there are two nested infinite while(%t) loops:
224 //** the outher loop control the sequence of segment
225 //** the inner loop handle the interactive operation on the single link segment
227 while %t do // loop on link segments
228 xe = xo; ye = yo ; //** o > origin ---- e > end
229 //** the first step is the the creation of a dummy graphic object (a link of ZERO leght)
230 //** and store this handler to modify it later
231 xpoly([xo;xe] , [yo;ye], 'lines') ; //** create the first 'dummy' object
232 gh_link = gh_axes.children(1) ; //** the last object is the above link :)
234 rep(3) = -1; //** initialization (as Claudio Macchiavelli has teached me :) )
235 while %t do //** infinite loop
237 //** for positive event exit from the loop
238 //** Any event on the [right] button OR a window closing => END the inner loop
239 if or(rep(3)==[0,2,3,5,-5,-1000]) then
243 //** otherwise ... get a new point
245 //** mouse event queque is cleared (15 Mar 2007 bugfix)
246 rep = xgetmouse([%t, %t]) ; //** looks better :)
249 //** focus has changed OR active window has been closed
250 if gh_figure.figure_id<>curwin | rep(3)==-1000 then
251 [%win, Cmenu] = resume(curwin,'Quit');
254 //** any rigth mouse event OR [Esc] OR [d] key : I want to disengage the current Link action
255 if or(rep(3)==[2 5 12 27 100]) then
256 p_size = size(gh_axes.children);
257 d_size = p_size(1)-o_size(1);
259 gh_compound_delete = glue(gh_axes.children(1:d_size) );
260 delete (gh_compound_delete); //** delete the object
261 drawnow(); //** update the screen
264 if %scicos_debug_gr then
265 disp("d1"); //** Debug
267 return; //** -----> Exit from the function
270 //plot new position of last link segment
271 xe = rep(1); ye = rep(2) ;
272 gh_link.data = [xo yo ; xe ye ] ; //** put the coordinate here
273 gh_link.foreground = clr //** put the color here ( 5 = red )
274 drawnow(); //** update the buffer
276 //** ----------------- end of last segment while loop ------------------------------
278 if %scicos_debug_gr then
279 disp("-->"); //** debug only
282 //** ---------- YOU ARE STILL IN THE "Link" Block-to-Block MAIN LOOP ----------------
283 //** The last segment end with [xe ye] coordinate:
285 //** look for a block with a valid (good) input
287 kto = getblock(scs_m,[xe;ye]) ;
288 if kto<>[] then // new point designs the "to block"
289 o2 = scs_m.objs(kto);
290 graphics2 = o2.graphics;
291 orig = graphics2.orig
293 theta = graphics2.theta
295 impo = graphics2.pout
297 [xin,yin,typin] = getinputports(o2)
299 o_ImplIndx = find(graphics2.out_implicit=='I');
301 //** check connection
304 message("This block has no input port.");
305 p_size = size(gh_axes.children);
306 d_size = p_size(1) - o_size(1);
308 gh_compound_delete = glue(gh_axes.children(1:d_size));
309 delete (gh_compound_delete); //** delete the object
311 if %scicos_debug_gr then
312 disp("d2"); //** Debug
315 drawnow(); //** update the diagram
316 return; //** EXIT point : link failed !
319 //** Connection is OK : compensate for block's rotation
321 xxx = rotate([xin;yin],...
323 [orig(1)+sz(1)/2;orig(2)+sz(2)/2]);
324 xin = xxx(1,:); yin = xxx(2,:);
325 [m,kp2] = mini((ye-yin)^2+(xe-xin)^2);
327 xc2 = xin(k); yc2 = yin(k);
330 //** check connection for "type"
333 message(["Selected ports don''t have the same type"
334 "The port at the origin of the link has type "+string(typo);
335 "the port at the end has type "+string(typin(k))+'.'])
336 p_size = size(gh_axes.children)
337 d_size = p_size(1)-o_size(1);
339 gh_compound_delete = glue(gh_axes.children(1:d_size));
340 delete (gh_compound_delete); //** delete the object
342 if %scicos_debug_gr then
343 disp("d3"); //** Debug
347 return; //** EXIT point from the function
350 //** check if is a normal regular input port (not an event input port)
351 if typi==1 then // regular input port
353 if ip(port_number)<>0 then
355 message(["Selected port is already connected.";..
356 "To start a link off another link, place the cursor";..
357 "on the split point and double click, or type l."]),
358 p_size = size(gh_axes.children);
359 d_size = p_size(1)-o_size(1);
361 gh_compound_delete = glue(gh_axes.children(1:d_size) );
362 delete (gh_compound_delete); //** delete the object
364 if %scicos_debug_gr then
365 disp("d4");//** Debug
373 szin = getportsiz(o2,port_number,'in')
375 //** further check for warning message about "size"
376 need_warning = %f ; //** flag initialization
377 if (szin(1)<>szout(1)) & mini([szin(1) szout(1)])>0 then
381 // check for different number of dimension
382 szout2 = []; szin2 = [];
383 if size(szout,'*')==1 then
389 if size(szin,'*')==1 then
395 if (szin2<>szout2) & mini([szin2 szout2])>0 then
401 message(["Warning :";
402 "Selected ports don''t have the same size";
403 "The port at the origin of the link has size " + sci2exp(szout);
404 "the port at the end has size " + sci2exp(szin)+"."])
408 // get port data type
409 // and say warning if doesn't match with szouttyp
410 szintyp = getporttyp(o2,port_number,'in')
411 if (szintyp>0 & szouttyp>0) then // if-then-else, event-select blocks case and all the -1 intyp/outtyp
412 if szintyp<>szouttyp then
413 tt_typ=['double';'complex';'int32';'int16';
414 'int8';'uint32';'uint16';'uint8']
417 message(["Warning :";
418 "Selected ports don''t have the same data type";
419 "The port at the origin of the link has datatype "+...
420 tt_typ(szouttyp)+' ('+sci2exp(szouttyp)+')';
421 "the port at the end has datatype "+...
422 tt_typ(szintyp)+' ('+sci2exp(szintyp)+')'+'.'])
427 elseif typi==2 & k<=size(ip,'*') then // implicit "input" port
429 if ip(port_number)<>0 then
430 message(["Selected port is already connected.";..
431 "To start a link off another link, place the cursor";..
432 "on the split point and double click."]),
433 p_size = size(gh_axes.children)
434 d_size = p_size(1)-o_size(1);
436 gh_compound_delete = glue(gh_axes.children(1:d_size) );
437 delete (gh_compound_delete); //** delete the object
439 if %scicos_debug_gr then
440 disp("d5");//** Debug
443 return ; //** Exit point
446 szin = getportsiz(o2,port_number,'in')
448 if szin<>szout & mini([szin szout])>0 then
449 message(["Warning :';
450 "Selected ports don''t have the same size";
451 "The port at the origin of the link has size "+string(szout);
452 "the port at the end has size "+string(szin)])
455 elseif (typi==2 & k>size(ip,'*')+size(cip,'*')) then // implicit "output" port
456 k = k-size(ip,'*')-size(cip,'*')
458 port_number = o_ImplIndx(k) //RN: explicit outputs are excluded
459 // in the computation of k
460 if impo(port_number)<>0 then
461 message(["Selected port is already connected.";..
462 "To start a link off another link, place the cursor";..
463 "on the split point and double click"]),
464 p_size = size(gh_axes.children);
465 d_size = p_size(1)-o_size(1);
467 gh_compound_delete = glue(gh_axes.children(1:d_size) );
468 delete (gh_compound_delete); //** delete the object
470 if %scicos_debug_gr then
471 disp("d6");//** Debug
474 return; //** Exit point
477 szin=getportsiz(o2,port_number,'out')
479 if szin<>szout & mini([szin szout])>0 then
480 message(["Warning :";
481 "Selected ports don''t have the same size";
482 "The port at the origin of the link has size " + string(szout);
483 "the port at the end has size " + string(szin)+'.'])
486 //** otherwise is an event input port
487 else // event input port
489 port_number = k-size(ip,'*');
491 if cip(port_number)<>0 then
493 message(["Selected port is already connected.";..
494 "To start a link off another link, place the cursor";..
495 "on the split point and double click."]),
496 p_size = size(gh_axes.children);
497 d_size = p_size(1)-o_size(1);
499 gh_compound_delete = glue(gh_axes.children(1:d_size) );
500 delete (gh_compound_delete); //** delete the object
502 if %scicos_debug_gr then
503 disp("d7");//** Debug
507 return; //** Exit point
511 szin = getportsiz(o2,port_number,'evtin');
512 if szin<>szout & mini([szin szout])>0 then
513 message(["Warning :";
514 "Selected ports don''t have the same size"
515 "The port at the origin of the link has size " + string(szout);
516 "the port at the end has size " + string(szin)+'.'])
520 //** "fin" : this end a very long list of check on the final destination of the link *****
522 if %scicos_debug_gr then
526 break; //** this break the outher loop
528 else // (kto==[]) new point ends current line segment: you remain in the outher loop
530 if xe<>xo|ye<>yo then // to avoid null length segments
533 if abs(xo-xc2)<abs(yo-yc2) then
539 gh_link.data = [xo yo ; xc2 yc2 ] ; //** temp
540 gh_link.foreground = clr ; //** put the color here
544 if %scicos_debug_gr then
545 disp("d8");//** Debug
548 xl = [xl;xc2]; yl = [yl;yc2] ;
549 xo = xc2 ; yo = yc2 ;
554 end // This is the end of the outher loop (loop on link segments)
555 //**---------------------------------------------------------------------------------------------
558 if gh_figure.figure_id<>curwin | rep(3)==-1000 then
559 //active window has been closed
560 [%win,Cmenu] = resume(curwin,'Quit')
563 // make last segment horizontal or vertical
565 to = [kto,port_number,bool2s(typpto=='in'|typpto=='evtin')]
569 message(["Selected port is already connected.";..
570 "To start a link off another link, place the cursor";..
571 "on the split point and double click"]),
572 p_size = size(gh_axes.children)
573 d_size = p_size(1)-o_size(1);
575 gh_compound_delete = glue(gh_axes.children(1:d_size) );
576 delete (gh_compound_delete); //** delete the object
579 if %scicos_debug_gr then
580 disp("d9");//** Debug
583 return //** EXIT point
586 //**-----------------------------------------------------------------------------------
587 //** the link is a valid link
589 //** from here the data strucures are update BUT not draw !
590 drawlater(); //** DO NOT UPDATE THE CANVAS !
592 if nx==1 then // 1 segment link
594 if fromsplit&(xl<>xc2|yl<>yc2) then
595 // try to move split point
596 if xx(wh)==xx(wh+1) then // split is on a vertical link
597 if (yy(wh)-yc2)*(yy(wh+1)-yc2)<0 then
599 gh_link.data = [xl yl ; xc2 yc2] ; //** put the coordinate here
601 elseif yy(wh)==yy(wh+1) then //split is on a horizontal link
602 if (xx(wh)-xc2)*(xx(wh+1)-xc2)<0 then
604 gh_link.data = [xl yl ; xc2 yc2 ] ; //** put the coordinate here
608 //** Alan's fix, 17/10/07
609 //** create a point in the middle of the link
610 //** in the case of a direct link between two port
611 //** of the same block
612 elseif kto==kfrom then
617 xl = [xl;xc2];yl=[yl;yc2]
619 if xl(nx)==xl(nx-1) then
620 // previous segment is vertical
621 nx = prod(size(xl)) ;
622 gh_link_del = gh_axes.children(1) ;
623 delete( gh_link_del );
624 gh_link_del = gh_axes.children(1) ;
625 delete( gh_link_del );
626 xpoly([xl(nx-1) ; xl(nx) ; xc2] , [yl(nx-1) ; yc2 ; yc2] ,'lines');
627 gh_link = gh_axes.children(1) ;
628 gh_link.foreground = clr
630 xl = [xl;xc2]; yl = [yl(1:nx-1);yc2;yc2]
632 //** ---- Previous segment is horizontal
633 elseif yl(nx)==yl(nx-1) then
634 // previous segment is horizontal
635 nx = prod(size(xl)) ;
636 gh_link_del = gh_axes.children(1) ;
637 delete( gh_link_del );
638 gh_link_del = gh_axes.children(1) ;
639 delete( gh_link_del );
640 xpoly([xl(nx-1);xc2;xc2],[yl(nx-1);yl(nx);yc2],'lines')
641 gh_link = gh_axes.children(1) ;
642 gh_link.foreground = clr
645 xl = [xl(1:nx-1);xc2;xc2]; yl = [yl;yc2]
647 // previous segment is oblique
648 // nothing particular is done
649 xl = [xl;xc2]; yl = [yl;yc2]
653 lk = scicos_link(xx=xl,yy=yl,ct=[clr,typ],from=from,to=to)
655 //**---- Mr. Clean :) -----------------------------------------------------------------------
656 p_size = size(gh_axes.children) ; //** p_size(1) is the number of compound object
657 d_size = p_size(1) - o_size(1) ; //** at the and of this "Link" operation
659 gh_compound_delete = glue(gh_axes.children(1:d_size) );
660 delete (gh_compound_delete); //** delete the object
662 //**------------------------------------------------------------------------------------------
664 //----------- update objects structure -----------------------------
665 //------------------------------------------------------------------
667 if fromsplit then // link comes from a split
668 nx=size(scs_m.objs)+1
673 link1.xx = [xx(1:wh);d(1)];
674 link1.yy = [yy(1:wh);d(2)];
678 link2.xx = [d(1);xx(wh+1:size(xx,1))];
679 link2.yy = [d(2);yy(wh+1:size(yy,1))];
680 link2.from = [nx,1,0];
683 // create split block
686 sp.graphics.orig = d;
687 sp.graphics.pin = ks;
688 sp.graphics.pout = [nx+1;nx+2];
692 sp=IMPSPLIT_f('define')
693 sp.graphics.orig = d;
694 sp.graphics.pin = ks;
695 sp.graphics.pout = [nx+1;nx+2];
697 IMPSPLIT_f('plot',sp)
699 sp=CLKSPLIT_f('define')
700 sp.graphics.orig = d;
701 sp.graphics.pein = ks;
702 sp.graphics.peout = [nx+1;nx+2];
703 CLKSPLIT_f('plot',sp)
706 glue(gh_axes.children(1) ); //** create the compound
707 //** be very careful: here the graphics datastructure has ONE more element than the
709 //---------------------------
710 scs_m.objs(ks) = link1 ; //** adjust the data of the first half of the old "splitted" link
712 gh_ks = get_gri(ks,o_size(1)) + 1 ; //** I need to compensate for the last entry
714 gh_axes.children(gh_ks).children.data = [ link1.xx , link1.yy] ; //** update the graphics datastructure
715 link1_color = gh_axes.children(gh_ks).children.foreground ; //** save the color
717 //---------------------------
719 scs_m.objs(nx) = sp ; //** the graphics datastructure is already up to date in "nx" position
721 //---------------------------
723 scs_m.objs(nx+1) = link2 ;
725 xpoly (link2.xx , link2.yy) ;
726 gh_axes.children(1).foreground = link1_color ;
727 glue(gh_axes.children(1) ); //** create the compound :)
729 //** update the diagram
730 scs_m.objs(to1(1)) = mark_prt(scs_m.objs(to1(1)),to1(2),outin(to1(3)+1),typ,nx+1)
734 //**----------------------------------------------------------------------------------
736 //** add new link in objects structure
737 nx = size(scs_m.objs)+1 ;
739 if smart then lk=scicos_route(lk,scs_m),end
741 scs_m.objs($+1) = lk ;
747 //** update connected blocks
748 scs_m.objs(kfrom) = mark_prt(scs_m.objs(kfrom),from(2),outin(from(3)+1),typ,nx)
749 scs_m.objs(kto) = mark_prt(scs_m.objs(kto),to(2),outin(to(3)+1),typ,nx)
753 [scs_m_save,nc_save,enable_undo,edited] = resume(scs_m_save,nc_save,%t,%t)