Merge branch 'master' into new.io.matching
[FaRetSys.git] / Block.cs
blobb6f1f5e1f7c064b3092582e8acbb993769051af2
1 using System;
2 using System.IO;
3 using System.Reflection;
4 using Cairo;
6 namespace Eithne
8 class Socket
10 private readonly int num;
11 private int x, y;
12 private readonly Block parent;
13 private readonly T type;
14 private Socket other;
16 public enum T
18 In,
19 Out
22 public int X
24 get { return x; }
27 public int Y
29 get { return y; }
30 set { y = value; }
33 public int PX
35 get { return parent.X + x; }
38 public int PY
40 get { return parent.Y + y; }
43 public Block Parent
45 get { return parent; }
48 public T Type
50 get { return type; }
53 public Socket Other
55 get { return other; }
58 public int Num
60 get { return num; }
63 public Socket(int x, int y, Block parent, T type, int num)
65 this.x = x;
66 this.y = y;
67 this.parent = parent;
68 this.type = type;
69 this.num = num;
71 other = null;
74 public void Draw(Context c)
76 int xc = parent.X + x;
77 int yc = parent.Y + y + 5;
79 if(other == null)
81 if(type == T.Out)
83 c.Arc(xc+6.5, yc, 4, 0, 2*Math.PI);
84 c.Color = new Color(0.2, 0.2, 1, 0.6);
85 c.Fill();
88 else
90 int r = 6;
92 if(type == T.Out)
93 xc += 7;
94 else
95 xc += 3;
97 c.Arc(xc, yc, r, 0, 2*Math.PI);
98 c.Color = new Color(1, 0, 0);
99 c.LineWidth = 2.5;
100 c.FillPreserve();
101 c.Color = new Color(0.3, 0, 0);
102 c.Stroke();
103 c.MoveTo(xc-0.707*r, yc-0.707*r);
104 c.LineTo(xc+0.707*r, yc+0.707*r);
105 c.Stroke();
106 c.MoveTo(xc-0.707*r, yc+0.707*r);
107 c.LineTo(xc+0.707*6, yc-0.707*6);
108 c.Stroke();
112 public void Disconnect()
114 if(other != null)
116 if(type == T.In)
117 parent.Invalidate();
118 else
119 other.parent.Invalidate();
121 other.other = null;
122 other = null;
126 public void Connect(Socket to)
128 Disconnect();
129 to.Disconnect();
131 other = to;
132 to.other = this;
136 class Block : IBlock
138 private readonly IPlugin plugin;
139 private readonly Schematic schematic;
140 private int x, y;
141 private int h = 0, w = 0, th = 0;
142 private int tx = 0, ty = 0;
143 private int sx = 0, sy = 0;
144 private int cx = 0, cy = 0;
145 private Socket[] socketin = null;
146 private Socket[] socketout = null;
147 private bool working = false;
148 private bool showerror = false;
150 private static ImageSurface StateBad = new ImageSurface(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data/state-bad.png"));
151 private static ImageSurface StateGood = new ImageSurface(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data/state-good.png"));
152 private static ImageSurface StateNotReady = new ImageSurface(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data/state-not-ready.png"));
153 private static ImageSurface StateReady = new ImageSurface(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data/state-ready.png"));
154 private static ImageSurface Clock = new ImageSurface(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data/clock.png"));
156 private static bool ConfigGradient = Config.Get("block/gradient", true);
157 private static bool ConfigInner = Config.Get("block/innerpath", true);
158 private static bool ConfigRound = Config.Get("block/round", true);
159 private static bool ConfigSmoothConnections = Config.Get("block/smoothconnections", true);
161 public enum State
163 Good,
164 Bad,
165 NotReady,
166 Ready
169 public bool ShowError
171 set { showerror = value; }
174 public IPlugin Plugin
176 get { return plugin; }
179 public int X
181 get { return x; }
184 public int Y
186 get { return y; }
189 public Socket[] SocketIn
191 get { return socketin; }
194 public Socket[] SocketOut
196 get { return socketout; }
199 public bool Working
201 get { return working; }
202 set { working = value; }
205 public Block(Schematic s, Context c, IPlugin plugin, int x, int y)
207 this.schematic = s;
208 this.plugin = plugin;
209 this.x = x;
210 this.y = y;
212 plugin.Block = this;
214 UpdateCoordinates(c);
216 socketin = new Socket[plugin.NumIn];
217 socketout = new Socket[plugin.NumOut];
219 int curpos = 10+(h-20-CalcHeight(plugin.NumIn))/2;
220 for(int i=0; i<plugin.NumIn; i++)
222 socketin[i] = new Socket(0, curpos, this, Socket.T.In, i);
223 curpos += 15;
226 curpos = 10+(h-20-CalcHeight(plugin.NumOut))/2;
227 for(int i=0; i<plugin.NumOut; i++)
229 socketout[i] = new Socket(w-10, curpos, this, Socket.T.Out, i);
230 curpos += 15;
234 public static void CheckGConf()
236 bool NewConfigGradient = Config.Get("block/gradient", true);
237 bool NewConfigInner = Config.Get("block/innerpath", true);
238 bool NewConfigRound = Config.Get("block/round", true);
239 bool NewConfigSmoothConnections = Config.Get("block/smoothconnections", true);
241 bool redraw =
242 ConfigGradient != NewConfigGradient ||
243 ConfigInner != NewConfigInner ||
244 ConfigRound != NewConfigRound ||
245 ConfigSmoothConnections != NewConfigSmoothConnections;
247 ConfigGradient = NewConfigGradient;
248 ConfigInner = NewConfigInner;
249 ConfigRound = NewConfigRound;
250 ConfigSmoothConnections = NewConfigSmoothConnections;
252 if(redraw)
253 MainWindow.RedrawSchematic();
256 public object Overlap(int x, int y)
258 if(x < this.x || x > this.x + w || y < this.y || y > this.y + h)
259 return null;
261 if(x < this.x + 10)
262 // porty wejściowe
264 int curpos = this.y+10+(h-20-CalcHeight(socketin.Length))/2;
266 for(int i=0; i<socketin.Length; i++)
268 if(y > curpos && y < curpos + 10)
269 return socketin[i];
271 curpos += 15;
274 else if(x > this.x + w - 10)
276 // porty wyjściowe
277 int curpos = this.y+10+(h-20-CalcHeight(socketout.Length))/2;
279 for(int i=0; i<socketout.Length; i++)
281 if(y > curpos && y < curpos + 10)
282 return socketout[i];
284 curpos += 15;
288 return this;
291 // FIXME wpisany na sztywno rozmiar obszaru roboczego
292 public void Move(int dx, int dy)
294 x += dx;
295 y += dy;
297 if(x < 0)
298 x = 0;
299 else if(x+w >= 2048)
300 x = 2048-w;
302 if(y < 0)
303 y = 0;
304 else if(y+h >= 2048)
305 y = 2048-h;
308 // usuwa wszystkie połączenia
309 public void Disconnect()
311 for(int i=0; i<socketin.Length; i++)
312 socketin[i].Disconnect();
314 for(int i=0; i<socketout.Length; i++)
315 socketout[i].Disconnect();
318 // wykonywane po zmianie liczby slotów we wtyczce
319 private void UpdateCoordinates()
321 int h1 = CalcHeight(plugin.NumIn);
322 int h2 = CalcHeight(plugin.NumOut);
324 // rozmiar bloku
325 h = Math.Max(Math.Max(th, h1), h2) + 20;
327 // położenie tekstu
328 ty = h/2 + th/2;
330 if(ty > h-15)
331 ty = h-15;
333 // położenie stanu
334 if(plugin is ConnectorPlugin)
335 sy = h/2 - 4;
336 else
337 sy = h - 11;
339 // położenie zegarka
340 cy = h/2 - 16;
343 // wykonywane tylko raz, przez konstruktor
344 private void UpdateCoordinates(Context c)
346 TextExtents t = c.TextExtents(plugin.Info.ShortName);
348 th = (int)t.Height;
350 // rozmiar bloku
351 w = (int)t.Width + 30;
353 // położenie tekstu
354 tx = 15;
356 // położenie stanu
357 if(plugin is ConnectorPlugin)
358 sx = w/2 - 4;
359 else
360 sx = w/2 - 3;
362 // położenie zegarka
363 cx = w/2 - 16;
365 UpdateCoordinates();
368 public void Draw(Context c, object selected)
370 DrawSockets(c);
372 if(this == selected || (selected is Socket && (selected as Socket).Parent == this))
373 DrawBlock(c, true);
374 else
375 DrawBlock(c, false);
377 DrawState(c);
378 if(working)
379 DrawClock(c);
381 if(selected is Socket)
383 for(int i=0; i<socketin.Length; i++)
384 if(socketin[i] == selected)
386 socketin[i].Draw(c);
387 return;
390 for(int i=0; i<socketout.Length; i++)
391 if(socketout[i] == selected)
393 socketout[i].Draw(c);
394 return;
398 if(showerror)
400 c.Color = new Color(1, 0, 0, 0.5);
401 DrawPath(c);
402 c.Fill();
406 public State CheckState()
408 for(int i=0; i<socketin.Length; i++)
409 if(SocketIn[i].Other == null)
410 return State.NotReady;
412 if(Plugin.WorkDone)
413 return State.Good;
415 if(WorkPossible())
416 return State.Ready;
417 else
418 return State.Bad;
421 public bool WorkPossible()
423 for(int i=0; i<socketin.Length; i++)
424 if(socketin[i].Other.Parent.CheckState() != State.Good)
425 return false;
427 return true;
430 private void DrawClock(Context c)
432 c.Save();
433 c.Translate(x + cx, y + cy);
434 Clock.Show(c, 0, 0);
435 c.Stroke();
436 c.Restore();
439 private void DrawState(Context c)
441 State s = CheckState();
443 c.Color = new Color(1, 1, 1);
444 c.Save();
445 c.Translate(x + sx, y + sy);
447 if(s == State.NotReady)
448 StateNotReady.Show(c, 0, 0);
449 else if(s == State.Bad)
450 StateBad.Show(c, 0, 0);
451 else if(s == State.Good)
452 StateGood.Show(c, 0, 0);
453 else
454 StateReady.Show(c, 0, 0);
456 c.Stroke();
457 c.Restore();
460 private void DrawBlockGradient(Context c)
462 LinearGradient g = new LinearGradient(0, y, 0, y+h);
463 if(plugin is IInPlugin)
465 g.AddColorStop(0, new Color(0.65, 0.85, 1.00, 0.85));
466 g.AddColorStop(0.33, new Color(0.45, 0.65, 1.00, 0.85));
467 g.AddColorStop(1, new Color(0.20, 0.50, 0.80, 0.85));
469 else if(plugin is IOutPlugin)
471 g.AddColorStop(0, new Color(1.00, 0.85, 1.00, 0.85));
472 g.AddColorStop(0.33, new Color(1.00, 0.65, 1.00, 0.85));
473 g.AddColorStop(1, new Color(0.80, 0.40, 0.80, 0.85));
475 else if(plugin is IImgProcPlugin)
477 g.AddColorStop(0, new Color(0.75, 1.00, 0.75, 0.85));
478 g.AddColorStop(0.33, new Color(0.55, 1.00, 0.55, 0.85));
479 g.AddColorStop(1, new Color(0.30, 0.80, 0.30, 0.85));
481 else if(plugin is IResProcPlugin)
483 g.AddColorStop(0, new Color(1.00, 0.75, 0.75, 0.85));
484 g.AddColorStop(0.33, new Color(1.00, 0.55, 0.55, 0.85));
485 g.AddColorStop(1, new Color(0.80, 0.30, 0.30, 0.85));
487 else if(plugin is IComparatorPlugin)
489 g.AddColorStop(0, new Color(1.00, 1.00, 0.75, 0.85));
490 g.AddColorStop(0.33, new Color(1.00, 1.00, 0.55, 0.85));
491 g.AddColorStop(1, new Color(0.80, 0.80, 0.30, 0.85));
493 else if(plugin is IOtherPlugin)
495 g.AddColorStop(0, new Color(0.7, 0.7, 0.7, 0.85));
496 g.AddColorStop(0.33, new Color(0.5, 0.5, 0.5, 0.85));
497 g.AddColorStop(1, new Color(0.35, 0.35, 0.35, 0.85));
500 DrawPath(c);
501 c.Pattern = g;
502 c.FillPreserve();
505 private void DrawBlockNoGradient(Context c)
507 if(plugin is IInPlugin)
508 c.Color = new Color(0.35, 0.55, 0.95, 0.85);
509 else if(plugin is IOutPlugin)
510 c.Color = new Color(0.95, 0.55, 0.95, 0.85);
511 else if(plugin is IImgProcPlugin)
512 c.Color = new Color(0.45, 0.95, 0.45, 0.85);
513 else if(plugin is IResProcPlugin)
514 c.Color = new Color(0.95, 0.45, 0.45, 0.85);
515 else if(plugin is IComparatorPlugin)
516 c.Color = new Color(0.95, 0.95, 0.45, 0.85);
517 else if(plugin is IOtherPlugin)
518 c.Color = new Color(0.5, 0.5, 0.5, 0.85);
520 DrawPath(c);
521 c.FillPreserve();
524 private void DrawBlock(Context c, bool IsSelected)
526 if(ConfigGradient)
527 DrawBlockGradient(c);
528 else
529 DrawBlockNoGradient(c);
531 if(showerror)
532 c.Color = new Color(1, 0, 0);
533 else if(IsSelected)
534 c.Color = new Color(0.2, 0.2, 1);
535 else
536 c.Color = new Color(0, 0, 0);
538 c.LineWidth = 2.0;
540 c.Stroke();
542 if(ConfigInner)
544 c.Color = new Color(1, 1, 1, 0.5);
545 c.LineWidth = 1;
546 DrawPathInner(c);
547 c.Stroke();
550 c.Color = new Color(0, 0, 0);
552 c.Save();
553 c.Translate(x + tx, y + ty);
554 c.ShowText(plugin.Info.ShortName);
555 c.Stroke();
556 c.Restore();
559 private void DrawSockets(Context c)
561 int curpos = y+10+(h-20-CalcHeight(socketout.Length))/2;
563 for(int i=0; i<socketout.Length; i++)
565 if(socketout[i].Other == null)
567 c.LineWidth = 1.5;
568 c.Arc(x+w-3, curpos+5, 4, 0, 2*Math.PI);
569 c.Color = new Color(1, 1, 1, 0.8);
570 c.FillPreserve();
571 c.Color = new Color(0, 0, 0);
572 c.Stroke();
574 else
576 c.LineWidth = 2.0;
577 c.MoveTo(x+w, curpos);
579 if(ConfigRound)
580 c.CurveTo(x+w-10, curpos, x+w-10, curpos+10, x+w, curpos+10);
581 else
583 c.LineTo(x+w-8, curpos);
584 c.LineTo(x+w-8, curpos+10);
585 c.LineTo(x+w, curpos+10);
588 c.LineTo(x+w, curpos);
589 c.Color = new Color(1, 1, 1, 0.8);
590 c.Fill();
591 c.MoveTo(x+w, curpos);
592 c.LineTo(x+w, curpos+10);
593 c.Color = new Color(0, 0, 0);
594 c.Stroke();
597 curpos += 15;
600 curpos = y+10+(h-20-CalcHeight(socketin.Length))/2;
602 for(int i=0; i<socketin.Length; i++)
604 if(socketin[i].Other != null)
606 c.LineWidth = 2.0;
607 c.MoveTo(x, curpos);
609 if(ConfigRound)
610 c.CurveTo(x+10, curpos, x+10, curpos+10, x, curpos+10);
611 else
613 c.LineTo(x+8, curpos);
614 c.LineTo(x+8, curpos+10);
615 c.LineTo(x, curpos+10);
618 c.LineTo(x, curpos);
619 c.Color = new Color(1, 1, 1, 0.8);
620 c.Fill();
621 c.MoveTo(x, curpos);
622 c.LineTo(x, curpos+10);
623 c.Color = new Color(0, 0, 0);
624 c.Stroke();
627 curpos += 15;
631 public void DrawConnections(Context c)
633 int curpos = y+15+(h-20-CalcHeight(socketout.Length))/2;
635 c.LineWidth = 1.0;
636 c.Color = new Color(0, 0, 0);
637 for(int i=0; i<socketout.Length; i++)
639 if(socketout[i].Other != null)
641 c.MoveTo(x+w, curpos);
643 if(ConfigSmoothConnections)
644 c.CurveTo(x+w+10, curpos, socketout[i].Other.PX-10, socketout[i].Other.PY+5, socketout[i].Other.PX, socketout[i].Other.PY+5);
645 else
646 c.LineTo(socketout[i].Other.PX, socketout[i].Other.PY+5);
648 c.Stroke();
651 curpos += 15;
655 private int CalcHeight(int sockets)
657 return Math.Max(sockets*10 + (sockets-1)*5, 0);
660 private void DrawPath(Context c)
662 if(ConfigRound)
663 DrawPathRound(c);
664 else
665 DrawPathSquare(c);
668 private void DrawPathRound(Context c)
670 // 1-------2
671 // | |
672 // | |
673 // 4-------3
675 // 1
676 c.MoveTo(x+10, y);
677 c.LineTo(x+w-10, y);
678 // 2
679 c.CurveTo(x+w, y, x+w, y, x+w, y+10);
681 // gniazda wyjściowe
682 if(socketout.Length == 0)
683 c.LineTo(x+w, y+h-10);
684 else
686 int curpos = y+10+(h-20-CalcHeight(socketout.Length))/2;
688 c.LineTo(x+w, curpos);
690 for(int i=0; i<socketout.Length; i++)
692 if(i!=0)
694 curpos += 5;
695 c.LineTo(x+w, curpos);
698 c.CurveTo(x+w-10, curpos, x+w-10, curpos+10, x+w, curpos+10);
699 curpos += 10;
702 c.LineTo(x+w,y+h-10);
705 // 3
706 c.CurveTo(x+w, y+h, x+w, y+h, x+w-10, y+h);
707 c.LineTo(x+10, y+h);
708 // 4
709 c.CurveTo(x, y+h, x, y+h, x, y+h-10);
711 // gniazda wejściowe
712 if(socketin.Length == 0)
713 c.LineTo(x, y+10);
714 else
716 int curpos = y+h-10-(h-20-CalcHeight(socketin.Length))/2;
718 c.LineTo(x, curpos);
720 for(int i=0; i<socketin.Length; i++)
722 if(i!=0)
724 curpos -= 5;
725 c.LineTo(x, curpos);
728 c.CurveTo(x+10, curpos, x+10, curpos-10, x, curpos-10);
729 curpos -= 10;
732 c.LineTo(x,y+10);
735 // 1
736 c.CurveTo(x, y, x, y, x+10, y);
739 private void DrawPathSquare(Context c)
741 // 1-------2
742 // | |
743 // | |
744 // 4-------3
746 // 1
747 c.MoveTo(x, y);
748 c.LineTo(x+w, y);
750 // 2
751 // gniazda wyjściowe
752 if(socketout.Length == 0)
753 c.LineTo(x+w, y+h);
754 else
756 int curpos = y+10+(h-20-CalcHeight(socketout.Length))/2;
758 c.LineTo(x+w, curpos);
760 for(int i=0; i<socketout.Length; i++)
762 if(i!=0)
764 curpos += 5;
765 c.LineTo(x+w, curpos);
768 c.LineTo(x+w-8, curpos);
769 c.LineTo(x+w-8, curpos+10);
770 c.LineTo(x+w, curpos+10);
772 curpos += 10;
775 c.LineTo(x+w,y+h);
778 // 3
779 c.LineTo(x, y+h);
781 // 4
782 // gniazda wejściowe
783 if(socketin.Length == 0)
784 c.LineTo(x, y);
785 else
787 int curpos = y+h-10-(h-20-CalcHeight(socketin.Length))/2;
789 c.LineTo(x, curpos);
791 for(int i=0; i<socketin.Length; i++)
793 if(i!=0)
795 curpos -= 5;
796 c.LineTo(x, curpos);
799 c.LineTo(x+8, curpos);
800 c.LineTo(x+8, curpos-10);
801 c.LineTo(x, curpos-10);
803 curpos -= 10;
806 c.LineTo(x,y+10);
810 c.LineTo(x, y);
811 c.LineTo(x+1, y);
814 private void DrawPathInner(Context c)
816 if(ConfigRound)
817 DrawPathInnerRound(c);
818 // TODO
819 // else
820 // DrawPathInnerSquare(c);
824 private void DrawPathInnerRound(Context c)
826 // 1-------2
827 // | |
828 // | |
829 // 4-------3
831 // 1
832 c.MoveTo(x+11.5, y+1.5);
833 c.LineTo(x+w-11.5, y+1.5);
834 // 2
835 c.CurveTo(x+w-1.5, y+1.5, x+w-1.5, y+1.5, x+w-1.5, y+8.5);
837 // gniazda wyjściowe
838 if(socketout.Length == 0)
839 c.LineTo(x+w-1.5, y+h-11.5);
840 else
842 int curpos = y+10+(h-20-CalcHeight(socketout.Length))/2;
844 c.LineTo(x+w-1.5, curpos-1.5);
846 for(int i=0; i<socketout.Length; i++)
848 if(i!=0)
850 curpos += 5;
851 c.LineTo(x+w-1.5, curpos-1.5);
854 c.CurveTo(x+w-11.5, curpos-1.5, x+w-11.5, curpos+11.5, x+w-1.5, curpos+11.5);
855 curpos += 10;
858 c.LineTo(x+w-1.5, y+h-8.5);
861 // 3
862 c.CurveTo(x+w-1.5, y+h-1.5, x+w-1.5, y+h-1.5, x+w-11.5, y+h-1.5);
863 c.LineTo(x+11.5, y+h-1.5);
864 // 4
865 c.CurveTo(x+1.5, y+h-1.5, x+1.5, y+h-1.5, x+1.5, y+h-8.5);
867 // gniazda wejściowe
868 if(socketin.Length == 0)
869 c.LineTo(x+1.5, y+11.5);
870 else
872 int curpos = y+h-10-(h-20-CalcHeight(socketin.Length))/2;
874 c.LineTo(x+1.5, curpos+1.5);
876 for(int i=0; i<socketin.Length; i++)
878 if(i!=0)
880 curpos -= 5;
881 c.LineTo(x+1.5, curpos+1.5);
884 c.CurveTo(x+11.5, curpos+1.5, x+11.5, curpos-11.5, x+1.5, curpos-11.5);
885 curpos -= 10;
888 c.LineTo(x+1.5, y+8.5);
891 // 1
892 c.CurveTo(x+1.5, y+1.5, x+1.5, y+1.5, x+11.5, y+1.5);
895 private void Invalidate(bool x)
897 Plugin.WorkDone = false;
898 Plugin.Invalidate();
900 for(int i=0; i<socketout.Length; i++)
902 Socket o = socketout[i].Other;
904 if(o != null && o.Parent.CheckState() == State.Good)
905 o.Parent.Invalidate(true);
909 public void Invalidate()
911 Invalidate(true);
912 schematic.QueueDraw();
915 public void SlotsChanged()
917 UpdateCoordinates();
919 if(socketin.Length != plugin.NumIn)
921 Socket[] newsocketin = new Socket[plugin.NumIn];
922 int curpos = 10+(h-20-CalcHeight(plugin.NumIn))/2;
924 for(int i=0; i<plugin.NumIn; i++)
926 if(i < socketin.Length)
927 newsocketin[i] = socketin[i];
928 else
929 newsocketin[i] = new Socket(0, curpos, this, Socket.T.In, i);
930 curpos += 15;
932 for(int i=plugin.NumIn; i<socketout.Length; i++)
933 socketout[i].Disconnect();
935 socketin = newsocketin;
937 else
939 int curpos = 10+(h-20-CalcHeight(socketin.Length))/2;
941 for(int i=0; i<socketin.Length; i++)
943 socketin[i].Y = curpos;
944 curpos += 15;
948 if(socketout.Length != plugin.NumOut)
950 Socket[] newsocketout = new Socket[plugin.NumOut];
951 int curpos = 10+(h-20-CalcHeight(plugin.NumOut))/2;
953 for(int i=0; i<plugin.NumOut; i++)
955 if(i < socketout.Length)
956 newsocketout[i] = socketout[i];
957 else
958 newsocketout[i] = new Socket(w-10, curpos, this, Socket.T.Out, i);
959 curpos += 15;
961 for(int i=plugin.NumOut; i<socketout.Length; i++)
962 socketout[i].Disconnect();
964 socketout = newsocketout;
966 else
968 int curpos = 10+(h-20-CalcHeight(socketout.Length))/2;
970 for(int i=0; i<socketout.Length; i++)
972 socketout[i].Y = curpos;
973 curpos += 15;
977 schematic.QueueDraw();
978 Invalidate();