- add progress to Euclid
[FaRetSys.git] / Schematic.cs
blob09e47582d168fff6640408e11ac14dc3a1191f95
1 using System;
2 using System.Collections;
3 using Cairo;
4 using Gtk;
5 using Mono.Unix;
7 namespace Eithne
9 class Schematic : DrawingArea
11 private static bool Antialias = Config.Get("schematic/antialias", true);
12 private static bool ChangeBackground = Config.Get("schematic/changebackground", false);
13 private static int BackgroundRed = Config.Get("schematic/red", 128);
14 private static int BackgroundGreen = Config.Get("schematic/green", 128);
15 private static int BackgroundBlue = Config.Get("schematic/blue", 128);
16 private static int BackgroundAlpha = Config.Get("schematic/alpha", 255);
18 internal new class Action
20 public enum Mode
22 Normal,
23 Move,
24 Connect
27 public static Mode m = Mode.Normal;
28 public static object data;
31 internal enum Connection
33 None,
34 Good,
35 Bad
38 private Statusbar status;
39 private ArrayList blocks = new ArrayList();
40 private static int aa = 10;
41 private object selected = null;
42 private int tmpx, tmpy;
44 public ArrayList Blocks
46 get { return blocks; }
49 public static void CheckGConf()
51 bool NewAntialias = Config.Get("schematic/antialias", true);
52 bool NewChangeBackground = Config.Get("schematic/changebackground", false);
53 int NewRed = Config.Get("schematic/red", 128);
54 int NewGreen = Config.Get("schematic/green", 128);
55 int NewBlue = Config.Get("schematic/blue", 128);
56 int NewAlpha = Config.Get("schematic/alpha", 255);
58 bool redraw =
59 Antialias != NewAntialias ||
60 ChangeBackground != NewChangeBackground ||
61 BackgroundRed != NewRed ||
62 BackgroundGreen != NewGreen ||
63 BackgroundBlue != NewBlue ||
64 BackgroundAlpha != NewAlpha;
66 Antialias = NewAntialias;
67 ChangeBackground = NewChangeBackground;
68 BackgroundRed = NewRed;
69 BackgroundGreen = NewGreen;
70 BackgroundBlue = NewBlue;
71 BackgroundAlpha = NewAlpha;
73 if(redraw)
74 MainWindow.RedrawSchematic();
77 public Schematic(Statusbar status) : base()
79 this.status = status;
81 // FIXME wpisany na sztywno rozmiar obszaru roboczego
82 SetSizeRequest(2048, 2048);
84 Events |= Gdk.EventMask.PointerMotionMask | Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask
85 | Gdk.EventMask.LeaveNotifyMask;
88 protected override bool OnExposeEvent(Gdk.EventExpose args)
90 Context c = Gdk.Context.CreateDrawable(this.GdkWindow);
92 if(Antialias)
93 c.Antialias = Cairo.Antialias.Gray;
94 else
95 c.Antialias = Cairo.Antialias.None;
97 Draw(c);
99 ((IDisposable) c.Target).Dispose();
100 ((IDisposable) c).Dispose();
102 return true;
105 private object CheckSelection(int x, int y)
107 foreach(Block b in new ReverseIterator(blocks))
109 object o = b.Overlap(x, y);
111 if(o != null)
112 return o;
115 return null;
118 private Connection CheckConnection(Socket from, Socket to)
120 if(to.Type == Socket.T.Out)
121 return Connection.None;
122 else
123 if(IsGoodConnection(from, to))
124 return Connection.Good;
125 else
126 return Connection.Bad;
129 private bool IsGoodConnection(Socket from, Socket to)
131 // ten sam blok
132 if(from.Parent == to.Parent)
133 return false;
134 // do gniazda już jest coś podłączone
135 if(to.Other != null)
136 return false;
138 IPlugin fp = from.Parent.Plugin;
139 IPlugin tp = to.Parent.Plugin;
141 foreach(string mOut in fp.MatchOut)
143 string tmp = mOut;
144 ArrayList matches = new ArrayList();
145 matches.Add(tmp);
147 while(tmp.LastIndexOf('/') != -1)
149 int lastIndex = tmp.LastIndexOf('/');
150 tmp = tmp.Substring(0, lastIndex);
151 matches.Add(tmp);
153 matches.Add("");
155 foreach(string mIn in tp.MatchIn)
157 if(matches.Contains(mIn))
158 return true;
162 return false;
165 protected override bool OnMotionNotifyEvent(Gdk.EventMotion args)
167 if(Action.m == Action.Mode.Normal)
169 object oldselected = selected;
171 selected = CheckSelection((int)args.X, (int)args.Y);
173 if(oldselected != selected)
175 status.Pop(1);
177 if(selected is Block)
178 status.Push(1, String.Format(Catalog.GetString("{0} block selected"), (selected as Block).Plugin.Info.Name));
179 else if(selected is Socket)
181 Socket s = selected as Socket;
182 IPlugin p = s.Parent.Plugin;
184 if(s.Type == Socket.T.In)
185 status.Push(1, String.Format(Catalog.GetString("{0} block, input socket {1}. {2}"),
186 p.Info.Name, s.Num, p.DescIn(s.Num)));
187 else
188 status.Push(1, String.Format(Catalog.GetString("{0} block, output socket {1}. {2}"),
189 p.Info.Name, s.Num, p.DescOut(s.Num)));
192 QueueDraw();
195 else if(Action.m == Action.Mode.Move)
197 int dx = (int)args.X - tmpx;
198 int dy = (int)args.Y - tmpy;
200 (selected as Block).Move(dx, dy);
201 QueueDraw();
203 tmpx = (int)args.X;
204 tmpy = (int)args.Y;
206 else if(Action.m == Action.Mode.Connect)
208 tmpx = (int)args.X;
209 tmpy = (int)args.Y;
211 object tmp = CheckSelection((int)args.X, (int)args.Y);
213 if(tmp is Socket)
214 Action.data = CheckConnection(selected as Socket, tmp as Socket);
215 else
216 Action.data = Connection.None;
218 QueueDraw();
221 return true;
224 protected override bool OnButtonPressEvent(Gdk.EventButton args)
226 status.Pop(1);
228 Schematic _t = this;
229 object selected = _t.selected;
231 object tmp = CheckSelection((int)args.X, (int)args.Y);
233 if(selected != null && selected == tmp)
235 if(selected is Block)
237 Block b = selected as Block;
239 if(args.Button == 1)
241 if(args.Type == Gdk.EventType.ButtonPress)
243 status.Push(1, Catalog.GetString("Move block to desired location"));
245 // przeniesienie klikniętego bloku na wierzch
246 if(blocks[blocks.Count-1] != selected)
248 blocks.Remove(selected);
249 blocks.Add(selected);
250 QueueDraw();
253 Action.m = Action.Mode.Move;
254 tmpx = (int)args.X;
255 tmpy = (int)args.Y;
257 else if(args.Type == Gdk.EventType.TwoButtonPress)
259 Action.m = Action.Mode.Normal;
261 if(b.Plugin is IOutPlugin && b.Plugin.WorkDone)
265 (b.Plugin as IOutPlugin).DisplayResults();
267 catch(Exception e)
269 b.ShowError = true;
270 QueueDraw();
271 new PluginError(e, b, true);
274 else if(b.Plugin.HasSetup)
278 b.Plugin.Setup();
280 catch(Exception e)
282 b.ShowError = true;
283 QueueDraw();
284 new PluginError(e, b, true);
289 else if(args.Button == 3)
291 ImageMenuItem mi;
293 status.Push(1, String.Format(Catalog.GetString("{0} menu"), b.Plugin.Info.Name));
295 Action.m = Action.Mode.Normal;
297 Menu m = new Menu();
299 if(b.Plugin is IOutPlugin)
301 mi = new ImageMenuItem(Catalog.GetString("Display _results"));
302 mi.Image = new Image(null, "system-search.png");
303 mi.Activated += PluginResults;
304 if(!b.Plugin.WorkDone)
305 mi.Sensitive = false;
306 m.Append(mi);
309 if(b.Plugin.HasSetup)
311 mi = new ImageMenuItem(Catalog.GetString("_Setup"));
312 mi.Image = new Image(null, "preferences-desktop.png");
313 mi.Activated += PluginSetup;
314 m.Append(mi);
317 if(b.Plugin.HasSetup || b.Plugin is IOutPlugin)
318 m.Append(new SeparatorMenuItem());
320 mi = new ImageMenuItem(Catalog.GetString("D_isconnect all"));
321 mi.Image = new Image(null, "edit-cut.png");
322 mi.Activated += delegate(object sender, EventArgs eargs)
324 b.Disconnect();
325 QueueDraw();
326 status.Pop(1);
327 status.Push(1, Catalog.GetString("Removed all block's connections"));
329 m.Append(mi);
331 mi = new ImageMenuItem(Catalog.GetString("In_validate"));
332 mi.Image = new Image(null, "user-trash-full.png");
333 if(b.CheckState() != Block.State.Good)
334 mi.Sensitive = false;
335 mi.Activated += delegate(object sender, EventArgs eargs)
337 b.Invalidate();
339 status.Pop(1);
340 status.Push(1, Catalog.GetString("Invalidated results"));
342 m.Append(mi);
344 mi = new ImageMenuItem(Catalog.GetString("_Delete"));
345 mi.Image = new Image(null, "edit-delete.png");
346 mi.Activated += delegate(object sender, EventArgs eargs)
348 b.Disconnect();
349 blocks.Remove(selected);
350 QueueDraw();
352 status.Pop(1);
353 status.Push(1, String.Format(Catalog.GetString("Deleted {0} block"), b.Plugin.Info.Name));
355 m.Append(mi);
357 m.Append(new SeparatorMenuItem());
359 mi = new ImageMenuItem(Catalog.GetString("_About"));
360 mi.Image = new Image(null, "help-browser.png");
361 mi.Activated += delegate(object sender, EventArgs eargs) { new PluginAbout(b.Plugin); };
362 m.Append(mi);
364 m.ShowAll();
365 m.Popup();
368 else if(selected is Socket)
370 Socket s = selected as Socket;
372 if(s.Other == null)
374 if(s.Type == Socket.T.Out)
375 if(args.Button == 1)
377 status.Push(1, Catalog.GetString("Connect block with another"));
378 Action.m = Action.Mode.Connect;
379 Action.data = Connection.None;
380 tmpx = (int)args.X;
381 tmpy = (int)args.Y;
382 QueueDraw();
385 else
387 if(args.Button == 1 && args.Type == Gdk.EventType.TwoButtonPress)
389 status.Push(1, Catalog.GetString("Removed connection"));
390 s.Disconnect();
391 QueueDraw();
393 else if(args.Button == 3)
395 Menu m = new Menu();
396 ImageMenuItem mi = new ImageMenuItem(Catalog.GetString("_Disconnect"));
397 mi.Image = new Image(null, "edit-cut.png");
398 mi.Activated += delegate(object sender, EventArgs eargs)
400 s.Disconnect();
401 _t.QueueDraw();
403 _t.status.Pop(1);
404 _t.status.Push(1, Catalog.GetString("Removed connection"));
406 m.Append(mi);
408 m.ShowAll();
409 m.Popup();
414 else
416 Action.m = Action.Mode.Normal;
417 selected = tmp;
418 QueueDraw();
421 return true;
424 private void PluginSetup(object sender, EventArgs args)
428 (selected as Block).Plugin.Setup();
430 catch(Exception e)
432 (selected as Block).ShowError = true;
433 QueueDraw();
434 new PluginError(e, selected as Block, true);
438 private void PluginResults(object sender, EventArgs args)
442 ((selected as Block).Plugin as IOutPlugin).DisplayResults();
444 catch(Exception e)
446 (selected as Block).ShowError = true;
447 QueueDraw();
448 new PluginError(e, selected as Block, true);
452 protected override bool OnButtonReleaseEvent(Gdk.EventButton args)
454 if(args.Button != 1)
455 return true;
457 if(Action.m != Action.Mode.Normal)
458 status.Pop(1);
460 Action.m = Action.Mode.Normal;
462 if(selected is Socket)
464 Socket from = selected as Socket;
466 selected = CheckSelection((int)args.X, (int)args.Y);
468 if(selected is Socket)
470 Socket to = selected as Socket;
472 if(CheckConnection(from, to) == Connection.Good)
474 status.Push(1, Catalog.GetString("Connected blocks"));
475 from.Connect(to);
479 QueueDraw();
482 return true;
485 public void Add(IPlugin plugin)
487 Context c = Gdk.Context.CreateDrawable(this.GdkWindow);
489 blocks.Add(new Block(this, c, plugin, 10, aa));
491 ((IDisposable) c.Target).Dispose();
492 ((IDisposable) c).Dispose();
494 aa += 50;
495 if(aa > 400)
496 aa = 10;
497 QueueDraw();
500 public void Load(ArrayList blocks)
502 this.blocks = blocks;
503 aa = 10;
504 selected = null;
505 QueueDraw();
508 public void Clear()
510 blocks = new ArrayList();
511 aa = 10;
512 selected = null;
513 QueueDraw();
516 private void Draw(Context c)
518 if(ChangeBackground)
520 if(MainWindow.HaveAlpha)
521 c.Color = new Color(BackgroundRed/255.0, BackgroundGreen/255.0, BackgroundBlue/255.0, BackgroundAlpha/255.0);
522 else
523 c.Color = new Color(BackgroundRed/255.0, BackgroundGreen/255.0, BackgroundBlue/255.0, 1.0);
525 c.Operator = Operator.Source;
526 c.Paint();
527 c.Operator = Operator.Over;
530 foreach(Block b in blocks)
531 b.Draw(c, selected);
533 foreach(Block b in blocks)
534 b.DrawConnections(c);
536 if(Action.m == Action.Mode.Connect)
538 c.Color = new Color(0, 0, 0, 0.5);
539 // c.SetDash(new double[1] {5}, 0);
540 c.LineWidth = 1.0;
541 c.MoveTo((selected as Socket).PX + 6.5, (selected as Socket).PY + 5);
542 c.LineTo(tmpx, tmpy);
543 c.Stroke();
545 // c.SetDash(new double[0] {}, 0);
546 switch((Connection)Action.data)
548 case Connection.None:
549 c.Color = new Color(1, 1, 1, 0.8);
550 c.Arc(tmpx, tmpy, 4, 0, 2*Math.PI);
551 break;
553 case Connection.Good:
554 c.Color = new Color(0.3, 1, 0.3, 0.8);
555 c.Arc(tmpx, tmpy, 7, 0, 2*Math.PI);
556 break;
558 case Connection.Bad:
559 c.Color = new Color(1, 0.3, 0.3, 0.8);
560 c.Arc(tmpx, tmpy, 7, 0, 2*Math.PI);
561 break;
563 c.FillPreserve();
564 switch((Connection)Action.data)
566 case Connection.None:
567 c.LineWidth = 1.5;
568 c.Color = new Color(0, 0, 0);
569 break;
571 case Connection.Good:
572 c.LineWidth = 3.0;
573 c.Color = new Color(0, 0.5, 0);
574 break;
576 case Connection.Bad:
577 c.LineWidth = 3.0;
578 c.Color = new Color(0.5, 0, 0);
579 break;
581 c.Stroke();
585 public void Redraw()
587 QueueDraw();