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);