2 using System
.Collections
;
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);
17 private static bool ConnectionAnimation
= Config
.Get("schematic/connectionanimation", true);
19 internal new class Action
28 public static Mode m
= Mode
.Normal
;
29 public static object data
;
32 internal enum Connection
39 private Statusbar status
;
40 private ArrayList blocks
= new ArrayList();
41 private static int aa
= 10;
42 private object selected
= null;
43 private int tmpx
, tmpy
;
45 public ArrayList Blocks
47 get { return blocks; }
50 public static void CheckGConf()
52 bool NewAntialias
= Config
.Get("schematic/antialias", true);
53 bool NewChangeBackground
= Config
.Get("schematic/changebackground", false);
54 int NewRed
= Config
.Get("schematic/red", 128);
55 int NewGreen
= Config
.Get("schematic/green", 128);
56 int NewBlue
= Config
.Get("schematic/blue", 128);
57 int NewAlpha
= Config
.Get("schematic/alpha", 255);
58 bool NewConnectionAnimation
= Config
.Get("schematic/connectionanimation", true);
61 Antialias
!= NewAntialias
||
62 ChangeBackground
!= NewChangeBackground
||
63 BackgroundRed
!= NewRed
||
64 BackgroundGreen
!= NewGreen
||
65 BackgroundBlue
!= NewBlue
||
66 BackgroundAlpha
!= NewAlpha
||
67 ConnectionAnimation
!= NewConnectionAnimation
;
69 Antialias
= NewAntialias
;
70 ChangeBackground
= NewChangeBackground
;
71 BackgroundRed
= NewRed
;
72 BackgroundGreen
= NewGreen
;
73 BackgroundBlue
= NewBlue
;
74 BackgroundAlpha
= NewAlpha
;
75 ConnectionAnimation
= NewConnectionAnimation
;
78 MainWindow
.RedrawSchematic();
81 public Schematic(Statusbar status
) : base()
85 // FIXME hardcoded working space size
86 SetSizeRequest(2048, 2048);
88 Events
|= Gdk
.EventMask
.PointerMotionMask
| Gdk
.EventMask
.ButtonPressMask
| Gdk
.EventMask
.ButtonReleaseMask
89 | Gdk
.EventMask
.LeaveNotifyMask
;
92 protected override bool OnExposeEvent(Gdk
.EventExpose args
)
94 Context c
= Gdk
.Context
.CreateDrawable(this.GdkWindow
);
97 c
.Antialias
= Cairo
.Antialias
.Gray
;
99 c
.Antialias
= Cairo
.Antialias
.None
;
103 ((IDisposable
) c
.Target
).Dispose();
104 ((IDisposable
) c
).Dispose();
109 private object CheckSelection(int x
, int y
)
111 foreach(Block b
in new ReverseIterator(blocks
))
113 object o
= b
.Overlap(x
, y
);
122 private Connection
CheckConnection(Socket
from, Socket to
)
124 if(to
.Type
== Socket
.T
.Out
)
125 return Connection
.None
;
127 if(IsGoodConnection(from, to
))
128 return Connection
.Good
;
130 return Connection
.Bad
;
133 private bool IsGoodConnection(Socket
from, Socket to
)
136 if(from.Parent
== to
.Parent
)
138 // something is already connected to the socket
142 IPlugin fp
= from.Parent
.Plugin
;
143 IPlugin tp
= to
.Parent
.Plugin
;
145 foreach(string mOut
in fp
.MatchOut
)
148 ArrayList matches
= new ArrayList();
151 while(tmp
.LastIndexOf('/') != -1)
153 int lastIndex
= tmp
.LastIndexOf('/');
154 tmp
= tmp
.Substring(0, lastIndex
);
159 foreach(string mIn
in tp
.MatchIn
)
161 if(matches
.Contains(mIn
))
169 protected override bool OnMotionNotifyEvent(Gdk
.EventMotion args
)
171 if(Action
.m
== Action
.Mode
.Normal
)
173 object oldselected
= selected
;
175 selected
= CheckSelection((int)args
.X
, (int)args
.Y
);
177 if(oldselected
!= selected
)
181 if(selected
is Block
)
182 status
.Push(1, String
.Format(Catalog
.GetString("{0} block selected"), (selected
as Block
).Plugin
.Info
.Name
));
183 else if(selected
is Socket
)
185 Socket s
= selected
as Socket
;
186 IPlugin p
= s
.Parent
.Plugin
;
188 if(s
.Type
== Socket
.T
.In
)
189 status
.Push(1, String
.Format(Catalog
.GetString("{0} block, input socket {1}. {2}"),
190 p
.Info
.Name
, s
.Num
, p
.DescIn(s
.Num
)));
192 status
.Push(1, String
.Format(Catalog
.GetString("{0} block, output socket {1}. {2}"),
193 p
.Info
.Name
, s
.Num
, p
.DescOut(s
.Num
)));
199 else if(Action
.m
== Action
.Mode
.Move
)
201 int dx
= (int)args
.X
- tmpx
;
202 int dy
= (int)args
.Y
- tmpy
;
204 (selected
as Block
).Move(dx
, dy
);
210 else if(Action
.m
== Action
.Mode
.Connect
)
215 object tmp
= CheckSelection((int)args
.X
, (int)args
.Y
);
218 Action
.data
= CheckConnection(selected
as Socket
, tmp
as Socket
);
220 Action
.data
= Connection
.None
;
228 protected override bool OnButtonPressEvent(Gdk
.EventButton args
)
233 object selected
= _t
.selected
;
235 object tmp
= CheckSelection((int)args
.X
, (int)args
.Y
);
237 if(selected
!= null && selected
== tmp
)
239 if(selected
is Block
)
241 Block b
= selected
as Block
;
245 if(args
.Type
== Gdk
.EventType
.ButtonPress
)
247 status
.Push(1, Catalog
.GetString("Move block to desired location"));
249 // move clicked block to the top
250 if(blocks
[blocks
.Count
-1] != selected
)
252 blocks
.Remove(selected
);
253 blocks
.Add(selected
);
257 Action
.m
= Action
.Mode
.Move
;
261 else if(args
.Type
== Gdk
.EventType
.TwoButtonPress
)
263 Action
.m
= Action
.Mode
.Normal
;
265 if(b
.Plugin
is IOutPlugin
&& b
.Plugin
.WorkDone
)
269 (b
.Plugin
as IOutPlugin
).DisplayResults();
275 new PluginError(e
, b
, true);
278 else if(b
.Plugin
.HasSetup
)
288 new PluginError(e
, b
, true);
293 else if(args
.Button
== 3)
297 status
.Push(1, String
.Format(Catalog
.GetString("{0} menu"), b
.Plugin
.Info
.Name
));
299 Action
.m
= Action
.Mode
.Normal
;
303 if(b
.Plugin
is IOutPlugin
)
305 mi
= new ImageMenuItem(Catalog
.GetString("Display _results"));
306 mi
.Image
= new Image(null, "system-search.png");
307 mi
.Activated
+= PluginResults
;
308 if(!b
.Plugin
.WorkDone
)
309 mi
.Sensitive
= false;
313 if(b
.Plugin
.HasSetup
)
315 mi
= new ImageMenuItem(Catalog
.GetString("_Setup"));
316 mi
.Image
= new Image(null, "preferences-desktop.png");
317 mi
.Activated
+= PluginSetup
;
321 if(b
.Plugin
.HasSetup
|| b
.Plugin
is IOutPlugin
)
322 m
.Append(new SeparatorMenuItem());
324 mi
= new ImageMenuItem(Catalog
.GetString("D_isconnect all"));
325 mi
.Image
= new Image(null, "edit-cut.png");
326 mi
.Activated
+= delegate(object sender
, EventArgs eargs
)
331 status
.Push(1, Catalog
.GetString("Removed all block's connections"));
335 mi
= new ImageMenuItem(Catalog
.GetString("In_validate"));
336 mi
.Image
= new Image(null, "user-trash-full.png");
337 if(b
.CheckState() != Block
.State
.Good
)
338 mi
.Sensitive
= false;
339 mi
.Activated
+= delegate(object sender
, EventArgs eargs
)
344 status
.Push(1, Catalog
.GetString("Invalidated results"));
348 mi
= new ImageMenuItem(Catalog
.GetString("_Delete"));
349 mi
.Image
= new Image(null, "edit-delete.png");
350 mi
.Activated
+= delegate(object sender
, EventArgs eargs
)
353 blocks
.Remove(selected
);
357 status
.Push(1, String
.Format(Catalog
.GetString("Deleted {0} block"), b
.Plugin
.Info
.Name
));
361 m
.Append(new SeparatorMenuItem());
363 mi
= new ImageMenuItem(Catalog
.GetString("_About"));
364 mi
.Image
= new Image(null, "help-browser.png");
365 mi
.Activated
+= delegate(object sender
, EventArgs eargs
) { new PluginAbout(b.Plugin); }
;
372 else if(selected
is Socket
)
374 Socket s
= selected
as Socket
;
378 if(s
.Type
== Socket
.T
.Out
)
381 status
.Push(1, Catalog
.GetString("Connect block with another"));
382 Action
.m
= Action
.Mode
.Connect
;
383 Action
.data
= Connection
.None
;
391 if(args
.Button
== 1 && args
.Type
== Gdk
.EventType
.TwoButtonPress
)
393 status
.Push(1, Catalog
.GetString("Removed connection"));
397 else if(args
.Button
== 3)
400 ImageMenuItem mi
= new ImageMenuItem(Catalog
.GetString("_Disconnect"));
401 mi
.Image
= new Image(null, "edit-cut.png");
402 mi
.Activated
+= delegate(object sender
, EventArgs eargs
)
408 _t
.status
.Push(1, Catalog
.GetString("Removed connection"));
420 Action
.m
= Action
.Mode
.Normal
;
428 private void PluginSetup(object sender
, EventArgs args
)
432 (selected
as Block
).Plugin
.Setup();
436 (selected
as Block
).ShowError
= true;
438 new PluginError(e
, selected
as Block
, true);
442 private void PluginResults(object sender
, EventArgs args
)
446 ((selected
as Block
).Plugin
as IOutPlugin
).DisplayResults();
450 (selected
as Block
).ShowError
= true;
452 new PluginError(e
, selected
as Block
, true);
456 protected override bool OnButtonReleaseEvent(Gdk
.EventButton args
)
461 if(Action
.m
!= Action
.Mode
.Normal
)
464 Action
.m
= Action
.Mode
.Normal
;
466 if(selected
is Socket
)
468 Socket
from = selected
as Socket
;
470 selected
= CheckSelection((int)args
.X
, (int)args
.Y
);
472 if(selected
is Socket
)
474 Socket to
= selected
as Socket
;
476 if(CheckConnection(from, to
) == Connection
.Good
)
478 status
.Push(1, Catalog
.GetString("Connected blocks"));
489 public void Add(IPlugin plugin
)
491 Context c
= Gdk
.Context
.CreateDrawable(this.GdkWindow
);
493 blocks
.Add(new Block(this, c
, plugin
, 10, aa
));
495 ((IDisposable
) c
.Target
).Dispose();
496 ((IDisposable
) c
).Dispose();
504 public void Load(ArrayList blocks
)
506 this.blocks
= blocks
;
514 blocks
= new ArrayList();
520 public void Draw(Context c
)
524 if(MainWindow
.HaveAlpha
)
525 c
.Color
= new Color(BackgroundRed
/255.0, BackgroundGreen
/255.0, BackgroundBlue
/255.0, BackgroundAlpha
/255.0);
527 c
.Color
= new Color(BackgroundRed
/255.0, BackgroundGreen
/255.0, BackgroundBlue
/255.0, 1.0);
529 c
.Operator
= Operator
.Source
;
531 c
.Operator
= Operator
.Over
;
534 foreach(Block b
in blocks
)
537 foreach(Block b
in blocks
)
538 b
.DrawConnections(c
);
540 if(Action
.m
== Action
.Mode
.Connect
)
542 c
.Color
= new Color(0, 0, 0, 0.75);
543 c
.SetDash(new double[2] {4,2}
, 0);
545 c
.MoveTo(tmpx
, tmpy
);
546 c
.LineTo((selected
as Socket
).PX
+ 6.5, (selected
as Socket
).PY
+ 5);
549 c
.SetDash(new double[0] {}, 0);
550 switch((Connection
)Action
.data
)
552 case Connection
.None
:
553 c
.Color
= new Color(1, 1, 1, 0.8);
554 c
.Arc(tmpx
, tmpy
, 4, 0, 2*Math
.PI
);
557 case Connection
.Good
:
558 c
.Color
= new Color(0.3, 1, 0.3, 0.8);
559 if(ConnectionAnimation
)
560 c
.Arc(tmpx
, tmpy
, 7 + Math
.Sin(DateTime
.Now
.Ticks
/1000000.0d
), 0, 2*Math
.PI
);
562 c
.Arc(tmpx
, tmpy
, 7, 0, 2*Math
.PI
);
566 c
.Color
= new Color(1, 0.3, 0.3, 0.8);
567 if(ConnectionAnimation
)
568 c
.Arc(tmpx
, tmpy
, 7 + Math
.Sin(DateTime
.Now
.Ticks
/500000.0d
) * 1.5f
, 0, 2*Math
.PI
);
570 c
.Arc(tmpx
, tmpy
, 7, 0, 2*Math
.PI
);
574 switch((Connection
)Action
.data
)
576 case Connection
.None
:
578 c
.Color
= new Color(0, 0, 0);
581 case Connection
.Good
:
583 c
.Color
= new Color(0, 0.5, 0);
588 c
.Color
= new Color(0.5, 0, 0);
593 if(ConnectionAnimation
)
594 GLib
.Timeout
.Add(200, new GLib
.TimeoutHandler(AnimTick
));
603 private bool AnimTick()