1 {
2 Define el frame que implementa la interfaz gráfica donde se muestra el PIC y al que
3 se le pueden agreagr compoentes electrónicos adicionales como leds, o pantallas LCD.
4 
5                                                 Creado por Tito Hinostroza 05/2018.
6                                                 Modif. por Tito Hinostroza 08/2018.
7 }
8 unit FramePICDiagram;
9 {$mode objfpc}{$H+}
10 interface
11 uses
12   Classes, SysUtils, FileUtil, fgl, Types, Forms, Controls, ExtCtrls, Graphics,
13   Menus, ActnList, LCLProc, ogEditionMot, ogMotGraf2D, ogDefObjGraf, PicCore,
14   Parser, MisUtils;
15 type
16   { TPinGraph }
17   {Objeto que modela a un pin físico de un componente electrónico.
18   Se penso en usar el mismo tipo TpicCore.pines[] y usar ese arreglo como contenedor
19   de objetos TPinGraph, pero considerando que los pines están fuertemente asociados a
20   un punto de conexión, se decidió crearlo como una extensión de TPtoConx, así se
21   simplifica considerablemente la administración.}
22   TPinGraph = class(TPtoConx)
23   private  //Parámetros del modelo interno del Pin
24     {Cuando es un componente común. se leerán estos parámetros, como modelo
25     del pin.}
26     vThev: single;
27     rThev: single;
28     procedure GetModel(out vThev0, rThev0: Single);  //Devuelve parámetros del modelo eléctrico
29     procedure SetModel(vThev0, rThev0: Single);  //Fija parámetros del modelo eléctrico
30   private  //Valores de voltaje e impedancia del nodo al que se encuentra conectado
31     vNod: single;
32     rNod: single;
33     procedure SetNodePars(vNod0, rNod0: Single);   //Fija parámetros debido al nodoconectado
34   private  //Campos adicionales cuando es pin de un PIC
35     {Se necesita una referencia al PIC cuando este pin es parte de un PIC.}
36     pic   : TPicCore;
37     nPin  : integer;    //Número de pin (del encapsulado)
38   private  //Propiedades geométricas
39     x1, y1, x2, y2: Single; //Cordenadas cuando se representa como rectángulo
40     lbl   : string;     //Etiqueta
41     xLbl, yLbl: Single; //Posición de la etiqueta
42   public
43     //procedure GetThevNod(out vThev0, rThev0: Single);//Devuelve parámetros del modelo eléctrico
44     procedure SetLabel(xl, yl: Single; txt: string; align: TAlignment =
45       taLeftJustify);
46     constructor Create(mGraf: TMotGraf);  //OJO: No es override
47   end;
48   TPicPinList = specialize TFPGObjectList<TPinGraph>;  //Lista para gestionar los puntos de control
49 
50   { TOgComponent }
51   {Incluye propiedades de los componentes para este editor gráfico.}
52   TOgComponent = class(TObjGraf)
53   private
54   public
55     Ref: string;  //Nomenclatura única del componente: R1, R2, CI1
56     ShowRef: boolean;
57     xRef, yRef: Single;  //Ubicación relativa de la etiqueta Ref
58 //    pins: TPicPinList;  //Lista de pines
AddPtoConexnull59     function AddPtoConex(xOff, yOff: Single): TPinGraph; override;
AddPinnull60     function AddPin(xCnx, yCnx, x1, y1, x2, y2: Single): TPinGraph;
61     constructor Create(mGraf: TMotGraf); override;
62     destructor Destroy; override;
63   end;
64 
65   TNode = class;
66 
67   { TOgConector }
68   TOgConector = class(TOgComponent)
69   private
70     OnConnect: procedure of object;
71     OnDisconnect: procedure of object;
72     nodParent: TNode;
73     PaintBox : TPaintBox;  //Referencia al PaintBox donde se dibuja
74     ptos: array of TFPoint;
75     procedure PCtlConnect(pCtl: TPtoCtrl; pCnx: TPtoConx);
76     procedure PCtlDisconnect(pCtl: TPtoCtrl; pCnx: TPtoConx);
ConnectedTonull77     function ConnectedTo(ogCon: TOgConector): boolean;
78   public
IsSelectedBynull79     function IsSelectedBy(xr, yr: Integer): Boolean; override;
80     procedure Draw; override;
81     constructor Create(mGraf: TMotGraf); override;
82     destructor Destroy; override;
83   end;
84   TConnectorList = specialize TFPGObjectList<TOgConector>;  //Lista para gestionar los puntos de control
85 
86   { TNode }
87   TNode = class
88   private
89     vt, rt: Single;
90     connectorList: TConnectorList;
91     pinList      : TPicPinList;  //Lista de pines conectadas al nodo
92     procedure UpdateModel;
Containsnull93     function Contains(ogCon: TOgConector): boolean;
ConnectedTonull94     function ConnectedTo(ogCon: TOgConector): boolean;
95     procedure AddConnector(ogCon: TOgConector);
96   public
97     constructor Create;
98     destructor Destroy; override;
99   end;
100   TNodeList = specialize TFPGObjectList<TNode>;  //Lista de nodos
101 
102   { TOgPic }
103   //Define el objeto gráfico PIC
104   TOgPic = class(TOgComponent)
105   private
106     pic: TPicCore;   //referencia al PIC
107     xpin: Single;  //Posición X del Pin
108     nPinsDiag: Integer;  //Número de pines a dibujar
109     nPinsSide: Integer;
110   public
111     procedure SetPic(pic0: TPicCore);
112     procedure Draw; override;
113     constructor Create(mGraf: TMotGraf); override;
114     destructor Destroy; override;
115   end;
116 
117   { TOgLogicState }
118   //Define el objeto gráfico LogicState
119   TOgLogicState = class(TOgComponent)
120   private
121     ptos: array of TFPoint;
122     pin: TPinGraph;
123   public
124     //procedure SetState(Value: boolean);
125     procedure Draw; override;
126     constructor Create(mGraf: TMotGraf); override;
127     destructor Destroy; override;
128   end;
129 
130   { TOgLedRed }
131   //Define el objeto Diodo Led
132   TOgLedRed = class(TOgComponent)
133   private
134     pin: TPinGraph;
135   public
136     //procedure SetState(Value: boolean);
137     procedure Draw; override;
138     constructor Create(mGraf: TMotGraf); override;
139     destructor Destroy; override;
140   end;
141 
142   { TOg7Segment }
143   //Define el objeto Display de 7 segmentos
144   TOg7Segment = class(TOgComponent)
145   private
146     pinA: TPinGraph;
147     pinB: TPinGraph;
148     pinC: TPinGraph;
149     pinD: TPinGraph;
150     pinE: TPinGraph;
151     pinF: TPinGraph;
152     pinG: TPinGraph;
153   public
154     //procedure SetState(Value: boolean);
155     procedure Draw; override;
156     constructor Create(mGraf: TMotGraf); override;
157     destructor Destroy; override;
158   end;
159 
160   { TOgResisten }
161   //Define el objeto Resistencia (Resistor)
162   TOgResisten = class(TOgComponent)
163   private
164   public
165     //procedure SetState(Value: boolean);
166     procedure Draw; override;
167     constructor Create(mGraf: TMotGraf); override;
168     destructor Destroy; override;
169   end;
170 
171   { TfraPICDiagram }
172   TfraPICDiagram = class(TFrame)
173     acAddLogTog: TAction;
174     acGenDelObject: TAction;
175     acGenConnTo: TAction;
176     acAddConn: TAction;
177     acAddLed: TAction;
178     acAddResis: TAction;
179     acAdd7SegComC: TAction;
180     acGenReconn: TAction;
181     ActionList1: TActionList;
182     MenuItem1: TMenuItem;
183     MenuItem2: TMenuItem;
184     MenuItem4: TMenuItem;
185     MenuItem5: TMenuItem;
186     mnReconn: TMenuItem;
187     mnConnect: TMenuItem;
188     mnReset: TMenuItem;
189     mnRun: TMenuItem;
190     MenuItem3: TMenuItem;
191     mnAddLogicTog: TMenuItem;
192     mnStepOver: TMenuItem;
193     mnDelete: TMenuItem;
194     PaintBox1: TPaintBox;
195     PopupMenu1: TPopupMenu;
196     procedure acAdd7SegComCExecute(Sender: TObject);
197     procedure acAddConnExecute(Sender: TObject);
198     procedure acAddLedExecute(Sender: TObject);
199     procedure acAddLogTogExecute(Sender: TObject);
200     procedure acAddResisExecute(Sender: TObject);
201     procedure acGenConnToExecute(Sender: TObject);
202     procedure acGenDelObjectExecute(Sender: TObject);
203     procedure acGenReconnExecute(Sender: TObject);
204   private  //Nombres y referencias
205     procedure connectorChange;
ExistsNamenull206     function ExistsName(AName: string): boolean;
UniqueNamenull207     function UniqueName(NameBase: string): string;
ExistsRefnull208     function ExistsRef(ARef: string): TOgComponent;
UniqueRefnull209     function UniqueRef(RefBase: string): string;
210   private  //Manejo de nodos
211     nodeList: TNodeList;
212     procedure AddConnectorToNodes(ogCon: TOgConector);
213     procedure UpdateNodeList;
214   private
215     Fpic: TPicCore;
216     ogPic: TOgPic;
217     motEdi: TEditionMot;
218     procedure ConnectAction(Sender: TObject);
219     procedure fraPICDiagramKeyDown(Sender: TObject; var Key: Word;
220       Shift: TShiftState);
221     procedure motEdi_MouseUpRight(Shift: TShiftState; x, y: integer);
222     procedure motEdi_MouseDown(Sender: TObject; Button: TMouseButton;
223       Shift: TShiftState; X, Y: Integer);
224     procedure motEdi_MouseUp(Sender: TObject; Button: TMouseButton;
225       Shift: TShiftState; X, Y: Integer);
226   public
227     procedure Refrescar;
228     procedure SetCompiler(cxp0: TCompilerBase);
229     constructor Create(AOwner: TComponent) ; override;
230     destructor Destroy; override;
231   end;
232 
233 implementation
234 {$R *.lfm}
235 const
236   SEP_PIN = 20;   //Separación entre pines
237   LON_PIN = 10;   //Longitud de pin
238   //Colores pro defecto
239   COL_CI  = $404040;  //Circuitos Integrados
240   COL_GND = $404040;  //GND
241   COL_VCC = clRed;    //Voltajes VCC
242   COL_HIM = $A0A0A0;  //Alta impedancia
243   COL_RES = $9FE7F9;  //Cuerpo de resistencias
244 const  //ID para componentes
245   ID_PINGRAF = 1;    //Un pin que desciende de un Punto de conexión
246   ID_COMPON  = 10;   //Componentes en general
247   ID_PIC     = 11;
248   ID_CONNEC  = 12;
249   ID_LEDRES  = 13;
250   ID_RESIST  = 14;
251   ID_7SEGME  = 15;
252   ID_TOG_LOG = 16;
253 
GetThevColnull254 function GetThevCol(vt, rt: Single): TColor;
255 {Devuelve un color que representa el estado de un circuito de Thevening.}
256 begin
257   if rt>1e+6 then begin
258     //Se considera alta impedancia
259     exit(COL_HIM);
260   end else begin
261     //Tiene potencial
262     if vt > 2.5 then begin
263       exit(COL_VCC);
264     end else begin
265       exit(COL_GND);
266     end;
267   end;
268 end;
ResParallelnull269 function ResParallel(r1, r2: Single): Single; inline;
270 begin
271   if r1+r2=0 then begin
272     exit(0)
273   end else begin
274     exit(r1*r2/(r1+r2));
275   end;
276 end;
277 { TNode }
278 procedure TNode.UpdateModel;
279 {Devuelve los parámetros de Thevening del nodo. Esto es útil para leer el voltaje del
280 nodo en cualquier momento, que es parte de un análisis común por nodos.}
281 var
282   pin: TPinGraph;
283   r0 : Single;
284   v1, r1, v2, r2: Single;
285   nResistor, nSource: integer;  //Contadores y banderas
286 begin
287   //Casos especiales
288   if pinList.Count = 0 then begin
289     //Nodo sin conexiones
290     vt := 0;
291     rt := 1e+9;  //Alta impedancia
292   end else if pinList.Count = 1 then begin
293     //Conectado a un solo pin
294     pinList[0].GetModel(vt, rt);  //Mismo modelo del nodo
295   end else begin
296     //Conectado a varios pines
297     {Va simplificando por un lado las que son fuentes (en v1, r1)
298     y por otro las que son solo resistencias (en r0). La idea es que al final
299     se tenga:
300 
301           +--[R1]---
302           |
303          [V1]
304           |
305          ---
306 
307     Y por el otro:
308 
309       ----+
310           |
311          [R0]
312           |
313          ---
314     }
315     nResistor := 0;
316     nSource   := 0;
317     for pin in pinList do begin
318       pin.GetModel(v2, r2);
319       if v2 = 0 then begin
320         //Es resistencia pura
321         if nResistor=0 then begin
322           //Primera resistencia
323           r0 := r2;  //toma su valor
324         end else begin
325           r0 := ResParallel(r0, r2);  //Acumula en paralelo
326         end;
327         inc(nResistor);  //Lleva la cuenta
328       end else begin
329         //Es fuente con resistencia
330         if nSource=0 then begin
331           //Primera fuente
332           v1 := v2;  //Toma su valor
333           r1 := r2;
334         end else begin
335           if r1+r2 = 0 then begin
336             //Hay conexión directa de dos fuentes
337             {Se pone valor de voltaje promedio para evitar la indeterminación, pero
338             ralemnte debería generarse un error o advertencia.}
339             v1 := (v1+v2)/2;
340           end else begin
341             v1 := v2 + (v1-v2)*r2/(r1+r2);
342           end;
343           r1 := ResParallel(r1, r2);
344         end;
345         inc(nSource);  //lleva la cuenta
346       end;
347     end;
348     //Ya se han explorado todos los pines. Ahora analzia lso casos
349     if nSource=0 then begin
350       //Todas son resistncias
351       vt := 0;
352       rt := r0;  //Resistencia acumulada
353     end else if nResistor=0 then begin
354       //Todas son fuentes thevening
355       vt := v1;  //Voltaje acumulado
356       rt := r1;  //Resistencia acumulada
357     end else begin
358       //Caso general: Fuentes de thevening con resistencia:
359       vt := v1*r0/(r0 + r1);
360       rt := ResParallel(r0, r1);
361     end;
362   end;
363 //debugln('Nodo actualizado: %d fuentes, %d resist.', [nSource, nResistor]);
364   {Ahora que ya se tienen los valores de voltaje e impedancia del nodo, pasa esa
365   información a todos los pines de los componentes conectados, para uniformizar estados}
366   for pin in pinList do begin
367     pin.SetNodePars(vt, rt);
368   end;
369 end;
Containsnull370 function TNode.Contains(ogCon: TOgConector): boolean;
371 {Indica si el conector está en la lista de conectores del nodo.}
372 var
373   c: TOgConector;
374 begin
375   for c in connectorList do begin
376     if c = ogCon then exit(true);
377   end;
378   //No está
379   exit(false);
380 end;
ConnectedTonull381 function TNode.ConnectedTo(ogCon: TOgConector): boolean;
382 {Indica si el conector indicado, está eléctricamente conectado a este nodo.}
383 var
384   c: TOgConector;
385 begin
386   //Verifia si etsá conectado a alguno de los conectores del nodo
387   for c in connectorList do begin
388     if c.ConnectedTo(ogCon) then exit(true);
389   end;
390   //No está conectado a ningún conector
391   exit(false);
392 end;
393 procedure TNode.AddConnector(ogCon: TOgConector);
394 {Agrega un connector a la lista de conectores del nodo. Se supone que todo los
395 conectores de un nodo están eléctrticamenet conectados.}
396   procedure AddPinOf(pCtl: TPtoCtrl);
397   var
398     pin: TPinGraph;
399   begin
400     if pCtl.ConnectedTo<>nil then begin
401       if pCtl.ConnectedTo.Id = ID_PINGRAF then begin
402         pin := TPinGraph(pCtl.ConnectedTo);
403         if pinList.IndexOf(pin) = -1 then begin
404           //No existe el pin, lo agrega
405           pinList.Add(pin);
406         end;
407       end;
408     end;
409   end;
410 begin
411   connectorList.Add(ogCon);
412   ogCon.nodParent := self;  //Guarda referencia
413   //También se guardan los pines a los que se encuentra conectado
414   AddPinOf(ogCon.pcBEGIN);
415   AddPinOf(ogCon.pcEND);
416 end;
417 constructor TNode.Create;
418 begin
419   connectorList:= TConnectorList.Create(false);
420   pinList := TPicPinList.Create(false);
421 end;
422 destructor TNode.Destroy;
423 begin
424   pinList.Destroy;
425   connectorList.Destroy;
426   inherited Destroy;
427 end;
428 { TPinGraph }
429 procedure TPinGraph.GetModel(out vThev0, rThev0: Single);
430 {Devuelve el equivalente de Thevening del pin. Equivale a devolver el modelo eléctrico
431 del pin, cuando está desconectado.}
432 begin
433   if pic = nil then begin
434     //No pertenece a un PIC, lee directamente sus parámetros
435     vThev0 := vThev;
436     rThev0 := rThev;
437   end else begin
438     //Es pin de un pic
439     pic.GetPinThev(nPin, vThev0, rThev0);
440   end;
441 end;
442 procedure TPinGraph.SetModel(vThev0, rThev0: Single);
443 begin
444   if pic = nil then begin
445     //No pertenece a un PIC, lee directamente sus parámetros
446     vThev := vThev0;
447     rThev := rThev0;
448   end else begin
449     //Es pin de un pic. No se puede cambiar
450   end;
451 end;
452 procedure TPinGraph.SetNodePars(vNod0, rNod0: Single);
453 {Fija los valores de voltaje que debe tener el pin, y la impedancia que debe ver,
454 por el efecto de estar conectado a algún nodo.
455 Se supone que ya se ha hecho el cálculo de voltaje/impedancia em el nodo.}
456 begin
457   if pic = nil then begin
458     //No pertenece a un PIC
459     vNod := vNod0;
460     rNod := rNod0;
461   end else begin
462     //Es parte de un PIC
463     pic.SetNodePars(nPin, vNod0, rNod0);
464   end;
465 end;
466 procedure TPinGraph.SetLabel(xl, yl: Single; txt: string;
467                              align: TAlignment = taLeftJustify);
468 begin
469   lbl := txt;
470   yLbl := yl;
471   case align of
472   taLeftJustify: xLbl := xl;  //Justificado a la
473   taRightJustify: xLbl := xl - v2d.TextWidth(txt);
474   end
475 end;
476 constructor TPinGraph.Create(mGraf: TMotGraf);
477 begin
478   inherited Create(mGraf);
479   {Se usa un ID porque identificar un objeto por ID es más rápido que usar
480   la comparación con: <variable> IS <Alguna Clase>.}
481   id := ID_PINGRAF;
482 end;
483 { TOgComponent }
TOgComponent.AddPtoConexnull484 function TOgComponent.AddPtoConex(xOff, yOff: Single): TPinGraph;
485 {Reescribimos nuestra propia función porque no vamos a agregar objetos TPtoConx,
486 sino objetos TPinGraph.}
487 begin
488   Result := TPinGraph.Create(v2d);
489   ////// Esta sección es similar al del método virtual AddPtoConex //////
490   Result.xFac := xOff/Width;
491   Result.yFac := yOff/Height;
492   //Actualiza coordenadas absolutas
493   Result.x := x + xOff;
494   Result.y := x + yOff;
495   Result.Parent := self;
496   PtosConex.Add(Result);
497 end;
TOgComponent.AddPinnull498 function TOgComponent.AddPin(xCnx, yCnx, //Coord. del punto de conexión
499                              x1, y1, x2, y2: Single): TPinGraph;
500 var
501   pin: TPinGraph;
502 begin
503   pin := AddPtoConex(xCnx, yCnx);
504   pin.v2d := self.v2d;
505   pin.x1 := x1;
506   pin.y1 := y1;
507   pin.x2 := x2;
508   pin.y2 := y2;
509   pin.nPin := PtosConex.Count;
510   Result := pin;
511 end;
512 constructor TOgComponent.Create(mGraf: TMotGraf);
513 begin
514   Id := ID_COMPON;
515   inherited Create(mGraf);
516 end;
517 destructor TOgComponent.Destroy;
518   begin
519     inherited Destroy;
520   end;
521 { TOgConector }
522 procedure TOgConector.PCtlConnect(pCtl: TPtoCtrl; pCnx: TPtoConx);
523 {Un punto de control se conecta a un punto de conexión }
524 begin
525    if OnConnect<>nil then OnConnect();
526 end;
527 procedure TOgConector.PCtlDisconnect(pCtl: TPtoCtrl; pCnx: TPtoConx);
528 {Un punto de control se desconecta a un punto de conexión }
529 begin
530   if OnDisconnect<>nil then OnDisconnect();
531 end;
TOgConector.ConnectedTonull532 function TOgConector.ConnectedTo(ogCon: TOgConector): boolean;
533 {Verifica si hay conexión entre este conector y "ogCon"}
ConnectedSameConexionPointnull534   function ConnectedSameConexionPoint(p1, p2: TPtoCtrl): boolean;
535   {Indica si los puntos de control indicados, están conectados al mismo Punto
536   de Conexión.}
537   begin
538     if p1.ConnectedTo = nil then exit(false);  //No está conectado a nada
539     if p2.ConnectedTo = nil then exit(false);  //No está conectado a nada
540     if p1.ConnectedTo = p2.ConnectedTo then exit(true) else exit(false);
541   end;
542 begin
543   if ConnectedSameConexionPoint(pcBEGIN, ogCon.pcBEGIN) then exit(true);
544   if ConnectedSameConexionPoint(pcBEGIN, ogCon.pcEND) then exit(true);
545   if ConnectedSameConexionPoint(pcEND, ogCon.pcBEGIN) then exit(true);
546   if ConnectedSameConexionPoint(pcEND, ogCon.pcEND) then exit(true);
547   exit(false);
548 end;
IsSelectedBynull549 function TOgConector.IsSelectedBy(xr, yr: Integer): Boolean;
550 var
551   x0, y0, x1, y1: Integer;
552 begin
553   v2d.XYpant(pcBEGIN.x, pcBEGIN.y,  x0, y0);
554   v2d.XYpant(pcEND.x, pcEND.y, x1, y1);
555   Result := PointSelectSegment(xr, yr, x0, y0, x1, y1 );
556 end;
557 procedure TOgConector.Draw;
558 const
559   ANCHO1 = 7;
560   ANCHO2 = 50;
561   ALTO1 = 10;
562   ALTO2 = 30;
563 var
564   col: TColor;
565   pct  : TPtoCtrl;
566   pcn : TPtoConx;
567   x1, y1: Single;
568   pMouse: TPoint;
569 begin
570   //Descripción
571   //v2d.SetText(clBlack, 11,'', true);
572   //v2d.Texto(X + 2, Y -20, 'Conector');
573   //Cuerpo
574   col := GetThevCol(nodParent.vt, nodParent.rt);  //Se supone que el nodo padre ya está actualizado
575   v2d.SetPen(psSolid, 1, col);
576   v2d.Line(pcBEGIN.x, pcBEGIN.y, pcEND.x, pcEND.y);
577   //Implementamos nosotros el remarcado y selección, para personalizar mejor
578   //---------------Draw mark --------------
579   if Marked and Highlight then begin
580     //Resaltado
581     v2d.SetPen(psSolid, 2, clBlue);   //RGB(128, 128, 255)
582     v2d.Line(pcBEGIN.x, pcBEGIN.y, pcEND.x, pcEND.y);
583     //Marcador de Voltaje
584     v2d.SetPen(psSolid, 1, clBlack);   //RGB(128, 128, 255)
585     v2d.SetBrush(clYellow);
586     pMouse := PaintBox.ScreenToClient(Mouse.CursorPos);
587     x1 := v2d.Xvirt(pMouse.x, pMouse.y);
588     y1 := v2d.Yvirt(pMouse.x, pMouse.y);
589 //    v2d.RectangR(x1, y1, x1+10, y1+20);
590     ptos[0].x := x1;
591     ptos[0].y := y1;
592     ptos[1].x := x1+ANCHO1;
593     ptos[1].y := y1-ALTO1;
594     ptos[2].x := x1+ANCHO1;
595     ptos[2].y := y1-ALTO2;
596     ptos[3].x := x1+ANCHO2;
597     ptos[3].y := y1-ALTO2;
598     ptos[4].x := x1+ANCHO2;
599     ptos[4].y := y1-ALTO1;
600     ptos[5].x := x1+20;
601     ptos[5].y := y1-ALTO1;
602     v2d.Polygon(ptos);
603 
604     v2d.SetText(True, False, False);
605     v2d.SetText(clBlack);
606     v2d.Texto(x1+ANCHO1+3, y1 - ALTO2+2, Format('%.2fV', [nodParent.vt]));
607   end;
608   //--------------- Draw selection state--------------
609   if Selected Then begin
610     if behav = behav1D then begin
611        for pct in PtosControl1 do pct.Draw;   //Dibuja puntos de control
612     end else if behav = behav2D then begin
613        for pct in PtosControl2 do pct.Draw;   //Dibuja puntos de control
614     end;
615   end;
616   //Draw Connection Points
617   if ShowPtosConex then begin
618      for pcn in PtosConex do pcn.Draw;
619   end;
620   //if MarkConnectPoints then begin
621     for pcn in PtosConex do if pcn.Marked then pcn.Mark;
622   //end
623 end;
624 constructor TOgConector.Create(mGraf: TMotGraf);
625 begin
626   inherited Create(mGraf);
627   Id := ID_CONNEC;
628   setlength(ptos, 6);
629   pcBEGIN.OnConnect := @PCtlConnect;
630   pcEND.OnConnect := @PCtlConnect;
631   pcBEGIN.OnDisconnect := @PCtlDisconnect;
632   pcEND.OnDisconnect := @PCtlDisconnect;
633 end;
634 destructor TOgConector.Destroy;
635 begin
636   inherited Destroy;
637 end;
638 { TOgPic }
639 procedure TOgPic.SetPic(pic0: TPicCore);
640 {Fija el dispositivo de trabajo y prepara las estructuras que
641 definen la geometría del componente, de modo que el dibujo sea rápido.}
642 var
643   newHeight, i: Integer;
644   ypin: Single;
645   pin: TPinGraph;
646 begin
647   pic := pic0;  //Actualiza referencia
648   Name := pic0.Model;
649   //Define geometría del cuerpo del PIC
650   if pic.Npins <= 6 then begin
651     nPinsDiag := 6;
652   end else if pic.Npins <=8 then begin
653     nPinsDiag := 8;
654   end else if pic.Npins <=14 then begin
655     nPinsDiag := 14;
656   end else if pic.Npins <=18 then begin
657     nPinsDiag := 18;
658   end else if pic.Npins <=28 then begin
659     nPinsDiag := 28;
660   end else if pic.Npins <=40 then begin
661     nPinsDiag := 40;
662   end else begin
663     //Caso de muchos pines
664     nPinsDiag := 40;
665   end;
666   nPinsSide := nPinsDiag div 2;  //Pines pro lado
667   newHeight := nPinsSide * SEP_PIN; //Altura del chip
668   //Actualiza tamaño. Se debe hacer antes de calcular las posiciones de los Ptos. de Conexión.
669   ReSize(Width, newHeight);
670   {Calcula posiciones relativas de los pines asumiendo un formato de encapsulado DIL.
671   Se crearán también los puntos de conexión en cada uno de los pines}
672   PtosConex.Clear;  //Se aprovechará para crear puntos de conexión
673   //Pines de la izquierda
674   ypin := SEP_PIN/2;   //posición inicial
675   xpin := -LON_PIN+3;
676   for i:=1 to nPinsSide do begin
677     //Pin
678     pin := AddPin(xpin, ypin-1,
679                   xpin, ypin-5, xpin+LON_PIN+1, ypin+5);
680     pin.SetLabel(5, ypin-8, pic.pines[i].GetLabel);
681     pin.pic := pic0;  //guarda referencia el PIC
682     //pin.lValue := @;
683     //Calcula siguiente posición
684     ypin := ypin + SEP_PIN;
685   end;
686   //Pines de la derecha
687   ypin := SEP_PIN/2 + (nPinsSide-1) * SEP_PIN;   //posición inicial
688   xpin := width-3;
689   for i:=nPinsSide+1 to nPinsDiag do begin
690     //Pin
691     pin := AddPin(xpin+LON_PIN-1, ypin,
692                   xpin, ypin-5, xpin+LON_PIN-1, ypin+5);
693     pin.SetLabel(xpin-2, ypin-8, pic.pines[i].GetLabel, taRightJustify);
694     pin.pic := pic0;  //guarda referencia el PIC
695     //Calcula siguiente posición
696     ypin := ypin - SEP_PIN;
697   end;
698   //Actualiza posición.
699   Relocate(x, y);  //Se mantiene la posición, pero se hace para actualizar a los puntos de conexión
700 end;
701 procedure TOgPic.Draw;
702 const
703   RAD_MARK = 15;  //Radio de la marca superior del chip
704 var
705   ancho, rt, vt, xMed: Single;
706   pin : TPinGraph;
707   pCnx: TPtoConx;
708 begin
709   if pic= nil then begin
710     v2d.SetPen(psSolid, 1, clBlack);
711     v2d.SetBrush(clGray);
712     v2d.RectangR(x, y, x+Width, y+Height);
713   end else begin //Caso normal
714     xMed := x + width/2;
715     //Dibuja título
716     ancho := v2d.TextWidth(Name);
717     v2d.SetText(True, False, False);
718     v2d.Texto(xMed - ancho/2 , y - 18, Name);
719     //Dibuja cuerpo
720     v2d.SetText(False, False, False);
721     v2d.SetText($D0D0D0);
722     v2d.SetPen(psSolid, 1, clGray);
723     v2d.SetBrush(COL_CI);
724     v2d.RectangR(x, y, x+Width, y+Height);  //fondo
725     v2d.SetBrush($202020);
726     v2d.RadialPie(xMed-RAD_MARK ,y-RAD_MARK, xMed+RAD_MARK,y+RAD_MARK,2880,2880);
727     //Dibuja los pines
728     for pCnx in self.PtosConex do begin
729       pin := TPinGraph(pCnx);
730       //En el PIC, los pines se pintan con el color del modelo interno
731       pin.GetModel(vt, rt);
732       v2d.SetBrush(GetThevCol(vt,rt));  //Rellena de acuerdo al estado
733       v2d.rectangR(x+pin.x1, y+pin.y1, x+pin.x2, y+pin.y2);
734       v2d.Texto(x+pin.xLbl, y+pin.yLbl, pin.lbl);
735     end;
736   end;
737   inherited;
738 end;
739 constructor TOgPic.Create(mGraf: TMotGraf);
740 begin
741   inherited Create(mGraf);
742   ID := ID_PIC;
743   Width := 140;
744   Height := 180;
745 //  pcTOP_CEN.Visible := false;
746 //  pcBOT_CEN.Visible := false;
747 //  pcCEN_LEF.Visible := false;
748 //  pcCEN_RIG.Visible := false;
749   SizeLocked := true;
750 //  ShowPtosConex:=true;  //Muestra los puntos de conexión
751 end;
752 destructor TOgPic.Destroy;
753 begin
754   inherited Destroy;
755 end;
756 { TOgLogicState }
757 procedure TOgLogicState.Draw;
758 var
759   ancho: Single;
760 begin
761   //Dibuja título
762   ancho := v2d.TextWidth(Name);
763   v2d.SetText(COL_GND);
764   v2d.SetText(True, False, False);
765   v2d.Texto(x + width/2 - ancho/2 , y - 18, Name);
766   //Dibuja cuerpo
767   v2d.SetPen(psSolid, 1, clBlack);
768   if pin.vThev>2.5 then begin
769     v2d.SetBrush(clRed)
770   end else begin
771     v2d.SetBrush(clGray);
772   end;
773   //v2d.RectangR(x, y, x+Width, y+Height);
774   ptos[0].x := x;
775   ptos[0].y := y;
776   ptos[1].x := x+20;
777   ptos[1].y := y;
778   ptos[2].x := x+30;
779   ptos[2].y := y+10;
780   ptos[3].x := x+20;
781   ptos[3].y := y+20;
782   ptos[4].x := x;
783   ptos[4].y := y+20;
784   v2d.Polygon(ptos);
785   inherited;
786 end;
787 constructor TOgLogicState.Create(mGraf: TMotGraf);
788 begin
789   inherited Create(mGraf);
790   id := ID_TOG_LOG;
791   setlength(ptos, 5);
792   Width  := 30;
793   Height := 20;
794   pcTOP_CEN.Visible := false;
795   pcBOT_CEN.Visible := false;
796   pcCEN_LEF.Visible := false;
797   pcCEN_RIG.Visible := false;
798   SizeLocked := true;
799   pin := AddPin(30, 10, 0, 0, 0, 0);
800   pin.rThev :=  0;
801   pin.vThev :=  5;  //voltios
802   //ShowPtosConex:=true;
803 end;
804 destructor TOgLogicState.Destroy;
805 begin
806   inherited Destroy;
807 end;
808 { TOgLedRed }
809 procedure TOgLedRed.Draw;
810 var
811   ancho, x2, y2, yled: Single;
812 begin
813   x2:=x+width;
814   yled := y + 40;
815   y2:=y+height;
816   //Dibuja título
817   ancho := v2d.TextWidth(Name);
818   v2d.SetText(COL_GND);
819   v2d.SetText(True, False, False);
820   v2d.Texto(x + width/2 - ancho/2 , y - 18, Name);
821   //Verifica valor lógico
822 
823   //FState
824   //Dibuja cuerpo
825   v2d.SetPen(psSolid, 2, COL_GND);
826   //Línea vertioal y conexión a tierra
827   v2d.Line(x+12, y, x+12, y2);
828   v2d.Line(x+5, y2, x+19, y2);
829   //Resistencia
830   v2d.SetPen(psSolid, 1, COL_GND);
831   v2d.SetBrush(COL_RES);
832   v2d.RectangR(x+5, y+10, x2-5, y+35);
833   //Símbolo circular
834   if pin.vNod>2 then v2d.SetBrush(clRed)
835   else v2d.SetBrush(clGray);
836   v2d.Ellipse(x, yled, x+width, yled+24);
837   v2d.Ellipse(x+3, yled+3, x+width-3, yled+24-3);
838   inherited;
839 end;
840 constructor TOgLedRed.Create(mGraf: TMotGraf);
841 begin
842   inherited Create(mGraf);
843   id := ID_LEDRES;
844   Width  := 24;
845   Height := 70;
846   pcTOP_CEN.Visible := false;
847   pcBOT_CEN.Visible := false;
848   pcCEN_LEF.Visible := false;
849   pcCEN_RIG.Visible := false;
850   SizeLocked := true;
851   pin := AddPin(12, 0, 0, 0, 0, 0);
852   pin.SetModel(0, 470); //0V, 470ohms. Por ahora se modela así
853   pin.lbl := 'VLed';
854   //ShowPtosConex:=true;
855 end;
856 destructor TOgLedRed.Destroy;
857 begin
858   inherited Destroy;
859 end;
860 { TOg7Segment }
861 procedure TOg7Segment.Draw;
862 var
863   ancho, x2, y2, x1, y1, y3: Single;
864   pCnx: TPtoConx;
865   pin: TPinGraph;
866 begin
867   //Dibuja título
868   ancho := v2d.TextWidth(Name);
869   v2d.SetText(COL_GND);
870   v2d.SetText(True, False, False);
871   v2d.Texto(x + width/2 - ancho/2 , y - 18, Name);
872   //Dibuja cuerpo
873   v2d.SetPen(psSolid, 2, COL_GND);
874   v2d.SetBrush(COL_HIM);
875   v2d.RectangR(x, y, x+Width, y+Height);
876   //Segmentos
877   x1 := x +10;
878   x2 := x+width-10;
879   y1 := y + 10;
880   y2 := y + 50;
881   y3 := y + 90;
882   //Segment A
883   if pinA.vNod>2 then begin
884     v2d.SetPen(psSolid, 1, clRed); v2d.SetBrush(clRed);
885   end else begin
886     v2d.SetPen(psSolid, 1, $808080); v2d.SetBrush($808080);
887   end;
888   v2d.RectangR(x1, y1-3, x2, y1+3);
889   //Segment B
890   if pinB.vNod>2 then begin
891     v2d.SetPen(psSolid, 1, clRed); v2d.SetBrush(clRed);
892   end else begin
893     v2d.SetPen(psSolid, 1, $808080); v2d.SetBrush($808080);
894   end;
895   v2d.RectangR(x2-3, y1+3, x2+3, y2-3);
896   //Segment C
897   if pinC.vNod>2 then begin
898     v2d.SetPen(psSolid, 1, clRed); v2d.SetBrush(clRed);
899   end else begin
900     v2d.SetPen(psSolid, 1, $808080); v2d.SetBrush($808080);
901   end;
902   v2d.RectangR(x2-3, y2+3, x2+3, y3-3);
903   //Segment D
904   if pinD.vNod>2 then begin
905     v2d.SetPen(psSolid, 1, clRed); v2d.SetBrush(clRed);
906   end else begin
907     v2d.SetPen(psSolid, 1, $808080); v2d.SetBrush($808080);
908   end;
909   v2d.RectangR(x1, y3-3, x2, y3+3);
910   //Segment E
911   if pinE.vNod>2 then begin
912     v2d.SetPen(psSolid, 1, clRed); v2d.SetBrush(clRed);
913   end else begin
914     v2d.SetPen(psSolid, 1, $808080); v2d.SetBrush($808080);
915   end;
916   v2d.RectangR(x1-3, y2+3, x1+3, y3-3);
917   //Segment F
918   if pinF.vNod>2 then begin
919     v2d.SetPen(psSolid, 1, clRed); v2d.SetBrush(clRed);
920   end else begin
921     v2d.SetPen(psSolid, 1, $808080); v2d.SetBrush($808080);
922   end;
923   v2d.RectangR(x1-3, y1+3, x1+3, y2-3);
924   //Segment G
925   if pinG.vNod>2 then begin
926     v2d.SetPen(psSolid, 1, clRed); v2d.SetBrush(clRed);
927   end else begin
928     v2d.SetPen(psSolid, 1, $808080); v2d.SetBrush($808080);
929   end;
930   v2d.RectangR(x1, y2-3, x2, y2+3);
931 
932   //conexión a tierra
933   v2d.SetPen(psSolid, 1, COL_GND);
934   y2 := y + height + 10;
935   v2d.Line(x+30, y+height, x+30, y2);
936   v2d.Line(x+24, y2, x+36, y2);
937   //Dibuja los pines
938   v2d.SetPen(psSolid, 1, COL_GND);
939   for pCnx in PtosConex do begin
940     pin := TPinGraph(pCnx);
941     //En el PIC, los pines se pintan con el color del modelo interno
942     v2d.SetBrush(clWhite);  //Rellena de acuerdo al estado
943     v2d.Line(pin.x, pin.y, pin.x+7, pin.y);
944     v2d.Texto(x+pin.xLbl, y+pin.yLbl, pin.lbl);
945   end;
946   inherited;
947 end;
948 constructor TOg7Segment.Create(mGraf: TMotGraf);
949 begin
950   inherited Create(mGraf);
951   id := ID_7SEGME;
952   Width  := 60;
953   Height := 100;
954   pcTOP_CEN.Visible := false;
955   pcBOT_CEN.Visible := false;
956   pcCEN_LEF.Visible := false;
957   pcCEN_RIG.Visible := false;
958   SizeLocked := true;
959   pinA := AddPin(-7, 5, 0, 0, 0, 0);
960   pinA.SetModel(0, 680);
961   pinA.lbl := 'A';
962   pinB := AddPin(-7,20, 0, 0, 0, 0);
963   pinB.SetModel(0, 680);
964   pinB.lbl := 'B';
965   pinC := AddPin(-7,35, 0, 0, 0, 0);
966   pinC.SetModel(0, 680);
967   pinC.lbl := 'C';
968   pinD := AddPin(-7,50, 0, 0, 0, 0);
969   pinD.SetModel(0, 680);
970   pinD.lbl := 'D';
971   pinE := AddPin(-7,65, 0, 0, 0, 0);
972   pinE.SetModel(0, 680);
973   pinE.lbl := 'E';
974   pinF := AddPin(-7,80, 0, 0, 0, 0);
975   pinF.SetModel(0, 680);
976   pinF.lbl := 'F';
977   pinG := AddPin(-7,95, 0, 0, 0, 0);
978   pinG.SetModel(0, 680);
979   pinG.lbl := 'G';
980   //ShowPtosConex:=true;
981 end;
982 destructor TOg7Segment.Destroy;
983 begin
984   inherited Destroy;
985 end;
986 { TOgResisten }
987 procedure TOgResisten.Draw;
988 var
989   ancho, x2, y2: Single;
990 begin
991   x2:=x+width;
992   y2:=y+height;
993   //Dibuja título
994   ancho := v2d.TextWidth(Name);
995   v2d.SetText(COL_GND);
996   v2d.SetText(True, False, False);
997   v2d.Texto(x + width/2 - ancho/2 , y - 18, Name);
998   //Verifica valor lógico
999 
1000   //Línea vertioal y conexión a tierra
1001   v2d.SetPen(psSolid, 2, COL_GND);
1002   v2d.Line(x+12, y, x+12, y2);
1003   v2d.Line(x+5, y2, x+19, y2);
1004   //Resistencia
1005   v2d.SetPen(psSolid, 1, COL_GND);
1006   v2d.SetBrush(COL_RES);
1007   v2d.RectangR(x+5, y+20, x2-5, y+50);
1008   inherited;
1009 end;
1010 constructor TOgResisten.Create(mGraf: TMotGraf);
1011 var
1012   pin: TPinGraph;
1013 begin
1014   inherited Create(mGraf);
1015   id := ID_RESIST;
1016   Width  := 24;
1017   Height := 70;
1018   pcTOP_CEN.Visible := false;
1019   pcBOT_CEN.Visible := false;
1020   pcCEN_LEF.Visible := false;
1021   pcCEN_RIG.Visible := false;
1022   SizeLocked := true;
1023   pin := AddPin(12, 0, 0, 0, 0, 0);
1024   pin.rThev := 1000;
1025   pin.vThev := 0;
1026   //ShowPtosConex:=true;
1027 end;
1028 destructor TOgResisten.Destroy;
1029 begin
1030   inherited Destroy;
1031 end;
1032 { TfraPICDiagram }
1033 procedure TfraPICDiagram.Refrescar;
1034 var
1035   nod: TNode;
1036 begin
1037   {Aqui debería hacerse la actualización del PIC, y de los otros elementos que se mueven
1038   con reloj.}
1039   //pic.ExecNCycle()
1040   {Actualiza el estado de los Nodos porqu se supone que los voltajes o resisetncias de
1041   los componentes pueden haber cambiado (Como los pines de salida del PIC).}
1042   if nodeList <> nil then begin
1043     for nod in nodeList do begin
1044       nod.UpdateModel;
1045     end;
1046   end; //Protección
1047   motEdi.Refresh;
1048 end;
1049 procedure TfraPICDiagram.SetCompiler(cxp0: TCompilerBase);
1050 begin
1051   Fpic := cxp0.picCore;
1052   //Inicia dispositivo
1053   ogPic.SetPic(cxp0.picCore);
1054   //Al fijar el PIC, se elimina y crea un nuevo PIC,por ello hay que llamar a UpdateNodeList().
1055   UpdateNodeList;
1056 end;
1057 procedure TfraPICDiagram.fraPICDiagramKeyDown(Sender: TObject; var Key: Word;
1058   Shift: TShiftState);
1059 begin
1060   MsgBox('fraPICDiagramKeyDown');
1061 end;
1062 procedure TfraPICDiagram.ConnectAction(Sender: TObject);
1063 var
1064   mnItem: TMenuItem;
1065   oc: TOgConector;
1066   a: TStringDynArray;
1067   comp1, comp2: TOgComponent;
1068   nPin1, nPin2: LongInt;
1069   pCnx1, pCnx2: TPtoConx;
1070   pin1 , pin2: TPinGraph;
1071   id1, id2: String;
1072 begin
1073   if Sender is TMenuItem then begin
1074     mnItem := TMenuItem(Sender);
1075     //Agrega conector
1076     acAddConnExecute(self);
1077     oc := TOgConector(motEdi.Selected);
1078     //Ubica nodo Inicial
1079 //    MsgBox(mnItem.Hint);
1080     a := Explode('-', mnItem.Hint);
1081     id1 := a[0];
1082     id2 := a[1];
1083     a := Explode('.', id1);
1084     comp1 := ExistsRef(a[0]);
1085     nPin1 := StrToInt(a[1]);
1086     pCnx1 := comp1.PtosConex[nPin1-1];
1087     if not(pCnx1 is TPinGraph) then exit;
1088     pin1 := TPinGraph(pCnx1);
1089     //Ubica nodo final
1090     a := Explode('.', id2);
1091     comp2 := ExistsRef(a[0]);
1092     nPin2 := StrToInt(a[1]);
1093     pCnx2 := comp2.PtosConex[nPin2-1];
1094     if not(pCnx2 is TPinGraph) then exit;
1095     pin2 := TPinGraph(pCnx2);
1096     //Ahora se conecta el conector a los Punttos de Conexión
1097     pin1.ConnectTo(oc.pcBEGIN);
1098     pin1.Locate(pin1.x, pin1.y); //Actualiza el "enganche"
1099     pin2.ConnectTo(oc.pcEND);
1100     pin2.Locate(pin2.x, pin2.y); //Actualiza el "enganche"
1101     //oc.Selec;          //Selecciona el conector
1102     Refrescar;
1103   end;
1104 end;
1105 //Manejo de nodos
1106 procedure TfraPICDiagram.AddConnectorToNodes(ogCon: TOgConector);
1107 {Agrega un conector al nodo que corresponda (al que contiene conectores que están
1108 unidos eléctricamente a "conn"), o crea un nuevo nodo.}
1109 var
1110   nod, newNode: TNode;
1111 begin
1112   for nod in nodeList do begin
1113     if nod.Contains(ogCon) then begin
1114       //Ya lo contiene en su lista. No hay nada que hacer.
1115       exit;
1116     end else if nod.ConnectedTo(ogCon) then begin
1117       //Está eléctricamente conectado, pero no está en la lista
1118       nod.AddConnector(ogCon);  //Lo agrega
1119       exit;
1120     end;
1121   end;
1122   //No pertenece a ningún nodo existente.
1123   newNode := TNode.Create;  //Se crea con sus listas de conectores y pines vacías
1124   newNode.AddConnector(ogCon);
1125   nodeList.Add(newNode);
1126 end;
1127 procedure TfraPICDiagram.UpdateNodeList;
1128 {Actualiza la lista de nodos a partir de los conectores existentes. Esta tarea
1129 es importante para realizar el análisis correcto del voltaje e impedancia del nodo.
1130 Como esta tarea puede ser algo pesada, por optimización se debe realizar solo cuando
1131 se pueda producir cambios en los nodos (creación, eliminación, conexión y desconexión)}
1132 var
1133   og: TObjGraf;
1134   ogCon: TOgConector;
1135 begin
1136   nodeList.Clear;
1137   //Explora objetos gráfiocs
1138   for og in motEdi.objects do begin
1139     if og is TOgConector then begin
1140       ogCon := TOgConector(og);
1141       AddConnectorToNodes(ogCon);
1142     end;
1143   end;
1144 //debugln('Lista de Nodos:');
1145 //for nod in nodeList do begin
1146 //  debugln('  Nodo con '+IntToStr(nod.connectorList.Count)+' conectores.');
1147 //end;
1148 end;
ExistsNamenull1149 function TfraPICDiagram.ExistsName(AName: string): boolean;
1150 {Indica si existe algún componente con el nombre AName}
1151 var
1152   og: TObjGraf;
1153 begin
1154   for og in motEdi.objects do begin
1155     if og.Name = AName then exit(true);
1156   end;
1157   exit(false);
1158 end;
TfraPICDiagram.UniqueNamenull1159 function TfraPICDiagram.UniqueName(NameBase: string): string;
1160 {Obtiene un nombre único tomando como base la cadena "NameBase", de modo que si
1161 en "NameBase" se indica "Nombre", se generará los nombres Nombre1, Nombre2, ... }
1162 var
1163   n: Integer;
1164 begin
1165   n := 1;   //Empieza con este valor
1166   Result := NameBase + IntToStr(n);  //Nombre tentativo
1167   While ExistsName(Result) do begin
1168     Inc(n);
1169     Result := NameBase + IntToStr(n);
1170   end;
1171 end;
ExistsRefnull1172 function TfraPICDiagram.ExistsRef(ARef: string): TOgComponent;
1173 {Indica si existe algún componente con la referencia Aref. Si no existe devuelve NIL.}
1174 var
1175   og: TObjGraf;
1176 begin
1177   for og in motEdi.objects do begin
1178     if not(og is TOgComponent) then continue;
1179     if TOgComponent(og).Ref = ARef then exit(TOgComponent(og));
1180   end;
1181   exit(Nil);
1182 end;
TfraPICDiagram.UniqueRefnull1183 function TfraPICDiagram.UniqueRef(RefBase: string): string;
1184 {Obtiene una referencia única tomando como base la cadena "RefBase", de modo que si
1185 en "RefBase" se indica "R", se generará los nombres R1, R2, R3, ... }
1186 var
1187   n: Integer;
1188 begin
1189   n := 1;   //Empieza con este valor
1190   Result := RefBase + IntToStr(n);  //Nombre tentativo
1191   While ExistsRef(Result)<>nil do begin
1192     Inc(n);
1193     Result := RefBase + IntToStr(n);
1194   end;
1195 end;
1196 procedure TfraPICDiagram.motEdi_MouseDown(Sender: TObject; Button: TMouseButton;
1197   Shift: TShiftState; X, Y: Integer);
1198 var
1199   LogInp: TOgLogicState;
1200   //pCnx: TPtoConx;
1201   //oc: TOgConector;
1202   //xv, yv: Single;
1203 begin
1204   if motEdi.selection.Count = 1 then begin
1205     //Hay uno seleccionado
1206     if motEdi.Selected.IsSelectedBy(X,Y) then begin
1207       //Click sobre un objeto seleccionado
1208       if motEdi.Selected is TOgLogicState then begin
1209         LogInp := TOgLogicState(motEdi.Selected);
1210         LogInp.pin.vThev := 5;
1211         Refrescar;
1212         //MsgBox('TOggle');
1213       end;
1214     end;
1215   end;
1216   //Verifica si se inicia la conexión de un pin
1217 //  if Button = mbLeft then begin
1218 //    pCnx := motEdi.ConnectionPointMarked;
1219 //    if pCnx <> nil then begin
1220 //      //Se soltó en con un punto de conexión marcado
1221 //      oc := TOgConector.Create(motEdi.v2d);  //Crea objeto
1222 //      oc.behav := behav1D;    //De tipo conector
1223 //      motEdi.AddGraphObject(oc);  //Lo agrega al editor
1224 //      //Ahora se conecta un nodo (Punto de control) al Pto. de Conexión
1225 //      pCnx.ConnectTo(oc.pcBEGIN);
1226 //      pCnx.Locate(pCnx.x, pCnx.y); //Actualiza el "enganche"
1227 //      oc.Selec;          //Selecciona el conector
1228 //      motEdi.v2d.XYvirt(X, Y, xv, yv);  //Obtiene coordenadas del mouse
1229 //      //oc.pcEND.Locate(xv+50, yv+50);   //Posiciona Punto final del conector
1230 //      oc.pcEND.OnChangePosition(oc.pcEND, 0, 0, xv+20, yv+20);
1231 //      //oc.ReSize(oc.Width, oc.Height);
1232 //      motEdi.CapturoEvento := oc;   //Indica al motor de edición que el conector se está dimensionando
1233 //      motEdi.EstPuntero := EP_DIMEN_OBJ;  //Pone editor en modo "Dimensionando"
1234 //      motEdi.Refrescar;            //Actualiza pantalla
1235 //    end;
1236 //  end;
1237 end;
1238 procedure TfraPICDiagram.motEdi_MouseUp(Sender: TObject; Button: TMouseButton;
1239   Shift: TShiftState; X, Y: Integer);
1240 var
1241   LogInp: TOgLogicState;
1242 begin
1243   if motEdi.selection.Count = 1 then begin
1244     //Hay un componente seleccionado
1245     if motEdi.Selected.IsSelectedBy(X,Y) then begin
1246       if motEdi.Selected is TOgLogicState then begin
1247         LogInp := TOgLogicState(motEdi.Selected);
1248         LogInp.pin.vThev := 0;
1249       end;
1250     end;
1251   end;
1252 end;
1253 procedure TfraPICDiagram.motEdi_MouseUpRight(Shift: TShiftState; x, y: integer);
1254   procedure VisibActionsAdd(State: boolean);
1255   begin
1256     acAddLogTog.Visible := State;
1257     acAddLed.Visible    := State;
1258     acAddConn.Visible   := State;
1259     acAddResis.Visible  := State;
1260     acAdd7SegComC.Visible := State;
1261   end;
1262 var
1263   og: TObjGraf;
1264   it, it2: TMenuItem;
1265   pin2, pin1: TPinGraph;
1266   comp1, comp2: TOgComponent;
1267   pCnx, pCnx2: TPtoConx;
1268 begin
1269   //Verifica el estado para activar acciones
1270   acGenDelObject.Visible := motEdi.selection.Count>0;
1271   if motEdi.selection.Count = 0 then begin
1272     //Ninguno seleccionado
1273     mnReset.Visible   := true;
1274     mnRun.Visible     := true;
1275     mnStepOver.Visible:= false;
1276     //mnAddLogicTog.Visible := true;
1277     VisibActionsAdd(true);
1278   end else if (motEdi.selection.Count = 1) and (motEdi.Selected is TOgComponent) then begin
1279     //Hay un componente seleccionado
1280     comp1 := TOgComponent(motEdi.Selected);  //Componente fuente
1281     mnReset.Visible   := true;
1282     mnRun.Visible     := true;
1283     mnStepOver.Visible:= true;
1284     //mnAddLogicTog.Visible := false;
1285     VisibActionsAdd(false);
1286   end else begin
1287     //Se ha seleccionado otra cosa o hay varios seleccionados
1288     mnReset.Visible   := false;
1289     mnRun.Visible     := false;
1290     mnStepOver.Visible:= false;
1291     //mnAddLogicTog.Visible := false;
1292     VisibActionsAdd(false);
1293   end;
1294   //Verifica la funcionalidad del menú de "Conectar a"
1295   //Verifica si se está marcado un punto de Conexión
1296   pCnx := motEdi.ConnectionPointMarked;
1297   if pCnx = nil then begin
1298     mnConnect.Visible := false;
1299   end else begin
1300     mnConnect.Visible := true;
1301     //mnAddLogicTog.Visible := false;  //Para que no confunda
1302     VisibActionsAdd(false);
1303     //Ubica componente de origen
1304     if not(pCnx.Parent is TOgComponent) then exit;
1305     comp1 := TOgComponent(pCnx.Parent);
1306     pin1 := TPinGraph(pCnx); //El Pto. de Conex. debe ser un pin
1307     if (comp1 = nil) or (pin1=nil) then exit;  //Protección
1308     mnConnect.Caption := Format('Connect %s to', [pin1.lbl]);
1309     //Actualiza menú de Conexión, con objetos gráficos
1310     mnConnect.Clear;
1311     for og in motEdi.objects do begin
1312       if not(og is TOgComponent) then continue;
1313       if og is TOgConector then continue;;
1314       it := AddItemToMenu(mnConnect, og.Name, nil);
1315       comp2 := TOgComponent(og);
1316       for pCnx2 in comp2.PtosConex do begin
1317         pin2 := TPinGraph(pCnx2);
1318         if pin2.lbl = 'NC' then continue;  //No conectado
1319         if pin2 = nil then continue;
1320         it2 := AddItemToMenu(it, pin2.lbl, @ConnectAction);
1321         it2.Hint := comp1.Ref + '.' + IntToStr(pin1.nPin)+'-'+
1322                     comp2.Ref + '.' + IntToStr(pin2.nPin);
1323       end;
1324     end;
1325   end;
1326   //Muestra
1327   PopupMenu1.PopUp;
1328 end;
1329 constructor TfraPICDiagram.Create(AOwner: TComponent);
1330 begin
1331   inherited Create(AOwner);
1332   //crea motor de edición
1333   motEdi := TEditionMot.Create(PaintBox1);
1334   nodeList := TNodeList.Create(true);
1335   //agrega objeto
1336   ogPic := TOgPic.Create(motEdi.v2d);
1337   ogPic.Ref := 'CI1';
1338   ogPic.Highlight := false;
1339 
1340   motEdi.AddGraphObject(ogPic);
1341   OnKeyDown := @fraPICDiagramKeyDown;
1342   motEdi.OnMouseDownLeft := @motEdi_MouseDown;
1343   motEdi.OnMouseUp       := @motEdi_MouseUp;
1344   motEdi.OnMouseUpRight  := @motEdi_MouseUpRight;
1345 end;
1346 destructor TfraPICDiagram.Destroy;
1347 begin
1348   nodeList.Destroy;
1349   {Marca "nodeList" en NIL porque cuando se destruye "motEdi", si es que hay connectores,
1350   unidos a algún componente, estos intentarán llamar a "UpdateNodeList", cuando se
1351   desconecten, al momento de destruirse, y "UpdateNodeList" intentaría acceder a "nodeList"}
1352   nodeList := nil;
1353   motEdi.Destroy;
1354   inherited Destroy;
1355 end;
1356 procedure TfraPICDiagram.connectorChange;
1357 begin
1358   if nodeList = nil then exit;  //Protección
1359   UpdateNodeList;
1360 end;
1361 /////////////////////// Acciones /////////////////////////
1362 procedure TfraPICDiagram.acGenConnToExecute(Sender: TObject);
1363 {Connecta el Pin de un objeto a otro.
1364 No se implementa aquí porque se implementa de forma dinámica.}
1365 begin
1366 end;
1367 procedure TfraPICDiagram.acAddLogTogExecute(Sender: TObject);
1368 {Agrega un Objeto Gráfico LogicToggle}
1369 var
1370   logTog: TOgLogicState;
1371 begin
1372   logTog := TOgLogicState.Create(motEdi.v2d);
1373   logTog.Highlight := false;
1374   logTog.Name := UniqueName('Logic');
1375   logTog.Ref := UniqueRef('LG');  //Genera nombe único
1376   motEdi.AddGraphObject(logTog);
1377   logTog.Selec;
1378   Refrescar;
1379 end;
1380 procedure TfraPICDiagram.acAddResisExecute(Sender: TObject);
1381 {Agrega un Objeto Gráfico Resistencia}
1382 var
1383   res: TOgResisten;
1384 begin
1385   res := TOgResisten.Create(motEdi.v2d);
1386   res.Highlight := false;
1387   res.Name := UniqueName('R');
1388   res.Ref := UniqueRef('R');  //Genera nombe único
1389   motEdi.AddGraphObject(res);
1390   res.Selec;
1391   Refrescar;
1392 end;
1393 procedure TfraPICDiagram.acAddLedExecute(Sender: TObject);
1394 {Agrega un Objeto Gráfico Led}
1395 var
1396   led: TOgLedRed;
1397 begin
1398   led := TOgLedRed.Create(motEdi.v2d);
1399   led.Highlight := false;
1400   led.Name := UniqueName('Led');
1401   led.Ref := UniqueRef('D');  //Genera nombe único
1402   motEdi.AddGraphObject(led);
1403   led.Selec;
1404   Refrescar;
1405 end;
1406 procedure TfraPICDiagram.acAddConnExecute(Sender: TObject);
1407 var
1408   conn: TOgConector;
1409 begin
1410   conn :=  TOgConector.Create(motEdi.v2d);
1411   conn.behav := behav1D;    //De tipo conector
1412   //conn.Highlight := false;
1413   conn.Name := UniqueName('Connector');
1414   conn.Ref := UniqueRef('CN');  //Genera nombe único
1415   conn.OnConnect := @connectorChange;
1416   conn.OnDisconnect := @connectorChange;
1417   conn.PaintBox := PaintBox1;  //Necesita esta referencia
1418   motEdi.AddGraphObject(conn);
1419   conn.Selec;
1420   UpdateNodeList;
1421   Refrescar;
1422 end;
1423 procedure TfraPICDiagram.acAdd7SegComCExecute(Sender: TObject);
1424 {Agrega un Objeto "Display" de 7 segmentos}
1425 var
1426   led: TOg7Segment;
1427 begin
1428   led := TOg7Segment.Create(motEdi.v2d);
1429   led.Highlight := false;
1430   led.Name := UniqueName('V7S');
1431   led.Ref := UniqueRef('V7S');  //Genera nombe único
1432   motEdi.AddGraphObject(led);
1433   led.Selec;
1434   Refrescar;
1435 end;
1436 procedure TfraPICDiagram.acGenDelObjectExecute(Sender: TObject);
1437 {Elimina un Objeto Gráfico.}
1438 begin
1439   if ogPic.Selected then begin
1440     MsgExc('Cannot delete PIC device.');
1441     ogPic.Deselec;
1442   end;
1443   //Elimina elementos seleccionados
1444   motEdi.DeleteSelected;
1445   UpdateNodeList;
1446 end;
1447 procedure TfraPICDiagram.acGenReconnExecute(Sender: TObject);
1448 {Reconecta componentes del diagrama, de acuerdo a las coordenadas de los conectores.}
1449 var
1450   og: TObjGraf;
1451   ogCon: TOgConector;
1452   xp, yp: Integer;
1453   selPntCnx: TPtoConx;
1454 begin
1455   nodeList.Clear;
1456   //Explora objetos gráfiocs
1457   for og in motEdi.objects do begin
1458     if og is TOgConector then begin
1459       ogCon := TOgConector(og);
1460       if ogCon.pcBEGIN.ConnectedTo = nil then begin
1461         motEdi.v2d.XYpant(ogCon.pcBEGIN.x, ogCon.pcBEGIN.y, xp, yp);
1462         selPntCnx := motEdi.SelectPointOfConexion(xp, yp, 2);
1463         if selPntCnx <> nil then selPntCnx.ConnectTo(ogCon.pcBEGIN);
1464       end;
1465       if ogCon.pcEND.ConnectedTo = nil then begin
1466         motEdi.v2d.XYpant(ogCon.pcEND.x, ogCon.pcEND.y, xp, yp);
1467         selPntCnx := motEdi.SelectPointOfConexion(xp, yp, 2);
1468         if selPntCnx <> nil then selPntCnx.ConnectTo(ogCon.pcEND);
1469       end;
1470     end;
1471   end;
1472   UpdateNodeList;
1473 end;
1474 
1475 end.
1476 
1477