-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathMainWindow.Menu.vb
More file actions
executable file
·1072 lines (873 loc) · 43.5 KB
/
Copy pathMainWindow.Menu.vb
File metadata and controls
executable file
·1072 lines (873 loc) · 43.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
' MainWindow.Menu.vb - Menu system implementation with GTK#3 compliant menu items
Imports Gtk
Imports System
Imports SimpleIDE.Utilities
Imports SimpleIDE.Editors
Imports SimpleIDE.Widgets
Imports SimpleIDE.Models
Imports SimpleIDE.Interfaces
Partial Public Class MainWindow
' Menu references for dynamic updates
Private pThemeMenu As Menu
Private pThemeRadioGroup As RadioMenuItem
Private pProjectExplorerMenuItem As CheckMenuItem
Private pBottomPanelMenuItem As CheckMenuItem
Private pFullScreenMenuItem As CheckMenuItem
Private pDebugConfigMenuItem As RadioMenuItem
Private pReleaseConfigMenuItem As RadioMenuItem
''' <summary>
''' True while SyncViewMenuCheckbox is itself assigning a CheckMenuItem's Active
''' property - guards the Toggled handlers below against re-entering their own toggle
''' logic when that assignment raises Toggled again
''' </summary>
Private pSyncingViewMenuCheckbox As Boolean = False
''' <summary>
''' Brings a View-menu CheckMenuItem's Active state back in line with reality after
''' its underlying state changed through a path other than clicking the checkbox
''' itself (a keyboard shortcut, Escape, etc.) - without this, the checkbox silently
''' goes stale, and clicking a stale checkbox then toggles from the wrong assumed
''' state, which can leave it showing the exact opposite of the truth
''' </summary>
''' <param name="vCheckItem">The checkbox to sync, or Nothing if not yet created</param>
''' <param name="vDesiredState">The real, current state it should reflect</param>
Private Sub SyncViewMenuCheckbox(vCheckItem As CheckMenuItem, vDesiredState As Boolean)
If vCheckItem Is Nothing OrElse vCheckItem.Active = vDesiredState Then Return
Try
pSyncingViewMenuCheckbox = True
vCheckItem.Active = vDesiredState
Finally
pSyncingViewMenuCheckbox = False
End Try
End Sub
' Edit/File menu items whose Sensitive state UpdateMenuStates keeps in sync with the
' current editor/tab context - previously local Dim variables inside CreateFileMenu/
' CreateEditMenu, promoted to fields so UpdateMenuStates (a no-op before this) can
' actually reach them
Private pSaveMenuItem As MenuItem
Private pSaveAllMenuItem As MenuItem
Private pCloseMenuItem As MenuItem
Private pCloseAllMenuItem As MenuItem
Private pUndoMenuItem As MenuItem
Private pRedoMenuItem As MenuItem
Private pCutMenuItem As MenuItem
Private pCopyMenuItem As MenuItem
' ===== Menu Creation =====
Private Sub CreateMenuBar()
Try
pMenuBar = New MenuBar()
' File menu
CreateFileMenu()
' Edit menu
CreateEditMenu()
' View menu
CreateViewMenu()
' Project menu
CreateProjectMenu()
' Build menu
CreateBuildMenu()
' Git menu
CreateGitMenu()
' AI menu
CreateAIMenu()
' Help menu
CreateHelpMenu()
Catch ex As Exception
Console.WriteLine($"CreateMenuBar error: {ex.Message}")
End Try
End Sub
' Helper method to create a menu item with icon
Private Function CreateMenuItemWithIcon(vLabel As String, vIconName As String) As MenuItem
Try
Dim lMenuItem As New MenuItem()
' Create box to hold icon and label
Dim lBox As New Box(Orientation.Horizontal, 6)
' Create icon - request the symbolic variant so every menu icon renders as a
' consistent, theme-colored monochrome glyph. Without this, several names
' (application-exit, system-run, media-playback-start, process-stop,
' help-browser, help-about) resolve to their full-color regular icon at
' IconSize.Menu instead, which visually clashes against the rest of the
' (correctly monochrome) menu - that inconsistency is what actually looked
' "broken". Falls back to the plain name if a theme lacks the symbolic variant.
Dim lIcon As New Image()
Dim lSymbolicName As String = vIconName & "-symbolic"
If IconTheme.Default.HasIcon(lSymbolicName) Then
lIcon.SetFromIconName(lSymbolicName, IconSize.Menu)
Else
lIcon.SetFromIconName(vIconName, IconSize.Menu)
End If
' Create label with mnemonic support
Dim lLabel As New Label(vLabel)
lLabel.UseUnderline = True
lLabel.Xalign = 0.0F
' Pack widgets
lBox.PackStart(lIcon, False, False, 0)
lBox.PackStart(lLabel, True, True, 0)
' Add box to menu item
lMenuItem.Add(lBox)
lMenuItem.ShowAll()
Return lMenuItem
Catch ex As Exception
Console.WriteLine($"CreateMenuItemWithIcon error: {ex.Message}")
Return New MenuItem(vLabel)
End Try
End Function
Private Sub CreateFileMenu()
Try
Dim lFileMenu As New Menu()
Dim lFileMenuItem As New MenuItem("_File")
lFileMenuItem.Submenu = lFileMenu
pMenuBar.Append(lFileMenuItem)
' New Project
Dim lNewProject As MenuItem = CreateMenuItemWithIcon("New _Project...", "document-new")
AddHandler lNewProject.Activated, AddressOf OnNewProject
lFileMenu.Append(lNewProject)
' Open Project
Dim lOpenProject As MenuItem = CreateMenuItemWithIcon("_Open project...", "document-open")
AddHandler lOpenProject.Activated, AddressOf OnOpenProject
lFileMenu.Append(lOpenProject)
' Open Solution
Dim lOpenSolution As MenuItem = CreateMenuItemWithIcon("Open _Solution...", "document-open")
AddHandler lOpenSolution.Activated, AddressOf OnOpenSolution
lFileMenu.Append(lOpenSolution)
' Recent Projects submenu
Dim lRecentProjects As New MenuItem("_Recent Projects")
Dim lRecentMenu As New Menu()
lRecentProjects.Submenu = lRecentMenu
UpdateRecentProjectsMenu(lRecentMenu)
lFileMenu.Append(lRecentProjects)
lFileMenu.Append(New SeparatorMenuItem())
' New File
Dim lNewFile As MenuItem = CreateMenuItemWithIcon("New _File...", "document-new")
AddHandler lNewFile.Activated, AddressOf OnNewFile
lFileMenu.Append(lNewFile)
' Open File
Dim lOpenFile As MenuItem = CreateMenuItemWithIcon("Open F_ile...", "document-open")
AddHandler lOpenFile.Activated, AddressOf OnOpenFile
lFileMenu.Append(lOpenFile)
lFileMenu.Append(New SeparatorMenuItem())
' Save
pSaveMenuItem = CreateMenuItemWithIcon("_Save", "document-save")
AddHandler pSaveMenuItem.Activated, AddressOf OnSave
lFileMenu.Append(pSaveMenuItem)
' Save As
Dim lSaveAs As MenuItem = CreateMenuItemWithIcon("Save _As...", "document-save-as")
AddHandler lSaveAs.Activated, AddressOf OnSaveAs
lFileMenu.Append(lSaveAs)
' Save All
pSaveAllMenuItem = New MenuItem("Save A_ll")
AddHandler pSaveAllMenuItem.Activated, AddressOf OnSaveAll
lFileMenu.Append(pSaveAllMenuItem)
' Revert to Saved
AddRevertToSavedMenuItem(lFileMenu)
lFileMenu.Append(New SeparatorMenuItem())
' Close File
pCloseMenuItem = New MenuItem("_Close")
AddHandler pCloseMenuItem.Activated, AddressOf OnCloseFile
lFileMenu.Append(pCloseMenuItem)
' Close All
pCloseAllMenuItem = New MenuItem("Close _All")
AddHandler pCloseAllMenuItem.Activated, AddressOf OnCloseAll
lFileMenu.Append(pCloseAllMenuItem)
lFileMenu.Append(New SeparatorMenuItem())
' Exit
Dim lExit As MenuItem = CreateMenuItemWithIcon("E_xit", "application-exit")
AddHandler lExit.Activated, AddressOf OnQuit
lFileMenu.Append(lExit)
Catch ex As Exception
Console.WriteLine($"CreateFileMenu error: {ex.Message}")
End Try
End Sub
Private Sub CreateEditMenu()
Try
Dim lEditMenu As New Menu()
Dim lEditMenuItem As New MenuItem("_Edit")
lEditMenuItem.Submenu = lEditMenu
pMenuBar.Append(lEditMenuItem)
' Undo
pUndoMenuItem = CreateMenuItemWithIcon("_Undo", "edit-undo")
AddHandler pUndoMenuItem.Activated, AddressOf OnUndo
lEditMenu.Append(pUndoMenuItem)
' Redo
pRedoMenuItem = CreateMenuItemWithIcon("_Redo", "edit-redo")
AddHandler pRedoMenuItem.Activated, AddressOf OnRedo
lEditMenu.Append(pRedoMenuItem)
lEditMenu.Append(New SeparatorMenuItem())
' Cut
pCutMenuItem = CreateMenuItemWithIcon("Cu_t", "edit-cut")
AddHandler pCutMenuItem.Activated, AddressOf OnCut
lEditMenu.Append(pCutMenuItem)
' Copy
pCopyMenuItem = CreateMenuItemWithIcon("_Copy", "edit-copy")
AddHandler pCopyMenuItem.Activated, AddressOf OnCopy
lEditMenu.Append(pCopyMenuItem)
' Paste
Dim lPaste As MenuItem = CreateMenuItemWithIcon("_Paste", "edit-paste")
AddHandler lPaste.Activated, AddressOf OnPaste
lEditMenu.Append(lPaste)
lEditMenu.Append(New SeparatorMenuItem())
' Select All
Dim lSelectAll As New MenuItem("Select _All")
AddHandler lSelectAll.Activated, AddressOf OnSelectAll
lEditMenu.Append(lSelectAll)
lEditMenu.Append(New SeparatorMenuItem())
' Find
Dim lFind As MenuItem = CreateMenuItemWithIcon("_Find...", "edit-find")
AddHandler lFind.Activated, AddressOf ShowFindPanel
lEditMenu.Append(lFind)
' Replace
Dim lReplace As MenuItem = CreateMenuItemWithIcon("R_eplace...", "edit-find-replace")
AddHandler lReplace.Activated, AddressOf OnReplace
lEditMenu.Append(lReplace)
lEditMenu.Append(New SeparatorMenuItem())
' Go to Line
Dim lGoToLine As New MenuItem("_Go to Line...")
AddHandler lGoToLine.Activated, AddressOf OnGoToLine
lEditMenu.Append(lGoToLine)
lEditMenu.Append(New SeparatorMenuItem())
' Indent
Dim lIndent As New MenuItem("_Indent")
AddHandler lIndent.Activated, AddressOf OnIndent
lEditMenu.Append(lIndent)
' Outdent
Dim lOutdent As New MenuItem("_Outdent")
AddHandler lOutdent.Activated, AddressOf OnOutdent
lEditMenu.Append(lOutdent)
' Format Document
Dim lFormatDoc As New MenuItem("Format _Document")
AddHandler lFormatDoc.Activated, AddressOf OnFormatDocument
lEditMenu.Append(lFormatDoc)
lEditMenu.Append(New SeparatorMenuItem())
' Preferences
Dim lPreferences As MenuItem = CreateMenuItemWithIcon("Pre_ferences...", "preferences-system")
AddHandler lPreferences.Activated, AddressOf OnEditPreferences
lEditMenu.Append(lPreferences)
Catch ex As Exception
Console.WriteLine($"CreateEditMenu error: {ex.Message}")
End Try
End Sub
''' <summary>
''' Keeps Undo/Redo/Save/Save All/Cut/Copy/Close/Close All's Sensitive state in sync
''' with the current editor/tab context - previously a complete no-op, called once at
''' startup and never again. Mirrors UpdateToolbarButtons' own signals (CanUndo/CanRedo/
''' HasSelection/Modified are already exposed by IEditor/TabInfo, nothing new to build)
''' rather than inventing new detection logic. Paste is deliberately left alone -
''' reliable cross-platform clipboard-content detection isn't cheaply available here,
''' so it stays unconditionally enabled as it always has been.
''' </summary>
Private Sub UpdateMenuStates()
Try
Dim lCurrentTab As TabInfo = GetCurrentTabInfo()
Dim lCurrentEditor As IEditor = GetCurrentEditor()
Dim lHasOpenTabs As Boolean = pOpenTabs.Count > 0
Dim lAnyModified As Boolean = False
for each lTab in pOpenTabs.Values
If lTab.Modified Then
lAnyModified = True
Exit for
End If
Next
If pSaveMenuItem IsNot Nothing Then pSaveMenuItem.Sensitive = lCurrentTab IsNot Nothing AndAlso lCurrentTab.Modified
If pSaveAllMenuItem IsNot Nothing Then pSaveAllMenuItem.Sensitive = lAnyModified
If pCloseMenuItem IsNot Nothing Then pCloseMenuItem.Sensitive = lHasOpenTabs
If pCloseAllMenuItem IsNot Nothing Then pCloseAllMenuItem.Sensitive = lHasOpenTabs
If pUndoMenuItem IsNot Nothing Then pUndoMenuItem.Sensitive = lCurrentEditor IsNot Nothing AndAlso lCurrentEditor.CanUndo
If pRedoMenuItem IsNot Nothing Then pRedoMenuItem.Sensitive = lCurrentEditor IsNot Nothing AndAlso lCurrentEditor.CanRedo
If pCutMenuItem IsNot Nothing Then pCutMenuItem.Sensitive = lCurrentEditor IsNot Nothing AndAlso lCurrentEditor.HasSelection
If pCopyMenuItem IsNot Nothing Then pCopyMenuItem.Sensitive = lCurrentEditor IsNot Nothing AndAlso lCurrentEditor.HasSelection
Catch ex As Exception
Console.WriteLine($"UpdateMenuStates error: {ex.Message}")
End Try
End Sub
Private Sub CreateViewMenu()
Try
Dim lViewMenu As New Menu()
Dim lViewMenuItem As New MenuItem("_View")
lViewMenuItem.Submenu = lViewMenu
pMenuBar.Append(lViewMenuItem)
' Project Explorer
Dim lProjectExp As New CheckMenuItem("_Project Explorer")
lProjectExp.Active = pLeftPanelVisible
AddHandler lProjectExp.Toggled, AddressOf OnToggleProjectExplorer
lViewMenu.Append(lProjectExp)
pProjectExplorerMenuItem = lProjectExp
' Bottom Panel - single toggle for the whole dock (Output/Errors/Warnings, TODO,
' AI Assistant, Git, Console, etc.) rather than one checkbox per tab. Which tab
' shows is picked via the panel's own tab strip once it's visible.
Dim lBottomPanel As New CheckMenuItem("_Bottom Panel")
lBottomPanel.Active = pBottomPanelVisible
AddHandler lBottomPanel.Toggled, AddressOf OnToggleBottomPanel
lViewMenu.Append(lBottomPanel)
pBottomPanelMenuItem = lBottomPanel
AddScratchpadMenuItem(lViewMenu)
lViewMenu.Append(New SeparatorMenuItem())
' Toolbar submenu
Dim lToolbar As New MenuItem("_Toolbar")
Dim lToolbarMenu As New Menu()
lToolbar.Submenu = lToolbarMenu
lViewMenu.Append(lToolbar)
' Show/Hide Toolbar
Dim lShowToolbar As New CheckMenuItem("_Show Toolbar")
lShowToolbar.Active = pSettingsManager.ShowToolbar
AddHandler lShowToolbar.Toggled, AddressOf OnToggleToolbar
lToolbarMenu.Append(lShowToolbar)
lToolbarMenu.Append(New SeparatorMenuItem())
' Show Labels
Dim lShowLabels As New CheckMenuItem("Show _Labels")
lShowLabels.Active = pSettingsManager.ToolbarShowLabels
AddHandler lShowLabels.Toggled, AddressOf OnToggleToolbarLabels
lToolbarMenu.Append(lShowLabels)
' Button Size submenu
Dim lButtonSize As New MenuItem("Button _Size")
Dim lButtonSizeMenu As New Menu()
lButtonSize.Submenu = lButtonSizeMenu
lToolbarMenu.Append(lButtonSize)
' Large buttons radio
Dim lLargeButtons As New RadioMenuItem("_Large")
lLargeButtons.Active = pSettingsManager.ToolbarLargeIcons
AddHandler lLargeButtons.Toggled, AddressOf OnToolbarLargeButtons
lButtonSizeMenu.Append(lLargeButtons)
' Small buttons radio (use same group as large)
Dim lSmallButtons As New RadioMenuItem(lLargeButtons, "_Small")
lSmallButtons.Active = Not pSettingsManager.ToolbarLargeIcons
AddHandler lSmallButtons.Toggled, AddressOf OnToolbarSmallButtons
lButtonSizeMenu.Append(lSmallButtons)
lViewMenu.Append(New SeparatorMenuItem())
' Full Screen
Dim lFullScreen As New CheckMenuItem("_Full Screen")
lFullScreen.Active = pIsFullScreen
AddHandler lFullScreen.Toggled, AddressOf OnToggleFullScreen
lViewMenu.Append(lFullScreen)
pFullScreenMenuItem = lFullScreen
lViewMenu.Append(New SeparatorMenuItem())
' Theme submenu
Dim lTheme As New MenuItem("T_hemes")
pThemeMenu = New Menu()
lTheme.Submenu = pThemeMenu
UpdateThemeMenu()
lViewMenu.Append(lTheme)
lViewMenu.Append(New SeparatorMenuItem())
' Zoom In
Dim lZoomIn As MenuItem = CreateMenuItemWithIcon("Zoom _In", "zoom-in")
AddHandler lZoomIn.Activated, AddressOf OnZoomIn
lViewMenu.Append(lZoomIn)
' Zoom Out
Dim lZoomOut As MenuItem = CreateMenuItemWithIcon("Zoom _Out", "zoom-out")
AddHandler lZoomOut.Activated, AddressOf OnZoomOut
lViewMenu.Append(lZoomOut)
' Reset Zoom
Dim lZoomReset As New MenuItem("_Reset Zoom")
AddHandler lZoomReset.Activated, AddressOf OnZoomReset
lViewMenu.Append(lZoomReset)
Catch ex As Exception
Console.WriteLine($"CreateViewMenu error: {ex.Message}")
End Try
End Sub
Private Sub CreateProjectMenu()
Try
Dim lProjectMenu As New Menu()
Dim lProjectMenuItem As New MenuItem("_Project")
lProjectMenuItem.Submenu = lProjectMenu
pMenuBar.Append(lProjectMenuItem)
' References
Dim lAddReference As New MenuItem("_References...")
AddHandler lAddReference.Activated, Sub() OnManageReferences(Nothing, Nothing, 0)
lProjectMenu.Append(lAddReference)
' Add Existing Item
Dim lAddExisting As New MenuItem("Add _Existing Item...")
AddHandler lAddExisting.Activated, AddressOf OnAddExistingItem
lProjectMenu.Append(lAddExisting)
' Add New Item
Dim lAddNew As New MenuItem("Add _New Item...")
AddHandler lAddNew.Activated, AddressOf OnAddNewItem
lProjectMenu.Append(lAddNew)
lProjectMenu.Append(New SeparatorMenuItem())
' Project Properties
Dim lProperties As New MenuItem("_Properties...")
AddHandler lProperties.Activated, AddressOf OnProjectProperties
lProjectMenu.Append(lProperties)
Catch ex As Exception
Console.WriteLine($"CreateProjectMenu error: {ex.Message}")
End Try
End Sub
''' <summary>
''' Creates the Build menu with proper F5/F6 accelerator labels
''' </summary>
Private Sub CreateBuildMenu()
Try
Dim lBuildMenu As New Menu()
Dim lBuildMenuItem As New MenuItem("_Build")
lBuildMenuItem.Submenu = lBuildMenu
pMenuBar.Append(lBuildMenuItem)
' Build Project (F6)
Dim lBuild As MenuItem = CreateMenuItemWithIcon("_Build Project", "system-run")
lBuild.UseUnderline = True
' Add F6 label to show the shortcut
lBuild.Label = "_Build Project" & vbTab & "F6"
AddHandler lBuild.Activated, AddressOf OnBuildProject
lBuildMenu.Append(lBuild)
' Build and Run (F5)
Dim lBuildRun As MenuItem = CreateMenuItemWithIcon("Build and _Run", "media-playback-start")
lBuildRun.UseUnderline = True
' Add F5 label to show the shortcut
lBuildRun.Label = "Build and _Run" & vbTab & "F5"
AddHandler lBuildRun.Activated, AddressOf OnBuildAndRun
lBuildMenu.Append(lBuildRun)
' Rebuild Project
Dim lRebuild As New MenuItem("_Rebuild Project")
AddHandler lRebuild.Activated, AddressOf OnRebuildProject
lBuildMenu.Append(lRebuild)
' Build Solution (Ctrl+Shift+B) - builds every project in the loaded .sln in
' dependency order; falls back to a plain project build when no solution is open
Dim lBuildSolution As MenuItem = CreateMenuItemWithIcon("Build _Solution", "system-run")
lBuildSolution.UseUnderline = True
lBuildSolution.Label = "Build _Solution" & vbTab & "Ctrl+Shift+B"
AddHandler lBuildSolution.Activated, AddressOf OnBuildSolution
lBuildMenu.Append(lBuildSolution)
' Clean Project
Dim lClean As New MenuItem("_Clean Project")
AddHandler lClean.Activated, AddressOf OnCleanProject
lBuildMenu.Append(lClean)
lBuildMenu.Append(New SeparatorMenuItem())
' Run Without Building (Ctrl+F5)
Dim lRun As MenuItem = CreateMenuItemWithIcon("R_un Without Building", "media-playback-start")
lRun.UseUnderline = True
lRun.Label = "R_un Without Building" & vbTab & "Ctrl+F5"
AddHandler lRun.Activated, AddressOf OnRunWithoutBuilding
lBuildMenu.Append(lRun)
' Stop (Shift+F5)
Dim lStop As MenuItem = CreateMenuItemWithIcon("_Stop", "process-stop")
lStop.UseUnderline = True
lStop.Label = "_Stop" & vbTab & "Shift+F5"
AddHandler lStop.Activated, AddressOf OnStopDebugging
lBuildMenu.Append(lStop)
lBuildMenu.Append(New SeparatorMenuItem())
' Configuration submenu
Dim lConfig As New MenuItem("C_onfiguration")
Dim lConfigMenu As New Menu()
lConfig.Submenu = lConfigMenu
Dim lDebugConfig As New RadioMenuItem("_Debug")
AddHandler lDebugConfig.Toggled, Sub()
If lDebugConfig.Active Then
OnConfigurationChanged("Debug")
End If
End Sub
lConfigMenu.Append(lDebugConfig)
pDebugConfigMenuItem = lDebugConfig
Dim lReleaseConfig As New RadioMenuItem(lDebugConfig.Group, "_Release")
AddHandler lReleaseConfig.Toggled, Sub()
If lReleaseConfig.Active Then
OnConfigurationChanged("Release")
End If
End Sub
lConfigMenu.Append(lReleaseConfig)
pReleaseConfigMenuItem = lReleaseConfig
' Reflect whatever configuration was already loaded (InitializeBuildSystem runs
' well before CreateMenuBar) rather than always defaulting to Debug - otherwise
' a project persisted with Release configuration shows "Debug" checked here, and
' clicking it does nothing (a RadioMenuItem doesn't fire Toggled for the item
' it believes is already active)
lReleaseConfig.Active = pBuildConfiguration IsNot Nothing AndAlso
String.Equals(pBuildConfiguration.Configuration, "Release", StringComparison.OrdinalIgnoreCase)
lDebugConfig.Active = Not lReleaseConfig.Active
lBuildMenu.Append(lConfig)
' Build Configuration Dialog
lBuildMenu.Append(New SeparatorMenuItem())
Dim lBuildConfig As New MenuItem("Build _Settings...")
AddHandler lBuildConfig.Activated, AddressOf OnBuildConfiguration
lBuildMenu.Append(lBuildConfig)
Catch ex As Exception
Console.WriteLine($"CreateBuildMenu error: {ex.Message}")
End Try
End Sub
' Add: SimpleIDE.MainWindow.OnBuildConfiguration
''' <summary>
''' Shows the build configuration dialog
''' </summary>
Private Sub OnBuildConfiguration(vSender As Object, vArgs As EventArgs)
ConfigureBuild()
End Sub
' Add: SimpleIDE.MainWindow.OnRunWithoutBuilding
''' <summary>
''' Runs the project without building (Ctrl+F5)
''' </summary>
Private Sub OnRunWithoutBuilding(vSender As Object, vArgs As EventArgs)
Task.Run(Async Function()
Await RunProject()
Return Nothing
End Function)
End Sub
''' <summary>
''' Handles build configuration change (Debug/Release)
''' </summary>
Private Sub OnConfigurationChanged(vConfiguration As String)
Try
If pBuildConfiguration IsNot Nothing Then
pBuildConfiguration.Configuration = vConfiguration
SaveBuildConfiguration()
UpdateStatusBar($"Build configuration: {vConfiguration}")
End If
Catch ex As Exception
Console.WriteLine($"OnConfigurationChanged error: {ex.Message}")
End Try
End Sub
Private Sub CreateGitMenu()
Try
Dim lGitMenu As New Menu()
Dim lGitMenuItem As New MenuItem("_Git")
lGitMenuItem.Submenu = lGitMenu
pMenuBar.Append(lGitMenuItem)
' Initialize Repository
Dim lInitRepo As New MenuItem("_Initialize Repository")
AddHandler lInitRepo.Activated, AddressOf GitInitRepository
lGitMenu.Append(lInitRepo)
lGitMenu.Append(New SeparatorMenuItem())
' Changes
Dim lChanges As New MenuItem("View _Changes")
AddHandler lChanges.Activated, AddressOf ShowGitStatus
lGitMenu.Append(lChanges)
' Commit
Dim lCommit As New MenuItem("_Commit...")
AddHandler lCommit.Activated, AddressOf OnGitCommit
lGitMenu.Append(lCommit)
' Push
Dim lPush As New MenuItem("_Push")
AddHandler lPush.Activated, AddressOf OnGitPush
lGitMenu.Append(lPush)
' Pull
Dim lPull As New MenuItem("P_ull")
AddHandler lPull.Activated, AddressOf OnGitPull
lGitMenu.Append(lPull)
lGitMenu.Append(New SeparatorMenuItem())
' Branch
Dim lBranch As New MenuItem("_Branch")
AddHandler lBranch.Activated, AddressOf ShowGitBranchDialog
lGitMenu.Append(lBranch)
' History
Dim lHistory As New MenuItem("_History")
AddHandler lHistory.Activated, AddressOf ShowGitHistory
lGitMenu.Append(lHistory)
lGitMenu.Append(New SeparatorMenuItem())
' Settings
Dim lSettings As New MenuItem("_Settings...")
AddHandler lSettings.Activated, AddressOf ShowGitSettings
lGitMenu.Append(lSettings)
Catch ex As Exception
Console.WriteLine($"CreateGitMenu error: {ex.Message}")
End Try
End Sub
Private Sub CreateAIMenu()
Try
Dim lAIMenu As New Menu()
Dim lAIMenuItem As New MenuItem("A_I")
lAIMenuItem.Submenu = lAIMenu
pMenuBar.Append(lAIMenuItem)
' Update Project Knowledge
Dim lUpdateKnowledge As New MenuItem("_Update project Knowledge")
AddHandler lUpdateKnowledge.Activated, AddressOf OnUpdateProjectKnowledge
lAIMenu.Append(lUpdateKnowledge)
lAIMenu.Append(New SeparatorMenuItem())
' Ask AI Assistant
Dim lAskAI As New MenuItem("_Ask AI Assistant...")
AddHandler lAskAI.Activated, AddressOf OnAskAIAssistant
lAIMenu.Append(lAskAI)
' Explain Code
Dim lExplainCode As New MenuItem("_Explain Selected code")
AddHandler lExplainCode.Activated, AddressOf OnExplainCode
lAIMenu.Append(lExplainCode)
' Fix Build Errors
Dim lFixErrors As New MenuItem("_Fix Build Errors")
AddHandler lFixErrors.Activated, AddressOf OnFixBuildErrors
lAIMenu.Append(lFixErrors)
' Generate Code
Dim lGenerateCode As New MenuItem("_Generate code...")
AddHandler lGenerateCode.Activated, AddressOf OnGenerateCode
lAIMenu.Append(lGenerateCode)
lAIMenu.Append(New SeparatorMenuItem())
' AI Settings
Dim lAISettings As New MenuItem("AI _Settings...")
AddHandler lAISettings.Activated, AddressOf OnAISettings
lAIMenu.Append(lAISettings)
Catch ex As Exception
Console.WriteLine($"CreateAIMenu error: {ex.Message}")
End Try
End Sub
Private Sub CreateHelpMenu()
Try
Dim lHelpMenu As New Menu()
Dim lHelpMenuItem As New MenuItem("_Help")
lHelpMenuItem.Submenu = lHelpMenu
pMenuBar.Append(lHelpMenuItem)
' View Help
Dim lViewHelp As MenuItem = CreateMenuItemWithIcon("_View Help", "help-browser")
AddHandler lViewHelp.Activated, AddressOf OnViewHelp
lHelpMenu.Append(lViewHelp)
' API Documentation
Dim lApiDocs As New MenuItem("_API documentation")
AddHandler lApiDocs.Activated, AddressOf OnApiDocumentation
lHelpMenu.Append(lApiDocs)
lHelpMenu.Append(New SeparatorMenuItem())
' GTK# Help submenu
Dim lGtkHelp As New MenuItem("GTK# _Help")
Dim lGtkHelpMenu As New Menu()
lGtkHelp.Submenu = lGtkHelpMenu
PopulateGtkHelpMenu(lGtkHelpMenu)
lHelpMenu.Append(lGtkHelp)
' .NET Help submenu
Dim lDotNetHelp As New MenuItem(".NET _Documentation")
Dim lDotNetHelpMenu As New Menu()
lDotNetHelp.Submenu = lDotNetHelpMenu
PopulateDotNetHelpMenu(lDotNetHelpMenu)
lHelpMenu.Append(lDotNetHelp)
' Install Desktop Integration (Linux taskbar/Alt-Tab icon fix)
Dim lDesktopIntegration As New MenuItem("Install Desktop _Integration")
AddHandler lDesktopIntegration.Activated, AddressOf OnInstallDesktopIntegration
lHelpMenu.Append(lDesktopIntegration)
lHelpMenu.Append(New SeparatorMenuItem())
' About
Dim lAbout As MenuItem = CreateMenuItemWithIcon("_About SimpleIDE", "help-about")
AddHandler lAbout.Activated, AddressOf OnAbout
lHelpMenu.Append(lAbout)
Catch ex As Exception
Console.WriteLine($"CreateHelpMenu error: {ex.Message}")
End Try
End Sub
' ===== Helper Methods =====
Private Sub UpdateRecentProjectsMenu(vMenu As Menu)
Try
' Clear existing items
for each lChild in vMenu.Children
vMenu.Remove(lChild)
Next
' Get recent projects from settings
Dim lRecentProjects As List(Of String) = pSettingsManager.GetRecentProjects()
If lRecentProjects.Count = 0 Then
Dim lNoRecent As New MenuItem("(No recent projects)")
lNoRecent.Sensitive = False
vMenu.Append(lNoRecent)
Else
for i As Integer = 0 To lRecentProjects.Count - 1
Dim lProject As String = lRecentProjects(i)
Dim lMenuItem As New MenuItem($"{i + 1}. {System.IO.Path.GetFileName(lProject)}")
lMenuItem.TooltipText = lProject
AddHandler lMenuItem.Activated, Sub() LoadProjectEnhanced(lProject)
vMenu.Append(lMenuItem)
Next
End If
vMenu.ShowAll()
Catch ex As Exception
Console.WriteLine($"UpdateRecentProjectsMenu error: {ex.Message}")
End Try
End Sub
' Update theme menu with all available themes
Private Sub UpdateThemeMenu()
Try
If pThemeMenu Is Nothing Then Return
' Clear existing items
for each lChild in pThemeMenu.Children
pThemeMenu.Remove(lChild)
Next
' Get current theme
Dim lCurrentTheme As String = pThemeManager.GetCurrentTheme()
' Add all available themes as radio menu items
pThemeRadioGroup = Nothing
for each lThemeName in pThemeManager.GetAvailableThemes()
Dim lThemeItem As RadioMenuItem
If pThemeRadioGroup Is Nothing Then
lThemeItem = New RadioMenuItem(lThemeName)
pThemeRadioGroup = lThemeItem
Else
lThemeItem = New RadioMenuItem(pThemeRadioGroup.Group, lThemeName)
End If
' Set active if current theme
If lThemeName = lCurrentTheme Then
lThemeItem.Active = True
End If
' Add handler - capture theme name in closure
Dim lCapturedThemeName As String = lThemeName
AddHandler lThemeItem.Toggled, Sub()
If lThemeItem.Active Then
ApplyTheme(lCapturedThemeName)
End If
End Sub
pThemeMenu.Append(lThemeItem)
Next
pThemeMenu.Append(New SeparatorMenuItem())
' Theme Editor menu item
Dim lThemeEditor As New MenuItem("Theme _Editor...")
AddHandler lThemeEditor.Activated, AddressOf OnThemeEditor
pThemeMenu.Append(lThemeEditor)
pThemeMenu.ShowAll()
' Subscribe to theme list changes - RemoveHandler first since UpdateThemeMenu is
' called repeatedly over the window's lifetime (MainWindow.Menu.vb:400, Theme.vb:331,
' and OnThemeListChanged itself below). Without this, each call stacked another
' subscription on top of the last, so OnThemeListChanged's own call back into
' UpdateThemeMenu caused the handler count to compound with every theme-list change -
' 1 firing became 2, 2 became 4, trending toward a UI freeze after just a few edits
' in the Theme Editor
RemoveHandler pThemeManager.ThemeListChanged, AddressOf OnThemeListChanged
AddHandler pThemeManager.ThemeListChanged, AddressOf OnThemeListChanged
Catch ex As Exception
Console.WriteLine($"UpdateThemeMenu error: {ex.Message}")
End Try
End Sub
' Handler for theme list changes
Private Sub OnThemeListChanged()
Try
' Update the theme menu when themes are added/removed
UpdateThemeMenu()
Catch ex As Exception
Console.WriteLine($"OnThemeListChanged error: {ex.Message}")
End Try
End Sub
' Open theme editor
Private Sub OnThemeEditor(vSender As Object, vArgs As EventArgs)
Try
' Show theme editor in a new tab
ShowThemeEditor()
Catch ex As Exception
Console.WriteLine($"OnThemeEditor error: {ex.Message}")
End Try
End Sub
Private Sub PopulateGtkHelpMenu(vMenu As Menu)
Try
Dim lLinks As New Dictionary(Of String, String) From {
{"GTK# documentation", "https://docs.gtk.org/gtk3/"},
{"Widget Gallery", "https://docs.gtk.org/gtk3/gallery.html"},
{"GTK# on GitHub", "https://github.com/GtkSharp/GtkSharp"},
{"GTK# API Reference", "https://docs.gtk.org/gtk3/"}
}
for each kvp in lLinks
Dim lMenuItem As New MenuItem(kvp.key)
Dim lUrl As String = kvp.Value
AddHandler lMenuItem.Activated, Sub() OpenUrl(lUrl)
vMenu.Append(lMenuItem)
Next
Catch ex As Exception
Console.WriteLine($"PopulateGtkHelpMenu error: {ex.Message}")
End Try
End Sub
Private Sub PopulateDotNetHelpMenu(vMenu As Menu)
Try
Dim lLinks As New Dictionary(Of String, String) From {
{"VB.NET documentation", "https://docs.microsoft.com/en-us/dotnet/visual-basic/"},
{".NET API Browser", "https://docs.microsoft.com/en-us/dotnet/api/"},
{"VB.NET Language Reference", "https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/"},
{"VB.NET Programming Guide", "https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/"}
}
for each kvp in lLinks
Dim lMenuItem As New MenuItem(kvp.key)
Dim lUrl As String = kvp.Value
AddHandler lMenuItem.Activated, Sub() OpenUrl(lUrl)
vMenu.Append(lMenuItem)
Next
Catch ex As Exception
Console.WriteLine($"PopulateDotNetHelpMenu error: {ex.Message}")
End Try
End Sub
' Apply theme by name (overload for menu usage)
Private Sub ApplyTheme(vThemeName As String)
Try
UpdateStatusBar("Applying Theme " + vThemeName)
pThemeManager.SetTheme(vThemeName)
' Update all open editors
for each lTabInfo in pOpenTabs.Values
If lTabInfo.Editor IsNot Nothing Then
Dim lEditor As CustomDrawingEditor = TryCast(lTabInfo.Editor, CustomDrawingEditor)
If lEditor IsNot Nothing Then
lEditor.ApplyTheme()
End If
End If
Next
Catch ex As Exception
Console.WriteLine($"ApplyTheme(String) error: {ex.Message}")
End Try
End Sub
''' <summary>
''' Handles the Revert to Saved menu action
''' </summary>
Private Sub OnRevertToSaved(vSender As Object, vArgs As EventArgs)
Try
' Get current tab
Dim lCurrentTab As TabInfo = GetCurrentTabInfo()
If lCurrentTab Is Nothing OrElse lCurrentTab.Editor Is Nothing Then
ShowInfo("Revert to Saved", "No file is currently open.")
Return
End If
' Check if file has a saved version
If String.IsNullOrEmpty(lCurrentTab.FilePath) OrElse lCurrentTab.FilePath.StartsWith("Untitled") Then
ShowInfo("Revert to Saved", "This file has never been saved.")
Return
End If
' Check if file exists on disk
If Not System.IO.File.Exists(lCurrentTab.FilePath) Then
ShowError("Revert to Saved", "The file no longer exists on disk.")
Return
End If
' Check if there are actually changes to revert
If Not lCurrentTab.Modified Then
ShowInfo("Revert to Saved", "No changes to revert.")
Return
End If
' Confirm with user
Dim lResponse As ResponseType = ShowCustomButtonDialog(