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_qd(%pt, scs_m, needcompile)
25 //** Edition of a link from an output block to an input block
26 //** using "Simulink like" orthogonal links only
27 //** oblique links are not accepted !
29 //** 28/11/08: Preparation of the "SL" operation
30 //** 24/07/07: Al@n's patch for rotation of blocks
32 //** N.B : Please set %scicos_debug_gr="%t" to activate the debug mode
33 %scicos_debug_gr = %f;
36 //----------- get link origin --------------------------------------
37 //------------------------------------------------------------------
42 [kfrom, wh] = getblocklink(scs_m,[xc1;yc1]); //** recover information
43 //** about the starting point
44 //** kfrom is the id of the selected block or link
46 if kfrom<>[] then //** check for the presence of a valid output
47 o1 = scs_m.objs(kfrom) ; //** acquire the object
49 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 ------------------------------
64 [xx,yy,ct,from,to] = (o1.xx,o1.yy,o1.ct,o1.from,o1.to);
65 if (-wh==size(xx,'*')) then
66 wh = -(wh+1) //** avoid with clicking at the end-point of link
70 [xout,yout,typout] = getoutputports(scs_m.objs(from(1)));
72 [m,kp1] = mini((yc1-yout)^2+(xc1-xout)^2);
76 if typo==-1 then //** old link comes from an event output port
78 else //** old link comes from an regular output or input (implicit) port
79 typp = outin(from(3)+1)
83 szout = getportsiz(scs_m.objs(from(1)),from(2),typp)
84 //** get port data type
85 if typp=='out'|typp=='in' then
86 szouttyp = getporttyp(scs_m.objs(from(1)),from(2),typp)
89 //** get initial split position
92 //** this function is used to compute the projection of the point
93 //** on the link segment
94 d = projaff(xx(wh:wh+1), yy(wh:wh+1),pt); //** module/graphics/macro/
96 //** orthogonal link logic
97 if xx(wh)==xx(wh+1) //** this is a vertical link
98 link_dir = "h" ; //** go horizontal from the split
99 elseif yy(wh)==yy(wh+1) //** this is an horizontal link
100 link_dir = "v" ; //** go vertical from the split
101 else //** this is an oblique link
102 if typo==-1 then //** old link comes from an event output port
103 link_dir = "v" ; //** go vertical for event link
104 else //** old link comes from an regular output or input (implicit) port
105 link_dir = "h"; //** go horizontal for "normal" link
109 else //** the split is on a corner
111 d = [xx(wh);yy(wh)] ;
112 //** ortogonal link logic
113 if typo==-1 then //** old link comes from an event output port
114 link_dir = "v" ; //** go vertical for event link
115 else //** old link comes from an regular output or input (implicit) port
116 link_dir = "h"; //** go horizontal for "normal" link
120 // Note : creation of the split block and modifications of links are
121 // done later, the sequel assumes that the split block is added
122 // at the end of scs_m
123 ks = kfrom; // selected link number
124 kfrom = size(scs_m.objs)+1;
125 port_number = 2; // to be created split block number
128 // to be created link from origin
130 from = [kfrom,port_number,0]
133 //** --------------------- "Link" case end here --------------------------
134 else // connection comes from a block
135 //** ------------------- start from a BLOCK ------------------------------
136 graphics1 = o1.graphics
137 orig = graphics1.orig
139 theta = graphics1.theta
143 cop = graphics1.peout
144 [xout,yout,typout] = getoutputports(o1)
146 i_ImplIndx = find(graphics1.in_implicit=='I');
150 messagebox("This block has no output port",'modal');
155 //** geometrical conversion for rotated block
156 xxx = rotate([xout;yout],...
158 [orig(1)+sz(1)/2; orig(2)+sz(2)/2]);
162 [m,kp1] = mini((yc1-yout)^2+(xc1-xout)^2) ;
164 xo = xout(k); yo = yout(k);
167 //** ---------------------- Checking -------------------------------------------
168 //** Check if the new requested link creation is compatible with the diagram
169 // Check if selected port is already connected and get port type ('in' or 'out')
171 if typo==1 then //** Regular output port
173 link_dir = "h" ; //** output port starts horizontal link
174 if op(port_number)<>0 then
176 messagebox(["Selected port is already connected.";..
177 "To start a link off another link, place the cursor";..
178 "on the split point and double click, or type l."],'modal')
183 elseif (typo==2 & k<=size(op,'*')) then //** Implicit output port (Modelica)
185 //** TODO : in case of Modelica port the choice is not yet clear :(
186 link_dir = "h" ; //** use the default
187 if op(port_number)<>0 then
189 messagebox(["Selected port is already connected.";..
190 "To start a link off another link, place the cursor";..
191 "on the split point and double click, or type l."],'modal')
196 elseif (typo==2 & k>size(op,'*')+size(cop,'*')) then //** Implicit input port
198 k = k-size(op,'*')-size(cop,'*');
199 port_number = i_ImplIndx(k)
200 //** TODO : in case of Modelica port the choice is not yet clear :(
201 link_dir = "h" ; //** use the default
202 if impi(port_number)<>0 then
204 messagebox(["Selected port is already connected.";..
205 "To start a link off another link, place the cursor";..
206 "on the split point and double click, or type l."],"modal")
207 unhilite_obj(kfrom) ;
211 else //** Event output port
212 port_number = k - size(op,'*') ;
213 //** In case of Event port the direction is strictly vertical
214 link_dir = "v" ; //**
216 if cop(port_number)<>0 then
218 messagebox(["Selected port is already connected.";..
219 "To start a link off another link, place the cursor";..
220 "on the split point and double click, or type l."],"modal")
224 typpfrom = 'evtout' ;
227 clr = default_color(typo) ;
230 szout = getportsiz(o1,port_number,typpfrom)
231 //** get port data type
232 if typpfrom=='out'|typpfrom=='in' then
233 szouttyp = getporttyp(o1,port_number,typpfrom);
236 // to be created link from origin
237 from = [kfrom,port_number, bool2s(typpfrom=='in'|typpfrom=='evtin')] ;
242 //** ---------------------- Checking Ends ----------------------------------------
244 //----------- get link path ----------------------------------------
245 //------------------------------------------------------------------
247 drawlater(); //** draw later mode
249 //** These indexes will be used to destroy the intermediate objects created below
250 //** during the "interactive" section
252 o_size = size(gh_axes.children) ; //** o_size(1) is the number of compound object
255 //** there are two nested infinite while(%t) loops:
256 //** the outher loop control the sequence of segment
257 //** the inner loop handle the interactive operation on the single link segment
259 //**------------------- OUTHER LOOP -----------------------------------------------------------
260 while %t do // loop on link segments
261 xe = xo; ye = yo ; //** o > origin ---- e > end
262 //** the first step is the the creation of a dummy graphic object (a link of ZERO leght)
263 //** and store this handler to modify it later
264 xpoly([xo;xe] , [yo;ye], 'lines') ; //** create the first 'dummy' object
265 gh_link = gh_axes.children(1) ; //** the last object is the above link :)
267 //**----------------------------- INNER LOOP -------------------------------------------
268 rep(3) = -1; //** initialization (as Claudio Macchiavelli has teached me :) )
269 while %t do //** infinite loop
271 //** for positive event exit from the loop
272 //** Any event on the [right] button OR a window closing => END the inner loop
273 if or(rep(3)==[0,2,3,5,-5,-1000]) then
277 //** otherwise ... get a new point
279 //** mouse event queque is cleared (15 Mar 2007 bugfix)
280 rep = xgetmouse([%t, %t]) ; //** looks better :)
283 //** focus has changed OR active window has been closed
284 if gh_figure.figure_id<>curwin | rep(3)==-1000 then
285 [%win, Cmenu] = resume(curwin,'Quit');
288 //** any rigth mouse event OR [Esc] OR [d] key : I want to disengage the current Link action
289 if or(rep(3)==[2 5 12 27 100]) then
290 p_size = size(gh_axes.children);
291 d_size = p_size(1)-o_size(1);
293 gh_compound_delete = glue(gh_axes.children(1:d_size) );
294 delete (gh_compound_delete); //** delete the object
295 drawnow(); //** update the screen
298 if %scicos_debug_gr then
299 disp("d1"); //** Debug
301 return; //** -----> Exit from the function
304 //** plot new link polyline
305 xe = rep(1); ye = rep(2) ;
307 //** Now there are two cases (at least); split link and Modelica are not handled ....
308 if link_dir=="h" then
309 //** horizontal orthogonal link
310 hdx = xo + (xe-xo)/2 ;
311 gh_link.data = [xo yo ; hdx yo ; hdx ye ; xe ye ];
312 elseif link_dir=="v" then
313 //** vertical orthogonal link
314 vdy = yo + (ye-yo)/2 ;
315 gh_link.data = [xo yo ; xo vdy ; xe vdy ; xe ye ];
318 gh_link.foreground = clr; //** put the color here ( 5 = red )
319 drawnow(); //** update the buffer
321 //** ------------------------------- INNER LOOP END ------------------------------
323 if %scicos_debug_gr then
324 disp("-->"); //** debug only
327 //** ---------- YOU ARE STILL IN THE "Link" Block-to-Block MAIN LOOP ----------------
328 //** The last segment end with [xe ye] coordinate:
330 //** look for a block with a valid (good) input
332 kto = getblock(scs_m,[xe;ye]) ;
333 if kto<>[] then // new point designs the "to block"
334 o2 = scs_m.objs(kto);
335 graphics2 = o2.graphics;
336 orig = graphics2.orig
338 theta = graphics2.theta
340 impo = graphics2.pout
342 [xin,yin,typin] = getinputports(o2)
344 o_ImplIndx = find(graphics2.out_implicit=='I');
346 //** check connection
349 messagebox("This block has no input port.","modal");
350 p_size = size(gh_axes.children);
351 d_size = p_size(1) - o_size(1);
353 gh_compound_delete = glue(gh_axes.children(1:d_size));
354 delete (gh_compound_delete); //** delete the object
356 if %scicos_debug_gr then
357 disp("d2"); //** Debug
360 drawnow(); //** update the diagram
361 return; //** EXIT point : link failed !
364 //** Connection is OK : compensate for block's rotation
366 xxx = rotate([xin;yin],...
368 [orig(1)+sz(1)/2;orig(2)+sz(2)/2]);
369 xin = xxx(1,:); yin = xxx(2,:);
370 [m,kp2] = mini((ye-yin)^2+(xe-xin)^2);
372 xc2 = xin(k); yc2 = yin(k);
375 //** check connection for "type"
378 messagebox(["Selected ports don''t have the same type"
379 "The port at the origin of the link has type "+string(typo);
380 "the port at the end has type "+string(typin(k))+'.'],"modal")
381 p_size = size(gh_axes.children)
382 d_size = p_size(1)-o_size(1);
384 gh_compound_delete = glue(gh_axes.children(1:d_size));
385 delete (gh_compound_delete); //** delete the object
387 if %scicos_debug_gr then
388 disp("d3"); //** Debug
392 return; //** EXIT point from the function
395 //** check if is a normal regular input port (not an event input port)
396 if typi==1 then // regular input port
398 if ip(port_number)<>0 then
400 messagebox(["Selected port is already connected.";..
401 "To start a link off another link, place the cursor";..
402 "on the split point and double click, or type l."],'modal'),
403 p_size = size(gh_axes.children);
404 d_size = p_size(1)-o_size(1);
406 gh_compound_delete = glue(gh_axes.children(1:d_size) );
407 delete (gh_compound_delete); //** delete the object
409 if %scicos_debug_gr then
410 disp("d4");//** Debug
418 szin = getportsiz(o2,port_number,'in')
420 //** further check for warning message about "size"
421 need_warning = %f ; //** flag initialization
422 if (szin(1)<>szout(1)) & mini([szin(1) szout(1)])>0 then
426 // check for different number of dimension
427 szout2 = []; szin2 = [];
428 if size(szout,'*')==1 then
434 if size(szin,'*')==1 then
440 if (szin2<>szout2) & mini([szin2 szout2])>0 then
446 messagebox(["Warning :";
447 "Selected ports don''t have the same size";
448 "The port at the origin of the link has size " + sci2exp(szout);
449 "the port at the end has size " + sci2exp(szin)+"."],"modal")
453 // get port data type
454 // and say warning if doesn't match with szouttyp
455 szintyp = getporttyp(o2,port_number,'in')
456 if (szintyp>0 & szouttyp>0) then // if-then-else, event-select blocks case and all the -1 intyp/outtyp
457 if szintyp<>szouttyp then
458 tt_typ=['double';'complex';'int32';'int16';
459 'int8';'uint32';'uint16';'uint8']
462 messagebox(["Warning :";
463 "Selected ports don''t have the same data type";
464 "The port at the origin of the link has datatype "+...
465 tt_typ(szouttyp)+' ('+sci2exp(szouttyp)+')';
466 "the port at the end has datatype "+...
467 tt_typ(szintyp)+' ('+sci2exp(szintyp)+')'+'.'],"modal")
472 elseif typi==2 & k<=size(ip,'*') then // implicit "input" port
474 if ip(port_number)<>0 then
475 messagebox(["Selected port is already connected.";..
476 "To start a link off another link, place the cursor";..
477 "on the split point and double click."],"modal"),
478 p_size = size(gh_axes.children)
479 d_size = p_size(1)-o_size(1);
481 gh_compound_delete = glue(gh_axes.children(1:d_size) );
482 delete (gh_compound_delete); //** delete the object
484 if %scicos_debug_gr then
485 disp("d5");//** Debug
488 return ; //** Exit point
491 szin = getportsiz(o2,port_number,'in')
493 if szin<>szout & mini([szin szout])>0 then
494 messagebox(["Warning :';
495 "Selected ports don''t have the same size";
496 "The port at the origin of the link has size "+string(szout);
497 "the port at the end has size "+string(szin)],"modal")
500 elseif (typi==2 & k>size(ip,'*')+size(cip,'*')) then // implicit "output" port
501 k = k-size(ip,'*')-size(cip,'*')
503 port_number = o_ImplIndx(k) //RN: explicit outputs are excluded
504 // in the computation of k
505 if impo(port_number)<>0 then
506 messagebox(["Selected port is already connected.";..
507 "To start a link off another link, place the cursor";..
508 "on the split point and double click"],"modal"),
509 p_size = size(gh_axes.children);
510 d_size = p_size(1)-o_size(1);
512 gh_compound_delete = glue(gh_axes.children(1:d_size) );
513 delete (gh_compound_delete); //** delete the object
515 if %scicos_debug_gr then
516 disp("d6");//** Debug
519 return; //** Exit point
522 szin=getportsiz(o2,port_number,'out')
524 if szin<>szout & mini([szin szout])>0 then
525 messagebox(["Warning :";
526 "Selected ports don''t have the same size";
527 "The port at the origin of the link has size " + string(szout);
528 "the port at the end has size " + string(szin)+'.'],"modal")
531 //** otherwise is an event input port
532 else // event input port
534 port_number = k-size(ip,'*');
536 if cip(port_number)<>0 then
538 messagebox(["Selected port is already connected.";..
539 "To start a link off another link, place the cursor";..
540 "on the split point and double click."],"modal"),
541 p_size = size(gh_axes.children);
542 d_size = p_size(1)-o_size(1);
544 gh_compound_delete = glue(gh_axes.children(1:d_size) );
545 delete (gh_compound_delete); //** delete the object
547 if %scicos_debug_gr then
548 disp("d7");//** Debug
552 return; //** Exit point
556 szin = getportsiz(o2,port_number,'evtin');
557 if szin<>szout & mini([szin szout])>0 then
558 messagebox(["Warning :";
559 "Selected ports don''t have the same size"
560 "The port at the origin of the link has size " + string(szout);
561 "the port at the end has size " + string(szin)+'.'],"modal")
565 //** "fin" : this end a very long list of check on the final destination of the link *****
567 if %scicos_debug_gr then
571 //** update the link data vector for the phinal phase
572 cmx = gh_link.data; //** recover the coordinates
573 //** add the coordinate at the vectors for the final link
574 xl = [xl; cmx(2:4,1) ]; //** "x" colum, excluding the first element
575 yl = [yl; cmx(2:4,2) ]; //** "y" colum, " " " "
577 break; //** this BREAK the outher loop and go at the final phase
579 else // (kto==[]) new point ends current line segment: you remain in the outher loop
581 if %scicos_debug_gr then
582 disp("d8"); //** Debug
585 if xe<>xo|ye<>yo then // to avoid null length segments
587 cmx = gh_link.data; //** recover the coordinates
588 //** add the coordinate at the vectors for the final link
589 xl = [xl; cmx(2:4,1) ]; //** "x" colum, excluding the first element
590 yl = [yl; cmx(2:4,2) ]; //** "y" colum, " " " "
592 //** new "zero" coordinate for the next "poly"
593 xo = cmx(4,1) ; //** "xe" the final point is the new starting point
594 yo = cmx(4,2) ; //** "ye" " " " " " " " "
599 end // This is the end of the outher loop (loop on link segments)
600 //**---------------------------------------------------------------------------------------------
603 if gh_figure.figure_id<>curwin | rep(3)==-1000 then
604 //active window has been closed
605 [%win,Cmenu] = resume(curwin,'Quit')
609 to = [kto,port_number,bool2s(typpto=='in'|typpto=='evtin')]
613 messagebox(["Selected port is already connected.";..
614 "To start a link off another link, place the cursor";..
615 "on the split point and double click"],"modal"),
616 p_size = size(gh_axes.children)
617 d_size = p_size(1)-o_size(1);
619 gh_compound_delete = glue(gh_axes.children(1:d_size) );
620 delete (gh_compound_delete); //** delete the object
623 if %scicos_debug_gr then
624 disp("d9");//** Debug
627 return //** EXIT point
630 //**-----------------------------------------------------------------------------------
631 //** the link is a valid link
633 //** from here the data strucures are update BUT not draw !
634 drawlater(); //** DO NOT UPDATE THE CANVAS !
636 // if nx==1 then // 1 segment link
638 // if fromsplit&(xl<>xc2|yl<>yc2) then
639 // // try to move split point
640 // if xx(wh)==xx(wh+1) then // split is on a vertical link
641 // if (yy(wh)-yc2)*(yy(wh+1)-yc2)<0 then
643 // gh_link.data = [xl yl ; xc2 yc2] ; //** put the coordinate here
645 // elseif yy(wh)==yy(wh+1) then //split is on a horizontal link
646 // if (xx(wh)-xc2)*(xx(wh+1)-xc2)<0 then
648 // gh_link.data = [xl yl ; xc2 yc2 ] ; //** put the coordinate here
652 // //** Alan's fix, 17/10/07
653 // //** create a point in the middle of the link
654 // //** in the case of a direct link between two port
655 // //** of the same block
656 // elseif kto==kfrom then
657 // xl = [xl;(xl+xc2)/2]
658 // yl = [yl;(yl+yc2)/2]
661 // xl = [xl;xc2];yl=[yl;yc2]
663 // if xl(nx)==xl(nx-1) then
664 // // previous segment is vertical
665 // nx = prod(size(xl)) ;
666 // gh_link_del = gh_axes.children(1) ;
667 // delete( gh_link_del );
668 // gh_link_del = gh_axes.children(1) ;
669 // delete( gh_link_del );
670 // xpoly([xl(nx-1) ; xl(nx) ; xc2] , [yl(nx-1) ; yc2 ; yc2] ,'lines');
671 // gh_link = gh_axes.children(1) ;
672 // gh_link.foreground = clr
673 // // form link datas
674 // xl = [xl;xc2]; yl = [yl(1:nx-1);yc2;yc2]
676 // //** ---- Previous segment is horizontal
677 // elseif yl(nx)==yl(nx-1) then
678 // // previous segment is horizontal
679 // nx = prod(size(xl)) ;
680 // gh_link_del = gh_axes.children(1) ;
681 // delete( gh_link_del );
682 // gh_link_del = gh_axes.children(1) ;
683 // delete( gh_link_del );
684 // xpoly([xl(nx-1);xc2;xc2],[yl(nx-1);yl(nx);yc2],'lines')
685 // gh_link = gh_axes.children(1) ;
686 // gh_link.foreground = clr
688 // // form link datas
689 // xl = [xl(1:nx-1);xc2;xc2]; yl = [yl;yc2]
691 // // previous segment is oblique
692 // // nothing particular is done
693 // xl = [xl;xc2]; yl = [yl;yc2]
697 lk = scicos_link(xx=xl, yy=yl, ct=[clr,typ], from=from, to=to) ;
699 //**---- Mr. Clean :) -----------------------------------------------------------------------
700 p_size = size(gh_axes.children) ; //** p_size(1) is the number of compound object
701 d_size = p_size(1) - o_size(1) ; //** at the and of this "Link" operation
703 gh_compound_delete = glue(gh_axes.children(1:d_size) );
704 delete (gh_compound_delete); //** delete the object
706 //**------------------------------------------------------------------------------------------
708 //----------- update objects structure -----------------------------
709 //------------------------------------------------------------------
711 if fromsplit then // link comes from a split
712 nx=size(scs_m.objs)+1
717 link1.xx = [xx(1:wh);d(1)];
718 link1.yy = [yy(1:wh);d(2)];
722 link2.xx = [d(1);xx(wh+1:size(xx,1))];
723 link2.yy = [d(2);yy(wh+1:size(yy,1))];
724 link2.from = [nx,1,0];
727 // create split block
730 sp.graphics.orig = d;
731 sp.graphics.pin = ks;
732 sp.graphics.pout = [nx+1;nx+2];
736 sp=IMPSPLIT_f('define')
737 sp.graphics.orig = d;
738 sp.graphics.pin = ks;
739 sp.graphics.pout = [nx+1;nx+2];
741 IMPSPLIT_f('plot',sp)
743 sp=CLKSPLIT_f('define')
744 sp.graphics.orig = d;
745 sp.graphics.pein = ks;
746 sp.graphics.peout = [nx+1;nx+2];
747 CLKSPLIT_f('plot',sp)
750 glue(gh_axes.children(1) ); //** create the compound
751 //** be very careful: here the graphics datastructure has ONE more element than the
753 //---------------------------
754 scs_m.objs(ks) = link1 ; //** adjust the data of the first half of the old "splitted" link
756 gh_ks = get_gri(ks,o_size(1)) + 1 ; //** I need to compensate for the last entry
758 gh_axes.children(gh_ks).children.data = [ link1.xx , link1.yy] ; //** update the graphics datastructure
759 link1_color = gh_axes.children(gh_ks).children.foreground ; //** save the color
761 //---------------------------
763 scs_m.objs(nx) = sp ; //** the graphics datastructure is already up to date in "nx" position
765 //---------------------------
767 scs_m.objs(nx+1) = link2 ;
769 xpoly (link2.xx , link2.yy) ;
770 gh_axes.children(1).foreground = link1_color ;
771 glue(gh_axes.children(1) ); //** create the compound :)
773 //** update the diagram
774 scs_m.objs(to1(1)) = mark_prt(scs_m.objs(to1(1)),to1(2),outin(to1(3)+1),typ,nx+1)
778 //**----------------------------------------------------------------------------------
780 //** add new link in objects structure
781 nx = size(scs_m.objs)+1 ;
782 scs_m.objs($+1) = lk ;
788 //** update connected blocks
789 scs_m.objs(kfrom) = mark_prt(scs_m.objs(kfrom),from(2),outin(from(3)+1),typ,nx)
790 scs_m.objs(kto) = mark_prt(scs_m.objs(kto),to(2),outin(to(3)+1),typ,nx)
794 [scs_m_save,nc_save,enable_undo,edited] = resume(scs_m_save,nc_save,%t,%t)