(empty log message)
@@ -0,0 +1,1654 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.ComponentModel; | |
4 | +using System.Data; | |
5 | +using System.Drawing; | |
6 | +using System.Linq; | |
7 | +using System.Text; | |
8 | +using System.Windows.Forms; | |
9 | +using System.IO; | |
10 | +using System.Diagnostics; | |
11 | +using System.Reflection; | |
12 | +using System.Drawing.Drawing2D; | |
13 | +using System.Drawing.Imaging; | |
14 | +using System.Threading; | |
15 | +using Sgry.Azuki; | |
16 | +using Sgry.Azuki.Highlighter; | |
17 | + | |
18 | +namespace sqwriter | |
19 | +{ | |
20 | + public partial class FormMain : Form | |
21 | + { | |
22 | + const int kRecentFileCountMax = 10; | |
23 | + const int kFileOpenRetryTime = 100; | |
24 | + const int kGridSpanX = 50; | |
25 | + const int kGridSpanY = 50; | |
26 | + const int kDefaultZoomIndex = 3; | |
27 | + readonly float[] ZoomScales = new float[] { | |
28 | + 0.25F, 0.5F, 0.75F, 1.0F, | |
29 | + 1.5F, 2.0F, 3.0F, 4.0F, | |
30 | + }; | |
31 | + enum JumpAlignment | |
32 | + { | |
33 | + Top, | |
34 | + Middle, | |
35 | + Bottom | |
36 | + } | |
37 | + | |
38 | + // | |
39 | + // Public properties | |
40 | + // | |
41 | + | |
42 | + public ViewPanel ViewPanel { get; private set; } | |
43 | + public ListView SectionList { get; private set; } | |
44 | + public ListView LaneList { get; private set; } | |
45 | + public MotionContoller MotionController { get; private set; } | |
46 | + public bool Grid | |
47 | + { | |
48 | + get { return grid; } | |
49 | + set | |
50 | + { | |
51 | + this.grid = value; | |
52 | + this.ViewPanel.Invalidate(); | |
53 | + } | |
54 | + } | |
55 | + bool DebugMode | |
56 | + { | |
57 | + get { return this.debugMode; } | |
58 | + set | |
59 | + { | |
60 | + this.debugMode = value; | |
61 | + if( this.debugMode ) | |
62 | + { | |
63 | + this.formDebug.Show( this ); | |
64 | + this.formDebug.Location = new Point( this.Right, this.Top ); | |
65 | + this.formDebug.Height = this.Height; | |
66 | + this.Activate(); | |
67 | + this.toolStripStatusLabelMode.Text = "[Debug mode]"; | |
68 | + } | |
69 | + else | |
70 | + { | |
71 | + this.formDebug.Hide(); | |
72 | + this.toolStripStatusLabelMode.Text = ""; | |
73 | + } | |
74 | + this.ViewPanel.Invalidate(); | |
75 | + } | |
76 | + } | |
77 | + | |
78 | + // | |
79 | + // Public methods | |
80 | + // | |
81 | + | |
82 | + public FormMain() | |
83 | + { | |
84 | + InitializeComponent(); | |
85 | + | |
86 | + this.MotionController = new MotionContoller(); | |
87 | + this.MotionController.ParamUpdate += new MotionContoller.ParamUpdateEventHandler( this.viewMotioner_ParamUpdate ); | |
88 | + | |
89 | + this.gridPen = new Pen( Color.FromArgb( 240, 240, 240 ), 1.0F ); | |
90 | + this.borderLinePen = new Pen( Color.Black, 1.0F ); // 線幅はあとで再設定 | |
91 | + this.debugLayoutLinePen = new Pen( Color.OrangeRed, 3.0F ); | |
92 | + this.foregroundBrush = new SolidBrush( Color.Black ); | |
93 | + this.backgroundBrush = new SolidBrush( Color.White ); | |
94 | + this.sourcecodeBrush = new SolidBrush( Color.LightBlue ); | |
95 | + this.sourcecodeFont = new Font( SystemFonts.MessageBoxFont.FontFamily.Name, 10.0F ); | |
96 | + this.linenoFont = new Font( SystemFonts.MessageBoxFont.FontFamily.Name, 12.0F ); | |
97 | + this.vectorScrollPen = new Pen( Color.Black, 4.0F ); | |
98 | + this.vectorScrollPen.EndCap = LineCap.ArrowAnchor; | |
99 | + this.errorBackgroundBrush = new SolidBrush( Color.FromArgb( 200, Color.Black ) ); | |
100 | + this.errorTextBrush = new SolidBrush( Color.OrangeRed ); | |
101 | + this.errorTextFont = new Font( SystemFonts.MessageBoxFont.FontFamily.Name, 10.0F ); | |
102 | + | |
103 | + this.SizeChanged += ( o, ea ) => { this.needLayouting = true; }; | |
104 | + this.DragEnter += ( o, ea ) => { ea.Effect = DragDropEffects.Copy; }; | |
105 | + this.DragDrop += ( o, ea ) => | |
106 | + { | |
107 | + if( ea.Data.GetDataPresent( DataFormats.FileDrop ) ) | |
108 | + { | |
109 | + string sourcePath = ((string[])ea.Data.GetData( DataFormats.FileDrop ))[0]; | |
110 | + if( this.LoadFile( sourcePath ) ) | |
111 | + { | |
112 | + this.AddRecentFile( sourcePath ); | |
113 | + } | |
114 | + } | |
115 | + }; | |
116 | + this.Shown += ( o, ea ) => | |
117 | + { | |
118 | + this.formDebug = new FormDebug(); | |
119 | + this.DebugMode = this.debugMode; | |
120 | + this.ViewPanel.Focus(); | |
121 | + }; | |
122 | + | |
123 | + this.Size = DefaultFormSize; | |
124 | + | |
125 | + this.SetupControls(); | |
126 | + | |
127 | + // 設定保持ファイル | |
128 | + this.setting = Setting.Load( "sqwriter.config" ); | |
129 | + if( this.setting.RecentFileList == null ) | |
130 | + { | |
131 | + this.setting.RecentFileList = new List<Setting.RecentFile>(); | |
132 | + } | |
133 | + while( this.setting.RecentFileList.Count > kRecentFileCountMax ) | |
134 | + { | |
135 | + this.setting.RecentFileList.RemoveAt( this.setting.RecentFileList.Count - 1 ); | |
136 | + } | |
137 | + this.UpdateOpenFileList(); | |
138 | + | |
139 | + this.SetupEditor(); | |
140 | + | |
141 | + string[] args = System.Environment.GetCommandLineArgs(); | |
142 | + if( args.Length >= 2 ) | |
143 | + { | |
144 | + if( LoadFile( args[1] ) ) | |
145 | + { | |
146 | + this.AddRecentFile( args[1] ); | |
147 | + } | |
148 | + } | |
149 | + } | |
150 | + | |
151 | + private void FormMain_Load( object sender, EventArgs e ) | |
152 | + { | |
153 | + } | |
154 | + | |
155 | + void SetupControls() | |
156 | + { | |
157 | + | |
158 | + Util.TraverseControls( this, ( c ) => c.Font = SystemFonts.MessageBoxFont ); | |
159 | + | |
160 | + this.ViewPanel = new ViewPanel(); | |
161 | + this.ViewPanel.Name = "ViewPanel"; | |
162 | + this.ViewPanel.Text = "Main view"; | |
163 | + this.ViewPanel.Dock = DockStyle.Fill; | |
164 | + this.ViewPanel.BorderStyle = BorderStyle.FixedSingle; | |
165 | + this.ViewPanel.Draw += new ViewPanel.ViewDrawEventHandler( viewPanel_Draw ); | |
166 | + this.ViewPanel.MouseDown += new MouseEventHandler( this.viewPanel_MouseDown ); | |
167 | + this.ViewPanel.MouseUp += new MouseEventHandler( this.viewPanel_MouseUp ); | |
168 | + this.ViewPanel.MouseLeave += new EventHandler( this.viewPanel_MouseLeave ); | |
169 | + this.ViewPanel.MouseMove += this.viewPanel_MouseMove; | |
170 | + this.ViewPanel.PreviewKeyDown += ( o, ea ) => { this.formShortcutKey.NotifyKeyDown( this.ViewPanel, ea ); }; | |
171 | + | |
172 | + this.splitContainer1.SplitterDistance = this.ClientRectangle.Width / 5; | |
173 | + this.splitContainer1.FixedPanel = FixedPanel.Panel1; | |
174 | + this.splitContainer1.SplitterIncrement = 20; | |
175 | + this.splitContainer2.SplitterDistance = this.splitContainer2.Height / 2; | |
176 | + this.splitContainer2.SplitterIncrement = 20; | |
177 | + | |
178 | + this.splitContainer3.Orientation = Orientation.Horizontal; | |
179 | + this.splitContainer3.Panel1.Controls.Add( this.ViewPanel ); | |
180 | + this.splitContainer3.SplitterDistance = this.splitContainer3.Height - 200; | |
181 | + this.splitContainer3.FixedPanel = FixedPanel.Panel2; | |
182 | + | |
183 | + // 見出しリスト | |
184 | + this.SectionList = new ListView(); | |
185 | + this.SectionList.Dock = DockStyle.Fill; | |
186 | + this.SectionList.View = View.Details; | |
187 | + this.SectionList.FullRowSelect = true; | |
188 | + this.SectionList.HideSelection = true; | |
189 | + this.SectionList.Columns.Add( "Section" ).AutoResize( ColumnHeaderAutoResizeStyle.HeaderSize ); | |
190 | + this.SectionList.HeaderStyle = ColumnHeaderStyle.Nonclickable; | |
191 | + this.SectionList.SelectedIndexChanged += SectionList_SelectedIndexChanged; | |
192 | + this.splitContainer2.Panel1.Controls.Add( this.SectionList ); | |
193 | + | |
194 | + // ライフラインリスト | |
195 | + this.LaneList = new ListView(); | |
196 | + this.LaneList.Dock = DockStyle.Fill; | |
197 | + this.LaneList.View = View.Details; | |
198 | + this.LaneList.FullRowSelect = true; | |
199 | + this.LaneList.MultiSelect = true; | |
200 | + this.LaneList.HideSelection = false; | |
201 | + this.LaneList.CheckBoxes = true; | |
202 | + var column = this.LaneList.Columns.Add( "Lane" ); | |
203 | + column.AutoResize( ColumnHeaderAutoResizeStyle.HeaderSize ); | |
204 | + this.LaneList.HeaderStyle = ColumnHeaderStyle.Nonclickable; | |
205 | + this.LaneList.ItemChecked += LaneList_ItemChecked; | |
206 | + this.LaneList.ItemSelectionChanged += ( o, ea ) => | |
207 | + { | |
208 | + if( this.LaneList.SelectedItems.Count > 0 ) | |
209 | + { | |
210 | + this.SelectElement( (SqElement)this.LaneList.SelectedItems[0].Tag ); | |
211 | + } | |
212 | + }; | |
213 | + this.LaneList.KeyDown += ( o, ea ) => { ea.SuppressKeyPress = this.formShortcutKey.NotifyKeyDown( o, ea ); }; | |
214 | + this.splitContainer2.Panel2.Controls.Add( this.LaneList ); | |
215 | + | |
216 | + var laneListToolStrip = new ToolStrip(); | |
217 | + laneListToolStrip.GripStyle = ToolStripGripStyle.Hidden; | |
218 | + var restoreButton = laneListToolStrip.Items.Add( "Restore", this.imageList1.Images["house.png"], LaneListToolStrip_RestoreClicked ); | |
219 | + restoreButton.ToolTipText = "Restore to original order and check state"; | |
220 | + var moveUpButton = laneListToolStrip.Items.Add( null, this.imageList1.Images["arrow_up.png"], LaneListToolStrip_MoveUpClicked ); | |
221 | + moveUpButton.ToolTipText = "Move upper (Ctrl + Up)"; | |
222 | + var moveDownButton = laneListToolStrip.Items.Add( null, this.imageList1.Images["arrow_down.png"], LaneListToolStrip_MoveDownClicked ); | |
223 | + moveDownButton.ToolTipText = "Move lower (Ctrl + Down)"; | |
224 | + this.splitContainer2.Panel2.Controls.Add( laneListToolStrip ); | |
225 | + | |
226 | + // ツールバー | |
227 | + | |
228 | + // ファイル履歴 | |
229 | + this.uxOpenFile.Image = this.imageList1.Images["page.png"]; | |
230 | + this.uxOpenFile.DropDownItems.Add( "&New", this.imageList1.Images["page_add.png"], uxOpenFile_NewClicked ); | |
231 | + this.uxOpenFile.DropDownItems.Add( "&Open", this.imageList1.Images["folder_page.png"], uxOpenFile_OpenClicked ); | |
232 | + this.uxOpenFile.DropDownItems.Add( new ToolStripSeparator() ); | |
233 | + this.uxOpenFile.DropDownItemClicked += uxOpenFile_DropDownItemClicked; | |
234 | + | |
235 | + this.uxOpenFolder.Image = this.imageList1.Images["folder.png"]; | |
236 | + this.uxOpenFolder.Click += ( o, ea ) => { | |
237 | + if( this.scriptFilePath != null ) | |
238 | + { | |
239 | + Process.Start( "EXPLORER.EXE", "/select,\"" + this.scriptFilePath + "\"" ); | |
240 | + } | |
241 | + }; | |
242 | + | |
243 | + this.uxShowSidePanel.Image = this.imageList1.Images["application_side_list.png"]; | |
244 | + this.uxShowSidePanel.Checked = true; | |
245 | + this.uxShowSidePanel.Click += ( o, ea ) => { this.splitContainer1.Panel1Collapsed = !this.uxShowSidePanel.Checked; }; | |
246 | + | |
247 | + this.uxFindButton.Image = this.imageList1.Images["magnifier.png"]; | |
248 | + this.uxFindButton.Click += ( o, ea ) => { this.uxFindBox.Focus(); }; | |
249 | + | |
250 | + this.uxFindBox.KeyDown += ( o, ea ) => { ea.SuppressKeyPress = this.formShortcutKey.NotifyKeyDown( o, ea ); }; | |
251 | + this.uxFindBox.LostFocus += uxFindBox_LostFocus; | |
252 | + this.uxFindBox.TextChanged += uxFindBox_TextChanged; | |
253 | + | |
254 | + this.uxFindPrev.Image = this.imageList1.Images["arrow_up.png"]; | |
255 | + this.uxFindPrev.Click += uxFindPrev_Click; | |
256 | + this.uxFindNext.Image = this.imageList1.Images["arrow_down.png"]; | |
257 | + this.uxFindNext.Click += uxFindNext_Click; | |
258 | + | |
259 | + this.uxKeyBinds.Image = this.imageList1.Images["keyboard.png"]; | |
260 | + this.uxKeyBinds.Click += ( o, ea ) => { this.formShortcutKey.Show(); }; | |
261 | + this.uxAbout.Image = this.imageList1.Images["sqwriter.png"]; | |
262 | + this.uxAbout.Click += ( o, ea ) => { new FormAbout().ShowDialog( this ); }; | |
263 | + | |
264 | + this.formShortcutKey = new FormShortcutKey(); | |
265 | + this.formShortcutKey.AddShortcutKeys( this.ViewPanel, "Main view", this.viewPanelShortcutKeys ); | |
266 | + this.formShortcutKey.AddShortcutKeys( this.uxFindBox, "Find box", this.findBoxShortcutKeys ); | |
267 | + this.formShortcutKey.AddShortcutKeys( this.LaneList, "Lane list", this.laneListShortcutKeys ); | |
268 | + this.formShortcutKey.AddShortcutKeys( this.editor, "Editor", this.editorShortcutKeys ); | |
269 | + | |
270 | + this.contextMenuStrip1.Items["toolStripMenuItemExportToImage"].Image = this.imageList1.Images["picture_save.png"]; | |
271 | + this.contextMenuStrip1.Items["toolStripMenuItemCopyToClipboard"].Image = this.imageList1.Images["page_paste.png"]; | |
272 | + } | |
273 | + | |
274 | + void SetupEditor() | |
275 | + { | |
276 | + this.editor.Dock = DockStyle.Fill; | |
277 | + this.editor.TextChanged += ( o, ea ) => | |
278 | + { | |
279 | + this.editingLineNo = this.editor.GetLineIndexFromCharIndex( this.editor.CaretIndex ) + 1; | |
280 | + this.UpdateDiagram( new StringReader( this.editor.Text ) ); | |
281 | + this.UpdateStatusBarFileInfo(); | |
282 | + }; | |
283 | + this.editor.CaretMoved += ( o, ea ) => { | |
284 | + int lineNo = this.editor.GetLineIndexFromCharIndex( this.editor.CaretIndex ) + 1; | |
285 | + if( lineNo != this.editingLineNo ) | |
286 | + { | |
287 | + this.editingLineNo = -1; | |
288 | + } | |
289 | + if( !this.suppressEditorCaretMovedEvent ) | |
290 | + { | |
291 | + this.SelectElementWithCaretPosition( this.editor.GetLineIndexFromCharIndex( this.editor.CaretIndex ) + 1 ); | |
292 | + } | |
293 | + }; | |
294 | + this.editor.PreviewKeyDown += ( o, ea ) => { this.formShortcutKey.NotifyKeyDown( this.editor, ea ); }; | |
295 | + | |
296 | + this.editor.Text = null; | |
297 | + this.editor.ClearHistory(); | |
298 | + | |
299 | + var cs = this.editor.ColorScheme; | |
300 | + cs.ForeColor = Color.FromArgb( 240, 240, 240 ); | |
301 | + cs.BackColor = Color.FromArgb( 32, 32, 32 ); | |
302 | + cs.SetColor( CharClass.Keyword, Color.CornflowerBlue, Color.Transparent ); | |
303 | + cs.SetColor( CharClass.Number, cs.ForeColor, Color.Transparent ); | |
304 | + cs.SetColor( CharClass.Comment, Color.Gray, Color.Transparent ); | |
305 | + cs.LineNumberBack = cs.BackColor; | |
306 | + cs.LineNumberFore = Color.Gray; | |
307 | + cs.DirtyLineBar = Color.OrangeRed; | |
308 | + cs.CleanedLineBar = Color.Gray; | |
309 | + cs.HighlightColor = Color.FromArgb( 64, 64, 64 ); | |
310 | + cs.SelectionBack = Color.FromArgb( 64, 64, 64 ); | |
311 | + cs.SelectionFore = cs.ForeColor; | |
312 | + | |
313 | + var kh = new KeywordHighlighter(); | |
314 | + string[] keywords = { | |
315 | + "lane", "send", "async", "call", "sync", "back", "return", "start", "end", "hline", "blank", "exit" | |
316 | + }; | |
317 | + Array.Sort( keywords ); | |
318 | + kh.AddKeywordSet( keywords, CharClass.Keyword ); | |
319 | + kh.AddLineHighlight( "//", CharClass.Comment ); | |
320 | + kh.AddLineHighlight( "#", CharClass.Comment ); | |
321 | + this.editor.Highlighter = kh; | |
322 | + | |
323 | + this.editor.Font = new Font( "Consolas", 10.5F ); | |
324 | + this.editor.View.DrawingOption = DrawingOption.ShowsLineNumber | DrawingOption.ShowsDirtBar | DrawingOption.HighlightCurrentLine; | |
325 | + } | |
326 | + | |
327 | + private void LaneListToolStrip_RestoreClicked( object sender, EventArgs e ) | |
328 | + { | |
329 | + this.RestoreLaneListItem(); | |
330 | + } | |
331 | + | |
332 | + private void LaneListToolStrip_MoveUpClicked( object sender, EventArgs e ) | |
333 | + { | |
334 | + this.MoveLaneListItemOrder( MoveDirection.Upper ); | |
335 | + } | |
336 | + | |
337 | + private void LaneListToolStrip_MoveDownClicked( object sender, EventArgs e ) | |
338 | + { | |
339 | + this.MoveLaneListItemOrder( MoveDirection.Lower ); | |
340 | + } | |
341 | + | |
342 | + /// <summary> | |
343 | + /// レーンリストのアイテムの順序とチェック状態を初期状態に復帰 | |
344 | + /// </summary> | |
345 | + void RestoreLaneListItem() | |
346 | + { | |
347 | + var list = new List<ListViewItem>(); | |
348 | + foreach( ListViewItem item in this.LaneList.Items ) | |
349 | + { | |
350 | + list.Add( item ); | |
351 | + } | |
352 | + list.Sort( ( item1, item2 ) => | |
353 | + { | |
354 | + var e1 = (SqElement)item1.Tag; | |
355 | + var e2 = (SqElement)item2.Tag; | |
356 | + return e1.LineNo - e2.LineNo; | |
357 | + } ); | |
358 | + this.LaneList.Items.Clear(); | |
359 | + foreach( ListViewItem item in list ) | |
360 | + { | |
361 | + this.LaneList.Items.Add( item ); | |
362 | + item.Checked = true; | |
363 | + } | |
364 | + | |
365 | + this.LaneList.SelectedItems.Clear(); | |
366 | + this.SelectElement( null ); | |
367 | + | |
368 | + this.needLayouting = true; | |
369 | + if( this.LaneList.Items.Count > 0 ) | |
370 | + { | |
371 | + this.JumpElement( (SqElement)this.LaneList.Items[0].Tag, JumpAlignment.Top ); | |
372 | + } | |
373 | + this.ViewPanel.Invalidate(); | |
374 | + } | |
375 | + | |
376 | + /// <summary> | |
377 | + /// レーンリストの選択中アイテムの順序を上下に移動 | |
378 | + /// </summary> | |
379 | + /// <param name="direction">移動方向</param> | |
380 | + void MoveLaneListItemOrder( MoveDirection direction ) | |
381 | + { | |
382 | + int begin, end, offset; | |
383 | + if( direction == MoveDirection.Upper ) | |
384 | + { | |
385 | + begin = 0; | |
386 | + end = this.LaneList.SelectedIndices.Count; | |
387 | + offset = -1; | |
388 | + } | |
389 | + else | |
390 | + { | |
391 | + begin = this.LaneList.SelectedIndices.Count - 1; | |
392 | + end = -1; | |
393 | + offset = +1; | |
394 | + } | |
395 | + | |
396 | + // InsertによりItemChecked通知が大量に出てしまうので一時的に通知止める | |
397 | + this.LaneList.ItemChecked -= LaneList_ItemChecked; | |
398 | + for( int i = begin; i != end; i -= offset ) | |
399 | + { | |
400 | + int index = this.LaneList.SelectedIndices[i]; | |
401 | + int insertIndex = index + offset; | |
402 | + if( insertIndex < 0 || this.LaneList.Items.Count <= insertIndex ) | |
403 | + { | |
404 | + break; | |
405 | + } | |
406 | + var item = this.LaneList.Items[index]; | |
407 | + bool focused = item.Focused; | |
408 | + this.LaneList.Items.RemoveAt( index ); | |
409 | + this.LaneList.Items.Insert( insertIndex, item ); | |
410 | + item.Focused = focused; | |
411 | + } | |
412 | + this.LaneList.ItemChecked += LaneList_ItemChecked; | |
413 | + | |
414 | + this.UpdateLaneStateFromLaneList( this.assembly.Lanes, this.assembly.Elements ); | |
415 | + | |
416 | + if( this.LaneList.SelectedItems.Count > 0 ) | |
417 | + { | |
418 | + this.JumpElement( (SqElement)this.LaneList.SelectedItems[0].Tag, JumpAlignment.Top ); | |
419 | + } | |
420 | + | |
421 | + this.ViewPanel.Invalidate(); | |
422 | + } | |
423 | + | |
424 | + void SectionList_SelectedIndexChanged( object sender, EventArgs e ) | |
425 | + { | |
426 | + if( this.SectionList.SelectedItems.Count > 0 ) | |
427 | + { | |
428 | + var selectedItem = this.SectionList.SelectedItems[0]; | |
429 | + int index = this.assembly.Elements.FindIndex( ( element ) => element.LineNo.ToString() == selectedItem.Name ); | |
430 | + if( index >= 0 ) | |
431 | + { | |
432 | + this.SelectElement( this.assembly.Elements[index] ); | |
433 | + } | |
434 | + } | |
435 | + } | |
436 | + | |
437 | + void SelectElement( SqElement element, bool forceMove = false ) | |
438 | + { | |
439 | + this.SelectElement( element, JumpAlignment.Middle, forceMove ); | |
440 | + } | |
441 | + | |
442 | + void SelectElement( SqElement element, JumpAlignment alignment, bool forceMove = false ) | |
443 | + { | |
444 | + this.selectedElement = element; | |
445 | + if( element != null ) | |
446 | + { | |
447 | + // 選択解除時は内容を維持したいので更新は非nullの時のみ | |
448 | + this.currentElement = element; | |
449 | + | |
450 | + // 一部が表示範囲外にはみ出していたらちゃんと見えるようスクロール | |
451 | + if( forceMove || !this.ViewPanel.VisibleArea.Contains( element.Bounds ) ) | |
452 | + { | |
453 | + this.JumpElement( element, alignment ); | |
454 | + } | |
455 | + | |
456 | + this.ViewPanel.Invalidate(); | |
457 | + } | |
458 | + | |
459 | + this.MoveEditorSelection( element ); | |
460 | + } | |
461 | + | |
462 | + void MoveEditorSelection( SqElement element ) | |
463 | + { | |
464 | + int begin = this.editor.CaretIndex; | |
465 | + int end = begin; | |
466 | + | |
467 | + if( element != null ) | |
468 | + { | |
469 | + begin = this.editor.GetCharIndexFromLineColumnIndex( element.LineNo - 1, 0 ); | |
470 | + end = this.editor.Document.GetLineEndIndexFromCharIndex( begin ); | |
471 | + | |
472 | + // 選択範囲から末尾の空白文字を除く | |
473 | + var text = this.editor.Document.GetTextInRange( begin, end ); | |
474 | + end -= (text.Length - text.TrimEnd().Length); | |
475 | + } | |
476 | + | |
477 | + this.suppressEditorCaretMovedEvent = true; | |
478 | + this.editor.SetSelection( begin, end ); | |
479 | + suppressEditorCaretMovedEvent = false; | |
480 | + this.editor.ScrollToCaret(); | |
481 | + } | |
482 | + | |
483 | + void uxFindNext_Click( object sender, EventArgs e ) | |
484 | + { | |
485 | + string pattern = this.uxFindBox.Text; | |
486 | + if( !string.IsNullOrEmpty( pattern ) ) | |
487 | + { | |
488 | + this.MoveMatchedElement( pattern, true ); | |
489 | + } | |
490 | + else | |
491 | + { | |
492 | + this.MoveSelection( MoveDirection.Lower ); | |
493 | + } | |
494 | + } | |
495 | + | |
496 | + void uxFindPrev_Click( object sender, EventArgs e ) | |
497 | + { | |
498 | + string pattern = this.uxFindBox.Text; | |
499 | + if( !string.IsNullOrEmpty( pattern ) ) | |
500 | + { | |
501 | + this.MoveMatchedElement( pattern, false ); | |
502 | + } | |
503 | + else | |
504 | + { | |
505 | + this.MoveSelection( MoveDirection.Upper ); | |
506 | + } | |
507 | + } | |
508 | + | |
509 | + void MoveMatchedElement( string pattern, bool forward ) | |
510 | + { | |
511 | + var foundElement = this.FindElementWithPattern( pattern, this.currentElement, forward ); | |
512 | + if( foundElement == null ) | |
513 | + { | |
514 | + // 先頭/末尾から | |
515 | + foundElement = this.FindElementWithPattern( pattern, null, forward ); | |
516 | + } | |
517 | + this.SelectElement( foundElement ); | |
518 | + if( foundElement == null ) | |
519 | + { | |
520 | + this.uxFindBox.BackColor = Color.Pink; | |
521 | + System.Media.SystemSounds.Beep.Play(); | |
522 | + } | |
523 | + } | |
524 | + | |
525 | + void uxFindBox_TextChanged( object sender, EventArgs e ) | |
526 | + { | |
527 | + this.uxFindBox.BackColor = Color.White; | |
528 | + this.selectedElement = null; | |
529 | + | |
530 | + string pattern = this.uxFindBox.Text; | |
531 | + if( !string.IsNullOrEmpty( pattern ) ) | |
532 | + { | |
533 | + if( this.currentElement != null && this.currentElement.IsMatched( pattern ) ) | |
534 | + { | |
535 | + this.SelectElement( this.currentElement ); | |
536 | + } | |
537 | + else | |
538 | + { | |
539 | + this.MoveMatchedElement( pattern, true ); | |
540 | + } | |
541 | + } | |
542 | + this.ViewPanel.Invalidate(); | |
543 | + } | |
544 | + | |
545 | + void uxFindBox_LostFocus( object sender, EventArgs e ) | |
546 | + { | |
547 | + this.uxFindBox.BackColor = Color.White; | |
548 | + this.ViewPanel.Focus(); | |
549 | + } | |
550 | + | |
551 | + void MoveSelection( MoveDirection direction ) | |
552 | + { | |
553 | + int move = (direction == MoveDirection.Lower) ? +1 : -1; | |
554 | + int index = 0; | |
555 | + if( this.currentElement != null ) | |
556 | + { | |
557 | + index = this.assembly.Elements.FindIndex( ( element ) => element == this.currentElement ); | |
558 | + } | |
559 | + index += move; | |
560 | + | |
561 | + while( 0 <= index && index < this.assembly.Elements.Count ) | |
562 | + { | |
563 | + if( this.assembly.Elements[index].Visible && this.assembly.Elements[index].IsSelectionMoveStop ) | |
564 | + { | |
565 | + this.SelectElement( this.assembly.Elements[index] ); | |
566 | + break; | |
567 | + } | |
568 | + index += move; | |
569 | + } | |
570 | + | |
571 | + this.JumpElement( this.selectedElement, JumpAlignment.Middle ); | |
572 | + } | |
573 | + | |
574 | + void MoveSection( MoveDirection direction ) | |
575 | + { | |
576 | + int move = (direction == MoveDirection.Lower) ? +1 : -1; | |
577 | + int index = 0; | |
578 | + if( this.currentElement != null ) | |
579 | + { | |
580 | + index = this.assembly.Elements.FindIndex( ( element ) => element == this.currentElement ); | |
581 | + } | |
582 | + index += move; | |
583 | + | |
584 | + SqElement foundElement = null; | |
585 | + while( 0 <= index && index < this.assembly.Elements.Count ) | |
586 | + { | |
587 | + if( this.assembly.Elements[index].Visible && this.assembly.Elements[index].Type == SqElement.ElementType.HorizontalLine ) | |
588 | + { | |
589 | + foundElement = this.assembly.Elements[index]; | |
590 | + break; | |
591 | + } | |
592 | + index += move; | |
593 | + } | |
594 | + | |
595 | + if( foundElement == null ) | |
596 | + { | |
597 | + this.selectedElement = null; | |
598 | + float x = this.ViewPanel.PositionXY.X; | |
599 | + float y = 0.0F; | |
600 | + if( direction == MoveDirection.Upper ) | |
601 | + { | |
602 | + // 上端に移動 | |
603 | + this.currentElement = null; | |
604 | + this.MotionController.JumpPosition( new PointF( x, y ) ); | |
605 | + } | |
606 | + else | |
607 | + { | |
608 | + // 下端に移動 | |
609 | + Trace.Assert( direction == MoveDirection.Lower ); | |
610 | + this.currentElement = this.assembly.Elements.Last(); | |
611 | + y = this.currentElement.Bounds.Bottom - this.ViewPanel.VisibleArea.Height; | |
612 | + if( y > this.ViewPanel.PositionXY.Y ) | |
613 | + { | |
614 | + this.MotionController.JumpPosition( new PointF( x, y ) ); | |
615 | + } | |
616 | + } | |
617 | + this.MoveEditorSelection( null ); | |
618 | + } | |
619 | + else | |
620 | + { | |
621 | + this.SelectElement( foundElement, JumpAlignment.Top, true ); | |
622 | + } | |
623 | + } | |
624 | + | |
625 | + void JumpElement( SqElement element, JumpAlignment alignment ) | |
626 | + { | |
627 | + if( this.needLayouting ) | |
628 | + { | |
629 | + Layouter.LayoutElements( assembly.Elements, assembly.Lanes, out this.layoutedSize ); | |
630 | + this.needLayouting = false; | |
631 | + } | |
632 | + | |
633 | + // 基本位置:横は現状維持、縦は画面中央に要素 | |
634 | + float x = this.ViewPanel.VisibleArea.Left; | |
635 | + float y = this.ViewPanel.VisibleArea.Top; | |
636 | + | |
637 | + if( alignment == JumpAlignment.Top ) | |
638 | + { | |
639 | + y = element.Bounds.Top - this.fixedHeaderHeight * this.ViewPanel.ViewScale; | |
640 | + } | |
641 | + else if( alignment == JumpAlignment.Middle ) | |
642 | + { | |
643 | + y = element.XY.Y - (this.ViewPanel.VisibleArea.Height / 2); | |
644 | + } | |
645 | + else if( alignment == JumpAlignment.Bottom ) | |
646 | + { | |
647 | + y = element.Bounds.Bottom - this.ViewPanel.VisibleArea.Height; | |
648 | + } | |
649 | + else | |
650 | + { | |
651 | + Trace.Assert( false ); | |
652 | + } | |
653 | + | |
654 | + // ライフラインは下側にはみ出している時だけ移動、それ以外は現状維持 | |
655 | + if( element.Type == SqElement.ElementType.Lane ) | |
656 | + { | |
657 | + if( element.Bounds.Bottom <= this.ViewPanel.VisibleArea.Bottom ) | |
658 | + { | |
659 | + y = this.ViewPanel.VisibleArea.Top; | |
660 | + } | |
661 | + } | |
662 | + | |
663 | + // はみ出し補正、要素の左端が必ず見えるように | |
664 | + float leftLaneX = (assembly.Lanes.Count > 0) ? assembly.Lanes[0].XY.X : 0.0F; | |
665 | + float checkLeft = element.Bounds.Left - leftLaneX; | |
666 | + float checkRight = element.Bounds.Right + leftLaneX; | |
667 | + if( element.Bounds.Right >= this.ViewPanel.VisibleArea.Right ) | |
668 | + { | |
669 | + x = checkRight - this.ViewPanel.VisibleArea.Width; | |
670 | + x = (x > checkLeft) ? checkLeft : x; | |
671 | + } | |
672 | + else if( checkLeft >= this.ViewPanel.VisibleArea.Right || | |
673 | + checkLeft <= this.ViewPanel.VisibleArea.Left ) | |
674 | + { | |
675 | + x = checkLeft; | |
676 | + } | |
677 | + x = (x < 0.0F) ? 0.0F : x; | |
678 | + y = (y < 0.0F) ? 0.0F : y; | |
679 | + | |
680 | + this.MotionController.JumpPosition( new PointF( x, y ) ); | |
681 | + } | |
682 | + | |
683 | + void SelectElementWithCaretPosition( int lineNo ) | |
684 | + { | |
685 | + if( this.assembly == null ) | |
686 | + { | |
687 | + return; | |
688 | + } | |
689 | + bool exact = false; | |
690 | + var foundElement = this.FindElementWithLineNo( lineNo, out exact ); | |
691 | + if( foundElement != null ) | |
692 | + { | |
693 | + // エディタの選択状態に反映させたくないのでSelectElementは使用せず | |
694 | + this.selectedElement = exact ? foundElement : null; | |
695 | + this.currentElement = foundElement; | |
696 | + | |
697 | + this.JumpElement( foundElement, JumpAlignment.Middle ); | |
698 | + } | |
699 | + } | |
700 | + | |
701 | + //TODO: こういう要素を検索するのもAssembyに移動 | |
702 | + SqElement FindElementWithLineNo( int lineNo, out bool exact ) | |
703 | + { | |
704 | + SqElement prevElement = null; | |
705 | + foreach( var element in this.assembly.Elements ) | |
706 | + { | |
707 | + if( element.Visible ) | |
708 | + { | |
709 | + if( element.LineNo > lineNo ) | |
710 | + { | |
711 | + break; | |
712 | + } | |
713 | + prevElement = element; | |
714 | + } | |
715 | + } | |
716 | + | |
717 | + exact = (prevElement != null && prevElement.LineNo == lineNo); | |
718 | + | |
719 | + return prevElement; | |
720 | + } | |
721 | + | |
722 | + SqElement FindElementWithPattern( string pattern, SqElement startAfter = null, bool forward = true ) | |
723 | + { | |
724 | + int index = -1; | |
725 | + if( startAfter != null ) | |
726 | + { | |
727 | + index = this.assembly.Elements.FindIndex( ( e ) => e == startAfter ); | |
728 | + } | |
729 | + | |
730 | + int foundIndex = -1; | |
731 | + if( forward ) | |
732 | + { | |
733 | + index = (index == -1) ? 0 : (index + 1); | |
734 | + if( index < this.assembly.Elements.Count ) | |
735 | + { | |
736 | + foundIndex = this.assembly.Elements.FindIndex( index, ( e ) => e.Visible && e.IsMatched( pattern ) ); | |
737 | + } | |
738 | + } | |
739 | + else | |
740 | + { | |
741 | + index = (index == -1) ? (this.assembly.Elements.Count - 1) : (index - 1); | |
742 | + if( index >= 0 ) | |
743 | + { | |
744 | + foundIndex = this.assembly.Elements.FindLastIndex( index, index + 1, ( e ) => e.Visible && e.IsMatched( pattern ) ); | |
745 | + } | |
746 | + } | |
747 | + | |
748 | + return (foundIndex >= 0) ? this.assembly.Elements[foundIndex] : null; | |
749 | + } | |
750 | + | |
751 | + void LaneList_ItemChecked( object sender, ItemCheckedEventArgs e ) | |
752 | + { | |
753 | + if( this.assembly != null ) | |
754 | + { | |
755 | + // レーンリスト準備中の通知は無視 | |
756 | + if( this.LaneList.Items.Count == this.assembly.Lanes.Count ) | |
757 | + { | |
758 | + this.UpdateLaneStateFromLaneList( this.assembly.Lanes, this.assembly.Elements ); | |
759 | + this.ViewPanel.Invalidate(); | |
760 | + } | |
761 | + } | |
762 | + } | |
763 | + | |
764 | + void viewMotioner_ParamUpdate( MotionContoller sender, MotionContoller.ParamUpdateEventArgs e ) | |
765 | + { | |
766 | + this.ViewPanel.PositionXY = e.PositionXY; | |
767 | + this.ViewPanel.ViewScale = e.Scale; | |
768 | + | |
769 | + if( e.ZoomFinished ) | |
770 | + { | |
771 | + var offsetXY = this.ViewPanel.PositionOffsetXY; | |
772 | + this.ViewPanel.PositionOffsetXY = new Point( 0, 0 ); | |
773 | + this.ViewPanel.PositionXY = new PointF( | |
774 | + this.ViewPanel.PositionXY.X - offsetXY.X / e.Scale, | |
775 | + this.ViewPanel.PositionXY.Y - offsetXY.Y / e.Scale ); | |
776 | + this.MotionController.PositionXY = this.ViewPanel.PositionXY; | |
777 | + } | |
778 | + | |
779 | + toolStripStatusLabelZoom.Text = string.Format( "Zoom:{0:0}%", e.Scale * 100.0F ); | |
780 | + | |
781 | +#if DEBUG | |
782 | + this.GetVisibleAreaProportion(); | |
783 | +#endif | |
784 | + this.ViewPanel.Invalidate(); | |
785 | + } | |
786 | + | |
787 | + void viewPanel_Draw( ViewPanel sender, ViewPanel.DrawEventArgs e ) | |
788 | + { | |
789 | + toolStripStatusLabelViewPoint.Text = string.Format( "View:({0},{1})", (int)e.PositionXY.X, (int)e.PositionXY.Y ); | |
790 | + | |
791 | + var sw = new Stopwatch(); | |
792 | + sw.Start(); | |
793 | + | |
794 | + var g = e.Graphics; | |
795 | + | |
796 | + var viewRect = new Rectangle( new Point( 0, 0 ), e.ViewWH ); | |
797 | + g.Clip = new Region( viewRect ); | |
798 | + | |
799 | + // 参考値:HighQuality:5.6ms -> Default:2.4ms | |
800 | + //g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; | |
801 | + //g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; | |
802 | + | |
803 | + g.FillRectangle( this.backgroundBrush, viewRect ); | |
804 | + | |
805 | + if( this.debugMode ) | |
806 | + { | |
807 | + // ソースをうっすらと表示 | |
808 | + if( this.scriptFilePath != null ) | |
809 | + { | |
810 | + using( StreamReader sr = new StreamReader( this.scriptFilePath, Encoding.Default ) ) | |
811 | + { | |
812 | + var format = new StringFormat(); | |
813 | + format.Alignment = StringAlignment.Near; | |
814 | + format.LineAlignment = StringAlignment.Near; | |
815 | + format.FormatFlags = System.Drawing.StringFormatFlags.NoWrap; | |
816 | + var textRect = viewRect; | |
817 | + textRect.Inflate( -5, -5 ); | |
818 | + g.DrawString( sr.ReadToEnd().Replace( '\t', ' ' ), this.sourcecodeFont, this.sourcecodeBrush, textRect, format ); | |
819 | + } | |
820 | + } | |
821 | + } | |
822 | + | |
823 | + // 方眼紙 | |
824 | + if( this.grid ) | |
825 | + { | |
826 | + this.DrawGridLines( | |
827 | + g, | |
828 | + new PointF( | |
829 | + (-e.DisplayedArea.Left % kGridSpanX) * e.ViewScale, | |
830 | + (-e.DisplayedArea.Top % kGridSpanY) * e.ViewScale ), | |
831 | + new SizeF( kGridSpanX * e.ViewScale, kGridSpanY * e.ViewScale ), | |
832 | + viewRect ); | |
833 | + // 行番号 | |
834 | + for( float y = ((int)this.ViewPanel.VisibleArea.Top / kGridSpanY) * kGridSpanY; | |
835 | + y < this.ViewPanel.VisibleArea.Bottom; | |
836 | + y += kGridSpanY ) | |
837 | + { | |
838 | + if( y >= 0 ) | |
839 | + { | |
840 | + float alpha = (e.ViewScale < 1.0F) ? ((e.ViewScale - 0.25F) / 0.75F) : 1.0F; | |
841 | + Brush brush = new SolidBrush( Color.FromArgb( (int)(alpha * 255), 200, 200, 200 ) ); | |
842 | + var xy = new PointF( 0, (y - this.ViewPanel.VisibleArea.Top) * e.ViewScale ); | |
843 | + var sf = new StringFormat(); | |
844 | + sf.LineAlignment = StringAlignment.Far; | |
845 | + g.DrawString( (y / 50 * 10).ToString(), this.linenoFont, brush, new RectangleF( xy, new SizeF( kGridSpanX * e.ViewScale, kGridSpanY * e.ViewScale ) ), sf ); | |
846 | + } | |
847 | + } | |
848 | + } | |
849 | + | |
850 | + // ここからが本番 | |
851 | + if( this.assembly != null ) | |
852 | + { | |
853 | + if( this.needLayouting ) | |
854 | + { | |
855 | + Layouter.LayoutElements( assembly.Elements, assembly.Lanes, out this.layoutedSize ); | |
856 | + this.needLayouting = false; | |
857 | + } | |
858 | + | |
859 | + this.fixedHeaderHeight = 0.0F; | |
860 | + foreach( var lane in assembly.Lanes.FindAll( ( element ) => element.Visible ) ) | |
861 | + { | |
862 | + float laneHeight = lane.Bounds.Height; | |
863 | + if( laneHeight > this.fixedHeaderHeight ) | |
864 | + { | |
865 | + this.fixedHeaderHeight = laneHeight; | |
866 | + } | |
867 | + } | |
868 | + | |
869 | + // 図面要素描画 | |
870 | + this.DrawElements( g, viewRect, e.PositionOffsetXY, e.PositionXY, e.ViewScale ); | |
871 | + } | |
872 | + | |
873 | + // ベクトルスクロール基準点 | |
874 | + if( this.MotionController.Mode == MotionContoller.ScrollMode.Vector ) | |
875 | + { | |
876 | + var onXY = this.MotionController.TouchOnXY; | |
877 | + var moveXY = this.MotionController.TouchMoveXY; | |
878 | + | |
879 | + g.SmoothingMode = SmoothingMode.HighQuality; | |
880 | + | |
881 | + g.FillEllipse( this.foregroundBrush, onXY.X - 5, onXY.Y - 5, 10, 10 ); | |
882 | + g.DrawLine( this.vectorScrollPen, onXY.X, onXY.Y, moveXY.X, moveXY.Y ); | |
883 | + | |
884 | + g.SmoothingMode = SmoothingMode.Default; | |
885 | + } | |
886 | + | |
887 | + // エラーメッセージ | |
888 | + if( this.assembly != null && this.assembly.Errors.Count > 0 ) | |
889 | + { | |
890 | + int errorCount = 0; | |
891 | + var sb = new StringBuilder(); | |
892 | + foreach( var error in this.assembly.Errors ) | |
893 | + { | |
894 | + if( error.LineNo != this.editingLineNo ) | |
895 | + { | |
896 | + sb.AppendFormat( "Line:{0} {1}", error.LineNo, error.MessageText ); | |
897 | + sb.AppendLine(); | |
898 | + errorCount++; | |
899 | + } | |
900 | + } | |
901 | + | |
902 | + if( errorCount > 0 ) | |
903 | + { | |
904 | + sb.Insert( 0, string.Format( "エラー({0}個):\n\n", errorCount ) ); | |
905 | + | |
906 | + g.FillRectangle( this.errorBackgroundBrush, viewRect ); | |
907 | + | |
908 | + var errorRect = viewRect; | |
909 | + errorRect.Inflate( -10, -10 ); | |
910 | + g.DrawString( sb.ToString(), this.errorTextFont, this.errorTextBrush, errorRect ); | |
911 | + } | |
912 | + } | |
913 | + | |
914 | + sw.Stop(); | |
915 | + this.toolStripStatusLabelDrawTime.Text = string.Format( "Draw:{0:F3}ms", sw.Elapsed.TotalMilliseconds ); | |
916 | + } | |
917 | + | |
918 | + /// <summary> | |
919 | + /// スクリプトファイル読み込み | |
920 | + /// </summary> | |
921 | + /// <param name="path">読み込むファイルのパス</param> | |
922 | + /// <returns></returns> | |
923 | + public bool LoadFile( string path ) | |
924 | + { | |
925 | + if( !File.Exists( path ) ) | |
926 | + { | |
927 | + return false; | |
928 | + } | |
929 | + | |
930 | + int retryCount; | |
931 | + for( retryCount = 1; retryCount >= 0; retryCount-- ) | |
932 | + { | |
933 | + try | |
934 | + { | |
935 | + using( var reader = new StreamReader( path, Encoding.Default ) ) | |
936 | + { | |
937 | + this.editor.Text = reader.ReadToEnd(); | |
938 | + this.editor.ClearHistory(); | |
939 | + this.editor.Document.IsDirty = false; | |
940 | + } | |
941 | + break; | |
942 | + } | |
943 | + catch( IOException ex ) | |
944 | + { | |
945 | + Trace.TraceError( "[ERROR][{0}]{1}", MethodBase.GetCurrentMethod().Name, ex.ToString() ); | |
946 | + } | |
947 | + System.Threading.Thread.Sleep( kFileOpenRetryTime ); | |
948 | + } | |
949 | + if( retryCount < 0 ) | |
950 | + { | |
951 | + MessageBox.Show( this, "Could not open file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); | |
952 | + return false; | |
953 | + } | |
954 | + | |
955 | + this.scriptFilePath = Path.GetFullPath( path ); | |
956 | + | |
957 | + this.UpdateStatusBarFileInfo(); | |
958 | + | |
959 | + // 図面更新 | |
960 | + this.UpdateDiagram( new StringReader( this.editor.Text ) ); | |
961 | + | |
962 | + return true; | |
963 | + } | |
964 | + | |
965 | + public bool UpdateDiagram( TextReader reader ) | |
966 | + { | |
967 | + var sw = new Stopwatch(); | |
968 | + sw.Start(); | |
969 | + { | |
970 | + var compiler = new SqCompiler(); | |
971 | + this.assembly = compiler.Compile( reader ); | |
972 | + } | |
973 | + sw.Stop(); | |
974 | + | |
975 | + this.lastCompilingTime = sw.Elapsed; | |
976 | + | |
977 | + // セクションリスト更新 | |
978 | + this.UpdateSectionList( this.assembly.Elements ); | |
979 | + | |
980 | + // ライフラインリスト更新 | |
981 | + this.UpdateLaneList( this.assembly.Lanes ); | |
982 | + | |
983 | + // ライフラインリストのチェック状態をライフライン要素に反映 | |
984 | + this.UpdateLaneStateFromLaneList( this.assembly.Lanes, this.assembly.Elements ); | |
985 | + | |
986 | + this.needLayouting = true; | |
987 | + | |
988 | + this.ViewPanel.Invalidate(); | |
989 | + | |
990 | + return true; | |
991 | + } | |
992 | + | |
993 | + void UpdateStatusBarFileInfo() | |
994 | + { | |
995 | + var sb = new StringBuilder(); | |
996 | + if( this.scriptFilePath != null && File.Exists( this.scriptFilePath ) ) | |
997 | + { | |
998 | + var info = new FileInfo( this.scriptFilePath ); | |
999 | + sb.AppendFormat( "{0} ({1}bytes)", Path.GetFileName( this.scriptFilePath ), info.Length ); | |
1000 | + if( this.lastSavedTime.Ticks != 0 ) | |
1001 | + { | |
1002 | + sb.AppendFormat( " Last saved at: {0}", this.lastSavedTime.ToLongTimeString() ); | |
1003 | + } | |
1004 | + } | |
1005 | + else | |
1006 | + { | |
1007 | + sb.Append( "-" ); | |
1008 | + } | |
1009 | + sb.AppendFormat( " Compile: {0}ms", this.lastCompilingTime.TotalMilliseconds ); | |
1010 | + this.toolStripStatusLabelFileInfo.Text = sb.ToString(); | |
1011 | + } | |
1012 | + | |
1013 | + void SaveEditorContents() | |
1014 | + { | |
1015 | + if( this.editor.Document.IsDirty && File.Exists( this.scriptFilePath ) ) | |
1016 | + { | |
1017 | + try | |
1018 | + { | |
1019 | + using( var writer = new StreamWriter( this.scriptFilePath ) ) | |
1020 | + { | |
1021 | + writer.Write( this.editor.Text ); | |
1022 | + this.editor.Document.IsDirty = false; | |
1023 | + this.lastSavedTime = DateTime.Now; | |
1024 | + } | |
1025 | + } | |
1026 | + catch( IOException ) | |
1027 | + { | |
1028 | + this.toolStripStatusLabelFileInfo.Text = "ERROR: Could not save file."; | |
1029 | + } | |
1030 | + | |
1031 | + this.UpdateStatusBarFileInfo(); | |
1032 | + } | |
1033 | + } | |
1034 | + | |
1035 | + | |
1036 | + // | |
1037 | + // Private fields | |
1038 | + // | |
1039 | + | |
1040 | + Setting setting; | |
1041 | + string scriptFilePath = null; | |
1042 | + TimeSpan lastCompilingTime; | |
1043 | + DateTime lastSavedTime; | |
1044 | + SqAssembly assembly = null; | |
1045 | + SqElement selectedElement = null; | |
1046 | + SqElement currentElement = null; | |
1047 | + //List<SqElement> highlightedElementList = new List<SqElement>(); | |
1048 | + Size DefaultFormSize = new Size( 800, 600 ); | |
1049 | + bool needLayouting = true; | |
1050 | + Size layoutedSize = new Size(); | |
1051 | + FormDebug formDebug = null; | |
1052 | + bool debugMode = false; | |
1053 | + int zoomIndex = kDefaultZoomIndex; | |
1054 | + bool grid = true; | |
1055 | + Pen gridPen; | |
1056 | + Pen borderLinePen; | |
1057 | + Pen debugLayoutLinePen; | |
1058 | + Brush foregroundBrush; | |
1059 | + Brush backgroundBrush; | |
1060 | + Brush sourcecodeBrush; | |
1061 | + Font sourcecodeFont; | |
1062 | + Font linenoFont; | |
1063 | + Pen vectorScrollPen; | |
1064 | + Brush errorBackgroundBrush; | |
1065 | + Brush errorTextBrush; | |
1066 | + Font errorTextFont; | |
1067 | + float fixedHeaderHeight; | |
1068 | + FormShortcutKey formShortcutKey = null; | |
1069 | + Point mouseDownPoint; | |
1070 | + bool suppressEditorCaretMovedEvent; | |
1071 | + int editingLineNo; | |
1072 | + | |
1073 | + // | |
1074 | + // Private methods | |
1075 | + // | |
1076 | + | |
1077 | + enum MoveDirection | |
1078 | + { | |
1079 | + Upper, | |
1080 | + Lower | |
1081 | + } | |
1082 | + | |
1083 | + private void viewPanel_MouseMove( object sender, MouseEventArgs e ) | |
1084 | + { | |
1085 | + if( e.Button == MouseButtons.Left ) | |
1086 | + { | |
1087 | + this.MotionController.TouchMove( e.Location ); | |
1088 | + } | |
1089 | + FormDebug.SetItem( "mousePoint", e.Location ); | |
1090 | + toolStripStatusLabelMousePoint.Text = string.Format( "Mouse:({0},{1})", e.X, e.Y ); | |
1091 | + } | |
1092 | + | |
1093 | + private void viewPanel_MouseLeave( object sender, EventArgs e ) | |
1094 | + { | |
1095 | + toolStripStatusLabelMousePoint.Text = "Mouse:(-,-)"; | |
1096 | + } | |
1097 | + | |
1098 | + private void viewPanel_MouseDown( object sender, MouseEventArgs e ) | |
1099 | + { | |
1100 | + this.ViewPanel.Focus(); | |
1101 | + | |
1102 | + if( e.Button == MouseButtons.Left ) | |
1103 | + { | |
1104 | + if( Control.ModifierKeys == Keys.Control ) | |
1105 | + { | |
1106 | + this.MotionController.TouchOn( e.Location, MotionContoller.TouchMode.Vector ); | |
1107 | + } | |
1108 | + else | |
1109 | + { | |
1110 | + this.MotionController.TouchOn( e.Location, MotionContoller.TouchMode.Drag ); | |
1111 | + } | |
1112 | + | |
1113 | + this.mouseDownPoint = e.Location; | |
1114 | + | |
1115 | + FormDebug.SetItem( "dragPoint", e.Location ); | |
1116 | + } | |
1117 | + else if( e.Button == MouseButtons.Right ) | |
1118 | + { | |
1119 | + bool enabled = false; | |
1120 | + if( this.assembly != null && this.assembly.Errors.Count <= 0 ) | |
1121 | + { | |
1122 | + enabled = true; | |
1123 | + } | |
1124 | + this.toolStripMenuItemExportToImage.Enabled = enabled; | |
1125 | + this.toolStripMenuItemCopyToClipboard.Enabled = enabled; | |
1126 | + contextMenuStrip1.Show( this.ViewPanel.PointToScreen( e.Location ) ); | |
1127 | + } | |
1128 | + } | |
1129 | + | |
1130 | + private void viewPanel_MouseUp( object sender, MouseEventArgs e ) | |
1131 | + { | |
1132 | + if( e.Button == MouseButtons.Left ) | |
1133 | + { | |
1134 | + this.MotionController.TouchOff( e.Location ); | |
1135 | + | |
1136 | + if( Math.Abs( e.Location.X - this.mouseDownPoint.X ) < 5 && | |
1137 | + Math.Abs( e.Location.Y - this.mouseDownPoint.Y ) < 5 ) | |
1138 | + { | |
1139 | + // クリックされた位置の要素を選択 | |
1140 | + if( this.assembly != null ) | |
1141 | + { | |
1142 | + var position = this.ViewPanel.ScreenToWorld( e.Location ); | |
1143 | + SqElement hitElement = null; | |
1144 | + | |
1145 | + // 固定表示部分がクリックされた | |
1146 | + if( this.ViewPanel.PositionXY.Y > 0 && (position.Y - this.ViewPanel.VisibleArea.Top) <= this.fixedHeaderHeight ) | |
1147 | + { | |
1148 | + foreach( var lane in this.assembly.Lanes ) | |
1149 | + { | |
1150 | + if( lane.Bounds.Top <= this.ViewPanel.VisibleArea.Top && | |
1151 | + lane.Bounds.Left <= position.X && position.X <= lane.Bounds.Right ) | |
1152 | + { | |
1153 | + hitElement = lane; | |
1154 | + } | |
1155 | + } | |
1156 | + } | |
1157 | + | |
1158 | + if( hitElement == null ) | |
1159 | + { | |
1160 | + hitElement = this.assembly.GetVisibleElementAt( position.X, position.Y ); | |
1161 | + } | |
1162 | + | |
1163 | + if( hitElement != null && hitElement.UserSelectable ) | |
1164 | + { | |
1165 | + this.LaneList.SelectedItems.Clear(); | |
1166 | + if( hitElement.Type == SqElement.ElementType.Lane ) | |
1167 | + { | |
1168 | + this.LaneList.Items[hitElement.Name].Selected = true; | |
1169 | + } | |
1170 | + } | |
1171 | + this.SelectElement( hitElement ); | |
1172 | + } | |
1173 | + } | |
1174 | + } | |
1175 | + } | |
1176 | + | |
1177 | + private void FormMain_MouseWheel( object sender, MouseEventArgs e ) | |
1178 | + { | |
1179 | + if( !this.ViewPanel.ClientRectangle.Contains( this.ViewPanel.PointToClient( Cursor.Position ) ) ) | |
1180 | + { | |
1181 | + return; | |
1182 | + } | |
1183 | + | |
1184 | + this.ViewPanel.Focus(); | |
1185 | + | |
1186 | + int move = -e.Delta / 120; | |
1187 | + if( Control.ModifierKeys == Keys.Control ) | |
1188 | + { | |
1189 | + Trace.TraceInformation( "[INFO][{0}][{1}]", DateTime.Now.Millisecond, MethodBase.GetCurrentMethod().Name ); | |
1190 | + var clientPoint = this.ViewPanel.PointToClient( this.PointToScreen( e.Location ) ); | |
1191 | + this.MotionController.PositionXY = this.ViewPanel.ScreenToWorld( clientPoint ); | |
1192 | + this.ViewPanel.PositionOffsetXY = clientPoint; | |
1193 | + | |
1194 | + this.zoomIndex -= move; | |
1195 | + this.zoomIndex = Util.Clamp( this.zoomIndex, 0, ZoomScales.Length - 1 ); | |
1196 | + this.MotionController.JumpScale( ZoomScales[this.zoomIndex] ); | |
1197 | + } | |
1198 | + else | |
1199 | + { | |
1200 | + float mx = 0.0F; | |
1201 | + float my = 0.0F; | |
1202 | + if( Control.ModifierKeys == Keys.Shift ) | |
1203 | + { | |
1204 | + this.MotionController.MovePosition( move * kGridSpanX, 0.0F, kGridSpanX, kGridSpanY ); | |
1205 | + } | |
1206 | + else | |
1207 | + { | |
1208 | + this.MotionController.MovePosition( 0.0F, move * kGridSpanY, kGridSpanX, kGridSpanY ); | |
1209 | + } | |
1210 | + this.MotionController.MovePosition( mx, my ); | |
1211 | + } | |
1212 | + } | |
1213 | + | |
1214 | + private void toolStripMenuItemExportToPng_Click( object sender, EventArgs e ) | |
1215 | + { | |
1216 | + var sfd = new SaveFileDialog(); | |
1217 | + sfd.FileName = Path.GetFileNameWithoutExtension( this.scriptFilePath ); | |
1218 | + sfd.Filter = "PNG ファイル|*.png|GIF ファイル|*.gif"; | |
1219 | + sfd.FilterIndex = 1; | |
1220 | + sfd.InitialDirectory = Path.GetDirectoryName( this.scriptFilePath ); | |
1221 | + //fd.DefaultExt = "png"; | |
1222 | + if( sfd.ShowDialog( this ) == DialogResult.OK ) | |
1223 | + { | |
1224 | + try | |
1225 | + { | |
1226 | + using( Bitmap buffer = new Bitmap( this.layoutedSize.Width, this.layoutedSize.Height ) ) | |
1227 | + { | |
1228 | + var g = Graphics.FromImage( buffer ); | |
1229 | + g.SmoothingMode = SmoothingMode.HighQuality; | |
1230 | + g.Clear( Color.White ); | |
1231 | + DrawElements( | |
1232 | + g, | |
1233 | + new Rectangle( 0, 0, buffer.Width, buffer.Height ), | |
1234 | + new Point( 0, 0 ), | |
1235 | + new Point( 0, 0 ), | |
1236 | + 1.0F ); | |
1237 | + var format = ImageFormat.Png; | |
1238 | + if( sfd.FilterIndex == 1 ) | |
1239 | + { | |
1240 | + format = ImageFormat.Png; | |
1241 | + } | |
1242 | + else if( sfd.FilterIndex == 2 ) | |
1243 | + { | |
1244 | + format = ImageFormat.Gif; | |
1245 | + } | |
1246 | + else | |
1247 | + { | |
1248 | + Trace.Assert( false ); | |
1249 | + } | |
1250 | + buffer.Save( sfd.FileName, format ); | |
1251 | + var info = new FileInfo( sfd.FileName ); | |
1252 | + var result = MessageBox.Show( this, | |
1253 | + string.Format( "画像の保存に成功しました。\n{0:N2}KB\nフォルダを開きますか?", info.Length / 1024.0F ), | |
1254 | + "情報", | |
1255 | + MessageBoxButtons.YesNo, | |
1256 | + MessageBoxIcon.Information ); | |
1257 | + if( result == DialogResult.Yes ) | |
1258 | + { | |
1259 | + // 参考:http://dobon.net/vb/dotnet/process/openexplore.html | |
1260 | + Process.Start( "EXPLORER.EXE", @"/select, " + sfd.FileName ); | |
1261 | + } | |
1262 | + } | |
1263 | + } | |
1264 | + catch( Exception ) | |
1265 | + { | |
1266 | + MessageBox.Show( this, "画像の保存に失敗しました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error ); | |
1267 | + } | |
1268 | + return; | |
1269 | + } | |
1270 | + } | |
1271 | + | |
1272 | + private void toolStripMenuItemCopyToClipboard_Click( object sender, EventArgs e ) | |
1273 | + { | |
1274 | + try | |
1275 | + { | |
1276 | + using( var buffer = new Bitmap( this.layoutedSize.Width, this.layoutedSize.Height ) ) | |
1277 | + { | |
1278 | + var g = Graphics.FromImage( buffer ); | |
1279 | + g.SmoothingMode = SmoothingMode.HighQuality; | |
1280 | + g.Clear( Color.White ); | |
1281 | + DrawElements( | |
1282 | + g, | |
1283 | + new Rectangle( 0, 0, buffer.Width, buffer.Height ), | |
1284 | + new Point( 0, 0 ), | |
1285 | + new Point( 0, 0 ), | |
1286 | + 1.0F ); | |
1287 | + | |
1288 | + // 参考:http://dobon.net/vb/dotnet/graphics/getclipboarddata.html | |
1289 | + Clipboard.SetImage( buffer ); | |
1290 | + MessageBox.Show( this, "クリップボードへコピーしました。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Information ); | |
1291 | + } | |
1292 | + } | |
1293 | + catch( Exception ) | |
1294 | + { | |
1295 | + MessageBox.Show( this, "クリップボードへのコピーに失敗しました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error ); | |
1296 | + } | |
1297 | + } | |
1298 | + | |
1299 | + void DrawGridLines( Graphics g, PointF offsetXY, SizeF gridWH, RectangleF viewportRect ) | |
1300 | + { | |
1301 | + for( float x = viewportRect.Left + offsetXY.X; x < viewportRect.Width; x += gridWH.Width ) | |
1302 | + { | |
1303 | + g.DrawLine( this.gridPen, x, viewportRect.Top, x, viewportRect.Bottom ); | |
1304 | + } | |
1305 | + for( float y = viewportRect.Top + offsetXY.Y; y < viewportRect.Height; y += gridWH.Height ) | |
1306 | + { | |
1307 | + g.DrawLine( this.gridPen, viewportRect.Left, y, viewportRect.Right, y ); | |
1308 | + } | |
1309 | + } | |
1310 | + | |
1311 | + void DrawElements( Graphics g, Rectangle viewRect, Point offsetXY, PointF positionXY, float scale ) | |
1312 | + { | |
1313 | + var worldToDisp = new Matrix(); | |
1314 | + worldToDisp.Translate( offsetXY.X, offsetXY.Y ); | |
1315 | + worldToDisp.Scale( scale, scale ); | |
1316 | + worldToDisp.Translate( -positionXY.X, -positionXY.Y ); | |
1317 | + | |
1318 | + g.Transform = worldToDisp; | |
1319 | + | |
1320 | + var dispToWorld = worldToDisp.Clone(); | |
1321 | + dispToWorld.Invert(); | |
1322 | + | |
1323 | + var cullingRect = Util.ToRectangle( Util.TransformRectangle( dispToWorld, viewRect ) ); | |
1324 | + | |
1325 | + var visibleLanes = this.assembly.Lanes.Where( ( lane ) => lane.Visible ).ToList(); | |
1326 | + var visibleElements = this.assembly.Elements.Where( ( element ) => element.Visible ).ToList(); | |
1327 | + | |
1328 | + // 拡大時はライフラインヘッダが大きくなりすぎないよう調整 | |
1329 | + // 行列による倍率を要素個別の倍率で打ち消し | |
1330 | + float elementScale = 1.0F / scale; | |
1331 | + elementScale = (elementScale < 1.0F) ? (1.0F - (1.0F - elementScale) * 2.0F / 3.0F) : 1.0F; | |
1332 | + visibleLanes.ForEach( ( lane ) => ((Lane)lane).Scale = elementScale ); | |
1333 | + | |
1334 | + // まずライフラインヘッダのはみ出しがあるかチェック | |
1335 | + bool isLaneHeaderFixed = false; | |
1336 | + foreach( var lane in visibleLanes ) | |
1337 | + { | |
1338 | + if( lane.Bounds.Top < g.ClipBounds.Y ) | |
1339 | + { | |
1340 | + isLaneHeaderFixed = true; | |
1341 | + break; | |
1342 | + } | |
1343 | + } | |
1344 | + | |
1345 | + var saveClipBounds = g.ClipBounds; | |
1346 | + | |
1347 | + if( isLaneHeaderFixed ) | |
1348 | + { | |
1349 | + // 固定表示部分のライフラインヘッダを描画 | |
1350 | + this.DrawFixedLaneHeader( g, viewRect, scale, visibleLanes, this.fixedHeaderHeight * scale ); | |
1351 | + | |
1352 | + // 固定表示部分をクリップ | |
1353 | + var lowerClipRect = saveClipBounds; | |
1354 | + lowerClipRect.Y += this.fixedHeaderHeight; | |
1355 | + lowerClipRect.Height -= this.fixedHeaderHeight; | |
1356 | + g.Clip = new Region( lowerClipRect ); | |
1357 | + } | |
1358 | + | |
1359 | + // 全ノード描画 | |
1360 | + int drawNodeCount = 0; | |
1361 | + foreach( var element in visibleElements ) | |
1362 | + { | |
1363 | + if( element.IntersectsWith( cullingRect ) ) | |
1364 | + { | |
1365 | + if( element == this.selectedElement ) | |
1366 | + { | |
1367 | + element.ForegroundColor = Color.OrangeRed; | |
1368 | + element.TextColor = Color.OrangeRed; | |
1369 | + } | |
1370 | + else | |
1371 | + { | |
1372 | + element.ForegroundColor = Color.Black; | |
1373 | + element.TextColor = Color.Black; | |
1374 | + } | |
1375 | + element.Draw( g ); | |
1376 | + drawNodeCount++; | |
1377 | + } | |
1378 | + } | |
1379 | + | |
1380 | + FormDebug.SetItem( "DrawNodes/All", string.Format( "{0}/{1}", drawNodeCount, visibleElements.Count ) ); | |
1381 | + | |
1382 | + if( this.debugMode ) | |
1383 | + { | |
1384 | + foreach( var element in visibleElements ) | |
1385 | + { | |
1386 | + element.DebugDraw( g ); | |
1387 | + } | |
1388 | + var drawRect = new Rectangle( new Point( 0, 0 ), this.layoutedSize ); | |
1389 | + drawRect.Inflate( -1, -1 ); | |
1390 | + drawRect.Width -= 1; | |
1391 | + drawRect.Height -= 1; | |
1392 | + g.DrawRectangle( this.debugLayoutLinePen, drawRect ); | |
1393 | + } | |
1394 | + | |
1395 | + g.Clip = new Region( saveClipBounds ); | |
1396 | + g.ResetTransform(); | |
1397 | + } | |
1398 | + | |
1399 | + void DrawFixedLaneHeader( Graphics g, Rectangle viewRect, float scale, List<SqElement> lanes, float laneHeaderHeightMax ) | |
1400 | + { | |
1401 | + var baseClipBounds = g.ClipBounds; | |
1402 | + var baseMatrix = g.Transform; | |
1403 | + | |
1404 | + // 固定表示部分の境界に線を引く | |
1405 | + float borderLineWidth = 1.0F; | |
1406 | + | |
1407 | + var mat = g.Transform; | |
1408 | + g.ResetTransform(); | |
1409 | + | |
1410 | + // 方眼紙を描き直し | |
1411 | + if( this.grid ) | |
1412 | + { | |
1413 | + g.FillRectangle( this.backgroundBrush, new Rectangle( 0, 0, viewRect.Width, (int)laneHeaderHeightMax ) ); | |
1414 | + this.DrawGridLines( | |
1415 | + g, | |
1416 | + new PointF( (-baseClipBounds.Left % kGridSpanX) * scale, 0 ), | |
1417 | + new SizeF( kGridSpanX * scale, kGridSpanY * scale ), | |
1418 | + new RectangleF( 0, 0, (viewRect.Width), laneHeaderHeightMax ) ); | |
1419 | + } | |
1420 | + | |
1421 | + // 線幅の半分だけ上にずらして描く | |
1422 | + this.borderLinePen.Width = borderLineWidth * scale; | |
1423 | + g.DrawLine( | |
1424 | + this.borderLinePen, | |
1425 | + (float)viewRect.Left, laneHeaderHeightMax - borderLineWidth / 2 * scale, | |
1426 | + (float)viewRect.Right, laneHeaderHeightMax - borderLineWidth / 2 * scale ); | |
1427 | + | |
1428 | + g.Transform = baseMatrix; | |
1429 | + | |
1430 | + // 固定表示部分以外をクリップ | |
1431 | + var upperClipRect = baseClipBounds; | |
1432 | + upperClipRect.Height = laneHeaderHeightMax / scale; | |
1433 | + g.Clip = new Region( upperClipRect ); | |
1434 | + | |
1435 | + // 固定表示部分の描画 | |
1436 | + foreach( var lane in lanes ) | |
1437 | + { | |
1438 | + var laneRect = Util.TransformRectangle( baseMatrix, lane.Bounds ); | |
1439 | + float shiftY = (laneRect.Top < 0) ? (laneRect.Top / scale) : 0.0F; | |
1440 | + g.TranslateTransform( 0.0F, -shiftY ); | |
1441 | + if( lane == this.selectedElement ) | |
1442 | + { | |
1443 | + lane.ForegroundColor = Color.OrangeRed; | |
1444 | + lane.TextColor = Color.OrangeRed; | |
1445 | + } | |
1446 | + else | |
1447 | + { | |
1448 | + lane.ForegroundColor = Color.Black; | |
1449 | + lane.TextColor = Color.Black; | |
1450 | + } | |
1451 | + lane.Draw( g ); | |
1452 | + g.Transform = baseMatrix; | |
1453 | + } | |
1454 | + | |
1455 | + g.Transform = baseMatrix; | |
1456 | + } | |
1457 | + | |
1458 | + void MoveToHome() | |
1459 | + { | |
1460 | + this.MotionController.PositionXY = new PointF( | |
1461 | + this.ViewPanel.PositionXY.X - this.ViewPanel.PositionOffsetXY.X / this.ViewPanel.ViewScale, | |
1462 | + this.ViewPanel.PositionXY.Y - this.ViewPanel.PositionOffsetXY.Y / this.ViewPanel.ViewScale ); | |
1463 | + this.ViewPanel.PositionOffsetXY = new Point( 0, 0 ); | |
1464 | + this.MotionController.JumpPosition( new PointF( 0, 0 ) ); | |
1465 | + | |
1466 | + if( this.zoomIndex != kDefaultZoomIndex ) | |
1467 | + { | |
1468 | + this.zoomIndex = kDefaultZoomIndex; | |
1469 | + this.MotionController.JumpScale( ZoomScales[this.zoomIndex] ); | |
1470 | + } | |
1471 | + } | |
1472 | + | |
1473 | + void UpdateSectionList( List<SqElement> elements ) | |
1474 | + { | |
1475 | + this.SectionList.Items.Clear(); | |
1476 | + foreach( var element in elements ) | |
1477 | + { | |
1478 | + if( element.Type == SqElement.ElementType.HorizontalLine ) | |
1479 | + { | |
1480 | + var hline = (HorizontalLine)element; | |
1481 | + if( !string.IsNullOrEmpty( hline.Label ) ) | |
1482 | + { | |
1483 | + this.SectionList.Items.Add( element.LineNo.ToString(), hline.Label, -1 ); | |
1484 | + } | |
1485 | + } | |
1486 | + } | |
1487 | + } | |
1488 | + | |
1489 | + // レーンリストの項目を更新 | |
1490 | + void UpdateLaneList( List<SqElement> lanes ) | |
1491 | + { | |
1492 | + if( this.LaneList == null ) | |
1493 | + { | |
1494 | + return; | |
1495 | + } | |
1496 | + | |
1497 | + // 前回のチェック状態はできるだけ引き継ぐ | |
1498 | + var prevItems = new List<ListViewItem>(); | |
1499 | + foreach( ListViewItem item in this.LaneList.Items ) | |
1500 | + { | |
1501 | + prevItems.Add( item ); | |
1502 | + } | |
1503 | + | |
1504 | + this.LaneList.Items.Clear(); | |
1505 | + foreach( Lane lane in lanes ) | |
1506 | + { | |
1507 | + // Labelは他との重複を許容しているのでNameをアイテムのキーに使う | |
1508 | + var item = this.LaneList.Items.Add( lane.Name, lane.Label, -1 ); | |
1509 | + item.Tag = lane; | |
1510 | + | |
1511 | + int index = prevItems.FindIndex( ( prevItem ) => prevItem.Text == item.Text ); | |
1512 | + item.Checked = (index != -1) ? prevItems[index].Checked : true; | |
1513 | + } | |
1514 | + } | |
1515 | + | |
1516 | + // レーンリストの選択状態をライフライン要素のVisibleに反映 | |
1517 | + void UpdateLaneStateFromLaneList( List<SqElement> lanes, List<SqElement> elements ) | |
1518 | + { | |
1519 | + if( this.LaneList == null || this.LaneList.Items.Count != lanes.Count ) | |
1520 | + { | |
1521 | + return; | |
1522 | + } | |
1523 | + | |
1524 | + // チェック状態を表示状態に反映 | |
1525 | + foreach( ListViewItem item in this.LaneList.Items ) | |
1526 | + { | |
1527 | + var lane = (Lane)item.Tag; | |
1528 | + if( lane != null ) | |
1529 | + { | |
1530 | + if( lane.Visible != item.Checked ) | |
1531 | + { | |
1532 | + lane.Visible = item.Checked; | |
1533 | + } | |
1534 | + } | |
1535 | + } | |
1536 | + | |
1537 | + // レーンリスト通りの順に並べ替え | |
1538 | + lanes.Sort( (e1, e2) => { | |
1539 | + return this.LaneList.Items[e1.Name].Index - this.LaneList.Items[e2.Name].Index; | |
1540 | + } ); | |
1541 | + | |
1542 | + foreach( var element in elements ) | |
1543 | + { | |
1544 | + // 関連しているレーンがひとつでも非表示ならその要素は非表示に | |
1545 | + if( element.Type != SqElement.ElementType.Lane ) | |
1546 | + { | |
1547 | + element.Visible = element.LinkedLanes.TrueForAll( ( lane ) => lane.Visible ); | |
1548 | + } | |
1549 | + } | |
1550 | + | |
1551 | + this.needLayouting = true; | |
1552 | + } | |
1553 | + | |
1554 | + // 図面全体に対する表示領域の位置の比率を取得 | |
1555 | + // 左端/上端を0.0、右端/下端を1.0とする | |
1556 | + RectangleF GetVisibleAreaProportion() | |
1557 | + { | |
1558 | + var xy = new PointF( | |
1559 | + this.MotionController.TargetPositionXY.X / this.layoutedSize.Width, | |
1560 | + this.MotionController.TargetPositionXY.Y / this.layoutedSize.Height ); | |
1561 | + var wh = new SizeF( | |
1562 | + (this.MotionController.TargetPositionXY.X + this.ViewPanel.VisibleArea.Width) / this.layoutedSize.Width - xy.X, | |
1563 | + (this.MotionController.TargetPositionXY.Y + this.ViewPanel.VisibleArea.Height) / this.layoutedSize.Height - xy.Y ); | |
1564 | + var proportion = new RectangleF( xy, wh ); | |
1565 | + | |
1566 | + var sb = new StringBuilder(); | |
1567 | + | |
1568 | + sb.AppendFormat( "l={0:0.00}, t={1:0.00}, r={2:0.00}, b={3:0.00}", proportion.Left, proportion.Top, proportion.Right, proportion.Bottom ); | |
1569 | + FormDebug.SetItem( "visibleArea", "{" + sb.ToString() + "}" ); | |
1570 | + | |
1571 | + return proportion; | |
1572 | + } | |
1573 | + | |
1574 | + private void UpdateOpenFileList() | |
1575 | + { | |
1576 | + var items = this.uxOpenFile.DropDownItems.Find( "RecentFile", false ); | |
1577 | + foreach( var item in items ) | |
1578 | + { | |
1579 | + this.uxOpenFile.DropDownItems.Remove( item ); | |
1580 | + } | |
1581 | + | |
1582 | + foreach( var recentFile in this.setting.RecentFileList ) | |
1583 | + { | |
1584 | + var sb = new StringBuilder(); | |
1585 | + sb.AppendFormat( "{0} {1} : {2}", | |
1586 | + recentFile.Time.ToShortDateString(), | |
1587 | + recentFile.Time.ToShortTimeString(), | |
1588 | + recentFile.FileName ); | |
1589 | + var item = this.uxOpenFile.DropDownItems.Add( sb.ToString() ); | |
1590 | + item.Name = "RecentFile"; | |
1591 | + item.Tag = recentFile; | |
1592 | + if( !File.Exists( recentFile.FileName ) ) | |
1593 | + { | |
1594 | + item.Enabled = false; | |
1595 | + } | |
1596 | + } | |
1597 | + } | |
1598 | + | |
1599 | + private void AddRecentFile( string path ) | |
1600 | + { | |
1601 | + this.setting.RecentDirectory = Path.GetDirectoryName( path ); | |
1602 | + this.setting.RecentFileList.RemoveAll( ( s ) => (s.FileName == path) ); | |
1603 | + if( this.setting.RecentFileList.Count >= kRecentFileCountMax ) | |
1604 | + { | |
1605 | + this.setting.RecentFileList.RemoveAt( this.setting.RecentFileList.Count - 1 ); | |
1606 | + } | |
1607 | + this.setting.RecentFileList.Insert( 0, new Setting.RecentFile() { FileName = path, Time = DateTime.Now } ); | |
1608 | + this.setting.Save(); | |
1609 | + | |
1610 | + this.UpdateOpenFileList(); | |
1611 | + } | |
1612 | + | |
1613 | + private void uxOpenFile_NewClicked( object sender, EventArgs e ) | |
1614 | + { | |
1615 | + var fileName = "sq_" + DateTime.Now.ToString( "yyyyMMdd_hhmmss_fff" ) + ".txt"; | |
1616 | + var path = Path.Combine( Directory.GetCurrentDirectory(), fileName ); | |
1617 | + using( var fs = File.Create( path ) ) | |
1618 | + { | |
1619 | + ; | |
1620 | + } | |
1621 | + if( this.LoadFile( path ) ) | |
1622 | + { | |
1623 | + this.AddRecentFile( path ); | |
1624 | + } | |
1625 | + } | |
1626 | + | |
1627 | + private void uxOpenFile_OpenClicked( object sender, EventArgs e ) | |
1628 | + { | |
1629 | + var openFile = new OpenFileDialog(); | |
1630 | + openFile.InitialDirectory = this.setting.RecentDirectory; | |
1631 | + | |
1632 | + var result = openFile.ShowDialog(); | |
1633 | + if( result == DialogResult.OK ) | |
1634 | + { | |
1635 | + if( this.LoadFile( openFile.FileName ) ) | |
1636 | + { | |
1637 | + this.AddRecentFile( openFile.FileName ); | |
1638 | + } | |
1639 | + } | |
1640 | + } | |
1641 | + | |
1642 | + private void uxOpenFile_DropDownItemClicked( object sender, ToolStripItemClickedEventArgs e ) | |
1643 | + { | |
1644 | + if( e.ClickedItem.Name == "RecentFile" ) | |
1645 | + { | |
1646 | + var fileName = ((Setting.RecentFile)e.ClickedItem.Tag).FileName; | |
1647 | + if( this.LoadFile( fileName ) ) | |
1648 | + { | |
1649 | + this.AddRecentFile( fileName ); | |
1650 | + } | |
1651 | + } | |
1652 | + } | |
1653 | + } | |
1654 | +} | |
\ No newline at end of file |
@@ -0,0 +1,619 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Linq; | |
4 | +using System.Text; | |
5 | +using System.IO; | |
6 | +using System.Diagnostics; | |
7 | +using System.Reflection; | |
8 | + | |
9 | +namespace sqwriter | |
10 | +{ | |
11 | + class SqCompiler | |
12 | + { | |
13 | + // | |
14 | + // Private fields | |
15 | + // | |
16 | + | |
17 | + enum Commands | |
18 | + { | |
19 | + Invalid, | |
20 | + | |
21 | + Lane, | |
22 | + SyncMessage, | |
23 | + ASyncMessage, | |
24 | + Return, | |
25 | + Start, | |
26 | + End, | |
27 | + Blank, | |
28 | + HorizontalLine, | |
29 | + Exit, | |
30 | + } | |
31 | + struct CommandNameRecord | |
32 | + { | |
33 | + public CommandNameRecord( string name, Commands command ) | |
34 | + { | |
35 | + this.Name = name; | |
36 | + this.Command = command; | |
37 | + } | |
38 | + public string Name; | |
39 | + public Commands Command; | |
40 | + } | |
41 | + | |
42 | + struct Record | |
43 | + { | |
44 | + public Commands Command; | |
45 | + public string[] Operands; | |
46 | + public int LineNo; | |
47 | + public string LineText; | |
48 | + } | |
49 | + | |
50 | + public struct ErrorInfo | |
51 | + { | |
52 | + public int LineNo; | |
53 | + public string MessageText; | |
54 | + } | |
55 | + | |
56 | + readonly CommandNameRecord[] commandNames = new CommandNameRecord[] | |
57 | + { | |
58 | + new CommandNameRecord( "lane", Commands.Lane ), | |
59 | + new CommandNameRecord( "sync", Commands.SyncMessage ), | |
60 | + new CommandNameRecord( "call", Commands.SyncMessage ), | |
61 | + new CommandNameRecord( "async", Commands.ASyncMessage ), | |
62 | + new CommandNameRecord( "send", Commands.ASyncMessage ), | |
63 | + new CommandNameRecord( "return", Commands.Return ), | |
64 | + new CommandNameRecord( "back", Commands.Return ), | |
65 | + new CommandNameRecord( "start", Commands.Start ), | |
66 | + new CommandNameRecord( "end", Commands.End ), | |
67 | + new CommandNameRecord( "blank", Commands.Blank ), | |
68 | + new CommandNameRecord( "hline", Commands.HorizontalLine ), | |
69 | + new CommandNameRecord( "exit", Commands.Exit ), | |
70 | + }; | |
71 | + | |
72 | + List<ErrorInfo> errorMessages = null; | |
73 | + | |
74 | + public SqAssembly Compile( TextReader reader ) | |
75 | + { | |
76 | + SqAssembly assembly = new SqAssembly(); | |
77 | + | |
78 | + this.errorMessages = assembly.Errors; | |
79 | + | |
80 | + List<Record> records = new List<Record>(); | |
81 | + MakeRecords( reader, ref records ); | |
82 | + | |
83 | + var lanes = assembly.Lanes; | |
84 | + var nodes = assembly.Elements; | |
85 | + this.MakeNodes( records, ref lanes, ref nodes ); | |
86 | + | |
87 | + return assembly; | |
88 | + } | |
89 | + | |
90 | + // | |
91 | + // Private methods | |
92 | + // | |
93 | + | |
94 | + // ソースファイルからレコードリストを作成 | |
95 | + void MakeRecords( TextReader reader, ref List<Record> records ) | |
96 | + { | |
97 | + for( int lineNo = 1; ; lineNo++ ) | |
98 | + { | |
99 | + string line = reader.ReadLine(); | |
100 | + if( line == null ) | |
101 | + { | |
102 | + break; | |
103 | + } | |
104 | + | |
105 | + line = line.Trim(); | |
106 | + | |
107 | + // 空白行 | |
108 | + if( line == "" ) | |
109 | + { | |
110 | + continue; | |
111 | + } | |
112 | + // コメント行 | |
113 | + if( line.Substring( 0, 1 ) == "#" || | |
114 | + (line.Length >= 2 && line.Substring( 0, 2 ) == "//" ) ) | |
115 | + { | |
116 | + continue; | |
117 | + } | |
118 | + | |
119 | + line = line.Replace( @"\n", "\n" ); | |
120 | + | |
121 | + string[] tokens = line.Split( | |
122 | + new char[] { ' ', '\t' }, | |
123 | + StringSplitOptions.RemoveEmptyEntries ); | |
124 | + | |
125 | + Record record = new Record(); | |
126 | + record.Command = Commands.Invalid; | |
127 | + | |
128 | + string token0 = tokens[0].ToLower(); | |
129 | + foreach( CommandNameRecord r in commandNames ) | |
130 | + { | |
131 | + if( r.Name == token0 ) | |
132 | + { | |
133 | + record.Command = r.Command; | |
134 | + break; | |
135 | + } | |
136 | + } | |
137 | + | |
138 | + if( record.Command == Commands.Invalid ) | |
139 | + { | |
140 | + errorMessages.Add( new ErrorInfo { LineNo = lineNo, MessageText = string.Format( "未定義のコマンドです:{0}", token0 ) } ); | |
141 | + continue; | |
142 | + } | |
143 | + | |
144 | + if( record.Command == Commands.Exit ) | |
145 | + { | |
146 | + break; | |
147 | + } | |
148 | + | |
149 | + record.Operands = new string[tokens.Length - 1]; | |
150 | + record.LineNo = lineNo; | |
151 | + record.LineText = line; | |
152 | + Array.Copy( tokens, 1, record.Operands, 0, record.Operands.Length ); | |
153 | + | |
154 | + records.Add( record ); | |
155 | + } | |
156 | + } | |
157 | + | |
158 | + // レコードリストからノードリストを作成 | |
159 | + void MakeNodes( List<Record> records, ref List<SqElement> lanes, ref List<SqElement> elements ) | |
160 | + { | |
161 | + int currentStep = 0; | |
162 | + Commands prevCommand = Commands.Invalid; | |
163 | + SqElement prevElement = null; | |
164 | + Dictionary<Lane, Activity> openActivities = new Dictionary<Lane, Activity>(); | |
165 | + Dictionary<string, Lane> laneTable = new Dictionary<string,Lane>(); | |
166 | + | |
167 | + foreach( Record r in records ) | |
168 | + { | |
169 | + Trace.Assert( r.Command != Commands.Exit && r.Command != Commands.Invalid ); | |
170 | + | |
171 | + if( prevCommand != Commands.Invalid ) | |
172 | + { | |
173 | + if( r.Command == Commands.SyncMessage || | |
174 | + r.Command == Commands.ASyncMessage || | |
175 | + r.Command == Commands.Return || | |
176 | + r.Command == Commands.Blank || | |
177 | + r.Command == Commands.HorizontalLine ) | |
178 | + { | |
179 | + currentStep++; | |
180 | + } | |
181 | + else | |
182 | + { | |
183 | + if( r.Command != prevCommand ) | |
184 | + { | |
185 | + currentStep++; | |
186 | + } | |
187 | + } | |
188 | + } | |
189 | + | |
190 | + SqElement element = null; | |
191 | + | |
192 | + if( r.Command == Commands.Lane ) | |
193 | + { | |
194 | + // レーン | |
195 | + Lane lane = MakeLane( r, currentStep, laneTable ); | |
196 | + if( lane == null ) | |
197 | + { | |
198 | + continue; | |
199 | + } | |
200 | + laneTable.Add( lane.Name, lane ); | |
201 | + element = lane; | |
202 | + } | |
203 | + else if( r.Command == Commands.Start ) | |
204 | + { | |
205 | + // 実行開始 | |
206 | + Activity activity = MakeActivity( r, currentStep, laneTable, openActivities ); | |
207 | + if( activity == null ) | |
208 | + { | |
209 | + continue; | |
210 | + } | |
211 | + openActivities.Add( activity.Lane, activity ); | |
212 | + element = activity; | |
213 | + } | |
214 | + else if( r.Command == Commands.End ) | |
215 | + { | |
216 | + // 実行終了 | |
217 | + ActivityTerminator terminator = TerminateActivity( r, currentStep, laneTable, openActivities ); | |
218 | + if( terminator == null ) | |
219 | + { | |
220 | + continue; | |
221 | + } | |
222 | + openActivities.Remove( terminator.LinkedActivity.Lane ); | |
223 | + element = terminator; | |
224 | + } | |
225 | + else if( r.Command == Commands.SyncMessage || | |
226 | + r.Command == Commands.ASyncMessage || | |
227 | + r.Command == Commands.Return ) | |
228 | + { | |
229 | + // メッセージ | |
230 | + MessageArrow message = MakeMessage( r, currentStep, laneTable ); | |
231 | + if( message == null ) | |
232 | + { | |
233 | + continue; | |
234 | + } | |
235 | + element = message; | |
236 | + } | |
237 | + else if( r.Command == Commands.Blank ) | |
238 | + { | |
239 | + Blank blank = MakeBlank( r, currentStep ); | |
240 | + if( blank == null ) | |
241 | + { | |
242 | + continue; | |
243 | + } | |
244 | + element = blank; | |
245 | + } | |
246 | + else if( r.Command == Commands.HorizontalLine ) | |
247 | + { | |
248 | + HorizontalLine hline = MakeHorizontalLine( r, currentStep ); | |
249 | + if( hline == null ) | |
250 | + { | |
251 | + continue; | |
252 | + } | |
253 | + element = hline; | |
254 | + } | |
255 | + else | |
256 | + { | |
257 | + //prevCommand = Commands.Invalid; | |
258 | + continue; | |
259 | + } | |
260 | + | |
261 | + // 位置補正 | |
262 | + //if( prevElement != null && | |
263 | + // prevElement.Type == SqElement.ElementType.MessageArrow && | |
264 | + // element.Type == SqElement.ElementType.MessageArrow ) | |
265 | + //{ | |
266 | + // // 双方の関連ライフラインを総当りで見る | |
267 | + // // 一致するものなければ同一縦位置での表示を許容 | |
268 | + // bool result = prevElement.LinkedLanes.TrueForAll( ( lane1 ) => | |
269 | + // element.LinkedLanes.TrueForAll( ( lane2 ) => (lane1 != lane2) ) ); | |
270 | + // if( result ) | |
271 | + // { | |
272 | + // currentStep--; | |
273 | + // element.Step--; | |
274 | + // } | |
275 | + //} | |
276 | + | |
277 | + element.LineNo = r.LineNo; | |
278 | + elements.Add( element ); | |
279 | + | |
280 | + prevCommand = r.Command; | |
281 | + prevElement = element; | |
282 | + } | |
283 | + | |
284 | + lanes.AddRange( laneTable.Values ); | |
285 | + } | |
286 | + | |
287 | + Lane MakeLane( Record record, int step, Dictionary<string,Lane> laneTable ) | |
288 | + { | |
289 | + if( record.Command != Commands.Lane ) | |
290 | + { | |
291 | + Trace.TraceInformation( "[ERROR][{0}]Invalid param.", MethodBase.GetCurrentMethod().Name ); | |
292 | + return null; | |
293 | + } | |
294 | + | |
295 | + Lane lane = new Lane(); | |
296 | + if( record.Operands.Length == 1 ) | |
297 | + { | |
298 | + lane.Name = record.Operands[0]; | |
299 | + lane.Label = record.Operands[0]; | |
300 | + } | |
301 | + else if( record.Operands.Length >= 2 ) | |
302 | + { | |
303 | + lane.Name = record.Operands[0]; | |
304 | + var sb = new StringBuilder(); | |
305 | + for( int i = 1; i < record.Operands.Length; i++ ) | |
306 | + { | |
307 | + sb.Append( record.Operands[i] ).Append( " " ); | |
308 | + } | |
309 | + lane.Label = sb.ToString().TrimEnd(); | |
310 | + } | |
311 | + else | |
312 | + { | |
313 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "パラメータ数が不正です:{0}", record.Operands.Length ) } ); | |
314 | + return null; | |
315 | + } | |
316 | + | |
317 | + if( laneTable.ContainsKey( lane.Name ) ) | |
318 | + { | |
319 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "レーン名\"{0}\"はすでに存在します", lane.Name ) } ); | |
320 | + return null; | |
321 | + } | |
322 | + | |
323 | + lane.Step = step; | |
324 | + | |
325 | + return lane; | |
326 | + } | |
327 | + | |
328 | + Activity MakeActivity( Record record, int step, Dictionary<string, Lane> laneTable, Dictionary<Lane, Activity> openActivities ) | |
329 | + { | |
330 | + if( record.Command != Commands.Start ) | |
331 | + { | |
332 | + Trace.TraceInformation( "[ERROR][{0}]Invalid param.", MethodBase.GetCurrentMethod().Name ); | |
333 | + return null; | |
334 | + } | |
335 | + | |
336 | + if( record.Operands.Length != 1 ) | |
337 | + { | |
338 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "パラメータ数が不正です:{0}", record.Operands.Length ) } ); | |
339 | + return null; | |
340 | + } | |
341 | + | |
342 | + Lane lane = null; | |
343 | + if( !laneTable.TryGetValue( record.Operands[0], out lane ) ) | |
344 | + { | |
345 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "\"{0}\"は定義されていません", record.Operands[0] ) } ); | |
346 | + return null; | |
347 | + } | |
348 | + | |
349 | + if( openActivities.ContainsKey( lane ) ) | |
350 | + { | |
351 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "すでにSTARTされています" ) } ); | |
352 | + return null; | |
353 | + } | |
354 | + | |
355 | + Activity execution = new Activity(); | |
356 | + execution.Lane = lane; | |
357 | + execution.Step = step; | |
358 | + | |
359 | + execution.LinkedLanes.Add( lane ); | |
360 | + | |
361 | + return execution; | |
362 | + } | |
363 | + | |
364 | + ActivityTerminator TerminateActivity( Record record, int step, Dictionary<string, Lane> laneTable, Dictionary<Lane, Activity> openActivities ) | |
365 | + { | |
366 | + if( record.Command != Commands.End ) | |
367 | + { | |
368 | + Trace.TraceInformation( "[ERROR][{0}]Invalid param.", MethodBase.GetCurrentMethod().Name ); | |
369 | + return null; | |
370 | + } | |
371 | + | |
372 | + if( record.Operands.Length != 1 ) | |
373 | + { | |
374 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "パラメータ数が不正です:{0}", record.Operands.Length ) } ); | |
375 | + return null; | |
376 | + } | |
377 | + | |
378 | + Lane lane = null; | |
379 | + if( !laneTable.TryGetValue( record.Operands[0], out lane ) ) | |
380 | + { | |
381 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "\"{0}\"は定義されていません", record.Operands[0] ) } ); | |
382 | + return null; | |
383 | + } | |
384 | + | |
385 | + if( !openActivities.ContainsKey( lane ) ) | |
386 | + { | |
387 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "対になるSTARTがありません", record.LineNo ) } ); | |
388 | + return null; | |
389 | + } | |
390 | + Activity execution = openActivities[lane]; | |
391 | + | |
392 | + ActivityTerminator terminator = new ActivityTerminator(); | |
393 | + terminator.LinkedActivity = execution; | |
394 | + terminator.Step = step; | |
395 | + //activity.EndStep = step; | |
396 | + | |
397 | + execution.LinkedLanes.Add( lane ); | |
398 | + | |
399 | + return terminator; | |
400 | + } | |
401 | + | |
402 | + MessageArrow MakeMessage( Record record, int step, Dictionary<string, Lane> laneTable ) | |
403 | + { | |
404 | + if( record.Command != Commands.SyncMessage && | |
405 | + record.Command != Commands.ASyncMessage && | |
406 | + record.Command != Commands.Return ) | |
407 | + { | |
408 | + Trace.TraceInformation( "[ERROR][{0}]Invalid param.", MethodBase.GetCurrentMethod().Name ); | |
409 | + return null; | |
410 | + } | |
411 | + | |
412 | + if( record.Operands.Length < 3 ) | |
413 | + { | |
414 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "パラメータ数が不正です:{0}", record.Operands.Length ) } ); | |
415 | + return null; | |
416 | + } | |
417 | + | |
418 | + string fromLaneName = null; | |
419 | + string toLaneName = null; | |
420 | + if( record.Operands[1] == ">" ) | |
421 | + { | |
422 | + fromLaneName = record.Operands[0]; | |
423 | + toLaneName = record.Operands[2]; | |
424 | + } | |
425 | + else if( record.Operands[1] == "<" ) | |
426 | + { | |
427 | + fromLaneName = record.Operands[2]; | |
428 | + toLaneName = record.Operands[0]; | |
429 | + } | |
430 | + else | |
431 | + { | |
432 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "\">\"または\"<\"が必要です" ) } ); | |
433 | + return null; | |
434 | + } | |
435 | + | |
436 | + MessageArrow message = new MessageArrow(); | |
437 | + | |
438 | + Lane fromLane = null; | |
439 | + if( fromLaneName == "-" ) | |
440 | + { | |
441 | + //fromLaneName = null; | |
442 | + } | |
443 | + else if( !laneTable.TryGetValue( fromLaneName, out fromLane ) ) | |
444 | + { | |
445 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "\"{0}\"は定義されていません", fromLaneName ) } ); | |
446 | + return null; | |
447 | + } | |
448 | + message.From = fromLane; | |
449 | + | |
450 | + Lane toLane = null; | |
451 | + if( toLaneName == "-" ) | |
452 | + { | |
453 | + //toLane = null; | |
454 | + } | |
455 | + else if( !laneTable.TryGetValue( toLaneName, out toLane ) ) | |
456 | + { | |
457 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "\"{0}\"は定義されていません", toLaneName ) } ); | |
458 | + return null; | |
459 | + } | |
460 | + message.To = toLane; | |
461 | + | |
462 | + if( message.From == null && message.To == null ) | |
463 | + { | |
464 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "送信元と送信先の両方に\"-\"を指定することはできません" ) } ); | |
465 | + return null; | |
466 | + } | |
467 | + | |
468 | + if( record.Operands.Length > 3 ) | |
469 | + { | |
470 | + message.Label = record.Operands[3]; | |
471 | + var sb = new StringBuilder(); | |
472 | + for( int i = 4; i < record.Operands.Length; i++ ) | |
473 | + { | |
474 | + sb.Append( record.Operands[i] ).Append( " " ); | |
475 | + } | |
476 | + message.ParamLabel = sb.ToString().TrimEnd(); | |
477 | + } | |
478 | + | |
479 | + if( record.Command == Commands.SyncMessage ) | |
480 | + { | |
481 | + message.ArrowType = MessageArrow.MessageArrowType.Sync; | |
482 | + } | |
483 | + else if( record.Command == Commands.ASyncMessage ) | |
484 | + { | |
485 | + message.ArrowType = MessageArrow.MessageArrowType.ASync; | |
486 | + } | |
487 | + else if( record.Command == Commands.Return ) | |
488 | + { | |
489 | + message.ArrowType = MessageArrow.MessageArrowType.Return; | |
490 | + } | |
491 | + else | |
492 | + { | |
493 | + Console.WriteLine( "[ERROR][{0}]", MethodBase.GetCurrentMethod().Name ); | |
494 | + } | |
495 | + message.Step = step; | |
496 | + | |
497 | + if( fromLane != null ) | |
498 | + { | |
499 | + message.LinkedLanes.Add( fromLane ); | |
500 | + } | |
501 | + if( toLane != null ) | |
502 | + { | |
503 | + message.LinkedLanes.Add( toLane ); | |
504 | + } | |
505 | + | |
506 | + return message; | |
507 | + } | |
508 | + | |
509 | + Blank MakeBlank( Record record, int step ) | |
510 | + { | |
511 | + Blank blank = null; | |
512 | + if( record.Operands.Length == 0 ) | |
513 | + { | |
514 | + blank = new Blank(); | |
515 | + } | |
516 | + else if( record.Operands.Length == 1 ) | |
517 | + { | |
518 | + float num; | |
519 | + if( !ParseNumeric( record.Operands[0], out num ) ) | |
520 | + { | |
521 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "有効な数値を指定して下さい:{0}", record.Operands[0] ) } ); | |
522 | + } | |
523 | + blank = new Blank( (int)num ); | |
524 | + } | |
525 | + else | |
526 | + { | |
527 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "パラメータ数が不正です:{0}", record.Operands.Length ) } ); | |
528 | + return null; | |
529 | + } | |
530 | + blank.Step = step; | |
531 | + | |
532 | + return blank; | |
533 | + } | |
534 | + | |
535 | + HorizontalLine MakeHorizontalLine( Record record, int step ) | |
536 | + { | |
537 | + HorizontalLine hline = new HorizontalLine(); | |
538 | + if( record.Operands.Length == 0 ) | |
539 | + { | |
540 | + // ラベルなし | |
541 | + } | |
542 | + else if( record.Operands.Length > 0 ) | |
543 | + { | |
544 | + var sb = new StringBuilder(); | |
545 | + for( int i = 0; i < record.Operands.Length; i++ ) | |
546 | + { | |
547 | + sb.Append( record.Operands[i] ).Append( " " ); | |
548 | + } | |
549 | + hline.Label = sb.ToString().TrimEnd(); | |
550 | + } | |
551 | + else | |
552 | + { | |
553 | + this.errorMessages.Add( new ErrorInfo { LineNo = record.LineNo, MessageText = string.Format( "パラメータ数が不正です:{0}", record.Operands.Length ) } ); | |
554 | + return null; | |
555 | + } | |
556 | + hline.Step = step; | |
557 | + | |
558 | + return hline; | |
559 | + } | |
560 | + | |
561 | + bool ParseNumeric( string s, out float num ) | |
562 | + { | |
563 | + num = 0; | |
564 | + s = s.ToLower(); | |
565 | + try | |
566 | + { | |
567 | + if( s.StartsWith( "#" ) || s.StartsWith( "x" ) ) | |
568 | + { | |
569 | + num = Int32.Parse( s.Substring( 1 ), System.Globalization.NumberStyles.HexNumber ); | |
570 | + } | |
571 | + else if( s.StartsWith( "0x" ) ) | |
572 | + { | |
573 | + num = Int32.Parse( s.Substring( 2 ), System.Globalization.NumberStyles.HexNumber ); | |
574 | + } | |
575 | + else | |
576 | + { | |
577 | + num = Int32.Parse( s, System.Globalization.NumberStyles.Number ); | |
578 | + } | |
579 | + } | |
580 | + catch( Exception ) | |
581 | + { | |
582 | + return false; | |
583 | + } | |
584 | + | |
585 | + return true; | |
586 | + } | |
587 | + } | |
588 | + | |
589 | + // アセンブリデータ(コンパイル結果) | |
590 | + class SqAssembly | |
591 | + { | |
592 | + List<SqElement> makedElements = new List<SqElement>(); | |
593 | + List<SqElement> makedLanes = new List<SqElement>(); | |
594 | + List<SqCompiler.ErrorInfo> errors = new List<SqCompiler.ErrorInfo>(); | |
595 | + | |
596 | + public List<SqElement> Elements | |
597 | + { | |
598 | + get { return this.makedElements; } | |
599 | + } | |
600 | + public List<SqElement> Lanes | |
601 | + { | |
602 | + get { return this.makedLanes; } | |
603 | + } | |
604 | + public List<SqCompiler.ErrorInfo> Errors | |
605 | + { | |
606 | + get { return this.errors; } | |
607 | + } | |
608 | + | |
609 | + public SqElement GetVisibleElementAt( float x, float y ) | |
610 | + { | |
611 | + int index = this.makedElements.FindIndex( ( element ) => element.Visible && element.Bounds.Contains( (int)x, (int)y ) ); | |
612 | + return (index >= 0) ? this.makedElements[index] : null; | |
613 | + } | |
614 | + | |
615 | + public SqAssembly() | |
616 | + { | |
617 | + } | |
618 | + } | |
619 | +} |
@@ -0,0 +1,53 @@ | ||
1 | +# ver.1.4.0 - 2016.11.15 | |
2 | + | |
3 | +* mod: 編集中の行に対するエラー表示はしないようにした (refs #36783) | |
4 | +* mod: セクション区切りを検索対象に戻した (refs #36780) | |
5 | +* add: スクリプトエディタを搭載 (refs #36783) | |
6 | +* add: history.txtを追加 | |
7 | +* mod: セクション区切りを検索対象から除外 (refs #36780) | |
8 | +* mod: コマンドライン引数/ドラッグアンドドロップで開いたファイルも履歴に追加 (refs #36781) | |
9 | +* fix: 先頭から下にセクション移動すると2つ下のセクションに移動してしまう問題を修正 | |
10 | +* OSDNにお引っ越し (2016.11.07) | |
11 | + | |
12 | +# ver.1.3.0 - 2016.11.02 | |
13 | + | |
14 | +* add: 図面行番号表示機能を追加 | |
15 | +* mod: マウスによる図面要素の選択をOn検知からOff検知に変更 | |
16 | +* fix: ズーム動作した後に表示基準点がずれる問題を修正 | |
17 | +* mod: キーバインド変更:Up/Downは選択要素の移動 | |
18 | +* mod: キーバインド変更:Ctrl+Up/Downでセクション区切りジャンプ | |
19 | +* mod: ライフライン、メッセージ、水平線の末尾パラメータの空白文字/改行を許容 | |
20 | +* mod: 自己メッセージの選択範囲を広げた | |
21 | +* mod: キーボードヘルプのリスト項目を実行しても反応なしはよくないのでKeyEnterdはnull許容せずとした | |
22 | +* mod: 選択した図面要素が一部でも表示範囲外なら見えるところまでスクロールするようにした | |
23 | +* mod: 図面要素の位置がグリッド線に合うようにした | |
24 | +* mod: Util::TraverseControlsの無駄判定を削除 | |
25 | +* add: ショートカットキーの一覧表示機能を追加 | |
26 | +* mod: ベクトルスクロールインジケータの見た目を良くした | |
27 | +* add: ライフラインの並べ替え機能を追加 | |
28 | +* add: セクション一覧表示機能を追加 | |
29 | +* fix: 固定表示領域のライフラインが選択できない問題を修正 | |
30 | +* add: 選択したライフラインをDELキーで非表示にできるようにした | |
31 | +* add: マウスクリックで要素を選択できるようにした | |
32 | +* mod: ツールバーから行番号ジャンプを削除 | |
33 | +* mod: 選択移動時の表示位置補正改善 | |
34 | +* fix: エラーメッセージに出るライフライン名が逆になっている問題を修正 | |
35 | + | |
36 | +# ver.1.2.0 - 2016.10.21 | |
37 | + | |
38 | +* add: キーワード検索機能を追加 | |
39 | +* add: ファイル履歴保存機能を追加 | |
40 | +* fix: メッセージコマンドの送信元か送信先に「-」を指定するとクラッシュする問題を修正 | |
41 | + | |
42 | +# ver.1.1.0 - 2016.10.12 | |
43 | + | |
44 | +* fix: LayoutElementsに渡すレイアウト幅が表示対象のライフラインに限定されていない問題を修正 | |
45 | +* add: ライフライン一覧表示と表示/非表示を切り替える機能を追加 | |
46 | +* mod: グリッド線の色をちょっと薄くした | |
47 | +* mod: ズームイン時のライフラインヘッダの拡大を緩やかにした | |
48 | +* mod: ズーム倍率最大を800%から400%にした | |
49 | +* mod: ViewPanelクラスの自前バッファリングを廃止してDoubleBufferedプロパティを使うようにした | |
50 | + | |
51 | +# ver.1.0.0 - 2016.10.05 | |
52 | + | |
53 | +* bitbucketに登録、開発再開 |
@@ -0,0 +1,444 @@ | ||
1 | +namespace sqwriter | |
2 | +{ | |
3 | + partial class FormMain | |
4 | + { | |
5 | + /// <summary> | |
6 | + /// 必要なデザイナー変数です。 | |
7 | + /// </summary> | |
8 | + private System.ComponentModel.IContainer components = null; | |
9 | + | |
10 | + /// <summary> | |
11 | + /// 使用中のリソースをすべてクリーンアップします。 | |
12 | + /// </summary> | |
13 | + /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param> | |
14 | + protected override void Dispose( bool disposing ) | |
15 | + { | |
16 | + if( disposing && (components != null) ) | |
17 | + { | |
18 | + components.Dispose(); | |
19 | + } | |
20 | + base.Dispose( disposing ); | |
21 | + } | |
22 | + | |
23 | + #region Windows フォーム デザイナーで生成されたコード | |
24 | + | |
25 | + /// <summary> | |
26 | + /// デザイナー サポートに必要なメソッドです。このメソッドの内容を | |
27 | + /// コード エディターで変更しないでください。 | |
28 | + /// </summary> | |
29 | + private void InitializeComponent() | |
30 | + { | |
31 | + this.components = new System.ComponentModel.Container(); | |
32 | + Sgry.Azuki.FontInfo fontInfo2 = new Sgry.Azuki.FontInfo(); | |
33 | + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain)); | |
34 | + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); | |
35 | + this.toolStripStatusLabelFileInfo = new System.Windows.Forms.ToolStripStatusLabel(); | |
36 | + this.toolStripStatusLabelMode = new System.Windows.Forms.ToolStripStatusLabel(); | |
37 | + this.toolStripStatusLabelDrawTime = new System.Windows.Forms.ToolStripStatusLabel(); | |
38 | + this.toolStripStatusLabelMousePoint = new System.Windows.Forms.ToolStripStatusLabel(); | |
39 | + this.toolStripStatusLabelViewPoint = new System.Windows.Forms.ToolStripStatusLabel(); | |
40 | + this.toolStripStatusLabelZoom = new System.Windows.Forms.ToolStripStatusLabel(); | |
41 | + this.toolStripContainer1 = new System.Windows.Forms.ToolStripContainer(); | |
42 | + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); | |
43 | + this.splitContainer2 = new System.Windows.Forms.SplitContainer(); | |
44 | + this.splitContainer3 = new System.Windows.Forms.SplitContainer(); | |
45 | + this.editor = new Sgry.Azuki.WinForms.AzukiControl(); | |
46 | + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); | |
47 | + this.uxOpenFile = new System.Windows.Forms.ToolStripDropDownButton(); | |
48 | + this.uxShowSidePanel = new System.Windows.Forms.ToolStripButton(); | |
49 | + this.uxOpenFolder = new System.Windows.Forms.ToolStripButton(); | |
50 | + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); | |
51 | + this.uxFindButton = new System.Windows.Forms.ToolStripButton(); | |
52 | + this.uxFindBox = new System.Windows.Forms.ToolStripTextBox(); | |
53 | + this.uxFindPrev = new System.Windows.Forms.ToolStripButton(); | |
54 | + this.uxFindNext = new System.Windows.Forms.ToolStripButton(); | |
55 | + this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); | |
56 | + this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); | |
57 | + this.toolStripMenuItemExportToImage = new System.Windows.Forms.ToolStripMenuItem(); | |
58 | + this.toolStripMenuItemCopyToClipboard = new System.Windows.Forms.ToolStripMenuItem(); | |
59 | + this.imageList1 = new System.Windows.Forms.ImageList(this.components); | |
60 | + this.uxKeyBinds = new System.Windows.Forms.ToolStripButton(); | |
61 | + this.uxAbout = new System.Windows.Forms.ToolStripButton(); | |
62 | + this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); | |
63 | + this.statusStrip1.SuspendLayout(); | |
64 | + this.toolStripContainer1.ContentPanel.SuspendLayout(); | |
65 | + this.toolStripContainer1.TopToolStripPanel.SuspendLayout(); | |
66 | + this.toolStripContainer1.SuspendLayout(); | |
67 | + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); | |
68 | + this.splitContainer1.Panel1.SuspendLayout(); | |
69 | + this.splitContainer1.Panel2.SuspendLayout(); | |
70 | + this.splitContainer1.SuspendLayout(); | |
71 | + ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit(); | |
72 | + this.splitContainer2.SuspendLayout(); | |
73 | + ((System.ComponentModel.ISupportInitialize)(this.splitContainer3)).BeginInit(); | |
74 | + this.splitContainer3.Panel2.SuspendLayout(); | |
75 | + this.splitContainer3.SuspendLayout(); | |
76 | + this.toolStrip1.SuspendLayout(); | |
77 | + this.contextMenuStrip1.SuspendLayout(); | |
78 | + this.SuspendLayout(); | |
79 | + // | |
80 | + // statusStrip1 | |
81 | + // | |
82 | + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { | |
83 | + this.toolStripStatusLabelFileInfo, | |
84 | + this.toolStripStatusLabelMode, | |
85 | + this.toolStripStatusLabelDrawTime, | |
86 | + this.toolStripStatusLabelMousePoint, | |
87 | + this.toolStripStatusLabelViewPoint, | |
88 | + this.toolStripStatusLabelZoom}); | |
89 | + this.statusStrip1.Location = new System.Drawing.Point(0, 379); | |
90 | + this.statusStrip1.Name = "statusStrip1"; | |
91 | + this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 16, 0); | |
92 | + this.statusStrip1.Size = new System.Drawing.Size(697, 22); | |
93 | + this.statusStrip1.TabIndex = 1; | |
94 | + this.statusStrip1.Text = "statusStrip1"; | |
95 | + // | |
96 | + // toolStripStatusLabelFileInfo | |
97 | + // | |
98 | + this.toolStripStatusLabelFileInfo.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; | |
99 | + this.toolStripStatusLabelFileInfo.Name = "toolStripStatusLabelFileInfo"; | |
100 | + this.toolStripStatusLabelFileInfo.Size = new System.Drawing.Size(381, 17); | |
101 | + this.toolStripStatusLabelFileInfo.Spring = true; | |
102 | + this.toolStripStatusLabelFileInfo.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; | |
103 | + // | |
104 | + // toolStripStatusLabelMode | |
105 | + // | |
106 | + this.toolStripStatusLabelMode.Name = "toolStripStatusLabelMode"; | |
107 | + this.toolStripStatusLabelMode.Size = new System.Drawing.Size(42, 17); | |
108 | + this.toolStripStatusLabelMode.Text = "Debug"; | |
109 | + // | |
110 | + // toolStripStatusLabelDrawTime | |
111 | + // | |
112 | + this.toolStripStatusLabelDrawTime.Name = "toolStripStatusLabelDrawTime"; | |
113 | + this.toolStripStatusLabelDrawTime.Size = new System.Drawing.Size(65, 17); | |
114 | + this.toolStripStatusLabelDrawTime.Text = "Draw:-.-ms"; | |
115 | + // | |
116 | + // toolStripStatusLabelMousePoint | |
117 | + // | |
118 | + this.toolStripStatusLabelMousePoint.Name = "toolStripStatusLabelMousePoint"; | |
119 | + this.toolStripStatusLabelMousePoint.Size = new System.Drawing.Size(67, 17); | |
120 | + this.toolStripStatusLabelMousePoint.Text = "Mouse:(-,-)"; | |
121 | + // | |
122 | + // toolStripStatusLabelViewPoint | |
123 | + // | |
124 | + this.toolStripStatusLabelViewPoint.Name = "toolStripStatusLabelViewPoint"; | |
125 | + this.toolStripStatusLabelViewPoint.Size = new System.Drawing.Size(56, 17); | |
126 | + this.toolStripStatusLabelViewPoint.Text = "View:(-,-)"; | |
127 | + // | |
128 | + // toolStripStatusLabelZoom | |
129 | + // | |
130 | + this.toolStripStatusLabelZoom.Name = "toolStripStatusLabelZoom"; | |
131 | + this.toolStripStatusLabelZoom.Size = new System.Drawing.Size(69, 17); | |
132 | + this.toolStripStatusLabelZoom.Text = "Zoom:100%"; | |
133 | + // | |
134 | + // toolStripContainer1 | |
135 | + // | |
136 | + this.toolStripContainer1.BottomToolStripPanelVisible = false; | |
137 | + // | |
138 | + // toolStripContainer1.ContentPanel | |
139 | + // | |
140 | + this.toolStripContainer1.ContentPanel.Controls.Add(this.splitContainer1); | |
141 | + this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(697, 354); | |
142 | + this.toolStripContainer1.Dock = System.Windows.Forms.DockStyle.Fill; | |
143 | + this.toolStripContainer1.LeftToolStripPanelVisible = false; | |
144 | + this.toolStripContainer1.Location = new System.Drawing.Point(0, 0); | |
145 | + this.toolStripContainer1.Name = "toolStripContainer1"; | |
146 | + this.toolStripContainer1.RightToolStripPanelVisible = false; | |
147 | + this.toolStripContainer1.Size = new System.Drawing.Size(697, 379); | |
148 | + this.toolStripContainer1.TabIndex = 2; | |
149 | + this.toolStripContainer1.Text = "toolStripContainer1"; | |
150 | + // | |
151 | + // toolStripContainer1.TopToolStripPanel | |
152 | + // | |
153 | + this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.toolStrip1); | |
154 | + // | |
155 | + // splitContainer1 | |
156 | + // | |
157 | + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; | |
158 | + this.splitContainer1.Location = new System.Drawing.Point(0, 0); | |
159 | + this.splitContainer1.Name = "splitContainer1"; | |
160 | + // | |
161 | + // splitContainer1.Panel1 | |
162 | + // | |
163 | + this.splitContainer1.Panel1.Controls.Add(this.splitContainer2); | |
164 | + // | |
165 | + // splitContainer1.Panel2 | |
166 | + // | |
167 | + this.splitContainer1.Panel2.Controls.Add(this.splitContainer3); | |
168 | + this.splitContainer1.Size = new System.Drawing.Size(697, 354); | |
169 | + this.splitContainer1.SplitterDistance = 231; | |
170 | + this.splitContainer1.TabIndex = 0; | |
171 | + // | |
172 | + // splitContainer2 | |
173 | + // | |
174 | + this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill; | |
175 | + this.splitContainer2.Location = new System.Drawing.Point(0, 0); | |
176 | + this.splitContainer2.Name = "splitContainer2"; | |
177 | + this.splitContainer2.Orientation = System.Windows.Forms.Orientation.Horizontal; | |
178 | + this.splitContainer2.Size = new System.Drawing.Size(231, 354); | |
179 | + this.splitContainer2.SplitterDistance = 197; | |
180 | + this.splitContainer2.TabIndex = 0; | |
181 | + // | |
182 | + // splitContainer3 | |
183 | + // | |
184 | + this.splitContainer3.Dock = System.Windows.Forms.DockStyle.Fill; | |
185 | + this.splitContainer3.Location = new System.Drawing.Point(0, 0); | |
186 | + this.splitContainer3.Name = "splitContainer3"; | |
187 | + // | |
188 | + // splitContainer3.Panel2 | |
189 | + // | |
190 | + this.splitContainer3.Panel2.Controls.Add(this.editor); | |
191 | + this.splitContainer3.Size = new System.Drawing.Size(462, 354); | |
192 | + this.splitContainer3.SplitterDistance = 153; | |
193 | + this.splitContainer3.TabIndex = 0; | |
194 | + // | |
195 | + // editor | |
196 | + // | |
197 | + this.editor.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(250)))), ((int)(((byte)(240))))); | |
198 | + this.editor.Cursor = System.Windows.Forms.Cursors.IBeam; | |
199 | + this.editor.DrawingOption = ((Sgry.Azuki.DrawingOption)(((((((Sgry.Azuki.DrawingOption.DrawsFullWidthSpace | Sgry.Azuki.DrawingOption.DrawsTab) | |
200 | + | Sgry.Azuki.DrawingOption.DrawsEol) | |
201 | + | Sgry.Azuki.DrawingOption.HighlightCurrentLine) | |
202 | + | Sgry.Azuki.DrawingOption.ShowsLineNumber) | |
203 | + | Sgry.Azuki.DrawingOption.ShowsDirtBar) | |
204 | + | Sgry.Azuki.DrawingOption.HighlightsMatchedBracket))); | |
205 | + this.editor.FirstVisibleLine = 0; | |
206 | + this.editor.Font = new System.Drawing.Font("MS UI Gothic", 9F); | |
207 | + fontInfo2.Name = "MS UI Gothic"; | |
208 | + fontInfo2.Size = 9; | |
209 | + fontInfo2.Style = System.Drawing.FontStyle.Regular; | |
210 | + this.editor.FontInfo = fontInfo2; | |
211 | + this.editor.ForeColor = System.Drawing.Color.Black; | |
212 | + this.editor.Location = new System.Drawing.Point(64, 153); | |
213 | + this.editor.Name = "editor"; | |
214 | + this.editor.ScrollPos = new System.Drawing.Point(0, 0); | |
215 | + this.editor.Size = new System.Drawing.Size(104, 62); | |
216 | + this.editor.TabIndex = 0; | |
217 | + this.editor.Text = "azukiControl1"; | |
218 | + this.editor.ViewWidth = 4129; | |
219 | + // | |
220 | + // toolStrip1 | |
221 | + // | |
222 | + this.toolStrip1.Dock = System.Windows.Forms.DockStyle.None; | |
223 | + this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; | |
224 | + this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { | |
225 | + this.uxOpenFile, | |
226 | + this.uxOpenFolder, | |
227 | + this.toolStripSeparator3, | |
228 | + this.uxShowSidePanel, | |
229 | + this.toolStripSeparator1, | |
230 | + this.uxFindButton, | |
231 | + this.uxFindBox, | |
232 | + this.uxFindPrev, | |
233 | + this.uxFindNext, | |
234 | + this.toolStripSeparator2, | |
235 | + this.uxKeyBinds, | |
236 | + this.uxAbout}); | |
237 | + this.toolStrip1.Location = new System.Drawing.Point(3, 0); | |
238 | + this.toolStrip1.Name = "toolStrip1"; | |
239 | + this.toolStrip1.Size = new System.Drawing.Size(555, 25); | |
240 | + this.toolStrip1.TabIndex = 1; | |
241 | + // | |
242 | + // uxOpenFile | |
243 | + // | |
244 | + this.uxOpenFile.Image = ((System.Drawing.Image)(resources.GetObject("uxOpenFile.Image"))); | |
245 | + this.uxOpenFile.ImageTransparentColor = System.Drawing.Color.Magenta; | |
246 | + this.uxOpenFile.Name = "uxOpenFile"; | |
247 | + this.uxOpenFile.Size = new System.Drawing.Size(54, 22); | |
248 | + this.uxOpenFile.Text = "&File"; | |
249 | + // | |
250 | + // uxShowSidePanel | |
251 | + // | |
252 | + this.uxShowSidePanel.CheckOnClick = true; | |
253 | + this.uxShowSidePanel.Image = ((System.Drawing.Image)(resources.GetObject("uxShowSidePanel.Image"))); | |
254 | + this.uxShowSidePanel.ImageTransparentColor = System.Drawing.Color.Magenta; | |
255 | + this.uxShowSidePanel.Name = "uxShowSidePanel"; | |
256 | + this.uxShowSidePanel.Size = new System.Drawing.Size(81, 22); | |
257 | + this.uxShowSidePanel.Text = "&Side panel"; | |
258 | + // | |
259 | + // uxOpenFolder | |
260 | + // | |
261 | + this.uxOpenFolder.Image = ((System.Drawing.Image)(resources.GetObject("uxOpenFolder.Image"))); | |
262 | + this.uxOpenFolder.ImageTransparentColor = System.Drawing.Color.Magenta; | |
263 | + this.uxOpenFolder.Name = "uxOpenFolder"; | |
264 | + this.uxOpenFolder.Size = new System.Drawing.Size(90, 22); | |
265 | + this.uxOpenFolder.Text = "&Open folder"; | |
266 | + // | |
267 | + // toolStripSeparator1 | |
268 | + // | |
269 | + this.toolStripSeparator1.Name = "toolStripSeparator1"; | |
270 | + this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25); | |
271 | + // | |
272 | + // uxFindButton | |
273 | + // | |
274 | + this.uxFindButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; | |
275 | + this.uxFindButton.Image = ((System.Drawing.Image)(resources.GetObject("uxFindButton.Image"))); | |
276 | + this.uxFindButton.ImageTransparentColor = System.Drawing.Color.Magenta; | |
277 | + this.uxFindButton.Name = "uxFindButton"; | |
278 | + this.uxFindButton.Size = new System.Drawing.Size(23, 22); | |
279 | + this.uxFindButton.ToolTipText = "Find (Ctrl + F)"; | |
280 | + // | |
281 | + // uxFindBox | |
282 | + // | |
283 | + this.uxFindBox.Name = "uxFindBox"; | |
284 | + this.uxFindBox.Size = new System.Drawing.Size(100, 25); | |
285 | + // | |
286 | + // uxFindPrev | |
287 | + // | |
288 | + this.uxFindPrev.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; | |
289 | + this.uxFindPrev.Image = ((System.Drawing.Image)(resources.GetObject("uxFindPrev.Image"))); | |
290 | + this.uxFindPrev.ImageTransparentColor = System.Drawing.Color.Magenta; | |
291 | + this.uxFindPrev.Name = "uxFindPrev"; | |
292 | + this.uxFindPrev.Size = new System.Drawing.Size(23, 22); | |
293 | + this.uxFindPrev.ToolTipText = "Move previous (Shift + F3)"; | |
294 | + // | |
295 | + // uxFindNext | |
296 | + // | |
297 | + this.uxFindNext.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; | |
298 | + this.uxFindNext.Image = ((System.Drawing.Image)(resources.GetObject("uxFindNext.Image"))); | |
299 | + this.uxFindNext.ImageTransparentColor = System.Drawing.Color.Magenta; | |
300 | + this.uxFindNext.Name = "uxFindNext"; | |
301 | + this.uxFindNext.Size = new System.Drawing.Size(23, 22); | |
302 | + this.uxFindNext.ToolTipText = "Move next (F3)"; | |
303 | + // | |
304 | + // toolStripSeparator2 | |
305 | + // | |
306 | + this.toolStripSeparator2.Name = "toolStripSeparator2"; | |
307 | + this.toolStripSeparator2.Size = new System.Drawing.Size(6, 25); | |
308 | + // | |
309 | + // contextMenuStrip1 | |
310 | + // | |
311 | + this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { | |
312 | + this.toolStripMenuItemExportToImage, | |
313 | + this.toolStripMenuItemCopyToClipboard}); | |
314 | + this.contextMenuStrip1.Name = "contextMenuStrip1"; | |
315 | + this.contextMenuStrip1.Size = new System.Drawing.Size(201, 48); | |
316 | + // | |
317 | + // toolStripMenuItemExportToImage | |
318 | + // | |
319 | + this.toolStripMenuItemExportToImage.Name = "toolStripMenuItemExportToImage"; | |
320 | + this.toolStripMenuItemExportToImage.Size = new System.Drawing.Size(200, 22); | |
321 | + this.toolStripMenuItemExportToImage.Text = "画像をファイルに保存"; | |
322 | + this.toolStripMenuItemExportToImage.Click += new System.EventHandler(this.toolStripMenuItemExportToPng_Click); | |
323 | + // | |
324 | + // toolStripMenuItemCopyToClipboard | |
325 | + // | |
326 | + this.toolStripMenuItemCopyToClipboard.Name = "toolStripMenuItemCopyToClipboard"; | |
327 | + this.toolStripMenuItemCopyToClipboard.Size = new System.Drawing.Size(200, 22); | |
328 | + this.toolStripMenuItemCopyToClipboard.Text = "画像をクリップボードへコピー"; | |
329 | + this.toolStripMenuItemCopyToClipboard.Click += new System.EventHandler(this.toolStripMenuItemCopyToClipboard_Click); | |
330 | + // | |
331 | + // imageList1 | |
332 | + // | |
333 | + this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream"))); | |
334 | + this.imageList1.TransparentColor = System.Drawing.Color.Transparent; | |
335 | + this.imageList1.Images.SetKeyName(0, "folder_page.png"); | |
336 | + this.imageList1.Images.SetKeyName(1, "information.png"); | |
337 | + this.imageList1.Images.SetKeyName(2, "page.png"); | |
338 | + this.imageList1.Images.SetKeyName(3, "page_add.png"); | |
339 | + this.imageList1.Images.SetKeyName(4, "application_side_list.png"); | |
340 | + this.imageList1.Images.SetKeyName(5, "page_edit.png"); | |
341 | + this.imageList1.Images.SetKeyName(6, "magnifier.png"); | |
342 | + this.imageList1.Images.SetKeyName(7, "arrow_up.png"); | |
343 | + this.imageList1.Images.SetKeyName(8, "arrow_down.png"); | |
344 | + this.imageList1.Images.SetKeyName(9, "house.png"); | |
345 | + this.imageList1.Images.SetKeyName(10, "keyboard.png"); | |
346 | + this.imageList1.Images.SetKeyName(11, "help.png"); | |
347 | + this.imageList1.Images.SetKeyName(12, "sqwriter.png"); | |
348 | + this.imageList1.Images.SetKeyName(13, "picture_save.png"); | |
349 | + this.imageList1.Images.SetKeyName(14, "page_paste.png"); | |
350 | + this.imageList1.Images.SetKeyName(15, "folder.png"); | |
351 | + // | |
352 | + // uxKeyBinds | |
353 | + // | |
354 | + this.uxKeyBinds.Image = ((System.Drawing.Image)(resources.GetObject("uxKeyBinds.Image"))); | |
355 | + this.uxKeyBinds.ImageTransparentColor = System.Drawing.Color.Magenta; | |
356 | + this.uxKeyBinds.Name = "uxKeyBinds"; | |
357 | + this.uxKeyBinds.Size = new System.Drawing.Size(78, 22); | |
358 | + this.uxKeyBinds.Text = "&Key binds"; | |
359 | + // | |
360 | + // uxAbout | |
361 | + // | |
362 | + this.uxAbout.Image = ((System.Drawing.Image)(resources.GetObject("uxAbout.Image"))); | |
363 | + this.uxAbout.ImageTransparentColor = System.Drawing.Color.Magenta; | |
364 | + this.uxAbout.Name = "uxAbout"; | |
365 | + this.uxAbout.Size = new System.Drawing.Size(60, 22); | |
366 | + this.uxAbout.Text = "&About"; | |
367 | + // | |
368 | + // toolStripSeparator3 | |
369 | + // | |
370 | + this.toolStripSeparator3.Name = "toolStripSeparator3"; | |
371 | + this.toolStripSeparator3.Size = new System.Drawing.Size(6, 25); | |
372 | + // | |
373 | + // FormMain | |
374 | + // | |
375 | + this.AllowDrop = true; | |
376 | + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 14F); | |
377 | + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; | |
378 | + this.ClientSize = new System.Drawing.Size(697, 401); | |
379 | + this.Controls.Add(this.toolStripContainer1); | |
380 | + this.Controls.Add(this.statusStrip1); | |
381 | + this.Font = new System.Drawing.Font("Consolas", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); | |
382 | + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); | |
383 | + this.Name = "FormMain"; | |
384 | + this.Text = "sqwriter"; | |
385 | + this.Load += new System.EventHandler(this.FormMain_Load); | |
386 | + this.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.FormMain_MouseWheel); | |
387 | + this.statusStrip1.ResumeLayout(false); | |
388 | + this.statusStrip1.PerformLayout(); | |
389 | + this.toolStripContainer1.ContentPanel.ResumeLayout(false); | |
390 | + this.toolStripContainer1.TopToolStripPanel.ResumeLayout(false); | |
391 | + this.toolStripContainer1.TopToolStripPanel.PerformLayout(); | |
392 | + this.toolStripContainer1.ResumeLayout(false); | |
393 | + this.toolStripContainer1.PerformLayout(); | |
394 | + this.splitContainer1.Panel1.ResumeLayout(false); | |
395 | + this.splitContainer1.Panel2.ResumeLayout(false); | |
396 | + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); | |
397 | + this.splitContainer1.ResumeLayout(false); | |
398 | + ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit(); | |
399 | + this.splitContainer2.ResumeLayout(false); | |
400 | + this.splitContainer3.Panel2.ResumeLayout(false); | |
401 | + ((System.ComponentModel.ISupportInitialize)(this.splitContainer3)).EndInit(); | |
402 | + this.splitContainer3.ResumeLayout(false); | |
403 | + this.toolStrip1.ResumeLayout(false); | |
404 | + this.toolStrip1.PerformLayout(); | |
405 | + this.contextMenuStrip1.ResumeLayout(false); | |
406 | + this.ResumeLayout(false); | |
407 | + this.PerformLayout(); | |
408 | + | |
409 | + } | |
410 | + | |
411 | + #endregion | |
412 | + | |
413 | + private System.Windows.Forms.StatusStrip statusStrip1; | |
414 | + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelFileInfo; | |
415 | + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelMousePoint; | |
416 | + private System.Windows.Forms.ToolStripContainer toolStripContainer1; | |
417 | + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelMode; | |
418 | + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelViewPoint; | |
419 | + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelZoom; | |
420 | + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelDrawTime; | |
421 | + private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; | |
422 | + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemExportToImage; | |
423 | + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemCopyToClipboard; | |
424 | + private System.Windows.Forms.SplitContainer splitContainer1; | |
425 | + private System.Windows.Forms.SplitContainer splitContainer2; | |
426 | + private System.Windows.Forms.ToolStrip toolStrip1; | |
427 | + private System.Windows.Forms.ImageList imageList1; | |
428 | + private System.Windows.Forms.ToolStripDropDownButton uxOpenFile; | |
429 | + private System.Windows.Forms.ToolStripButton uxShowSidePanel; | |
430 | + private System.Windows.Forms.ToolStripButton uxOpenFolder; | |
431 | + private System.Windows.Forms.ToolStripTextBox uxFindBox; | |
432 | + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; | |
433 | + private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; | |
434 | + private System.Windows.Forms.ToolStripButton uxFindPrev; | |
435 | + private System.Windows.Forms.ToolStripButton uxFindNext; | |
436 | + private System.Windows.Forms.ToolStripButton uxFindButton; | |
437 | + private System.Windows.Forms.SplitContainer splitContainer3; | |
438 | + private Sgry.Azuki.WinForms.AzukiControl editor; | |
439 | + private System.Windows.Forms.ToolStripButton uxKeyBinds; | |
440 | + private System.Windows.Forms.ToolStripButton uxAbout; | |
441 | + private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; | |
442 | + } | |
443 | +} | |
444 | + |
@@ -0,0 +1,227 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Linq; | |
4 | +using System.Text; | |
5 | +using System.Windows.Forms; | |
6 | +using System.Drawing; | |
7 | + | |
8 | +namespace sqwriter | |
9 | +{ | |
10 | + partial class FormMain | |
11 | + { | |
12 | + ShortcutKey[] findBoxShortcutKeys | |
13 | + { | |
14 | + get | |
15 | + { | |
16 | + return new ShortcutKey[] { | |
17 | + new ShortcutKey { | |
18 | + LabelText = "Find next", | |
19 | + KeyEnterd = (control, ea) => { this.uxFindNext.PerformClick(); }, | |
20 | + KeyCode = Keys.Enter | |
21 | + }, | |
22 | + new ShortcutKey { | |
23 | + LabelText = "Find next", | |
24 | + KeyEnterd = (control, ea) => { this.uxFindNext.PerformClick(); }, | |
25 | + KeyCode = Keys.F3 | |
26 | + }, | |
27 | + new ShortcutKey { | |
28 | + LabelText = "Find previous", | |
29 | + KeyEnterd = (control, ea) => { this.uxFindPrev.PerformClick(); }, | |
30 | + KeyCode = Keys.Enter, Shift = true | |
31 | + }, | |
32 | + new ShortcutKey { | |
33 | + LabelText = "Find previous", | |
34 | + KeyEnterd = (control, ea) => { this.uxFindPrev.PerformClick(); }, | |
35 | + KeyCode = Keys.F3, Shift = true | |
36 | + }, | |
37 | + }; | |
38 | + } | |
39 | + } | |
40 | + ShortcutKey[] laneListShortcutKeys | |
41 | + { | |
42 | + get | |
43 | + { | |
44 | + return new ShortcutKey[] { | |
45 | + new ShortcutKey { | |
46 | + LabelText = "Select all", | |
47 | + KeyEnterd = (control, ea) => { foreach( ListViewItem item in this.LaneList.Items ) item.Selected = true; }, | |
48 | + KeyCode = Keys.A, Control = true | |
49 | + }, | |
50 | + new ShortcutKey { | |
51 | + LabelText = "Move upper", | |
52 | + KeyEnterd = (control, ea) => { this.MoveLaneListItemOrder( MoveDirection.Upper ); }, | |
53 | + KeyCode = Keys.Up, Control = true | |
54 | + }, | |
55 | + new ShortcutKey { | |
56 | + LabelText = "Move lower", | |
57 | + KeyEnterd = (control, ea) => { this.MoveLaneListItemOrder( MoveDirection.Lower ); }, | |
58 | + KeyCode = Keys.Down, Control = true | |
59 | + }, | |
60 | + }; | |
61 | + } | |
62 | + } | |
63 | + ShortcutKey[] editorShortcutKeys | |
64 | + { | |
65 | + get | |
66 | + { | |
67 | + return new ShortcutKey[] { | |
68 | + new ShortcutKey { | |
69 | + LabelText = "Save", | |
70 | + KeyEnterd = (control, ea) => { this.SaveEditorContents(); }, | |
71 | + KeyCode = Keys.S, Control = true | |
72 | + }, | |
73 | + }; | |
74 | + } | |
75 | + } | |
76 | + ShortcutKey[] viewPanelShortcutKeys | |
77 | + { | |
78 | + get | |
79 | + { | |
80 | + return new ShortcutKey[] { | |
81 | + new ShortcutKey { | |
82 | + LabelText = "Jump to home position", | |
83 | + KeyEnterd = (control, ea) => { this.MoveToHome(); }, | |
84 | + KeyCode = Keys.Space | |
85 | + }, | |
86 | + new ShortcutKey { | |
87 | + LabelText = "Jump to top", | |
88 | + KeyEnterd = (control, ea) => { this.MotionController.JumpPosition( new PointF( this.ViewPanel.PositionXY.X, 0.0F ) ); }, | |
89 | + KeyCode = Keys.Home | |
90 | + }, | |
91 | + new ShortcutKey { | |
92 | + LabelText = "Jump to bottom", | |
93 | + KeyEnterd = (control, ea) => | |
94 | + { | |
95 | + float y = this.layoutedSize.Height - this.ViewPanel.VisibleArea.Height; | |
96 | + y = (y < 0.0F) ? 0.0F : y; | |
97 | + this.MotionController.JumpPosition( new PointF( this.ViewPanel.PositionXY.X, y ) ); | |
98 | + }, | |
99 | + KeyCode = Keys.End | |
100 | + }, | |
101 | + new ShortcutKey { | |
102 | + LabelText = "Scroll left", | |
103 | + KeyEnterd = (control, ea) => { if( this.GetVisibleAreaProportion().Left > 0.0F ) this.MotionController.MovePosition( -kGridSpanX, 0.0F, kGridSpanX, kGridSpanY ); }, | |
104 | + KeyCode = Keys.Left | |
105 | + }, | |
106 | + new ShortcutKey { | |
107 | + LabelText = "Scroll right", | |
108 | + KeyEnterd = (control, ea) => { if( this.GetVisibleAreaProportion().Right < 1.0F ) this.MotionController.MovePosition( kGridSpanX, 0.0F, kGridSpanX, kGridSpanY ); }, | |
109 | + KeyCode = Keys.Right | |
110 | + }, | |
111 | + new ShortcutKey { | |
112 | + LabelText = "Page up", | |
113 | + KeyEnterd = (control, ea) => { if( this.GetVisibleAreaProportion().Top > 0.0F ) this.MotionController.MovePosition( 0.0F, -kGridSpanY * 10, kGridSpanX, kGridSpanY ); }, | |
114 | + KeyCode = Keys.PageUp | |
115 | + }, | |
116 | + new ShortcutKey { | |
117 | + LabelText = "Page down", | |
118 | + KeyEnterd = (control, ea) => { if( this.GetVisibleAreaProportion().Bottom < 1.0F ) this.MotionController.MovePosition( 0.0F, kGridSpanY * 10, kGridSpanX, kGridSpanY ); }, | |
119 | + KeyCode = Keys.PageDown | |
120 | + }, | |
121 | + new ShortcutKey { | |
122 | + LabelText = "Move up", | |
123 | + KeyEnterd = (control, ea) => { this.MoveSelection( MoveDirection.Upper ); }, | |
124 | + KeyCode = Keys.Up | |
125 | + }, | |
126 | + new ShortcutKey { | |
127 | + LabelText = "Move down", | |
128 | + KeyEnterd = (control, ea) => { this.MoveSelection( MoveDirection.Lower ); }, | |
129 | + KeyCode = Keys.Down | |
130 | + }, | |
131 | + new ShortcutKey { | |
132 | + LabelText = "Jump previous header", | |
133 | + KeyEnterd = (control, ea) => { this.MoveSection( MoveDirection.Upper ); }, | |
134 | + KeyCode = Keys.Up, Control = true | |
135 | + }, | |
136 | + new ShortcutKey { | |
137 | + LabelText = "Jump next header", | |
138 | + KeyEnterd = (control, ea) => { this.MoveSection( MoveDirection.Lower ); }, | |
139 | + KeyCode = Keys.Down, Control = true | |
140 | + }, | |
141 | + new ShortcutKey { | |
142 | + LabelText = "Zoom in", | |
143 | + KeyEnterd = (control, ea) => { | |
144 | + var clientPoint = this.ViewPanel.PointToClient( MousePosition ); | |
145 | + this.MotionController.PositionXY = this.ViewPanel.ScreenToWorld( clientPoint ); | |
146 | + this.ViewPanel.PositionOffsetXY = clientPoint; | |
147 | + this.zoomIndex = Util.Clamp( this.zoomIndex + 1, 0, ZoomScales.Length - 1 ); | |
148 | + this.MotionController.JumpScale( ZoomScales[this.zoomIndex] ); | |
149 | + }, | |
150 | + KeyCode = Keys.OemOpenBrackets | |
151 | + }, | |
152 | + new ShortcutKey { | |
153 | + LabelText = "Zoom out", | |
154 | + KeyEnterd = (control, ea) => { | |
155 | + var clientPoint = this.ViewPanel.PointToClient( MousePosition ); | |
156 | + this.MotionController.PositionXY = this.ViewPanel.ScreenToWorld( clientPoint ); | |
157 | + this.ViewPanel.PositionOffsetXY = clientPoint; | |
158 | + this.zoomIndex = Util.Clamp( this.zoomIndex - 1, 0, ZoomScales.Length - 1 ); | |
159 | + this.MotionController.JumpScale( ZoomScales[this.zoomIndex] ); | |
160 | + }, | |
161 | + KeyCode = Keys.OemCloseBrackets | |
162 | + }, | |
163 | + new ShortcutKey { | |
164 | + LabelText = "Find", | |
165 | + KeyEnterd = (control, ea) => { this.uxFindBox.Focus(); this.uxFindBox.SelectAll(); }, | |
166 | + KeyCode = Keys.F, Control = true | |
167 | + }, | |
168 | + new ShortcutKey { | |
169 | + LabelText = "Find next", | |
170 | + KeyEnterd = (control, ea) => { this.uxFindNext.PerformClick(); }, | |
171 | + KeyCode = Keys.F3 | |
172 | + }, | |
173 | + new ShortcutKey { | |
174 | + LabelText = "Find previous", | |
175 | + KeyEnterd = (control, ea) => { this.uxFindPrev.PerformClick(); }, | |
176 | + KeyCode = Keys.F3, Shift = true | |
177 | + }, | |
178 | + new ShortcutKey { | |
179 | + LabelText = "Move selected lane to left", | |
180 | + KeyEnterd = (control, ea) => { if( this.selectedElement != null && this.selectedElement.Type == SqElement.ElementType.Lane ) this.MoveLaneListItemOrder( MoveDirection.Upper ); }, | |
181 | + KeyCode = Keys.Left, Control = true | |
182 | + }, | |
183 | + new ShortcutKey { | |
184 | + LabelText = "Move selected lane to right", | |
185 | + KeyEnterd = (control, ea) => { if( this.selectedElement != null && this.selectedElement.Type == SqElement.ElementType.Lane ) this.MoveLaneListItemOrder( MoveDirection.Lower ); }, | |
186 | + KeyCode = Keys.Right, Control = true | |
187 | + }, | |
188 | + new ShortcutKey { | |
189 | + LabelText = null, | |
190 | + KeyEnterd = (control, ea) => | |
191 | + { | |
192 | + // 選択中のライフラインを非表示にする | |
193 | + if( this.selectedElement != null && this.selectedElement.Type == SqElement.ElementType.Lane ) | |
194 | + { | |
195 | + this.LaneList.Items[this.selectedElement.Name].Checked = false; | |
196 | + this.UpdateLaneStateFromLaneList( this.assembly.Lanes, this.assembly.Elements ); | |
197 | + this.selectedElement = null; | |
198 | + this.ViewPanel.Invalidate(); | |
199 | + } | |
200 | + }, | |
201 | + KeyCode = Keys.Delete | |
202 | + }, | |
203 | + new ShortcutKey { | |
204 | + LabelText = "Cancel selection", | |
205 | + KeyEnterd = (control, ea) => { this.selectedElement = null; this.ViewPanel.Invalidate(); }, | |
206 | + KeyCode = Keys.Escape | |
207 | + }, | |
208 | + new ShortcutKey { | |
209 | + LabelText = null, | |
210 | + KeyEnterd = (control, ea) => { this.selectedElement = null; this.ViewPanel.Invalidate(); }, | |
211 | + KeyCode = Keys.Escape | |
212 | + }, | |
213 | + new ShortcutKey { | |
214 | + LabelText = "Debug mode on/off", | |
215 | + KeyEnterd = (control, ea) => { this.DebugMode = !this.debugMode; }, | |
216 | + KeyCode = Keys.D | |
217 | + }, | |
218 | + new ShortcutKey { | |
219 | + LabelText = "Grid line on/off", | |
220 | + KeyEnterd = (control, ea) => { this.Grid = !this.Grid; }, | |
221 | + KeyCode = Keys.G | |
222 | + }, | |
223 | + }; | |
224 | + } | |
225 | + } | |
226 | + } | |
227 | +} |
@@ -0,0 +1,278 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.ComponentModel; | |
4 | +using System.Data; | |
5 | +using System.Drawing; | |
6 | +using System.Linq; | |
7 | +using System.Text; | |
8 | +using System.Windows.Forms; | |
9 | + | |
10 | +namespace sqwriter | |
11 | +{ | |
12 | + public partial class FormShortcutKey : Form | |
13 | + { | |
14 | + //public event EventHandler<ShortcutKey> KeyEntered; | |
15 | + | |
16 | + // | |
17 | + // Public methods | |
18 | + // | |
19 | + | |
20 | + public FormShortcutKey() | |
21 | + { | |
22 | + InitializeComponent(); | |
23 | + | |
24 | + Util.TraverseControls( this, ( c ) => c.Font = SystemFonts.MessageBoxFont ); | |
25 | + | |
26 | + this.MinimizeBox = false; | |
27 | + | |
28 | + this.FormBorderStyle = FormBorderStyle.Sizable; | |
29 | + this.ShowIcon = false; | |
30 | + this.ShowInTaskbar = false; | |
31 | + this.Text = "Key binds"; | |
32 | + this.SizeChanged += ( sender, e ) => { this.UpdateListColumnWidth(); }; | |
33 | + this.FormClosing += ( sender, e ) => { this.Hide(); e.Cancel = true; }; | |
34 | + | |
35 | + this.listView = new ListView(); | |
36 | + this.listView.Dock = DockStyle.Fill; | |
37 | + //this.listView.GridLines = true; | |
38 | + this.listView.FullRowSelect = true; | |
39 | + this.listView.HeaderStyle = ColumnHeaderStyle.None; | |
40 | + this.listView.View = View.Details; | |
41 | + this.listView.ShowGroups = true; | |
42 | + this.listView.MultiSelect = false; | |
43 | + this.listView.HideSelection = false; | |
44 | + | |
45 | + this.listView.DoubleClick += ( o, ea ) => { this.EnterSelectedItem(); }; | |
46 | + this.listView.KeyDown += ( o, ea ) => { if( ea.KeyCode == Keys.Enter ) this.EnterSelectedItem(); }; | |
47 | + | |
48 | + this.listView.Columns.Add( "command", "" ); | |
49 | + this.listView.Columns.Add( "key", "" ); | |
50 | + //this.listView.MouseEnter += ( s, ea ) => { this.tsc.BottomToolStripPanelVisible = false; }; | |
51 | + //this.listView.MouseMove += ( o, ea ) => | |
52 | + //{ | |
53 | + // var cp = this.PointToClient( this.listView.PointToScreen( ea.Location ) ); | |
54 | + // if( cp.Y > (this.ClientSize.Height - this.tsc.BottomToolStripPanel.Height) && cp.Y < this.ClientSize.Height ) | |
55 | + // { | |
56 | + // this.tsc.BottomToolStripPanelVisible = true; | |
57 | + // } | |
58 | + //}; | |
59 | + | |
60 | + //var statusStrip = new StatusStrip(); | |
61 | + //statusStrip.Dock = DockStyle.Bottom; | |
62 | + //var toolStrip = new ToolStrip(); | |
63 | + //var filterBox = new ToolStripTextBox( "uxFilterBox" ); | |
64 | + //toolStrip.Items.Add( filterBox ); | |
65 | + | |
66 | + this.tsc = new ToolStripContainer(); | |
67 | + this.tsc.Dock = DockStyle.Fill; | |
68 | + this.tsc.ContentPanel.Controls.Add( this.listView ); | |
69 | + //this.tsc.TopToolStripPanel.Controls.Add( toolStrip ); | |
70 | + //this.tsc.TopToolStripPanelVisible = true; | |
71 | + //this.tsc.BottomToolStripPanel.Controls.Add( statusStrip ); | |
72 | + //this.tsc.BottomToolStripPanelVisible = false; | |
73 | + this.Controls.Add( this.tsc ); | |
74 | + | |
75 | + this.shortcutKeyGroups = new Dictionary<object, ShortcutKeyGroup>(); | |
76 | + } | |
77 | + | |
78 | + void FormShortcutKey_MouseMove( object sender, MouseEventArgs e ) | |
79 | + { | |
80 | + var cp = this.PointToClient( this.listView.PointToScreen( e.Location ) ); | |
81 | + if( cp.Y > this.ClientSize.Height - this.tsc.BottomToolStripPanel.Height && cp.Y < this.ClientSize.Height ) | |
82 | + { | |
83 | + this.tsc.BottomToolStripPanelVisible = true; | |
84 | + } | |
85 | + } | |
86 | + | |
87 | + void EnterSelectedItem() | |
88 | + { | |
89 | + if( this.listView.SelectedItems.Count > 0 ) | |
90 | + { | |
91 | + var sk = (ShortcutKey)this.listView.SelectedItems[0].Tag; | |
92 | + sk.OnKeyEnterd(); | |
93 | + } | |
94 | + } | |
95 | + | |
96 | + public void AddShortcutKeys( object target, string label, ShortcutKey[] shortcutKeys ) | |
97 | + { | |
98 | + if( this.shortcutKeyGroups.ContainsKey( target ) ) | |
99 | + { | |
100 | + this.shortcutKeyGroups[target].Keys.AddRange( shortcutKeys ); | |
101 | + } | |
102 | + else | |
103 | + { | |
104 | + var keyGroup = new ShortcutKeyGroup() { Target = target, LabelText = label, Keys = new List<ShortcutKey>( shortcutKeys ) }; | |
105 | + this.shortcutKeyGroups.Add( target, keyGroup ); | |
106 | + } | |
107 | + this.UpdateShortcutKeyList(); | |
108 | + } | |
109 | + | |
110 | + public void ClearShortcutKeys( object target = null ) | |
111 | + { | |
112 | + if( target == null ) | |
113 | + { | |
114 | + this.shortcutKeyGroups.Clear(); | |
115 | + } | |
116 | + else | |
117 | + { | |
118 | + if( this.shortcutKeyGroups.ContainsKey( target ) ) | |
119 | + { | |
120 | + this.shortcutKeyGroups.Remove( target ); | |
121 | + } | |
122 | + } | |
123 | + } | |
124 | + | |
125 | + public bool NotifyKeyDown( object sender, PreviewKeyDownEventArgs e ) | |
126 | + { | |
127 | + return this.NotifyKeyDown( sender, e.KeyCode, e.Shift, e.Control, e.Alt ); | |
128 | + } | |
129 | + | |
130 | + public bool NotifyKeyDown( object sender, KeyEventArgs e ) | |
131 | + { | |
132 | + return this.NotifyKeyDown( sender, e.KeyCode, e.Shift, e.Control, e.Alt ); | |
133 | + } | |
134 | + | |
135 | + public bool NotifyKeyDown( object sender, Keys keyCode, bool shift, bool control, bool alt ) | |
136 | + { | |
137 | + bool handled = false; | |
138 | + if( this.shortcutKeyGroups.ContainsKey( sender ) ) | |
139 | + { | |
140 | + var keyGroup = this.shortcutKeyGroups[sender]; | |
141 | + int index = keyGroup.Keys.FindIndex( ( sk ) => | |
142 | + keyCode == sk.KeyCode && shift == sk.Shift && control == sk.Control && alt == sk.Alt ); | |
143 | + if( index >= 0 ) | |
144 | + { | |
145 | + keyGroup.Keys[index].OnKeyEnterd(); | |
146 | + var item = this.FindListItem( sender, keyGroup.Keys[index] ); | |
147 | + if( item != null ) | |
148 | + { | |
149 | + item.Selected = true; | |
150 | + item.ListView.EnsureVisible( item.Index ); | |
151 | + } | |
152 | + handled = true; | |
153 | + } | |
154 | + } | |
155 | + return handled; | |
156 | + } | |
157 | + | |
158 | + // | |
159 | + // Private methods | |
160 | + // | |
161 | + | |
162 | + ListViewItem FindListItem( object target, ShortcutKey shortcutKey ) | |
163 | + { | |
164 | + foreach( ListViewGroup listGroup in this.listView.Groups ) | |
165 | + { | |
166 | + if( listGroup.Tag == target ) | |
167 | + { | |
168 | + int index = listGroup.Items.IndexOfKey( shortcutKey.ToString() ); | |
169 | + if( index >= 0 ) | |
170 | + { | |
171 | + return listGroup.Items[index]; | |
172 | + } | |
173 | + } | |
174 | + } | |
175 | + return null; | |
176 | + } | |
177 | + | |
178 | + ToolStripContainer tsc; | |
179 | + ListView listView; | |
180 | + Dictionary<object, ShortcutKeyGroup> shortcutKeyGroups; | |
181 | + | |
182 | + void UpdateShortcutKeyList() | |
183 | + { | |
184 | + if( this.Visible ) | |
185 | + { | |
186 | + this.listView.Items.Clear(); | |
187 | + this.listView.Groups.Clear(); | |
188 | + int groupIndex = 0; | |
189 | + foreach( var keyGroup in this.shortcutKeyGroups.Values ) | |
190 | + { | |
191 | + var listGroup = this.listView.Groups.Add( groupIndex.ToString(), keyGroup.LabelText ); | |
192 | + listGroup.Tag = keyGroup.Target; | |
193 | + foreach( var shortcutKey in keyGroup.Keys ) | |
194 | + { | |
195 | + if( !string.IsNullOrEmpty( shortcutKey.LabelText ) ) | |
196 | + { | |
197 | + var item = new ListViewItem( shortcutKey.LabelText, listGroup ); | |
198 | + item.Name = shortcutKey.ToString(); | |
199 | + item.SubItems.Add( shortcutKey.ToString() ); | |
200 | + item.Tag = shortcutKey; | |
201 | + this.listView.Items.Add( item ); | |
202 | + } | |
203 | + } | |
204 | + } | |
205 | + } | |
206 | + } | |
207 | + | |
208 | + void FormShortcutKey_Load( object sender, EventArgs e ) | |
209 | + { | |
210 | + this.UpdateShortcutKeyList(); | |
211 | + this.UpdateListColumnWidth(); | |
212 | + } | |
213 | + | |
214 | + void UpdateListColumnWidth() | |
215 | + { | |
216 | + foreach( ColumnHeader ch in this.listView.Columns ) | |
217 | + { | |
218 | + ch.Width = this.listView.ClientSize.Width / this.listView.Columns.Count; | |
219 | + } | |
220 | + } | |
221 | + } | |
222 | + | |
223 | + /// <summary> | |
224 | + /// ショートカットキー受け付け対象ごとの情報 | |
225 | + /// </summary> | |
226 | + public class ShortcutKeyGroup | |
227 | + { | |
228 | + public object Target { get; set; } | |
229 | + public string LabelText { get; set; } | |
230 | + public List<ShortcutKey> Keys { get; set; } | |
231 | + } | |
232 | + | |
233 | + /// <summary> | |
234 | + /// ショートカットキーごとの情報 | |
235 | + /// </summary> | |
236 | + public class ShortcutKey | |
237 | + { | |
238 | + /// <summary> | |
239 | + /// ショートカットキーの見出し | |
240 | + /// </summary> | |
241 | + public string LabelText { get; set; } | |
242 | + | |
243 | + public Keys KeyCode { get; set; } | |
244 | + public bool Shift { get; set; } | |
245 | + public bool Control { get; set; } | |
246 | + public bool Alt { get; set; } | |
247 | + | |
248 | + /// <summary> | |
249 | + /// 設定されたキーの組み合わせが押された時に実行するデリゲード | |
250 | + /// </summary> | |
251 | + public EventHandler KeyEnterd { get; set; } | |
252 | + | |
253 | + /// <summary> | |
254 | + /// KeyEnteredに登録されているデリゲードを実行 | |
255 | + /// </summary> | |
256 | + public void OnKeyEnterd() | |
257 | + { | |
258 | + if( this.KeyEnterd != null ) | |
259 | + { | |
260 | + this.KeyEnterd( this.Control, new EventArgs() ); | |
261 | + } | |
262 | + } | |
263 | + | |
264 | + /// <summary> | |
265 | + /// キーの組み合わせを文字列化 | |
266 | + /// </summary> | |
267 | + /// <returns>Shift + Ctrl + Alt + キー名 の形式</returns> | |
268 | + public override string ToString() | |
269 | + { | |
270 | + var sb = new StringBuilder(); | |
271 | + sb.Append( Shift ? "Shift + " : "" ); | |
272 | + sb.Append( Control ? "Ctrl + " : "" ); | |
273 | + sb.Append( Alt ? "Alt + " : "" ); | |
274 | + sb.Append( KeyCode.ToString() ); | |
275 | + return sb.ToString(); | |
276 | + } | |
277 | + } | |
278 | +} |
@@ -0,0 +1,36 @@ | ||
1 | +using System.Reflection; | |
2 | +using System.Runtime.CompilerServices; | |
3 | +using System.Runtime.InteropServices; | |
4 | + | |
5 | +// アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 | |
6 | +// アセンブリに関連付けられている情報を変更するには、 | |
7 | +// これらの属性値を変更してください。 | |
8 | +[assembly: AssemblyTitle( "sqwriter" )] | |
9 | +[assembly: AssemblyDescription( "" )] | |
10 | +[assembly: AssemblyConfiguration( "" )] | |
11 | +[assembly: AssemblyCompany( "" )] | |
12 | +[assembly: AssemblyProduct( "sqwriter" )] | |
13 | +[assembly: AssemblyCopyright( "Copyright (c) 2012-2016 suconbu." )] | |
14 | +[assembly: AssemblyTrademark( "" )] | |
15 | +[assembly: AssemblyCulture( "" )] | |
16 | + | |
17 | +// ComVisible を false に設定すると、その型はこのアセンブリ内で COM コンポーネントから | |
18 | +// 参照不可能になります。COM からこのアセンブリ内の型にアクセスする場合は、 | |
19 | +// その型の ComVisible 属性を true に設定してください。 | |
20 | +[assembly: ComVisible( false )] | |
21 | + | |
22 | +// 次の GUID は、このプロジェクトが COM に公開される場合の、typelib の ID です | |
23 | +[assembly: Guid( "7602efe4-a243-46c6-8135-0281021f1466" )] | |
24 | + | |
25 | +// アセンブリのバージョン情報は、以下の 4 つの値で構成されています: | |
26 | +// | |
27 | +// Major Version | |
28 | +// Minor Version | |
29 | +// Build Number | |
30 | +// Revision | |
31 | +// | |
32 | +// すべての値を指定するか、下のように '*' を使ってビルドおよびリビジョン番号を | |
33 | +// 既定値にすることができます: | |
34 | +[assembly: AssemblyVersion("1.4.0.*")] | |
35 | +//[assembly: AssemblyVersion( "1.0.0.0" )] | |
36 | +//[assembly: AssemblyFileVersion( "1.0.0.0" )] |
@@ -0,0 +1,70 @@ | ||
1 | +//------------------------------------------------------------------------------ | |
2 | +// <auto-generated> | |
3 | +// このコードはツールによって生成されました。 | |
4 | +// ランタイム バージョン:4.0.30319.269 | |
5 | +// | |
6 | +// このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 | |
7 | +// コードが再生成されるときに損失したりします。 | |
8 | +// </auto-generated> | |
9 | +//------------------------------------------------------------------------------ | |
10 | + | |
11 | +namespace sqwriter.Properties { | |
12 | + using System; | |
13 | + | |
14 | + | |
15 | + /// <summary> | |
16 | + /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。 | |
17 | + /// </summary> | |
18 | + // このクラスは StronglyTypedResourceBuilder クラスが ResGen | |
19 | + // または Visual Studio のようなツールを使用して自動生成されました。 | |
20 | + // メンバーを追加または削除するには、.ResX ファイルを編集して、/str オプションと共に | |
21 | + // ResGen を実行し直すか、または VS プロジェクトをビルドし直します。 | |
22 | + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] | |
23 | + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | |
24 | + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | |
25 | + internal class Resources { | |
26 | + | |
27 | + private static global::System.Resources.ResourceManager resourceMan; | |
28 | + | |
29 | + private static global::System.Globalization.CultureInfo resourceCulture; | |
30 | + | |
31 | + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] | |
32 | + internal Resources() { | |
33 | + } | |
34 | + | |
35 | + /// <summary> | |
36 | + /// このクラスで使用されているキャッシュされた ResourceManager インスタンスを返します。 | |
37 | + /// </summary> | |
38 | + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |
39 | + internal static global::System.Resources.ResourceManager ResourceManager { | |
40 | + get { | |
41 | + if (object.ReferenceEquals(resourceMan, null)) { | |
42 | + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("sqwriter.Properties.Resources", typeof(Resources).Assembly); | |
43 | + resourceMan = temp; | |
44 | + } | |
45 | + return resourceMan; | |
46 | + } | |
47 | + } | |
48 | + | |
49 | + /// <summary> | |
50 | + /// 厳密に型指定されたこのリソース クラスを使用して、すべての検索リソースに対し、 | |
51 | + /// 現在のスレッドの CurrentUICulture プロパティをオーバーライドします。 | |
52 | + /// </summary> | |
53 | + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |
54 | + internal static global::System.Globalization.CultureInfo Culture { | |
55 | + get { | |
56 | + return resourceCulture; | |
57 | + } | |
58 | + set { | |
59 | + resourceCulture = value; | |
60 | + } | |
61 | + } | |
62 | + | |
63 | + internal static System.Drawing.Bitmap sqwriter { | |
64 | + get { | |
65 | + object obj = ResourceManager.GetObject("sqwriter", resourceCulture); | |
66 | + return ((System.Drawing.Bitmap)(obj)); | |
67 | + } | |
68 | + } | |
69 | + } | |
70 | +} |
@@ -0,0 +1,26 @@ | ||
1 | +//------------------------------------------------------------------------------ | |
2 | +// <auto-generated> | |
3 | +// このコードはツールによって生成されました。 | |
4 | +// ランタイム バージョン:4.0.30319.269 | |
5 | +// | |
6 | +// このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 | |
7 | +// コードが再生成されるときに損失したりします。 | |
8 | +// </auto-generated> | |
9 | +//------------------------------------------------------------------------------ | |
10 | + | |
11 | +namespace sqwriter.Properties { | |
12 | + | |
13 | + | |
14 | + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | |
15 | + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] | |
16 | + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { | |
17 | + | |
18 | + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); | |
19 | + | |
20 | + public static Settings Default { | |
21 | + get { | |
22 | + return defaultInstance; | |
23 | + } | |
24 | + } | |
25 | + } | |
26 | +} |
@@ -0,0 +1,607 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Linq; | |
4 | +using System.Text; | |
5 | +using System.Drawing; | |
6 | + | |
7 | +namespace sqwriter | |
8 | +{ | |
9 | + struct Area | |
10 | + { | |
11 | + // | |
12 | + // Public fields/properties | |
13 | + // | |
14 | + | |
15 | + public int Left; | |
16 | + public int Top; | |
17 | + public int Right; | |
18 | + public int Bottom; | |
19 | + | |
20 | + public int Width | |
21 | + { | |
22 | + get { return -Left + Right; } | |
23 | + } | |
24 | + public int Height | |
25 | + { | |
26 | + get { return -Top + Bottom; } | |
27 | + } | |
28 | + | |
29 | + // | |
30 | + // Public methods | |
31 | + // | |
32 | + | |
33 | + public Area( int left, int top, int right, int bottom ) | |
34 | + { | |
35 | + this.Left = left; | |
36 | + this.Top = top; | |
37 | + this.Right = right; | |
38 | + this.Bottom = bottom; | |
39 | + } | |
40 | + | |
41 | + public Rectangle MakeRectangle( Point basePoint ) | |
42 | + { | |
43 | + return this.MakeRectangle( basePoint, 1.0F, 1.0F ); | |
44 | + } | |
45 | + public Rectangle MakeRectangle( Point basePoint, float scaleX, float scaleY ) | |
46 | + { | |
47 | + return new Rectangle( | |
48 | + basePoint.X + (int)(Left * scaleX), | |
49 | + basePoint.Y + (int)(Top * scaleY), | |
50 | + (int)((-Left + Right) * scaleX), | |
51 | + (int)((-Top + Bottom) * scaleY) ); | |
52 | + } | |
53 | + } | |
54 | + | |
55 | + // 図面要素 | |
56 | + abstract class SqElement | |
57 | + { | |
58 | + // | |
59 | + // Public properties | |
60 | + // | |
61 | + | |
62 | + public enum ElementType | |
63 | + { | |
64 | + Lane, | |
65 | + MessageArrow, | |
66 | + Activity, | |
67 | + ActivityTerminator, | |
68 | + Blank, | |
69 | + HorizontalLine, | |
70 | + } | |
71 | + | |
72 | + public abstract ElementType Type { get; } | |
73 | + | |
74 | + // ノード名 | |
75 | + public string Name { get; set; } | |
76 | + | |
77 | + // ノードの基準座標 | |
78 | + public Point XY { get; set; } | |
79 | + | |
80 | + // レイアウト用エリア(余白を含む) | |
81 | + public Area Area { get; set; } | |
82 | + | |
83 | + // 縦方向位置 | |
84 | + public int Step { get; set; } | |
85 | + | |
86 | + // 外接矩形 | |
87 | + public virtual Rectangle Bounds { get { return this.Area.MakeRectangle( this.XY ); } } | |
88 | + | |
89 | + // 表示有無 | |
90 | + public bool Visible { get; set; } | |
91 | + | |
92 | + // 関連しているライフライン | |
93 | + public List<Lane> LinkedLanes { get; set; } | |
94 | + | |
95 | + // 元になったコマンドの行番号 | |
96 | + public int LineNo { get; set; } | |
97 | + | |
98 | + // 選択可能な要素かどうか | |
99 | + public bool UserSelectable { get; protected set; } | |
100 | + | |
101 | + // 選択移動可能な要素かどうか | |
102 | + public bool IsSelectionMoveStop { get; protected set; } | |
103 | + | |
104 | + public Color ForegroundColor | |
105 | + { | |
106 | + set | |
107 | + { | |
108 | + this.linePen.Color = value; | |
109 | + this.foregroundBrush = new SolidBrush( value ); | |
110 | + } | |
111 | + } | |
112 | + public Color BackgroundColor | |
113 | + { | |
114 | + set | |
115 | + { | |
116 | + this.backgroundBrush = new SolidBrush( value ); | |
117 | + } | |
118 | + } | |
119 | + public Color TextColor | |
120 | + { | |
121 | + set | |
122 | + { | |
123 | + this.textBrush = new SolidBrush( value ); | |
124 | + } | |
125 | + } | |
126 | + | |
127 | + // | |
128 | + // Public methods | |
129 | + // | |
130 | + | |
131 | + public abstract void Draw( Graphics g ); | |
132 | + | |
133 | + public virtual bool IntersectsWith( Rectangle rect ) | |
134 | + { | |
135 | + return rect.IntersectsWith( this.Bounds ); | |
136 | + } | |
137 | + | |
138 | + public virtual void DebugDraw( Graphics g ) | |
139 | + { | |
140 | + // 基準点 | |
141 | + this.debugPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; | |
142 | + g.DrawEllipse( this.debugPen, new Rectangle( this.XY.X - 2, this.XY.Y - 2, 4, 4 ) ); | |
143 | + | |
144 | + // エリア | |
145 | + this.debugPen.DashPattern = new float[] { 2.0F, 3.0F }; | |
146 | + g.DrawRectangle( this.debugPen, this.Area.MakeRectangle( this.XY ) ); | |
147 | + } | |
148 | + | |
149 | + public abstract bool IsMatched( string pattern ); | |
150 | + | |
151 | + // | |
152 | + // Protected fields | |
153 | + // | |
154 | + | |
155 | + protected Pen linePen = new Pen( Color.Black, 1.0F ); | |
156 | + protected Brush backgroundBrush = new SolidBrush( Color.White ); | |
157 | + protected Brush foregroundBrush = new SolidBrush( Color.Black ); | |
158 | + protected Font textFont = new Font( SystemFonts.MessageBoxFont.FontFamily.Name, 10.0F ); | |
159 | + protected Brush textBrush = new SolidBrush( Color.Black ); | |
160 | + | |
161 | + // | |
162 | + // Protected methods | |
163 | + // | |
164 | + | |
165 | + protected void Initialize() | |
166 | + { | |
167 | + this.Visible = true; | |
168 | + this.LinkedLanes = new List<Lane>(); | |
169 | + } | |
170 | + | |
171 | + // | |
172 | + // Private fields | |
173 | + // | |
174 | + | |
175 | + private Pen debugPen = new Pen( Color.OrangeRed, 1.0F ); | |
176 | + } | |
177 | + | |
178 | + // ライフライン | |
179 | + class Lane : SqElement | |
180 | + { | |
181 | + const int kTopMagin = 4; | |
182 | + const int kBottomMagin = 6; | |
183 | + readonly Area DefaultArea = new Area( -50, -50, 50, 0 ); | |
184 | + | |
185 | + // | |
186 | + // Public properties | |
187 | + // | |
188 | + | |
189 | + public override ElementType Type { get { return ElementType.Lane; } } | |
190 | + public string Label { get; set; } | |
191 | + public float Scale | |
192 | + { | |
193 | + get { return this.scale; } | |
194 | + set | |
195 | + { | |
196 | + if( this.scale != value ) | |
197 | + { | |
198 | + //this.linePen = new Pen( Color.Black, 1.0F * value ); | |
199 | + this.textFont = new Font( SystemFonts.MessageBoxFont.FontFamily.Name, 10.0F * value ); | |
200 | + } | |
201 | + this.scale = value; | |
202 | + } | |
203 | + } | |
204 | + public override Rectangle Bounds { get { return this.Area.MakeRectangle( this.XY, 1.0F, this.scale ); } } | |
205 | + | |
206 | + // | |
207 | + // Public methods | |
208 | + // | |
209 | + | |
210 | + public Lane() | |
211 | + { | |
212 | + base.Initialize(); | |
213 | + | |
214 | + var area = this.DefaultArea; | |
215 | +// area.Top -= kTopMagin; | |
216 | +// area.Bottom += kBottomMagin; | |
217 | + this.Area = area; | |
218 | + this.UserSelectable = true; | |
219 | + this.IsSelectionMoveStop = false; | |
220 | + } | |
221 | + | |
222 | + public override bool IntersectsWith( Rectangle rect ) | |
223 | + { | |
224 | + // レーンは下にずーっと線が出てるので横方向だけでチェック | |
225 | + return (rect.Left <= this.Bounds.Right && this.Bounds.Left <= rect.Right); | |
226 | + } | |
227 | + | |
228 | + public override void Draw( Graphics g ) | |
229 | + { | |
230 | + var area = this.DefaultArea; | |
231 | + area.Top += kTopMagin; | |
232 | + area.Bottom -= kBottomMagin; | |
233 | + var r = area.MakeRectangle( this.XY, 1.0F, this.scale ); | |
234 | + | |
235 | + // 矩形 | |
236 | + this.linePen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; | |
237 | + g.FillRectangle( this.backgroundBrush, r ); | |
238 | + g.DrawRectangle( this.linePen, r ); | |
239 | + | |
240 | + // ラベル | |
241 | + StringFormat format = new StringFormat(); | |
242 | + format.LineAlignment = StringAlignment.Center; | |
243 | + format.Alignment = StringAlignment.Center; | |
244 | + g.DrawString( this.Label, this.textFont, this.textBrush, r, format ); | |
245 | + | |
246 | + // ライフライン | |
247 | + this.linePen.DashPattern = new float[] { 6.0F, 4.0F }; | |
248 | + g.DrawLine( this.linePen, this.XY.X, r.Bottom, this.XY.X, g.VisibleClipBounds.Bottom ); | |
249 | + } | |
250 | + | |
251 | + public override bool IsMatched( string pattern ) | |
252 | + { | |
253 | + return this.Label != null && this.Label.Contains( pattern ); | |
254 | + } | |
255 | + | |
256 | + // | |
257 | + // Private fields | |
258 | + // | |
259 | + | |
260 | + float scale = 1.0F; | |
261 | + } | |
262 | + | |
263 | + // ライフライン間の矢印 | |
264 | + class MessageArrow : SqElement | |
265 | + { | |
266 | + const int kActivityHalfWidth = 5; | |
267 | + const int kLabelLeftMargin = 5; | |
268 | + const int kSelfMessageArrowWidth = 25; | |
269 | + readonly Size ArrowSize = new Size( 10, 10 ); | |
270 | + readonly Size CircleSize = new Size( 10, 10 ); | |
271 | + | |
272 | + // | |
273 | + // Public properties | |
274 | + // | |
275 | + | |
276 | + public enum MessageArrowType | |
277 | + { | |
278 | + Sync, | |
279 | + ASync, | |
280 | + Return, | |
281 | + }; | |
282 | + public enum DirectionType | |
283 | + { | |
284 | + LeftToRight, | |
285 | + RightToLeft, | |
286 | + Self, | |
287 | + } | |
288 | + | |
289 | + public override ElementType Type { get { return ElementType.MessageArrow; } } | |
290 | + public readonly Area DefaultArea = new Area( 0, -25, 0, 25 ); | |
291 | + public readonly Size SelfMessageSize = new Size( 50, 15 ); | |
292 | + | |
293 | + public string Label { get; set; } | |
294 | + public string ParamLabel { get; set; } | |
295 | + public MessageArrowType ArrowType { get; set; } | |
296 | + public Lane From { get; set; } | |
297 | + public Lane To { get; set; } | |
298 | + public DirectionType Direction { get; set; } | |
299 | + public Point EndXY { get; set; } | |
300 | + | |
301 | + // | |
302 | + // Public methods | |
303 | + // | |
304 | + | |
305 | + public MessageArrow() | |
306 | + { | |
307 | + base.Initialize(); | |
308 | + | |
309 | + this.Area = DefaultArea; | |
310 | + this.ArrowType = MessageArrowType.Sync; | |
311 | + this.Direction = DirectionType.LeftToRight; | |
312 | + this.UserSelectable = true; | |
313 | + this.IsSelectionMoveStop = true; | |
314 | + } | |
315 | + | |
316 | + public override void Draw( Graphics g ) | |
317 | + { | |
318 | + // 矢尻の向き(1:右 -1:左) | |
319 | + int arrowDir = (this.Direction == MessageArrow.DirectionType.LeftToRight) ? 1 : -1; | |
320 | + | |
321 | + Point startPoint = new Point(); | |
322 | + Point endPoint = new Point(); | |
323 | + | |
324 | + int labelOffsetX = kActivityHalfWidth + kLabelLeftMargin; | |
325 | + | |
326 | + // まずは線だけ描く | |
327 | + if( this.Direction == DirectionType.Self ) | |
328 | + { | |
329 | + // 自己メッセージ | |
330 | + startPoint = this.XY; | |
331 | + endPoint = new Point( this.XY.X, this.XY.Y + this.SelfMessageSize.Height ); | |
332 | + Point[] points = new Point[] { | |
333 | + startPoint, | |
334 | + new Point( startPoint.X + kSelfMessageArrowWidth, startPoint.Y ), | |
335 | + new Point( startPoint.X + kSelfMessageArrowWidth, startPoint.Y + this.SelfMessageSize.Height ), | |
336 | + endPoint, | |
337 | + }; | |
338 | + this.linePen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; | |
339 | + g.DrawLines( this.linePen, points ); | |
340 | + | |
341 | + labelOffsetX = kSelfMessageArrowWidth + kLabelLeftMargin; | |
342 | + } | |
343 | + else | |
344 | + { | |
345 | + // 他レーンへのメッセージ | |
346 | + if( this.ArrowType == MessageArrowType.Return ) | |
347 | + { | |
348 | + // 応答メッセージだけは破線です | |
349 | + this.linePen.DashPattern = new float[] { 6.0F, 4.0F }; | |
350 | + } | |
351 | + | |
352 | + if( this.From == null ) | |
353 | + { | |
354 | + startPoint.X = this.XY.X + this.Area.Left + CircleSize.Width; | |
355 | + startPoint.Y = this.XY.Y; | |
356 | + endPoint = this.XY; | |
357 | + } | |
358 | + else if( this.To == null ) | |
359 | + { | |
360 | + startPoint = this.XY; | |
361 | + endPoint.X = this.XY.X + this.Area.Right - CircleSize.Width; | |
362 | + endPoint.Y = this.XY.Y; | |
363 | + } | |
364 | + else | |
365 | + { | |
366 | + startPoint = this.XY; | |
367 | + endPoint = new Point( this.To.XY.X, this.XY.Y ); | |
368 | + } | |
369 | + //endPoint.X += this.Area.Width * arrowDir; | |
370 | + g.DrawLine( this.linePen, startPoint, endPoint ); | |
371 | + } | |
372 | + | |
373 | + // Lost/Foundの丸印を描く | |
374 | + if( this.From == null || this.To == null ) | |
375 | + { | |
376 | + Point circlePoint; | |
377 | + if( this.From == null ) | |
378 | + { | |
379 | + circlePoint = new Point( startPoint.X - CircleSize.Width, startPoint.Y - CircleSize.Height / 2 ); | |
380 | + } | |
381 | + else | |
382 | + { | |
383 | + circlePoint = new Point( endPoint.X, endPoint.Y - CircleSize.Height / 2 ); | |
384 | + } | |
385 | + Rectangle circleRect = new Rectangle( circlePoint, CircleSize ); | |
386 | + g.FillEllipse( this.backgroundBrush, circleRect ); | |
387 | + } | |
388 | + | |
389 | + // 矢尻描く | |
390 | + Point[] arrowPoints = new Point[] { | |
391 | + new Point( endPoint.X - ArrowSize.Width * arrowDir, endPoint.Y - (ArrowSize.Height / 2) ), | |
392 | + endPoint, | |
393 | + new Point( endPoint.X - ArrowSize.Width * arrowDir, endPoint.Y + (ArrowSize.Height / 2) ), | |
394 | + }; | |
395 | + if( this.ArrowType == MessageArrowType.Sync ) | |
396 | + { | |
397 | + g.FillPolygon( this.foregroundBrush, arrowPoints ); | |
398 | + } | |
399 | + else | |
400 | + { | |
401 | + g.DrawLines( this.linePen, arrowPoints ); | |
402 | + } | |
403 | + | |
404 | + // ラベルを描く | |
405 | + SizeF textSize = g.MeasureString( this.Label, this.textFont ); | |
406 | + StringFormat format = new StringFormat(); | |
407 | + format.LineAlignment = StringAlignment.Center; | |
408 | + format.Alignment = StringAlignment.Near; | |
409 | + | |
410 | + Rectangle r = this.Area.MakeRectangle( this.XY ); | |
411 | + g.DrawString( this.Label, this.textFont, textBrush, new Point( r.Left + labelOffsetX, (int)(this.XY.Y - textSize.Height) ) ); | |
412 | + g.DrawString( this.ParamLabel, this.textFont, textBrush, new Point( r.Left + labelOffsetX, this.XY.Y ) ); | |
413 | + } | |
414 | + | |
415 | + public override bool IsMatched( string pattern ) | |
416 | + { | |
417 | + return (this.Label != null && this.Label.Contains( pattern )) || | |
418 | + (this.ParamLabel != null && this.ParamLabel.Contains( pattern )); | |
419 | + } | |
420 | + } | |
421 | + | |
422 | + // 活性区間 | |
423 | + class Activity : SqElement | |
424 | + { | |
425 | + // | |
426 | + // Public properties | |
427 | + // | |
428 | + | |
429 | + public override ElementType Type { get { return ElementType.Activity; } } | |
430 | + public Point EndXY { get; set; } | |
431 | + public Lane Lane { get; set; } | |
432 | + public readonly int Gap = 10; | |
433 | + | |
434 | + // | |
435 | + // Public methods | |
436 | + // | |
437 | + | |
438 | + public Activity() | |
439 | + { | |
440 | + base.Initialize(); | |
441 | + | |
442 | + this.Area = new Area( -5, 0, 5, 0 ); | |
443 | + this.UserSelectable = false; | |
444 | + this.IsSelectionMoveStop = false; | |
445 | + } | |
446 | + | |
447 | + public override bool IntersectsWith( Rectangle rect ) | |
448 | + { | |
449 | + var area = this.Area; | |
450 | + area.Bottom = this.EndXY.Y - this.XY.Y; | |
451 | + return area.MakeRectangle( this.XY ).IntersectsWith( rect ); | |
452 | + } | |
453 | + | |
454 | + public override void Draw( Graphics g ) | |
455 | + { | |
456 | + var r = new Rectangle( | |
457 | + this.XY.X + this.Area.Left, this.XY.Y, | |
458 | + Area.Width, (EndXY.Y - this.XY.Y) ); | |
459 | + | |
460 | + g.FillRectangle( this.backgroundBrush, r ); | |
461 | + g.DrawRectangle( this.linePen, r ); | |
462 | + } | |
463 | + | |
464 | + public override bool IsMatched( string pattern ) | |
465 | + { | |
466 | + return false; | |
467 | + } | |
468 | + } | |
469 | + | |
470 | + // 活性区間終了部分 | |
471 | + class ActivityTerminator : SqElement | |
472 | + { | |
473 | + // | |
474 | + // Public properties | |
475 | + // | |
476 | + | |
477 | + public override ElementType Type { get { return ElementType.ActivityTerminator; } } | |
478 | + public Activity LinkedActivity { get; set; } | |
479 | + | |
480 | + // | |
481 | + // Public methods | |
482 | + // | |
483 | + | |
484 | + public ActivityTerminator() | |
485 | + { | |
486 | + base.Initialize(); | |
487 | + | |
488 | + this.Area = new Area( -5, 0, 5, 0 ); | |
489 | + this.UserSelectable = false; | |
490 | + this.IsSelectionMoveStop = false; | |
491 | + } | |
492 | + | |
493 | + public override bool IntersectsWith( Rectangle rect ) | |
494 | + { | |
495 | + return false; | |
496 | + } | |
497 | + | |
498 | + public override void Draw( Graphics g ) | |
499 | + { | |
500 | + // 何も描画しなくてよし | |
501 | + return; | |
502 | + } | |
503 | + | |
504 | + public override bool IsMatched( string pattern ) | |
505 | + { | |
506 | + return false; | |
507 | + } | |
508 | + } | |
509 | + | |
510 | + // 空白 | |
511 | + class Blank : SqElement | |
512 | + { | |
513 | + // | |
514 | + // Public properties | |
515 | + // | |
516 | + | |
517 | + public override ElementType Type { get { return ElementType.Blank; } } | |
518 | + readonly Area DefaultArea = new Area( 0, 0, 0, 50 ); | |
519 | + | |
520 | + // | |
521 | + // Public methods | |
522 | + // | |
523 | + | |
524 | + public Blank() | |
525 | + { | |
526 | + base.Initialize(); | |
527 | + | |
528 | + this.Area = this.DefaultArea; | |
529 | + this.UserSelectable = false; | |
530 | + this.IsSelectionMoveStop = false; | |
531 | + } | |
532 | + | |
533 | + public Blank( int size ) | |
534 | + { | |
535 | + base.Initialize(); | |
536 | + | |
537 | + var area = this.DefaultArea; | |
538 | + area.Bottom = size; | |
539 | + this.Area = area; | |
540 | + } | |
541 | + | |
542 | + public override bool IntersectsWith( Rectangle rect ) | |
543 | + { | |
544 | + return false; | |
545 | + } | |
546 | + | |
547 | + public override void Draw( Graphics g ) | |
548 | + { | |
549 | + // 何も描画しなくてよし | |
550 | + return; | |
551 | + } | |
552 | + | |
553 | + public override bool IsMatched( string pattern ) | |
554 | + { | |
555 | + return false; | |
556 | + } | |
557 | + } | |
558 | + | |
559 | + // 水平線 | |
560 | + class HorizontalLine : SqElement | |
561 | + { | |
562 | + // | |
563 | + // Public properties | |
564 | + // | |
565 | + | |
566 | + const int kLabelLeftMargin = 5; | |
567 | + public override ElementType Type { get { return ElementType.HorizontalLine; } } | |
568 | + // デフォルトエリアの縦方向はMessageクラスに合わせた | |
569 | + readonly Area DefaultArea = new Area( 0, -25, 0, 25 ); | |
570 | + public string Label { get; set; } | |
571 | + | |
572 | + // | |
573 | + // Public methods | |
574 | + // | |
575 | + | |
576 | + public HorizontalLine() | |
577 | + { | |
578 | + base.Initialize(); | |
579 | + | |
580 | + this.Area = this.DefaultArea; | |
581 | + this.UserSelectable = false; | |
582 | + this.IsSelectionMoveStop = false; | |
583 | + } | |
584 | + | |
585 | + public override void Draw( Graphics g ) | |
586 | + { | |
587 | + // 線を描く | |
588 | + var areaRect= this.Area.MakeRectangle( this.XY ); | |
589 | + this.linePen.Width = 2.0F; | |
590 | + g.DrawLine( this.linePen, areaRect.Left, this.XY.Y, areaRect.Right, this.XY.Y ); | |
591 | + | |
592 | + // ラベルを描く | |
593 | + var format = new StringFormat(); | |
594 | + format.LineAlignment = StringAlignment.Center; | |
595 | + format.Alignment = StringAlignment.Near; | |
596 | + | |
597 | + var r = this.Area.MakeRectangle( this.XY ); | |
598 | + var textSize = g.MeasureString( this.Label, this.textFont ); | |
599 | + g.DrawString( this.Label, this.textFont, this.textBrush, new Point( r.Left + kLabelLeftMargin, (int)(this.XY.Y - textSize.Height) ) ); | |
600 | + } | |
601 | + | |
602 | + public override bool IsMatched( string pattern ) | |
603 | + { | |
604 | + return this.Label != null && this.Label.Contains( pattern ); | |
605 | + } | |
606 | + } | |
607 | +} |
@@ -0,0 +1,97 @@ | ||
1 | +namespace sqwriter | |
2 | +{ | |
3 | + partial class FormAbout | |
4 | + { | |
5 | + /// <summary> | |
6 | + /// 必要なデザイナー変数です。 | |
7 | + /// </summary> | |
8 | + private System.ComponentModel.IContainer components = null; | |
9 | + | |
10 | + /// <summary> | |
11 | + /// 使用中のリソースをすべてクリーンアップします。 | |
12 | + /// </summary> | |
13 | + /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param> | |
14 | + protected override void Dispose( bool disposing ) | |
15 | + { | |
16 | + if( disposing && (components != null) ) | |
17 | + { | |
18 | + components.Dispose(); | |
19 | + } | |
20 | + base.Dispose( disposing ); | |
21 | + } | |
22 | + | |
23 | + #region Windows フォーム デザイナーで生成されたコード | |
24 | + | |
25 | + /// <summary> | |
26 | + /// デザイナー サポートに必要なメソッドです。このメソッドの内容を | |
27 | + /// コード エディターで変更しないでください。 | |
28 | + /// </summary> | |
29 | + private void InitializeComponent() | |
30 | + { | |
31 | + this.label1 = new System.Windows.Forms.Label(); | |
32 | + this.pictureBox1 = new System.Windows.Forms.PictureBox(); | |
33 | + this.button2 = new System.Windows.Forms.Button(); | |
34 | + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); | |
35 | + this.SuspendLayout(); | |
36 | + // | |
37 | + // label1 | |
38 | + // | |
39 | + this.label1.Font = new System.Drawing.Font("Consolas", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); | |
40 | + this.label1.Location = new System.Drawing.Point(58, 12); | |
41 | + this.label1.Name = "label1"; | |
42 | + this.label1.Size = new System.Drawing.Size(224, 67); | |
43 | + this.label1.TabIndex = 0; | |
44 | + this.label1.Text = "Name Version Copyright"; | |
45 | + // | |
46 | + // pictureBox1 | |
47 | + // | |
48 | + this.pictureBox1.Image = global::sqwriter.Properties.Resources.sqwriter; | |
49 | + this.pictureBox1.Location = new System.Drawing.Point(12, 12); | |
50 | + this.pictureBox1.Name = "pictureBox1"; | |
51 | + this.pictureBox1.Size = new System.Drawing.Size(40, 40); | |
52 | + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; | |
53 | + this.pictureBox1.TabIndex = 3; | |
54 | + this.pictureBox1.TabStop = false; | |
55 | + this.pictureBox1.DoubleClick += new System.EventHandler(this.pictureBox1_DoubleClick); | |
56 | + // | |
57 | + // button2 | |
58 | + // | |
59 | + this.button2.DialogResult = System.Windows.Forms.DialogResult.OK; | |
60 | + this.button2.Location = new System.Drawing.Point(207, 55); | |
61 | + this.button2.Name = "button2"; | |
62 | + this.button2.Size = new System.Drawing.Size(75, 23); | |
63 | + this.button2.TabIndex = 4; | |
64 | + this.button2.Text = "OK"; | |
65 | + this.button2.UseVisualStyleBackColor = true; | |
66 | + // | |
67 | + // FormAbout | |
68 | + // | |
69 | + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 14F); | |
70 | + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; | |
71 | + this.ClientSize = new System.Drawing.Size(294, 88); | |
72 | + this.Controls.Add(this.button2); | |
73 | + this.Controls.Add(this.pictureBox1); | |
74 | + this.Controls.Add(this.label1); | |
75 | + this.Font = new System.Drawing.Font("Consolas", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); | |
76 | + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; | |
77 | + this.KeyPreview = true; | |
78 | + this.MaximizeBox = false; | |
79 | + this.MinimizeBox = false; | |
80 | + this.Name = "FormAbout"; | |
81 | + this.ShowIcon = false; | |
82 | + this.ShowInTaskbar = false; | |
83 | + this.Text = "About"; | |
84 | + this.Load += new System.EventHandler(this.AboutForm_Load); | |
85 | + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.FormAbout_KeyDown); | |
86 | + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); | |
87 | + this.ResumeLayout(false); | |
88 | + | |
89 | + } | |
90 | + | |
91 | + #endregion | |
92 | + | |
93 | + private System.Windows.Forms.Label label1; | |
94 | + private System.Windows.Forms.PictureBox pictureBox1; | |
95 | + private System.Windows.Forms.Button button2; | |
96 | + } | |
97 | +} | |
\ No newline at end of file |
@@ -0,0 +1,96 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.ComponentModel; | |
4 | +using System.Data; | |
5 | +using System.Drawing; | |
6 | +using System.Linq; | |
7 | +using System.Text; | |
8 | +using System.Windows.Forms; | |
9 | +using System.Diagnostics; | |
10 | + | |
11 | +namespace sqwriter | |
12 | +{ | |
13 | + public partial class FormAbout : Form | |
14 | + { | |
15 | + public FormAbout() | |
16 | + { | |
17 | + InitializeComponent(); | |
18 | + } | |
19 | + | |
20 | + // | |
21 | + // Private fields | |
22 | + // | |
23 | + | |
24 | + Timer timer = new Timer(); | |
25 | + Point pictureLocation; | |
26 | + | |
27 | + // | |
28 | + // Private methods | |
29 | + // | |
30 | + | |
31 | + private void AboutForm_Load( object sender, EventArgs e ) | |
32 | + { | |
33 | + Util.TraverseControls( this, ( c ) => c.Font = SystemFonts.MessageBoxFont ); | |
34 | + | |
35 | + FileVersionInfo ver = FileVersionInfo.GetVersionInfo( | |
36 | + System.Reflection.Assembly.GetExecutingAssembly().Location ); | |
37 | + | |
38 | + this.label1.Text = ver.ProductName + " " + | |
39 | + "ver." + ver.ProductMajorPart + "." + ver.ProductMinorPart + "." + ver.ProductBuildPart + "\n" + | |
40 | + ver.LegalCopyright; | |
41 | + | |
42 | + this.Location = new Point( | |
43 | + this.Owner.Location.X + (this.Owner.Width - this.Width) / 2, | |
44 | + this.Owner.Location.Y + (this.Owner.Height - this.Height) / 2 ); | |
45 | + | |
46 | + this.timer.Tick += timer_Tick; | |
47 | + | |
48 | + } | |
49 | + | |
50 | + private void FormAbout_KeyDown( object sender, KeyEventArgs e ) | |
51 | + { | |
52 | + if( e.KeyCode == Keys.Escape ) | |
53 | + { | |
54 | + this.Close(); | |
55 | + } | |
56 | + } | |
57 | + | |
58 | + private void pictureBox1_DoubleClick( object sender, EventArgs e ) | |
59 | + { | |
60 | + this.pictureBox1.Enabled = false; | |
61 | + this.pictureLocation = this.pictureBox1.Location; | |
62 | + this.timer.Tag = 1; | |
63 | + this.timer.Interval = 10; | |
64 | + this.timer.Start(); | |
65 | + } | |
66 | + | |
67 | + void timer_Tick( object sender, EventArgs e ) | |
68 | + { | |
69 | + if( (int)this.timer.Tag == 1 ) | |
70 | + { | |
71 | + this.pictureBox1.Location = new Point( this.pictureBox1.Location.X, this.pictureBox1.Location.Y + 10 ); | |
72 | + if( this.pictureBox1.Location.Y >= this.Height ) | |
73 | + { | |
74 | + this.timer.Tag = 2; | |
75 | + this.timer.Interval = 2000; | |
76 | + } | |
77 | + } | |
78 | + else if( (int)this.timer.Tag == 2 ) | |
79 | + { | |
80 | + this.pictureBox1.Location = new Point( this.pictureBox1.Location.X, -this.pictureBox1.Height ); | |
81 | + this.timer.Tag = 3; | |
82 | + this.timer.Interval = 50; | |
83 | + } | |
84 | + else if( (int)this.timer.Tag == 3 ) | |
85 | + { | |
86 | + this.pictureBox1.Location = new Point( this.pictureBox1.Location.X, this.pictureBox1.Location.Y + 1 ); | |
87 | + if( this.pictureBox1.Location.Y >= pictureLocation.Y ) | |
88 | + { | |
89 | + this.pictureBox1.Enabled = true; | |
90 | + this.timer.Tag = 0; | |
91 | + this.timer.Stop(); | |
92 | + } | |
93 | + } | |
94 | + } | |
95 | + } | |
96 | +} |
@@ -0,0 +1,99 @@ | ||
1 | +namespace sqwriter | |
2 | +{ | |
3 | + partial class FormDebug | |
4 | + { | |
5 | + /// <summary> | |
6 | + /// 必要なデザイナー変数です。 | |
7 | + /// </summary> | |
8 | + private System.ComponentModel.IContainer components = null; | |
9 | + | |
10 | + /// <summary> | |
11 | + /// 使用中のリソースをすべてクリーンアップします。 | |
12 | + /// </summary> | |
13 | + /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param> | |
14 | + protected override void Dispose( bool disposing ) | |
15 | + { | |
16 | + if( disposing && (components != null) ) | |
17 | + { | |
18 | + components.Dispose(); | |
19 | + } | |
20 | + base.Dispose( disposing ); | |
21 | + } | |
22 | + | |
23 | + #region Windows フォーム デザイナーで生成されたコード | |
24 | + | |
25 | + /// <summary> | |
26 | + /// デザイナー サポートに必要なメソッドです。このメソッドの内容を | |
27 | + /// コード エディターで変更しないでください。 | |
28 | + /// </summary> | |
29 | + private void InitializeComponent() | |
30 | + { | |
31 | + this.listView1 = new System.Windows.Forms.ListView(); | |
32 | + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); | |
33 | + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); | |
34 | + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); | |
35 | + this.SuspendLayout(); | |
36 | + // | |
37 | + // listView1 | |
38 | + // | |
39 | + this.listView1.BackColor = System.Drawing.Color.White; | |
40 | + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { | |
41 | + this.columnHeader1, | |
42 | + this.columnHeader2}); | |
43 | + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; | |
44 | + this.listView1.Font = new System.Drawing.Font("Consolas", 9F); | |
45 | + this.listView1.FullRowSelect = true; | |
46 | + this.listView1.GridLines = true; | |
47 | + this.listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; | |
48 | + this.listView1.Location = new System.Drawing.Point(0, 0); | |
49 | + this.listView1.Name = "listView1"; | |
50 | + this.listView1.Size = new System.Drawing.Size(384, 361); | |
51 | + this.listView1.TabIndex = 0; | |
52 | + this.listView1.UseCompatibleStateImageBehavior = false; | |
53 | + this.listView1.View = System.Windows.Forms.View.Details; | |
54 | + this.listView1.SizeChanged += new System.EventHandler(this.listView1_SizeChanged); | |
55 | + // | |
56 | + // columnHeader1 | |
57 | + // | |
58 | + this.columnHeader1.Text = "Name"; | |
59 | + // | |
60 | + // columnHeader2 | |
61 | + // | |
62 | + this.columnHeader2.Text = "Value"; | |
63 | + // | |
64 | + // statusStrip1 | |
65 | + // | |
66 | + this.statusStrip1.Location = new System.Drawing.Point(0, 339); | |
67 | + this.statusStrip1.Name = "statusStrip1"; | |
68 | + this.statusStrip1.Size = new System.Drawing.Size(384, 22); | |
69 | + this.statusStrip1.TabIndex = 1; | |
70 | + this.statusStrip1.Text = "statusStrip1"; | |
71 | + // | |
72 | + // FormDebug | |
73 | + // | |
74 | + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 14F); | |
75 | + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; | |
76 | + this.ClientSize = new System.Drawing.Size(384, 361); | |
77 | + this.ControlBox = false; | |
78 | + this.Controls.Add(this.statusStrip1); | |
79 | + this.Controls.Add(this.listView1); | |
80 | + this.Font = new System.Drawing.Font("Consolas", 9F); | |
81 | + this.Name = "FormDebug"; | |
82 | + this.ShowInTaskbar = false; | |
83 | + this.Text = "watcher"; | |
84 | + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormDebug_FormClosing); | |
85 | + this.Load += new System.EventHandler(this.FormDebug_Load); | |
86 | + this.ResumeLayout(false); | |
87 | + this.PerformLayout(); | |
88 | + | |
89 | + } | |
90 | + | |
91 | + #endregion | |
92 | + | |
93 | + private System.Windows.Forms.ListView listView1; | |
94 | + private System.Windows.Forms.ColumnHeader columnHeader1; | |
95 | + private System.Windows.Forms.ColumnHeader columnHeader2; | |
96 | + private System.Windows.Forms.StatusStrip statusStrip1; | |
97 | + | |
98 | + } | |
99 | +} | |
\ No newline at end of file |
@@ -0,0 +1,103 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.ComponentModel; | |
4 | +using System.Data; | |
5 | +using System.Drawing; | |
6 | +using System.Linq; | |
7 | +using System.Text; | |
8 | +using System.Windows.Forms; | |
9 | + | |
10 | +namespace sqwriter | |
11 | +{ | |
12 | + public partial class FormDebug : Form | |
13 | + { | |
14 | + Dictionary<string, string> items = new Dictionary<string, string>(); | |
15 | + bool needListClear = false; | |
16 | + bool needListUpdate = false; | |
17 | + Timer timer = new Timer(); | |
18 | + static FormDebug instance = null; | |
19 | + | |
20 | + public FormDebug() | |
21 | + { | |
22 | + InitializeComponent(); | |
23 | + instance = this; | |
24 | + } | |
25 | + | |
26 | + public static void SetItem( string key, object data ) | |
27 | + { | |
28 | + if( instance != null ) | |
29 | + { | |
30 | + if( instance.items.ContainsKey( key ) ) | |
31 | + { | |
32 | + instance.items[key] = data.ToString(); | |
33 | + } | |
34 | + else | |
35 | + { | |
36 | + instance.items.Add( key, data.ToString() ); | |
37 | + instance.needListClear = true; | |
38 | + } | |
39 | + instance.needListUpdate = true; | |
40 | + //UpdateList(); | |
41 | + } | |
42 | + } | |
43 | + | |
44 | + | |
45 | + private void FormDebug_Load( object sender, EventArgs e ) | |
46 | + { | |
47 | + this.listView1.Columns[0].Width = 150; | |
48 | + | |
49 | + timer.Interval = 100; | |
50 | + timer.Tick += new EventHandler( timer_Tick ); | |
51 | + timer.Start(); | |
52 | + } | |
53 | + | |
54 | + void timer_Tick( object sender, EventArgs e ) | |
55 | + { | |
56 | + if( this.needListUpdate ) | |
57 | + { | |
58 | + UpdateList(); | |
59 | + this.needListUpdate = false; | |
60 | + } | |
61 | + } | |
62 | + | |
63 | + private void UpdateList() | |
64 | + { | |
65 | + if( !this.Visible ) | |
66 | + { | |
67 | + return; | |
68 | + } | |
69 | + if( this.needListClear ) | |
70 | + { | |
71 | + this.listView1.Items.Clear(); | |
72 | + foreach( string key in this.items.Keys ) | |
73 | + { | |
74 | + ListViewItem listItem = this.listView1.Items.Add( key ); | |
75 | + listItem.SubItems.Add( this.items[key] ); | |
76 | + } | |
77 | + this.needListClear = false; | |
78 | + } | |
79 | + else | |
80 | + { | |
81 | + int i = 0; | |
82 | + foreach( string key in this.items.Keys ) | |
83 | + { | |
84 | + this.listView1.Items[i].SubItems[1].Text = this.items[key]; | |
85 | + i++; | |
86 | + } | |
87 | + } | |
88 | + } | |
89 | + | |
90 | + private void listView1_SizeChanged( object sender, EventArgs e ) | |
91 | + { | |
92 | + this.listView1.Columns[1].Width = this.listView1.ClientSize.Width - this.listView1.Columns[0].Width; | |
93 | + } | |
94 | + | |
95 | + private void FormDebug_FormClosing( object sender, FormClosingEventArgs e ) | |
96 | + { | |
97 | + if( e.CloseReason == CloseReason.UserClosing ) | |
98 | + { | |
99 | + e.Cancel = true; | |
100 | + } | |
101 | + } | |
102 | + } | |
103 | +} |
@@ -0,0 +1,47 @@ | ||
1 | +namespace sqwriter | |
2 | +{ | |
3 | + partial class FormShortcutKey | |
4 | + { | |
5 | + /// <summary> | |
6 | + /// Required designer variable. | |
7 | + /// </summary> | |
8 | + private System.ComponentModel.IContainer components = null; | |
9 | + | |
10 | + /// <summary> | |
11 | + /// Clean up any resources being used. | |
12 | + /// </summary> | |
13 | + /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> | |
14 | + protected override void Dispose( bool disposing ) | |
15 | + { | |
16 | + if( disposing && (components != null) ) | |
17 | + { | |
18 | + components.Dispose(); | |
19 | + } | |
20 | + base.Dispose( disposing ); | |
21 | + } | |
22 | + | |
23 | + #region Windows Form Designer generated code | |
24 | + | |
25 | + /// <summary> | |
26 | + /// Required method for Designer support - do not modify | |
27 | + /// the contents of this method with the code editor. | |
28 | + /// </summary> | |
29 | + private void InitializeComponent() | |
30 | + { | |
31 | + this.SuspendLayout(); | |
32 | + // | |
33 | + // FormShortcutKey | |
34 | + // | |
35 | + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); | |
36 | + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; | |
37 | + this.ClientSize = new System.Drawing.Size(284, 261); | |
38 | + this.Name = "FormShortcutKey"; | |
39 | + this.Text = "FormShortcutKey"; | |
40 | + this.Load += new System.EventHandler(this.FormShortcutKey_Load); | |
41 | + this.ResumeLayout(false); | |
42 | + | |
43 | + } | |
44 | + | |
45 | + #endregion | |
46 | + } | |
47 | +} | |
\ No newline at end of file |
@@ -0,0 +1,209 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Linq; | |
4 | +using System.Text; | |
5 | +using System.Drawing; | |
6 | +using System.Diagnostics; | |
7 | +using System.Reflection; | |
8 | + | |
9 | +namespace sqwriter | |
10 | +{ | |
11 | + class Layouter | |
12 | + { | |
13 | + //TODO: SqAssemblyに持っていってもいい | |
14 | + //! 指定された矩形エリアに合わせてノードの位置や幅高さを調整 | |
15 | + public static void LayoutElements( List<SqElement> elements, List<SqElement> lanes, out Size layoutedSize ) | |
16 | + { | |
17 | + // 表示対象のものに絞る | |
18 | + var visibleLanes = lanes.Where( ( lane ) => lane.Visible ).ToList(); | |
19 | + | |
20 | + layoutedSize = new Size(); | |
21 | + if( visibleLanes.Count <= 0 ) | |
22 | + { | |
23 | + foreach( SqElement element in elements ) | |
24 | + { | |
25 | + element.Visible = false; | |
26 | + } | |
27 | + return; | |
28 | + } | |
29 | + | |
30 | + int widthSum = 0; | |
31 | + foreach( Lane lane in visibleLanes ) | |
32 | + { | |
33 | + widthSum += lane.Area.Width * 2; | |
34 | + } | |
35 | + | |
36 | + // レイアウト用の幅を決める | |
37 | + // 指定の幅が狭すぎる場合はレーン幅の合計の方を採用 | |
38 | + layoutedSize.Width = widthSum; | |
39 | + | |
40 | + // レーンの位置を決める | |
41 | + // 1レーンあたりの幅 | |
42 | + int laneWidth = layoutedSize.Width / visibleLanes.Count; | |
43 | + int x = laneWidth / 2; | |
44 | + int y = 0; | |
45 | + | |
46 | + foreach( Lane lane in visibleLanes ) | |
47 | + { | |
48 | + // 初期レーン以外のY座標は後で変更されるよ | |
49 | + lane.XY = new Point( x, y ); | |
50 | + | |
51 | + x += laneWidth; | |
52 | + } | |
53 | + | |
54 | + SqElement prevElement = null; | |
55 | + // 実行中から伸びるメッセージが重ならないようにすることを試みた痕跡 | |
56 | + //Dictionary<Lane, Activity> activeExecutions = new Dictionary<Lane,Activity>(); | |
57 | + foreach( SqElement element in elements ) | |
58 | + { | |
59 | + if( !element.Visible ) | |
60 | + { | |
61 | + continue; | |
62 | + } | |
63 | + | |
64 | + if( prevElement == null ) | |
65 | + { | |
66 | + y += (-element.Area.Top); | |
67 | + } | |
68 | + else if( prevElement != null && prevElement.Step < element.Step ) | |
69 | + { | |
70 | + y += prevElement.Area.Bottom + (-element.Area.Top); | |
71 | + } | |
72 | + | |
73 | + if( element.Type == SqElement.ElementType.Lane ) | |
74 | + { | |
75 | + element.XY = new Point( element.XY.X, y ); | |
76 | + } | |
77 | + else if( element.Type == SqElement.ElementType.Activity ) | |
78 | + { | |
79 | + Activity activity = (Activity)element; | |
80 | + element.XY = new Point( activity.Lane.XY.X, y ); | |
81 | + // 直前がメッセージ受信だったらそこにつなげる | |
82 | + if( prevElement != null && prevElement.Type == SqElement.ElementType.MessageArrow ) | |
83 | + { | |
84 | + MessageArrow msg = (MessageArrow)prevElement; | |
85 | + if( msg.To == activity.Lane ) | |
86 | + { | |
87 | + element.XY = new Point( activity.Lane.XY.X, msg.EndXY.Y ); | |
88 | + } | |
89 | + } | |
90 | + // 終わりの位置はActivityTerminatorにて決定 | |
91 | + //activeExecutions.Add( exec.Lane, exec ); | |
92 | + } | |
93 | + else if( element.Type == SqElement.ElementType.ActivityTerminator ) | |
94 | + { | |
95 | + ActivityTerminator term = (ActivityTerminator)element; | |
96 | + if( term.LinkedActivity == null ) | |
97 | + { | |
98 | + Trace.TraceError( "[ERROR][{0}]LinkedActivity is null.", MethodBase.GetCurrentMethod().Name ); | |
99 | + continue; | |
100 | + } | |
101 | + Activity start = term.LinkedActivity; | |
102 | + term.XY = new Point( start.Lane.XY.X, y ); | |
103 | + start.EndXY = new Point( term.XY.X, term.XY.Y - start.Gap ); | |
104 | + //activeExecutions.Remove( exec.Lane ); | |
105 | + } | |
106 | + else if( element.Type == SqElement.ElementType.MessageArrow ) | |
107 | + { | |
108 | + MessageArrow msg = (MessageArrow)element; | |
109 | + | |
110 | + Trace.Assert( msg.From != null || msg.To != null ); | |
111 | + | |
112 | + int fromX; | |
113 | + if( msg.From == null ) | |
114 | + { | |
115 | + fromX = msg.To.XY.X - laneWidth / 2; | |
116 | + } | |
117 | + else | |
118 | + { | |
119 | + fromX = msg.From.XY.X; | |
120 | + } | |
121 | + | |
122 | + int toX; | |
123 | + if( msg.To == null ) | |
124 | + { | |
125 | + toX = msg.From.XY.X + laneWidth / 2; | |
126 | + } | |
127 | + else | |
128 | + { | |
129 | + toX = msg.To.XY.X; | |
130 | + } | |
131 | + | |
132 | + if( msg.From == null ) | |
133 | + { | |
134 | + // 送信元なしの場合、基準点は送信先の位置とする | |
135 | + msg.XY = new Point( toX, y ); | |
136 | + msg.Direction = MessageArrow.DirectionType.LeftToRight; | |
137 | + Area area = msg.Area; | |
138 | + area.Left = fromX - toX; | |
139 | + area.Right = 0; | |
140 | + msg.Area = area; | |
141 | + } | |
142 | + else | |
143 | + { | |
144 | + msg.XY = new Point( fromX, y ); | |
145 | + | |
146 | + if( msg.From == msg.To ) | |
147 | + { | |
148 | + msg.Direction = MessageArrow.DirectionType.Self; | |
149 | + Area area = msg.Area; | |
150 | + area.Right = msg.DefaultArea.Right + msg.SelfMessageSize.Width; | |
151 | + area.Bottom = msg.DefaultArea.Bottom; | |
152 | + msg.Area = area; | |
153 | + } | |
154 | + else if( fromX <= toX ) | |
155 | + { | |
156 | + msg.Direction = MessageArrow.DirectionType.LeftToRight; | |
157 | + Area area = msg.Area; | |
158 | + area.Left = msg.DefaultArea.Left; | |
159 | + area.Right = toX - fromX; | |
160 | + msg.Area = area; | |
161 | + } | |
162 | + else | |
163 | + { | |
164 | + msg.Direction = MessageArrow.DirectionType.RightToLeft; | |
165 | + Area area = msg.Area; | |
166 | + area.Left = msg.To.XY.X - msg.From.XY.X; | |
167 | + area.Right = msg.DefaultArea.Right; | |
168 | + msg.Area = area; | |
169 | + } | |
170 | + } | |
171 | + | |
172 | + if( msg.Direction == MessageArrow.DirectionType.Self ) | |
173 | + { | |
174 | + msg.EndXY = new Point( toX, msg.XY.Y + msg.SelfMessageSize.Height ); | |
175 | + } | |
176 | + else | |
177 | + { | |
178 | + msg.EndXY = new Point( toX, msg.XY.Y ); | |
179 | + } | |
180 | + } | |
181 | + else if( element.Type == SqElement.ElementType.Blank ) | |
182 | + { | |
183 | + Blank blank = (Blank)element; | |
184 | + blank.XY = new Point( 0, y ); | |
185 | + Area area = blank.Area; | |
186 | + area.Right = layoutedSize.Width; | |
187 | + blank.Area = area; | |
188 | + } | |
189 | + else if( element.Type == SqElement.ElementType.HorizontalLine ) | |
190 | + { | |
191 | + HorizontalLine hline = (HorizontalLine)element; | |
192 | + hline.XY = new Point( 0, y ); | |
193 | + Area area = hline.Area; | |
194 | + area.Right = layoutedSize.Width; | |
195 | + hline.Area = area; | |
196 | + } | |
197 | + | |
198 | + prevElement = element; | |
199 | + } | |
200 | + | |
201 | + y += prevElement.Area.Bottom; | |
202 | + layoutedSize.Height = y; | |
203 | + | |
204 | + FormDebug.SetItem( "layoutedSize", layoutedSize.ToString() ); | |
205 | + | |
206 | + return; | |
207 | + } | |
208 | + } | |
209 | +} |
@@ -0,0 +1,536 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Linq; | |
4 | +using System.Text; | |
5 | +using System.Windows.Forms; | |
6 | +using System.Drawing; | |
7 | +using System.Reflection; | |
8 | +using System.Diagnostics; | |
9 | + | |
10 | +namespace sqwriter | |
11 | +{ | |
12 | + // スクロール/ズーム制御 | |
13 | + public class MotionContoller | |
14 | + { | |
15 | + // デフォルトのタイマー周期[ms] | |
16 | + const int kDefaultTimerInterval = 15; | |
17 | + | |
18 | + // | |
19 | + // Public events | |
20 | + // | |
21 | + | |
22 | + public delegate void ParamUpdateEventHandler( MotionContoller sender, ParamUpdateEventArgs e ); | |
23 | + | |
24 | + public class ParamUpdateEventArgs : EventArgs | |
25 | + { | |
26 | + public PointF PositionXY; | |
27 | + public float Scale; | |
28 | + public bool ZoomFinished; | |
29 | + } | |
30 | + | |
31 | + public event ParamUpdateEventHandler ParamUpdate; | |
32 | + | |
33 | + // | |
34 | + // Public properties | |
35 | + // | |
36 | + | |
37 | + public enum ScrollMode | |
38 | + { | |
39 | + None, | |
40 | + Drag, | |
41 | + Vector, | |
42 | + Flick, | |
43 | + Point, | |
44 | + } | |
45 | + | |
46 | + public enum TouchMode | |
47 | + { | |
48 | + None, | |
49 | + Drag, | |
50 | + Vector, | |
51 | + } | |
52 | + | |
53 | + public enum ZoomMode | |
54 | + { | |
55 | + None, | |
56 | + Zooming, | |
57 | + } | |
58 | + | |
59 | + public PointF PositionXY | |
60 | + { | |
61 | + get { return this.positionXY; } | |
62 | + set | |
63 | + { | |
64 | + this.StopScroll(); | |
65 | + //this.EndZoom(); | |
66 | + | |
67 | + this.positionXY = value; | |
68 | + ParamUpdate( this, new ParamUpdateEventArgs { PositionXY = this.positionXY, Scale = this.scale } ); | |
69 | + FormDebug.SetItem( "Motion.positionXY", this.positionXY ); | |
70 | + FormDebug.SetItem( "Motion.targetXY", this.targetXY ); | |
71 | + } | |
72 | + } | |
73 | + | |
74 | + public float Scale | |
75 | + { | |
76 | + get { return this.scale; } | |
77 | + set | |
78 | + { | |
79 | + this.StopScroll(); | |
80 | + //this.EndZoom(); | |
81 | + this.scale = value; | |
82 | + ParamUpdate( this, new ParamUpdateEventArgs { PositionXY = this.positionXY, Scale = this.scale } ); | |
83 | + FormDebug.SetItem( "Motion.scale", this.scale ); | |
84 | + } | |
85 | + } | |
86 | + | |
87 | + public int Interval | |
88 | + { | |
89 | + set { this.timer.Interval = value; } | |
90 | + } | |
91 | + | |
92 | + public ScrollMode Mode | |
93 | + { | |
94 | + get { return this.mode; } | |
95 | + } | |
96 | + | |
97 | + public ZoomMode ModeOfZoom | |
98 | + { | |
99 | + get { return this.zoomMode; } | |
100 | + } | |
101 | + | |
102 | + public PointF TargetPositionXY | |
103 | + { | |
104 | + get | |
105 | + { | |
106 | + if( this.mode == ScrollMode.Point ) | |
107 | + { | |
108 | + return this.targetXY; | |
109 | + } | |
110 | + else | |
111 | + { | |
112 | + return this.positionXY; | |
113 | + } | |
114 | + } | |
115 | + } | |
116 | + public float TargetScale | |
117 | + { | |
118 | + get | |
119 | + { | |
120 | + if( this.zoomMode == ZoomMode.Zooming ) | |
121 | + { | |
122 | + return this.targetScale; | |
123 | + } | |
124 | + else | |
125 | + { | |
126 | + return this.scale; | |
127 | + } | |
128 | + } | |
129 | + } | |
130 | + public PointF TouchOnXY | |
131 | + { | |
132 | + get { return this.touchOnXY; } | |
133 | + } | |
134 | + public PointF TouchMoveXY | |
135 | + { | |
136 | + get { return this.touchMoveXY; } | |
137 | + } | |
138 | + | |
139 | + // | |
140 | + // Public methods | |
141 | + // | |
142 | + | |
143 | + public MotionContoller() | |
144 | + { | |
145 | + this.timer.Interval = kDefaultTimerInterval; | |
146 | + this.timer.Tick += new EventHandler( timer_Tick ); | |
147 | + } | |
148 | + | |
149 | + public MotionContoller( PointF xy, float scale ) | |
150 | + { | |
151 | + this.positionXY = xy; | |
152 | + this.scale = scale; | |
153 | + this.timer.Interval = kDefaultTimerInterval; | |
154 | + this.timer.Tick += new EventHandler( timer_Tick ); | |
155 | + } | |
156 | + | |
157 | + /// <summary> | |
158 | + /// タッチOn通知 | |
159 | + /// </summary> | |
160 | + /// <param name="touchOnXY">スクリーン座標</param> | |
161 | + public void TouchOn( PointF xy, TouchMode mode ) | |
162 | + { | |
163 | + if( mode == TouchMode.Drag ) | |
164 | + { | |
165 | + this.StartDragScroll( xy ); | |
166 | + } | |
167 | + else if( mode == TouchMode.Vector ) | |
168 | + { | |
169 | + this.StartVectorScroll( xy ); | |
170 | + } | |
171 | + } | |
172 | + | |
173 | + /// <summary> | |
174 | + /// タッチOff通知 | |
175 | + /// </summary> | |
176 | + /// <param name="touchOnXY">スクリーン座標</param> | |
177 | + public void TouchOff( PointF xy ) | |
178 | + { | |
179 | + if( this.mode == ScrollMode.Drag ) | |
180 | + { | |
181 | + float speed; | |
182 | + float dir; | |
183 | + if( this.GetFlickScrollParam( out speed, out dir ) ) | |
184 | + { | |
185 | + this.StartFlickScroll( speed, dir ); | |
186 | + } | |
187 | + else | |
188 | + { | |
189 | + this.StopScroll(); | |
190 | + } | |
191 | + } | |
192 | + else if( this.mode == ScrollMode.Vector ) | |
193 | + { | |
194 | + this.StopScroll(); | |
195 | + } | |
196 | + } | |
197 | + | |
198 | + /// <summary> | |
199 | + /// タッチ位置移動通知 | |
200 | + /// </summary> | |
201 | + /// <param name="touchOnXY">スクリーン座標</param> | |
202 | + public void TouchMove( PointF xy ) | |
203 | + { | |
204 | + this.touchMoveXY = xy; | |
205 | + | |
206 | + if( this.mode == ScrollMode.Drag ) | |
207 | + { | |
208 | + this.MoveDragScroll( xy ); | |
209 | + } | |
210 | + } | |
211 | + | |
212 | + /// <summary> | |
213 | + /// 現在の位置からの相対移動 | |
214 | + /// </summary> | |
215 | + /// <param name="moveX"></param> | |
216 | + /// <param name="moveY"></param> | |
217 | + public void MovePosition( float moveX, float moveY ) | |
218 | + { | |
219 | + PointF xy = new PointF( | |
220 | + this.TargetPositionXY.X + moveX, | |
221 | + this.TargetPositionXY.Y + moveY ); | |
222 | + this.StartPointScroll( xy ); | |
223 | + } | |
224 | + | |
225 | + /// <summary> | |
226 | + /// 現在の位置からの相対移動(位置揃え指定) | |
227 | + /// </summary> | |
228 | + /// <param name="moveX"></param> | |
229 | + /// <param name="moveY"></param> | |
230 | + /// <param name="alignX"></param> | |
231 | + /// <param name="alignY"></param> | |
232 | + public void MovePosition( float moveX, float moveY, uint alignX, uint alignY ) | |
233 | + { | |
234 | + PointF txy = this.TargetPositionXY; | |
235 | + | |
236 | + float mx = 0.0F; | |
237 | + float my = 0.0F; | |
238 | + if( alignX > 0 ) | |
239 | + { | |
240 | + if( moveX < 0.0F ) | |
241 | + { | |
242 | + mx = (int)Math.Ceiling( (double)txy.X / alignX ) * alignX - txy.X; | |
243 | + } | |
244 | + else if( moveX > 0.0F ) | |
245 | + { | |
246 | + mx = (int)Math.Floor( (double)txy.X / alignX ) * alignX - txy.X; | |
247 | + } | |
248 | + } | |
249 | + if( alignY > 0 ) | |
250 | + { | |
251 | + if( moveY < 0.0F ) | |
252 | + { | |
253 | + my = (int)Math.Ceiling( (double)txy.Y / alignY ) * alignY - txy.Y; | |
254 | + } | |
255 | + else if( moveY > 0.0F ) | |
256 | + { | |
257 | + my = (int)Math.Floor( (double)txy.Y / alignY ) * alignY - txy.Y; | |
258 | + } | |
259 | + } | |
260 | + PointF xy = new PointF( | |
261 | + txy.X + mx + moveX, | |
262 | + txy.Y + my + moveY ); | |
263 | + this.StartPointScroll( xy ); | |
264 | + } | |
265 | + | |
266 | + /// <summary> | |
267 | + /// 指定された位置への移動 | |
268 | + /// </summary> | |
269 | + /// <param name="jumpXY"></param> | |
270 | + public void JumpPosition( PointF jumpXY ) | |
271 | + { | |
272 | + this.StartPointScroll( jumpXY ); | |
273 | + } | |
274 | + | |
275 | + /// <summary> | |
276 | + /// スケール変更 | |
277 | + /// </summary> | |
278 | + /// <param name="scale"></param> | |
279 | + public void JumpScale( float scale ) | |
280 | + { | |
281 | + this.StartZoom( scale ); | |
282 | + } | |
283 | + | |
284 | + public void Step() | |
285 | + { | |
286 | + bool zoomFinished = false; | |
287 | + | |
288 | + if( this.mode == ScrollMode.Flick ) | |
289 | + { | |
290 | + // 減速率反映 | |
291 | + //this.scrollSpeed *= 0.97F; | |
292 | + this.scrollSpeed *= 0.90F; | |
293 | + | |
294 | + if( this.scrollSpeed < 3.0F ) | |
295 | + { | |
296 | + // 十分に遅くなったら止まったものと見なす | |
297 | + //this.PositionXY.X = (float)Math.Round( this.PositionXY.X ); | |
298 | + //this.PositionXY.Y = (float)Math.Round( this.PositionXY.Y ); | |
299 | + this.mode = ScrollMode.None; | |
300 | + this.StopTimer(); | |
301 | + } | |
302 | + else | |
303 | + { | |
304 | + // フレームレートにあわせて移動量を調節 | |
305 | + float move = this.scrollSpeed / (1000 / this.timer.Interval) * 50 / this.scale; | |
306 | + this.positionXY.X += (float)Math.Cos( this.scrollDirection ) * move; | |
307 | + this.positionXY.Y += (float)Math.Sin( this.scrollDirection ) * move; | |
308 | + } | |
309 | + } | |
310 | + else if( this.mode == ScrollMode.Point ) | |
311 | + { | |
312 | + // 1コマで動かす目標座標に対する割合(1.0とすると1コマで目標座標に到達) | |
313 | + //float pointScrollRatio = 0.02F; | |
314 | + float pointScrollRatio = 0.2F; | |
315 | + float dx = this.targetXY.X - this.positionXY.X; | |
316 | + float dy = this.targetXY.Y - this.positionXY.Y; | |
317 | + | |
318 | + if( Math.Abs( dx ) < 1.0F && Math.Abs( dy ) < 1.0F ) | |
319 | + { | |
320 | + this.positionXY = this.targetXY; | |
321 | + this.mode = ScrollMode.None; | |
322 | + this.StopTimer(); | |
323 | + } | |
324 | + else | |
325 | + { | |
326 | + float mx = dx * pointScrollRatio; | |
327 | + float my = dy * pointScrollRatio; | |
328 | + | |
329 | + // ちゃんと最後まで移動し切るための小細工 | |
330 | + this.positionXY.X += (mx == 0 && dx != 0) ? Math.Sign( dx ) : mx; | |
331 | + this.positionXY.Y += (my == 0 && dy != 0) ? Math.Sign( dy ) : my; | |
332 | + } | |
333 | + } | |
334 | + else if( this.mode == ScrollMode.Vector ) | |
335 | + { | |
336 | + float dx = this.touchMoveXY.X - this.touchOnXY.X; | |
337 | + float dy = this.touchMoveXY.Y - this.touchOnXY.Y; | |
338 | + | |
339 | + this.positionXY.X += dx / 10.0F; | |
340 | + this.positionXY.Y += dy / 10.0F; | |
341 | + } | |
342 | + | |
343 | + if( this.zoomMode == ZoomMode.Zooming ) | |
344 | + { | |
345 | + //float ratio = 0.02F; | |
346 | + float ratio = 0.2F; | |
347 | + float ds = this.targetScale - this.scale; | |
348 | + if( Math.Abs( ds / this.targetScale ) < 0.01F && this.mode == ScrollMode.None ) | |
349 | + { | |
350 | + this.scale = this.targetScale; | |
351 | + this.StopZoom(); | |
352 | + zoomFinished = true; | |
353 | + } | |
354 | + else | |
355 | + { | |
356 | + this.scale += ds * ratio; | |
357 | + } | |
358 | + } | |
359 | + | |
360 | + FormDebug.SetItem( "Motion.positionXY", this.positionXY ); | |
361 | + FormDebug.SetItem( "Motion.scale", this.scale ); | |
362 | + | |
363 | + this.ParamUpdate( this, new ParamUpdateEventArgs { PositionXY = this.positionXY, Scale = this.scale, ZoomFinished = zoomFinished } ); | |
364 | + } | |
365 | + | |
366 | + // | |
367 | + // Private methods | |
368 | + // | |
369 | + | |
370 | + void timer_Tick( object sender, EventArgs e ) | |
371 | + { | |
372 | + this.Step(); | |
373 | + } | |
374 | + | |
375 | + void StartDragScroll( PointF touchXY ) | |
376 | + { | |
377 | + //StopZoom(); | |
378 | + //StopScroll(); | |
379 | + this.prevXY[0] = touchXY; | |
380 | + this.prevXY[1] = touchXY; | |
381 | + this.touchOnXY = touchXY; | |
382 | + this.touchMoveXY = touchXY; | |
383 | + this.touchOnPositionXY = this.positionXY; | |
384 | + this.mode = ScrollMode.Drag; | |
385 | + StartTimer(); | |
386 | + } | |
387 | + | |
388 | + void StartVectorScroll( PointF touchXY ) | |
389 | + { | |
390 | + this.touchOnXY = touchXY; | |
391 | + this.touchMoveXY = touchXY; | |
392 | + this.mode = ScrollMode.Vector; | |
393 | + StartTimer(); | |
394 | + } | |
395 | + | |
396 | + void StartFlickScroll( float speed, float direction ) | |
397 | + { | |
398 | + this.scrollSpeed = speed; | |
399 | + this.scrollDirection = direction; | |
400 | + this.mode = ScrollMode.Flick; | |
401 | + this.StartTimer(); | |
402 | + } | |
403 | + | |
404 | + void StartPointScroll( PointF targetXY ) | |
405 | + { | |
406 | + this.targetXY = targetXY; | |
407 | + this.mode = ScrollMode.Point; | |
408 | + this.StartTimer(); | |
409 | + } | |
410 | + | |
411 | + //void EndScroll() | |
412 | + //{ | |
413 | + // // 目標値を反映してから停止 | |
414 | + // if( this.mode == ScrollMode.Point ) | |
415 | + // { | |
416 | + // this.PositionXY = this.targetXY; | |
417 | + // } | |
418 | + // this.StopScroll(); | |
419 | + //} | |
420 | + | |
421 | + void StopScroll() | |
422 | + { | |
423 | + this.mode = ScrollMode.None; | |
424 | + StopTimer(); | |
425 | + | |
426 | + this.ParamUpdate( this, new ParamUpdateEventArgs { PositionXY = this.positionXY, Scale = this.scale } ); | |
427 | + } | |
428 | + | |
429 | + void MoveDragScroll( PointF xy ) | |
430 | + { | |
431 | + if( this.mode == ScrollMode.Drag ) | |
432 | + { | |
433 | + this.positionXY.X = this.touchOnPositionXY.X - (xy.X - this.touchOnXY.X) / this.scale; | |
434 | + this.positionXY.Y = this.touchOnPositionXY.Y - (xy.Y - this.touchOnXY.Y) / this.scale; | |
435 | + | |
436 | + this.prevXY[1] = this.prevXY[0]; | |
437 | + this.prevXY[0] = xy; | |
438 | + | |
439 | + FormDebug.SetItem( "Motion.positionXY", this.positionXY ); | |
440 | + | |
441 | + ParamUpdate( this, new ParamUpdateEventArgs { PositionXY = this.positionXY, Scale = this.scale } ); | |
442 | + } | |
443 | + } | |
444 | + | |
445 | + bool GetFlickScrollParam( out float speed, out float direction ) | |
446 | + { | |
447 | + speed = 0.0F; | |
448 | + direction = 0.0F; | |
449 | + | |
450 | + if( this.mode != ScrollMode.Drag ) | |
451 | + { | |
452 | + return false; | |
453 | + } | |
454 | + | |
455 | + float dx = this.prevXY[1].X - this.prevXY[0].X; | |
456 | + float dy = this.prevXY[1].Y - this.prevXY[0].Y; | |
457 | + float dist = (float)Math.Sqrt( dx * dx + dy * dy ); | |
458 | + if( dist < 3.0F ) | |
459 | + { | |
460 | + return false; | |
461 | + } | |
462 | + | |
463 | + speed = dist * 3.0F; | |
464 | + direction = (float)Math.Atan2( (double)dy, (double)dx ); | |
465 | + | |
466 | + return true; | |
467 | + } | |
468 | + | |
469 | + void StartZoom( float targetScale ) | |
470 | + { | |
471 | + this.targetScale = targetScale; | |
472 | + this.zoomMode = ZoomMode.Zooming; | |
473 | + this.StartTimer(); | |
474 | + } | |
475 | + void StopZoom() | |
476 | + { | |
477 | + this.zoomMode = ZoomMode.None; | |
478 | + this.StopTimer(); | |
479 | + } | |
480 | + void EndZoom() | |
481 | + { | |
482 | + // 目標値を反映してから停止 | |
483 | + if( this.zoomMode == ZoomMode.Zooming ) | |
484 | + { | |
485 | + this.scale = this.targetScale; | |
486 | + } | |
487 | + this.StopZoom(); | |
488 | + } | |
489 | + | |
490 | + void StartTimer() | |
491 | + { | |
492 | + //this.mode = mode; | |
493 | + | |
494 | + if( this.mode == ScrollMode.Flick || | |
495 | + this.mode == ScrollMode.Point || | |
496 | + this.mode == ScrollMode.Vector || | |
497 | + this.zoomMode == ZoomMode.Zooming ) | |
498 | + { | |
499 | + this.timer.Start(); | |
500 | + } | |
501 | + | |
502 | + FormDebug.SetItem( "Motion.mode", this.mode ); | |
503 | + FormDebug.SetItem( "Motion.zoomMode", this.zoomMode ); | |
504 | + } | |
505 | + void StopTimer() | |
506 | + { | |
507 | + //this.mode = ScrollMode.None; | |
508 | + if( this.mode == ScrollMode.None && | |
509 | + this.zoomMode == ZoomMode.None ) | |
510 | + { | |
511 | + this.timer.Stop(); | |
512 | + } | |
513 | + | |
514 | + FormDebug.SetItem( "Motion.mode", this.mode ); | |
515 | + FormDebug.SetItem( "Motion.zoomMode", this.zoomMode ); | |
516 | + } | |
517 | + | |
518 | + // | |
519 | + // Private fields | |
520 | + // | |
521 | + | |
522 | + PointF positionXY; | |
523 | + float scale = 1.0F; | |
524 | + PointF touchOnXY; | |
525 | + PointF touchMoveXY; | |
526 | + PointF touchOnPositionXY; | |
527 | + ScrollMode mode = ScrollMode.None; | |
528 | + ZoomMode zoomMode = ZoomMode.None; | |
529 | + float scrollSpeed; | |
530 | + float scrollDirection; | |
531 | + PointF[] prevXY = new PointF[2]; | |
532 | + PointF targetXY; | |
533 | + Timer timer = new Timer(); | |
534 | + float targetScale; | |
535 | + } | |
536 | +} |
@@ -0,0 +1,21 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Linq; | |
4 | +using System.Windows.Forms; | |
5 | + | |
6 | +namespace sqwriter | |
7 | +{ | |
8 | + static class Program | |
9 | + { | |
10 | + /// <summary> | |
11 | + /// アプリケーションのメイン エントリ ポイントです。 | |
12 | + /// </summary> | |
13 | + [STAThread] | |
14 | + static void Main() | |
15 | + { | |
16 | + Application.EnableVisualStyles(); | |
17 | + Application.SetCompatibleTextRenderingDefault( false ); | |
18 | + Application.Run( new FormMain() ); | |
19 | + } | |
20 | + } | |
21 | +} |
@@ -0,0 +1,66 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Linq; | |
4 | +using System.Text; | |
5 | +using System.Configuration; | |
6 | +using System.Xml.Serialization; | |
7 | +using System.IO; | |
8 | + | |
9 | +namespace sqwriter | |
10 | +{ | |
11 | + public class Setting | |
12 | + { | |
13 | + public struct RecentFile | |
14 | + { | |
15 | + public string FileName; | |
16 | + public DateTime Time; | |
17 | + } | |
18 | + | |
19 | + [System.Xml.Serialization.XmlIgnore] | |
20 | + public string Path { get; set; } | |
21 | + | |
22 | + public string RecentDirectory { get; set; } | |
23 | + public List<RecentFile> RecentFileList { get; set; } | |
24 | + | |
25 | + public static Setting Load( string path ) | |
26 | + { | |
27 | + Setting setting = null; | |
28 | + try | |
29 | + { | |
30 | + using( var fs = new FileStream( "sqwriter.config", FileMode.Open ) ) | |
31 | + { | |
32 | + var xs = new XmlSerializer( typeof( Setting ) ); | |
33 | + setting = (Setting)xs.Deserialize( fs ); | |
34 | + } | |
35 | + } | |
36 | + catch( FileNotFoundException ) | |
37 | + { | |
38 | + } | |
39 | + | |
40 | + if( setting == null ) | |
41 | + { | |
42 | + setting = new Setting(); | |
43 | + setting.RecentDirectory = Directory.GetCurrentDirectory(); | |
44 | + } | |
45 | + | |
46 | + setting.Path = path; | |
47 | + | |
48 | + return setting; | |
49 | + } | |
50 | + | |
51 | + public void Save() | |
52 | + { | |
53 | + try | |
54 | + { | |
55 | + using( var fs = new FileStream( "sqwriter.config", FileMode.Create ) ) | |
56 | + { | |
57 | + var xs = new XmlSerializer( typeof( Setting ) ); | |
58 | + xs.Serialize( fs, this ); | |
59 | + } | |
60 | + } | |
61 | + catch( Exception ) | |
62 | + { | |
63 | + } | |
64 | + } | |
65 | + } | |
66 | +} |
@@ -0,0 +1,148 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Drawing; | |
4 | +using System.Drawing.Drawing2D; | |
5 | +using System.Windows.Forms; | |
6 | +using System.IO; | |
7 | +using System.Text.RegularExpressions; | |
8 | + | |
9 | +namespace sqwriter | |
10 | +{ | |
11 | + static class Util | |
12 | + { | |
13 | + public static string[] GetFilesInDirectory(string directoryPath, string regexPattern, string excludeRegexPattern = null, bool recursive = false) | |
14 | + { | |
15 | + var filePaths = new List<string>(); | |
16 | + var option = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; | |
17 | + foreach (string path in Directory.GetFiles(directoryPath, "*", option)) | |
18 | + { | |
19 | + string name = Path.GetFileName(path); | |
20 | + bool exclude = false; | |
21 | + if (excludeRegexPattern != null) | |
22 | + { | |
23 | + exclude = Regex.IsMatch(name, excludeRegexPattern, RegexOptions.IgnoreCase); | |
24 | + } | |
25 | + if (!exclude && Regex.IsMatch(name, regexPattern, RegexOptions.IgnoreCase)) | |
26 | + { | |
27 | + filePaths.Add(path); | |
28 | + } | |
29 | + } | |
30 | + return filePaths.ToArray(); | |
31 | + } | |
32 | + | |
33 | + public static string[] GetDirectoriesInDirectory(string directoryPath, string regexPattern, string excludeRegexPattern = null) | |
34 | + { | |
35 | + var directoryPaths = new List<string>(); | |
36 | + foreach (string path in Directory.GetDirectories(directoryPath)) | |
37 | + { | |
38 | + string name = Path.GetFileName(path); | |
39 | + bool exclude = false; | |
40 | + if (excludeRegexPattern != null) | |
41 | + { | |
42 | + exclude = Regex.IsMatch(name, excludeRegexPattern, RegexOptions.IgnoreCase); | |
43 | + } | |
44 | + if (!exclude && Regex.IsMatch(name, regexPattern, RegexOptions.IgnoreCase)) | |
45 | + { | |
46 | + directoryPaths.Add(path); | |
47 | + } | |
48 | + } | |
49 | + return directoryPaths.ToArray(); | |
50 | + } | |
51 | + | |
52 | + public static void TraverseControls(Control control, Action<Control> action) | |
53 | + { | |
54 | + foreach (Control c in control.Controls) | |
55 | + { | |
56 | + TraverseControls(c, action); | |
57 | + } | |
58 | + action(control); | |
59 | + } | |
60 | + | |
61 | + public static string GetVersionString(int fieldCount = 4) | |
62 | + { | |
63 | + return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(fieldCount); | |
64 | + } | |
65 | + | |
66 | + public static string GetApplicationName() | |
67 | + { | |
68 | + return System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; | |
69 | + } | |
70 | + | |
71 | + public static string GetCopyrightString() | |
72 | + { | |
73 | + // 参考:http://dobon.net/vb/dotnet/file/myversioninfo.html | |
74 | + return ((System.Reflection.AssemblyCopyrightAttribute)Attribute.GetCustomAttribute( | |
75 | + System.Reflection.Assembly.GetExecutingAssembly(), | |
76 | + typeof(System.Reflection.AssemblyCopyrightAttribute))).Copyright; | |
77 | + } | |
78 | + | |
79 | + public static double GetDistance(System.Drawing.Point point1, System.Drawing.Point point2) | |
80 | + { | |
81 | + return Math.Sqrt(Math.Pow(point2.X - point1.X, 2.0) + Math.Pow(point2.Y - point1.Y, 2.0)); | |
82 | + } | |
83 | + | |
84 | + public static void WriteLog(Exception ex) | |
85 | + { | |
86 | + using (var writer = new StreamWriter(Util.GetApplicationName() + ".log", true)) | |
87 | + { | |
88 | + writer.WriteLine("[{0}]", DateTime.Now.ToString()); | |
89 | + // 恥ずかしいので例外文字列に含まれてるビルド環境のパスをファイル名だけに置き換える | |
90 | + var match = Regex.Match(ex.ToString(), @"場所 (\w:\\.+):"); | |
91 | + if (match.Groups.Count > 1) | |
92 | + { | |
93 | + string path = match.Groups[1].Value; | |
94 | + string name = Path.GetFileName(path); | |
95 | + writer.WriteLine(ex.ToString().Replace(path, name)); | |
96 | + } | |
97 | + else | |
98 | + { | |
99 | + writer.WriteLine(ex.GetType().ToString() + ": " + ex.Message); | |
100 | + } | |
101 | + writer.WriteLine(); | |
102 | + } | |
103 | + } | |
104 | + public static RectangleF TransformRectangle( Matrix matrix, RectangleF rect ) | |
105 | + { | |
106 | + PointF[] points = new PointF[] { | |
107 | + new PointF( rect.Left, rect.Top ), | |
108 | + new PointF( rect.Right, rect.Bottom ), | |
109 | + }; | |
110 | + | |
111 | + matrix.TransformPoints( points ); | |
112 | + | |
113 | + return new RectangleF( | |
114 | + points[0].X, | |
115 | + points[0].Y, | |
116 | + (points[1].X - points[0].X), | |
117 | + (points[1].Y - points[0].Y) ); | |
118 | + } | |
119 | + public static Rectangle ToRectangle( RectangleF rect ) | |
120 | + { | |
121 | + return new Rectangle( (int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height ); | |
122 | + } | |
123 | + public static int Clamp( int value, int min, int max ) | |
124 | + { | |
125 | + if( value < min ) | |
126 | + { | |
127 | + return min; | |
128 | + } | |
129 | + if( value > max ) | |
130 | + { | |
131 | + return max; | |
132 | + } | |
133 | + return value; | |
134 | + } | |
135 | + public static float Clamp( float value, float min, float max ) | |
136 | + { | |
137 | + if( value < min ) | |
138 | + { | |
139 | + return min; | |
140 | + } | |
141 | + if( value > max ) | |
142 | + { | |
143 | + return max; | |
144 | + } | |
145 | + return value; | |
146 | + } | |
147 | + } | |
148 | +} |
@@ -0,0 +1,202 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Linq; | |
4 | +using System.Text; | |
5 | +using System.Windows.Forms; | |
6 | +using System.Drawing; | |
7 | +using System.Reflection; | |
8 | +using System.Diagnostics; | |
9 | + | |
10 | +namespace sqwriter | |
11 | +{ | |
12 | + // バックバッファ付きパネル | |
13 | + public class ViewPanel : Panel | |
14 | + { | |
15 | + public delegate void ViewDrawEventHandler( ViewPanel sender, DrawEventArgs e ); | |
16 | + | |
17 | + public class DrawEventArgs : EventArgs | |
18 | + { | |
19 | + public Graphics Graphics; | |
20 | + | |
21 | + /// <summary> | |
22 | + /// 基準点座標[world] | |
23 | + /// </summary> | |
24 | + public PointF PositionXY; | |
25 | + | |
26 | + /// <summary> | |
27 | + /// バッファ左上から基準点までのオフセット[pixel] | |
28 | + /// </summary> | |
29 | + public Point PositionOffsetXY; | |
30 | + | |
31 | + /// <summary> | |
32 | + /// バッファ幅高さ[pixel] | |
33 | + /// </summary> | |
34 | + public Size ViewWH; | |
35 | + | |
36 | + /// <summary> | |
37 | + /// 表示範囲[world] | |
38 | + /// </summary> | |
39 | + public RectangleF DisplayedArea; | |
40 | + | |
41 | + /// <summary> | |
42 | + /// ズーム倍率(1.0=100%) | |
43 | + /// </summary> | |
44 | + public float ViewScale; | |
45 | + } | |
46 | + | |
47 | + // | |
48 | + // Events | |
49 | + // | |
50 | + | |
51 | + public event ViewDrawEventHandler Draw; | |
52 | + | |
53 | + // | |
54 | + // Public properties | |
55 | + // | |
56 | + | |
57 | + // 基準点座標[world] | |
58 | + public PointF PositionXY | |
59 | + { | |
60 | + get { return this.positionXY; } | |
61 | + set | |
62 | + { | |
63 | + this.positionXY = value; | |
64 | + this.UpdateDisplayedArea(); | |
65 | + FormDebug.SetItem( "ViewPanel.positionXY", this.positionXY ); | |
66 | + } | |
67 | + } | |
68 | + | |
69 | + // ズーム倍率 | |
70 | + public float ViewScale | |
71 | + { | |
72 | + get { return this.viewScale; } | |
73 | + set { this.viewScale = value; this.UpdateDisplayedArea(); } | |
74 | + } | |
75 | + | |
76 | + // ビューポート左上からの基準点までのオフセット[pixel] | |
77 | + public Point PositionOffsetXY | |
78 | + { | |
79 | + get { return this.positionOffsetXY; } | |
80 | + set | |
81 | + { | |
82 | + this.positionOffsetXY = value; | |
83 | + this.UpdateDisplayedArea(); | |
84 | + FormDebug.SetItem( "ViewPanel.positionOffsetXY", this.positionOffsetXY ); | |
85 | + } | |
86 | + } | |
87 | + | |
88 | + // ビューポート幅高さ[Pixel] | |
89 | + public Size ViewportWH | |
90 | + { | |
91 | + get { return this.viewportWH; } | |
92 | + set | |
93 | + { | |
94 | + this.viewportWH = value; | |
95 | + this.UpdateDisplayedArea(); | |
96 | + FormDebug.SetItem( "ViewPanel.viewportWH", this.viewportWH ); | |
97 | + } | |
98 | + } | |
99 | + | |
100 | + // 表示範囲[world] | |
101 | + public RectangleF VisibleArea { get; private set; } | |
102 | + | |
103 | + // | |
104 | + // Public methods | |
105 | + // | |
106 | + | |
107 | + public ViewPanel() | |
108 | + { | |
109 | + this.ClientSizeChanged += new EventHandler( ViewPanel_ClientSizeChanged ); | |
110 | + this.Paint += new PaintEventHandler( ViewPanel_Paint ); | |
111 | + | |
112 | + this.ViewScale = 1.0F; | |
113 | + this.ViewportWH = this.ClientSize; | |
114 | + this.PositionXY = new PointF( 0.0F, 0.0F ); | |
115 | + this.PositionOffsetXY = new Point( 0, 0 ); | |
116 | + | |
117 | + this.DoubleBuffered = true; | |
118 | + } | |
119 | + | |
120 | + public PointF ScreenToWorld( Point xy ) | |
121 | + { | |
122 | + return new PointF( | |
123 | + this.positionXY.X + (xy.X - this.positionOffsetXY.X) / this.viewScale, | |
124 | + this.positionXY.Y + (xy.Y - this.positionOffsetXY.Y) / this.viewScale ); | |
125 | + } | |
126 | + | |
127 | + // | |
128 | + // Protected methods | |
129 | + // | |
130 | + | |
131 | + protected override void OnPaintBackground( PaintEventArgs e ) | |
132 | + { | |
133 | + //base.OnPaintBackground(e); | |
134 | + } | |
135 | + | |
136 | + // | |
137 | + // Private fields | |
138 | + // | |
139 | + | |
140 | + // 基準点座標[world] | |
141 | + PointF positionXY; | |
142 | + | |
143 | + // ズーム倍率 | |
144 | + float viewScale; | |
145 | + | |
146 | + // ビューポート左上からの基準点までのオフセット[pixel] | |
147 | + Point positionOffsetXY; | |
148 | + | |
149 | + Size viewportWH; | |
150 | + | |
151 | + // | |
152 | + // Private methods | |
153 | + // | |
154 | + | |
155 | + void UpdateDisplayedArea() | |
156 | + { | |
157 | + this.VisibleArea = new RectangleF( | |
158 | + this.positionXY.X - (this.positionOffsetXY.X / this.viewScale), | |
159 | + this.positionXY.Y - (this.positionOffsetXY.Y / this.viewScale), | |
160 | + this.viewportWH.Width / this.viewScale, | |
161 | + this.viewportWH.Height / this.viewScale ); | |
162 | + | |
163 | + var sb = new StringBuilder(); | |
164 | + sb.AppendFormat( "l={0:0}, t={1:0}, r={2:0}, b={3:0}", this.VisibleArea.Left, this.VisibleArea.Top, this.VisibleArea.Right, this.VisibleArea.Bottom ); | |
165 | + FormDebug.SetItem( "ViewPanel.DisplayedArea", "{" + sb.ToString() + "}" ); | |
166 | + } | |
167 | + | |
168 | + void ViewPanel_ClientSizeChanged( object sender, EventArgs e ) | |
169 | + { | |
170 | + this.ViewportWH = this.ClientSize; | |
171 | + | |
172 | + this.Invalidate(); | |
173 | + } | |
174 | + | |
175 | + void ViewPanel_Paint( object sender, PaintEventArgs e ) | |
176 | + { | |
177 | + if( this.Draw != null ) | |
178 | + { | |
179 | + this.Draw( | |
180 | + this, | |
181 | + new DrawEventArgs { | |
182 | + Graphics = e.Graphics, | |
183 | + PositionXY = this.PositionXY, | |
184 | + PositionOffsetXY = this.positionOffsetXY, | |
185 | + ViewWH = this.viewportWH, | |
186 | + DisplayedArea = this.VisibleArea, | |
187 | + ViewScale = this.ViewScale | |
188 | + } ); | |
189 | + } | |
190 | + } | |
191 | + | |
192 | + public override bool PreProcessMessage( ref Message msg ) | |
193 | + { | |
194 | + if( msg.Msg == 0x0100/*WM_KEYDOWN*/ ) | |
195 | + { | |
196 | + // 矢印キーで他コントロールにフォーカスが移動しないよう止める | |
197 | + return true; | |
198 | + } | |
199 | + return base.PreProcessMessage( ref msg ); | |
200 | + } | |
201 | + } | |
202 | +} |