diff --git a/Doc/ProjectTree.md b/Doc/ProjectTree.md index 2adc8b4..b54b3db 100644 --- a/Doc/ProjectTree.md +++ b/Doc/ProjectTree.md @@ -26,5 +26,67 @@ Right-click a scxml file to display the context menu commands. ![](../Images/ProjectTree_UnitMenu.png) +## Post Save Unit Actions +It is available to execute post save cmd script after the scxml unit file was saved + +> NOTE: This option is available only in project mode! + +1. Select a unit in Project Tree +2. Call **`Edit Post Save`** menu item + +![](../Images/PostSaveUnit.png) + +3. Edit post save script + +![](../Images/PostSaveUnit_Macro.png) + +### Post Save Unit Commands +Commands that could be executed by state machine chart editor + +**Format:** + +```batch +$(AppFilePath) command [Unit HWND] [Command] [Arg1|Arg2|Arg3] +``` + +**Example:** + +```batch +$(AppFilePath) command $(UnitHandle) SaveToSVG $(UnitFileDir)\$(UnitName).svg +``` + +| Command | Arguments | Description | +|---|---|---| +| SaveToSVG | Arg1=FileName | Saves state chart to SVG | +| SaveRawScxmlToFile | Arg1=FileName | Saves state chart to scxml without comments and metainformation | +| SaveRawScxmlToHPP | Arg1=FileName | Saves state chart to scxml without comments and metainformation as C++ Header | +| SaveScxmlToPas | Arg1=FileName | Saves state chart to DFM file | +| SaveToDot | Arg1=FileName | Saves state chart to Graphviz DOT file | +| SaveToDotPlusPng | Arg1=FileName | Saves state chart to Graphviz DOT and PNG files | +| SaveToBMP | Arg1=FileName | Saves state chart to BMP file | +| SaveToPNG | Arg1=FileName | Saves state chart to PNG file | + +### Post Save Application Commands +Commands that could be executed by ScxmlEditor application + +**Format:** + +```batch +$(AppFilePath) command [App HWND] [Command] [Arg1|Arg2|Arg3] +``` + +**Example:** + +```batch +$(AppFilePath) command $(AppHandle) SwitchLog Debug True +``` + +| Command | Arguments | Description | +|---|---|---| +| SwitchLog | Arg1=Debug| Switches Log tab to Debug output | +| | Arg1=CMD | Switches Log tab to CMD output | +| | Arg2=True,False (Bool) | Clear output or not | + + | [TOP](#top-anchor) | [Contents](../README.md#table-of-contents) | [SCXML Wiki](https://alexzhornyak.github.io/SCXML-tutorial/) | [Forum](https://github.com/alexzhornyak/ScxmlEditor-Tutorial/discussions) | |---|---|---|---| diff --git a/Doc/Transitions.md b/Doc/Transitions.md index 503d167..de7b2f4 100644 --- a/Doc/Transitions.md +++ b/Doc/Transitions.md @@ -48,6 +48,17 @@ Multiple self transitions may be quickly arranged by pressing **'Arrange Self-co ![Transitions_Self_Arrange](../Images/Transitions_Self_Arrange.gif) +### Self Transitions Inside States +It is available since ScxmlEditor 2.4 to arrange self transitions inside of state. + +![tr_inside](../Images/Transition_Self_Inside.png) + +1. Set option **`SelfConnectionInside`** to **`true`** in the property inspector +2. Execute **`Arrange Self-Connections`** command from IDE Insight or right popup menu +3. (Optionally) Align Self-Transition to left, top, right or bottom side of the state + +![tr_align](../Images/Transition_Self_Align.gif) + ## Delayed transition A delayed transition is a transition that happens after a period of time, specifically being in a specific state for a certain amount of time. diff --git a/Images/PostSaveUnit.png b/Images/PostSaveUnit.png new file mode 100644 index 0000000..ea7e8f5 Binary files /dev/null and b/Images/PostSaveUnit.png differ diff --git a/Images/PostSaveUnit_Macro.png b/Images/PostSaveUnit_Macro.png new file mode 100644 index 0000000..5cdeb8a Binary files /dev/null and b/Images/PostSaveUnit_Macro.png differ diff --git a/Images/Transition_Self_Align.gif b/Images/Transition_Self_Align.gif new file mode 100644 index 0000000..8be03e1 Binary files /dev/null and b/Images/Transition_Self_Align.gif differ diff --git a/Images/Transition_Self_Inside.png b/Images/Transition_Self_Inside.png new file mode 100644 index 0000000..c515a14 Binary files /dev/null and b/Images/Transition_Self_Inside.png differ diff --git a/README.md b/README.md index df0a9a6..3f28599 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ **[Video overview - v.2.2](https://youtu.be/30dyXAs-m1A)** -# Scxml Editor 2.3 +# Scxml Editor 2.4 Powerful tool for creating, editing and debugging SCXML charts. ![MainExample](Images/Inheritance_TV_example.gif) @@ -24,18 +24,19 @@ Powerful tool for creating, editing and debugging SCXML charts. [![Discord](Images/Discord.svg)](https://discord.gg/5XWDsbEXzn) ### Changelog +**2.4:** [Post Save Commands](Doc/ProjectTree.md#post-save-unit-actions), [Self-Transitions Inside](Doc/Transitions.md#self-transitions-inside-states)
**2.3:** Highlight Transitions
-**2.2.4:** [Import QtCreator state charts](Doc/ImportStateCharts.md)
-**2.2.3:** [Transition indexes bugfix](https://github.com/alexzhornyak/ScxmlEditor-Tutorial/issues/66)
-**2.2.2:** [Option to override SmartTransitions](Doc/SmartSwitchTransitions.md#option-to-override-inverted-condition-since-scxmleditor-222)
-**2.2.1:** [Qt SVG Monitors Released](https://github.com/alexzhornyak/QtScxmlMonitor/blob/main/README.md)
-**2.2:** [Invoke ID is sending by testing apps](Doc/DebugScxmlStateCharts.md#how-to-debug-multiple-invoked-state-machines)
-**2.1.10:** [New breakpoints interface](Doc/DebugScxmlStateCharts.md#breakpoints)
-**2.1.9:** [Better handling of virtual states](Doc/VisualStateChartSplitting.md#adding-onentry-onexit-datamodel-and-invoke-to-virtual-states)
-**2.1.8:** [Support of custom console testing applications](Doc/DebugScxmlStateCharts.md#custom-testing-application-setup) like [SCION command-line tool](https://gitlab.com/scion-scxml/cli)
-**2.1.7:** [SVG Export Settings](Doc/ExportScxmlToSVG.md#svg-export-settings)
-**2.1.6:** UScxmlTester with EcmaScript, In() predicate autocomplete, QtScxmlTester 5.9.1->5.15
-**2.1.5:** [Refactored Qt external debugger](https://github.com/alexzhornyak/QtScxmlMonitor/blob/main/README.md#qt-scxml-external-debugging-monitor)
+**2.2.4:** [Import QtCreator state charts](Doc/ImportStateCharts.md)
+**2.2.3:** [Transition indexes bugfix](https://github.com/alexzhornyak/ScxmlEditor-Tutorial/issues/66)
+**2.2.2:** [Option to override SmartTransitions](Doc/SmartSwitchTransitions.md#option-to-override-inverted-condition-since-scxmleditor-222)
+**2.2.1:** [Qt SVG Monitors Released](https://github.com/alexzhornyak/QtScxmlMonitor/blob/main/README.md)
+**2.2:** [Invoke ID is sending by testing apps](Doc/DebugScxmlStateCharts.md#how-to-debug-multiple-invoked-state-machines)
+**2.1.10:** [New breakpoints interface](Doc/DebugScxmlStateCharts.md#breakpoints)
+**2.1.9:** [Better handling of virtual states](Doc/VisualStateChartSplitting.md#adding-onentry-onexit-datamodel-and-invoke-to-virtual-states)
+**2.1.8:** [Support of custom console testing applications](Doc/DebugScxmlStateCharts.md#custom-testing-application-setup) like [SCION command-line tool](https://gitlab.com/scion-scxml/cli)
+**2.1.7:** [SVG Export Settings](Doc/ExportScxmlToSVG.md#svg-export-settings)
+**2.1.6:** UScxmlTester with EcmaScript, In() predicate autocomplete, QtScxmlTester 5.9.1->5.15
+**2.1.5:** [Refactored Qt external debugger](https://github.com/alexzhornyak/QtScxmlMonitor/blob/main/README.md#qt-scxml-external-debugging-monitor)
**2.1.4:** [Export SCXML to SVG](Doc/ExportScxmlToSVG.md), [Structure View](Doc/ScxmlStructureView.md) ## System requirements @@ -47,15 +48,15 @@ Powerful tool for creating, editing and debugging SCXML charts. ## Installation You can find portable version as attached Zip in ScxmlEditor Github Release page -Latest version: **[2.3.1.1712]** +Latest version: **[2.4.0.1734]** ### Windows Installation #### First Install 1. Download from latest Release page and unpack it in any target location 2. Install **ScxmlEditor\vcredist_x86.exe** for **UscxmlTester**, **Graphviz** -3. Install **ScxmlEditor\vcredist_x64.exe** for **QtScxmlTester**
+3. Install **ScxmlEditor\vcredist_x64.exe** for **QtScxmlTester**
(_You may skip steps 2 and 3 if you have previously installed MSVC 2015 Update 3 redistributable_) -4. Install **ScxmlEditor\UScxmlTester\vcredist_x86_vc10.exe** for **UscxmlTester** with **EcmaScript** datamodel
+4. Install **ScxmlEditor\UScxmlTester\vcredist_x86_vc10.exe** for **UscxmlTester** with **EcmaScript** datamodel
(_You may skip step 4 if you have previously installed MSVC 2010 redistributable_) #### Update @@ -123,6 +124,7 @@ Current binaries are compiled with single development licensies registered by th - Main menu - Main toolbar - [Project tree](Doc/ProjectTree.md) + - [Post Save Unit](Doc/ProjectTree.md#post-save-unit-actions) - [Property inspector](Doc/PropertyInspector.md) - [SCXML source code view and live editing](Doc/LiveScxmlEdit.md) - Projects @@ -138,6 +140,7 @@ Current binaries are compiled with single development licensies registered by th - [Chart design panel](Doc/ChartDesignPanel.md) - States and children (Shapes) - [Transitions (Connections)](Doc/Transitions.md) + - [Self-Transitions](Doc/Transitions.md#self-transitions-connections) - [Smart Switch Transitions](Doc/SmartSwitchTransitions.md) - [Inheritance](Doc/Inheritance.md) - [DOT-based autolayout](Doc/DotBasedAutoLayout.md#dot-based-auto-layout) @@ -193,14 +196,14 @@ Press **'Ctrl+.'** to call **IDE Insight dialog** where you may search for all a ![StructureViewSearch](Images/StructureView_Search.png) ## [Debugging](Doc/DebugScxmlStateCharts.md) -**ScxmlEditor** has an ability to receive and send string UDP commands:
+**ScxmlEditor** has an ability to receive and send string UDP commands:
### Receive API: - `@@@` - clear highlighted states in all statecharts - `@@@ScxmlName` - clear highlighted states in statechart where [\](https://alexzhornyak.github.io/SCXML-tutorial/Doc/scxml.html) 'name' is equal `ScxmlName` -- `Type@ScxmlName@Msg@Id` - commands to highlight state or display message in **CallStack** panel
+- `Type@ScxmlName@Msg@Id` - commands to highlight state or display message in **CallStack** panel
**Description:** - `Type` - integer type of command: `1 - AfterEnter, 2 - BeforeEnter, 3 - AfterExit, 4 - BeforeExit, 5 - Step, 6 - BeforeExecContent, 7 - AfterExecContent, 8 - BeforeInvoke, 9 - AfterInvoke, 10 - BeforeUnInvoke, 11 - AfterUnInvoke, 12 - BeforeTakingTransition, 13 - AfterTakingTransition, 14 - StableConfiguration, 15 - BeforeProcessingEvent`
- `ScxmlName` - name of [\](https://alexzhornyak.github.io/SCXML-tutorial/Doc/scxml.html)
+ `Type` - integer type of command: `1 - AfterEnter, 2 - BeforeEnter, 3 - AfterExit, 4 - BeforeExit, 5 - Step, 6 - BeforeExecContent, 7 - AfterExecContent, 8 - BeforeInvoke, 9 - AfterInvoke, 10 - BeforeUnInvoke, 11 - AfterUnInvoke, 12 - BeforeTakingTransition, 13 - AfterTakingTransition, 14 - StableConfiguration, 15 - BeforeProcessingEvent`
+ `ScxmlName` - name of [\](https://alexzhornyak.github.io/SCXML-tutorial/Doc/scxml.html)
`Msg` - message which depends on type of command. For example: for **BeforeEnter** or **BeforeExit** - it is the id(name) of states, for **BeforeInvoke** or **BeforeUnInvoke** it is the name of invoked element, etc.
`Id` - [identifier of the invoked](https://alexzhornyak.github.io/SCXML-tutorial/Doc/invoke.html#id) state machine (Since ScxmlEditor 2.2). Can be empty for root machines > **BeforeEnter** graphically highlight and **BeforeExit** unhighlight the corresponding states, other commands are displayed in **CallStack** panel @@ -209,10 +212,10 @@ Press **'Ctrl+.'** to call **IDE Insight dialog** where you may search for all a > Message format: `FromState|TransitionIndex` where `TransitionIndex` is transition xml child index #### Example of commands: -- `2@CalculatorStateMachine@operand1` - highlight state `operand1` in statechart **CalculatorStateMachine**
-- `4@CalculatorStateMachine@operand1` - unhighlight state `operand1` in statechart **CalculatorStateMachine**
-- `2@ScxmlSub1@isSub1@ID_SUB_1` - highlight state `isSub1` in statechart **ScxmlSub1** when [invoke Id](Doc/DebugScxmlStateCharts.md#how-to-debug-multiple-invoked-state-machines) is `ID_SUB_1`
-- `12@CalculatorStateMachine@operand1|0` - highlight the first transition from **operand1** state in statechart **CalculatorStateMachine**
+- `2@CalculatorStateMachine@operand1` - highlight state `operand1` in statechart **CalculatorStateMachine**
+- `4@CalculatorStateMachine@operand1` - unhighlight state `operand1` in statechart **CalculatorStateMachine**
+- `2@ScxmlSub1@isSub1@ID_SUB_1` - highlight state `isSub1` in statechart **ScxmlSub1** when [invoke Id](Doc/DebugScxmlStateCharts.md#how-to-debug-multiple-invoked-state-machines) is `ID_SUB_1`
+- `12@CalculatorStateMachine@operand1|0` - highlight the first transition from **operand1** state in statechart **CalculatorStateMachine**
You can also [trace the execution of the chart](Doc/DebugScxmlStateCharts.md#trace-mode) and use [breakpoints](Doc/DebugScxmlStateCharts.md#breakpoints). diff --git a/Src/CommonConsts.h b/Src/CommonConsts.h index 81805a6..a3696af 100644 --- a/Src/CommonConsts.h +++ b/Src/CommonConsts.h @@ -83,4 +83,15 @@ struct TMatchFind { } }; +#define SCXML_INTERPROCESS_COMMAND L"command" +#define SCXML_INTERPROCESS_BUFFER_SIZE 4096 + +struct INTERPROCESS_COPYDATA +{ + wchar_t wchCommand[SCXML_INTERPROCESS_BUFFER_SIZE]; + wchar_t wchArg1[SCXML_INTERPROCESS_BUFFER_SIZE]; + wchar_t wchArg2[SCXML_INTERPROCESS_BUFFER_SIZE]; + wchar_t wchArg3[SCXML_INTERPROCESS_BUFFER_SIZE]; +}; + #endif diff --git a/Src/ScxmlEditor.cbproj b/Src/ScxmlEditor.cbproj index 6f76f03..7db5a84 100644 --- a/Src/ScxmlEditor.cbproj +++ b/Src/ScxmlEditor.cbproj @@ -1000,9 +1000,9 @@ IF "%_VAR_ALL_DEFINES_%" == "%_VAR_NOT_DEBUG_%" ( copy /y $(OUTPUTPATH) $(PROJEC True True 2 - 3 - 1 - 1712 + 4 + 0 + 1734 False False False @@ -1014,7 +1014,7 @@ IF "%_VAR_ALL_DEFINES_%" == "%_VAR_NOT_DEBUG_%" ( copy /y $(OUTPUTPATH) $(PROJEC alexander.zhornyak@gmail.com Scxml State Charts Editor - 2.3.1.1712 + 2.4.0.1734 alexander.zhornyak@gmail.com diff --git a/Src/ScxmlEditor.cpp b/Src/ScxmlEditor.cpp index 77e30cb..0fb2526 100644 --- a/Src/ScxmlEditor.cpp +++ b/Src/ScxmlEditor.cpp @@ -1,84 +1,132 @@ /*********************************************************************************** - BSD 3-Clause License +BSD 3-Clause License - Copyright (c) 2018, https://github.com/alexzhornyak, alexander.zhornyak@gmail.com - All rights reserved. +Copyright (c) 2018, https://github.com/alexzhornyak, alexander.zhornyak@gmail.com +All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. + * Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************************************************************************************/ +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ***************************************************************************************/ #include #pragma hdrstop #include +#include + +#include "CommonConsts.h" + //--------------------------------------------------------------------------- -USEFORM("UnitLineStringEditor.cpp", LineStringEditor); -USEFORM("UnitDialogDelayedTransition.cpp", DialogDelayedTransition); -USEFORM("UnitReplaceRefactorForm.cpp", ReplaceRefactor); -USEFORM("UnitIdeInsight.cpp", DialogInsight); -USEFORM("UnitFrameTransitionTypes.cpp", FrameTransitionTypes); /* TFrame: File Type */ +USEFORM("UnitDialogCollectOutputs.cpp", DialogCollectOutputs); +USEFORM("UnitPresetCondition.cpp", PresetCondition); +USEFORM("UnitSettingsEditor.cpp", FormSettingsEditor); +USEFORM("UnitTransitionEditor.cpp", FormTransitionEditor); +USEFORM("UnitDialogTreeSelect.cpp", DialogTreeSelect); +USEFORM("UnitSearchForm.cpp", FormSearch); +USEFORM("UnitDialogRegExp.cpp", DialogRegExp); +USEFORM("UnitDialogFileNotFound.cpp", DialogFileNotFound); +USEFORM("UnitStringPairsEditor.cpp", FormStringPairsEditor); +USEFORM("UnitSyntaxEditorForm.cpp", FormSyntaxEditorForm); +USEFORM("UnitReplaceForm.cpp", FormReplaceDlg); +USEFORM("UnitDialogSelectFromToShape.cpp", DialogSelectShape); +USEFORM("UnitFormCollectionEditor.cpp", FormCollectionEditor); +USEFORM("UnitImagePreviewer.cpp", ImagePreviewer); +USEFORM("UnitMacroComposer.cpp", MacroComposer); +USEFORM("UnitDialogFilterProperty.cpp", DialogFilterProperty); +USEFORM("UnitDialogQScxmlComiler.cpp", DialogQScxmlCompiler); +USEFORM("UnitComboStringEditor.cpp", ComboStringEditor); +USEFORM("UnitSyntaxEditor.cpp", FrameSyntaxEditor); /* TFrame: File Type */ +USEFORM("UnitDialogCollectProperty.cpp", DialogCopyProperty); +USEFORM("UnitStringsEditor.cpp", StringEditorForm); +USEFORM("UnitSimpleReplaceDialog.cpp", SimpleReplaceDialog); +USEFORM("UnitPresetOnOff.cpp", PresetOnOff); +USEFORM("UnitHotKeysHelp.cpp", FormHotKeysHelp); USEFORM("UnitDModule.cpp", DModule); /* TDataModule: File Type */ USEFORM("UnitSimpleHelp.cpp", FormSimpleHelp); USEFORM("UnitFrameSearchResults.cpp", FrameSearchResults); /* TFrame: File Type */ -USEFORM("UnitSyntaxEditorEx.cpp", FrameSyntaxEditorEx); /* TFrame: File Type */ -USEFORM("UnitFrameTrigger.cpp", FrameTrigger); /* TFrame: File Type */ -USEFORM("UnitMain.cpp", FormScxmlGui); -USEFORM("UnitFrameGifMaker.cpp", FrameGifMaker); /* TFrame: File Type */ +USEFORM("UnitLineStringEditor.cpp", LineStringEditor); +USEFORM("UnitFrameTransitionTypes.cpp", FrameTransitionTypes); /* TFrame: File Type */ +USEFORM("UnitReplaceRefactorForm.cpp", ReplaceRefactor); +USEFORM("UnitDialogDelayedTransition.cpp", DialogDelayedTransition); +USEFORM("UnitIdeInsight.cpp", DialogInsight); USEFORM("UnitDialogWait.cpp", DialogWait); USEFORM("UnitDialogRegisterScxmlUnitsAndProjects.cpp", DialogRegisterScxmlFiles); USEFORM("UnitFrameScxmlLiveEdit.cpp", FrameScxmlLiveEdit); /* TFrame: File Type */ USEFORM("UnitProtocolBindingImportForm.cpp", BindingsImporter); -USEFORM("UnitHotKeysHelp.cpp", FormHotKeysHelp); -USEFORM("UnitDialogSelectFromToShape.cpp", DialogSelectShape); -USEFORM("UnitSyntaxEditorForm.cpp", FormSyntaxEditorForm); -USEFORM("UnitReplaceForm.cpp", FormReplaceDlg); -USEFORM("UnitMacroComposer.cpp", MacroComposer); -USEFORM("UnitImagePreviewer.cpp", ImagePreviewer); -USEFORM("UnitFormCollectionEditor.cpp", FormCollectionEditor); -USEFORM("UnitPresetCondition.cpp", PresetCondition); -USEFORM("UnitDialogCollectOutputs.cpp", DialogCollectOutputs); -USEFORM("UnitDialogRegExp.cpp", DialogRegExp); -USEFORM("UnitStringPairsEditor.cpp", FormStringPairsEditor); -USEFORM("UnitDialogFileNotFound.cpp", DialogFileNotFound); -USEFORM("UnitSearchForm.cpp", FormSearch); -USEFORM("UnitSettingsEditor.cpp", FormSettingsEditor); -USEFORM("UnitTransitionEditor.cpp", FormTransitionEditor); -USEFORM("UnitDialogTreeSelect.cpp", DialogTreeSelect); -USEFORM("UnitSimpleReplaceDialog.cpp", SimpleReplaceDialog); -USEFORM("UnitStringsEditor.cpp", StringEditorForm); -USEFORM("UnitDialogCollectProperty.cpp", DialogCopyProperty); -USEFORM("UnitPresetOnOff.cpp", PresetOnOff); -USEFORM("UnitComboStringEditor.cpp", ComboStringEditor); -USEFORM("UnitDialogQScxmlComiler.cpp", DialogQScxmlCompiler); -USEFORM("UnitDialogFilterProperty.cpp", DialogFilterProperty); -USEFORM("UnitSyntaxEditor.cpp", FrameSyntaxEditor); /* TFrame: File Type */ +USEFORM("UnitSyntaxEditorEx.cpp", FrameSyntaxEditorEx); /* TFrame: File Type */ +USEFORM("UnitFrameGifMaker.cpp", FrameGifMaker); /* TFrame: File Type */ +USEFORM("UnitMain.cpp", FormScxmlGui); +USEFORM("UnitFrameTrigger.cpp", FrameTrigger); /* TFrame: File Type */ + + //--------------------------------------------------------------------------- -WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int) -{ - try - { +WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR argv, int argc) { + try { + + /* + This code is intended to use from command line + for sending commands to other active ScxmlEditors + */ + const int iArgCount = ParamCount(); + if (iArgCount >= 3) { + if (ParamStr(1) == SCXML_INTERPROCESS_COMMAND) { + const HWND hwndHandle = (HWND)ParamStr(2).ToIntDef(0); + + const UnicodeString sCommand = ParamStr(3); + + INTERPROCESS_COPYDATA ACopyData; + memset(&ACopyData, 0, sizeof(INTERPROCESS_COPYDATA)); + + wcscpy_s(ACopyData.wchCommand, SCXML_INTERPROCESS_BUFFER_SIZE, sCommand.c_str()); + + /* Optional arguments */ + if (iArgCount >= 4) { + const UnicodeString sArg1 = ParamStr(4); + wcscpy_s(ACopyData.wchArg1, SCXML_INTERPROCESS_BUFFER_SIZE, sArg1.c_str()); + } + + if (iArgCount >= 5) { + const UnicodeString sArg2 = ParamStr(5); + wcscpy_s(ACopyData.wchArg2, SCXML_INTERPROCESS_BUFFER_SIZE, sArg2.c_str()); + } + + if (iArgCount >= 6) { + const UnicodeString sArg3 = ParamStr(6); + wcscpy_s(ACopyData.wchArg3, SCXML_INTERPROCESS_BUFFER_SIZE, sArg3.c_str()); + } + + COPYDATASTRUCT MyCDS; + MyCDS.dwData = 0; // function identifier + MyCDS.cbData = sizeof(ACopyData); // size of data + MyCDS.lpData = &ACopyData; // data structure + SendMessage(hwndHandle, WM_COPYDATA, (WPARAM)0, (LPARAM)(LPVOID) & MyCDS); + + return 0; + } + } + + /* Application main thread */ Application->Initialize(); Application->MainFormOnTaskBar = true; Application->Title = "ScxmlEditor"; @@ -86,18 +134,14 @@ WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int) Application->CreateForm(__classid(TFormScxmlGui), &FormScxmlGui); Application->Run(); } - catch (Exception &exception) - { + catch(Exception & exception) { Application->ShowException(&exception); } - catch (...) - { - try - { + catch(...) { + try { throw Exception(""); } - catch (Exception &exception) - { + catch(Exception & exception) { Application->ShowException(&exception); } } diff --git a/Src/ScxmlEditor.res b/Src/ScxmlEditor.res index dd32813..da5ecee 100644 Binary files a/Src/ScxmlEditor.res and b/Src/ScxmlEditor.res differ diff --git a/Src/ScxmlEditor_resources.rc b/Src/ScxmlEditor_resources.rc index 3c1845e..e0aceaf 100644 --- a/Src/ScxmlEditor_resources.rc +++ b/Src/ScxmlEditor_resources.rc @@ -16,8 +16,8 @@ CompleteOs RCData "complete_os.lua" PngInvoke RCData "Images\\invoke_16_16.png" PngSetValue RCData "Images\\setvalue_16_16.png" PngOnEntry RCData "Images\\onenter_16_16.png" -ResCurPan Cursor "Images\\PanningCursor.cur" PngContent RCData "Images\\content_16_16.png" +ResCurPan Cursor "Images\\PanningCursor.cur" CompleteMath RCData "complete_math.lua" PngData RCData "Images\\data_16_16.png" PngAssign RCData "Images\\assign_16_16.png" @@ -29,12 +29,12 @@ PngIf RCData "Images\\if_16_16.png" PngError RCData "Images\\error_16.png" PngWatch RCData "Images\\watch_16_16.png" PngLog RCData "Images\\log_16_16.png" -PngTrigger RCData "Images\\trigger_16_16.png" -PngCancel RCData "Images\\cancel_16_16.png" CompleteString RCData "complete_string.lua" +PngCancel RCData "Images\\cancel_16_16.png" PngProtocolWeak RCData "Images\\protocol_weak_16_16.png" -PngScript RCData "Images\\script_16_16.png" ResLogProperties RCData "ScxmlEditor.properties" +PngScript RCData "Images\\script_16_16.png" +PngTrigger RCData "Images\\trigger_16_16.png" PngTransitionXML RCData "Images\\XMLText_Transition_16.png" CompleteDebug RCData "complete_debug.lua" CompletePython RCData "complete_all_python.txt" diff --git a/Src/TreeEditor/UnitTreeChildManagers.cpp b/Src/TreeEditor/UnitTreeChildManagers.cpp index bc240fc..098d945 100644 --- a/Src/TreeEditor/UnitTreeChildManagers.cpp +++ b/Src/TreeEditor/UnitTreeChildManagers.cpp @@ -196,7 +196,8 @@ int __fastcall TScxmlAlignChildEx::YPosition(TTreeNodeShape* ANode, int ABrother TChildScxmlBaseShape *AChildShape = dynamic_cast(ANode); TVisualScxmlBaseShape *AVisualParent = dynamic_cast(ANode->Parent); - if (AChildShape && AVisualParent && ABrotherIndex == 0 && AVisualParent->ChildrenAlignY == scayClusterTop) { + if (AChildShape && AVisualParent && ABrotherIndex == 0 && + (AVisualParent->ChildrenAlignY == scayClusterTop || AVisualParent->ChildrenAlignY == scayAlwaysTop)) { return AVisualParent->CalculateChildrenTop(AVisualParent->Y1) + VertMargin; } else @@ -206,7 +207,8 @@ int __fastcall TScxmlAlignChildEx::YPosition(TTreeNodeShape* ANode, int ABrother // --------------------------------------------------------------------------- int __fastcall TScxmlAlignChildEx::GetStartConnectionTopOffset(TTreeNodeShape* ANodeFrom) { TVisualScxmlBaseShape *AVisualFrom = dynamic_cast(ANodeFrom); - if (AVisualFrom && AVisualFrom->IsCluster() && AVisualFrom->ChildrenAlignY == scayClusterTop) { + if (AVisualFrom && ((AVisualFrom->IsCluster() && AVisualFrom->ChildrenAlignY == scayClusterTop) + || AVisualFrom->ChildrenAlignY == scayAlwaysTop)) { return AVisualFrom->GetClusterHeight(); } return 0; diff --git a/Src/UnitMain.cpp b/Src/UnitMain.cpp index 651609f..ace2964 100644 --- a/Src/UnitMain.cpp +++ b/Src/UnitMain.cpp @@ -562,7 +562,9 @@ FActiveEditorDockPanel(0), FBreakpointSync(false) { TransitionXMLEditor->Show(); - HTMLPropInfo->Height = SettingsData->PropInspInfoHeight; + if (SettingsData->PropInspInfoHeight > HTMLPropInfo->Constraints->MinHeight) { + HTMLPropInfo->Height = SettingsData->PropInspInfoHeight; + } PropSettingsInspector->Splitter = SettingsData->PropInspGutterWidth; Application->HintShortPause = SettingsData->HintShortPause; @@ -612,19 +614,22 @@ FActiveEditorDockPanel(0), FBreakpointSync(false) { /* CMD start 'scxml' or 'sproj' */ try { if (ParamCount() >= 1) { const UnicodeString sFileName = ParamStr(1); - if (FileExists(sFileName)) { - const UnicodeString sExt = ExtractFileExt(sFileName); - if (SameText(sExt, TStateMachineProject::FileExt_)) { - DoOpenProject(sFileName); - } - else if (SameText(sExt, TStateMachineEditorUnit::FileExt_)) { - DoOpenUnit(sFileName); + /* 'command' is the reserved name for command options */ + if (sFileName != SCXML_INTERPROCESS_COMMAND) { + if (FileExists(sFileName)) { + const UnicodeString sExt = ExtractFileExt(sFileName); + if (SameText(sExt, TStateMachineProject::FileExt_)) { + DoOpenProject(sFileName); + } + else if (SameText(sExt, TStateMachineEditorUnit::FileExt_)) { + DoOpenUnit(sFileName); + } + else + throw Exception("CMD arg ext [" + sExt + "] is not supported! File [" + sFileName + "]"); } else - throw Exception("CMD arg ext [" + sExt + "] is not supported! File [" + sFileName + "]"); + throw Exception("CMD arg file [" + sFileName + "] does not exist!"); } - else - throw Exception("CMD arg file [" + sFileName + "] does not exist!"); } } catch(Exception * E) { @@ -3110,7 +3115,7 @@ void __fastcall TFormScxmlGui::actRunExecute(TObject * Sender) { DeleteFile(sTempFile); try { - AScxmlActivePanel->SaveRawScxmlToFile(sTempFile); + AScxmlActivePanel->StateMachineEditor->SaveRawScxmlToFile(sTempFile); } catch(EStateMachineConnectionException * E) { AScxmlActivePanel->ActivateZonePage(); @@ -3837,7 +3842,7 @@ void __fastcall TFormScxmlGui::actExportToRawScxmlExecute(TObject * Sender) { if (AScxmlActivePanel) { SaveDialog->Filter = TStateMachineEditorUnit::OpenDialogFilter; if (SaveDialog->Execute(this->Handle)) { - AScxmlActivePanel->SaveRawScxmlToFile(SaveDialog->FileName); + AScxmlActivePanel->StateMachineEditor->SaveRawScxmlToFile(SaveDialog->FileName); } } } @@ -3853,7 +3858,7 @@ void __fastcall TFormScxmlGui::actExportToHPPExecute(TObject * Sender) { if (AScxmlActivePanel) { SaveDialog->Filter = L"HPP files(*.hpp)|*.hpp|All files(*.*)|*.*"; if (SaveDialog->Execute(this->Handle)) { - AScxmlActivePanel->SaveRawScxmlToHPP(SaveDialog->FileName); + AScxmlActivePanel->StateMachineEditor->SaveRawScxmlToHPP(SaveDialog->FileName); } } } @@ -4237,7 +4242,7 @@ void __fastcall TFormScxmlGui::actExportToDFMExecute(TObject * Sender) { TStateMachineEditorUnit* AUnit = GetActiveUnit(); if (AUnit && AUnit->StateMachineDockPanel) { const UnicodeString &sFilePath = AUnit->FilePath; - AUnit->StateMachineDockPanel->SaveScxmlToPas(ChangeFileExt(sFilePath, ".scxml.pas")); + AUnit->StateMachineDockPanel->StateMachineEditor->SaveScxmlToPas(ChangeFileExt(sFilePath, ".scxml.pas")); } } catch(Exception * E) { @@ -4440,8 +4445,47 @@ void __fastcall TFormScxmlGui::actExportAnsiCAccept(TObject * Sender) { LOG_ERROR(LOG_ERROR_MSG); } } + // --------------------------------------------------------------------------- +void __fastcall TFormScxmlGui::OnMsgCopyData(TWMCopyData &msg) { + if (msg.CopyDataStruct && msg.CopyDataStruct->cbData == sizeof(INTERPROCESS_COPYDATA)) { + INTERPROCESS_COPYDATA *ACopyData = reinterpret_cast(msg.CopyDataStruct->lpData); + if (ACopyData) { + WLOG_INFO(L"MAIN_FORM> Copy data command:[%s] arg1:[%s] arg2:[%s] arg3:[%s]", // + ACopyData->wchCommand, ACopyData->wchArg1, ACopyData->wchArg2, ACopyData->wchArg3); + + try { + /* Commands related to Active Editor */ + TStateMachineDockPanel* ADockPanel = ActiveEditorDockPanel; + if (ADockPanel) { + ADockPanel->StateMachineEditor->ExecuteInterprocessCommand(ACopyData); + } + + /* Commands related to Main Form */ + if (SameText(ACopyData->wchCommand, L"SwitchLog")) { + + const bool bClear = StrToBoolDef(ACopyData->wchArg2, false); + if (SameText(ACopyData->wchArg1, L"Debug")) { + this->SwitchToProgramLog(bClear); + } + else if (SameText(ACopyData->wchArg1, L"CMD")) { + this->SwitchToTesterLog(bClear); + } + } + } + catch(Exception * E) { + WLOG_ERROR(L"MAIN_FORM> %s", E->Message.c_str()); + } + + } + } + else { + WLOG_ERROR(L"Invalid WM_COPYDATA"); + } +} + +// --------------------------------------------------------------------------- void __fastcall TFormScxmlGui::OnConvertedToQt(TMessage & msg) { FConvertToQtSpawnPtr.reset(); @@ -5932,11 +5976,7 @@ void __fastcall TFormScxmlGui::actExportGraphDotAccept(TObject *Sender) { try { TStateMachineDockPanel* ADockPanel = ActiveEditorDockPanel; if (ADockPanel) { - const UnicodeString sFileDot = actExportGraphDot->Dialog->FileName; - std::auto_ptrADialogWaitPtr(new TDialogWait(this)); - ADialogWaitPtr->ShowDialog(UnicodeString().sprintf(L"Exporting to DOT[%s] ...", ExtractFileName(sFileDot).c_str())); - Graphviz::ExportToDot(ADockPanel->StateMachineEditor->TheTree, sFileDot); - WLOG_INFO(L"Successfully saved <%s>", sFileDot.c_str()); + ADockPanel->StateMachineEditor->SaveToDot(actExportGraphDot->Dialog->FileName); } } catch(Exception * E) { @@ -5949,16 +5989,7 @@ void __fastcall TFormScxmlGui::actExportGraphDotPlusPngAccept(TObject *Sender) { try { TStateMachineDockPanel* ADockPanel = ActiveEditorDockPanel; if (ADockPanel) { - const UnicodeString sFileDot = actExportGraphDotPlusPng->Dialog->FileName; - std::auto_ptrADialogWaitPtr(new TDialogWait(this)); - ADialogWaitPtr->ShowDialog(UnicodeString().sprintf(L"Exporting to DOT[%s] ...", ExtractFileName(sFileDot).c_str())); - Graphviz::ExportToDot(ADockPanel->StateMachineEditor->TheTree, sFileDot); - WLOG_INFO(L"Successfully saved <%s>", sFileDot.c_str()); - - const UnicodeString sFilePng = ChangeFileExt(sFileDot, L".png"); - ADialogWaitPtr->ShowDialog(UnicodeString().sprintf(L"Exporting to PNG[%s] ...", ExtractFileName(sFilePng).c_str())); - Graphviz::ConvertDotToPng(sFileDot, sFilePng); - WLOG_INFO(L"Successfully converted <%s> to <%s>", sFileDot.c_str(), sFilePng.c_str()); + ADockPanel->StateMachineEditor->SaveToDotPlusPng(actExportGraphDotPlusPng->Dialog->FileName); } } catch(Exception * E) { @@ -6027,7 +6058,6 @@ void __fastcall TFormScxmlGui::actExportSVGAccept(TObject *Sender) { ADockPanel->StateMachineEditor->SaveToSVG(sFile, ADockPanel->StateMachineEditor->RootScxml); - WLOG_INFO(L"Successfully saved <%s>", sFile.c_str()); } } catch(Exception * E) { diff --git a/Src/UnitMain.h b/Src/UnitMain.h index fa184d5..bd7a7c3 100644 --- a/Src/UnitMain.h +++ b/Src/UnitMain.h @@ -678,6 +678,7 @@ class TFormScxmlGui : public TForm void __fastcall OnDeleteObjects(TMessage &msg); void __fastcall OnMsgAddOrOpenExistingUnit(TMessage &msg); void __fastcall OnMsgUpdateDebugQueue(TMessage &msg); + void __fastcall OnMsgCopyData(TWMCopyData &msg); BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(WM_SCXML_STOP_DEBUGGING, TMessage, OnStopDebugging) @@ -686,6 +687,7 @@ class TFormScxmlGui : public TForm VCL_MESSAGE_HANDLER(WM_SCXML_DELETE_OBJECTS, TMessage, OnDeleteObjects) VCL_MESSAGE_HANDLER(WM_SCXML_ADD_OR_OPEN_EXISTING_UNIT, TMessage, OnMsgAddOrOpenExistingUnit) VCL_MESSAGE_HANDLER(WM_SCXML_UPDATE_DBG_MSG_QUEUE, TMessage, OnMsgUpdateDebugQueue) + VCL_MESSAGE_HANDLER(WM_COPYDATA, TWMCopyData, OnMsgCopyData) END_MESSAGE_MAP(TForm) TStateMachineEditorUnit* __fastcall GetActiveUnit(); diff --git a/Src/UnitProjectProperties.cpp b/Src/UnitProjectProperties.cpp index e7ad77e..011b83c 100644 --- a/Src/UnitProjectProperties.cpp +++ b/Src/UnitProjectProperties.cpp @@ -69,6 +69,8 @@ UnicodeString __fastcall TProjectPostBuild::GetMacros(void)const { AMacrosPtr->Values["$(ProjectDir)"] = ExtractFileDir(FProject->FilePath); AMacrosPtr->Values["$(ProjectName)"] = TPath::GetFileNameWithoutExtension(FProject->FilePath); AMacrosPtr->Values["$(AppDir)"] = ExtractFileDir(Application->ExeName); + AMacrosPtr->Values["$(AppFilePath)"] = Application->ExeName; + AMacrosPtr->Values["$(AppHandle)"] = UnicodeString((int)Application->MainFormHandle); if (FProject && FProject->ProjectRoot) { const UnicodeString sFlatPath = ChangeFileExt(FProject->ProjectRoot->FilePath, ".flat.scxml"); diff --git a/Src/UnitSVGExporter.cpp b/Src/UnitSVGExporter.cpp index 7d284a4..0fcb087 100644 --- a/Src/UnitSVGExporter.cpp +++ b/Src/UnitSVGExporter.cpp @@ -1,34 +1,34 @@ /*********************************************************************************** - BSD 3-Clause License - - Copyright (c) 2018, https://github.com/alexzhornyak - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************************************************************************************/ +BSD 3-Clause License + +Copyright (c) 2018, https://github.com/alexzhornyak +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + + * Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ***************************************************************************************/ #include #pragma hdrstop @@ -40,6 +40,7 @@ #include "Log4cpp_VCL.hpp" #include +#include /* https://github.com/TurboPack/PNGComponents */ /* Mozilla Public License 1.1 (MPL 1.1) */ @@ -63,18 +64,21 @@ class TTeePanelAccess : public TCustomTeePanel { //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- __fastcall TTreeSVGCanvasEx::TTreeSVGCanvasEx(const UnicodeString sUnitName, Classes::TStrings* AStrings) : TTreeSVGCanvas(AStrings), -UnitName(sUnitName) { +UnitName(sUnitName), FInitWindowRect(0, 0, 0, 0) { } //--------------------------------------------------------------------------- Types::TRect __fastcall TTreeSVGCanvasEx::InitWindow(Graphics::TCanvas* DestCanvas, Tecanvas::TView3DOptions* A3DOptions, Graphics::TColor ABackColor, bool Is3D, const Types::TRect &UserRect) { - const TRect AResultRect = TTreeSVGCanvas::InitWindow(DestCanvas, A3DOptions, ABackColor, Is3D, UserRect); + if (IsRectEmpty(&FInitWindowRect)) { + const TRect AResultRect = TTreeSVGCanvas::InitWindow(DestCanvas, A3DOptions, ABackColor, Is3D, UserRect); - Add(""); + Add(""); + FInitWindowRect = AResultRect; + } - return AResultRect; + return FInitWindowRect; } //--------------------------------------------------------------------------- @@ -238,7 +242,7 @@ void __fastcall TTreeSVGCanvasEx::StartGroup(const UnicodeString &sID, const Uni //--------------------------------------------------------------------------- void __fastcall TTreeSVGCanvasEx::EndGroup(void) { - Add(""); + Add(L""); } //--------------------------------------------------------------------------- @@ -246,6 +250,37 @@ void __fastcall TTreeSVGCanvasEx::AddDesc(const UnicodeString &sDescription) { Add(L"" + VerifySpecial(sDescription) + L""); } +//--------------------------------------------------------------------------- +void __fastcall TTreeSVGCanvasEx::DrawPolyBezier(const TCurvePoints &tmpCurve, const int tmpNum) { + if (tmpNum < 2) { + return; + } + + UnicodeString d = UnicodeString().sprintf( // + L"M %d %d", // + tmpCurve[0].x, tmpCurve[0].y); + + // central curves are cubic Bezier + int iCount = 0; + + for (int i = 1; i < tmpNum; i++) { + + if (iCount % 3 == 0) { + d = d + " C"; + } + + d = d + UnicodeString().sprintf( // + L" %d,%d", // + tmpCurve[i].x, tmpCurve[i].y); + + iCount += 1; + } + + Add(UnicodeString().sprintf( // + L"", // + d.c_str(), SVGPen().c_str())); +} + //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- diff --git a/Src/UnitSVGExporter.h b/Src/UnitSVGExporter.h index 98654b2..6298cb8 100644 --- a/Src/UnitSVGExporter.h +++ b/Src/UnitSVGExporter.h @@ -34,10 +34,13 @@ #define UnitSVGExporterH //--------------------------------------------------------------------------- +#include #include "TreeSVGCanvas.hpp" class TTreeSVGCanvasEx: public TTreeSVGCanvas { + TRect FInitWindowRect; + protected: virtual System::UnicodeString __fastcall HeaderContents(void); public: @@ -58,6 +61,8 @@ class TTreeSVGCanvasEx: public TTreeSVGCanvas virtual void __fastcall AddDesc(const UnicodeString &sDescription); + void __fastcall DrawPolyBezier(const TCurvePoints &tmpCurve, const int tmpNum); + }; extern void __fastcall SaveTreeToSvg(TCustomTeePanel *APanel, const UnicodeString &sUnitName, const TRect &ARect, TStringList *AOutputList); diff --git a/Src/UnitScxmlBaseShape.cpp b/Src/UnitScxmlBaseShape.cpp index 4f47159..12aae55 100644 --- a/Src/UnitScxmlBaseShape.cpp +++ b/Src/UnitScxmlBaseShape.cpp @@ -871,7 +871,7 @@ void __fastcall TScxmlBaseShape::PropsToAttributes(ILMDXmlElement * ANode) { bool bDoSave = true; // , , - if (!bRequiredOrDefault) { + if (!bRequiredOrDefault && !SettingsData->ForceSaveDefaultScxmlValues) { PPropInfo APropInfo = GetPropInfo(this, sAttrName); if (APropInfo) { switch((*APropInfo->PropType)->Kind) { @@ -1346,6 +1346,7 @@ FInitial(L""), FExamined(false), FSkipDebugging(false), FBreakpointSet(false) { FAvailableTypes.insert(sctWatch); FSelfConnectionTextOffsets = new TPersistentRect; + FSelfConnectionInside = false; FParentOffsetStored = new TPersistentPoint; @@ -1397,7 +1398,10 @@ void __fastcall TVisualScxmlBaseShape::OnGetPropEditorClass(TPersistent *AInstan // --------------------------------------------------------------------------- bool __fastcall TVisualScxmlBaseShape::OnFilterPropEvent(const UnicodeString & sPropName) { - if (sPropName == L"SelfConnectionTextOffsets" && !HasSelfConnections) { + std::auto_ptrASelfConnStringList(new TStringList()); + ASelfConnStringList->Add(L"SelfConnectionTextOffsets"); + ASelfConnStringList->Add(L"SelfConnectionInside"); + if (ASelfConnStringList->IndexOf(sPropName) != -1 && !HasSelfConnections) { return false; } @@ -1421,6 +1425,11 @@ bool __fastcall TVisualScxmlBaseShape::OnFilterPropEvent(const UnicodeString & s AStringList->Add("Y0"); AStringList->Add("Y1"); + if (!this->IsCluster()) { + AStringList->Add("VertTextAlign"); + } + AStringList->Add("HorizTextAlign"); + const int iIndex = AStringList->IndexOf(sPropName); const bool bShow = iIndex == -1 ? TScxmlBaseShape::OnFilterPropEvent(sPropName) : true; @@ -1482,6 +1491,22 @@ UnicodeString __fastcall TVisualScxmlBaseShape::OnGetHTMLPropertyInfo(const Unic ; } + if (sPropName == L"SelfConnectionInside") { + return L"Self-connections are distributed inside of a state\n" // + "Call 'Arrange Self-Connections' operation to see the result\n" // + ; + } + + if (sPropName == L"VertTextAlign") { + return L"Vertical text alignment\n" // + ; + } + + if (sPropName == L"HorizTextAlign") { + return L"Horizontal text alignment\n" // + ; + } + if (sPropName == L"SkipDebugging") { return // "If it is set to true, then OnEnter and OnExit actions will not be applied to this shape during Debug Session.\n" @@ -1507,6 +1532,7 @@ UnicodeString __fastcall TVisualScxmlBaseShape::OnGetHTMLPropertyInfo(const Unic return // L"scayClusterTop - children are aligned to the top corner of the shape in cluster mode\n" // "scayAlwaysBottom - children are aligned to the bottom corner of the shape\n" // + "scayAlwaysTop - children are aligned to the top corner of the shape\n" // ; } @@ -1518,6 +1544,11 @@ void __fastcall TVisualScxmlBaseShape::SetSelfConnectionTextOffsets(TPersistentR FSelfConnectionTextOffsets->Assign(val); } +// --------------------------------------------------------------------------- +void __fastcall TVisualScxmlBaseShape::SetSelfConnectionInside(bool val) { + FSelfConnectionInside = val; +} + // --------------------------------------------------------------------------- int __fastcall TVisualScxmlBaseShape::GetParentOffsetX(void) { if (this->Parent) { @@ -1670,6 +1701,7 @@ void __fastcall TVisualScxmlBaseShape::Assign(Classes::TPersistent * Source) { FChildrenAlignX = ABaseShape->FChildrenAlignX; FChildrenAlignY = ABaseShape->FChildrenAlignY; FChildrenAlignXOffset = ABaseShape->FChildrenAlignXOffset; + FSelfConnectionInside = ABaseShape->FSelfConnectionInside; SkipDebugging = ABaseShape->SkipDebugging; // Update @@ -1689,17 +1721,17 @@ void __fastcall TVisualScxmlBaseShape::Assign(Classes::TPersistent * Source) { // --------------------------------------------------------------------------- TColor __fastcall TVisualScxmlBaseShape::GetNormalColor(void) { - return TColor(0x00FFD680); + return SettingsData->ThemeSettings->StateNormalColor; } // --------------------------------------------------------------------------- TColor __fastcall TVisualScxmlBaseShape::GetHeadColor(void) { - return TColor(0x00FFD680); + return SettingsData->ThemeSettings->StateNormalColor; } // --------------------------------------------------------------------------- TColor __fastcall TVisualScxmlBaseShape::GetClusterColor(void) { - return clWhite; + return SettingsData->ThemeSettings->StateClusterColor; } // --------------------------------------------------------------------------- @@ -1719,6 +1751,11 @@ void __fastcall TVisualScxmlBaseShape::UpdateBreakpointView() { tiNone; } +// --------------------------------------------------------------------------- +TVertTextAlign __fastcall TVisualScxmlBaseShape::GetVertTextAlign(void) { + return this->IsCluster() ? Teetree::vtaTop : TScxmlBaseShape::GetVertTextAlign(); +} + // --------------------------------------------------------------------------- void __fastcall TVisualScxmlBaseShape::SetNormalAppearance(void) { const bool bIsCluster = this->IsCluster(); @@ -1729,12 +1766,6 @@ void __fastcall TVisualScxmlBaseShape::SetNormalAppearance(void) { if (this->Color != GetClusterColor()) { this->Color = GetClusterColor(); } - if (this->VertTextAlign != Teetree::vtaTop) { - this->VertTextAlign = Teetree::vtaTop; - } - if (this->Text->VertAlign != Teetree::vtaTop) { - this->Text->VertAlign = Teetree::vtaTop; - } } else { if (this->Style != GetNormalStyle()) { @@ -1743,34 +1774,28 @@ void __fastcall TVisualScxmlBaseShape::SetNormalAppearance(void) { if (this->Color != GetNormalColor()) { this->Color = GetNormalColor(); } - if (this->VertTextAlign != vtaCenter) { - this->VertTextAlign = vtaCenter; - } - if (this->Text->VertAlign != vtaCenter) { - this->Text->VertAlign = vtaCenter; - } } this->Transparent = bIsCluster && ClassType() != __classid(TScxmlShape); - if (this->Border->Style != psSolid) { - this->Border->Style = psSolid; + if (this->Border->Style != SettingsData->ThemeSettings->StateNormalBorderStyle) { + this->Border->Style = SettingsData->ThemeSettings->StateNormalBorderStyle; } if (FExamined) { this->Border->Width = 3; - this->Border->Color = clBlue; + this->Border->Color = SettingsData->ThemeSettings->StateExaminedBorderColor; } else { TColor ABorderColor = this->Border->Color; int iBorderWidth = this->Border->Width; if (GetIsInitial()) { - ABorderColor = TColor(0x000080FF); + ABorderColor = SettingsData->ThemeSettings->StateInitialBorderColor; iBorderWidth = 2; } else { - ABorderColor = clBlack; + ABorderColor = SettingsData->ThemeSettings->StateNormalBorderColor; iBorderWidth = 1; } @@ -1807,14 +1832,19 @@ void __fastcall TVisualScxmlBaseShape::SetNormalAppearance(void) { UpdateBreakpointView(); + TFontStyles AFontStyle = SettingsData->ThemeSettings->StateNormalFontStyle; + if (!bIsCluster && this->SelfConnectionInside) { + AFontStyle = SettingsData->ThemeSettings->StateSelfConnectionInsideFontStyle; + } + if (FEntered) { - if (this->Font->Style != TFontStyles() << fsBold) { - this->Font->Style = TFontStyles() << fsBold; + if (this->Font->Style != AFontStyle << fsBold) { + this->Font->Style = AFontStyle << fsBold; } } else { - if (this->Font->Style != TFontStyles()) { - this->Font->Style = TFontStyles(); + if (this->Font->Style != AFontStyle) { + this->Font->Style = AFontStyle; } } if (this->Shadow->Visible != false) { @@ -1985,7 +2015,7 @@ int __fastcall TVisualScxmlBaseShape::GetClusterHeight(void) { // --------------------------------------------------------------------------- int __fastcall TVisualScxmlBaseShape::CalculateChildrenTop(int iDefaultTop) { - return IsCluster() ? this->Top + GetClusterHeight() : iDefaultTop; + return(IsCluster() || this->ChildrenAlignY == scayAlwaysTop) ? this->Top + GetClusterHeight() : iDefaultTop; } // --------------------------------------------------------------------------- @@ -2068,7 +2098,8 @@ int __fastcall TVisualScxmlBaseShape::MaxHeightExpandedChildsEx(void) { } } } - return this->ChildrenAlignY == scayClusterTop ? CalculateChildrenTop(AdjustedRectangle.Bottom) : AdjustedRectangle.Bottom; + return(this->ChildrenAlignY == scayClusterTop || this->ChildrenAlignY == scayAlwaysTop) ? CalculateChildrenTop + (AdjustedRectangle.Bottom) : AdjustedRectangle.Bottom; } // --------------------------------------------------------------------------- @@ -2164,6 +2195,26 @@ void __fastcall TChildScxmlBaseShape::Assign(Classes::TPersistent * Source) { throw Exception(__FUNCTION__ "> Source can not be empty!"); } +// --------------------------------------------------------------------------- +TColor __fastcall TChildScxmlBaseShape::GetNormalColor(void) { + return SettingsData->ThemeSettings->ChildNormalColor; +} + +// --------------------------------------------------------------------------- +TFontStyles __fastcall TChildScxmlBaseShape::GetNormalFontStyle() { + return SettingsData->ThemeSettings->ChildNormalFontStyle; +} + +// --------------------------------------------------------------------------- +TColor __fastcall TChildScxmlBaseShape::GetNormalBorderColor(void) { + return SettingsData->ThemeSettings->ChildNormalBorderColor; +} + +// --------------------------------------------------------------------------- +TPenStyle __fastcall TChildScxmlBaseShape::GetNormalBorderStyle(void) { + return SettingsData->ThemeSettings->ChildNormalBorderStyle; +} + // --------------------------------------------------------------------------- void __fastcall TChildScxmlBaseShape::DefaultEditProperty(void) { diff --git a/Src/UnitScxmlBaseShape.h b/Src/UnitScxmlBaseShape.h index 595d62e..172c0dd 100644 --- a/Src/UnitScxmlBaseShape.h +++ b/Src/UnitScxmlBaseShape.h @@ -389,7 +389,7 @@ class TScxmlBaseShape: public TTreeNodeShape { }; typedef enum { scaxLeft, scaxRight, scaxCenter } TShapeChildrenAlignX; -typedef enum { scayClusterTop, scayAlwaysBottom } TShapeChildrenAlignY; +typedef enum { scayClusterTop, scayAlwaysBottom, scayAlwaysTop } TShapeChildrenAlignY; //--------------------------------------------------------------------------- class TVisualScxmlBaseShape : public TScxmlBaseShape { @@ -414,6 +414,9 @@ class TVisualScxmlBaseShape : public TScxmlBaseShape { TPersistentRect *FSelfConnectionTextOffsets; void __fastcall SetSelfConnectionTextOffsets(TPersistentRect *val); + bool FSelfConnectionInside; + void __fastcall SetSelfConnectionInside(bool val); + TPersistentPoint *FParentOffsetStored; void __fastcall SetParentOffsetStored(TPersistentPoint *val); @@ -433,6 +436,7 @@ class TVisualScxmlBaseShape : public TScxmlBaseShape { virtual void __fastcall SetErrorAppearance(void); virtual void __fastcall DrawShapeCanvas(Tecanvas::TCanvas3D* ACanvas, const Types::TRect &R); /* inherited */ + virtual TVertTextAlign __fastcall GetVertTextAlign(void); /* inhrerited */ UnicodeString FInitial; virtual UnicodeString __fastcall GetInitial(void); @@ -510,12 +514,15 @@ class TVisualScxmlBaseShape : public TScxmlBaseShape { __published: __property TPersistentRect *SelfConnectionTextOffsets = {read=FSelfConnectionTextOffsets, write=SetSelfConnectionTextOffsets}; + __property bool SelfConnectionInside = {read=FSelfConnectionInside, write=SetSelfConnectionInside, default=false}; __property TPersistentPoint *ParentOffsetStored = {read=FParentOffsetStored, write=SetParentOffsetStored}; __property ChildIndex; __property TShapeChildrenAlignX ChildrenAlignX = {read=FChildrenAlignX, write=FChildrenAlignX, default=scaxLeft}; __property TShapeChildrenAlignY ChildrenAlignY = {read=FChildrenAlignY, write=FChildrenAlignY, default=scayClusterTop}; __property int ChildrenAlignXOffset = {read=FChildrenAlignXOffset, write=FChildrenAlignXOffset, default=0}; __property bool SkipDebugging = {read=FSkipDebugging, write=SetSkipDebugging, default=false}; + __property VertTextAlign; + __property HorizTextAlign; }; @@ -547,7 +554,7 @@ class TChildScxmlBaseShape : public TScxmlBaseShape { inline virtual TColor __fastcall GetFinalColor(void) { return GetNormalColor(); } - inline virtual TColor __fastcall GetNormalColor(void) { return clWhite; } + virtual TColor __fastcall GetNormalColor(void); virtual TColor __fastcall GetFinalFontColor(void); @@ -555,16 +562,16 @@ class TChildScxmlBaseShape : public TScxmlBaseShape { inline virtual TFontStyles __fastcall GetFinalFontStyle(void) { return GetNormalFontStyle(); } - inline virtual TFontStyles __fastcall GetNormalFontStyle() { return TFontStyles(); } + inline virtual TFontStyles __fastcall GetNormalFontStyle(); inline virtual TColor __fastcall GetFinalBorderColor(void) { return GetNormalBorderColor(); } // , - inline virtual TColor __fastcall GetNormalBorderColor(void) { return TColor(RGB(32, 32, 32)); } + virtual TColor __fastcall GetNormalBorderColor(void); virtual TPenStyle __fastcall GetFinalBorderStyle(void); - inline virtual TPenStyle __fastcall GetNormalBorderStyle(void) { return psSolid; } + virtual TPenStyle __fastcall GetNormalBorderStyle(void); // virtual void __fastcall DrawShapeCanvas(Tecanvas::TCanvas3D* ACanvas, const Types::TRect &R); /* inherited */ diff --git a/Src/UnitScxmlShape.cpp b/Src/UnitScxmlShape.cpp index bca30c0..5a1ddd7 100644 --- a/Src/UnitScxmlShape.cpp +++ b/Src/UnitScxmlShape.cpp @@ -1,34 +1,34 @@ /*********************************************************************************** - BSD 3-Clause License +BSD 3-Clause License - Copyright (c) 2018, https://github.com/alexzhornyak - All rights reserved. +Copyright (c) 2018, https://github.com/alexzhornyak +All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. + * Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************************************************************************************/ +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ***************************************************************************************/ #include #pragma hdrstop @@ -227,7 +227,8 @@ void __fastcall TScxmlShape::Assign(Classes::TPersistent* Source) { // --------------------------------------------------------------------------- TColor __fastcall TScxmlShape::GetHeadColor(void) { - return(this->StateMachineEditorUnit && this->StateMachineEditorUnit->IsVirtual) ? clSilver : clMoneyGreen; + return(this->StateMachineEditorUnit && this->StateMachineEditorUnit->IsVirtual) + ? SettingsData->ThemeSettings->VirtualNormalColor : SettingsData->ThemeSettings->ScxmlNormalHeadColor; } // --------------------------------------------------------------------------- @@ -299,7 +300,7 @@ void __fastcall TScxmlShape::DrawShapeCanvas(Tecanvas::TCanvas3D * ACanvas, cons if (!bIsDatamodelEmpty) { ACanvas->BackMode = cbmTransparent; ACanvas->TextAlign = TA_RIGHT; - ACanvas->Font->Color = clMaroon; + ACanvas->Font->Color = SettingsData->ThemeSettings->ScxmlDatamodelFontColor; ACanvas->TextOut3D(this->X1 - 3, this->Y0 + 3, TeeTreeZ, this->Datamodel); } @@ -319,14 +320,14 @@ void __fastcall TScxmlShape::DrawShapeCanvas(Tecanvas::TCanvas3D * ACanvas, cons if (this->StateMachineEditorUnit->IsVirtual) { ACanvas->BackMode = cbmTransparent; ACanvas->TextAlign = TA_LEFT; - ACanvas->Font->Color = clBlue; + ACanvas->Font->Color = SettingsData->ThemeSettings->ScxmlVirtualFontColor; ACanvas->Font->Style = TFontStyles(); ACanvas->TextOut3D(R.Left + 3, R.Top + 3, TeeTreeZ, L"VIRTUAL"); } else if (this->StateMachineEditorUnit->IsInherited) { ACanvas->BackMode = cbmTransparent; ACanvas->TextAlign = TA_LEFT; - ACanvas->Font->Color = clBlue; + ACanvas->Font->Color = SettingsData->ThemeSettings->ScxmlVirtualFontColor; ACanvas->TextOut3D(R.Left + 3, R.Top + 3, TeeTreeZ, L"Inherited: "+this->StateMachineEditorUnit->Inherited); } } diff --git a/Src/UnitSettings.cpp b/Src/UnitSettings.cpp index 6e69c10..511dc1c 100644 --- a/Src/UnitSettings.cpp +++ b/Src/UnitSettings.cpp @@ -98,6 +98,7 @@ __fastcall TSettingsData::TSettingsData(TComponent* Owner) : TSettingsBase(Owner FScxmlMsgTypes = DEFAULT_SETTINGS_SCXML_MSG_TYPES; FSkipCommentsInRawScxml = true; + FForceSaveDefaultScxmlValues = false; FTestingShowCallStack = true; FTestingSwitchToPanel = true; @@ -149,6 +150,7 @@ __fastcall TSettingsData::TSettingsData(TComponent* Owner) : TSettingsBase(Owner FTestSettings = new TTestSettings(tsbtApp); FExportSvgSettings = new TExportSvgSettings(); + FThemeSettings = new TThemeSettings(); FConnectionInvertedConditionMacro = new TStringList; @@ -193,6 +195,7 @@ __fastcall TSettingsData::~TSettingsData() { delete FLoggingProperties; delete FTestSettings; delete FExportSvgSettings; + delete FThemeSettings; delete FConnectionInvertedConditionMacro; delete FDefaultConnectionInvertedConditionMacro; delete FRegistryItems; @@ -269,6 +272,7 @@ void __fastcall TSettingsData::Assign(TPersistent* Source) { FScxmlMsgTypes = ASettingsData->FScxmlMsgTypes; FSkipCommentsInRawScxml = ASettingsData->FSkipCommentsInRawScxml; + FForceSaveDefaultScxmlValues = ASettingsData->FForceSaveDefaultScxmlValues; FTestingShowCallStack = ASettingsData->FTestingShowCallStack; FTestingSwitchToPanel = ASettingsData->FTestingSwitchToPanel; @@ -294,6 +298,7 @@ void __fastcall TSettingsData::Assign(TPersistent* Source) { FTestSettings->Assign(ASettingsData->FTestSettings); FExportSvgSettings->Assign(ASettingsData->FExportSvgSettings); + FThemeSettings->Assign(ASettingsData->FThemeSettings); FConnectionInvertedConditionMacro->Assign(ASettingsData->FConnectionInvertedConditionMacro); @@ -421,6 +426,9 @@ void __fastcall TSettingsData::OnGetPropEditorClass(TPersistent *AInstance, ILMD else if (sPropName == L"ExportSvgSettings") { AEditorClass = __classid(TExportSvgSettingsPropEditor); } + else if (sPropName == L"ThemeSettings") { + AEditorClass = __classid(TThemeSettingsPropEditor); + } else if (sPropName == L"TestApplicationPresets") { AEditorClass = __classid(TTestApplicationPresetesPropEditor); } @@ -472,6 +480,7 @@ void __fastcall TSettingsData::PropSettingsRegisterCategories(TLMDPropertyInspec APropSettingsInspector->RegisterPropCategory(L"Visual", L"ChartFocusLineColor"); APropSettingsInspector->RegisterPropCategory(L"Visual", L"ChartActiveStateColor"); APropSettingsInspector->RegisterPropCategory(L"Visual", L"ChartTestCoverageColor"); + APropSettingsInspector->RegisterPropCategory(L"Visual", L"ThemeSettings"); APropSettingsInspector->RegisterPropCategory(L"Scxml AutoLayout", L"AutoLayoutSplines"); APropSettingsInspector->RegisterPropCategory(L"Scxml AutoLayout", L"AutoLayoutUseNativeLabelPos"); @@ -495,6 +504,7 @@ void __fastcall TSettingsData::PropSettingsRegisterCategories(TLMDPropertyInspec APropSettingsInspector->RegisterPropCategory(L"Scxml parser", L"ValidateChildren"); APropSettingsInspector->RegisterPropCategory(L"Scxml parser", L"ValidateXMLText"); APropSettingsInspector->RegisterPropCategory(L"Scxml parser", L"ValidateEmptyTransitions"); + APropSettingsInspector->RegisterPropCategory(L"Scxml parser", L"ForceSaveDefaultScxmlValues"); APropSettingsInspector->RegisterPropCategory(L"Scxml tester", L"TestingShowCallStack"); APropSettingsInspector->RegisterPropCategory(L"Scxml tester", L"CallStackTypes"); diff --git a/Src/UnitSettings.h b/Src/UnitSettings.h index b68906e..dd0d5e6 100644 --- a/Src/UnitSettings.h +++ b/Src/UnitSettings.h @@ -48,6 +48,7 @@ #include "UnitSettingsBinaryItems.h" #include "UnitSVGSettings.h" #include "UnitTestingApplicationsPresets.h" +#include "UnitThemeSettings.h" //--------------------------------------------------------------------------- #define DEFAULT_HIDE_WINDOWS_STATUS (TTreeEditWindows() << teInspector << teFont << teFormat) @@ -89,6 +90,9 @@ class TSettingsData: public TSettingsBase TExportSvgSettings * FExportSvgSettings; inline void __fastcall SetExportSvgSettings(TExportSvgSettings *val) { FExportSvgSettings->Assign(val); } + TThemeSettings * FThemeSettings; + inline void __fastcall SetThemeSettings(TThemeSettings *val) { FThemeSettings->Assign(val); } + TEditorSearchTypes FSearchTypes; TEditorSearchDocumentType FSearchDocumentType; @@ -185,7 +189,8 @@ class TSettingsData: public TSettingsBase TScxmlMsgTypes FScxmlMsgTypes; inline bool __fastcall IsScxmlMsgTypesStored(void) { return FScxmlMsgTypes!=DEFAULT_SETTINGS_SCXML_MSG_TYPES; } - bool FSkipCommentsInRawScxml; + bool FSkipCommentsInRawScxml; + bool FForceSaveDefaultScxmlValues; bool FAviaExtensionEnabled; bool FProfilingEnabled; @@ -337,6 +342,7 @@ class TSettingsData: public TSettingsBase __property bool ValidateChildren = {read=FValidateChildren, write=FValidateChildren, default=true}; __property bool ValidateXMLText = {read=FValidateXMLText, write=FValidateXMLText, default=true}; __property bool ValidateEmptyTransitions = {read=FValidateEmptyTransitions, write=FValidateEmptyTransitions, default=true}; + __property bool ForceSaveDefaultScxmlValues = {read=FForceSaveDefaultScxmlValues, write=FForceSaveDefaultScxmlValues, default=false}; __property bool ZoomHintsEnabled = {read=FZoomHintsEnabled, write=FZoomHintsEnabled, default=true}; __property int ZoomHintsStartLevel = {read=FZoomHintsStartLevel, write=FZoomHintsStartLevel, default=90}; @@ -382,6 +388,8 @@ class TSettingsData: public TSettingsBase __property UnicodeString LuautilsLuacSyntaxCheckParamsCMD = {read=GetLuautilsLuacSyntaxCheckParamsCMD, write=FLuautilsLuacSyntaxCheckParamsCMD, stored=IsLuautilsLuacSyntaxCheckParamsCMDStored}; __property UnicodeString LuautilsBinaryConverter = {read=GetLuautilsBinaryConverter, write=FLuautilsBinaryConverter, stored=IsLuautilsBinaryConverterStored}; + __property TThemeSettings * ThemeSettings = {read=FThemeSettings, write=SetThemeSettings}; + // SVG __property TExportSvgSettings * ExportSvgSettings = {read=FExportSvgSettings, write=SetExportSvgSettings}; diff --git a/Src/UnitStateMachineConnection.cpp b/Src/UnitStateMachineConnection.cpp index 8459e09..7c5ded4 100644 --- a/Src/UnitStateMachineConnection.cpp +++ b/Src/UnitStateMachineConnection.cpp @@ -59,7 +59,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitSVGExporter.h" #include "ScxmlShapes.hpp" -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- #pragma package(smart_init) @@ -72,7 +72,7 @@ void RegisterStateMachineConnection() { Classes::RegisterClassA(__classid(TParamTriggerItems)); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- UnicodeString ClipText(const UnicodeString &sText, TClipTextType AType, int iClipMax) { if (sText.Length() > iClipMax) { switch(AType) { @@ -93,12 +93,12 @@ UnicodeString ClipText(const UnicodeString &sText, TClipTextType AType, int iCli return sText; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- bool IsStateMachineConnectionClipboardFormat(const UnicodeString &sText) { return sText.Pos(L"object TStateMachineConnection") == 1; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void PasteStateMachineConnectionFromText(TCustomTree *ADestTree, const UnicodeString &sText) { try { if (!ADestTree) @@ -107,7 +107,7 @@ void PasteStateMachineConnectionFromText(TCustomTree *ADestTree, const UnicodeSt std::auto_ptrAStringListPtr(new TStringList()); AStringListPtr->Text = sText; - // так как у нас будут новые родители + // так как у нас будут новые родители UnicodeString sFromShape = L""; UnicodeString sToShape = L""; @@ -134,10 +134,10 @@ void PasteStateMachineConnectionFromText(TCustomTree *ADestTree, const UnicodeSt std::auto_ptrAClipboardComponentPtr(AOutStreamPtr->ReadComponent(NULL)); TStateMachineConnection *AConnection = dynamic_cast(AClipboardComponentPtr.get()); if (AConnection) { - // если выбрано соединение, тогда назначаем его тем, которое в буфере + // если выбрано соединение, тогда назначаем его тем, которое в буфере if (ADestTree->Connections->Selected) { - // стиль соединения должен остаться прежним + // стиль соединения должен остаться прежним TStateMachineConnection *ASelectedConnection = dynamic_cast(ADestTree->Connections->Selected); if (ASelectedConnection) { ASelectedConnection->AssignStateMachineConnection(AConnection); @@ -164,7 +164,7 @@ void PasteStateMachineConnectionFromText(TCustomTree *ADestTree, const UnicodeSt ANewConnection->Assign(AConnection); - // bug fix: какого-то хрена не назначаются точки при множественном назначении + // bug fix: какого-то хрена не назначаются точки при множественном назначении ANewConnection->Style = AConnection->Style; ANewConnection->Points->Clear(); @@ -173,7 +173,7 @@ void PasteStateMachineConnectionFromText(TCustomTree *ADestTree, const UnicodeSt AConnection->Points->Item[i].YStyle, AConnection->Points->Item[i].YValue); } - // необходимо удалить временное соединение, чтобы его уже не было на момент формирования нового имени + // необходимо удалить временное соединение, чтобы его уже не было на момент формирования нового имени AClipboardComponentPtr.reset(0); const Unique::TUniquePair AUniqueName = Unique::GetUniqueName(ADestTree->Owner, __classid(TStateMachineConnection)); @@ -200,7 +200,7 @@ void PasteStateMachineConnectionFromText(TCustomTree *ADestTree, const UnicodeSt ANewConnection->ToShape = ADestTree->Selected->Items[1]; ANewConnection->Assign(AConnection); - // bug fix: какого-то хрена не назначаются точки при множественном назначении + // bug fix: какого-то хрена не назначаются точки при множественном назначении ANewConnection->Style = AConnection->Style; ANewConnection->Points->Clear(); @@ -209,7 +209,7 @@ void PasteStateMachineConnectionFromText(TCustomTree *ADestTree, const UnicodeSt AConnection->Points->Item[i].YStyle, AConnection->Points->Item[i].YValue); } - // необходимо удалить временное соединение, чтобы его уже не было на момент формирования нового имени + // необходимо удалить временное соединение, чтобы его уже не было на момент формирования нового имени AClipboardComponentPtr.reset(0); const Unique::TUniquePair AUniqueName = Unique::GetUniqueName(ADestTree->Owner, __classid(TStateMachineConnection)); @@ -219,7 +219,7 @@ void PasteStateMachineConnectionFromText(TCustomTree *ADestTree, const UnicodeSt if (ANewConnection->AdjustableSides) { - ANewConnection->Draw(); // даём команду отрисовать, чтобы обновились все значения в точках + ANewConnection->Draw(); // даём команду отрисовать, чтобы обновились все значения в точках Editorutils::AdjustSidesConnection(ANewConnection); } @@ -237,17 +237,17 @@ void PasteStateMachineConnectionFromText(TCustomTree *ADestTree, const UnicodeSt } } -// --------------------------------------------------------------------------- -// ----------------------- EStateMachineConnectionException ------------------ -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// ----------------------- EStateMachineConnectionException ------------------ +// --------------------------------------------------------------------------- __fastcall EStateMachineConnectionException::EStateMachineConnectionException(TStateMachineConnection *AStateMachineConnection, const UnicodeString &sCategory, const UnicodeString &sMsg) : Exception(sMsg), FStateMachineConnection(AStateMachineConnection), FCategory(sCategory) { } -// --------------------------------------------------------------------------- -// ------------------------- TStateMachineConnection ------------------------- -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// ------------------------- TStateMachineConnection ------------------------- +// --------------------------------------------------------------------------- __fastcall TStateMachineConnection::TStateMachineConnection(Classes::TComponent* AOwner) : TTreeConnection(AOwner), FTransitionEditor(NULL), FXML(L""), FCondition(L""), FConditionBack(L""), FEvent(L""), FAdjustableSides(true), FContentTrigger(new TContentTrigger(this)), FParams(new TParamTriggerItems(this)), FGuid(new GUID), FSwitch(tstNONE) { @@ -300,7 +300,7 @@ FContentTrigger(new TContentTrigger(this)), FParams(new TParamTriggerItems(this) FSkipAutolayout = false; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- __fastcall TStateMachineConnection::~TStateMachineConnection(void) { if (FTransitionEditor) { delete FTransitionEditor; @@ -328,7 +328,7 @@ __fastcall TStateMachineConnection::~TStateMachineConnection(void) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- bool __fastcall TStateMachineConnection::OnFilterPropEvent(const UnicodeString &sPropName) { std::auto_ptrABlackListPtr(new TStringList()); ABlackListPtr->CaseSensitive = true; @@ -350,11 +350,11 @@ bool __fastcall TStateMachineConnection::OnFilterPropEvent(const UnicodeString & return IsPublishedProp(__classid(TTreeConnection), sPropName) == false; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::OnGetPropCaptionColor(TObject *Sender, Lmdinspropinsp::TLMDPropertyInspectorItem *AItem, TColor &AColor) { - // специальный случай + // специальный случай if (AItem->PropName == L"InheritanceResolver") { AColor = clTeal; return; @@ -396,7 +396,7 @@ void __fastcall TStateMachineConnection::OnGetPropCaptionColor(TObject *Sender, } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::OnGetPropEditorClass(TPersistent *AInstance, ILMDProperty *APropInfo, TLMDPropEditorClass &AEditorClass) { if (APropInfo) { @@ -410,7 +410,7 @@ void __fastcall TStateMachineConnection::OnGetPropEditorClass(TPersistent *AInst else if (sPropName == L"ContentTrigger") { AEditorClass = __classid(TContentPropEditor); } - // указываем флаг AviaExtensionEnabled иначе редактор отменит фильтр + // указываем флаг AviaExtensionEnabled иначе редактор отменит фильтр else if (SettingsData->AviaExtensionEnabled && sPropName == L"ProtocolControlBinding") { AEditorClass = __classid(TProtocolControlBindingPropertyEditor); } @@ -432,7 +432,7 @@ void __fastcall TStateMachineConnection::OnGetPropEditorClass(TPersistent *AInst } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- UnicodeString __fastcall TStateMachineConnection::OnGetHTMLPropertyInfo(const UnicodeString &sPropName) { if (sPropName == L"Event") { return // @@ -625,7 +625,7 @@ UnicodeString __fastcall TStateMachineConnection::OnGetHTMLPropertyInfo(const Un return L""; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetSwitch(TTransitionSwitchType val) { FSwitch = val; @@ -634,7 +634,7 @@ void __fastcall TStateMachineConnection::SetSwitch(TTransitionSwitchType val) { UpdateTransitionText(); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetVerticalCentering(bool val) { if (FVerticalCentering != val) { FVerticalCentering = val; @@ -646,7 +646,7 @@ void __fastcall TStateMachineConnection::SetVerticalCentering(bool val) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::UpdateDummyText(void) { if (Tree) { for (int i = 0; i < Tree->Shapes->Count; i++) { @@ -658,7 +658,7 @@ void __fastcall TStateMachineConnection::UpdateDummyText(void) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::UpdateAppearance() { if (!this->ComponentState.Contains(csLoading)) { @@ -700,7 +700,7 @@ void __fastcall TStateMachineConnection::UpdateAppearance() { this->Border->Style = psDash; this->Border->Color = TColor(RGB(200, 0, 0)); - // так как стрелки выглядят одинаково по размеру, то необходимо указать направление откуда + // так как стрелки выглядят одинаково по размеру, то необходимо указать направление откуда if (Locked || InheritanceMismatch) { USHORT ushHue, ushLuminance, ushSaturation; ColorToHLS(AFromBackColor, ushHue, ushLuminance, ushSaturation); @@ -714,7 +714,7 @@ void __fastcall TStateMachineConnection::UpdateAppearance() { this->Border->Style = psDash; this->Border->Color = clGray; - // так как стрелки выглядят одинаково по размеру, то необходимо указать направление откуда + // так как стрелки выглядят одинаково по размеру, то необходимо указать направление откуда if (Locked || InheritanceMismatch) { USHORT ushHue, ushLuminance, ushSaturation; ColorToHLS(AFromBackColor, ushHue, ushLuminance, ushSaturation); @@ -751,7 +751,7 @@ void __fastcall TStateMachineConnection::UpdateAppearance() { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- UnicodeString __fastcall TStateMachineConnection::GetTarget(void) { if (this->ToShape) { TVisualScxmlBaseShape *AShape = dynamic_cast(this->ToShape); @@ -762,21 +762,21 @@ UnicodeString __fastcall TStateMachineConnection::GetTarget(void) { return L""; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetEvent(UnicodeString val) { FEvent = val; UpdateTransitionText(); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetCondition(UnicodeString val) { FCondition = val.Trim(); UpdateTransitionText(); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetBreakpointSet(bool val) { if (FBreakpointSet != val) { FBreakpointSet = val; @@ -786,21 +786,21 @@ void __fastcall TStateMachineConnection::SetBreakpointSet(bool val) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- UnicodeString __fastcall TStateMachineConnection::GetConditionBack(void) { if (FConditionBack.IsEmpty()) { try { return GetConditionBackFromSettingsThrow(GetSyntaxSchemeThrow()); } catch(Exception * E) { - // safe for inspector + // safe for inspector } } return FConditionBack; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- UnicodeString __fastcall TStateMachineConnection::GetSyntaxSchemeThrow(void) { UnicodeString sSyntaxScheme = L""; if (this->StateMachineEditor) { @@ -812,7 +812,7 @@ UnicodeString __fastcall TStateMachineConnection::GetSyntaxSchemeThrow(void) { return sSyntaxScheme; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- UnicodeString __fastcall TStateMachineConnection::GetConditionBackFromSettingsThrow(const UnicodeString &sSyntaxScheme) { const UnicodeString sInvertedConditionMacro = SettingsData->ConnectionInvertedConditionMacro->Values[sSyntaxScheme]; @@ -823,30 +823,30 @@ UnicodeString __fastcall TStateMachineConnection::GetConditionBackFromSettingsTh return sInvertedConditionMacro; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetConditionBack(UnicodeString val) { FConditionBack = val.Trim(); UpdateTransitionText(); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetDescription(UnicodeString val) { FDescription = val.Trim(); UpdateTransitionText(); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::Assign(Classes::TPersistent* Source) { if (Source) { TTreeConnection *AConnection = dynamic_cast(Source); if (Source) { - // ********************************************* // - // сначала все назначения из базового класса !!! // - // ********************************************* // + // ********************************************* // + // сначала все назначения из базового класса !!! // + // ********************************************* // TTreeConnection::Assign(AConnection); - // ********************************************* // + // ********************************************* // TStateMachineConnection * ATreeConnection = dynamic_cast(Source); if (ATreeConnection) { @@ -861,7 +861,7 @@ void __fastcall TStateMachineConnection::Assign(Classes::TPersistent* Source) { throw Exception(__FUNCTION__ "> Source can not be empty!"); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::AssignStateMachineConnection(TStateMachineConnection *AStateMachineConnection) { if (AStateMachineConnection) { FXML = AStateMachineConnection->FXML; @@ -887,17 +887,17 @@ void __fastcall TStateMachineConnection::AssignStateMachineConnection(TStateMach FSkipAutolayout = AStateMachineConnection->FSkipAutolayout; FBreakpointSet = AStateMachineConnection->FBreakpointSet; - // здесь произойдет UpdateTransitionText + // здесь произойдет UpdateTransitionText FProtocolControlBinding->Assign(AStateMachineConnection->FProtocolControlBinding); - // параметры с применением Set + // параметры с применением Set InheritanceMismatch = AStateMachineConnection->InheritanceMismatch; UpdateAppearance(); } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- TStateMachineEditorUnit *__fastcall TStateMachineConnection::GetStateMachineEditorUnit(void) { if (this->Tree) { TStateMachineEditor * AStateMachineEditor = StateMachineEditor; @@ -908,7 +908,7 @@ TStateMachineEditorUnit *__fastcall TStateMachineConnection::GetStateMachineEdit return NULL; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- TStateMachineEditor * __fastcall TStateMachineConnection::GetStateMachineEditor(void) { if (this->Tree) { return dynamic_cast(this->Tree->Owner); @@ -916,26 +916,26 @@ TStateMachineEditor * __fastcall TStateMachineConnection::GetStateMachineEditor( return NULL; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::ShowEditor(void) { if (!FTransitionEditor) { FTransitionEditor = new TFormTransitionEditor(this, this); } FTransitionEditor->Show(); - // восстанавливаем свёрнутое + // восстанавливаем свёрнутое if (FTransitionEditor->WindowState == wsMinimized) { FTransitionEditor->WindowState = wsNormal; } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SaveEditor(void) { if (FTransitionEditor) { FTransitionEditor->ActionSave->Execute(); } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::UpdateTransitionText(void) { this->Text->Clear(); if ((FScxmlTransitionDisplayTypes.Contains(stdtEvent) || FScxmlTransitionDisplayTypes.Contains(stdtMAXSIZE)) && !FEvent.IsEmpty()) { @@ -973,7 +973,7 @@ void __fastcall TStateMachineConnection::UpdateTransitionText(void) { } } if (this->ClipOutXML) { - // обязательно Trim в этом месте, так как иначе будут добавлены '\r\n' + // обязательно Trim в этом месте, так как иначе будут добавлены '\r\n' this->Text->Add(ClipText(AXMLList->Text.Trim(), ClipTypeXML, ClipOutMax)); } else { @@ -996,29 +996,29 @@ void __fastcall TStateMachineConnection::UpdateTransitionText(void) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- bool __fastcall TStateMachineConnection::IsScxmlTransitionDisplayTypesStored(void) { return !FScxmlTransitionDisplayTypes.Contains(stdtMAXSIZE); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetScxmlTransitionDisplayTypes(TScxmlTransitionDisplayTypes ATypes) { FScxmlTransitionDisplayTypes = ATypes << stdtEvent; UpdateTransitionText(); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetXML(UnicodeString val) { FXML = val.Trim(); UpdateTransitionText(); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::DoAppendExtraParamsAndChildren(Lmdxml::ILMDXmlElement *AElement, Lmdxml::ILMDXmlElement *AParentNode) { - // дополнительные аттрибуты + // дополнительные аттрибуты std::auto_ptrAExtraParamsList(new TStringList()); AExtraParamsList->Text = this->ExtraParams; for (int i = 0; i < AExtraParamsList->Count; i++) { @@ -1051,10 +1051,10 @@ void __fastcall TStateMachineConnection::DoAppendExtraParamsAndChildren(Lmdxml:: } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::AppendTransitionElement(Lmdxml::ILMDXmlElement *AParentNode) { try { - // только интерфейс должен быть для пристыковки дальше !!! + // только интерфейс должен быть для пристыковки дальше !!! _di_ILMDXmlElement AElement = LMDCreateXmlElement("transition"); bool bTransitionIsEmpty = true; @@ -1084,8 +1084,8 @@ void __fastcall TStateMachineConnection::AppendTransitionElement(Lmdxml::ILMDXml } } - if (this->Type != TScxmlTransitionType::external) { - AElement->SetAttr("type", "internal"); + if (this->Type != TScxmlTransitionType::external || SettingsData->ForceSaveDefaultScxmlValues) { + AElement->SetAttr("type", this->Type == TScxmlTransitionType::external ? L"external" : L"internal"); } DoAppendExtraParamsAndChildren(AElement, AParentNode); @@ -1100,7 +1100,7 @@ void __fastcall TStateMachineConnection::AppendTransitionElement(Lmdxml::ILMDXml } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::AppendTransitionSwitchElement(Lmdxml::ILMDXmlElement *AParentNode, const UnicodeString &sTarget) { try { if (sTarget.IsEmpty()) @@ -1114,7 +1114,7 @@ void __fastcall TStateMachineConnection::AppendTransitionSwitchElement(Lmdxml::I this->Name + L"> SWITCH Not applicable for SELF-CONNECTION!"); } - // только интерфейс должен быть для пристыковки дальше !!! + // только интерфейс должен быть для пристыковки дальше !!! _di_ILMDXmlElement AElement = LMDCreateXmlElement(L"transition"); switch(SWITCH) { @@ -1163,7 +1163,7 @@ void __fastcall TStateMachineConnection::AppendTransitionSwitchElement(Lmdxml::I } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::MakeSelfConnection(void) { try { if (!this->IsSelfConnection) @@ -1180,7 +1180,7 @@ void __fastcall TStateMachineConnection::MakeSelfConnection(void) { } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- TSelfConnectionInfo __fastcall TStateMachineConnection::GetSelfConnectionInfo() { TSelfConnectionInfo AInfo; memset(&AInfo, 0, sizeof(TSelfConnectionInfo)); @@ -1194,13 +1194,26 @@ TSelfConnectionInfo __fastcall TStateMachineConnection::GetSelfConnectionInfo() if (this->Points->Count() == 4) { - // пока ориентируемся по этой точке, предполагаем, что она параллельна со второй точкой + const int tmpAngle = RoundTo(RadToDeg(ArcTan2((this->Points->Item[2].X -this->Points->Item[0].X), // + (this->Points->Item[2].Y -this->Points->Item[0].Y))), 0); + + WLOG_DEBUG(L"%d", tmpAngle); + + // throw Exception("Break"); + + // пока ориентируемся по этой точке, предполагаем, что она параллельна со второй точкой + const int iStartPointX = this->Points->Item[0].X; + const int iStartPointY = this->Points->Item[0].Y; + const int iCheckPointX = this->Points->Item[1].X; const int iCheckPointY = this->Points->Item[1].Y; + const int iCheckPointX2 = this->Points->Item[2].X; + const int iCheckPointY2 = this->Points->Item[2].Y; - // определение верха - if ((iCheckPointX >= this->FromShape->X0 && iCheckPointX <= this->FromShape->X1) && iCheckPointY <= this->FromShape->Y0) { - AInfo.Align = scaTop; + // определение верха + if ((iCheckPointX2 > iStartPointX) && // + (iCheckPointY2 < iStartPointY && iCheckPointY < iStartPointY)) { + AInfo.Align = AVisShape->SelfConnectionInside ? scaBottom : scaTop; switch(this->Points->Item[1].XStyle) { case cpsFromRel: @@ -1227,9 +1240,10 @@ TSelfConnectionInfo __fastcall TStateMachineConnection::GetSelfConnectionInfo() AInfo.TextOffset = AVisShape->SelfConnectionTextOffsets->Top; } else - // определение низа - if ((iCheckPointX >= this->FromShape->X0 && iCheckPointX <= this->FromShape->X1) && iCheckPointY >= this->FromShape->Y1) { - AInfo.Align = scaBottom; + // определение низа + if ((iCheckPointX2 > iStartPointX) && // + (iCheckPointY2 > iStartPointY && iCheckPointY > iStartPointY)) { + AInfo.Align = AVisShape->SelfConnectionInside ? scaTop : scaBottom; switch(this->Points->Item[1].XStyle) { case cpsFromRel: @@ -1256,9 +1270,10 @@ TSelfConnectionInfo __fastcall TStateMachineConnection::GetSelfConnectionInfo() AInfo.TextOffset = AVisShape->SelfConnectionTextOffsets->Bottom; } else - // определение влево - if ((iCheckPointY >= this->FromShape->Y0 && iCheckPointY <= this->FromShape->Y1) && iCheckPointX <= this->FromShape->X0) { - AInfo.Align = scaLeft; + // определение влево + if ((iCheckPointY2 > iStartPointY) && // + (iCheckPointX2 < iStartPointX && iCheckPointX < iStartPointX)) { + AInfo.Align = AVisShape->SelfConnectionInside ? scaRight : scaLeft; switch(this->Points->Item[1].YStyle) { case cpsFromRel: @@ -1285,9 +1300,10 @@ TSelfConnectionInfo __fastcall TStateMachineConnection::GetSelfConnectionInfo() AInfo.TextOffset = AVisShape->SelfConnectionTextOffsets->Left; } else - // определение вправо - if ((iCheckPointY >= this->FromShape->Y0 && iCheckPointY <= this->FromShape->Y1) && iCheckPointX >= this->FromShape->X1) { - AInfo.Align = scaRight; + // определение вправо + if ((iCheckPointY2 > iStartPointY) && // + (iCheckPointX2 > iStartPointX && iCheckPointX > iStartPointX)) { + AInfo.Align = AVisShape->SelfConnectionInside ? scaLeft : scaRight; switch(this->Points->Item[1].YStyle) { case cpsFromRel: @@ -1318,7 +1334,7 @@ TSelfConnectionInfo __fastcall TStateMachineConnection::GetSelfConnectionInfo() return AInfo; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- struct TCorner { TCorner() { iOffset = 0; @@ -1331,57 +1347,67 @@ struct TCorner { int iIndex; }; -// --------------------------------------------------------------------------- -void GetSelfConnectionCorners(TTreeConnection * AConnection, const bool bIsSelf, TCorner &ATop, TCorner &ABottom, TCorner &ALeft, - TCorner &ARight) { +// --------------------------------------------------------------------------- +void GetSelfConnectionCorners(TTreeConnection * AConnection, const bool bIsSelf, const bool bIsReverseOrder, TCorner &ATop, + TCorner &ABottom, TCorner &ALeft, TCorner &ARight) { if (AConnection->FromShape == AConnection->ToShape) { if (AConnection->Points->Count() == 4) { - // ориентируемся по первой точке, она является ключевой в Self-Connection + + // ориентируемся по первой точке, она является ключевой в Self-Connection + const int iStartPointX = AConnection->Points->Item[0].X; + const int iStartPointY = AConnection->Points->Item[0].Y; + const int iCheckPointX = AConnection->Points->Item[1].X; const int iCheckPointY = AConnection->Points->Item[1].Y; + const int iCheckPointX2 = AConnection->Points->Item[2].X; + const int iCheckPointY2 = AConnection->Points->Item[2].Y; - // определение верха - if ((iCheckPointX >= AConnection->FromShape->X0 && iCheckPointX <= AConnection->FromShape->X1) - && iCheckPointY <= AConnection->FromShape->Y0) { + // определение верха + if ((iCheckPointX2 > iStartPointX) && // + (iCheckPointY2 < iStartPointY && iCheckPointY < iStartPointY)) { if (!bIsSelf) { - ATop.iOffset = abs(AConnection->FromShape->Y0 - iCheckPointY); + const int iStartY = bIsReverseOrder ? AConnection->FromShape->Y1 : AConnection->FromShape->Y0; + ATop.iOffset = abs(iStartY - iCheckPointY); ATop.iIndex++; } ATop.iCount++; } - // определение низа - if ((iCheckPointX >= AConnection->FromShape->X0 && iCheckPointX <= AConnection->FromShape->X1) - && iCheckPointY >= AConnection->FromShape->Y1) { + // определение низа + if ((iCheckPointX2 > iStartPointX) && // + (iCheckPointY2 > iStartPointY && iCheckPointY > iStartPointY)) { if (!bIsSelf) { - ABottom.iOffset = abs(AConnection->FromShape->Y1 - iCheckPointY); + const int iStartY = bIsReverseOrder ? AConnection->FromShape->Y0 : AConnection->FromShape->Y1; + ABottom.iOffset = abs(iStartY - iCheckPointY); ABottom.iIndex++; } ABottom.iCount++; } - // определение влево - if ((iCheckPointY >= AConnection->FromShape->Y0 && iCheckPointY <= AConnection->FromShape->Y1) - && iCheckPointX <= AConnection->FromShape->X0) { + // определение влево + if ((iCheckPointY2 > iStartPointY) && // + (iCheckPointX2 < iStartPointX && iCheckPointX < iStartPointX)) { if (!bIsSelf) { - ALeft.iOffset = abs(AConnection->FromShape->X0 - iCheckPointX); + const int iStartX = bIsReverseOrder ? AConnection->FromShape->X1 : AConnection->FromShape->X0; + ALeft.iOffset = abs(iStartX - iCheckPointX); ALeft.iIndex++; } ALeft.iCount++; } - // определение вправо - if ((iCheckPointY >= AConnection->FromShape->Y0 && iCheckPointY <= AConnection->FromShape->Y1) - && iCheckPointX >= AConnection->FromShape->X1) { + // определение вправо + if ((iCheckPointY2 > iStartPointY) && // + (iCheckPointX2 > iStartPointX && iCheckPointX > iStartPointX)) { if (!bIsSelf) { - ARight.iOffset = abs(AConnection->FromShape->X1 - iCheckPointX); + const int iStartX = bIsReverseOrder ? AConnection->FromShape->X0 : AConnection->FromShape->X1; + ARight.iOffset = abs(iStartX - iCheckPointX); ARight.iIndex++; } @@ -1391,7 +1417,7 @@ void GetSelfConnectionCorners(TTreeConnection * AConnection, const bool bIsSelf, } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::AlignSelfConnection(const TSelfConnectionAlign AConnectionAlign, const int iLengthOffsetBegin/* = 0*/, const int iLengthOffsetEnd/* = 0*/, const int iTextOffset/* = 0*/) { try { @@ -1405,9 +1431,9 @@ void __fastcall TStateMachineConnection::AlignSelfConnection(const TSelfConnecti const int iCharHeight = this->Tree->Canvas->TextHeight(TeeCharForHeight); const int iTextHeight = iTextLinesCount * iCharHeight + 6; - const int iSelfTextHeight = - (iTextHeight < SettingsData->ConnectionSelfDefaultHeight ? SettingsData->ConnectionSelfDefaultHeight : iTextHeight) - + iTextOffset; + int iSelfTextHeight = (iTextHeight < SettingsData->ConnectionSelfDefaultHeight ? + SettingsData->ConnectionSelfDefaultHeight : iTextHeight) + iTextOffset; + #if 0 // для глубокой отладки WLOG_DEBUG(L"Self-connection:[%s] iTextLinesCount=%d iCharHeight=%d iTextHeight=%d iSelfTextHeight:[%d]", this->SimpleText.c_str(), iTextLinesCount, iCharHeight, iTextHeight, iSelfTextHeight); @@ -1417,12 +1443,20 @@ void __fastcall TStateMachineConnection::AlignSelfConnection(const TSelfConnecti bool bFindSelf = false; + /* https://github.com/alexzhornyak/ScxmlEditor-Tutorial/issues/94 */ + bool bReverse = false; + + TVisualScxmlBaseShape * AVisualFrom = this->GetVisualFrom(); + if (AVisualFrom) { + bReverse = AVisualFrom->SelfConnectionInside; + } + for (int i = 0; i < this->FromShape->Connections->Count; i++) { if (this->FromShape->Connections->Items[i] == this) { bFindSelf = true; } - GetSelfConnectionCorners(this->FromShape->Connections->Items[i], bFindSelf, ATop, ABottom, ALeft, ARight); + GetSelfConnectionCorners(this->FromShape->Connections->Items[i], bFindSelf, bReverse, ATop, ABottom, ALeft, ARight); } this->Points->Clear(); @@ -1433,46 +1467,75 @@ void __fastcall TStateMachineConnection::AlignSelfConnection(const TSelfConnecti int iQuoterWidth = iShapeWidth / 4; int iQuoterHeight = iShapeHeight / 4; - switch(AConnectionAlign) { - case scaTop: - iQuoterWidth = iQuoterWidth / (ATop.iCount + 1) * (ATop.iIndex + 1); - iQuoterWidth = iQuoterWidth * 100 / iShapeWidth; + TSelfConnectionAlign AResultAlign = AConnectionAlign; - this->Points->Add(cpsFromPercent, 0 + iQuoterWidth + iLengthOffsetBegin, cpsFromPercent, 0); - this->Points->Add(cpsFromPercent, 0 + iLengthOffsetBegin, cpsFromRel, 0 - iSelfTextHeight - ATop.iOffset); - this->Points->Add(cpsFromPercent, 100 - iLengthOffsetEnd, cpsPrevious, 0); - this->Points->Add(cpsFromPercent, 100 - iQuoterWidth - iLengthOffsetEnd, cpsFromPercent, 0); - break; - case scaBottom: - iQuoterWidth = iQuoterWidth / (ABottom.iCount + 1) * (ABottom.iIndex + 1); - iQuoterWidth = iQuoterWidth * 100 / iShapeWidth; - - this->Points->Add(cpsFromPercent, 0 + iQuoterWidth + iLengthOffsetBegin, cpsFromPercent, 100); - this->Points->Add(cpsFromPercent, 0 + iLengthOffsetBegin, cpsPrevious, iSelfTextHeight + ABottom.iOffset); - this->Points->Add(cpsFromPercent, 100 - iLengthOffsetEnd, cpsPrevious, 0); - this->Points->Add(cpsFromPercent, 100 - iQuoterWidth - iLengthOffsetEnd, cpsFromPercent, 100); - break; - case scaLeft: - iQuoterHeight = iQuoterHeight / (ALeft.iCount + 1) * (ALeft.iIndex + 1); - iQuoterHeight = iQuoterHeight * 100 / iShapeHeight; - - this->Points->Add(cpsFromPercent, 0, cpsFromPercent, 0 + iQuoterHeight + iLengthOffsetBegin); - this->Points->Add(cpsFromRel, 0 - iSelfTextHeight - ALeft.iOffset, cpsFromPercent, 0 + iLengthOffsetBegin); - this->Points->Add(cpsPrevious, 0, cpsFromPercent, 100 - iLengthOffsetEnd); - this->Points->Add(cpsFromPercent, 0, cpsFromPercent, 100 - iQuoterHeight - iLengthOffsetEnd); - break; - case scaRight: - iQuoterHeight = iQuoterHeight / (ARight.iCount + 1) * (ARight.iIndex + 1); - iQuoterHeight = iQuoterHeight * 100 / iShapeHeight; - - this->Points->Add(cpsFromPercent, 100, cpsFromPercent, 0 + iQuoterHeight + iLengthOffsetBegin); - this->Points->Add(cpsPrevious, iSelfTextHeight + ARight.iOffset, cpsFromPercent, 0 + iLengthOffsetBegin); - this->Points->Add(cpsPrevious, 0, cpsFromPercent, 100 - iLengthOffsetEnd); - this->Points->Add(cpsFromPercent, 100, cpsFromPercent, 100 - iQuoterHeight - iLengthOffsetEnd); - break; + if (bReverse) { + switch(AConnectionAlign) { + case scaTop: + AResultAlign = scaBottom; + break; + case scaBottom: + AResultAlign = scaTop; + break; + case scaLeft: + AResultAlign = scaRight; + break; + case scaRight: + AResultAlign = scaLeft; + break; + } + } + + switch(AResultAlign) { + case scaTop: { + iQuoterWidth = iQuoterWidth / (ATop.iCount + 1) * (ATop.iIndex + 1); + iQuoterWidth = iQuoterWidth * 100 / iShapeWidth; + + const int iStartY = bReverse ? 100 : 0; + const TConnectionPointStyle AMiddleStyleY = bReverse ? cpsPrevious : cpsFromRel; + + this->Points->Add(cpsFromPercent, 0 + iQuoterWidth + iLengthOffsetBegin, cpsFromPercent, iStartY); + this->Points->Add(cpsFromPercent, 0 + iLengthOffsetBegin, AMiddleStyleY, 0 - iSelfTextHeight - ATop.iOffset); + this->Points->Add(cpsFromPercent, 100 - iLengthOffsetEnd, cpsPrevious, 0); + this->Points->Add(cpsFromPercent, 100 - iQuoterWidth - iLengthOffsetEnd, cpsFromPercent, iStartY); + }break; + case scaBottom: { + iQuoterWidth = iQuoterWidth / (ABottom.iCount + 1) * (ABottom.iIndex + 1); + iQuoterWidth = iQuoterWidth * 100 / iShapeWidth; + + const int iStartY = bReverse ? 0 : 100; + + this->Points->Add(cpsFromPercent, 0 + iQuoterWidth + iLengthOffsetBegin, cpsFromPercent, iStartY); + this->Points->Add(cpsFromPercent, 0 + iLengthOffsetBegin, cpsPrevious, iSelfTextHeight + ABottom.iOffset); + this->Points->Add(cpsFromPercent, 100 - iLengthOffsetEnd, cpsPrevious, 0); + this->Points->Add(cpsFromPercent, 100 - iQuoterWidth - iLengthOffsetEnd, cpsFromPercent, iStartY); + }break; + case scaLeft: { + iQuoterHeight = iQuoterHeight / (ALeft.iCount + 1) * (ALeft.iIndex + 1); + iQuoterHeight = iQuoterHeight * 100 / iShapeHeight; + + const int iStartX = bReverse ? 100 : 0; + const TConnectionPointStyle AMiddleStyleX = bReverse ? cpsPrevious : cpsFromRel; + + this->Points->Add(cpsFromPercent, iStartX, cpsFromPercent, 0 + iQuoterHeight + iLengthOffsetBegin); + this->Points->Add(AMiddleStyleX, 0 - iSelfTextHeight - ALeft.iOffset, cpsFromPercent, 0 + iLengthOffsetBegin); + this->Points->Add(cpsPrevious, 0, cpsFromPercent, 100 - iLengthOffsetEnd); + this->Points->Add(cpsFromPercent, iStartX, cpsFromPercent, 100 - iQuoterHeight - iLengthOffsetEnd); + }break; + case scaRight: { + iQuoterHeight = iQuoterHeight / (ARight.iCount + 1) * (ARight.iIndex + 1); + iQuoterHeight = iQuoterHeight * 100 / iShapeHeight; + + const int iStartX = bReverse ? 0 : 100; + + this->Points->Add(cpsFromPercent, iStartX, cpsFromPercent, 0 + iQuoterHeight + iLengthOffsetBegin); + this->Points->Add(cpsPrevious, iSelfTextHeight + ARight.iOffset, cpsFromPercent, 0 + iLengthOffsetBegin); + this->Points->Add(cpsPrevious, 0, cpsFromPercent, 100 - iLengthOffsetEnd); + this->Points->Add(cpsFromPercent, iStartX, cpsFromPercent, 100 - iQuoterHeight - iLengthOffsetEnd); + }break; } - // для того, чтобы сформировались координаты X и Y + // для того, чтобы сформировались координаты X и Y Editorutils::CalculatePointsPosition(this); } @@ -1481,7 +1544,7 @@ void __fastcall TStateMachineConnection::AlignSelfConnection(const TSelfConnecti } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- bool __fastcall TStateMachineConnection::Draw(void) { bool result = false; @@ -1504,7 +1567,7 @@ bool __fastcall TStateMachineConnection::Draw(void) { /* Process FromShape */ { int iTransitionIterIndex = 0; - // 1) Smart Transitions + // 1) Smart Transitions Editorutils::TConnectionFromToMap AInConnections; Editorutils::CollectInConnections(this->FromShape, AInConnections); @@ -1516,7 +1579,7 @@ bool __fastcall TStateMachineConnection::Draw(void) { } } - // 2) Regular Transitions + // 2) Regular Transitions for (int k = 0; k < this->FromShape->Connections->Count; k++) { TStateMachineConnection *AConnection = dynamic_cast(this->FromShape->Connections->Items[k]); /* 'ExcludeFromSave==false' гарантирует VisualFrom и VisualTo */ @@ -1535,7 +1598,7 @@ bool __fastcall TStateMachineConnection::Draw(void) { /* Process ToShape */ if (!this->IsSelfConnection && this->SWITCH != tstNONE) { - // 1) Smart Transitions + // 1) Smart Transitions Editorutils::TConnectionFromToMap AInConnections; Editorutils::CollectInConnections(this->ToShape, AInConnections); @@ -1566,12 +1629,12 @@ bool __fastcall TStateMachineConnection::Draw(void) { result = true; - // раньше вызывалось только один раз, - // 26.04.2019 тестово устанавливаем постоянно + // раньше вызывалось только один раз, + // 26.04.2019 тестово устанавливаем постоянно UpdateAppearance(); if (Visible()) { - // use manager to draw connection line(s)... + // use manager to draw connection line(s)... if (Style == csAuto) { if (Tree && Tree->GlobalFormat.ChildManager) { result = Tree->GlobalFormat.ChildManager->DrawConnection(this); @@ -1593,7 +1656,7 @@ bool __fastcall TStateMachineConnection::Draw(void) { return result; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::DoInternalDrawEx(void) { TTreeEx *ATree = dynamic_cast(Tree); if (!ATree) { @@ -1603,7 +1666,7 @@ void __fastcall TStateMachineConnection::DoInternalDrawEx(void) { DoPreparePoints(); - // не делаем 'const', так как для Curve может поменяться их кол-во + // не делаем 'const', так как для Curve может поменяться их кол-во int tmpNum = Points->Count(); if (!tmpNum) return; @@ -1620,7 +1683,7 @@ void __fastcall TStateMachineConnection::DoInternalDrawEx(void) { TCurvePoints tmpCurve; GetCurvePoints(tmpCurve); - // Curves need 4 points, or more than 4 in groups of 3 + // Curves need 4 points, or more than 4 in groups of 3 if (tmpNum > 4) { while ((tmpNum - 4) % 3 != 0) { tmpCurve[tmpNum] = tmpCurve[tmpNum - 1]; @@ -1628,7 +1691,14 @@ void __fastcall TStateMachineConnection::DoInternalDrawEx(void) { } } - PolyBezier(Tree->Canvas->Handle, tmpCurve, tmpNum); + /* fix: https://github.com/alexzhornyak/ScxmlEditor-Tutorial/issues/90 */ + if (TTreeSVGCanvasEx * ATreeSVGCanvasEx = dynamic_cast(Tree->Canvas)) { + // Draw as SVG cubic bezier path + ATreeSVGCanvasEx->DrawPolyBezier(tmpCurve, tmpNum); + } + else { + PolyBezier(Tree->Canvas->Handle, tmpCurve, tmpNum); + } for (int i = 0; i < tmpNum; i++) { ARealPoints.push_back(tmpCurve[i]); @@ -1647,7 +1717,7 @@ void __fastcall TStateMachineConnection::DoInternalDrawEx(void) { case csSides: { const double dDistance = Editorutils::DistanceBetweenPoints(tmpX, tmpY, tmpX, Points->Item[i].Y); if (dDistance <= 1.0f) { - // WLOG_DEBUG(L"Too small distance point=%d dist=%f", i, dDistance); + // WLOG_DEBUG(L"Too small distance point=%d dist=%f", i, dDistance); ARealPoints.push_back(TPoint(Points->Item[i].X, Points->Item[i].Y)); } else { @@ -1660,7 +1730,7 @@ void __fastcall TStateMachineConnection::DoInternalDrawEx(void) { case csInvertedSides: { const double dDistance = Editorutils::DistanceBetweenPoints(tmpX, tmpY, Points->Item[i].X, tmpY); if (dDistance <= 1.0f) { - // WLOG_DEBUG(L"Too small distance point=%d dist=%f", i, dDistance); + // WLOG_DEBUG(L"Too small distance point=%d dist=%f", i, dDistance); ARealPoints.push_back(TPoint(Points->Item[i].X, Points->Item[i].Y)); } else { @@ -1684,7 +1754,7 @@ void __fastcall TStateMachineConnection::DoInternalDrawEx(void) { } else { - // в этом месте только одна точка может быть! + // в этом месте только одна точка может быть! ARealPoints.push_back(TPoint(Points->Item[0].X, Points->Item[0].Y)); } } @@ -1697,7 +1767,7 @@ void __fastcall TStateMachineConnection::DoInternalDrawEx(void) { int tmpY1 = 0; /* Draw Arrows */ - // 1) Arrow From + // 1) Arrow From if (ARealPoints.size() > 1) { tmpX1 = ARealPoints[1].x; tmpY1 = ARealPoints[1].y; @@ -1710,9 +1780,9 @@ void __fastcall TStateMachineConnection::DoInternalDrawEx(void) { ArrowFrom->Draw(Points->Item[0], 270 - tmpAngle); } - // 2) Arrow To + // 2) Arrow To tmpAngle = 0; - const int iLast = tmpNum - 1; // last point index + const int iLast = tmpNum - 1; // last point index if (iLast > 0) { tmpX1 = Points->Item[iLast].X; tmpY1 = Points->Item[iLast].Y; @@ -1779,7 +1849,7 @@ void __fastcall TStateMachineConnection::DoInternalDrawEx(void) { /* Отрисовка индексов соединений */ if (this->Points->Count() && this->FromShape) { - // проверяем сколько переходов типа Transition, если больше одного, тогда покажем нумерацию + // проверяем сколько переходов типа Transition, если больше одного, тогда покажем нумерацию int iStateConnectionsCount = 0; int iIndex = 0; for (int i = 0; i < this->FromShape->Connections->Count; i++) { @@ -1803,7 +1873,7 @@ void __fastcall TStateMachineConnection::DoInternalDrawEx(void) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- TPoint __fastcall TStateMachineConnection::GetTextAbsolutePosWithoutCentering(void) { int tmpX = 0; int tmpY = 0; @@ -1842,7 +1912,7 @@ TPoint __fastcall TStateMachineConnection::GetTextAbsolutePosWithoutCentering(vo return Point(tmpX, tmpY); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::CalculateTextPosWithoutDraw(void) { if (!Tree) return; @@ -1856,7 +1926,7 @@ void __fastcall TStateMachineConnection::CalculateTextPosWithoutDraw(void) { DoPreparePoints(); - // не делаем 'const', так как для Curve может поменяться их кол-во + // не делаем 'const', так как для Curve может поменяться их кол-во int tmpNum = Points->Count(); if (!tmpNum) return; @@ -1897,7 +1967,7 @@ void __fastcall TStateMachineConnection::CalculateTextPosWithoutDraw(void) { const int tmpH = Tree->Canvas->TextHeight(TeeCharForHeight); - // центруем, если текст только по Центру + // центруем, если текст только по Центру if (FVerticalCentering && !tmpAngle) { ATextPos.y -= tmpH * tmpCount / 2; } @@ -1907,7 +1977,7 @@ void __fastcall TStateMachineConnection::CalculateTextPosWithoutDraw(void) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::DrawText(int Angle) { if (!Tree) return; @@ -1933,7 +2003,7 @@ void __fastcall TStateMachineConnection::DrawText(int Angle) { const int tmpH = Tree->Canvas->TextHeight(TeeCharForHeight); - // центруем, если текст только по Центру + // центруем, если текст только по Центру if (FVerticalCentering && !Angle) { ATextPos.y -= tmpH * tmpCount / 2; } @@ -1942,7 +2012,7 @@ void __fastcall TStateMachineConnection::DrawText(int Angle) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::FillTextColorQueue(std::deque &AColorQueue) { if (!FEvent.IsEmpty()) { AColorQueue.push_back(clBlack); @@ -1997,13 +2067,13 @@ void __fastcall TStateMachineConnection::FillTextColorQueue(std::deque & } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::DoDrawText(int tmpCount, int tmpX, int tmpOffX, int tmpY, int tmpOffY, int Angle, int tmpH) { DoDrawTextInternal(true, tmpCount, tmpX, tmpOffX, tmpY, tmpOffY, Angle, tmpH); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::DoDrawTextInternal(const bool bDraw, int tmpCount, int tmpX, int tmpOffX, int tmpY, int tmpOffY, int Angle, int tmpH) { std::dequeAColorQueue; @@ -2052,7 +2122,7 @@ void __fastcall TStateMachineConnection::DoDrawTextInternal(const bool bDraw, in const int iTextY = tmpY + tmpOffY; if (bDraw) { - // если бэкграунд, тогда только просчитываем данные + // если бэкграунд, тогда только просчитываем данные if (bNeedToDrawBackground) { AVecText.push_back(boost::make_tuple(Tree->Canvas->Font->Style.Contains(fsBold), Tree->Canvas->Font->Color, tmpS, iTextX, iTextY)); @@ -2131,12 +2201,12 @@ void __fastcall TStateMachineConnection::DoDrawTextInternal(const bool bDraw, in } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- int __fastcall TStateMachineConnection::GetTransitionIndex(void) { return Editorutils::GetConnectionIndex(this); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetTransitionIndex(int val) { if (Editorutils::SetConnectionIndex(this, val)) { if (!this->ComponentState.Contains(csLoading) && !this->ComponentState.Contains(csReading)) { @@ -2147,7 +2217,7 @@ void __fastcall TStateMachineConnection::SetTransitionIndex(int val) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetConnectionOverStyle(const TConnectionOverType AType) { if (this->FromShape && this->ToShape) { @@ -2161,14 +2231,14 @@ void __fastcall TStateMachineConnection::SetConnectionOverStyle(const TConnectio this->Points->Clear(); - // 1 точка: привязана к FromShape + // 1 точка: привязана к FromShape this->Points->Add(cpsFromPercent, 50, cpsFromPercent, 0); - // 2 точка: вне фигуры + // 2 точка: вне фигуры const int iPrevious = (this->FromShape->Y0 > this->ToShape->Y0) ? (-(this->FromShape->Y0 -this->ToShape->Y0) - 50) : -50; this->Points->Add(cpsFromPercent, 50, cpsPrevious, iPrevious); - // 3 точка: привязана к ToShape + // 3 точка: привязана к ToShape this->Points->Add(cpsToPercent, 50, cpsToPercent, 0); this->Text->VertAlign = TVertTextAlign::vtaBottom; @@ -2254,7 +2324,7 @@ void __fastcall TStateMachineConnection::SetConnectionOverStyle(const TConnectio } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetInheritanceMismatch(bool val) { if (StateMachineEditorUnit && StateMachineEditorUnit->IsInherited) { FInheritanceMismatch = val; @@ -2264,26 +2334,26 @@ void __fastcall TStateMachineConnection::SetInheritanceMismatch(bool val) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::SetSkipAutolayout(bool val) { FSkipAutolayout = val; - //this->Brush->Style = FSkipDebugging ? bsCross : bsSolid; + //this->Brush->Style = FSkipDebugging ? bsCross : bsSolid; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::DoPreparePoints(void) { const int tmpNum = Points->Count(); if (Style != csAuto) { if (Style == csCurve) { - // If curve with less than 4 points, call Setup + // If curve with less than 4 points, call Setup if (tmpNum < 4) { SetupPoints(); } } else { - // If line with less than 2 points, call Setup + // If line with less than 2 points, call Setup if (tmpNum < 2) { #ifdef _PANIC_DEBUG_ WLOG_DEBUG(L"%s> Setup points. Current point count:[%d]", this->SimpleText.c_str(), tmpNum); @@ -2296,7 +2366,7 @@ void __fastcall TStateMachineConnection::DoPreparePoints(void) { Editorutils::CalculatePointsPosition(this); - // убираем точки, которые накладываются друг на друга + // убираем точки, которые накладываются друг на друга for (int i = tmpNum - 2; i >= 0; i--) { const double dDistanceToPrev = Editorutils::DistanceBetweenPoints(Points->Item[i].X, Points->Item[i].Y, Points->Item[i + 1].X, Points->Item[i + 1].Y); @@ -2324,7 +2394,7 @@ void __fastcall TStateMachineConnection::DoPreparePoints(void) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::DoPrepareIBounds(void) { TRect tmpBounds(0, 0, 0, 0); const int tmpNum = Points->Count(); @@ -2355,13 +2425,13 @@ void __fastcall TStateMachineConnection::DoPrepareIBounds(void) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::ForceCalculateBounds(void) { UpdateAppearance(); DoPreparePoints(); - // не делаем 'const', так как для Curve может поменяться их кол-во + // не делаем 'const', так как для Curve может поменяться их кол-во int tmpNum = Points->Count(); if (!tmpNum) return; @@ -2369,17 +2439,17 @@ void __fastcall TStateMachineConnection::ForceCalculateBounds(void) { DoPrepareIBounds(); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- bool __fastcall TStateMachineConnection::IsPointInTextPolygon(const TPoint &pt) { return PointInPolygon(pt, FDrawTextData.Polygon, 3); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- bool __fastcall TStateMachineConnection::IsPointInTextPolygon(const int iX, const int iY) { return IsPointInTextPolygon(TPoint(iX, iY)); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::AssignTextPolygonToPoints(TPointCollection * APoints) { if (!APoints) return; @@ -2396,12 +2466,12 @@ void __fastcall TStateMachineConnection::AssignTextPolygonToPoints(TPointCollect APoints->EndUpdate(); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- bool __fastcall TStateMachineConnection::IsTextEmpty(void) { return !FText || FText->Text.IsEmpty(); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- UnicodeString __fastcall TStateMachineConnection::ToClipboardText(void) { std::auto_ptrAInStreamPtr(new TMemoryStream()); AInStreamPtr->WriteComponent(this); @@ -2413,13 +2483,13 @@ UnicodeString __fastcall TStateMachineConnection::ToClipboardText(void) { std::auto_ptrAConnectionListPtr(new TStringList()); AConnectionListPtr->LoadFromStream(AOutStreamPtr.get()); if (AConnectionListPtr->Count) { - AConnectionListPtr->Strings[0] = L"object " + ClassName(); // чтобы имя компонента не записывалось + AConnectionListPtr->Strings[0] = L"object " + ClassName(); // чтобы имя компонента не записывалось return AConnectionListPtr->Text; } return L""; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- bool __fastcall TStateMachineConnection::IsEditorModified(void) { if (FTransitionEditor) { return FTransitionEditor->IsModified(); @@ -2427,7 +2497,7 @@ bool __fastcall TStateMachineConnection::IsEditorModified(void) { return false; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- bool __fastcall TStateMachineConnection::IsEditorOpened(void) { if (FTransitionEditor) { return FTransitionEditor->Showing; @@ -2435,17 +2505,17 @@ bool __fastcall TStateMachineConnection::IsEditorOpened(void) { return false; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- TVisualScxmlBaseShape * __fastcall TStateMachineConnection::GetVisualFrom(void) { return dynamic_cast(this->FromShape); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- TVisualScxmlBaseShape * __fastcall TStateMachineConnection::GetVisualTo(void) { return dynamic_cast(this->ToShape); } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- bool __fastcall TStateMachineConnection::GetExcludeFromSave(void) { if (this->VisualFrom && this->VisualTo && !this->VisualFrom->ExcludeFromSave && !this->VisualTo->ExcludeFromSave) { return false; @@ -2454,7 +2524,7 @@ bool __fastcall TStateMachineConnection::GetExcludeFromSave(void) { return true; } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- void __fastcall TStateMachineConnection::FillEventNamesList(TStrings *AList) { if (this->Tree) { for (int i = 0; i < this->Tree->Shapes->Count; i++) { @@ -2483,4 +2553,4 @@ void __fastcall TStateMachineConnection::FillEventNamesList(TStrings *AList) { } } -// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- diff --git a/Src/UnitStateMachineUnit.cpp b/Src/UnitStateMachineUnit.cpp index fa3bfe0..cc29783 100644 --- a/Src/UnitStateMachineUnit.cpp +++ b/Src/UnitStateMachineUnit.cpp @@ -129,6 +129,8 @@ UnicodeString __fastcall TUnitPostSave::GetMacros(void)const { if (FUnit) { AMacrosPtr->Values["$(AppDir)"] = ExtractFileDir(Application->ExeName); + AMacrosPtr->Values["$(AppFilePath)"] = Application->ExeName; + AMacrosPtr->Values["$(AppHandle)"] = UnicodeString((int)Application->MainFormHandle); if (FUnit->StateMachineProject) { AMacrosPtr->Values["$(ProjectDir)"] = ExtractFileDir(FUnit->StateMachineProject->FilePath); @@ -139,6 +141,10 @@ UnicodeString __fastcall TUnitPostSave::GetMacros(void)const { AMacrosPtr->Values["$(UnitFileName)"] = ExtractFileName(FUnit->FilePath); AMacrosPtr->Values["$(UnitFileDir)"] = ExtractFileDir(FUnit->FilePath); AMacrosPtr->Values["$(UnitName)"] = TPath::GetFileNameWithoutExtension(FUnit->FilePath); + + if (FUnit->StateMachineDockPanel) { + AMacrosPtr->Values["$(UnitHandle)"] = UnicodeString((int)FUnit->StateMachineDockPanel->StateMachineEditor->Handle); + } } return AMacrosPtr->Text; @@ -577,8 +583,6 @@ void __fastcall TStateMachineEditorUnit::DoSave(const Lmdtypes::TLMDString AFile ASpawner.StartProcessInfinite(); DeleteFile(sTempFile); - - FormScxmlGui->SwitchToTesterLog(false); } } catch(Exception * E) { diff --git a/Src/UnitStateShape.cpp b/Src/UnitStateShape.cpp index d08b77a..2ec53b9 100644 --- a/Src/UnitStateShape.cpp +++ b/Src/UnitStateShape.cpp @@ -43,6 +43,7 @@ #include "UnitScxmlShape.h" #include "UnitPropInspectorExtensions.h" #include "UnitDialogFileNotFound.h" +#include "UnitSettings.h" // --------------------------------------------------------------------------- @@ -168,12 +169,12 @@ __fastcall TParallelShape::TParallelShape(Classes::TComponent* AOwner) : TVisual // --------------------------------------------------------------------------- TColor __fastcall TParallelShape::GetHeadColor(void) { - return TColor(0x00CAFFCA); + return SettingsData->ThemeSettings->ParallelNormalColor; } // --------------------------------------------------------------------------- TColor __fastcall TParallelShape::GetNormalColor(void) { - return TColor(0x00CAFFCA); + return SettingsData->ThemeSettings->ParallelNormalColor; } // --------------------------------------------------------------------------- @@ -542,12 +543,12 @@ void __fastcall TVirtualShape::OnGetPropEditorClass(TPersistent *AInstance, ILMD // --------------------------------------------------------------------------- TColor __fastcall TVirtualShape::GetHeadColor(void) { - return clGray; + return SettingsData->ThemeSettings->VirtualHeadColor; } // --------------------------------------------------------------------------- TColor __fastcall TVirtualShape::GetNormalColor(void) { - return clSilver; + return SettingsData->ThemeSettings->VirtualNormalColor; } // --------------------------------------------------------------------------- diff --git a/Src/UnitTestSettings.cpp b/Src/UnitTestSettings.cpp index ad9310f..c9a8d28 100644 --- a/Src/UnitTestSettings.cpp +++ b/Src/UnitTestSettings.cpp @@ -194,6 +194,7 @@ UnicodeString TTestSettings::GetExpandedCMD(UnicodeString sCMD, const UnicodeStr sCMD = StringReplace(sCMD, L"$(UnitName)", sFileNameOnly, TReplaceFlags() << rfReplaceAll); sCMD = StringReplace(sCMD, L"$(AppDir)", SettingsData->AppPath, TReplaceFlags() << rfReplaceAll); + sCMD = StringReplace(sCMD, L"$(AppFilePath)", Application->ExeName, TReplaceFlags() << rfReplaceAll); return Unicodeutils::ExpandEnvironmentStringsDef(sCMD); } @@ -254,6 +255,7 @@ void __fastcall TTestingCMDStringPropEditor::Edit(void) { ADialogPtr->EditDocSystem->AppendLine(L"%APPDATA%=" + Unicodeutils::ExpandEnvironmentStringsDef("%APPDATA%")); ADialogPtr->EditDocUser->AppendLine(L"$(AppDir)=" + SettingsData->AppPath); + ADialogPtr->EditDocUser->AppendLine(L"$(AppFilePath)=" + Application->ExeName); ADialogPtr->EditDocUser->AppendLine(L"$(UnitFilePath)=Path\\To\\ActiveUnitFileName.scxml"); ADialogPtr->EditDocUser->AppendLine(L"$(UnitFileName)=ActiveUnitFileName.scxml"); ADialogPtr->EditDocUser->AppendLine(L"$(UnitFileDir)=Path\\To"); diff --git a/Src/UnitThemeSettings.cpp b/Src/UnitThemeSettings.cpp new file mode 100644 index 0000000..d07535b --- /dev/null +++ b/Src/UnitThemeSettings.cpp @@ -0,0 +1,159 @@ +/*********************************************************************************** + BSD 3-Clause License + + Copyright (c) 2018, https://github.com/alexzhornyak + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***************************************************************************************/ +#include +#pragma hdrstop + +#include "UnitThemeSettings.h" + +#include +#include "Log4cpp_VCL.hpp" + +#include "UnitMain.h" +#include "UnitPropInspectorExtensions.h" +#include "UnitSettings.h" + +//--------------------------------------------------------------------------- + +#pragma package(smart_init) + +void RegisterThemeSettings() { +#pragma startup RegisterThemeSettings + + Classes::RegisterClassA(__classid(TThemeSettings)); +} + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +__fastcall TThemeSettings::TThemeSettings() { + FChildNormalColor = clWhite; + FChildNormalFontStyle = TFontStyles(); + FChildNormalBorderColor = g_CHILD_NORMAL_BORDER_COLOR; + FChildNormalBorderStyle = psSolid; + + FStateNormalColor = g_STATE_NORMAL_COLOR; + FStateClusterColor = clWhite; + FStateInitialBorderColor = g_STATE_INITIAL_BORDER_COLOR; + FStateExaminedBorderColor = clBlue; + FStateNormalBorderColor = clBlack; + FStateNormalBorderStyle = psSolid; + FStateNormalFontStyle = TFontStyles(); + FStateSelfConnectionInsideFontStyle = g_STATE_SELF_CONNECTION_INSIDE_FONT_STYLE; + + FScxmlNormalHeadColor = clMoneyGreen; + FScxmlDatamodelFontColor = clMaroon; + FScxmlVirtualFontColor = clBlue; + + FParallelNormalColor = g_PARALLEL_NORMAL_COLOR; + + FVirtualNormalColor = clSilver; + FVirtualHeadColor = clGray; +} + +// --------------------------------------------------------------------------- +__fastcall TThemeSettings::~TThemeSettings(void) { + +} + +// --------------------------------------------------------------------------- +void __fastcall TThemeSettings::Assign(Classes::TPersistent* Source) { + if (Source) { + // ********************************************* // + + TThemeSettings * AThemeSettings = dynamic_cast(Source); + if (AThemeSettings) { + FChildNormalColor = AThemeSettings->FChildNormalColor; + FChildNormalFontStyle = AThemeSettings->FChildNormalFontStyle; + FChildNormalBorderColor = AThemeSettings->FChildNormalBorderColor; + FChildNormalBorderStyle = AThemeSettings->FChildNormalBorderStyle; + + FStateNormalColor = AThemeSettings->FStateNormalColor; + FStateClusterColor = AThemeSettings->FStateClusterColor; + FStateInitialBorderColor = AThemeSettings->FStateInitialBorderColor; + FStateExaminedBorderColor = AThemeSettings->FStateExaminedBorderColor; + FStateNormalBorderColor = AThemeSettings->FStateNormalBorderColor; + FStateNormalBorderStyle = AThemeSettings->FStateNormalBorderStyle; + FStateNormalFontStyle = AThemeSettings->FStateNormalFontStyle; + FStateSelfConnectionInsideFontStyle = AThemeSettings->FStateSelfConnectionInsideFontStyle; + + FScxmlNormalHeadColor = AThemeSettings->FScxmlNormalHeadColor; + FScxmlDatamodelFontColor = AThemeSettings->FScxmlDatamodelFontColor; + FScxmlVirtualFontColor = AThemeSettings->FScxmlVirtualFontColor; + + FParallelNormalColor = AThemeSettings->FParallelNormalColor; + + FVirtualNormalColor = AThemeSettings->FVirtualNormalColor; + FVirtualHeadColor = AThemeSettings->FVirtualHeadColor; + + } + else + throw Exception(__FUNCTION__ "> Can not cast <" + Source->ClassName() + "> to <"+this->ClassName() + ">"); + + } + else + throw Exception(__FUNCTION__ "> Source can not be empty!"); +} + +// --------------------------------------------------------------------------- +bool __fastcall TThemeSettings::OnFilterPropEvent(const UnicodeString &sPropName) { + return true; +} + +// --------------------------------------------------------------------------- +void __fastcall TThemeSettings::OnGetPropEditorClass(TPersistent *AInstance, ILMDProperty *APropInfo, TLMDPropEditorClass &AEditorClass) { +// if (APropInfo) { +// const UnicodeString sPropName = APropInfo->Name(); +// if (sPropName == L"ExeName") { +// AEditorClass = __classid(TExternTesterExePropEditor); +// } +// } +} + +//--------------------------------------------------------------------------- +//---------------------- TThemeSettingsPropEditor ---------------------------- +//--------------------------------------------------------------------------- +Lmdtypes::TLMDString __fastcall TThemeSettingsPropEditor::GetValue(void) { + UnicodeString sText = L"Theme Settings"; + + try { + TThemeSettings *ASource = dynamic_cast(this->GetObjectValue(0)); + if (!ASource) + throw Exception("Can not cast to !"); + + } + catch(Exception * E) { + LOG_ERROR(LOG_ERROR_MSG); + } + + return sText; +} + diff --git a/Src/UnitThemeSettings.h b/Src/UnitThemeSettings.h new file mode 100644 index 0000000..a5d1108 --- /dev/null +++ b/Src/UnitThemeSettings.h @@ -0,0 +1,113 @@ +/*********************************************************************************** + BSD 3-Clause License + + Copyright (c) 2018, https://github.com/alexzhornyak + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***************************************************************************************/ + +#ifndef UnitThemeSettingsH +#define UnitThemeSettingsH +//--------------------------------------------------------------------------- + +#include "LMDInsPropEditors.hpp" + +static const TColor g_CHILD_NORMAL_BORDER_COLOR = TColor(RGB(32, 32, 32)); +static const TColor g_STATE_NORMAL_COLOR = TColor(0x00FFD680); +static const TColor g_STATE_INITIAL_BORDER_COLOR = TColor(0x000080FF); +static const TFontStyles g_STATE_SELF_CONNECTION_INSIDE_FONT_STYLE = TFontStyles() << fsUnderline; +static const int g_STATE_SELF_CONNECTION_INSIDE_FONT_STYLE_INT = 4; // Require recalculation from Int if changed !!! +static const TColor g_PARALLEL_NORMAL_COLOR = TColor(0x00CAFFCA); + +class TThemeSettings: public TPersistent { +__published: + virtual bool __fastcall OnFilterPropEvent(const UnicodeString &sPropName); + virtual void __fastcall OnGetPropEditorClass(TPersistent *AInstance, ILMDProperty *APropInfo,TLMDPropEditorClass &AEditorClass); +private: + TColor FStateNormalColor; + TColor FStateClusterColor; + TColor FStateInitialBorderColor; + TColor FStateExaminedBorderColor; + TColor FStateNormalBorderColor; + TPenStyle FStateNormalBorderStyle; + TFontStyles FStateNormalFontStyle; + TFontStyles FStateSelfConnectionInsideFontStyle; + + TColor FScxmlNormalHeadColor; + TColor FVirtualNormalColor; + TColor FVirtualHeadColor; + TColor FScxmlDatamodelFontColor; + TColor FScxmlVirtualFontColor; + + TColor FParallelNormalColor; + + TColor FChildNormalColor; + TFontStyles FChildNormalFontStyle; + TColor FChildNormalBorderColor; + TPenStyle FChildNormalBorderStyle; + +protected: + +public: + __fastcall TThemeSettings(); + virtual __fastcall ~TThemeSettings(void); + + virtual void __fastcall Assign(TPersistent* Source); + +__published: + __property TColor StateNormalColor = {read=FStateNormalColor, write=FStateNormalColor, default=g_STATE_NORMAL_COLOR}; + __property TColor StateClusterColor = {read=FStateClusterColor, write=FStateClusterColor, default=clWhite}; + __property TColor StateInitialBorderColor = {read=FStateInitialBorderColor, write=FStateInitialBorderColor, default=g_STATE_INITIAL_BORDER_COLOR}; + __property TColor StateExaminedBorderColor = {read=FStateExaminedBorderColor, write=FStateExaminedBorderColor, default=clBlue}; + __property TColor StateNormalBorderColor = {read=FStateNormalBorderColor, write=FStateNormalBorderColor, default=clBlack}; + __property TPenStyle StateNormalBorderStyle = {read=FStateNormalBorderStyle, write=FStateNormalBorderStyle, default=psSolid}; + __property TFontStyles StateNormalFontStyle = {read=FStateNormalFontStyle, write=FStateNormalFontStyle, default=0}; + __property TFontStyles StateSelfConnectionInsideFontStyle = {read=FStateSelfConnectionInsideFontStyle, write=FStateSelfConnectionInsideFontStyle, default=g_STATE_SELF_CONNECTION_INSIDE_FONT_STYLE_INT}; + + __property TColor ChildNormalColor = {read=FChildNormalColor, write=FChildNormalColor, default=clWhite}; + __property TFontStyles ChildNormalFontStyle = {read=FChildNormalFontStyle, write=FChildNormalFontStyle, default=0}; + __property TColor ChildNormalBorderColor = {read=FChildNormalBorderColor, write=FChildNormalBorderColor, default=g_CHILD_NORMAL_BORDER_COLOR}; + __property TPenStyle ChildNormalBorderStyle = {read=FChildNormalBorderStyle, write=FChildNormalBorderStyle, default=psSolid}; + + __property TColor ScxmlNormalHeadColor = {read=FScxmlNormalHeadColor, write=FScxmlNormalHeadColor, default=clMoneyGreen}; + __property TColor ScxmlDatamodelFontColor = {read=FScxmlDatamodelFontColor, write=FScxmlDatamodelFontColor, default=clMaroon}; + __property TColor ScxmlVirtualFontColor = {read=FScxmlVirtualFontColor, write=FScxmlVirtualFontColor, default=clBlue}; + + __property TColor ParallelNormalColor = {read=FParallelNormalColor, write=FParallelNormalColor, default=g_PARALLEL_NORMAL_COLOR}; + + __property TColor VirtualNormalColor = {read=FVirtualNormalColor, write=FVirtualNormalColor, default=clSilver}; + __property TColor VirtualHeadColor = {read=FVirtualHeadColor, write=FVirtualHeadColor, default=clGray}; +}; + +/* PROP EDITORS */ +//--------------------------------------------------------------------------- +class TThemeSettingsPropEditor : public TLMDClassPropEditor { +protected: + virtual Lmdtypes::TLMDString __fastcall GetValue(void); +}; + +#endif diff --git a/Src/UnitTreeEditorStateMachine.cpp b/Src/UnitTreeEditorStateMachine.cpp index 407638a..2246dc6 100644 --- a/Src/UnitTreeEditorStateMachine.cpp +++ b/Src/UnitTreeEditorStateMachine.cpp @@ -1743,6 +1743,8 @@ void __fastcall TStateMachineEditor::ConvertScxmlDataToDesign(const UnicodeStrin FLockClearUndo = true; LoadScxmlData(sScxmlData, CurrentFile); + + this->MarkModified(1, "Manual Edit", true); } __finally { FLockClearUndo = false; @@ -7615,6 +7617,356 @@ void __fastcall TStateMachineEditor::EditAppearanceClick(System::TObject* Sender this->TeeModified(true, 1, "Edit tree connections"); } +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::Edit1Click(System::TObject* Sender) { + if (TheTree->Selected->Count() > 0) { + + InternalEditTreeShapePage(this, TheTree->Selected->First(), stFormat, true, this->OnEditNodeTreeShow); + + SetToolBars(); + TeeModified(true, 1, "Shape appearance"); + } +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::OnEditNodeTreeShow(System::TObject* Sender) { + TNodeTreeEditor * ANodeTreeEditor = dynamic_cast(Sender); + if (ANodeTreeEditor) { + TTreeNodeShape *ASelected = GetSafeTreeListFirst(TheTree->Selected->Shapes); + if (ASelected) { + /* Setup Theme Colors */ + if (TScxmlShape * AScxmlShape = dynamic_cast(ASelected)) { + ANodeTreeEditor->Shape4->Brush->Color = SettingsData->ThemeSettings->ScxmlNormalHeadColor; + } + else if (TParallelShape * AParallelShape = dynamic_cast(ASelected)) { + ANodeTreeEditor->Shape4->Brush->Color = SettingsData->ThemeSettings->ParallelNormalColor; + } + else if (TVirtualShape * AVirtualShape = dynamic_cast(ASelected)) { + ANodeTreeEditor->Shape4->Brush->Color = SettingsData->ThemeSettings->VirtualNormalColor; + } + else if (TVisualScxmlBaseShape * AVisualScxmlBaseShape = dynamic_cast(ASelected)) { + ANodeTreeEditor->Shape4->Brush->Color = SettingsData->ThemeSettings->StateNormalColor; + ANodeTreeEditor->Shape5->Brush->Color = SettingsData->ThemeSettings->StateNormalBorderColor; + } + else if (TChildScxmlBaseShape * AChildScxmlBaseShape = dynamic_cast(ASelected)) { + ANodeTreeEditor->Shape4->Brush->Color = SettingsData->ThemeSettings->ChildNormalColor; + ANodeTreeEditor->Shape5->Brush->Color = SettingsData->ThemeSettings->ChildNormalBorderColor; + } + + /* All Visual Shapes */ + if (TVisualScxmlBaseShape * AVisualScxmlBaseShape = dynamic_cast(ASelected)) { + ANodeTreeEditor->ShapeClusterColor->Brush->Color = SettingsData->ThemeSettings->StateClusterColor; + ANodeTreeEditor->ShapeClusterColor->Visible = true; + ANodeTreeEditor->LabelClusterColor->Visible = true; + + /* Override Color Handlers */ + ANodeTreeEditor->Shape4->OnMouseUp = this->ThemeStateColorMouseUp; + ANodeTreeEditor->Shape5->OnMouseUp = this->ThemeBorderNormalColorMouseUp; + ANodeTreeEditor->ShapeClusterColor->OnMouseUp = this->ThemeStateClusterColorMouseUp; + ANodeTreeEditor->Button1->OnClick = this->ThemeBorderClick; + } + else { + ANodeTreeEditor->ShapeClusterColor->Visible = false; + ANodeTreeEditor->LabelClusterColor->Visible = false; + } + + /* All Child Shapes */ + if (TChildScxmlBaseShape * AChildScxmlBaseShape = dynamic_cast(ASelected)) { + /* Override Color Handlers */ + ANodeTreeEditor->Shape4->OnMouseUp = this->ThemeStateColorMouseUp; + ANodeTreeEditor->Shape5->OnMouseUp = this->ThemeBorderNormalColorMouseUp; + ANodeTreeEditor->Button1->OnClick = this->ThemeBorderClick; + } + } + } +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::ThemeStateColorMouseUp(System::TObject* Sender, Controls::TMouseButton Button, + Classes::TShiftState Shift, int X, int Y) { + + TShape * AShape = dynamic_cast(Sender); + if (AShape) { + TTreeNodeShape *ASelected = GetSafeTreeListFirst(TheTree->Selected->Shapes); + if (ASelected) { + + TColor AOldColor = AShape->Brush->Color; + TColor ANewColor = EditColor(this, AOldColor); + if (AOldColor != ANewColor) { + AShape->Brush->Color = ANewColor; + + if (TScxmlShape * AScxmlShape = dynamic_cast(ASelected)) { + SettingsData->ThemeSettings->ScxmlNormalHeadColor = ANewColor; + } + else if (TParallelShape * AParallelShape = dynamic_cast(ASelected)) { + SettingsData->ThemeSettings->ParallelNormalColor = ANewColor; + } + else if (TVirtualShape * AVirtualShape = dynamic_cast(ASelected)) { + SettingsData->ThemeSettings->VirtualNormalColor = ANewColor; + } + else if (TVisualScxmlBaseShape * AVisualScxmlBaseShape = dynamic_cast(ASelected)) { + SettingsData->ThemeSettings->StateNormalColor = ANewColor; + } + else if (TChildScxmlBaseShape * AChildScxmlBaseShape = dynamic_cast(ASelected)) { + SettingsData->ThemeSettings->ChildNormalColor = ANewColor; + } + } + } + } +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::ThemeStateClusterColorMouseUp(System::TObject* Sender, Controls::TMouseButton Button, + Classes::TShiftState Shift, int X, int Y) { + + TShape * AShape = dynamic_cast(Sender); + if (AShape) { + TTreeNodeShape *ASelected = GetSafeTreeListFirst(TheTree->Selected->Shapes); + if (ASelected) { + + TColor AOldColor = AShape->Brush->Color; + TColor ANewColor = EditColor(this, AOldColor); + if (AOldColor != ANewColor) { + AShape->Brush->Color = ANewColor; + + if (TVisualScxmlBaseShape * AVisualScxmlBaseShape = dynamic_cast(ASelected)) { + SettingsData->ThemeSettings->StateClusterColor = ANewColor; + } + } + } + } +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::ThemeBorderNormalColorMouseUp(System::TObject* Sender, Controls::TMouseButton Button, + Classes::TShiftState Shift, int X, int Y) { + + TShape * AShape = dynamic_cast(Sender); + if (AShape) { + TTreeNodeShape *ASelected = GetSafeTreeListFirst(TheTree->Selected->Shapes); + if (ASelected) { + + TColor AOldColor = AShape->Brush->Color; + TColor ANewColor = EditColor(this, AOldColor); + if (AOldColor != ANewColor) { + AShape->Brush->Color = ANewColor; + + if (TVisualScxmlBaseShape * AVisualScxmlBaseShape = dynamic_cast(ASelected)) { + SettingsData->ThemeSettings->StateNormalBorderColor = ANewColor; + } + else if (TChildScxmlBaseShape * AChildScxmlBaseShape = dynamic_cast(ASelected)) { + SettingsData->ThemeSettings->ChildNormalBorderColor = ANewColor; + } + } + } + } +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::ThemeBorderClick(System::TObject* Sender) { + TTreeNodeShape *ASelected = GetSafeTreeListFirst(TheTree->Selected->Shapes); + if (ASelected) { + + std::auto_ptrAChartPenPtr(new TChartPen((TNotifyEvent)NULL)); + AChartPenPtr->Assign(ASelected->Border); + + if (TVisualScxmlBaseShape * AVisualScxmlBaseShape = dynamic_cast(ASelected)) { + AChartPenPtr->Color = SettingsData->ThemeSettings->StateNormalBorderColor; + AChartPenPtr->Style = SettingsData->ThemeSettings->StateNormalBorderStyle; + } + else if (TChildScxmlBaseShape * AChildScxmlBaseShape = dynamic_cast(ASelected)) { + AChartPenPtr->Color = SettingsData->ThemeSettings->ChildNormalBorderColor; + AChartPenPtr->Style = SettingsData->ThemeSettings->ChildNormalBorderStyle; + } + + if (EditChartPen(this, AChartPenPtr.get())) { + if (TVisualScxmlBaseShape * AVisualScxmlBaseShape = dynamic_cast(ASelected)) { + SettingsData->ThemeSettings->StateNormalBorderColor = AChartPenPtr->Color; + } + else if (TChildScxmlBaseShape * AChildScxmlBaseShape = dynamic_cast(ASelected)) { + SettingsData->ThemeSettings->ChildNormalBorderColor = AChartPenPtr->Color; + } + else { + for (int i = 1; i < TheTree->Selected->Count(); i++) { + TheTree->Selected->Items[i]->Border->Assign(AChartPenPtr.get()); + } + } + + TNodeTreeEditor * ANodeTreeEditor = dynamic_cast(dynamic_cast(Sender)->Owner); + if (ANodeTreeEditor) { + ANodeTreeEditor->Shape5->Brush->Color = AChartPenPtr->Color; + } + } + } +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::ExecuteInterprocessCommand(INTERPROCESS_COPYDATA *ACopyData) { + if (SameText(ACopyData->wchCommand, L"SaveToSVG")) { + this->SaveToSVG(ACopyData->wchArg1); + } + else if (SameText(ACopyData->wchCommand, L"SaveRawScxmlToFile")) { + this->SaveRawScxmlToFile(ACopyData->wchArg1); + } + else if (SameText(ACopyData->wchCommand, L"SaveRawScxmlToHPP")) { + this->SaveRawScxmlToHPP(ACopyData->wchArg1); + } + else if (SameText(ACopyData->wchCommand, L"SaveScxmlToPas")) { + this->SaveScxmlToPas(ACopyData->wchArg1); + } + else if (SameText(ACopyData->wchCommand, L"SaveToDot")) { + this->SaveToDot(ACopyData->wchArg1); + } + else if (SameText(ACopyData->wchCommand, L"SaveToDotPlusPng")) { + this->SaveToDotPlusPng(ACopyData->wchArg1); + } + else if (SameText(ACopyData->wchCommand, L"SaveToBMP")) { + this->SaveToBMP(ACopyData->wchArg1); + } + else if (SameText(ACopyData->wchCommand, L"SaveToPNG")) { + this->SaveToPNG(ACopyData->wchArg1); + } +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::OnMsgCopyData(TWMCopyData &msg) { + if (msg.CopyDataStruct && msg.CopyDataStruct->cbData == sizeof(INTERPROCESS_COPYDATA)) { + INTERPROCESS_COPYDATA *ACopyData = reinterpret_cast(msg.CopyDataStruct->lpData); + if (ACopyData) { + WLOG_INFO(L"EDITOR> Copy data command:[%s] arg1:[%s] arg2:[%s] arg3:[%s]", // + ACopyData->wchCommand, ACopyData->wchArg1, ACopyData->wchArg2, ACopyData->wchArg3); + + try { + this->ExecuteInterprocessCommand(ACopyData); + } + catch(Exception * E) { + WLOG_ERROR(L"EDITOR_COMMAND> %s", E->Message.c_str()); + } + } + } + else { + WLOG_ERROR(L"Invalid WM_COPYDATA"); + } +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::SaveToBMP(const UnicodeString &sFileName) { + TScxmlShape *AScxmlRootShape = this->RootScxml; + if (AScxmlRootShape) { + const int i_OFFSET = 3; + + const int iOldHoriz = TheTree->View3DOptions->HorizOffset; + const int iOldVert = TheTree->View3DOptions->VertOffset; + + const bool bWasFocusDisabled = TheTreeEx->DisableFocus; + TheTreeEx->DisableFocus = true; + + try { + TheTreeEx->View3DOptions->HorizOffset = 0; + TheTreeEx->View3DOptions->VertOffset = 0; + const TRect ARectSource(0, 0, AScxmlRootShape->X1 + i_OFFSET, AScxmlRootShape->Y1 + i_OFFSET); + + std::auto_ptrABmpSourcePtr(TheTreeEx->TeeCreateBitmap(clWhite, ARectSource)); + + ABmpSourcePtr->SaveToFile(sFileName); + } + __finally { + TheTreeEx->DisableFocus = bWasFocusDisabled; + TheTreeEx->View3DOptions->HorizOffset = iOldHoriz; + TheTreeEx->View3DOptions->VertOffset = iOldVert; + } + } +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::SaveToPNG(const UnicodeString &sFileName) { + TScxmlShape *AScxmlRootShape = this->RootScxml; + if (AScxmlRootShape) { + const int i_OFFSET = 3; + + const int iOldHoriz = TheTree->View3DOptions->HorizOffset; + const int iOldVert = TheTree->View3DOptions->VertOffset; + + const bool bWasFocusDisabled = TheTreeEx->DisableFocus; + TheTreeEx->DisableFocus = true; + + try { + TheTreeEx->View3DOptions->HorizOffset = 0; + TheTreeEx->View3DOptions->VertOffset = 0; + const TRect ARectSource(0, 0, AScxmlRootShape->X1 + i_OFFSET, AScxmlRootShape->Y1 + i_OFFSET); + + std::auto_ptrABmpSourcePtr(TheTreeEx->TeeCreateBitmap(clWhite, ARectSource)); + + const UnicodeString sValue = SettingsData->TempRegistry->Values[this->Name + ".SpinPNGCompressionLevel"]; + + std::auto_ptrAPngImagePtr(new TPngImage()); + APngImagePtr->Assign(ABmpSourcePtr.get()); + APngImagePtr->CompressionLevel = sValue.ToIntDef(7); + APngImagePtr->SaveToFile(sFileName); + } + __finally { + TheTreeEx->DisableFocus = bWasFocusDisabled; + TheTreeEx->View3DOptions->HorizOffset = iOldHoriz; + TheTreeEx->View3DOptions->VertOffset = iOldVert; + } + } +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::SaveRawScxmlToFile(const UnicodeString & sFileName) { + const Statemachine::TIterateSaveTypes ATypes = SettingsData->SkipCommentsInRawScxml == false ? Statemachine::MaxPossibleTypes() : + (Statemachine::MaxPossibleTypes() >> Statemachine::istComments); + + Statemachine::SaveTreeToScxml(TheTree, sFileName, false, true, ATypes); +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::SaveRawScxmlToHPP(const UnicodeString & sFileName) { + std::auto_ptrAStringList(new TStringList()); + AStringList->Text = Statemachine::GetRawScxml(TheTree, SettingsData->SkipCommentsInRawScxml); + + TStateMachineEditor::ConvertTextToHPP(AStringList.get(), TPath::GetFileNameWithoutExtension(sFileName)); + + AStringList->SaveToFile(sFileName); +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::SaveScxmlToPas(const UnicodeString & sFileName) { + std::auto_ptrAMemoryStreamPtr(new TMemoryStream()); + SaveTreeToStream(TheTree, AMemoryStreamPtr.get()); + + std::auto_ptrAOutStreamPtr(new TMemoryStream()); + + AMemoryStreamPtr->Position = 0; + ObjectBinaryToText(AMemoryStreamPtr.get(), AOutStreamPtr.get()); + AOutStreamPtr->Position = 0; + + AOutStreamPtr->SaveToFile(sFileName); + + WLOG_INFO(L"Successfully saved <%s>!", sFileName.c_str()); +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::SaveToDot(const UnicodeString &sFileName) { + std::auto_ptrADialogWaitPtr(new TDialogWait(this)); + ADialogWaitPtr->ShowDialog(UnicodeString().sprintf(L"Exporting to DOT[%s] ...", ExtractFileName(sFileName).c_str())); + Graphviz::ExportToDot(TheTree, sFileName); + WLOG_INFO(L"Successfully saved <%s>", sFileName.c_str()); +} + +// --------------------------------------------------------------------------- +void __fastcall TStateMachineEditor::SaveToDotPlusPng(const UnicodeString &sFileName) { + std::auto_ptrADialogWaitPtr(new TDialogWait(this)); + ADialogWaitPtr->ShowDialog(UnicodeString().sprintf(L"Exporting to DOT[%s] ...", ExtractFileName(sFileName).c_str())); + Graphviz::ExportToDot(TheTree, sFileName); + WLOG_INFO(L"Successfully saved <%s>", sFileName.c_str()); + + const UnicodeString sFilePng = ChangeFileExt(sFileName, L".png"); + ADialogWaitPtr->ShowDialog(UnicodeString().sprintf(L"Exporting to PNG[%s] ...", ExtractFileName(sFilePng).c_str())); + Graphviz::ConvertDotToPng(sFileName, sFilePng); + WLOG_INFO(L"Successfully converted <%s> to <%s>", sFileName.c_str(), sFilePng.c_str()); +} + // --------------------------------------------------------------------------- // -------------------- TStateMachineDockPanel ----------------------------- // --------------------------------------------------------------------------- @@ -8197,40 +8549,6 @@ UnicodeString __fastcall TStateMachineDockPanel::GetRawScxmlForceComments() { return Statemachine::GetRawScxml(FStateMachineEditor->TheTree, false /* do not skip comments */); } -// --------------------------------------------------------------------------- -void __fastcall TStateMachineDockPanel::SaveRawScxmlToFile(const UnicodeString & sFileName) { - const Statemachine::TIterateSaveTypes ATypes = SettingsData->SkipCommentsInRawScxml == false ? Statemachine::MaxPossibleTypes() : - (Statemachine::MaxPossibleTypes() >> Statemachine::istComments); - - Statemachine::SaveTreeToScxml(FStateMachineEditor->TheTree, sFileName, false, true, ATypes); -} - -// --------------------------------------------------------------------------- -void __fastcall TStateMachineDockPanel::SaveRawScxmlToHPP(const UnicodeString & sFileName) { - std::auto_ptrAStringList(new TStringList()); - AStringList->Text = RawScxml; - - TStateMachineEditor::ConvertTextToHPP(AStringList.get(), TPath::GetFileNameWithoutExtension(sFileName)); - - AStringList->SaveToFile(sFileName); -} - -// --------------------------------------------------------------------------- -void __fastcall TStateMachineDockPanel::SaveScxmlToPas(const UnicodeString & sFileName) { - std::auto_ptrAMemoryStreamPtr(new TMemoryStream()); - SaveTreeToStream(FStateMachineEditor->TheTree, AMemoryStreamPtr.get()); - - std::auto_ptrAOutStreamPtr(new TMemoryStream()); - - AMemoryStreamPtr->Position = 0; - ObjectBinaryToText(AMemoryStreamPtr.get(), AOutStreamPtr.get()); - AOutStreamPtr->Position = 0; - - AOutStreamPtr->SaveToFile(sFileName); - - WLOG_INFO(L"Successfully saved <%s>!", sFileName.c_str()); -} - // --------------------------------------------------------------------------- std::pair__fastcall TStateMachineDockPanel::EnterStateNode(const UnicodeString & sId, const bool bEntered, const bool bOpenClosedUnits) { diff --git a/Src/UnitTreeEditorStateMachine.h b/Src/UnitTreeEditorStateMachine.h index e44d8a1..86015fd 100644 --- a/Src/UnitTreeEditorStateMachine.h +++ b/Src/UnitTreeEditorStateMachine.h @@ -118,7 +118,8 @@ class TStateMachineEditor : public TTreeEditorEx { void __fastcall TabControl1Change(System::TObject* Sender); - virtual void __fastcall EditAppearanceClick(System::TObject* Sender); + virtual void __fastcall EditAppearanceClick(System::TObject* Sender); + virtual void __fastcall Edit1Click(System::TObject* Sender); private: /* VARIABLES */ @@ -322,6 +323,12 @@ class TStateMachineEditor : public TTreeEditorEx { void __fastcall OnMenuChartVersion(System::TObject* Sender); void __fastcall OnMenuChartStatistics(System::TObject* Sender); + void __fastcall OnEditNodeTreeShow(System::TObject* Sender); + void __fastcall ThemeStateColorMouseUp(System::TObject* Sender, Controls::TMouseButton Button, Classes::TShiftState Shift, int X, int Y); + void __fastcall ThemeStateClusterColorMouseUp(System::TObject* Sender, Controls::TMouseButton Button, Classes::TShiftState Shift, int X, int Y); + void __fastcall ThemeBorderNormalColorMouseUp(System::TObject* Sender, Controls::TMouseButton Button, Classes::TShiftState Shift, int X, int Y); + void __fastcall ThemeBorderClick(System::TObject* Sender); + void __fastcall CheckImageAdvancedDrawItem(TObject *Sender, TCanvas *ACanvas, const TRect &ARect, TOwnerDrawState State); std::mapFShapeImagesMap; @@ -512,10 +519,14 @@ class TStateMachineEditor : public TTreeEditorEx { void __fastcall OnActionConnectionHighlightExecute(TObject *Sender); void __fastcall OnActionConnectionHighlightUpdate(TObject *Sender); + void __fastcall ExecuteInterprocessCommand(INTERPROCESS_COPYDATA *ACopyData); + void __fastcall OnMsgDeleteTreeShape(TMessage &AMsg); + void __fastcall OnMsgCopyData(TWMCopyData &msg); BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(WM_SCXML_DELETE_TREE_SHAPE, TMessage, OnMsgDeleteTreeShape) + VCL_MESSAGE_HANDLER(WM_COPYDATA, TWMCopyData, OnMsgCopyData) END_MESSAGE_MAP(TTreeEditorEx) public: @@ -557,6 +568,16 @@ class TStateMachineEditor : public TTreeEditorEx { void __fastcall SaveToSVG(TStringList *AOutputList, TTreeNodeShape *ARootShape = NULL); void __fastcall SaveToSVG(const UnicodeString &sFileName, TTreeNodeShape *ARootShape = NULL); + void __fastcall SaveRawScxmlToFile(const UnicodeString &sFileName); + void __fastcall SaveRawScxmlToHPP(const UnicodeString &sFileName); + void __fastcall SaveScxmlToPas(const UnicodeString &sFileName); + + void __fastcall SaveToDot(const UnicodeString &sFileName); + void __fastcall SaveToDotPlusPng(const UnicodeString &sFileName); + + void __fastcall SaveToBMP(const UnicodeString &sFileName); + void __fastcall SaveToPNG(const UnicodeString &sFileName); + void __fastcall GetDataIDs(TStrings *AIDList); void __fastcall GetStateNames(TStrings *AStateNamesList); @@ -681,10 +702,6 @@ class TStateMachineDockPanel : public TLMDDockPanel { void __fastcall ClearAllBreakpoints(void); - void __fastcall SaveRawScxmlToFile(const UnicodeString &sFileName); - void __fastcall SaveRawScxmlToHPP(const UnicodeString &sFileName); - void __fastcall SaveScxmlToPas(const UnicodeString &sFileName); - void __fastcall UpdateCaption(void); void __fastcall UpdateSyntaxView(void);