Consolidate Python ignore rules into root gitignore
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
# MQL5 Expert Advisor 開発指示書
|
||||
|
||||
あなたはMQL5のシニアエンジニアであり、同時に定量的リスク管理の専門家です。常に**『バックテストの再現性』と『ライブ実行時のエラー耐性』**を最優先に考えた回答をしてください。
|
||||
|
||||
## 1. 基本設計方針
|
||||
- **言語:** MQL5 (C++ベース)
|
||||
- **標準ライブラリの優先:** `Trade\Trade.mqh` の `CTrade` クラスを積極的に使用し、注文処理(OrderSend)を簡略化・安全化すること。
|
||||
- **イベント駆動:** `OnInit`, `OnDeinit`, `OnTick` などのイベントハンドラを適切に使用すること。
|
||||
|
||||
## 2. コーディングスタイル
|
||||
- **命名規則:**
|
||||
- 外部パラメータ(input)は `input_` または `inp` を接頭辞につける。
|
||||
- グローバル変数は `g_`、メンバ変数は `m_` をつける。
|
||||
- **エラーハンドリング:** - 注文実行時やインジケータハンドル作成時は、必ず戻り値をチェックし、失敗した場合は `GetLastError()` を用いてログ出力(Print)すること。
|
||||
- **最適化:** - 重い処理は `OnTick` ではなく `OnInit` や特定の足が確定したタイミングで行うように工夫すること。
|
||||
|
||||
## 3. 重要事項
|
||||
- **マジックナンバー:** EAごとに固有の `input int MagicNumber` を定義し、注文時に必ず使用すること。
|
||||
- **シンボル/期間:** `_Symbol` および `_Period` を使用し、汎用性を持たせること。
|
||||
- **コメント:** コードの重要セクションには、ロジックを説明する英語のコメントを付与すること。
|
||||
|
||||
## 4. 禁止事項
|
||||
- MQL4の古い関数(OrderSendの旧形式など)は絶対に使用しないこと。
|
||||
- バックテストのパフォーマンスを著しく低下させる無駄なループ処理を避けること。
|
||||
|
||||
## 5. ドキュメント管理規則 (Documentation & Specifications)
|
||||
- **フォルダ構成:** プロジェクトルートに `docs` フォルダを維持し、各EA/インジケータに対応する仕様書(Markdown形式)を格納すること。
|
||||
- **ファイル命名:** 仕様書は英語版と日本語版を両方作成し、以下の形式で区別すること:
|
||||
- 日本語版:`{プログラム名}_spec_ja.md`
|
||||
- 英語版:`{プログラム名}_spec_en.md`
|
||||
- **新規作成時のルール:** - 新しいEAまたはインジケータを作成する際は、コードを書く前、あるいは同時に `docs/` 内に日本語版と英語版の両方の仕様書を生成すること。
|
||||
- **修正時の同期ルール:** - プログラムのロジック、外部パラメータ(input)、または重要な関数を変更した際は、必ず対応する `docs/{プログラム名}_spec_ja.md` および `docs/{プログラム名}_spec_en.md` を読み込み、修正内容を反映させること。
|
||||
- 修正の際は「変更履歴(Changelog)」セクションを仕様書末尾に設け、日付と修正概要を記録すること。
|
||||
|
||||
## 6. 仕様書の標準構成案
|
||||
仕様書を作成する際は、以下の項目を含めること:
|
||||
1. **概要**: プログラムの目的と動作概要。
|
||||
2. **使用インジケータ**: 依存している標準・カスタムインジケータ。
|
||||
3. **パラメータ設定**: `input` 変数の説明、デフォルト値、設定の意味。
|
||||
4. **エントリー/エグジット条件**: ロジックの詳細(文章および箇条書き)。
|
||||
5. **リスク管理**: マジックナンバー、ロット計算、ストップロス等の仕様。
|
||||
6. **変更履歴**: 日付、修正箇所、修正理由。
|
||||
|
||||
## 7. フォルダ構成と再利用性のルール
|
||||
### 7.1 プロジェクト単位のフォルダ管理
|
||||
- **プロジェクトフォルダ:** 各EA/インジケータは `Experts/MyProject/`、`Indicators/MyProject/` のようにプロジェクト名でフォルダを作成し、その中に関連ファイルを配置すること。
|
||||
- **仕様書の配置:** 対応する仕様書は `docs/MyProject/` 内に格納すること。
|
||||
|
||||
### 7.2 標準フォルダ構成
|
||||
```
|
||||
MQL5/
|
||||
├── Experts/
|
||||
│ └── MyProject/ # プロジェクトごとのフォルダ
|
||||
│ ├── MyEA.mq5 # メインソース
|
||||
│ └── MyEA.mqh # (オプション) EA固有のヘッダー
|
||||
├── Indicators/
|
||||
│ └── MyProject/ # 関連するカスタムインジケータ
|
||||
│ └── MySignal.mq5
|
||||
├── Include/
|
||||
│ └── MyLib/ # 【重要】自作ライブラリの本拠地
|
||||
│ ├── Common/ # 汎用ツール(時間操作、ログ、配列操作など)
|
||||
│ │ └── TimeUtils.mqh
|
||||
│ ├── Trading/ # トレードロジック(資金管理、注文処理)
|
||||
│ │ └── RiskManager.mqh
|
||||
│ ├── Signals/ # 売買サイン判定ロジック
|
||||
│ │ └── CrossLogic.mqh
|
||||
│ └── Wrapper/ # 標準ライブラリの拡張
|
||||
│ └── MyTrade.mqh
|
||||
├── Scripts/
|
||||
│ └── Utilities/ # 一括決済などの便利ツール
|
||||
├── docs/ # 仕様書フォルダ
|
||||
│ └── MyProject/
|
||||
│ ├── MyEA_spec_ja.md # 日本語仕様書
|
||||
│ └── MyEA_spec_en.md # 英語仕様書
|
||||
└── .github/ # Copilot指示書など
|
||||
└── copilot-instructions.md
|
||||
```
|
||||
|
||||
### 7.3 再利用性のルール
|
||||
- **共通ロジックの配置:** 複数のプロジェクトで利用可能なロジックは、必ず `Include/MyLib/` 内の適切なサブフォルダにクラスまたは関数として定義すること。
|
||||
- `Common/`: 汎用ユーティリティ(時間、ログ、配列操作など)
|
||||
- `Trading/`: トレード関連(資金管理、注文処理、ポジション管理など)
|
||||
- `Signals/`: 売買サイン判定ロジック
|
||||
- `Wrapper/`: 標準ライブラリの拡張クラス
|
||||
- **EAの構成:** `Experts/` 内の `.mq5` ファイルはエントリーポイントとしての役割に専念させ、具体的なロジックは `Include/MyLib/` 側のヘッダーファイルをインクルードして呼び出す形式をとること。
|
||||
- **依存関係の解決:** 新しいファイルを作成する際は、既存の `Include/MyLib/` 内にある自作ライブラリを優先的に再利用するよう提案すること。
|
||||
|
||||
## 8. 自動コンパイルとバグ修正フロー
|
||||
- **対象:** 新規作成または修正した `.mq5` / `.mqh` ファイル。
|
||||
- **実行手段:** まず VSCode の MQL Tools のコンパイル機能を優先して使用し、環境要件や自動化の都合で難しい場合は `metaeditor64.exe /compile` を使用すること。
|
||||
- **必須ループ:** 「実装 → コンパイル → ログ確認 → 修正」を繰り返し、`0 errors, 0 warnings` を満たすまで作業を継続すること。
|
||||
- **ログ管理:** コンパイルログは `MQL5/Logs/compile_{ProgramName}.log` に保存し、修正時は直近ログを根拠に対応すること。
|
||||
- **修正優先度:** コンパイルエラーを最優先で解消し、その後に警告を解消すること。
|
||||
- **完了条件:** ①コンパイル成功、②主要ロジックの整合性確認、③仕様書(`_spec_ja.md` / `_spec_en.md`)への反映。
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
# ==============================================================================
|
||||
# MQL5 Project .gitignore
|
||||
# ==============================================================================
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Compiled Files (コンパイル済みファイル)
|
||||
# ------------------------------------------------------------------------------
|
||||
*.ex4
|
||||
*.ex5
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Logs and Temporary Files (ログと一時ファイル)
|
||||
# ------------------------------------------------------------------------------
|
||||
*.log
|
||||
Logs/
|
||||
*/Logs/
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Tester and Profiles (テスターとプロファイル)
|
||||
# ------------------------------------------------------------------------------
|
||||
Tester/
|
||||
*/Tester/
|
||||
Profiles/
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Runtime Generated Files (実行時生成ファイル)
|
||||
# ------------------------------------------------------------------------------
|
||||
Files/
|
||||
Images/
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Standard MT5 Folders (標準MT5フォルダ - 除外)
|
||||
# ------------------------------------------------------------------------------
|
||||
# Market downloads
|
||||
Market/
|
||||
*/Market/
|
||||
|
||||
# Standard examples
|
||||
Examples/
|
||||
Experts/Examples/
|
||||
Indicators/Examples/
|
||||
Scripts/Examples/
|
||||
|
||||
# Standard advisors
|
||||
Experts/Advisors/
|
||||
|
||||
# Free robots and indicators
|
||||
Experts/Free Robots/
|
||||
Indicators/Free Indicators/
|
||||
|
||||
# Standard libraries (Include配下の標準ライブラリは含めるが、サブフォルダのMarket等は除外)
|
||||
Include/*/Market/
|
||||
Include/*/Examples/
|
||||
|
||||
# Services
|
||||
Services/
|
||||
|
||||
# Shared Projects
|
||||
Shared Projects/
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Third-party Packages (サードパーティパッケージ)
|
||||
# ------------------------------------------------------------------------------
|
||||
# OANDA packages
|
||||
Indicators/oanda_basic_package/
|
||||
Indicators/oanda_lab/
|
||||
Indicators/oanda_lab_new/
|
||||
|
||||
# Market indicators/experts (root level ex5 files)
|
||||
Indicators/*.ex5
|
||||
Experts/*.ex5
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Editor and IDE (エディタとIDE設定)
|
||||
# ------------------------------------------------------------------------------
|
||||
.history/
|
||||
.vscode/ipch/
|
||||
.vscode/msvc.json
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# OS Specific (OS固有ファイル)
|
||||
# ------------------------------------------------------------------------------
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Windows
|
||||
Thumbs.db
|
||||
desktop.ini
|
||||
experts.dat
|
||||
*.lnk
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Python Project (python_for_ea)
|
||||
# ------------------------------------------------------------------------------
|
||||
# Python bytecode and C extensions
|
||||
python_for_ea/**/__pycache__/
|
||||
python_for_ea/**/*.py[cod]
|
||||
python_for_ea/**/*$py.class
|
||||
python_for_ea/**/*.so
|
||||
|
||||
# Virtual environments
|
||||
python_for_ea/**/.venv/
|
||||
python_for_ea/**/venv/
|
||||
python_for_ea/**/env/
|
||||
python_for_ea/**/ENV/
|
||||
|
||||
# Environment variables
|
||||
python_for_ea/**/.env
|
||||
python_for_ea/**/.env.*
|
||||
!python_for_ea/**/.env.example
|
||||
|
||||
# Python package and build outputs
|
||||
python_for_ea/**/build/
|
||||
python_for_ea/**/dist/
|
||||
python_for_ea/**/*.egg-info/
|
||||
python_for_ea/**/.eggs/
|
||||
python_for_ea/**/*.egg
|
||||
|
||||
# Test, coverage, type-checker, and linter caches
|
||||
python_for_ea/**/.pytest_cache/
|
||||
python_for_ea/**/.coverage
|
||||
python_for_ea/**/.coverage.*
|
||||
python_for_ea/**/htmlcov/
|
||||
python_for_ea/**/.tox/
|
||||
python_for_ea/**/.nox/
|
||||
python_for_ea/**/.mypy_cache/
|
||||
python_for_ea/**/.pyright/
|
||||
python_for_ea/**/.ruff_cache/
|
||||
python_for_ea/**/.ty/
|
||||
|
||||
# Jupyter, editor, local output, and database files
|
||||
python_for_ea/**/.ipynb_checkpoints/
|
||||
python_for_ea/**/.vscode/
|
||||
python_for_ea/**/.idea/
|
||||
python_for_ea/**/*.code-workspace
|
||||
python_for_ea/**/logs/
|
||||
python_for_ea/**/data/
|
||||
python_for_ea/**/output/
|
||||
python_for_ea/**/outputs/
|
||||
python_for_ea/**/tmp/
|
||||
python_for_ea/**/temp/
|
||||
python_for_ea/**/.cache/
|
||||
python_for_ea/**/*.db
|
||||
python_for_ea/**/*.sqlite
|
||||
python_for_ea/**/*.sqlite3
|
||||
python_for_ea/**/.streamlit/secrets.toml
|
||||
|
||||
# Excel / Office temporary files
|
||||
python_for_ea/**/~$*.xlsx
|
||||
python_for_ea/**/~$*.xls
|
||||
python_for_ea/**/~$*.csv
|
||||
|
||||
# uv.lock is intentionally not ignored so reproducible environments can be tracked.
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# VS Code AI Rules (VSCode AI設定)
|
||||
# ------------------------------------------------------------------------------
|
||||
.github/instructions/codacy.instructions.md
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# MQL Clangd Settings
|
||||
# ------------------------------------------------------------------------------
|
||||
.clangd
|
||||
.clang-format
|
||||
.cache/
|
||||
|
||||
# ==============================================================================
|
||||
# Keep Custom Projects (自作プロジェクトは含める)
|
||||
# ==============================================================================
|
||||
# !Experts/YourProjectName/
|
||||
# !Indicators/YourProjectName/
|
||||
# !Include/MyLib/
|
||||
# !Scripts/Utilities/
|
||||
# !docs/
|
||||
# !README.md
|
||||
# !.github/copilot-instructions.md
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"C_Cpp.default.includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/Include"
|
||||
],
|
||||
"C_Cpp.default.compilerPath": "",
|
||||
"C_Cpp.default.intelliSenseMode": "gcc-x64",
|
||||
"C_Cpp.errorSquiggles": "disabled",
|
||||
"C_Cpp.autocompleteAddParentheses": true,
|
||||
"files.exclude": {
|
||||
"**/*.ex4": true,
|
||||
"**/*.ex5": true,
|
||||
"**/*_@!!@.mq4": true,
|
||||
"**/*_@!!@.mq5": true,
|
||||
"**/*_@!!@.mqh": true,
|
||||
"**/*_@!!@.log": true
|
||||
},
|
||||
"files.associations": {
|
||||
"*.mqh": "cpp",
|
||||
"*.mq4": "cpp",
|
||||
"*.mq5": "cpp"
|
||||
},
|
||||
"editor.tabSize": 3,
|
||||
"C_Cpp.default.forcedInclude": [
|
||||
"c:\\Users\\new\\.vscode\\extensions\\l-i-v.mql-tools-2.2.0\\data\\mql5_en.mqh"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
# MQL5 Expert Advisor 開発指示書
|
||||
|
||||
あなたはMQL5のシニアエンジニアであり、同時に定量的リスク管理の専門家です。常に**『バックテストの再現性』と『ライブ実行時のエラー耐性』**を最優先に考えた回答をしてください。
|
||||
|
||||
## 1. 基本設計方針
|
||||
- **言語:** MQL5 (C++ベース)
|
||||
- **標準ライブラリの優先:** `Trade\Trade.mqh` の `CTrade` クラスを積極的に使用し、注文処理(OrderSend)を簡略化・安全化すること。
|
||||
- **イベント駆動:** `OnInit`, `OnDeinit`, `OnTick` などのイベントハンドラを適切に使用すること。
|
||||
|
||||
## 2. コーディングスタイル
|
||||
- **命名規則:**
|
||||
- 外部パラメータ(input)は `input_` または `inp` を接頭辞につける。
|
||||
- グローバル変数は `g_`、メンバ変数は `m_` をつける。
|
||||
- **エラーハンドリング:** - 注文実行時やインジケータハンドル作成時は、必ず戻り値をチェックし、失敗した場合は `GetLastError()` を用いてログ出力(Print)すること。
|
||||
- **最適化:** - 重い処理は `OnTick` ではなく `OnInit` や特定の足が確定したタイミングで行うように工夫すること。
|
||||
|
||||
## 3. 重要事項
|
||||
- **マジックナンバー:** EAごとに固有の `input int MagicNumber` を定義し、注文時に必ず使用すること。
|
||||
- **シンボル/期間:** `_Symbol` および `_Period` を使用し、汎用性を持たせること。
|
||||
- **コメント:** コードの重要セクションには、ロジックを説明する英語のコメントを付与すること。
|
||||
|
||||
## 4. 禁止事項
|
||||
- MQL4の古い関数(OrderSendの旧形式など)は絶対に使用しないこと。
|
||||
- バックテストのパフォーマンスを著しく低下させる無駄なループ処理を避けること。
|
||||
|
||||
## 5. ドキュメント管理規則 (Documentation & Specifications)
|
||||
- **フォルダ構成:** プロジェクトルートに `docs` フォルダを維持し、各EA/インジケータに対応する仕様書(Markdown形式)を格納すること。
|
||||
- **ファイル命名:** 仕様書は英語版と日本語版を両方作成し、以下の形式で区別すること:
|
||||
- 日本語版:`{プログラム名}_spec_ja.md`
|
||||
- 英語版:`{プログラム名}_spec_en.md`
|
||||
- **新規作成時のルール:** - 新しいEAまたはインジケータを作成する際は、コードを書く前、あるいは同時に `docs/` 内に日本語版と英語版の両方の仕様書を生成すること。
|
||||
- **修正時の同期ルール:** - プログラムのロジック、外部パラメータ(input)、または重要な関数を変更した際は、必ず対応する `docs/{プログラム名}_spec_ja.md` および `docs/{プログラム名}_spec_en.md` を読み込み、修正内容を反映させること。
|
||||
- 修正の際は「変更履歴(Changelog)」セクションを仕様書末尾に設け、日付と修正概要を記録すること。
|
||||
|
||||
## 6. 仕様書の標準構成案
|
||||
仕様書を作成する際は、以下の項目を含めること:
|
||||
1. **概要**: プログラムの目的と動作概要。
|
||||
2. **使用インジケータ**: 依存している標準・カスタムインジケータ。
|
||||
3. **パラメータ設定**: `input` 変数の説明、デフォルト値、設定の意味。
|
||||
4. **エントリー/エグジット条件**: ロジックの詳細(文章および箇条書き)。
|
||||
5. **リスク管理**: マジックナンバー、ロット計算、ストップロス等の仕様。
|
||||
6. **変更履歴**: 日付、修正箇所、修正理由。
|
||||
|
||||
## 7. フォルダ構成と再利用性のルール
|
||||
### 7.1 プロジェクト単位のフォルダ管理
|
||||
- **プロジェクトフォルダ:** 各EA/インジケータは `Experts/MyProject/`、`Indicators/MyProject/` のようにプロジェクト名でフォルダを作成し、その中に関連ファイルを配置すること。
|
||||
- **仕様書の配置:** 対応する仕様書は `docs/MyProject/` 内に格納すること。
|
||||
|
||||
### 7.2 標準フォルダ構成
|
||||
```
|
||||
MQL5/
|
||||
├── Experts/
|
||||
│ └── MyProject/ # プロジェクトごとのフォルダ
|
||||
│ ├── MyEA.mq5 # メインソース
|
||||
│ └── MyEA.mqh # (オプション) EA固有のヘッダー
|
||||
├── Indicators/
|
||||
│ └── MyProject/ # 関連するカスタムインジケータ
|
||||
│ └── MySignal.mq5
|
||||
├── Include/
|
||||
│ └── MyLib/ # 【重要】自作ライブラリの本拠地
|
||||
│ ├── Common/ # 汎用ツール(時間操作、ログ、配列操作など)
|
||||
│ │ └── TimeUtils.mqh
|
||||
│ ├── Trading/ # トレードロジック(資金管理、注文処理)
|
||||
│ │ └── RiskManager.mqh
|
||||
│ ├── Signals/ # 売買サイン判定ロジック
|
||||
│ │ └── CrossLogic.mqh
|
||||
│ └── Wrapper/ # 標準ライブラリの拡張
|
||||
│ └── MyTrade.mqh
|
||||
├── Scripts/
|
||||
│ └── Utilities/ # 一括決済などの便利ツール
|
||||
├── docs/ # 仕様書フォルダ
|
||||
│ └── MyProject/
|
||||
│ ├── MyEA_spec_ja.md # 日本語仕様書
|
||||
│ └── MyEA_spec_en.md # 英語仕様書
|
||||
└── .github/ # Copilot指示書など
|
||||
└── copilot-instructions.md
|
||||
```
|
||||
|
||||
### 7.3 再利用性のルール
|
||||
- **共通ロジックの配置:** 複数のプロジェクトで利用可能なロジックは、必ず `Include/MyLib/` 内の適切なサブフォルダにクラスまたは関数として定義すること。
|
||||
- `Common/`: 汎用ユーティリティ(時間、ログ、配列操作など)
|
||||
- `Trading/`: トレード関連(資金管理、注文処理、ポジション管理など)
|
||||
- `Signals/`: 売買サイン判定ロジック
|
||||
- `Wrapper/`: 標準ライブラリの拡張クラス
|
||||
- **EAの構成:** `Experts/` 内の `.mq5` ファイルはエントリーポイントとしての役割に専念させ、具体的なロジックは `Include/MyLib/` 側のヘッダーファイルをインクルードして呼び出す形式をとること。
|
||||
- **依存関係の解決:** 新しいファイルを作成する際は、既存の `Include/MyLib/` 内にある自作ライブラリを優先的に再利用するよう提案すること。
|
||||
|
||||
## 8. 自動コンパイルとバグ修正フロー
|
||||
- **対象:** 新規作成または修正した `.mq5` / `.mqh` ファイル。
|
||||
- **実行手段:** まず VSCode の MQL Tools のコンパイル機能を優先して使用し、環境要件や自動化の都合で難しい場合は `metaeditor64.exe /compile` を使用すること。
|
||||
- **必須ループ:** 「実装 → コンパイル → ログ確認 → 修正」を繰り返し、`0 errors, 0 warnings` を満たすまで作業を継続すること。
|
||||
- **ログ管理:** コンパイルログは `MQL5/Logs/compile_{ProgramName}.log` に保存し、修正時は直近ログを根拠に対応すること。
|
||||
- **修正優先度:** コンパイルエラーを最優先で解消し、その後に警告を解消すること。
|
||||
- **完了条件:** ①コンパイル成功、②主要ロジックの整合性確認、③仕様書(`_spec_ja.md` / `_spec_en.md`)への反映。
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,935 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HIT_EA.mq5 |
|
||||
//| Copyright 2026, nanpin-martin.com |
|
||||
//| https://www.nanpin-martin.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2026, nanpin-martin.com"
|
||||
#property link "https://nanpin-martin.com/"
|
||||
#property version "1.00"
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| バッチファイル実行用の設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#import "Shell32.dll"
|
||||
int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd);
|
||||
#import
|
||||
|
||||
// バッチファイルのパス
|
||||
string get_trend_reply_bat = "C:\\ea_py\\get_trend_reply.bat"; // H4: trend
|
||||
string get_entry_reply_bat = "C:\\ea_py\\get_entry_reply.bat"; // H1: entry
|
||||
|
||||
// プロセス完了ファイルの設定
|
||||
string done_trend_file = "process_done_trend.txt";
|
||||
string done_entry_file = "process_done_entry.txt";
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| インプットの設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//--- 入力パラメータ
|
||||
input double lot_size = 0.01; // ロット数
|
||||
input double spread_limit = 20; // 許容スプレッド(point)
|
||||
input int magic_number = 10001; // マジックナンバー
|
||||
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
|
||||
ulong slippage = 10; // スリッページ
|
||||
|
||||
//--- 主要な定数・設定
|
||||
#define POSITION_LIMIT 48
|
||||
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
|
||||
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
|
||||
#define HISTORY_BARS 72
|
||||
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
|
||||
#define TARGET_SIZE 13
|
||||
#define DEFAULT_TARGET_PRICE 0.0
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| EAの状態をまとめる構造体
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
struct EAState
|
||||
{
|
||||
int trend_state; // ★追加:トレンドを格納する変数
|
||||
int res_chk; // GPTの回答が正しく取得できたか
|
||||
double en_price[5]; // エントリー基準価格
|
||||
double tp_price[5]; // 利益確定価格
|
||||
double sl_price[5]; // ロスカット基準価格
|
||||
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
|
||||
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
|
||||
int chk_cnt; // エントリー判定の試行回数
|
||||
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
|
||||
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
|
||||
datetime last_chk;
|
||||
};
|
||||
|
||||
EAState g_ea; // EA全体の状態をここで管理
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 必要な関数プロトタイプ宣言
|
||||
//| プロセス完了ファイル("process_done.txt")関連
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
// "process_done.txt"を作成する関数
|
||||
void CreateDoneFile(const string name);
|
||||
|
||||
// "process_done.txt"を削除する関数
|
||||
void DeleteDoneFile(const string name);
|
||||
|
||||
// "process_done.txt"の存在を確認し、存在する場合はtrueを返す関数
|
||||
bool CheckDoneFile(const string name);
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 必要な関数プロトタイプ宣言
|
||||
//| OHLCデータの取得からターゲット価格の取得まで
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//| 最新のOHLCデータを取得する関数
|
||||
bool GetLatestOHLC(datetime ×[], double &open_prices[], double &high_prices[], double &low_prices[], double &close_prices[], ENUM_TIMEFRAMES tf, int bars_count);
|
||||
|
||||
//| "ohlc.csv"を出力する関数
|
||||
void RecordOHLC(const string filename, const datetime ×[], const double &open_prices[], const double &high_prices[], const double &low_prices[], const double &close_prices[]);
|
||||
|
||||
//| バッチファイル(Pythonスクリプト)を実行する関数
|
||||
void ExecuteBatchTrend();
|
||||
void ExecuteBatchEntry();
|
||||
|
||||
// | "ohlc.csv"を出力後、バッチファイルの実行する関数
|
||||
bool RecordOHLCAndExecuteBatch_Trend(EAState &state);
|
||||
bool RecordOHLCAndExecuteBatch_Entry(EAState &state);
|
||||
|
||||
//| ターゲット価格を取得する関数
|
||||
bool GetTargetPrices(EAState &state);
|
||||
|
||||
//| "target_prices.txt"を読み込む関数
|
||||
void LoadTargetPrices(double &target_prices[]);
|
||||
|
||||
//| "xxx"を読み込む関数
|
||||
bool GetTrendState(EAState &state);
|
||||
void LoadTrendState(int &trend_state);
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 必要な関数プロトタイプ宣言
|
||||
//| エントリー注文関連
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//| エントリー注文を送信する関数 (1:buy-stop, 2:buy-limit, 3:sell-stop, 4:sell-limit)
|
||||
bool SendOrder(int orderType, double price, double tp, double sl);
|
||||
|
||||
//| 注文の執行ポリシーを取得する関数
|
||||
ENUM_ORDER_TYPE_FILLING GetOrderFillingPolicy(string symbol);
|
||||
|
||||
//| 注文コメント(ローカル時刻)を生成する関数(先頭に orderType を付与)
|
||||
string RequestComment(int orderType);
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 必要な関数プロトタイプ宣言
|
||||
//| 時間制限処理関連
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//| 時間が経過したエントリー注文をキャンセルする関数
|
||||
bool CancelExpiredOrders();
|
||||
|
||||
//| 時間が経過したポジションをクローズする関数
|
||||
bool CloseExpiredPositions();
|
||||
|
||||
//| 指定された時間に最も近いバーのインデックスを返す関数
|
||||
// int GetBarIndexByTime(datetime time, int default_index = 0);
|
||||
int GetBarShiftByTime(datetime time, ENUM_TIMEFRAMES tf, int default_shift = -1);
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 起動時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
void OnInit()
|
||||
// プロセス完了ファイル("process_done.txt)"を作成
|
||||
{
|
||||
CreateDoneFile(done_trend_file);
|
||||
CreateDoneFile(done_entry_file);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| ティック毎の処理
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
static int init_order_flg = initial_order;
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// (1) H4更新検知:トレンド用
|
||||
// ─────────────────────────────────────────────
|
||||
int current_bars_H4 = iBars(NULL, PERIOD_H4);
|
||||
static int pre_bars_H4 = current_bars_H4;
|
||||
int bars_H4_change = current_bars_H4 - pre_bars_H4;
|
||||
|
||||
if(bars_H4_change > 0 || init_order_flg == 1)
|
||||
{
|
||||
RecordOHLCAndExecuteBatch_Trend(g_ea);
|
||||
}
|
||||
pre_bars_H4 = current_bars_H4;
|
||||
|
||||
// trend done待ち(なければ以降をスキップ)
|
||||
if(!CheckDoneFile(done_trend_file))
|
||||
return;
|
||||
|
||||
// トレンド取得
|
||||
GetTrendState(g_ea);
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// (2) H1更新検知:エントリー用
|
||||
// ─────────────────────────────────────────────
|
||||
static bool bars_H1_check = false;
|
||||
|
||||
int current_bars_H1 = iBars(NULL, PERIOD_H1);
|
||||
static int pre_bars_H1 = current_bars_H1;
|
||||
int bars_H1_change = current_bars_H1 - pre_bars_H1;
|
||||
|
||||
if(bars_H1_change > 0 || init_order_flg == 1)
|
||||
{
|
||||
init_order_flg = 0;
|
||||
bars_H1_check = true;
|
||||
g_ea.chk_cnt = 0;
|
||||
g_ea.last_chk = 0;
|
||||
RecordOHLCAndExecuteBatch_Entry(g_ea);
|
||||
}
|
||||
pre_bars_H1 = current_bars_H1;
|
||||
|
||||
// ── ティック情報・コメント表示 ──
|
||||
MqlTick last_tick;
|
||||
if(!SymbolInfoTick(_Symbol, last_tick))
|
||||
{
|
||||
return;
|
||||
}
|
||||
double Ask = last_tick.ask;
|
||||
double Bid = last_tick.bid;
|
||||
double Spread = MathRound((Ask - Bid) / Point()) * Point();
|
||||
|
||||
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
|
||||
|
||||
string message = StringFormat(
|
||||
" \nAsk: %." + IntegerToString(digits) + "f"
|
||||
"\nBid: %." + IntegerToString(digits) + "f"
|
||||
"\nSpread: %." + IntegerToString(digits) + "f"
|
||||
"\n\nLast Trend Update:\n %s"
|
||||
"\n\nTrend State: %.0f" // ★追加
|
||||
"\n\nLast Target Update:\n %s"
|
||||
"\n\n[T1 Buy Stop ] en: %." + IntegerToString(digits) + "f tp: %." + IntegerToString(digits) + "f sl: %." + IntegerToString(digits) + "f"
|
||||
"\n[T2 Buy Limit] en: %." + IntegerToString(digits) + "f tp: %." + IntegerToString(digits) + "f sl: %." + IntegerToString(digits) + "f"
|
||||
"\n[T3 Sell Stop] en: %." + IntegerToString(digits) + "f tp: %." + IntegerToString(digits) + "f sl: %." + IntegerToString(digits) + "f"
|
||||
"\n[T4 SellLimit] en: %." + IntegerToString(digits) + "f tp: %." + IntegerToString(digits) + "f sl: %." + IntegerToString(digits) + "f\n",
|
||||
Ask, Bid, Spread,
|
||||
TimeToString(g_ea.last_trend_update, TIME_DATE | TIME_MINUTES),
|
||||
g_ea.trend_state, // ★追加
|
||||
TimeToString(g_ea.last_target_update, TIME_DATE | TIME_MINUTES),
|
||||
g_ea.en_price[1], g_ea.tp_price[1], g_ea.sl_price[1],
|
||||
g_ea.en_price[2], g_ea.tp_price[2], g_ea.sl_price[2],
|
||||
g_ea.en_price[3], g_ea.tp_price[3], g_ea.sl_price[3],
|
||||
g_ea.en_price[4], g_ea.tp_price[4], g_ea.sl_price[4]
|
||||
);
|
||||
Comment(message);
|
||||
|
||||
// スプレッド制限
|
||||
if(Spread > spread_limit * Point())
|
||||
return;
|
||||
|
||||
// entry done待ち
|
||||
if(!CheckDoneFile(done_entry_file))
|
||||
return;
|
||||
|
||||
// ターゲット取得
|
||||
GetTargetPrices(g_ea);
|
||||
|
||||
// 期限切れ注文キャンセル・ポジクローズ
|
||||
if(OrdersTotal() > 0)
|
||||
CancelExpiredOrders();
|
||||
if(PositionsTotal() > 0)
|
||||
CloseExpiredPositions();
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// エントリー条件判定&注文送信(H1更新タイミングで1回)
|
||||
// ─────────────────────────────────────────────
|
||||
// if(bars_H4_check && TimeCurrent() - g_ea.last_chk >= 60)
|
||||
// {
|
||||
// bars_H4_check = false;
|
||||
// g_ea.last_chk = TimeCurrent();
|
||||
if(bars_H1_check && TimeCurrent() - g_ea.last_chk >= 60)
|
||||
{
|
||||
bars_H1_check = false;
|
||||
g_ea.last_chk = TimeCurrent();
|
||||
|
||||
if(g_ea.res_chk == 0)
|
||||
{
|
||||
Print("[Entry Skip] res_chk=0 (range). No entry orders are sent.");
|
||||
g_ea.chk_cnt = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int used = OrdersTotal() + PositionsTotal();
|
||||
if(used >= POSITION_LIMIT)
|
||||
{
|
||||
Print("Position limit exceeded: used=", used, " limit=", POSITION_LIMIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
int sent_success = 0; // ★ 送信成功数(= SendOrder true の回数)
|
||||
|
||||
// ★ 1..4 を順に判定して、条件OKなら送る
|
||||
for(int t=1; t<=4; t++)
|
||||
{
|
||||
// ポジション上限チェック(途中で到達したら打ち切り)
|
||||
used = OrdersTotal() + PositionsTotal();
|
||||
if(used >= POSITION_LIMIT)
|
||||
{
|
||||
Print("Position limit reached while sending. used=", used, " limit=", POSITION_LIMIT);
|
||||
break;
|
||||
}
|
||||
|
||||
string entry_type;
|
||||
double cur_price; // ログ用(Ask/Bid)
|
||||
|
||||
if(t==1)
|
||||
{
|
||||
entry_type="Buy Stop";
|
||||
cur_price=Ask;
|
||||
}
|
||||
else
|
||||
if(t==2)
|
||||
{
|
||||
entry_type="Buy Limit";
|
||||
cur_price=Ask;
|
||||
}
|
||||
else
|
||||
if(t==3)
|
||||
{
|
||||
entry_type="Sell Stop";
|
||||
cur_price=Bid;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry_type="Sell Limit"; // t==4
|
||||
cur_price=Bid;
|
||||
}
|
||||
|
||||
double en = g_ea.en_price[t];
|
||||
double tp = g_ea.tp_price[t];
|
||||
double sl = g_ea.sl_price[t];
|
||||
|
||||
bool ok=false;
|
||||
|
||||
if(t==1)
|
||||
ok = (Ask < en && tp > en && sl < en); // buy-stop
|
||||
else
|
||||
if(t==2)
|
||||
ok = (Ask > en && tp > en && sl < en); // buy-limit
|
||||
else
|
||||
if(t==3)
|
||||
ok = (Bid > en && tp < en && sl > en); // sell-stop
|
||||
else
|
||||
ok = (Bid < en && tp < en && sl > en); // sell-limit
|
||||
|
||||
if(ok)
|
||||
{
|
||||
Print("[", entry_type, " Order Try at ", cur_price, "] en=", en, " tp=", tp, " sl=", sl);
|
||||
|
||||
if(SendOrder(t, en, tp, sl))
|
||||
{
|
||||
sent_success++;
|
||||
Print("[", entry_type, " Order Sent] ticket ok. en=", en, " tp=", tp, " sl=", sl);
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("[", entry_type, " Order Failed] en=", en, " tp=", tp, " sl=", sl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("[No ", entry_type, "] cur=", cur_price, " en=", en, " tp=", tp, " sl=", sl);
|
||||
}
|
||||
}
|
||||
|
||||
if(sent_success > 0)
|
||||
{
|
||||
g_ea.chk_cnt = 0; // 1件でも通ったら終了
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ea.chk_cnt += 1;
|
||||
Print("[Retry] no order sent. chk_cnt=", g_ea.chk_cnt, "/10");
|
||||
|
||||
if(g_ea.chk_cnt < 10)
|
||||
{
|
||||
// bars_H4_check = true; // 60秒後に再度このブロックに入る
|
||||
bars_H1_check = true; // ★ GPT-EAの bars_H4_check → bars_H1_check に変更
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("[Retry End] reached max tries. reset chk_cnt.");
|
||||
g_ea.chk_cnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| "process_done.txt"を作成する関数
|
||||
//+------------------------------------------------------------------+
|
||||
void CreateDoneFile(const string name)
|
||||
{
|
||||
if(!FileIsExist(name))
|
||||
{
|
||||
int h = FileOpen(name, FILE_WRITE|FILE_TXT);
|
||||
if(h != INVALID_HANDLE)
|
||||
FileClose(h);
|
||||
else
|
||||
Print("Failed to create file: ", name, " err=", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| "process_done.txt"を削除する関数
|
||||
//+------------------------------------------------------------------+
|
||||
void DeleteDoneFile(const string name)
|
||||
{
|
||||
if(FileIsExist(name))
|
||||
FileDelete(name);
|
||||
}
|
||||
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| "process_done.txt"の存在を確認し、存在する場合はtrueを返す関数
|
||||
//+------------------------------------------------------------------+
|
||||
bool CheckDoneFile(const string name)
|
||||
{
|
||||
return FileIsExist(name);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 最新のOHLCデータを取得する関数
|
||||
//+------------------------------------------------------------------+
|
||||
bool GetLatestOHLC(datetime ×[], double &open_prices[], double &high_prices[], double &low_prices[], double &close_prices[], ENUM_TIMEFRAMES tf, int bars_count)
|
||||
{
|
||||
ArrayResize(times, 0);
|
||||
ArrayResize(open_prices, 0);
|
||||
ArrayResize(high_prices, 0);
|
||||
ArrayResize(low_prices, 0);
|
||||
ArrayResize(close_prices, 0);
|
||||
|
||||
if(bars_count < 2)
|
||||
return false;
|
||||
|
||||
// 時間データを取得
|
||||
if(CopyTime(_Symbol, tf, 0, bars_count, times) <= 0)
|
||||
{
|
||||
Print(__FUNCTION__, ": Failed to copy time data (bars=", bars_count, ") err=", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// OHLCデータを取得
|
||||
MqlRates rates[];
|
||||
if(CopyRates(_Symbol, tf, 0, bars_count, rates) <= 0)
|
||||
{
|
||||
Print(__FUNCTION__, ": Failed to copy rates data (bars=", bars_count, ") err=", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 必要なデータを配列に格納
|
||||
for(int i = 0; i < ArraySize(rates); i++)
|
||||
{
|
||||
ArrayResize(open_prices, i + 1);
|
||||
ArrayResize(high_prices, i + 1);
|
||||
ArrayResize(low_prices, i + 1);
|
||||
ArrayResize(close_prices, i + 1);
|
||||
|
||||
open_prices[i] = rates[i].open;
|
||||
high_prices[i] = rates[i].high;
|
||||
low_prices[i] = rates[i].low;
|
||||
close_prices[i] = rates[i].close;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| "ohlc.csv"を出力する関数
|
||||
//+------------------------------------------------------------------+
|
||||
void RecordOHLC(const string filename, const datetime ×[], const double &open_prices[], const double &high_prices[], const double &low_prices[], const double &close_prices[])
|
||||
{
|
||||
// 出力先ファイル名
|
||||
// string filename = "ohlc.csv";
|
||||
|
||||
// ファイルを "書き込みモード" でオープン (テキスト/ANSI)
|
||||
int fileHandle = FileOpen(filename, FILE_WRITE | FILE_TXT | FILE_ANSI);
|
||||
|
||||
// ファイルが開けたかチェック
|
||||
if(fileHandle == INVALID_HANDLE)
|
||||
{
|
||||
Print(__FUNCTION__, " : Failed to open file: ", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
// 配列サイズを取得 (times, open, high, low, close の要素数は同じ前提)
|
||||
int size = ArraySize(times);
|
||||
|
||||
// ヘッダー行を追加
|
||||
FileWrite(fileHandle, "Time,Open,High,Low,Close");
|
||||
|
||||
// 小数点の桁数を取得
|
||||
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
|
||||
|
||||
// フォーマット文字列を動的に生成
|
||||
string formatString = StringFormat("%%s,%%.%df,%%.%df,%%.%df,%%.%df", digits, digits, digits, digits);
|
||||
|
||||
// 1行ずつ "時刻, Open, High, Low, Close" の形式で書き込み
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
// 時間をフォーマット
|
||||
string timeStr = TimeToString(times[i], TIME_DATE | TIME_MINUTES);
|
||||
|
||||
// 1行分の文字列を生成 (小数点以下の桁数を `digits` に調整)
|
||||
string line = StringFormat(formatString,
|
||||
timeStr, open_prices[i], high_prices[i], low_prices[i], close_prices[i]);
|
||||
|
||||
// ファイルに書き込み (改行付き)
|
||||
FileWrite(fileHandle, line);
|
||||
}
|
||||
|
||||
// 書き込み終了後、ファイルを閉じる
|
||||
FileClose(fileHandle);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| バッチファイル(Pythonスクリプト)を実行する関数
|
||||
//+------------------------------------------------------------------+
|
||||
void ExecuteBatchTrend()
|
||||
{
|
||||
if(CheckDoneFile(done_trend_file))
|
||||
{
|
||||
DeleteDoneFile(done_trend_file);
|
||||
ShellExecuteW(0, "open", get_trend_reply_bat, "", "", 1);
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void ExecuteBatchEntry()
|
||||
{
|
||||
if(CheckDoneFile(done_entry_file))
|
||||
{
|
||||
DeleteDoneFile(done_entry_file);
|
||||
ShellExecuteW(0, "open", get_entry_reply_bat, "", "", 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| "ohlc.csv"を出力後、バッチファイルの実行する関数
|
||||
//+------------------------------------------------------------------+
|
||||
bool RecordOHLCAndExecuteBatch_Trend(EAState &state)
|
||||
{
|
||||
datetime times[];
|
||||
double open_prices[], high_prices[], low_prices[], close_prices[];
|
||||
|
||||
if(!GetLatestOHLC(times, open_prices, high_prices, low_prices, close_prices,
|
||||
PERIOD_H4, HISTORY_BARS))
|
||||
{ Print("GetLatestOHLC(H4) failed."); return false; }
|
||||
|
||||
RecordOHLC("ohlc_H4.csv", times, open_prices, high_prices, low_prices, close_prices);
|
||||
ExecuteBatchTrend();
|
||||
|
||||
state.load_trend_flg = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool RecordOHLCAndExecuteBatch_Entry(EAState &state)
|
||||
{
|
||||
datetime times[];
|
||||
double open_prices[], high_prices[], low_prices[], close_prices[];
|
||||
|
||||
if(!GetLatestOHLC(times, open_prices, high_prices, low_prices, close_prices,
|
||||
PERIOD_H1, HISTORY_BARS))
|
||||
{ Print("GetLatestOHLC(H1) failed."); return false; }
|
||||
|
||||
RecordOHLC("ohlc_H1.csv", times, open_prices, high_prices, low_prices, close_prices);
|
||||
ExecuteBatchEntry();
|
||||
|
||||
state.load_target_flg = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool GetTrendState(EAState &state)
|
||||
{
|
||||
bool ProcessDone = CheckDoneFile(done_trend_file);
|
||||
if(ProcessDone && g_ea.load_trend_flg)
|
||||
{
|
||||
int trend_state;
|
||||
LoadTrendState(trend_state);
|
||||
state.trend_state = trend_state;
|
||||
Print("trend_state: ", state.trend_state);
|
||||
g_ea.load_trend_flg = false;
|
||||
g_ea.last_trend_update = TimeLocal();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void LoadTrendState(int &trend_state)
|
||||
{
|
||||
string filename = "trend_state.txt";
|
||||
if(FileIsExist(filename))
|
||||
{
|
||||
int filehandle = FileOpen(filename, FILE_READ | FILE_TXT);
|
||||
if(filehandle != INVALID_HANDLE)
|
||||
{
|
||||
string line = FileReadString(filehandle);
|
||||
trend_state = (int)StringToInteger(line);
|
||||
FileClose(filehandle);
|
||||
}
|
||||
else
|
||||
{ Print("Failed to open trend_state.txt"); trend_state = 0; }
|
||||
}
|
||||
else
|
||||
{ Print("trend_state.txt not found"); trend_state = 0; }
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| ターゲット価格を取得する関数
|
||||
//+------------------------------------------------------------------+
|
||||
bool GetTargetPrices(EAState &state)
|
||||
{
|
||||
bool ProcessDone = CheckDoneFile(done_entry_file); // ←変更
|
||||
if(ProcessDone && g_ea.load_target_flg) // ←変更
|
||||
{
|
||||
double target_prices[];
|
||||
LoadTargetPrices(target_prices);
|
||||
|
||||
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
|
||||
|
||||
// 先頭は res_chk
|
||||
state.res_chk = (int)target_prices[0];
|
||||
|
||||
// ★ 1..4 の (en,tp,sl) を読む:合計12個
|
||||
for(int t=1; t<=4; t++)
|
||||
{
|
||||
int base = 1 + (t-1)*3; // 1,4,7,10
|
||||
state.en_price[t] = NormalizeDouble(target_prices[base + 0], digits);
|
||||
state.tp_price[t] = NormalizeDouble(target_prices[base + 1], digits);
|
||||
state.sl_price[t] = NormalizeDouble(target_prices[base + 2], digits);
|
||||
}
|
||||
|
||||
// ログ(任意)
|
||||
Print("target_prices: res=", state.res_chk,
|
||||
" | T1 en=", state.en_price[1], " tp=", state.tp_price[1], " sl=", state.sl_price[1],
|
||||
" | T2 en=", state.en_price[2], " tp=", state.tp_price[2], " sl=", state.sl_price[2],
|
||||
" | T3 en=", state.en_price[3], " tp=", state.tp_price[3], " sl=", state.sl_price[3],
|
||||
" | T4 en=", state.en_price[4], " tp=", state.tp_price[4], " sl=", state.sl_price[4]);
|
||||
|
||||
g_ea.load_target_flg = false; // ←変更
|
||||
g_ea.last_target_update = TimeLocal(); // ←変更
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| "target_prices.txt"を読み込む関数
|
||||
//+------------------------------------------------------------------+
|
||||
void LoadTargetPrices(double &target_prices[])
|
||||
{
|
||||
ArrayResize(target_prices, TARGET_SIZE);
|
||||
string filename = "target_prices.txt";
|
||||
|
||||
if(FileIsExist(filename))
|
||||
{
|
||||
int filehandle = FileOpen(filename, FILE_READ | FILE_TXT);
|
||||
if(filehandle != INVALID_HANDLE)
|
||||
{
|
||||
int i = 0;
|
||||
while(!FileIsEnding(filehandle) && i < TARGET_SIZE)
|
||||
{
|
||||
string line = FileReadString(filehandle);
|
||||
target_prices[i] = StringToDouble(line);
|
||||
i++;
|
||||
}
|
||||
FileClose(filehandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Failed to open file. Error code: ", GetLastError());
|
||||
for(int i = 0; i < TARGET_SIZE; i++)
|
||||
{
|
||||
target_prices[i] = DEFAULT_TARGET_PRICE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("File does not exist: ", filename);
|
||||
for(int i = 0; i < TARGET_SIZE; i++)
|
||||
{
|
||||
target_prices[i] = DEFAULT_TARGET_PRICE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| エントリー注文を送信する関数 (1:buy-stop, 2:buy-limit, 3:sell-stop, 4:sell-limit)
|
||||
//+------------------------------------------------------------------+
|
||||
bool SendOrder(int orderType, double price, double tp, double sl)
|
||||
{
|
||||
MqlTradeRequest request = {};
|
||||
MqlTradeResult result = {};
|
||||
|
||||
request.magic = magic_number;
|
||||
request.symbol = _Symbol;
|
||||
request.volume = lot_size;
|
||||
request.deviation = slippage;
|
||||
request.type_filling = GetOrderFillingPolicy(_Symbol);
|
||||
request.price = NormalizeDouble(price, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
|
||||
request.tp = NormalizeDouble(tp, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
|
||||
request.sl = NormalizeDouble(sl, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
|
||||
request.comment = RequestComment(orderType);
|
||||
|
||||
string orderTypeStr = "";
|
||||
|
||||
// 指値または逆指値注文
|
||||
request.action = TRADE_ACTION_PENDING;
|
||||
|
||||
switch(orderType)
|
||||
{
|
||||
case 1: // 順張り買い (buy-stop)
|
||||
request.type = ORDER_TYPE_BUY_STOP;
|
||||
orderTypeStr = "buy-stop";
|
||||
break;
|
||||
|
||||
case 2: // 逆張り買い (buy-limit)
|
||||
request.type = ORDER_TYPE_BUY_LIMIT;
|
||||
orderTypeStr = "buy-limit";
|
||||
break;
|
||||
|
||||
case 3: // 順張り売り (sell-stop)
|
||||
request.type = ORDER_TYPE_SELL_STOP;
|
||||
orderTypeStr = "sell-stop";
|
||||
break;
|
||||
|
||||
case 4: // 逆張り売り (sell-limit)
|
||||
request.type = ORDER_TYPE_SELL_LIMIT;
|
||||
orderTypeStr = "sell-limit";
|
||||
break;
|
||||
|
||||
default: // 不正なorderType
|
||||
Print(__FUNCTION__, ": invalid orderType=", orderType);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 注文送信
|
||||
if(!OrderSend(request, result))
|
||||
{
|
||||
Print(__FUNCTION__, ": OrderSend failed. err=", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 注文成功確認
|
||||
if(result.retcode == TRADE_RETCODE_PLACED ||
|
||||
result.retcode == TRADE_RETCODE_DONE ||
|
||||
result.retcode == TRADE_RETCODE_DONE_PARTIAL)
|
||||
{
|
||||
Print(request.comment + " - " + orderTypeStr + " order success (ticket=", result.order, ")");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Print(__FUNCTION__, ": OrderSend retcode=", result.retcode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 注文の執行ポリシーを取得する関数
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ORDER_TYPE_FILLING GetOrderFillingPolicy(string symbol)
|
||||
{
|
||||
long fill_mode = SymbolInfoInteger(symbol, SYMBOL_FILLING_MODE);
|
||||
if((fill_mode & SYMBOL_FILLING_IOC) != 0)
|
||||
return ORDER_FILLING_IOC;
|
||||
if((fill_mode & SYMBOL_FILLING_FOK) != 0)
|
||||
return ORDER_FILLING_FOK;
|
||||
return ORDER_FILLING_RETURN;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 注文コメント(ローカル時刻)を生成する関数(先頭に orderType を付与)
|
||||
//+------------------------------------------------------------------+
|
||||
string RequestComment(int orderType)
|
||||
{
|
||||
datetime localTime = TimeLocal();
|
||||
string timeStr = TimeToString(localTime, TIME_DATE|TIME_MINUTES);
|
||||
|
||||
// 先頭に 1,2,3,4 を付ける(例: "1 | PC Time: 2026.02.14 19:05")
|
||||
return IntegerToString(orderType) + " | PC Time: " + timeStr;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 時間が経過したエントリー注文をキャンセルする関数
|
||||
//+------------------------------------------------------------------+
|
||||
bool CancelExpiredOrders()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// 未決済注文の数を取得
|
||||
for(int i = OrdersTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
ulong ticket = OrderGetTicket(i);
|
||||
if(OrderSelect(ticket)) // 注文を選択
|
||||
{
|
||||
if(OrderGetString(ORDER_SYMBOL) != _Symbol)
|
||||
continue;
|
||||
if(OrderGetInteger(ORDER_MAGIC) != magic_number)
|
||||
continue;
|
||||
|
||||
datetime open_time = (datetime)OrderGetInteger(ORDER_TIME_SETUP);
|
||||
|
||||
int open_shift = GetBarShiftByTime(open_time, PERIOD_H1, -1); // H1
|
||||
if(open_shift < 0)
|
||||
continue; // 時刻解決できないなら触らない
|
||||
|
||||
if(open_shift >= ENTRY_H1_LIMIT) // H1本数(=1本 ≒ 1時間)
|
||||
{
|
||||
MqlTradeRequest request = {};
|
||||
MqlTradeResult trade_result = {};
|
||||
request.action=TRADE_ACTION_REMOVE; // 取引操作タイプ
|
||||
request.order = ticket; // 注文チケット
|
||||
if(!OrderSend(request, trade_result)) // 削除リクエスト送信
|
||||
{
|
||||
Print("Failed to delete order. Ticket: ", ticket, " Error: ", GetLastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(trade_result.retcode == TRADE_RETCODE_DONE)
|
||||
{
|
||||
Print("Order canceled successfully due to a time limit. Ticket: ", ticket);
|
||||
result = true; // 削除成功フラグ
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Order cancellation failed. Ticket: ", ticket, " Retcode: ", trade_result.retcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 時間が経過したポジションをクローズする関数
|
||||
//+------------------------------------------------------------------+
|
||||
bool CloseExpiredPositions()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// ポジションを逆順でループ
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
string position_symbol = PositionGetSymbol(i);
|
||||
if(position_symbol!="")
|
||||
{
|
||||
// Magic Number とシンボルでフィルタリング
|
||||
if(position_symbol != _Symbol)
|
||||
continue;
|
||||
if(PositionGetInteger(POSITION_MAGIC) == magic_number)
|
||||
{
|
||||
// ポジションのエントリー時刻を取得
|
||||
datetime entry_time = (datetime)PositionGetInteger(POSITION_TIME);
|
||||
|
||||
int entry_shift = GetBarShiftByTime(entry_time, PERIOD_H1, -1);
|
||||
if(entry_shift < 0)
|
||||
continue;
|
||||
|
||||
if(entry_shift >= CLOSE_H1_LIMIT) // H1本数(=12本 ≒ 12時間)
|
||||
{
|
||||
MqlTradeRequest request = {};
|
||||
MqlTradeResult trade_result = {};
|
||||
|
||||
// ポジションタイプに応じてリクエストを設定
|
||||
int position_type = (int)PositionGetInteger(POSITION_TYPE);
|
||||
request.action = TRADE_ACTION_DEAL;
|
||||
request.position = PositionGetInteger(POSITION_TICKET); // ポジションのチケット番号
|
||||
request.symbol = position_symbol; // シンボル
|
||||
request.volume = PositionGetDouble(POSITION_VOLUME); // ポジションサイズ
|
||||
request.price = (position_type == POSITION_TYPE_BUY)
|
||||
? SymbolInfoDouble(position_symbol, SYMBOL_BID) // BUYの場合はBIDでクローズ
|
||||
: SymbolInfoDouble(position_symbol, SYMBOL_ASK); // SELLの場合はASKでクローズ
|
||||
request.deviation = slippage;
|
||||
request.type = (position_type == POSITION_TYPE_BUY)
|
||||
? ORDER_TYPE_SELL // BUYポジションをSELLでクローズ
|
||||
: ORDER_TYPE_BUY; // SELLポジションをBUYでクローズ
|
||||
request.type_filling = GetOrderFillingPolicy(position_symbol); // 注文執行ポリシー
|
||||
request.magic = magic_number;
|
||||
|
||||
// 注文送信
|
||||
if(!OrderSend(request, trade_result))
|
||||
{
|
||||
Print("Failed to close position. Ticket: ", request.position, " Error: ", GetLastError());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 結果の確認
|
||||
if(trade_result.retcode == TRADE_RETCODE_DONE || trade_result.retcode == TRADE_RETCODE_DONE_PARTIAL)
|
||||
{
|
||||
Print("Position closed successfully due to a time limit. Ticket: ", request.position);
|
||||
result = true; // 少なくとも1つ成功した場合
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Failed to close position. Ticket: ", request.position, " Retcode: ", trade_result.retcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Failed to select position at index ", i, ". Error: ", GetLastError());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 指定された時間に最も近いバーのインデックスを返す関数
|
||||
//+------------------------------------------------------------------+
|
||||
int GetBarShiftByTime(datetime time, ENUM_TIMEFRAMES tf, int default_shift = -1)
|
||||
{
|
||||
if(time <= 0)
|
||||
return default_shift;
|
||||
int shift = iBarShift(_Symbol, tf, time, false); // 近傍バーで解決する
|
||||
if(shift < 0)
|
||||
return default_shift;
|
||||
return shift;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,441 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HIT_EA.mq5 |
|
||||
//| Copyright 2026, nanpin-martin.com |
|
||||
//| https://www.nanpin-martin.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2026, nanpin-martin.com"
|
||||
#property link "https://nanpin-martin.com/"
|
||||
#property version "1.01"
|
||||
|
||||
#include <MyLib/Trading/SLTPManager.mqh>
|
||||
#include <MyLib/Panel/SLTPManagerPanel.mqh>
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| バッチファイル実行用の設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
// Windowsプロセス起動・終了確認用
|
||||
#define CREATE_NO_WINDOW 0x08000000
|
||||
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
|
||||
#define SYNCHRONIZE 0x00100000
|
||||
#define WAIT_OBJECT_0 0
|
||||
#define WAIT_TIMEOUT 258
|
||||
#define STILL_ACTIVE 259
|
||||
|
||||
struct STARTUPINFO_W
|
||||
{
|
||||
uint cb;
|
||||
string lpReserved;
|
||||
string lpDesktop;
|
||||
string lpTitle;
|
||||
uint dwX;
|
||||
uint dwY;
|
||||
uint dwXSize;
|
||||
uint dwYSize;
|
||||
uint dwXCountChars;
|
||||
uint dwYCountChars;
|
||||
uint dwFillAttribute;
|
||||
uint dwFlags;
|
||||
ushort wShowWindow;
|
||||
ushort cbReserved2;
|
||||
long lpReserved2;
|
||||
long hStdInput;
|
||||
long hStdOutput;
|
||||
long hStdError;
|
||||
};
|
||||
|
||||
struct PROCESS_INFORMATION
|
||||
{
|
||||
long hProcess;
|
||||
long hThread;
|
||||
uint dwProcessId;
|
||||
uint dwThreadId;
|
||||
};
|
||||
|
||||
#import "kernel32.dll"
|
||||
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
|
||||
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
|
||||
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
|
||||
int CloseHandle(long hObject);
|
||||
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
|
||||
#import
|
||||
|
||||
// バッチファイルのパス
|
||||
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
|
||||
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
|
||||
|
||||
// プロセス完了ファイルの設定
|
||||
string done_trend_file = "process_done_trend.txt";
|
||||
string done_entry_file = "process_done_entry.txt";
|
||||
|
||||
// Python出力ファイル
|
||||
string trend_state_file = "trend_state.txt";
|
||||
string target_prices_file = "target_prices.txt";
|
||||
|
||||
// Python実行中を判定するための管理ファイル
|
||||
string running_trend_file = "process_running_trend.txt";
|
||||
string running_entry_file = "process_running_entry.txt";
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| インプットの設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//--- 入力パラメータ
|
||||
input double lot_size = 0.01; // ロット数
|
||||
input double spread_limit = 60; // 許容スプレッド(point)
|
||||
input int magic_number = 10001; // マジックナンバー
|
||||
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
|
||||
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
|
||||
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
|
||||
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
|
||||
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
|
||||
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
|
||||
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
|
||||
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
|
||||
input int input_entry_max_candidate_age_minutes = 45; // H1候補価格を新規発注に使う最大経過分数
|
||||
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
|
||||
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
|
||||
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
|
||||
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
|
||||
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
|
||||
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
|
||||
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
|
||||
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
|
||||
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
|
||||
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
|
||||
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
|
||||
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
|
||||
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
|
||||
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
|
||||
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
|
||||
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
|
||||
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
|
||||
ulong slippage = 10; // スリッページ
|
||||
|
||||
//--- 主要な定数・設定
|
||||
#define POSITION_LIMIT 48
|
||||
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
|
||||
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
|
||||
#define HISTORY_BARS 72
|
||||
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
|
||||
#define M15_CONFIRM_BARS 30
|
||||
#define M15_MIN_ENTRY_ZONE_POINTS 10
|
||||
#define M15_MIN_BODY_RATIO 0.25
|
||||
#define M15_REJECTION_WICK_RATIO 0.35
|
||||
#define ENTRY_RETRY_SECONDS 60
|
||||
#define ENTRY_RETRY_LIMIT 10
|
||||
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
|
||||
#define TARGET_SIZE 13
|
||||
#define DEFAULT_TARGET_PRICE 0.0
|
||||
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
|
||||
|
||||
#define MARKET_LOW_VOL_RANGE 0
|
||||
#define MARKET_HIGH_VOL_RANGE 1
|
||||
#define MARKET_LOW_VOL_UP 2
|
||||
#define MARKET_HIGH_VOL_UP 3
|
||||
#define MARKET_LOW_VOL_DOWN 4
|
||||
#define MARKET_HIGH_VOL_DOWN 5
|
||||
#define MARKET_TECHNICAL_ERROR_STOP 6
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| EAの状態をまとめる構造体
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
struct EAState
|
||||
{
|
||||
int trend_state; // H4 market_state(0..5、6は技術エラー停止)を格納する変数
|
||||
int res_chk; // GPTの回答が正しく取得できたか
|
||||
double en_price[5]; // エントリー基準価格
|
||||
double tp_price[5]; // 利益確定価格
|
||||
double sl_price[5]; // ロスカット基準価格
|
||||
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
|
||||
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
|
||||
int chk_cnt; // エントリー判定の試行回数
|
||||
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
|
||||
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
|
||||
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
|
||||
datetime last_chk;
|
||||
};
|
||||
|
||||
EAState g_ea; // EA全体の状態をここで管理
|
||||
|
||||
// initial_order 用の初回処理フラグ
|
||||
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
|
||||
bool g_init_trend_pending = false;
|
||||
bool g_init_entry_pending = false;
|
||||
|
||||
// H4/H1のバー更新状態
|
||||
int g_pre_bars_H4 = 0;
|
||||
int g_pre_bars_H1 = 0;
|
||||
int g_pre_bars_M15 = 0;
|
||||
bool g_bars_H1_check = false;
|
||||
bool g_bars_M15_check = false;
|
||||
|
||||
// ティックごとの価格情報
|
||||
struct TickContext
|
||||
{
|
||||
double ask;
|
||||
double bid;
|
||||
double spread;
|
||||
double spread_points;
|
||||
int digits;
|
||||
};
|
||||
|
||||
// 外部Pythonプロセスの状態
|
||||
struct ExternalProcessState
|
||||
{
|
||||
long handle;
|
||||
uint process_id;
|
||||
bool active;
|
||||
bool exit_code_ready;
|
||||
uint exit_code;
|
||||
datetime started_at;
|
||||
};
|
||||
|
||||
ExternalProcessState g_trend_process;
|
||||
ExternalProcessState g_entry_process;
|
||||
|
||||
CSLTPManager g_sltp_manager;
|
||||
CSLTPManagerPanel g_sltp_panel;
|
||||
SLTPManagerPanelSettings g_sltp_settings;
|
||||
bool g_sltp_settings_valid = false;
|
||||
bool g_sltp_panel_created = false;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 起動時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief EA起動時の初期化処理を行います。
|
||||
*
|
||||
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
|
||||
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
|
||||
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
|
||||
*/
|
||||
int OnInit()
|
||||
// プロセス完了ファイルと実行中ファイルの状態を初期化
|
||||
{
|
||||
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
|
||||
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
|
||||
|
||||
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
|
||||
g_init_trend_pending = (initial_order == 1);
|
||||
g_init_entry_pending = (initial_order == 1);
|
||||
|
||||
if(!InitializeSLTPManager())
|
||||
return INIT_FAILED;
|
||||
|
||||
return INIT_SUCCEEDED;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 終了時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
ResetExternalProcessState(g_trend_process);
|
||||
ResetExternalProcessState(g_entry_process);
|
||||
|
||||
if(g_sltp_panel_created)
|
||||
g_sltp_panel.Destroy(reason);
|
||||
|
||||
// Clear chart status text left by Comment() when the EA is removed.
|
||||
Comment("");
|
||||
ChartRedraw(0);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| ティック毎の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief ティック受信ごとにEA全体の処理を制御します。
|
||||
*
|
||||
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
|
||||
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
|
||||
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
|
||||
*/
|
||||
void OnTick()
|
||||
{
|
||||
TickContext ctx;
|
||||
if(!GetTickContext(ctx))
|
||||
return;
|
||||
|
||||
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
|
||||
ManageExpiredTrades();
|
||||
|
||||
// Existing-position protection stays active even while Python results are pending.
|
||||
ManageSLTPPositions();
|
||||
|
||||
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
|
||||
RecoverTimedOutPythonProcesses();
|
||||
|
||||
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
|
||||
ProcessTrendUpdate(g_ea);
|
||||
|
||||
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
|
||||
if(!IsTrendResultReady())
|
||||
return;
|
||||
|
||||
RefreshTrendState(g_ea);
|
||||
|
||||
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
|
||||
ProcessEntryUpdate(g_ea);
|
||||
|
||||
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
|
||||
ProcessM15EntryTimingUpdate();
|
||||
|
||||
UpdateStatusComment(ctx);
|
||||
|
||||
// ここから下は新規注文に関する処理。
|
||||
if(!IsSpreadAllowed(ctx))
|
||||
return;
|
||||
|
||||
if(!IsEntryResultReady())
|
||||
return;
|
||||
|
||||
RefreshTargetPrices(g_ea);
|
||||
ProcessEntryDecisionIfNeeded(g_ea, ctx);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| SLTP manager panel and settings bridge
|
||||
//+------------------------------------------------------------------+
|
||||
string SLTPBoolText(const bool value)
|
||||
{
|
||||
return value ? "ON" : "OFF";
|
||||
}
|
||||
|
||||
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
|
||||
{
|
||||
settings.manager_enabled = input_sltp_manager_enabled;
|
||||
|
||||
settings.use_breakeven = input_sltp_use_breakeven;
|
||||
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
|
||||
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
|
||||
|
||||
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
|
||||
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
|
||||
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
|
||||
|
||||
settings.use_active_trailing = input_sltp_use_active_trailing;
|
||||
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
|
||||
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
|
||||
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
|
||||
settings.active_step_move_pips = input_sltp_active_step_move_pips;
|
||||
|
||||
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
|
||||
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
|
||||
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
|
||||
|
||||
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
|
||||
}
|
||||
|
||||
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
|
||||
const bool print_summary)
|
||||
{
|
||||
g_sltp_settings_valid = false;
|
||||
|
||||
g_sltp_manager.SetMagicNumber((ulong)magic_number);
|
||||
g_sltp_manager.SetSymbol(_Symbol);
|
||||
g_sltp_manager.SetDeviationInPoints(slippage);
|
||||
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
|
||||
settings.breakeven_trigger_pips,
|
||||
settings.breakeven_buffer_pips);
|
||||
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
|
||||
settings.elapsed_breakeven_hours,
|
||||
settings.elapsed_breakeven_buffer_pips);
|
||||
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
|
||||
settings.active_breakeven_pips,
|
||||
settings.active_stop_loss_offset_pips,
|
||||
settings.active_step_trigger_pips,
|
||||
settings.active_step_move_pips);
|
||||
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
|
||||
settings.tp_progress_trigger_percent,
|
||||
settings.tp_progress_sl_lock_percent);
|
||||
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
|
||||
|
||||
if(!g_sltp_manager.ValidateSettings())
|
||||
{
|
||||
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_sltp_settings = settings;
|
||||
g_sltp_settings_valid = true;
|
||||
|
||||
if(print_summary)
|
||||
{
|
||||
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
|
||||
" BE=", SLTPBoolText(settings.use_breakeven),
|
||||
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
|
||||
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
|
||||
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
|
||||
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitializeSLTPManager()
|
||||
{
|
||||
SLTPManagerPanelSettings initial_settings;
|
||||
LoadSLTPInputSettings(initial_settings);
|
||||
|
||||
if(!ApplySLTPSettings(initial_settings, true))
|
||||
return false;
|
||||
|
||||
g_sltp_panel.Init(g_sltp_settings);
|
||||
if(input_sltp_show_panel)
|
||||
{
|
||||
if(!g_sltp_panel.CreatePanel())
|
||||
{
|
||||
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
|
||||
return true;
|
||||
}
|
||||
|
||||
g_sltp_panel.SetInitialValues();
|
||||
g_sltp_panel_created = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ManageSLTPPositions()
|
||||
{
|
||||
if(!g_sltp_settings_valid)
|
||||
return;
|
||||
if(!g_sltp_settings.manager_enabled)
|
||||
return;
|
||||
|
||||
g_sltp_manager.ManagePositions();
|
||||
g_sltp_manager.HighVolatilityLimit();
|
||||
}
|
||||
|
||||
void OnChartEvent(const int id,
|
||||
const long &lparam,
|
||||
const double &dparam,
|
||||
const string &sparam)
|
||||
{
|
||||
if(!g_sltp_panel_created)
|
||||
return;
|
||||
|
||||
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
|
||||
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
|
||||
{
|
||||
if(!ApplySLTPSettings(candidate_settings, true))
|
||||
Print("HIT SLTP panel apply failed. Please review panel values.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Function implementations are kept in project headers so the EA entry points stay compact.
|
||||
#include <MyLib/Common/HITRuntimeController.mqh>
|
||||
#include <MyLib/Signals/HITEntrySignal.mqh>
|
||||
#include <MyLib/Common/HITExternalProcess.mqh>
|
||||
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
|
||||
#include <MyLib/Trading/HITTradeManager.mqh>
|
||||
@@ -0,0 +1,440 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HIT_EA.mq5 |
|
||||
//| Copyright 2026, nanpin-martin.com |
|
||||
//| https://www.nanpin-martin.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2026, nanpin-martin.com"
|
||||
#property link "https://nanpin-martin.com/"
|
||||
#property version "1.01"
|
||||
|
||||
#include <MyLib/Trading/SLTPManager.mqh>
|
||||
#include <MyLib/Panel/SLTPManagerPanel.mqh>
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| バッチファイル実行用の設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
// Windowsプロセス起動・終了確認用
|
||||
#define CREATE_NO_WINDOW 0x08000000
|
||||
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
|
||||
#define SYNCHRONIZE 0x00100000
|
||||
#define WAIT_OBJECT_0 0
|
||||
#define WAIT_TIMEOUT 258
|
||||
#define STILL_ACTIVE 259
|
||||
|
||||
struct STARTUPINFO_W
|
||||
{
|
||||
uint cb;
|
||||
string lpReserved;
|
||||
string lpDesktop;
|
||||
string lpTitle;
|
||||
uint dwX;
|
||||
uint dwY;
|
||||
uint dwXSize;
|
||||
uint dwYSize;
|
||||
uint dwXCountChars;
|
||||
uint dwYCountChars;
|
||||
uint dwFillAttribute;
|
||||
uint dwFlags;
|
||||
ushort wShowWindow;
|
||||
ushort cbReserved2;
|
||||
long lpReserved2;
|
||||
long hStdInput;
|
||||
long hStdOutput;
|
||||
long hStdError;
|
||||
};
|
||||
|
||||
struct PROCESS_INFORMATION
|
||||
{
|
||||
long hProcess;
|
||||
long hThread;
|
||||
uint dwProcessId;
|
||||
uint dwThreadId;
|
||||
};
|
||||
|
||||
#import "kernel32.dll"
|
||||
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
|
||||
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
|
||||
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
|
||||
int CloseHandle(long hObject);
|
||||
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
|
||||
#import
|
||||
|
||||
// バッチファイルのパス
|
||||
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
|
||||
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
|
||||
|
||||
// プロセス完了ファイルの設定
|
||||
string done_trend_file = "process_done_trend.txt";
|
||||
string done_entry_file = "process_done_entry.txt";
|
||||
|
||||
// Python出力ファイル
|
||||
string trend_state_file = "trend_state.txt";
|
||||
string target_prices_file = "target_prices.txt";
|
||||
|
||||
// Python実行中を判定するための管理ファイル
|
||||
string running_trend_file = "process_running_trend.txt";
|
||||
string running_entry_file = "process_running_entry.txt";
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| インプットの設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//--- 入力パラメータ
|
||||
input double lot_size = 0.01; // ロット数
|
||||
input double spread_limit = 60; // 許容スプレッド(point)
|
||||
input int magic_number = 10001; // マジックナンバー
|
||||
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
|
||||
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
|
||||
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
|
||||
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
|
||||
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
|
||||
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
|
||||
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
|
||||
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
|
||||
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
|
||||
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
|
||||
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
|
||||
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
|
||||
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
|
||||
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
|
||||
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
|
||||
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
|
||||
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
|
||||
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
|
||||
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
|
||||
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
|
||||
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
|
||||
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
|
||||
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
|
||||
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
|
||||
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
|
||||
ulong slippage = 10; // スリッページ
|
||||
|
||||
//--- 主要な定数・設定
|
||||
#define POSITION_LIMIT 48
|
||||
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
|
||||
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
|
||||
#define HISTORY_BARS 72
|
||||
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
|
||||
#define M15_CONFIRM_BARS 30
|
||||
#define M15_MIN_ENTRY_ZONE_POINTS 10
|
||||
#define M15_MIN_BODY_RATIO 0.25
|
||||
#define M15_REJECTION_WICK_RATIO 0.35
|
||||
#define ENTRY_RETRY_SECONDS 60
|
||||
#define ENTRY_RETRY_LIMIT 10
|
||||
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
|
||||
#define TARGET_SIZE 13
|
||||
#define DEFAULT_TARGET_PRICE 0.0
|
||||
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
|
||||
|
||||
#define MARKET_LOW_VOL_RANGE 0
|
||||
#define MARKET_HIGH_VOL_RANGE 1
|
||||
#define MARKET_LOW_VOL_UP 2
|
||||
#define MARKET_HIGH_VOL_UP 3
|
||||
#define MARKET_LOW_VOL_DOWN 4
|
||||
#define MARKET_HIGH_VOL_DOWN 5
|
||||
#define MARKET_TECHNICAL_ERROR_STOP 6
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| EAの状態をまとめる構造体
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
struct EAState
|
||||
{
|
||||
int trend_state; // H4 market_state(0..5、6は技術エラー停止)を格納する変数
|
||||
int res_chk; // GPTの回答が正しく取得できたか
|
||||
double en_price[5]; // エントリー基準価格
|
||||
double tp_price[5]; // 利益確定価格
|
||||
double sl_price[5]; // ロスカット基準価格
|
||||
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
|
||||
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
|
||||
int chk_cnt; // エントリー判定の試行回数
|
||||
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
|
||||
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
|
||||
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
|
||||
datetime last_chk;
|
||||
};
|
||||
|
||||
EAState g_ea; // EA全体の状態をここで管理
|
||||
|
||||
// initial_order 用の初回処理フラグ
|
||||
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
|
||||
bool g_init_trend_pending = false;
|
||||
bool g_init_entry_pending = false;
|
||||
|
||||
// H4/H1のバー更新状態
|
||||
int g_pre_bars_H4 = 0;
|
||||
int g_pre_bars_H1 = 0;
|
||||
int g_pre_bars_M15 = 0;
|
||||
bool g_bars_H1_check = false;
|
||||
bool g_bars_M15_check = false;
|
||||
|
||||
// ティックごとの価格情報
|
||||
struct TickContext
|
||||
{
|
||||
double ask;
|
||||
double bid;
|
||||
double spread;
|
||||
double spread_points;
|
||||
int digits;
|
||||
};
|
||||
|
||||
// 外部Pythonプロセスの状態
|
||||
struct ExternalProcessState
|
||||
{
|
||||
long handle;
|
||||
uint process_id;
|
||||
bool active;
|
||||
bool exit_code_ready;
|
||||
uint exit_code;
|
||||
datetime started_at;
|
||||
};
|
||||
|
||||
ExternalProcessState g_trend_process;
|
||||
ExternalProcessState g_entry_process;
|
||||
|
||||
CSLTPManager g_sltp_manager;
|
||||
CSLTPManagerPanel g_sltp_panel;
|
||||
SLTPManagerPanelSettings g_sltp_settings;
|
||||
bool g_sltp_settings_valid = false;
|
||||
bool g_sltp_panel_created = false;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 起動時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief EA起動時の初期化処理を行います。
|
||||
*
|
||||
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
|
||||
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
|
||||
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
|
||||
*/
|
||||
int OnInit()
|
||||
// プロセス完了ファイルと実行中ファイルの状態を初期化
|
||||
{
|
||||
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
|
||||
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
|
||||
|
||||
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
|
||||
g_init_trend_pending = (initial_order == 1);
|
||||
g_init_entry_pending = (initial_order == 1);
|
||||
|
||||
if(!InitializeSLTPManager())
|
||||
return INIT_FAILED;
|
||||
|
||||
return INIT_SUCCEEDED;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 終了時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
ResetExternalProcessState(g_trend_process);
|
||||
ResetExternalProcessState(g_entry_process);
|
||||
|
||||
if(g_sltp_panel_created)
|
||||
g_sltp_panel.Destroy(reason);
|
||||
|
||||
// Clear chart status text left by Comment() when the EA is removed.
|
||||
Comment("");
|
||||
ChartRedraw(0);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| ティック毎の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief ティック受信ごとにEA全体の処理を制御します。
|
||||
*
|
||||
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
|
||||
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
|
||||
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
|
||||
*/
|
||||
void OnTick()
|
||||
{
|
||||
TickContext ctx;
|
||||
if(!GetTickContext(ctx))
|
||||
return;
|
||||
|
||||
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
|
||||
ManageExpiredTrades();
|
||||
|
||||
// Existing-position protection stays active even while Python results are pending.
|
||||
ManageSLTPPositions();
|
||||
|
||||
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
|
||||
RecoverTimedOutPythonProcesses();
|
||||
|
||||
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
|
||||
ProcessTrendUpdate(g_ea);
|
||||
|
||||
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
|
||||
if(!IsTrendResultReady())
|
||||
return;
|
||||
|
||||
RefreshTrendState(g_ea);
|
||||
|
||||
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
|
||||
ProcessEntryUpdate(g_ea);
|
||||
|
||||
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
|
||||
ProcessM15EntryTimingUpdate();
|
||||
|
||||
UpdateStatusComment(ctx);
|
||||
|
||||
// ここから下は新規注文に関する処理。
|
||||
if(!IsSpreadAllowed(ctx))
|
||||
return;
|
||||
|
||||
if(!IsEntryResultReady())
|
||||
return;
|
||||
|
||||
RefreshTargetPrices(g_ea);
|
||||
ProcessEntryDecisionIfNeeded(g_ea, ctx);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| SLTP manager panel and settings bridge
|
||||
//+------------------------------------------------------------------+
|
||||
string SLTPBoolText(const bool value)
|
||||
{
|
||||
return value ? "ON" : "OFF";
|
||||
}
|
||||
|
||||
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
|
||||
{
|
||||
settings.manager_enabled = input_sltp_manager_enabled;
|
||||
|
||||
settings.use_breakeven = input_sltp_use_breakeven;
|
||||
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
|
||||
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
|
||||
|
||||
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
|
||||
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
|
||||
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
|
||||
|
||||
settings.use_active_trailing = input_sltp_use_active_trailing;
|
||||
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
|
||||
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
|
||||
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
|
||||
settings.active_step_move_pips = input_sltp_active_step_move_pips;
|
||||
|
||||
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
|
||||
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
|
||||
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
|
||||
|
||||
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
|
||||
}
|
||||
|
||||
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
|
||||
const bool print_summary)
|
||||
{
|
||||
g_sltp_settings_valid = false;
|
||||
|
||||
g_sltp_manager.SetMagicNumber((ulong)magic_number);
|
||||
g_sltp_manager.SetSymbol(_Symbol);
|
||||
g_sltp_manager.SetDeviationInPoints(slippage);
|
||||
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
|
||||
settings.breakeven_trigger_pips,
|
||||
settings.breakeven_buffer_pips);
|
||||
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
|
||||
settings.elapsed_breakeven_hours,
|
||||
settings.elapsed_breakeven_buffer_pips);
|
||||
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
|
||||
settings.active_breakeven_pips,
|
||||
settings.active_stop_loss_offset_pips,
|
||||
settings.active_step_trigger_pips,
|
||||
settings.active_step_move_pips);
|
||||
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
|
||||
settings.tp_progress_trigger_percent,
|
||||
settings.tp_progress_sl_lock_percent);
|
||||
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
|
||||
|
||||
if(!g_sltp_manager.ValidateSettings())
|
||||
{
|
||||
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_sltp_settings = settings;
|
||||
g_sltp_settings_valid = true;
|
||||
|
||||
if(print_summary)
|
||||
{
|
||||
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
|
||||
" BE=", SLTPBoolText(settings.use_breakeven),
|
||||
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
|
||||
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
|
||||
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
|
||||
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitializeSLTPManager()
|
||||
{
|
||||
SLTPManagerPanelSettings initial_settings;
|
||||
LoadSLTPInputSettings(initial_settings);
|
||||
|
||||
if(!ApplySLTPSettings(initial_settings, true))
|
||||
return false;
|
||||
|
||||
g_sltp_panel.Init(g_sltp_settings);
|
||||
if(input_sltp_show_panel)
|
||||
{
|
||||
if(!g_sltp_panel.CreatePanel())
|
||||
{
|
||||
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
|
||||
return true;
|
||||
}
|
||||
|
||||
g_sltp_panel.SetInitialValues();
|
||||
g_sltp_panel_created = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ManageSLTPPositions()
|
||||
{
|
||||
if(!g_sltp_settings_valid)
|
||||
return;
|
||||
if(!g_sltp_settings.manager_enabled)
|
||||
return;
|
||||
|
||||
g_sltp_manager.ManagePositions();
|
||||
g_sltp_manager.HighVolatilityLimit();
|
||||
}
|
||||
|
||||
void OnChartEvent(const int id,
|
||||
const long &lparam,
|
||||
const double &dparam,
|
||||
const string &sparam)
|
||||
{
|
||||
if(!g_sltp_panel_created)
|
||||
return;
|
||||
|
||||
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
|
||||
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
|
||||
{
|
||||
if(!ApplySLTPSettings(candidate_settings, true))
|
||||
Print("HIT SLTP panel apply failed. Please review panel values.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Function implementations are kept in project headers so the EA entry points stay compact.
|
||||
#include <MyLib/Common/HITRuntimeController.mqh>
|
||||
#include <MyLib/Signals/HITEntrySignal.mqh>
|
||||
#include <MyLib/Common/HITExternalProcess.mqh>
|
||||
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
|
||||
#include <MyLib/Trading/HITTradeManager.mqh>
|
||||
@@ -0,0 +1,462 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HIT_EA.mq5 |
|
||||
//| Copyright 2026, nanpin-martin.com |
|
||||
//| https://www.nanpin-martin.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2026, nanpin-martin.com"
|
||||
#property link "https://nanpin-martin.com/"
|
||||
#property version "1.01"
|
||||
|
||||
#include <MyLib/Trading/SLTPManager.mqh>
|
||||
#include <MyLib/Panel/SLTPManagerPanel.mqh>
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| バッチファイル実行用の設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
// Windowsプロセス起動・終了確認用
|
||||
#define CREATE_NO_WINDOW 0x08000000
|
||||
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
|
||||
#define SYNCHRONIZE 0x00100000
|
||||
#define WAIT_OBJECT_0 0
|
||||
#define WAIT_TIMEOUT 258
|
||||
#define STILL_ACTIVE 259
|
||||
|
||||
struct STARTUPINFO_W
|
||||
{
|
||||
uint cb;
|
||||
string lpReserved;
|
||||
string lpDesktop;
|
||||
string lpTitle;
|
||||
uint dwX;
|
||||
uint dwY;
|
||||
uint dwXSize;
|
||||
uint dwYSize;
|
||||
uint dwXCountChars;
|
||||
uint dwYCountChars;
|
||||
uint dwFillAttribute;
|
||||
uint dwFlags;
|
||||
ushort wShowWindow;
|
||||
ushort cbReserved2;
|
||||
long lpReserved2;
|
||||
long hStdInput;
|
||||
long hStdOutput;
|
||||
long hStdError;
|
||||
};
|
||||
|
||||
struct PROCESS_INFORMATION
|
||||
{
|
||||
long hProcess;
|
||||
long hThread;
|
||||
uint dwProcessId;
|
||||
uint dwThreadId;
|
||||
};
|
||||
|
||||
#import "kernel32.dll"
|
||||
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
|
||||
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
|
||||
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
|
||||
int CloseHandle(long hObject);
|
||||
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
|
||||
#import
|
||||
|
||||
// バッチファイルのパス
|
||||
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
|
||||
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
|
||||
|
||||
// プロセス完了ファイルの設定
|
||||
string done_trend_file = "process_done_trend.txt";
|
||||
string done_entry_file = "process_done_entry.txt";
|
||||
|
||||
// Python出力ファイル
|
||||
string trend_state_file = "trend_state.txt";
|
||||
string target_prices_file = "target_prices.txt";
|
||||
string target_zones_file = "target_zones.txt";
|
||||
|
||||
// Python実行中を判定するための管理ファイル
|
||||
string running_trend_file = "process_running_trend.txt";
|
||||
string running_entry_file = "process_running_entry.txt";
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| インプットの設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
enum SplitLotMode
|
||||
{
|
||||
SPLIT_LOT_TOTAL = 0, // 総ロットをN分割
|
||||
SPLIT_LOT_FIXED = 1 // 1注文あたり固定ロット
|
||||
};
|
||||
|
||||
//--- 入力パラメータ
|
||||
input double lot_size = 0.01; // ロット数
|
||||
input double spread_limit = 60; // 許容スプレッド(point)
|
||||
input int magic_number = 10001; // マジックナンバー
|
||||
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
|
||||
input int input_position_limit = 10; // 自EAの未約定注文+ポジション上限
|
||||
input bool use_split_entry_zone = false; // H1予測ゾーンで分割エントリーする
|
||||
input int split_entry_count = 3; // 分割エントリー本数(1..10)
|
||||
input SplitLotMode split_lot_mode = SPLIT_LOT_TOTAL; // 分割ロット配分モード
|
||||
input double split_total_lot_size = 0.09; // 総量分割モードの合計ロット
|
||||
input double split_fixed_lot_size = 0.01; // 固定ロットモードの1注文ロット
|
||||
input bool cancel_old_split_pending_on_new_zone = true; // 新ゾーン読込時に旧分割pendingを取消
|
||||
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
|
||||
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
|
||||
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
|
||||
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
|
||||
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
|
||||
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
|
||||
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
|
||||
input int input_entry_max_candidate_age_minutes = 120; // H1候補価格を新規発注に使う最大経過分数
|
||||
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
|
||||
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
|
||||
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
|
||||
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
|
||||
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
|
||||
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
|
||||
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
|
||||
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
|
||||
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
|
||||
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
|
||||
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
|
||||
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
|
||||
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
|
||||
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
|
||||
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
|
||||
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
|
||||
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
|
||||
ulong slippage = 10; // スリッページ
|
||||
|
||||
//--- 主要な定数・設定
|
||||
#define POSITION_LIMIT 48
|
||||
#define ENTRY_H1_LIMIT 2 // H1本数(=2時間)
|
||||
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
|
||||
#define HISTORY_BARS 72
|
||||
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
|
||||
#define M15_CONFIRM_BARS 30
|
||||
#define M15_MIN_ENTRY_ZONE_POINTS 10
|
||||
#define M15_MIN_BODY_RATIO 0.25
|
||||
#define M15_REJECTION_WICK_RATIO 0.35
|
||||
#define ENTRY_RETRY_SECONDS 60
|
||||
#define ENTRY_RETRY_LIMIT 10
|
||||
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
|
||||
#define TARGET_SIZE 13
|
||||
#define TARGET_ZONE_SCHEMA_VERSION 2
|
||||
#define DEFAULT_TARGET_PRICE 0.0
|
||||
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
|
||||
|
||||
#define MARKET_LOW_VOL_RANGE 0
|
||||
#define MARKET_HIGH_VOL_RANGE 1
|
||||
#define MARKET_LOW_VOL_UP 2
|
||||
#define MARKET_HIGH_VOL_UP 3
|
||||
#define MARKET_LOW_VOL_DOWN 4
|
||||
#define MARKET_HIGH_VOL_DOWN 5
|
||||
#define MARKET_TECHNICAL_ERROR_STOP 6
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| EAの状態をまとめる構造体
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
struct EAState
|
||||
{
|
||||
int trend_state; // H4 market_state(0..5、6は技術エラー停止)を格納する変数
|
||||
int res_chk; // GPTの回答が正しく取得できたか
|
||||
double en_price[5]; // エントリー基準価格
|
||||
double tp_price[5]; // 利益確定価格
|
||||
double sl_price[5]; // ロスカット基準価格
|
||||
int zone_res_chk; // 予測ゾーンが正しく取得できたか
|
||||
string zone_candidate_id; // H1確定足由来の候補ID
|
||||
double zone_low[5]; // 分割エントリー用ゾーン下限
|
||||
double zone_high[5]; // 分割エントリー用ゾーン上限
|
||||
double zone_tp[5]; // 分割エントリー用TP
|
||||
double zone_sl[5]; // 分割エントリー用SL
|
||||
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
|
||||
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
|
||||
int chk_cnt; // エントリー判定の試行回数
|
||||
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
|
||||
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
|
||||
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
|
||||
datetime last_chk;
|
||||
};
|
||||
|
||||
EAState g_ea; // EA全体の状態をここで管理
|
||||
|
||||
// initial_order 用の初回処理フラグ
|
||||
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
|
||||
bool g_init_trend_pending = false;
|
||||
bool g_init_entry_pending = false;
|
||||
|
||||
// H4/H1のバー更新状態
|
||||
int g_pre_bars_H4 = 0;
|
||||
int g_pre_bars_H1 = 0;
|
||||
int g_pre_bars_M15 = 0;
|
||||
bool g_bars_H1_check = false;
|
||||
bool g_bars_M15_check = false;
|
||||
|
||||
// ティックごとの価格情報
|
||||
struct TickContext
|
||||
{
|
||||
double ask;
|
||||
double bid;
|
||||
double spread;
|
||||
double spread_points;
|
||||
int digits;
|
||||
};
|
||||
|
||||
// 外部Pythonプロセスの状態
|
||||
struct ExternalProcessState
|
||||
{
|
||||
long handle;
|
||||
uint process_id;
|
||||
bool active;
|
||||
bool exit_code_ready;
|
||||
uint exit_code;
|
||||
datetime started_at;
|
||||
};
|
||||
|
||||
ExternalProcessState g_trend_process;
|
||||
ExternalProcessState g_entry_process;
|
||||
|
||||
CSLTPManager g_sltp_manager;
|
||||
CSLTPManagerPanel g_sltp_panel;
|
||||
SLTPManagerPanelSettings g_sltp_settings;
|
||||
bool g_sltp_settings_valid = false;
|
||||
bool g_sltp_panel_created = false;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 起動時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief EA起動時の初期化処理を行います。
|
||||
*
|
||||
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
|
||||
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
|
||||
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
|
||||
*/
|
||||
int OnInit()
|
||||
// プロセス完了ファイルと実行中ファイルの状態を初期化
|
||||
{
|
||||
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
|
||||
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
|
||||
|
||||
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
|
||||
g_init_trend_pending = (initial_order == 1);
|
||||
g_init_entry_pending = (initial_order == 1);
|
||||
|
||||
if(!InitializeSLTPManager())
|
||||
return INIT_FAILED;
|
||||
|
||||
return INIT_SUCCEEDED;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 終了時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
ResetExternalProcessState(g_trend_process);
|
||||
ResetExternalProcessState(g_entry_process);
|
||||
|
||||
if(g_sltp_panel_created)
|
||||
g_sltp_panel.Destroy(reason);
|
||||
|
||||
// Clear chart status text left by Comment() when the EA is removed.
|
||||
Comment("");
|
||||
ChartRedraw(0);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| ティック毎の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief ティック受信ごとにEA全体の処理を制御します。
|
||||
*
|
||||
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
|
||||
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
|
||||
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
|
||||
*/
|
||||
void OnTick()
|
||||
{
|
||||
TickContext ctx;
|
||||
if(!GetTickContext(ctx))
|
||||
return;
|
||||
|
||||
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
|
||||
ManageExpiredTrades();
|
||||
|
||||
// Existing-position protection stays active even while Python results are pending.
|
||||
ManageSLTPPositions();
|
||||
|
||||
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
|
||||
RecoverTimedOutPythonProcesses();
|
||||
|
||||
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
|
||||
ProcessTrendUpdate(g_ea);
|
||||
|
||||
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
|
||||
if(!IsTrendResultReady())
|
||||
return;
|
||||
|
||||
RefreshTrendState(g_ea);
|
||||
|
||||
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
|
||||
ProcessEntryUpdate(g_ea);
|
||||
|
||||
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
|
||||
ProcessM15EntryTimingUpdate();
|
||||
|
||||
UpdateStatusComment(ctx);
|
||||
|
||||
// ここから下は新規注文に関する処理。
|
||||
if(!IsSpreadAllowed(ctx))
|
||||
return;
|
||||
|
||||
if(!IsEntryResultReady())
|
||||
return;
|
||||
|
||||
RefreshTargetPrices(g_ea);
|
||||
ProcessEntryDecisionIfNeeded(g_ea, ctx);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| SLTP manager panel and settings bridge
|
||||
//+------------------------------------------------------------------+
|
||||
string SLTPBoolText(const bool value)
|
||||
{
|
||||
return value ? "ON" : "OFF";
|
||||
}
|
||||
|
||||
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
|
||||
{
|
||||
settings.manager_enabled = input_sltp_manager_enabled;
|
||||
|
||||
settings.use_breakeven = input_sltp_use_breakeven;
|
||||
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
|
||||
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
|
||||
|
||||
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
|
||||
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
|
||||
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
|
||||
|
||||
settings.use_active_trailing = input_sltp_use_active_trailing;
|
||||
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
|
||||
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
|
||||
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
|
||||
settings.active_step_move_pips = input_sltp_active_step_move_pips;
|
||||
|
||||
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
|
||||
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
|
||||
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
|
||||
|
||||
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
|
||||
}
|
||||
|
||||
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
|
||||
const bool print_summary)
|
||||
{
|
||||
g_sltp_settings_valid = false;
|
||||
|
||||
g_sltp_manager.SetMagicNumber((ulong)magic_number);
|
||||
g_sltp_manager.SetSymbol(_Symbol);
|
||||
g_sltp_manager.SetDeviationInPoints(slippage);
|
||||
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
|
||||
settings.breakeven_trigger_pips,
|
||||
settings.breakeven_buffer_pips);
|
||||
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
|
||||
settings.elapsed_breakeven_hours,
|
||||
settings.elapsed_breakeven_buffer_pips);
|
||||
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
|
||||
settings.active_breakeven_pips,
|
||||
settings.active_stop_loss_offset_pips,
|
||||
settings.active_step_trigger_pips,
|
||||
settings.active_step_move_pips);
|
||||
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
|
||||
settings.tp_progress_trigger_percent,
|
||||
settings.tp_progress_sl_lock_percent);
|
||||
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
|
||||
|
||||
if(!g_sltp_manager.ValidateSettings())
|
||||
{
|
||||
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_sltp_settings = settings;
|
||||
g_sltp_settings_valid = true;
|
||||
|
||||
if(print_summary)
|
||||
{
|
||||
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
|
||||
" BE=", SLTPBoolText(settings.use_breakeven),
|
||||
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
|
||||
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
|
||||
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
|
||||
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitializeSLTPManager()
|
||||
{
|
||||
SLTPManagerPanelSettings initial_settings;
|
||||
LoadSLTPInputSettings(initial_settings);
|
||||
|
||||
if(!ApplySLTPSettings(initial_settings, true))
|
||||
return false;
|
||||
|
||||
g_sltp_panel.Init(g_sltp_settings);
|
||||
if(input_sltp_show_panel)
|
||||
{
|
||||
if(!g_sltp_panel.CreatePanel())
|
||||
{
|
||||
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
|
||||
return true;
|
||||
}
|
||||
|
||||
g_sltp_panel.SetInitialValues();
|
||||
g_sltp_panel_created = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ManageSLTPPositions()
|
||||
{
|
||||
if(!g_sltp_settings_valid)
|
||||
return;
|
||||
if(!g_sltp_settings.manager_enabled)
|
||||
return;
|
||||
|
||||
g_sltp_manager.ManagePositions();
|
||||
g_sltp_manager.HighVolatilityLimit();
|
||||
}
|
||||
|
||||
void OnChartEvent(const int id,
|
||||
const long &lparam,
|
||||
const double &dparam,
|
||||
const string &sparam)
|
||||
{
|
||||
if(!g_sltp_panel_created)
|
||||
return;
|
||||
|
||||
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
|
||||
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
|
||||
{
|
||||
if(!ApplySLTPSettings(candidate_settings, true))
|
||||
Print("HIT SLTP panel apply failed. Please review panel values.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Function implementations are kept in project headers so the EA entry points stay compact.
|
||||
#include <MyLib/Common/HITRuntimeController.mqh>
|
||||
#include <MyLib/Signals/HITEntrySignal.mqh>
|
||||
#include <MyLib/Common/HITExternalProcess.mqh>
|
||||
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
|
||||
#include <MyLib/Trading/HITTradeManager.mqh>
|
||||
@@ -0,0 +1,441 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HIT_EA.mq5 |
|
||||
//| Copyright 2026, nanpin-martin.com |
|
||||
//| https://www.nanpin-martin.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2026, nanpin-martin.com"
|
||||
#property link "https://nanpin-martin.com/"
|
||||
#property version "1.01"
|
||||
|
||||
#include <MyLib/Trading/SLTPManager.mqh>
|
||||
#include <MyLib/Panel/SLTPManagerPanel.mqh>
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| バッチファイル実行用の設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
// Windowsプロセス起動・終了確認用
|
||||
#define CREATE_NO_WINDOW 0x08000000
|
||||
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
|
||||
#define SYNCHRONIZE 0x00100000
|
||||
#define WAIT_OBJECT_0 0
|
||||
#define WAIT_TIMEOUT 258
|
||||
#define STILL_ACTIVE 259
|
||||
|
||||
struct STARTUPINFO_W
|
||||
{
|
||||
uint cb;
|
||||
string lpReserved;
|
||||
string lpDesktop;
|
||||
string lpTitle;
|
||||
uint dwX;
|
||||
uint dwY;
|
||||
uint dwXSize;
|
||||
uint dwYSize;
|
||||
uint dwXCountChars;
|
||||
uint dwYCountChars;
|
||||
uint dwFillAttribute;
|
||||
uint dwFlags;
|
||||
ushort wShowWindow;
|
||||
ushort cbReserved2;
|
||||
long lpReserved2;
|
||||
long hStdInput;
|
||||
long hStdOutput;
|
||||
long hStdError;
|
||||
};
|
||||
|
||||
struct PROCESS_INFORMATION
|
||||
{
|
||||
long hProcess;
|
||||
long hThread;
|
||||
uint dwProcessId;
|
||||
uint dwThreadId;
|
||||
};
|
||||
|
||||
#import "kernel32.dll"
|
||||
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
|
||||
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
|
||||
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
|
||||
int CloseHandle(long hObject);
|
||||
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
|
||||
#import
|
||||
|
||||
// バッチファイルのパス
|
||||
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
|
||||
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
|
||||
|
||||
// プロセス完了ファイルの設定
|
||||
string done_trend_file = "process_done_trend.txt";
|
||||
string done_entry_file = "process_done_entry.txt";
|
||||
|
||||
// Python出力ファイル
|
||||
string trend_state_file = "trend_state.txt";
|
||||
string target_prices_file = "target_prices.txt";
|
||||
|
||||
// Python実行中を判定するための管理ファイル
|
||||
string running_trend_file = "process_running_trend.txt";
|
||||
string running_entry_file = "process_running_entry.txt";
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| インプットの設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//--- 入力パラメータ
|
||||
input double lot_size = 0.01; // ロット数
|
||||
input double spread_limit = 60; // 許容スプレッド(point)
|
||||
input int magic_number = 10001; // マジックナンバー
|
||||
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
|
||||
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
|
||||
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
|
||||
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
|
||||
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
|
||||
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
|
||||
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
|
||||
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
|
||||
input int input_entry_max_candidate_age_minutes = 45; // H1候補価格を新規発注に使う最大経過分数
|
||||
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
|
||||
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
|
||||
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
|
||||
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
|
||||
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
|
||||
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
|
||||
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
|
||||
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
|
||||
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
|
||||
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
|
||||
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
|
||||
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
|
||||
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
|
||||
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
|
||||
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
|
||||
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
|
||||
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
|
||||
ulong slippage = 10; // スリッページ
|
||||
|
||||
//--- 主要な定数・設定
|
||||
#define POSITION_LIMIT 48
|
||||
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
|
||||
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
|
||||
#define HISTORY_BARS 72
|
||||
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
|
||||
#define M15_CONFIRM_BARS 30
|
||||
#define M15_MIN_ENTRY_ZONE_POINTS 10
|
||||
#define M15_MIN_BODY_RATIO 0.25
|
||||
#define M15_REJECTION_WICK_RATIO 0.35
|
||||
#define ENTRY_RETRY_SECONDS 60
|
||||
#define ENTRY_RETRY_LIMIT 10
|
||||
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
|
||||
#define TARGET_SIZE 13
|
||||
#define DEFAULT_TARGET_PRICE 0.0
|
||||
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
|
||||
|
||||
#define MARKET_LOW_VOL_RANGE 0
|
||||
#define MARKET_HIGH_VOL_RANGE 1
|
||||
#define MARKET_LOW_VOL_UP 2
|
||||
#define MARKET_HIGH_VOL_UP 3
|
||||
#define MARKET_LOW_VOL_DOWN 4
|
||||
#define MARKET_HIGH_VOL_DOWN 5
|
||||
#define MARKET_TECHNICAL_ERROR_STOP 6
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| EAの状態をまとめる構造体
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
struct EAState
|
||||
{
|
||||
int trend_state; // H4 market_state(0..5、6は技術エラー停止)を格納する変数
|
||||
int res_chk; // GPTの回答が正しく取得できたか
|
||||
double en_price[5]; // エントリー基準価格
|
||||
double tp_price[5]; // 利益確定価格
|
||||
double sl_price[5]; // ロスカット基準価格
|
||||
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
|
||||
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
|
||||
int chk_cnt; // エントリー判定の試行回数
|
||||
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
|
||||
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
|
||||
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
|
||||
datetime last_chk;
|
||||
};
|
||||
|
||||
EAState g_ea; // EA全体の状態をここで管理
|
||||
|
||||
// initial_order 用の初回処理フラグ
|
||||
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
|
||||
bool g_init_trend_pending = false;
|
||||
bool g_init_entry_pending = false;
|
||||
|
||||
// H4/H1のバー更新状態
|
||||
int g_pre_bars_H4 = 0;
|
||||
int g_pre_bars_H1 = 0;
|
||||
int g_pre_bars_M15 = 0;
|
||||
bool g_bars_H1_check = false;
|
||||
bool g_bars_M15_check = false;
|
||||
|
||||
// ティックごとの価格情報
|
||||
struct TickContext
|
||||
{
|
||||
double ask;
|
||||
double bid;
|
||||
double spread;
|
||||
double spread_points;
|
||||
int digits;
|
||||
};
|
||||
|
||||
// 外部Pythonプロセスの状態
|
||||
struct ExternalProcessState
|
||||
{
|
||||
long handle;
|
||||
uint process_id;
|
||||
bool active;
|
||||
bool exit_code_ready;
|
||||
uint exit_code;
|
||||
datetime started_at;
|
||||
};
|
||||
|
||||
ExternalProcessState g_trend_process;
|
||||
ExternalProcessState g_entry_process;
|
||||
|
||||
CSLTPManager g_sltp_manager;
|
||||
CSLTPManagerPanel g_sltp_panel;
|
||||
SLTPManagerPanelSettings g_sltp_settings;
|
||||
bool g_sltp_settings_valid = false;
|
||||
bool g_sltp_panel_created = false;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 起動時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief EA起動時の初期化処理を行います。
|
||||
*
|
||||
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
|
||||
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
|
||||
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
|
||||
*/
|
||||
int OnInit()
|
||||
// プロセス完了ファイルと実行中ファイルの状態を初期化
|
||||
{
|
||||
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
|
||||
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
|
||||
|
||||
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
|
||||
g_init_trend_pending = (initial_order == 1);
|
||||
g_init_entry_pending = (initial_order == 1);
|
||||
|
||||
if(!InitializeSLTPManager())
|
||||
return INIT_FAILED;
|
||||
|
||||
return INIT_SUCCEEDED;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 終了時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
ResetExternalProcessState(g_trend_process);
|
||||
ResetExternalProcessState(g_entry_process);
|
||||
|
||||
if(g_sltp_panel_created)
|
||||
g_sltp_panel.Destroy(reason);
|
||||
|
||||
// Clear chart status text left by Comment() when the EA is removed.
|
||||
Comment("");
|
||||
ChartRedraw(0);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| ティック毎の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief ティック受信ごとにEA全体の処理を制御します。
|
||||
*
|
||||
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
|
||||
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
|
||||
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
|
||||
*/
|
||||
void OnTick()
|
||||
{
|
||||
TickContext ctx;
|
||||
if(!GetTickContext(ctx))
|
||||
return;
|
||||
|
||||
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
|
||||
ManageExpiredTrades();
|
||||
|
||||
// Existing-position protection stays active even while Python results are pending.
|
||||
ManageSLTPPositions();
|
||||
|
||||
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
|
||||
RecoverTimedOutPythonProcesses();
|
||||
|
||||
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
|
||||
ProcessTrendUpdate(g_ea);
|
||||
|
||||
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
|
||||
if(!IsTrendResultReady())
|
||||
return;
|
||||
|
||||
RefreshTrendState(g_ea);
|
||||
|
||||
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
|
||||
ProcessEntryUpdate(g_ea);
|
||||
|
||||
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
|
||||
ProcessM15EntryTimingUpdate();
|
||||
|
||||
UpdateStatusComment(ctx);
|
||||
|
||||
// ここから下は新規注文に関する処理。
|
||||
if(!IsSpreadAllowed(ctx))
|
||||
return;
|
||||
|
||||
if(!IsEntryResultReady())
|
||||
return;
|
||||
|
||||
RefreshTargetPrices(g_ea);
|
||||
ProcessEntryDecisionIfNeeded(g_ea, ctx);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| SLTP manager panel and settings bridge
|
||||
//+------------------------------------------------------------------+
|
||||
string SLTPBoolText(const bool value)
|
||||
{
|
||||
return value ? "ON" : "OFF";
|
||||
}
|
||||
|
||||
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
|
||||
{
|
||||
settings.manager_enabled = input_sltp_manager_enabled;
|
||||
|
||||
settings.use_breakeven = input_sltp_use_breakeven;
|
||||
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
|
||||
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
|
||||
|
||||
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
|
||||
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
|
||||
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
|
||||
|
||||
settings.use_active_trailing = input_sltp_use_active_trailing;
|
||||
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
|
||||
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
|
||||
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
|
||||
settings.active_step_move_pips = input_sltp_active_step_move_pips;
|
||||
|
||||
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
|
||||
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
|
||||
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
|
||||
|
||||
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
|
||||
}
|
||||
|
||||
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
|
||||
const bool print_summary)
|
||||
{
|
||||
g_sltp_settings_valid = false;
|
||||
|
||||
g_sltp_manager.SetMagicNumber((ulong)magic_number);
|
||||
g_sltp_manager.SetSymbol(_Symbol);
|
||||
g_sltp_manager.SetDeviationInPoints(slippage);
|
||||
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
|
||||
settings.breakeven_trigger_pips,
|
||||
settings.breakeven_buffer_pips);
|
||||
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
|
||||
settings.elapsed_breakeven_hours,
|
||||
settings.elapsed_breakeven_buffer_pips);
|
||||
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
|
||||
settings.active_breakeven_pips,
|
||||
settings.active_stop_loss_offset_pips,
|
||||
settings.active_step_trigger_pips,
|
||||
settings.active_step_move_pips);
|
||||
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
|
||||
settings.tp_progress_trigger_percent,
|
||||
settings.tp_progress_sl_lock_percent);
|
||||
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
|
||||
|
||||
if(!g_sltp_manager.ValidateSettings())
|
||||
{
|
||||
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_sltp_settings = settings;
|
||||
g_sltp_settings_valid = true;
|
||||
|
||||
if(print_summary)
|
||||
{
|
||||
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
|
||||
" BE=", SLTPBoolText(settings.use_breakeven),
|
||||
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
|
||||
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
|
||||
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
|
||||
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitializeSLTPManager()
|
||||
{
|
||||
SLTPManagerPanelSettings initial_settings;
|
||||
LoadSLTPInputSettings(initial_settings);
|
||||
|
||||
if(!ApplySLTPSettings(initial_settings, true))
|
||||
return false;
|
||||
|
||||
g_sltp_panel.Init(g_sltp_settings);
|
||||
if(input_sltp_show_panel)
|
||||
{
|
||||
if(!g_sltp_panel.CreatePanel())
|
||||
{
|
||||
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
|
||||
return true;
|
||||
}
|
||||
|
||||
g_sltp_panel.SetInitialValues();
|
||||
g_sltp_panel_created = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ManageSLTPPositions()
|
||||
{
|
||||
if(!g_sltp_settings_valid)
|
||||
return;
|
||||
if(!g_sltp_settings.manager_enabled)
|
||||
return;
|
||||
|
||||
g_sltp_manager.ManagePositions();
|
||||
g_sltp_manager.HighVolatilityLimit();
|
||||
}
|
||||
|
||||
void OnChartEvent(const int id,
|
||||
const long &lparam,
|
||||
const double &dparam,
|
||||
const string &sparam)
|
||||
{
|
||||
if(!g_sltp_panel_created)
|
||||
return;
|
||||
|
||||
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
|
||||
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
|
||||
{
|
||||
if(!ApplySLTPSettings(candidate_settings, true))
|
||||
Print("HIT SLTP panel apply failed. Please review panel values.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Function implementations are kept in project headers so the EA entry points stay compact.
|
||||
#include <MyLib/Common/HITRuntimeController.mqh>
|
||||
#include <MyLib/Signals/HITEntrySignal.mqh>
|
||||
#include <MyLib/Common/HITExternalProcess.mqh>
|
||||
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
|
||||
#include <MyLib/Trading/HITTradeManager.mqh>
|
||||
@@ -0,0 +1,441 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HIT_EA.mq5 |
|
||||
//| Copyright 2026, nanpin-martin.com |
|
||||
//| https://www.nanpin-martin.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2026, nanpin-martin.com"
|
||||
#property link "https://nanpin-martin.com/"
|
||||
#property version "1.01"
|
||||
|
||||
#include <MyLib/Trading/SLTPManager.mqh>
|
||||
#include <MyLib/Panel/SLTPManagerPanel.mqh>
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| バッチファイル実行用の設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
// Windowsプロセス起動・終了確認用
|
||||
#define CREATE_NO_WINDOW 0x08000000
|
||||
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
|
||||
#define SYNCHRONIZE 0x00100000
|
||||
#define WAIT_OBJECT_0 0
|
||||
#define WAIT_TIMEOUT 258
|
||||
#define STILL_ACTIVE 259
|
||||
|
||||
struct STARTUPINFO_W
|
||||
{
|
||||
uint cb;
|
||||
string lpReserved;
|
||||
string lpDesktop;
|
||||
string lpTitle;
|
||||
uint dwX;
|
||||
uint dwY;
|
||||
uint dwXSize;
|
||||
uint dwYSize;
|
||||
uint dwXCountChars;
|
||||
uint dwYCountChars;
|
||||
uint dwFillAttribute;
|
||||
uint dwFlags;
|
||||
ushort wShowWindow;
|
||||
ushort cbReserved2;
|
||||
long lpReserved2;
|
||||
long hStdInput;
|
||||
long hStdOutput;
|
||||
long hStdError;
|
||||
};
|
||||
|
||||
struct PROCESS_INFORMATION
|
||||
{
|
||||
long hProcess;
|
||||
long hThread;
|
||||
uint dwProcessId;
|
||||
uint dwThreadId;
|
||||
};
|
||||
|
||||
#import "kernel32.dll"
|
||||
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
|
||||
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
|
||||
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
|
||||
int CloseHandle(long hObject);
|
||||
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
|
||||
#import
|
||||
|
||||
// バッチファイルのパス
|
||||
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
|
||||
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
|
||||
|
||||
// プロセス完了ファイルの設定
|
||||
string done_trend_file = "process_done_trend.txt";
|
||||
string done_entry_file = "process_done_entry.txt";
|
||||
|
||||
// Python出力ファイル
|
||||
string trend_state_file = "trend_state.txt";
|
||||
string target_prices_file = "target_prices.txt";
|
||||
|
||||
// Python実行中を判定するための管理ファイル
|
||||
string running_trend_file = "process_running_trend.txt";
|
||||
string running_entry_file = "process_running_entry.txt";
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| インプットの設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//--- 入力パラメータ
|
||||
input double lot_size = 0.01; // ロット数
|
||||
input double spread_limit = 60; // 許容スプレッド(point)
|
||||
input int magic_number = 10001; // マジックナンバー
|
||||
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
|
||||
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
|
||||
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
|
||||
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
|
||||
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
|
||||
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
|
||||
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
|
||||
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
|
||||
input int input_entry_max_candidate_age_minutes = 45; // H1候補価格を新規発注に使う最大経過分数
|
||||
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
|
||||
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
|
||||
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
|
||||
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
|
||||
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
|
||||
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
|
||||
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
|
||||
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
|
||||
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
|
||||
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
|
||||
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
|
||||
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
|
||||
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
|
||||
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
|
||||
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
|
||||
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
|
||||
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
|
||||
ulong slippage = 10; // スリッページ
|
||||
|
||||
//--- 主要な定数・設定
|
||||
#define POSITION_LIMIT 48
|
||||
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
|
||||
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
|
||||
#define HISTORY_BARS 72
|
||||
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
|
||||
#define M15_CONFIRM_BARS 30
|
||||
#define M15_MIN_ENTRY_ZONE_POINTS 10
|
||||
#define M15_MIN_BODY_RATIO 0.25
|
||||
#define M15_REJECTION_WICK_RATIO 0.35
|
||||
#define ENTRY_RETRY_SECONDS 60
|
||||
#define ENTRY_RETRY_LIMIT 10
|
||||
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
|
||||
#define TARGET_SIZE 13
|
||||
#define DEFAULT_TARGET_PRICE 0.0
|
||||
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
|
||||
|
||||
#define MARKET_LOW_VOL_RANGE 0
|
||||
#define MARKET_HIGH_VOL_RANGE 1
|
||||
#define MARKET_LOW_VOL_UP 2
|
||||
#define MARKET_HIGH_VOL_UP 3
|
||||
#define MARKET_LOW_VOL_DOWN 4
|
||||
#define MARKET_HIGH_VOL_DOWN 5
|
||||
#define MARKET_TECHNICAL_ERROR_STOP 6
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| EAの状態をまとめる構造体
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
struct EAState
|
||||
{
|
||||
int trend_state; // H4 market_state(0..5、6は技術エラー停止)を格納する変数
|
||||
int res_chk; // GPTの回答が正しく取得できたか
|
||||
double en_price[5]; // エントリー基準価格
|
||||
double tp_price[5]; // 利益確定価格
|
||||
double sl_price[5]; // ロスカット基準価格
|
||||
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
|
||||
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
|
||||
int chk_cnt; // エントリー判定の試行回数
|
||||
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
|
||||
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
|
||||
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
|
||||
datetime last_chk;
|
||||
};
|
||||
|
||||
EAState g_ea; // EA全体の状態をここで管理
|
||||
|
||||
// initial_order 用の初回処理フラグ
|
||||
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
|
||||
bool g_init_trend_pending = false;
|
||||
bool g_init_entry_pending = false;
|
||||
|
||||
// H4/H1のバー更新状態
|
||||
int g_pre_bars_H4 = 0;
|
||||
int g_pre_bars_H1 = 0;
|
||||
int g_pre_bars_M15 = 0;
|
||||
bool g_bars_H1_check = false;
|
||||
bool g_bars_M15_check = false;
|
||||
|
||||
// ティックごとの価格情報
|
||||
struct TickContext
|
||||
{
|
||||
double ask;
|
||||
double bid;
|
||||
double spread;
|
||||
double spread_points;
|
||||
int digits;
|
||||
};
|
||||
|
||||
// 外部Pythonプロセスの状態
|
||||
struct ExternalProcessState
|
||||
{
|
||||
long handle;
|
||||
uint process_id;
|
||||
bool active;
|
||||
bool exit_code_ready;
|
||||
uint exit_code;
|
||||
datetime started_at;
|
||||
};
|
||||
|
||||
ExternalProcessState g_trend_process;
|
||||
ExternalProcessState g_entry_process;
|
||||
|
||||
CSLTPManager g_sltp_manager;
|
||||
CSLTPManagerPanel g_sltp_panel;
|
||||
SLTPManagerPanelSettings g_sltp_settings;
|
||||
bool g_sltp_settings_valid = false;
|
||||
bool g_sltp_panel_created = false;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 起動時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief EA起動時の初期化処理を行います。
|
||||
*
|
||||
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
|
||||
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
|
||||
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
|
||||
*/
|
||||
int OnInit()
|
||||
// プロセス完了ファイルと実行中ファイルの状態を初期化
|
||||
{
|
||||
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
|
||||
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
|
||||
|
||||
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
|
||||
g_init_trend_pending = (initial_order == 1);
|
||||
g_init_entry_pending = (initial_order == 1);
|
||||
|
||||
if(!InitializeSLTPManager())
|
||||
return INIT_FAILED;
|
||||
|
||||
return INIT_SUCCEEDED;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 終了時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
ResetExternalProcessState(g_trend_process);
|
||||
ResetExternalProcessState(g_entry_process);
|
||||
|
||||
if(g_sltp_panel_created)
|
||||
g_sltp_panel.Destroy(reason);
|
||||
|
||||
// Clear chart status text left by Comment() when the EA is removed.
|
||||
Comment("");
|
||||
ChartRedraw(0);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| ティック毎の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief ティック受信ごとにEA全体の処理を制御します。
|
||||
*
|
||||
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
|
||||
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
|
||||
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
|
||||
*/
|
||||
void OnTick()
|
||||
{
|
||||
TickContext ctx;
|
||||
if(!GetTickContext(ctx))
|
||||
return;
|
||||
|
||||
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
|
||||
ManageExpiredTrades();
|
||||
|
||||
// Existing-position protection stays active even while Python results are pending.
|
||||
ManageSLTPPositions();
|
||||
|
||||
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
|
||||
RecoverTimedOutPythonProcesses();
|
||||
|
||||
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
|
||||
ProcessTrendUpdate(g_ea);
|
||||
|
||||
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
|
||||
if(!IsTrendResultReady())
|
||||
return;
|
||||
|
||||
RefreshTrendState(g_ea);
|
||||
|
||||
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
|
||||
ProcessEntryUpdate(g_ea);
|
||||
|
||||
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
|
||||
ProcessM15EntryTimingUpdate();
|
||||
|
||||
UpdateStatusComment(ctx);
|
||||
|
||||
// ここから下は新規注文に関する処理。
|
||||
if(!IsSpreadAllowed(ctx))
|
||||
return;
|
||||
|
||||
if(!IsEntryResultReady())
|
||||
return;
|
||||
|
||||
RefreshTargetPrices(g_ea);
|
||||
ProcessEntryDecisionIfNeeded(g_ea, ctx);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| SLTP manager panel and settings bridge
|
||||
//+------------------------------------------------------------------+
|
||||
string SLTPBoolText(const bool value)
|
||||
{
|
||||
return value ? "ON" : "OFF";
|
||||
}
|
||||
|
||||
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
|
||||
{
|
||||
settings.manager_enabled = input_sltp_manager_enabled;
|
||||
|
||||
settings.use_breakeven = input_sltp_use_breakeven;
|
||||
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
|
||||
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
|
||||
|
||||
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
|
||||
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
|
||||
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
|
||||
|
||||
settings.use_active_trailing = input_sltp_use_active_trailing;
|
||||
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
|
||||
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
|
||||
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
|
||||
settings.active_step_move_pips = input_sltp_active_step_move_pips;
|
||||
|
||||
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
|
||||
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
|
||||
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
|
||||
|
||||
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
|
||||
}
|
||||
|
||||
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
|
||||
const bool print_summary)
|
||||
{
|
||||
g_sltp_settings_valid = false;
|
||||
|
||||
g_sltp_manager.SetMagicNumber((ulong)magic_number);
|
||||
g_sltp_manager.SetSymbol(_Symbol);
|
||||
g_sltp_manager.SetDeviationInPoints(slippage);
|
||||
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
|
||||
settings.breakeven_trigger_pips,
|
||||
settings.breakeven_buffer_pips);
|
||||
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
|
||||
settings.elapsed_breakeven_hours,
|
||||
settings.elapsed_breakeven_buffer_pips);
|
||||
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
|
||||
settings.active_breakeven_pips,
|
||||
settings.active_stop_loss_offset_pips,
|
||||
settings.active_step_trigger_pips,
|
||||
settings.active_step_move_pips);
|
||||
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
|
||||
settings.tp_progress_trigger_percent,
|
||||
settings.tp_progress_sl_lock_percent);
|
||||
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
|
||||
|
||||
if(!g_sltp_manager.ValidateSettings())
|
||||
{
|
||||
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_sltp_settings = settings;
|
||||
g_sltp_settings_valid = true;
|
||||
|
||||
if(print_summary)
|
||||
{
|
||||
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
|
||||
" BE=", SLTPBoolText(settings.use_breakeven),
|
||||
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
|
||||
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
|
||||
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
|
||||
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitializeSLTPManager()
|
||||
{
|
||||
SLTPManagerPanelSettings initial_settings;
|
||||
LoadSLTPInputSettings(initial_settings);
|
||||
|
||||
if(!ApplySLTPSettings(initial_settings, true))
|
||||
return false;
|
||||
|
||||
g_sltp_panel.Init(g_sltp_settings);
|
||||
if(input_sltp_show_panel)
|
||||
{
|
||||
if(!g_sltp_panel.CreatePanel())
|
||||
{
|
||||
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
|
||||
return true;
|
||||
}
|
||||
|
||||
g_sltp_panel.SetInitialValues();
|
||||
g_sltp_panel_created = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ManageSLTPPositions()
|
||||
{
|
||||
if(!g_sltp_settings_valid)
|
||||
return;
|
||||
if(!g_sltp_settings.manager_enabled)
|
||||
return;
|
||||
|
||||
g_sltp_manager.ManagePositions();
|
||||
g_sltp_manager.HighVolatilityLimit();
|
||||
}
|
||||
|
||||
void OnChartEvent(const int id,
|
||||
const long &lparam,
|
||||
const double &dparam,
|
||||
const string &sparam)
|
||||
{
|
||||
if(!g_sltp_panel_created)
|
||||
return;
|
||||
|
||||
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
|
||||
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
|
||||
{
|
||||
if(!ApplySLTPSettings(candidate_settings, true))
|
||||
Print("HIT SLTP panel apply failed. Please review panel values.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Function implementations are kept in project headers so the EA entry points stay compact.
|
||||
#include <MyLib/Common/HITRuntimeController.mqh>
|
||||
#include <MyLib/Signals/HITEntrySignal.mqh>
|
||||
#include <MyLib/Common/HITExternalProcess.mqh>
|
||||
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
|
||||
#include <MyLib/Trading/HITTradeManager.mqh>
|
||||
@@ -0,0 +1,462 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HIT_EA.mq5 |
|
||||
//| Copyright 2026, nanpin-martin.com |
|
||||
//| https://www.nanpin-martin.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2026, nanpin-martin.com"
|
||||
#property link "https://nanpin-martin.com/"
|
||||
#property version "1.01"
|
||||
|
||||
#include <MyLib/Trading/SLTPManager.mqh>
|
||||
#include <MyLib/Panel/SLTPManagerPanel.mqh>
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| バッチファイル実行用の設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
// Windowsプロセス起動・終了確認用
|
||||
#define CREATE_NO_WINDOW 0x08000000
|
||||
#define PROCESS_QUERY_LIMITED_INFORMATION 0x00001000
|
||||
#define SYNCHRONIZE 0x00100000
|
||||
#define WAIT_OBJECT_0 0
|
||||
#define WAIT_TIMEOUT 258
|
||||
#define STILL_ACTIVE 259
|
||||
|
||||
struct STARTUPINFO_W
|
||||
{
|
||||
uint cb;
|
||||
string lpReserved;
|
||||
string lpDesktop;
|
||||
string lpTitle;
|
||||
uint dwX;
|
||||
uint dwY;
|
||||
uint dwXSize;
|
||||
uint dwYSize;
|
||||
uint dwXCountChars;
|
||||
uint dwYCountChars;
|
||||
uint dwFillAttribute;
|
||||
uint dwFlags;
|
||||
ushort wShowWindow;
|
||||
ushort cbReserved2;
|
||||
long lpReserved2;
|
||||
long hStdInput;
|
||||
long hStdOutput;
|
||||
long hStdError;
|
||||
};
|
||||
|
||||
struct PROCESS_INFORMATION
|
||||
{
|
||||
long hProcess;
|
||||
long hThread;
|
||||
uint dwProcessId;
|
||||
uint dwThreadId;
|
||||
};
|
||||
|
||||
#import "kernel32.dll"
|
||||
int CreateProcessW(string lpApplicationName, string lpCommandLine, long lpProcessAttributes, long lpThreadAttributes, int bInheritHandles, uint dwCreationFlags, long lpEnvironment, string lpCurrentDirectory, STARTUPINFO_W &lpStartupInfo, PROCESS_INFORMATION &lpProcessInformation);
|
||||
int WaitForSingleObject(long hHandle, uint dwMilliseconds);
|
||||
int GetExitCodeProcess(long hProcess, uint &lpExitCode);
|
||||
int CloseHandle(long hObject);
|
||||
long OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
|
||||
#import
|
||||
|
||||
// バッチファイルのパス
|
||||
string get_trend_reply_bat = "C:\\ea_py\\bat\\get_trend_reply.bat"; // H4: trend
|
||||
string get_entry_reply_bat = "C:\\ea_py\\bat\\get_entry_reply.bat"; // H1: entry
|
||||
|
||||
// プロセス完了ファイルの設定
|
||||
string done_trend_file = "process_done_trend.txt";
|
||||
string done_entry_file = "process_done_entry.txt";
|
||||
|
||||
// Python出力ファイル
|
||||
string trend_state_file = "trend_state.txt";
|
||||
string target_prices_file = "target_prices.txt";
|
||||
string target_zones_file = "target_zones.txt";
|
||||
|
||||
// Python実行中を判定するための管理ファイル
|
||||
string running_trend_file = "process_running_trend.txt";
|
||||
string running_entry_file = "process_running_entry.txt";
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| インプットの設定
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
enum SplitLotMode
|
||||
{
|
||||
SPLIT_LOT_TOTAL = 0, // 総ロットをN分割
|
||||
SPLIT_LOT_FIXED = 1 // 1注文あたり固定ロット
|
||||
};
|
||||
|
||||
//--- 入力パラメータ
|
||||
input double lot_size = 0.01; // ロット数
|
||||
input double spread_limit = 60; // 許容スプレッド(point)
|
||||
input int magic_number = 10001; // マジックナンバー
|
||||
input int initial_order = 0; // 起動時の注文(0:なし, 1:あり)
|
||||
input int input_position_limit = 10; // 自EAの未約定注文+ポジション上限
|
||||
input bool use_split_entry_zone = false; // H1予測ゾーンで分割エントリーする
|
||||
input int split_entry_count = 3; // 分割エントリー本数(1..10)
|
||||
input SplitLotMode split_lot_mode = SPLIT_LOT_TOTAL; // 分割ロット配分モード
|
||||
input double split_total_lot_size = 0.09; // 総量分割モードの合計ロット
|
||||
input double split_fixed_lot_size = 0.01; // 固定ロットモードの1注文ロット
|
||||
input bool cancel_old_split_pending_on_new_zone = true; // 新ゾーン読込時に旧分割pendingを取消
|
||||
input bool use_m15_entry_filter = true; // M15確定足で発注タイミングを確認
|
||||
input double m15_entry_zone_atr_multiplier = 1.50; // M15平均レンジ何本分まで候補価格への接近を許可
|
||||
input bool use_m15_imbalance_confirmation = true; // T1/T3でM15初動確認を追加
|
||||
input int m15_imbalance_avg_body_period = 20; // M15平均実体計算期間
|
||||
input double m15_imbalance_sensitivity = 2.0; // M15初動検知感度
|
||||
input double m15_imbalance_min_avg_body_points = 1.0; // 平均実体の最小値(point)
|
||||
input bool use_m15_imbalance_debug_log = false; // M15初動確認ログ
|
||||
input int input_entry_max_candidate_age_minutes = 45; // H1候補価格を新規発注に使う最大経過分数
|
||||
input bool input_sltp_manager_enabled = false; // UI連動SLTP管理を有効化
|
||||
input bool input_sltp_show_panel = true; // SLTP操作パネルを表示
|
||||
input bool input_sltp_use_breakeven = false; // 通常ブレークイーブンを有効化
|
||||
input double input_sltp_breakeven_trigger_pips = 30.0; // 通常BE開始pips
|
||||
input double input_sltp_breakeven_buffer_pips = 3.0; // 通常BE固定バッファpips
|
||||
input bool input_sltp_use_elapsed_breakeven = false; // 保有時間BEを有効化
|
||||
input double input_sltp_elapsed_breakeven_hours = 4.0; // 保有時間BE開始時間
|
||||
input double input_sltp_elapsed_breakeven_buffer_pips = 3.0; // 保有時間BE固定バッファpips
|
||||
input bool input_sltp_use_active_trailing = false; // アクティブトレーリングを有効化
|
||||
input double input_sltp_active_breakeven_pips = 30.0; // アクティブ開始pips
|
||||
input double input_sltp_active_stop_loss_offset_pips = 5.0; // 初期固定pips
|
||||
input double input_sltp_active_step_trigger_pips = 10.0; // ステップ更新間隔pips
|
||||
input double input_sltp_active_step_move_pips = 5.0; // 1ステップ固定追加pips
|
||||
input bool input_sltp_use_tp_progress_stop = false; // TP進捗SLを有効化
|
||||
input double input_sltp_tp_progress_trigger_percent = 70.0; // TP進捗SL開始率
|
||||
input double input_sltp_tp_progress_sl_lock_percent = 30.0; // TP距離固定率
|
||||
input bool input_sltp_use_high_volatility_limit = false; // 急変時SL引き締めを有効化
|
||||
ulong slippage = 10; // スリッページ
|
||||
|
||||
//--- 主要な定数・設定
|
||||
#define POSITION_LIMIT 48
|
||||
#define ENTRY_H1_LIMIT 1 // H1本数(=1時間)
|
||||
#define CLOSE_H1_LIMIT 12 // H1本数(=12時間)
|
||||
#define HISTORY_BARS 72
|
||||
#define OHLC_START_SHIFT 1 // 1: 確定足のみをPythonへ渡す
|
||||
#define M15_CONFIRM_BARS 30
|
||||
#define M15_MIN_ENTRY_ZONE_POINTS 10
|
||||
#define M15_MIN_BODY_RATIO 0.25
|
||||
#define M15_REJECTION_WICK_RATIO 0.35
|
||||
#define ENTRY_RETRY_SECONDS 60
|
||||
#define ENTRY_RETRY_LIMIT 10
|
||||
// ANALYZE_TIMEFRAME は削除(H4/H1 両方使うため定数ではなく直接指定)
|
||||
#define TARGET_SIZE 13
|
||||
#define TARGET_ZONE_SCHEMA_VERSION 2
|
||||
#define DEFAULT_TARGET_PRICE 0.0
|
||||
#define PYTHON_TIMEOUT_SECONDS 600 // Python完了待ちの上限(秒)
|
||||
|
||||
#define MARKET_LOW_VOL_RANGE 0
|
||||
#define MARKET_HIGH_VOL_RANGE 1
|
||||
#define MARKET_LOW_VOL_UP 2
|
||||
#define MARKET_HIGH_VOL_UP 3
|
||||
#define MARKET_LOW_VOL_DOWN 4
|
||||
#define MARKET_HIGH_VOL_DOWN 5
|
||||
#define MARKET_TECHNICAL_ERROR_STOP 6
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| EAの状態をまとめる構造体
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
struct EAState
|
||||
{
|
||||
int trend_state; // H4 market_state(0..5、6は技術エラー停止)を格納する変数
|
||||
int res_chk; // GPTの回答が正しく取得できたか
|
||||
double en_price[5]; // エントリー基準価格
|
||||
double tp_price[5]; // 利益確定価格
|
||||
double sl_price[5]; // ロスカット基準価格
|
||||
int zone_res_chk; // 予測ゾーンが正しく取得できたか
|
||||
string zone_candidate_id; // H1確定足由来の候補ID
|
||||
double zone_low[5]; // 分割エントリー用ゾーン下限
|
||||
double zone_high[5]; // 分割エントリー用ゾーン上限
|
||||
double zone_tp[5]; // 分割エントリー用TP
|
||||
double zone_sl[5]; // 分割エントリー用SL
|
||||
bool load_trend_flg; // ★変更:トレンドを更新するタイミングか
|
||||
bool load_target_flg; // ★変更:ターゲット価格を更新するタイミングか
|
||||
int chk_cnt; // エントリー判定の試行回数
|
||||
datetime last_trend_update; // ★追加:前回トレンドを更新した時刻
|
||||
datetime last_target_update; // ★変更:前回ターゲット価格を更新した時刻
|
||||
datetime target_loaded_at; // H1候補価格をEAへ読み込んだサーバー時刻
|
||||
datetime last_chk;
|
||||
};
|
||||
|
||||
EAState g_ea; // EA全体の状態をここで管理
|
||||
|
||||
// initial_order 用の初回処理フラグ
|
||||
// H4トレンド処理とH1エントリー処理で別々に管理し、初回起動時の再実行ループを防ぐ。
|
||||
bool g_init_trend_pending = false;
|
||||
bool g_init_entry_pending = false;
|
||||
|
||||
// H4/H1のバー更新状態
|
||||
int g_pre_bars_H4 = 0;
|
||||
int g_pre_bars_H1 = 0;
|
||||
int g_pre_bars_M15 = 0;
|
||||
bool g_bars_H1_check = false;
|
||||
bool g_bars_M15_check = false;
|
||||
|
||||
// ティックごとの価格情報
|
||||
struct TickContext
|
||||
{
|
||||
double ask;
|
||||
double bid;
|
||||
double spread;
|
||||
double spread_points;
|
||||
int digits;
|
||||
};
|
||||
|
||||
// 外部Pythonプロセスの状態
|
||||
struct ExternalProcessState
|
||||
{
|
||||
long handle;
|
||||
uint process_id;
|
||||
bool active;
|
||||
bool exit_code_ready;
|
||||
uint exit_code;
|
||||
datetime started_at;
|
||||
};
|
||||
|
||||
ExternalProcessState g_trend_process;
|
||||
ExternalProcessState g_entry_process;
|
||||
|
||||
CSLTPManager g_sltp_manager;
|
||||
CSLTPManagerPanel g_sltp_panel;
|
||||
SLTPManagerPanelSettings g_sltp_settings;
|
||||
bool g_sltp_settings_valid = false;
|
||||
bool g_sltp_panel_created = false;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 起動時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief EA起動時の初期化処理を行います。
|
||||
*
|
||||
* Python連携用のdone/runningファイル状態を確認し、`initial_order` が有効な場合は
|
||||
* H4トレンド判定とH1エントリー価格生成をそれぞれ初回実行対象にします。
|
||||
* H4/H1の初回フラグを分けることで、起動直後にH4処理だけが繰り返される状態を防ぎます。
|
||||
*/
|
||||
int OnInit()
|
||||
// プロセス完了ファイルと実行中ファイルの状態を初期化
|
||||
{
|
||||
PrepareDoneFileOnInit(done_trend_file, running_trend_file, "trend");
|
||||
PrepareDoneFileOnInit(done_entry_file, running_entry_file, "entry");
|
||||
|
||||
// initial_order=1 の場合でも、H4/H1を別々に1回だけ初回実行する。
|
||||
g_init_trend_pending = (initial_order == 1);
|
||||
g_init_entry_pending = (initial_order == 1);
|
||||
|
||||
if(!InitializeSLTPManager())
|
||||
return INIT_FAILED;
|
||||
|
||||
return INIT_SUCCEEDED;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 終了時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
ResetExternalProcessState(g_trend_process);
|
||||
ResetExternalProcessState(g_entry_process);
|
||||
|
||||
if(g_sltp_panel_created)
|
||||
g_sltp_panel.Destroy(reason);
|
||||
|
||||
// Clear chart status text left by Comment() when the EA is removed.
|
||||
Comment("");
|
||||
ChartRedraw(0);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| ティック毎の処理
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief ティック受信ごとにEA全体の処理を制御します。
|
||||
*
|
||||
* 処理順序は、ティック情報取得、期限切れ注文/ポジション管理、H4トレンド更新、
|
||||
* H1エントリー価格更新、M15エントリータイミング更新、ステータス表示、新規注文判定の順です。
|
||||
* 時間制限処理はPython完了待ちやスプレッド判定より前に実行します。
|
||||
*/
|
||||
void OnTick()
|
||||
{
|
||||
TickContext ctx;
|
||||
if(!GetTickContext(ctx))
|
||||
return;
|
||||
|
||||
// 期限切れ注文・ポジションは、Python待ちやスプレッド制限に関係なく先に処理する。
|
||||
ManageExpiredTrades();
|
||||
|
||||
// Existing-position protection stays active even while Python results are pending.
|
||||
ManageSLTPPositions();
|
||||
|
||||
// 外部Pythonがdoneを返さない場合に、一定時間で待機状態を解除して再実行対象にする。
|
||||
RecoverTimedOutPythonProcesses();
|
||||
|
||||
// H4新バーまたは初回起動時に、トレンド判定用Pythonを起動する。
|
||||
ProcessTrendUpdate(g_ea);
|
||||
|
||||
// トレンド判定が完了していない場合、新規注文側の処理だけをスキップする。
|
||||
if(!IsTrendResultReady())
|
||||
return;
|
||||
|
||||
RefreshTrendState(g_ea);
|
||||
|
||||
// H1新バーまたは初回起動時に、エントリー価格生成用Pythonを起動する。
|
||||
ProcessEntryUpdate(g_ea);
|
||||
|
||||
// M15確定足ごとに、H1候補価格を発注してよいタイミングか再判定する。
|
||||
ProcessM15EntryTimingUpdate();
|
||||
|
||||
UpdateStatusComment(ctx);
|
||||
|
||||
// ここから下は新規注文に関する処理。
|
||||
if(!IsSpreadAllowed(ctx))
|
||||
return;
|
||||
|
||||
if(!IsEntryResultReady())
|
||||
return;
|
||||
|
||||
RefreshTargetPrices(g_ea);
|
||||
ProcessEntryDecisionIfNeeded(g_ea, ctx);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| SLTP manager panel and settings bridge
|
||||
//+------------------------------------------------------------------+
|
||||
string SLTPBoolText(const bool value)
|
||||
{
|
||||
return value ? "ON" : "OFF";
|
||||
}
|
||||
|
||||
void LoadSLTPInputSettings(SLTPManagerPanelSettings &settings)
|
||||
{
|
||||
settings.manager_enabled = input_sltp_manager_enabled;
|
||||
|
||||
settings.use_breakeven = input_sltp_use_breakeven;
|
||||
settings.breakeven_trigger_pips = input_sltp_breakeven_trigger_pips;
|
||||
settings.breakeven_buffer_pips = input_sltp_breakeven_buffer_pips;
|
||||
|
||||
settings.use_elapsed_breakeven = input_sltp_use_elapsed_breakeven;
|
||||
settings.elapsed_breakeven_hours = input_sltp_elapsed_breakeven_hours;
|
||||
settings.elapsed_breakeven_buffer_pips = input_sltp_elapsed_breakeven_buffer_pips;
|
||||
|
||||
settings.use_active_trailing = input_sltp_use_active_trailing;
|
||||
settings.active_breakeven_pips = input_sltp_active_breakeven_pips;
|
||||
settings.active_stop_loss_offset_pips = input_sltp_active_stop_loss_offset_pips;
|
||||
settings.active_step_trigger_pips = input_sltp_active_step_trigger_pips;
|
||||
settings.active_step_move_pips = input_sltp_active_step_move_pips;
|
||||
|
||||
settings.use_tp_progress_stop = input_sltp_use_tp_progress_stop;
|
||||
settings.tp_progress_trigger_percent = input_sltp_tp_progress_trigger_percent;
|
||||
settings.tp_progress_sl_lock_percent = input_sltp_tp_progress_sl_lock_percent;
|
||||
|
||||
settings.use_high_volatility_limit = input_sltp_use_high_volatility_limit;
|
||||
}
|
||||
|
||||
bool ApplySLTPSettings(const SLTPManagerPanelSettings &settings,
|
||||
const bool print_summary)
|
||||
{
|
||||
g_sltp_settings_valid = false;
|
||||
|
||||
g_sltp_manager.SetMagicNumber((ulong)magic_number);
|
||||
g_sltp_manager.SetSymbol(_Symbol);
|
||||
g_sltp_manager.SetDeviationInPoints(slippage);
|
||||
g_sltp_manager.SetBreakevenSettings(settings.use_breakeven,
|
||||
settings.breakeven_trigger_pips,
|
||||
settings.breakeven_buffer_pips);
|
||||
g_sltp_manager.SetElapsedBreakevenSettings(settings.use_elapsed_breakeven,
|
||||
settings.elapsed_breakeven_hours,
|
||||
settings.elapsed_breakeven_buffer_pips);
|
||||
g_sltp_manager.SetActiveTrailingSettings(settings.use_active_trailing,
|
||||
settings.active_breakeven_pips,
|
||||
settings.active_stop_loss_offset_pips,
|
||||
settings.active_step_trigger_pips,
|
||||
settings.active_step_move_pips);
|
||||
g_sltp_manager.SetTpProgressStopSettings(settings.use_tp_progress_stop,
|
||||
settings.tp_progress_trigger_percent,
|
||||
settings.tp_progress_sl_lock_percent);
|
||||
g_sltp_manager.SetHighVolatilityLimitSettings(settings.use_high_volatility_limit);
|
||||
|
||||
if(!g_sltp_manager.ValidateSettings())
|
||||
{
|
||||
Print("HIT SLTP settings rejected. Manager is disabled until valid settings are applied.");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_sltp_settings = settings;
|
||||
g_sltp_settings_valid = true;
|
||||
|
||||
if(print_summary)
|
||||
{
|
||||
Print("HIT SLTP settings: Manager=", SLTPBoolText(settings.manager_enabled),
|
||||
" BE=", SLTPBoolText(settings.use_breakeven),
|
||||
" ElapsedBE=", SLTPBoolText(settings.use_elapsed_breakeven),
|
||||
" ActiveTrail=", SLTPBoolText(settings.use_active_trailing),
|
||||
" TPProgress=", SLTPBoolText(settings.use_tp_progress_stop),
|
||||
" HighVol=", SLTPBoolText(settings.use_high_volatility_limit));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitializeSLTPManager()
|
||||
{
|
||||
SLTPManagerPanelSettings initial_settings;
|
||||
LoadSLTPInputSettings(initial_settings);
|
||||
|
||||
if(!ApplySLTPSettings(initial_settings, true))
|
||||
return false;
|
||||
|
||||
g_sltp_panel.Init(g_sltp_settings);
|
||||
if(input_sltp_show_panel)
|
||||
{
|
||||
if(!g_sltp_panel.CreatePanel())
|
||||
{
|
||||
Print("HIT SLTP panel is unavailable. EA continues with input-based SLTP settings.");
|
||||
return true;
|
||||
}
|
||||
|
||||
g_sltp_panel.SetInitialValues();
|
||||
g_sltp_panel_created = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ManageSLTPPositions()
|
||||
{
|
||||
if(!g_sltp_settings_valid)
|
||||
return;
|
||||
if(!g_sltp_settings.manager_enabled)
|
||||
return;
|
||||
|
||||
g_sltp_manager.ManagePositions();
|
||||
g_sltp_manager.HighVolatilityLimit();
|
||||
}
|
||||
|
||||
void OnChartEvent(const int id,
|
||||
const long &lparam,
|
||||
const double &dparam,
|
||||
const string &sparam)
|
||||
{
|
||||
if(!g_sltp_panel_created)
|
||||
return;
|
||||
|
||||
SLTPManagerPanelSettings candidate_settings = g_sltp_settings;
|
||||
if(g_sltp_panel.HandleChartEvent(id, lparam, dparam, sparam, candidate_settings))
|
||||
{
|
||||
if(!ApplySLTPSettings(candidate_settings, true))
|
||||
Print("HIT SLTP panel apply failed. Please review panel values.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Function implementations are kept in project headers so the EA entry points stay compact.
|
||||
#include <MyLib/Common/HITRuntimeController.mqh>
|
||||
#include <MyLib/Signals/HITEntrySignal.mqh>
|
||||
#include <MyLib/Common/HITExternalProcess.mqh>
|
||||
#include <MyLib/Signals/HITPythonSignalGateway.mqh>
|
||||
#include <MyLib/Trading/HITTradeManager.mqh>
|
||||
@@ -0,0 +1,395 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| TradingPanel EA entry point
|
||||
//+------------------------------------------------------------------+
|
||||
#include <MyLib/Trading/TradingPanelTradingManagers.mqh>
|
||||
#include <MyLib/Panel/TradingPanelPanel.mqh>
|
||||
|
||||
#define POSITION_TYPE_ALL ((ENUM_POSITION_TYPE) - 1) // フィルタ無し
|
||||
|
||||
// トータルブレークイーブン
|
||||
#define BE_BUY "BreakEvenBuy"
|
||||
#define BE_SELL "BreakEvenSell"
|
||||
|
||||
//--- カテゴリ1:取引設定
|
||||
input group "■ 取引設定";
|
||||
input int exit_time_interval = 4; // 時間制限クローズまでの保有時間(時間)
|
||||
|
||||
//--- カテゴリ2:基本設定
|
||||
input group "■ 基本設定";
|
||||
input ulong slippage = 10; // スリッページ
|
||||
input int magic_number = 10001; // マジックナンバー
|
||||
|
||||
input group "■ SLTP設定: Common";
|
||||
input double take_profit_pips = 150.0; // TP設定値
|
||||
input double default_sl = 100.0; // SL初期値
|
||||
input double stop_offset_pips = 10.0; // ストップロスオフセット(pips)
|
||||
|
||||
input group "■ SLTP設定: TRAIL";
|
||||
input bool enable_breakeven = true; // ブレークイーブンを有効化
|
||||
input double breakeven_pips = 30.0; // ブレークイーブン判定利幅
|
||||
input double stop_loss_offset_pips = 5.0; // 建値からのマージン
|
||||
input double step_trigger_pips = 10.0; // トレール更新トリガーpips
|
||||
input double step_move_pips = 8.0; // トレール更新pips
|
||||
input double tp_edit_pips = 10.0; // TP更新初期pips
|
||||
|
||||
//--- カテゴリ4:フィルター設定
|
||||
input group "■ レンジフィルター設定";
|
||||
input double range_pips = 80.0; // レンジ幅pips1
|
||||
|
||||
//--- カテゴリ5:時間設定
|
||||
input group "■ 取引時間設定";
|
||||
input bool isTradingTimeEnabled = true; // 取引時間を制限
|
||||
input int TradeStartHour = 4; // 開始時間GMT(時間)
|
||||
input int TradeStartMin = 0; // 開始時間GMT(分)
|
||||
input int TradeEndHour = 23; // 終了時間GMT(時間)
|
||||
input int TradeEndMin = 0; // 終了時間GMT(分)
|
||||
|
||||
int TimerPeriod_sec = 1; // n 秒ごとに OnTimer
|
||||
|
||||
bool wasInTradingTime = false;
|
||||
bool beforeTradingInitDone = false;
|
||||
bool afterTradingInitDone = false;
|
||||
|
||||
bool timelimit_exit = true; // 時間制限クローズ 初期状態
|
||||
|
||||
bool input_lock = true; // 時間制限クローズ 初期状態
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// EAとの共有用グローバル変数
|
||||
// --------------------------------------------------------------
|
||||
int gl_exitTimeIntervalInSeconds = exit_time_interval * 3600;
|
||||
double gl_breakeven_pips = breakeven_pips;
|
||||
double gl_stop_loss_offset_pips = stop_loss_offset_pips;
|
||||
double gl_step_trigger_pips = step_trigger_pips;
|
||||
double gl_step_move_pips = step_move_pips;
|
||||
double gl_default_sl_pips = default_sl;
|
||||
double gl_take_profit_pips = take_profit_pips;
|
||||
double gl_stop_offset_pips = stop_offset_pips;
|
||||
|
||||
int buy_position = 0; // CountPositions() で随時更新
|
||||
int sell_position = 0;
|
||||
datetime last_buy_time = 0;
|
||||
datetime last_sell_time = 0;
|
||||
bool buy_total_be_flg = false;
|
||||
bool sell_total_be_flg = false;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| トータルのブレークイーブン用変数
|
||||
//+------------------------------------------------------------------+
|
||||
bool InpShowBuyLine = true; // 買いのブレークイーブンライン
|
||||
bool InpShowSellLine = true; // 売りのブレークイーブンライン
|
||||
double BufferPips = 2.0; // BE バッファ
|
||||
int LabelShiftBars = 60; // 何本前のバーにラベルを置くか
|
||||
double LabelOffsetPips = 4.0; // ライン ⇔ ラベルの距離
|
||||
|
||||
CTradingPanelStopManager g_stop_manager;
|
||||
CTradingPanelPositionManager g_position_manager;
|
||||
CTradingPanelBreakEvenLineManager g_break_even_manager;
|
||||
CTradingPanelPanel g_panel;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 起動時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
g_stop_manager.Init(_Symbol, (ulong)magic_number, slippage);
|
||||
g_position_manager.Init(_Symbol, (ulong)magic_number, slippage);
|
||||
g_break_even_manager.Init(_Symbol, (ulong)magic_number);
|
||||
g_panel.Init(exit_time_interval,
|
||||
range_pips,
|
||||
breakeven_pips,
|
||||
stop_loss_offset_pips,
|
||||
step_trigger_pips,
|
||||
step_move_pips,
|
||||
default_sl,
|
||||
take_profit_pips,
|
||||
tp_edit_pips,
|
||||
stop_offset_pips);
|
||||
|
||||
// EA設定変更用のパネルを表示
|
||||
if (!g_panel.CreatePanel(input_lock))
|
||||
return INIT_FAILED;
|
||||
g_panel.SetInitialValues();
|
||||
|
||||
// Backfill missing initial stops for existing matching positions.
|
||||
g_position_manager.ApplyInitialStops(gl_default_sl_pips, gl_take_profit_pips);
|
||||
|
||||
// タイマーをセット
|
||||
EventSetTimer(TimerPeriod_sec);
|
||||
|
||||
return (INIT_SUCCEEDED); // 成功コードを明示しておく
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 削除時の処理
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
EventKillTimer();
|
||||
|
||||
// EA適用後のプロパティで変更すると、EAを再読み込みする。
|
||||
g_panel.Destroy(reason);
|
||||
|
||||
// トータルブレークイーブンラインを削除
|
||||
if (InpShowBuyLine)
|
||||
g_break_even_manager.DeleteLine(BE_BUY);
|
||||
|
||||
if (InpShowSellLine)
|
||||
g_break_even_manager.DeleteLine(BE_SELL);
|
||||
|
||||
// EAが削除された際にコメントを消す
|
||||
Comment("");
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| タイマー処理
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTimer()
|
||||
{
|
||||
// 時間状態の変化を検知
|
||||
HandleTradingTimeTransition();
|
||||
|
||||
// ティックが少ない時間帯でも時間制限クローズを監視する。
|
||||
g_position_manager.CloseTimedPositions(POSITION_TYPE_BUY, ORDER_TYPE_SELL,
|
||||
timelimit_exit, gl_exitTimeIntervalInSeconds, slippage);
|
||||
g_position_manager.CloseTimedPositions(POSITION_TYPE_SELL, ORDER_TYPE_BUY,
|
||||
timelimit_exit, gl_exitTimeIntervalInSeconds, slippage);
|
||||
|
||||
// 取引時間が指定時間内か確認
|
||||
if (!IsTradingTime())
|
||||
return;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| ティック毎の処理
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
// 時間状態の変化を検知
|
||||
HandleTradingTimeTransition();
|
||||
|
||||
// EAの設定を画面上に表示
|
||||
DisplayEAValues();
|
||||
|
||||
// 時間制限クローズは取引時間フィルターとは独立して実行する。
|
||||
g_position_manager.CloseTimedPositions(POSITION_TYPE_BUY, ORDER_TYPE_SELL,
|
||||
timelimit_exit, gl_exitTimeIntervalInSeconds, slippage);
|
||||
g_position_manager.CloseTimedPositions(POSITION_TYPE_SELL, ORDER_TYPE_BUY,
|
||||
timelimit_exit, gl_exitTimeIntervalInSeconds, slippage);
|
||||
|
||||
// 取引時間が指定時間内か確認
|
||||
if (!IsTradingTime())
|
||||
return;
|
||||
|
||||
// レート急伸SL
|
||||
g_stop_manager.HighVolatilityLimit();
|
||||
|
||||
//------------------------------------
|
||||
// ブレークイーブン / トレールストップ監視
|
||||
//------------------------------------
|
||||
g_stop_manager.ManageStops(enable_breakeven,
|
||||
gl_breakeven_pips,
|
||||
gl_stop_loss_offset_pips,
|
||||
gl_step_trigger_pips,
|
||||
gl_step_move_pips);
|
||||
|
||||
g_break_even_manager.ManageBuy(buy_total_be_flg && InpShowBuyLine,
|
||||
buy_total_be_flg,
|
||||
BufferPips,
|
||||
LabelShiftBars,
|
||||
LabelOffsetPips,
|
||||
gl_default_sl_pips,
|
||||
g_stop_manager);
|
||||
g_break_even_manager.ManageSell(sell_total_be_flg && InpShowSellLine,
|
||||
sell_total_be_flg,
|
||||
BufferPips,
|
||||
LabelShiftBars,
|
||||
LabelOffsetPips,
|
||||
gl_default_sl_pips,
|
||||
g_stop_manager);
|
||||
|
||||
// 保有ポジションの確認
|
||||
buy_position = g_position_manager.CountPositions(POSITION_TYPE_BUY, magic_number);
|
||||
sell_position = g_position_manager.CountPositions(POSITION_TYPE_SELL, magic_number);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 取引時間を指定する関数
|
||||
//+------------------------------------------------------------------+
|
||||
bool IsTradingTime()
|
||||
{
|
||||
// 取引時間が有効化されていない場合、常にtrueを返す
|
||||
if (!isTradingTimeEnabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
MqlDateTime structTime;
|
||||
TimeCurrent(structTime);
|
||||
structTime.sec = 0;
|
||||
|
||||
structTime.hour = TradeStartHour;
|
||||
structTime.min = TradeStartMin;
|
||||
datetime timeStart = StructToTime(structTime);
|
||||
|
||||
structTime.hour = TradeEndHour;
|
||||
structTime.min = TradeEndMin;
|
||||
datetime timeEnd = StructToTime(structTime);
|
||||
|
||||
// エラーチェック
|
||||
if (TradeStartHour >= TradeEndHour && TradeStartMin >= TradeEndMin)
|
||||
{
|
||||
Print("Error: Invalid Time input");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 現在の時間を取得
|
||||
datetime now = TimeCurrent();
|
||||
|
||||
// 時間内かどうかをチェック
|
||||
return (now >= timeStart && now < timeEnd);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 取引時間内外に状態が変化した時の初期化処理
|
||||
//+------------------------------------------------------------------+
|
||||
void HandleTradingTimeTransition()
|
||||
{
|
||||
bool nowInTradingTime = IsTradingTime();
|
||||
|
||||
// --- 時間内に入った瞬間 ---
|
||||
if (nowInTradingTime && !wasInTradingTime)
|
||||
{
|
||||
if (!beforeTradingInitDone)
|
||||
{
|
||||
Print("取引時間内 初期化処理");
|
||||
beforeTradingInitDone = true;
|
||||
}
|
||||
afterTradingInitDone = false;
|
||||
}
|
||||
|
||||
// --- 時間外に出た瞬間 ---
|
||||
if (!nowInTradingTime && wasInTradingTime)
|
||||
{
|
||||
if (!afterTradingInitDone)
|
||||
{
|
||||
Print("取引時間外 初期化処理");
|
||||
afterTradingInitDone = true;
|
||||
}
|
||||
beforeTradingInitDone = false;
|
||||
}
|
||||
|
||||
wasInTradingTime = nowInTradingTime;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| pipsを価格に換算する関数
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
// 出力処理を関数にまとめる
|
||||
//+------------------------------------------------------------------+
|
||||
void DisplayEAValues()
|
||||
{
|
||||
Comment("\n",
|
||||
"ブレークイーブン: ", (int)gl_breakeven_pips, "pips\n",
|
||||
"時間制限クローズ: ", timelimit_exit ? "ON" : "OFF",
|
||||
" | 保有時間: ", gl_exitTimeIntervalInSeconds / 3600, "時間\n",
|
||||
"------------------------------------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
// +------------------------------------------------------------------+
|
||||
// | チャートイベントのハンドラ
|
||||
// +------------------------------------------------------------------+
|
||||
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
||||
{
|
||||
ENUM_POSITION_TYPE tp_side = POSITION_TYPE_ALL;
|
||||
double tp_adjust_pips = 0.0;
|
||||
|
||||
if (g_panel.HandleChartEvent(id,
|
||||
lparam,
|
||||
dparam,
|
||||
sparam,
|
||||
exit_time_interval,
|
||||
range_pips,
|
||||
breakeven_pips,
|
||||
stop_loss_offset_pips,
|
||||
step_trigger_pips,
|
||||
step_move_pips,
|
||||
default_sl,
|
||||
take_profit_pips,
|
||||
tp_edit_pips,
|
||||
stop_offset_pips,
|
||||
timelimit_exit,
|
||||
input_lock,
|
||||
buy_total_be_flg,
|
||||
sell_total_be_flg,
|
||||
gl_exitTimeIntervalInSeconds,
|
||||
gl_breakeven_pips,
|
||||
gl_stop_loss_offset_pips,
|
||||
gl_step_trigger_pips,
|
||||
gl_step_move_pips,
|
||||
gl_default_sl_pips,
|
||||
gl_take_profit_pips,
|
||||
gl_stop_offset_pips,
|
||||
tp_side,
|
||||
tp_adjust_pips))
|
||||
{
|
||||
g_position_manager.AdjustTakeProfit(tp_adjust_pips, tp_side);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// 取引イベントコールバック(再エントリーを防止)
|
||||
//------------------------------------------------------------------
|
||||
void OnTradeTransaction(const MqlTradeTransaction &trans,
|
||||
const MqlTradeRequest &request,
|
||||
const MqlTradeResult &result)
|
||||
{
|
||||
bool recalc_needed = false; // ポジション再集計フラグ
|
||||
|
||||
// 1) Deal が追加された(約定)
|
||||
if (trans.type == TRADE_TRANSACTION_DEAL_ADD)
|
||||
{
|
||||
recalc_needed = true;
|
||||
|
||||
//---- Deal 詳細を取得 --------------------------------------
|
||||
if (HistoryDealSelect(trans.deal)) // Deal を選択
|
||||
{
|
||||
ENUM_DEAL_REASON deal_reason = (ENUM_DEAL_REASON)
|
||||
HistoryDealGetInteger(trans.deal, DEAL_REASON);
|
||||
|
||||
ENUM_DEAL_ENTRY deal_entry = (ENUM_DEAL_ENTRY)
|
||||
HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
|
||||
|
||||
//==== ★ クローズ条件(手動 or SL/TP) ===================
|
||||
bool is_close =
|
||||
(deal_entry == DEAL_ENTRY_OUT) &&
|
||||
(deal_reason == DEAL_REASON_CLIENT || // 手動決済
|
||||
deal_reason == DEAL_REASON_MOBILE || // スマホアプリ決済
|
||||
deal_reason == DEAL_REASON_WEB || // WEB版決済
|
||||
deal_reason == DEAL_REASON_EXPERT || // EAのタイマー決済
|
||||
deal_reason == DEAL_REASON_SL || // SL ヒット(部分/全量とも)
|
||||
deal_reason == DEAL_REASON_TP); // TP ヒット(部分/全量とも)
|
||||
|
||||
if (is_close)
|
||||
{
|
||||
Print("Position closed (", EnumToString(deal_reason), ") — EA waits for next prediction.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2) サーバ側でポジション内容が変更 (数量減少・SL変更等)
|
||||
else if (trans.type == TRADE_TRANSACTION_POSITION)
|
||||
{
|
||||
recalc_needed = true;
|
||||
}
|
||||
|
||||
// 3) 必要に応じてポジション再集計
|
||||
if (recalc_needed)
|
||||
{
|
||||
g_position_manager.CheckPositions(buy_position, sell_position, last_buy_time, last_sell_time);
|
||||
g_position_manager.ApplyInitialStops(gl_default_sl_pips, gl_take_profit_pips);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Array.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArray |
|
||||
//| Purpose: Base class of dynamic arrays. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArray : public CObject
|
||||
{
|
||||
protected:
|
||||
int m_step_resize; // increment size of the array
|
||||
int m_data_total; // number of elements
|
||||
int m_data_max; // maximmum size of the array without memory reallocation
|
||||
int m_sort_mode; // mode of array sorting
|
||||
|
||||
public:
|
||||
CArray(void);
|
||||
~CArray(void);
|
||||
//--- methods of access to protected data
|
||||
int Step(void) const { return(m_step_resize); }
|
||||
bool Step(const int step);
|
||||
int Total(void) const { return(m_data_total); }
|
||||
int Available(void) const { return(m_data_max-m_data_total); }
|
||||
int Max(void) const { return(m_data_max); }
|
||||
bool IsSorted(const int mode=0) const { return(m_sort_mode==mode); }
|
||||
int SortMode(void) const { return(m_sort_mode); }
|
||||
//--- cleaning method
|
||||
void Clear(void) { m_data_total=0; }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- sorting method
|
||||
void Sort(const int mode=0);
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0) { m_sort_mode=-1; }
|
||||
//--- templates for methods of searching for minimum and maximum
|
||||
template<typename T>
|
||||
int Minimum(const T &data[],const int start,const int count) const;
|
||||
template<typename T>
|
||||
int Maximum(const T &data[],const int start,const int count) const;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArray::CArray(void) : m_step_resize(16),
|
||||
m_data_total(0),
|
||||
m_data_max(0),
|
||||
m_sort_mode(-1)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArray::~CArray(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method Set for variable m_step_resize |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArray::Step(const int step)
|
||||
{
|
||||
//--- check
|
||||
if(step>0)
|
||||
{
|
||||
m_step_resize=step;
|
||||
return(true);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sorting an array in ascending order |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArray::Sort(const int mode)
|
||||
{
|
||||
//--- check
|
||||
if(IsSorted(mode))
|
||||
return;
|
||||
m_sort_mode=mode;
|
||||
if(m_data_total<=1)
|
||||
return;
|
||||
//--- sort
|
||||
QuickSort(0,m_data_total-1,mode);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing header of array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArray::Save(const int file_handle)
|
||||
{
|
||||
//--- check handle
|
||||
if(file_handle!=INVALID_HANDLE)
|
||||
{
|
||||
//--- write start marker - 0xFFFFFFFFFFFFFFFF
|
||||
if(FileWriteLong(file_handle,-1)==sizeof(long))
|
||||
{
|
||||
//--- write array type
|
||||
if(FileWriteInteger(file_handle,Type(),INT_VALUE)==INT_VALUE)
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading header of array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArray::Load(const int file_handle)
|
||||
{
|
||||
//--- check handle
|
||||
if(file_handle!=INVALID_HANDLE)
|
||||
{
|
||||
//--- read and check start marker - 0xFFFFFFFFFFFFFFFF
|
||||
if(FileReadLong(file_handle)==-1)
|
||||
{
|
||||
//--- read and check array type
|
||||
if(FileReadInteger(file_handle,INT_VALUE)==Type())
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find minimum of array |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CArray::Minimum(const T &data[],const int start,const int count) const
|
||||
{
|
||||
int real_count;
|
||||
//--- check for empty array
|
||||
if(m_data_total<1)
|
||||
{
|
||||
SetUserError(ERR_USER_ARRAY_IS_EMPTY);
|
||||
return(-1);
|
||||
}
|
||||
//--- check for start is out of range
|
||||
if(start<0 || start>=m_data_total)
|
||||
{
|
||||
SetUserError(ERR_USER_ITEM_NOT_FOUND);
|
||||
return(-1);
|
||||
}
|
||||
//--- compute count of elements
|
||||
real_count=(count==WHOLE_ARRAY || start+count>m_data_total) ? m_data_total-start : count;
|
||||
#ifdef __MQL5__
|
||||
return(ArrayMinimum(data,start,real_count));
|
||||
#else
|
||||
return(ArrayMinimum(data,real_count,start));
|
||||
#endif
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find maximum of array |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CArray::Maximum(const T &data[],const int start,const int count) const
|
||||
{
|
||||
int real_count;
|
||||
//--- check for empty array
|
||||
if(m_data_total<1)
|
||||
{
|
||||
SetUserError(ERR_USER_ARRAY_IS_EMPTY);
|
||||
return(-1);
|
||||
}
|
||||
//--- check for start is out of range
|
||||
if(start<0 || start>=m_data_total)
|
||||
{
|
||||
SetUserError(ERR_USER_ITEM_NOT_FOUND);
|
||||
return(-1);
|
||||
}
|
||||
//--- compute count of elements
|
||||
real_count=(count==WHOLE_ARRAY || start+count>m_data_total) ? m_data_total-start : count;
|
||||
#ifdef __MQL5__
|
||||
return(ArrayMaximum(data,start,real_count));
|
||||
#else
|
||||
return(ArrayMaximum(data,real_count,start));
|
||||
#endif
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,770 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayChar.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayChar. |
|
||||
//| Purpose: Class of dynamic array of char type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayChar : public CArray
|
||||
{
|
||||
protected:
|
||||
char m_data[]; // data array
|
||||
|
||||
public:
|
||||
CArrayChar(void);
|
||||
~CArrayChar(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_CHAR); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const char element);
|
||||
bool AddArray(const char &src[]);
|
||||
bool AddArray(const CArrayChar *src);
|
||||
bool Insert(const char element,const int pos);
|
||||
bool InsertArray(const char &src[],const int pos);
|
||||
bool InsertArray(const CArrayChar *src,const int pos);
|
||||
bool AssignArray(const char &src[]);
|
||||
bool AssignArray(const CArrayChar *src);
|
||||
//--- method of access to the array
|
||||
char At(const int index) const;
|
||||
char operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods of changing
|
||||
bool Update(const int index,const char element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods of deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for comparing arrays
|
||||
bool CompareArray(const char &array[]) const;
|
||||
bool CompareArray(const CArrayChar *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const char element);
|
||||
int Search(const char element) const;
|
||||
int SearchGreat(const char element) const;
|
||||
int SearchLess(const char element) const;
|
||||
int SearchGreatOrEqual(const char element) const;
|
||||
int SearchLessOrEqual(const char element) const;
|
||||
int SearchFirst(const char element) const;
|
||||
int SearchLast(const char element) const;
|
||||
int SearchLinear(const char element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const char element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayChar::CArrayChar(void)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayChar::~CArrayChar(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayChar::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::Add(const char element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::AddArray(const char &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::AddArray(const CArrayChar *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::Insert(const char element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::InsertArray(const char &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::InsertArray(const CArrayChar *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::AssignArray(const char &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::AssignArray(const CArrayChar *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
char CArrayChar::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(CHAR_MAX);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::Update(const int index,const char element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::Shift(const int index,const int shift)
|
||||
{
|
||||
char tmp_char;
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
tmp_char=m_data[index];
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
m_data[index+shift]=tmp_char;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::CompareArray(const char &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::CompareArray(const CArrayChar *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayChar::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
int i,j;
|
||||
char p_char;
|
||||
char t_char;
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
i=beg;
|
||||
j=end;
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
p_char=m_data[(beg+end)>>1];
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_char)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_char)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
t_char=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_char;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::InsertSort(const char element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- find position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayChar::SearchLinear(const char element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]==element)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayChar::QuickSearch(const char element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
char t_char;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_char=m_data[m];
|
||||
if(t_char==element)
|
||||
break;
|
||||
if(t_char>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayChar::Search(const char element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayChar::SearchGreat(const char element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]<=element)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayChar::SearchLess(const char element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]>=element)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayChar::SearchGreatOrEqual(const char element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayChar::SearchLessOrEqual(const char element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayChar::SearchFirst(const char element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayChar::SearchLast(const char element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteInteger(file_handle,m_data[i],CHAR_VALUE)!=CHAR_VALUE)
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayChar::Load(const int file_handle)
|
||||
{
|
||||
int i,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=(char)FileReadInteger(file_handle,CHAR_VALUE);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,770 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayColor.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayColor. |
|
||||
//| Purpose: Class of dynamic array of color type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayColor : public CArray
|
||||
{
|
||||
protected:
|
||||
color m_data[]; // data array
|
||||
|
||||
public:
|
||||
CArrayColor(void);
|
||||
~CArrayColor(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_COLOR); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const color element);
|
||||
bool AddArray(const color &src[]);
|
||||
bool AddArray(const CArrayColor *src);
|
||||
bool Insert(const color element,const int pos);
|
||||
bool InsertArray(const color &src[],const int pos);
|
||||
bool InsertArray(const CArrayColor *src,const int pos);
|
||||
bool AssignArray(const color &src[]);
|
||||
bool AssignArray(const CArrayColor *src);
|
||||
//--- method of access to the array
|
||||
color At(const int index) const;
|
||||
color operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods change
|
||||
bool Update(const int index,const color element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods for deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for compare arrays
|
||||
bool CompareArray(const color &array[]) const;
|
||||
bool CompareArray(const CArrayColor *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const color element);
|
||||
int Search(const color element) const;
|
||||
int SearchGreat(const color element) const;
|
||||
int SearchLess(const color element) const;
|
||||
int SearchGreatOrEqual(const color element) const;
|
||||
int SearchLessOrEqual(const color element) const;
|
||||
int SearchFirst(const color element) const;
|
||||
int SearchLast(const color element) const;
|
||||
int SearchLinear(const color element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const color element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayColor::CArrayColor(void)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayColor::~CArrayColor(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayColor::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::Add(const color element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::AddArray(const color &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::AddArray(const CArrayColor *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::Insert(const color element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::InsertArray(const color &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::InsertArray(const CArrayColor *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::AssignArray(const color &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::AssignArray(const CArrayColor *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
color CArrayColor::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(clrNONE);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::Update(const int index,const color element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::Shift(const int index,const int shift)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
color tmp_long=m_data[index];
|
||||
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
|
||||
m_data[index+shift]=tmp_long;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::CompareArray(const color &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::CompareArray(const CArrayColor *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayColor::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
int i=beg;
|
||||
int j=end;
|
||||
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
color p_long=m_data[(beg+end)>>1];
|
||||
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_long)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_long)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
color tmp=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=tmp;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::InsertSort(const color element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- search position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayColor::SearchLinear(const color element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]==element)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayColor::QuickSearch(const color element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
long t_long;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_long=m_data[m];
|
||||
if(t_long==element)
|
||||
break;
|
||||
if(t_long>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayColor::Search(const color element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayColor::SearchGreat(const color element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]<=element)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayColor::SearchLess(const color element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]>=element)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayColor::SearchGreatOrEqual(const color element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayColor::SearchLessOrEqual(const color element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayColor::SearchFirst(const color element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayColor::SearchLast(const color element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteLong(file_handle,m_data[i])!=sizeof(long))
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayColor::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=(color)FileReadLong(file_handle);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,770 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayDatetime.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayDatetime. |
|
||||
//| Purpose: Class of dynamic array of datetime type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayDatetime : public CArray
|
||||
{
|
||||
protected:
|
||||
datetime m_data[]; // data array
|
||||
|
||||
public:
|
||||
CArrayDatetime(void);
|
||||
~CArrayDatetime(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_DATETIME); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const datetime element);
|
||||
bool AddArray(const datetime &src[]);
|
||||
bool AddArray(const CArrayDatetime *src);
|
||||
bool Insert(const datetime element,const int pos);
|
||||
bool InsertArray(const datetime &src[],const int pos);
|
||||
bool InsertArray(const CArrayDatetime *src,const int pos);
|
||||
bool AssignArray(const datetime &src[]);
|
||||
bool AssignArray(const CArrayDatetime *src);
|
||||
//--- method of access to the array
|
||||
datetime At(const int index) const;
|
||||
datetime operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods change
|
||||
bool Update(const int index,const datetime element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods for deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for compare arrays
|
||||
bool CompareArray(const datetime &array[]) const;
|
||||
bool CompareArray(const CArrayDatetime *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const datetime element);
|
||||
int Search(const datetime element) const;
|
||||
int SearchGreat(const datetime element) const;
|
||||
int SearchLess(const datetime element) const;
|
||||
int SearchGreatOrEqual(const datetime element) const;
|
||||
int SearchLessOrEqual(const datetime element) const;
|
||||
int SearchFirst(const datetime element) const;
|
||||
int SearchLast(const datetime element) const;
|
||||
int SearchLinear(const datetime element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const datetime element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayDatetime::CArrayDatetime(void)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayDatetime::~CArrayDatetime(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDatetime::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::Add(const datetime element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::AddArray(const datetime &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::AddArray(const CArrayDatetime *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::Insert(const datetime element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::InsertArray(const datetime &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::InsertArray(const CArrayDatetime *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::AssignArray(const datetime &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::AssignArray(const CArrayDatetime *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
datetime CArrayDatetime::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(LONG_MAX);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::Update(const int index,const datetime element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::Shift(const int index,const int shift)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
datetime tmp_long=m_data[index];
|
||||
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
|
||||
m_data[index+shift]=tmp_long;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::CompareArray(const datetime &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::CompareArray(const CArrayDatetime *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayDatetime::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
int i=beg;
|
||||
int j=end;
|
||||
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
datetime p_long=m_data[(beg+end)>>1];
|
||||
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_long)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_long)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
datetime tmp=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=tmp;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::InsertSort(const datetime element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- search position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDatetime::SearchLinear(const datetime element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]==element)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDatetime::QuickSearch(const datetime element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
long t_long;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_long=m_data[m];
|
||||
if(t_long==element)
|
||||
break;
|
||||
if(t_long>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDatetime::Search(const datetime element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDatetime::SearchGreat(const datetime element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]<=element)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDatetime::SearchLess(const datetime element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]>=element)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDatetime::SearchGreatOrEqual(const datetime element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDatetime::SearchLessOrEqual(const datetime element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDatetime::SearchFirst(const datetime element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDatetime::SearchLast(const datetime element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteLong(file_handle,m_data[i])!=sizeof(long))
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDatetime::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=(datetime)FileReadLong(file_handle);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,777 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayDouble.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayDouble. |
|
||||
//| Puprpose: Class of dynamic array of double type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayDouble : public CArray
|
||||
{
|
||||
protected:
|
||||
double m_data[]; // data array
|
||||
double m_delta; // search tolerance
|
||||
|
||||
public:
|
||||
CArrayDouble(void);
|
||||
~CArrayDouble(void);
|
||||
//--- methods of access to protected data
|
||||
void Delta(const double delta) { m_delta=MathAbs(delta); }
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_DOUBLE); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const double element);
|
||||
bool AddArray(const double &src[]);
|
||||
bool AddArray(const CArrayDouble *src);
|
||||
bool Insert(const double element,const int pos);
|
||||
bool InsertArray(const double &src[],const int pos);
|
||||
bool InsertArray(const CArrayDouble *src,const int pos);
|
||||
bool AssignArray(const double &src[]);
|
||||
bool AssignArray(const CArrayDouble *src);
|
||||
//--- method of access to the array
|
||||
double At(const int index) const;
|
||||
double operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods of changing
|
||||
bool Update(const int index,const double element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods of deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for comparing arrays
|
||||
bool CompareArray(const double &array[]) const;
|
||||
bool CompareArray(const CArrayDouble *array) const;
|
||||
//--- methods for working with a sorted array
|
||||
bool InsertSort(const double element);
|
||||
int Search(const double element) const;
|
||||
int SearchGreat(const double element) const;
|
||||
int SearchLess(const double element) const;
|
||||
int SearchGreatOrEqual(const double element) const;
|
||||
int SearchLessOrEqual(const double element) const;
|
||||
int SearchFirst(const double element) const;
|
||||
int SearchLast(const double element) const;
|
||||
int SearchLinear(const double element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const double element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayDouble::CArrayDouble(void) : m_delta(0.0)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayDouble::~CArrayDouble(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDouble::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::Add(const double element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::AddArray(const double &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::AddArray(const CArrayDouble *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::Insert(const double element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::InsertArray(const double &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::InsertArray(const CArrayDouble *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::AssignArray(const double &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::AssignArray(const CArrayDouble *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
double CArrayDouble::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(DBL_MAX);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::Update(const int index,const double element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::Shift(const int index,const int shift)
|
||||
{
|
||||
double tmp_double;
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
tmp_double=m_data[index];
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
m_data[index+shift]=tmp_double;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::CompareArray(const double &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::CompareArray(const CArrayDouble *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayDouble::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
int i,j;
|
||||
double p_double,t_double;
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
i=beg;
|
||||
j=end;
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
p_double=m_data[(beg+end)>>1];
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_double)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_double)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
t_double=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_double;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::InsertSort(const double element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- search position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDouble::SearchLinear(const double element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(MathAbs(m_data[i]-element)<=m_delta)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDouble::QuickSearch(const double element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
double t_double;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_double=m_data[m];
|
||||
//--- compare with delta
|
||||
if(MathAbs(t_double-element)<=m_delta)
|
||||
break;
|
||||
if(t_double>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDouble::Search(const double element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
//--- compare with delta
|
||||
if(MathAbs(m_data[pos]-element)<=m_delta)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDouble::SearchGreat(const double element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
//--- compare with delta
|
||||
while(m_data[pos]<=element+m_delta)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDouble::SearchLess(const double element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
//--- compare with delta
|
||||
while(m_data[pos]>=element-m_delta)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDouble::SearchGreatOrEqual(const double element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDouble::SearchLessOrEqual(const double element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDouble::SearchFirst(const double element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
//--- compare with delta
|
||||
while(MathAbs(m_data[pos]-element)<=m_delta)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayDouble::SearchLast(const double element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
//--- compare with delta
|
||||
while(MathAbs(m_data[pos]-element)<=m_delta)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteDouble(file_handle,m_data[i])!=sizeof(double))
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayDouble::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=FileReadDouble(file_handle);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,777 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayFloat.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayFloat. |
|
||||
//| Purpose: Class of dynamic array of float type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayFloat : public CArray
|
||||
{
|
||||
protected:
|
||||
float m_data[]; // data array
|
||||
float m_delta; // search tolerance
|
||||
|
||||
public:
|
||||
CArrayFloat(void);
|
||||
~CArrayFloat(void);
|
||||
//--- methods of access to protected data
|
||||
void Delta(const float delta) { m_delta=(float)MathAbs(delta); }
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_FLOAT); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const float element);
|
||||
bool AddArray(const float &src[]);
|
||||
bool AddArray(const CArrayFloat *src);
|
||||
bool Insert(const float element,const int pos);
|
||||
bool InsertArray(const float &src[],const int pos);
|
||||
bool InsertArray(const CArrayFloat *src,const int pos);
|
||||
bool AssignArray(const float &src[]);
|
||||
bool AssignArray(const CArrayFloat *src);
|
||||
//--- method of access to the array
|
||||
float At(const int index) const;
|
||||
float operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods of changing
|
||||
bool Update(const int index,const float element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for comparing arrays
|
||||
bool CompareArray(const float &array[]) const;
|
||||
bool CompareArray(const CArrayFloat *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const float element);
|
||||
int Search(const float element) const;
|
||||
int SearchGreat(const float element) const;
|
||||
int SearchLess(const float element) const;
|
||||
int SearchGreatOrEqual(const float element) const;
|
||||
int SearchLessOrEqual(const float element) const;
|
||||
int SearchFirst(const float element) const;
|
||||
int SearchLast(const float element) const;
|
||||
int SearchLinear(const float element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const float element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayFloat::CArrayFloat(void) : m_delta(0.0)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayFloat::~CArrayFloat(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayFloat::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::Add(const float element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::AddArray(const float &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::AddArray(const CArrayFloat *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::Insert(const float element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::InsertArray(const float &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::InsertArray(const CArrayFloat *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::AssignArray(const float &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::AssignArray(const CArrayFloat *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
float CArrayFloat::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(FLT_MAX);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::Update(const int index,const float element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::Shift(const int index,const int shift)
|
||||
{
|
||||
float tmp_float;
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
tmp_float=m_data[index];
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
m_data[index+shift]=tmp_float;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::CompareArray(const float &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::CompareArray(const CArrayFloat *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array)) return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayFloat::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
int i,j;
|
||||
float p_float,t_float;
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
i=beg;
|
||||
j=end;
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
p_float=m_data[(beg+end)>>1];
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_float)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_float)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
t_float=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_float;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::InsertSort(const float element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- search position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayFloat::SearchLinear(const float element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(MathAbs(m_data[i]-element)<=m_delta)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayFloat::QuickSearch(const float element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
float t_float;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_float=m_data[m];
|
||||
//--- compare with delta
|
||||
if(MathAbs(t_float-element)<=m_delta)
|
||||
break;
|
||||
if(t_float>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayFloat::Search(const float element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
//--- compare with delta
|
||||
if(MathAbs(m_data[pos]-element)<=m_delta)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayFloat::SearchGreat(const float element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
//--- compare with delta
|
||||
while(m_data[pos]<=element+m_delta)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayFloat::SearchLess(const float element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
//--- compare with delta
|
||||
while(m_data[pos]>=element-m_delta)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayFloat::SearchGreatOrEqual(const float element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayFloat::SearchLessOrEqual(const float element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayFloat::SearchFirst(const float element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
//--- compare with delta
|
||||
while(MathAbs(m_data[pos]-element)<=m_delta)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayFloat::SearchLast(const float element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
//--- compare with delta
|
||||
while(MathAbs(m_data[pos]-element)<=m_delta)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteFloat(file_handle,m_data[i])!=sizeof(float))
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayFloat::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=FileReadFloat(file_handle);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,769 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayInt.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayInt. |
|
||||
//| Puprose: Class of dynamic array of int type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayInt : public CArray
|
||||
{
|
||||
protected:
|
||||
int m_data[]; // data array
|
||||
|
||||
public:
|
||||
CArrayInt(void);
|
||||
~CArrayInt(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_INT); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const int element);
|
||||
bool AddArray(const int &src[]);
|
||||
bool AddArray(const CArrayInt *src);
|
||||
bool Insert(const int element,const int pos);
|
||||
bool InsertArray(const int &src[],const int pos);
|
||||
bool InsertArray(const CArrayInt *src,const int pos);
|
||||
bool AssignArray(const int &src[]);
|
||||
bool AssignArray(const CArrayInt *src);
|
||||
//--- method of access to the array
|
||||
int At(const int index) const;
|
||||
int operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods of changing
|
||||
bool Update(const int index,const int element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods of deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for comparing arrays
|
||||
bool CompareArray(const int &array[]) const;
|
||||
bool CompareArray(const CArrayInt *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const int element);
|
||||
int Search(const int element) const;
|
||||
int SearchGreat(const int element) const;
|
||||
int SearchLess(const int element) const;
|
||||
int SearchGreatOrEqual(const int element) const;
|
||||
int SearchLessOrEqual(const int element) const;
|
||||
int SearchFirst(const int element) const;
|
||||
int SearchLast(const int element) const;
|
||||
int SearchLinear(const int element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const int element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayInt::CArrayInt(void)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayInt::~CArrayInt(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayInt::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::Add(const int element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::AddArray(const int &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::AddArray(const CArrayInt *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::Insert(const int element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::InsertArray(const int &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::InsertArray(const CArrayInt *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::AssignArray(const int &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::AssignArray(const CArrayInt *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayInt::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(INT_MAX);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::Update(const int index,const int element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::Shift(const int index,const int shift)
|
||||
{
|
||||
int tmp_int;
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
tmp_int=m_data[index];
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
m_data[index+shift]=tmp_int;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::CompareArray(const int &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::CompareArray(const CArrayInt *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayInt::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
int i,j;
|
||||
int p_int,t_int;
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
i=beg;
|
||||
j=end;
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
p_int=m_data[(beg+end)>>1];
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_int)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_int)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
t_int=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_int;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::InsertSort(const int element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- find position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayInt::SearchLinear(const int element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]==element)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayInt::QuickSearch(const int element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
int t_int;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_int=m_data[m];
|
||||
if(t_int==element)
|
||||
break;
|
||||
if(t_int>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayInt::Search(const int element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayInt::SearchGreat(const int element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]<=element)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayInt::SearchLess(const int element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]>=element)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayInt::SearchGreatOrEqual(const int element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayInt::SearchLessOrEqual(const int element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayInt::SearchFirst(const int element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayInt::SearchLast(const int element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteInteger(file_handle,m_data[i],INT_VALUE)!=INT_VALUE)
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayInt::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=FileReadInteger(file_handle,INT_VALUE);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,769 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayLong.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayLong. |
|
||||
//| Purpose: Class of dynamic array of long type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayLong : public CArray
|
||||
{
|
||||
protected:
|
||||
long m_data[]; // data array
|
||||
|
||||
public:
|
||||
CArrayLong(void);
|
||||
~CArrayLong(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_LONG); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const long element);
|
||||
bool AddArray(const long &src[]);
|
||||
bool AddArray(const CArrayLong *src);
|
||||
bool Insert(const long element,const int pos);
|
||||
bool InsertArray(const long &src[],const int pos);
|
||||
bool InsertArray(const CArrayLong *src,const int pos);
|
||||
bool AssignArray(const long &src[]);
|
||||
bool AssignArray(const CArrayLong *src);
|
||||
//--- method of access to the array
|
||||
long At(const int index) const;
|
||||
long operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods change
|
||||
bool Update(const int index,const long element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods for deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for compare arrays
|
||||
bool CompareArray(const long &array[]) const;
|
||||
bool CompareArray(const CArrayLong *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const long element);
|
||||
int Search(const long element) const;
|
||||
int SearchGreat(const long element) const;
|
||||
int SearchLess(const long element) const;
|
||||
int SearchGreatOrEqual(const long element) const;
|
||||
int SearchLessOrEqual(const long element) const;
|
||||
int SearchFirst(const long element) const;
|
||||
int SearchLast(const long element) const;
|
||||
int SearchLinear(const long element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const long element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayLong::CArrayLong(void)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayLong::~CArrayLong(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayLong::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::Add(const long element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::AddArray(const long &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::AddArray(const CArrayLong *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::Insert(const long element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::InsertArray(const long &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::InsertArray(const CArrayLong *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::AssignArray(const long &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::AssignArray(const CArrayLong *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
long CArrayLong::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(LONG_MAX);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::Update(const int index,const long element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::Shift(const int index,const int shift)
|
||||
{
|
||||
long tmp_long;
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
tmp_long=m_data[index];
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
m_data[index+shift]=tmp_long;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::CompareArray(const long &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::CompareArray(const CArrayLong *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayLong::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
int i,j;
|
||||
long p_long,t_long;
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
i=beg;
|
||||
j=end;
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
p_long=m_data[(beg+end)>>1];
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_long)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_long)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
t_long=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_long;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::InsertSort(const long element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- search position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayLong::SearchLinear(const long element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]==element)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayLong::QuickSearch(const long element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
long t_long;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_long=m_data[m];
|
||||
if(t_long==element)
|
||||
break;
|
||||
if(t_long>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayLong::Search(const long element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayLong::SearchGreat(const long element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]<=element)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayLong::SearchLess(const long element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]>=element)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayLong::SearchGreatOrEqual(const long element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayLong::SearchLessOrEqual(const long element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayLong::SearchFirst(const long element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayLong::SearchLast(const long element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteLong(file_handle,m_data[i])!=sizeof(long))
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayLong::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=FileReadLong(file_handle);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,759 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayObj.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayObj. |
|
||||
//| Puprose: Class of dynamic array of pointers to instances |
|
||||
//| of the CObject class and its derivatives. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayObj : public CArray
|
||||
{
|
||||
protected:
|
||||
CObject *m_data[]; // data array
|
||||
bool m_free_mode; // flag of necessity of "physical" deletion of object
|
||||
|
||||
public:
|
||||
CArrayObj(void);
|
||||
~CArrayObj(void);
|
||||
//--- methods of access to protected data
|
||||
bool FreeMode(void) const { return(m_free_mode); }
|
||||
void FreeMode(const bool mode) { m_free_mode=mode; }
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(0x7778); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- method of creating an element of array
|
||||
virtual bool CreateElement(const int index) { return(false); }
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(CObject *element);
|
||||
bool AddArray(const CArrayObj *src);
|
||||
bool Insert(CObject *element,const int pos);
|
||||
bool InsertArray(const CArrayObj *src,const int pos);
|
||||
bool AssignArray(const CArrayObj *src);
|
||||
//--- method of access to thre array
|
||||
CObject *At(const int index) const;
|
||||
//--- methods of changing
|
||||
bool Update(const int index,CObject *element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods of deleting
|
||||
CObject *Detach(const int index);
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
void Clear(void);
|
||||
//--- method for comparing arrays
|
||||
bool CompareArray(const CArrayObj *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(CObject *element);
|
||||
int Search(const CObject *element) const;
|
||||
int SearchGreat(const CObject *element) const;
|
||||
int SearchLess(const CObject *element) const;
|
||||
int SearchGreatOrEqual(const CObject *element) const;
|
||||
int SearchLessOrEqual(const CObject *element) const;
|
||||
int SearchFirst(const CObject *element) const;
|
||||
int SearchLast(const CObject *element) const;
|
||||
|
||||
protected:
|
||||
void QuickSort(int beg,int end,const int mode);
|
||||
int QuickSearch(const CObject *element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayObj::CArrayObj(void) : m_free_mode(true)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayObj::~CArrayObj(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayObj::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
{
|
||||
//--- "physical" removal of the object (if necessary and possible)
|
||||
if(m_free_mode && CheckPointer(m_data[dest+i])==POINTER_DYNAMIC)
|
||||
delete m_data[dest+i];
|
||||
//---
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
m_data[src+i]=NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
{
|
||||
//--- "physical" removal of the object (if necessary and possible)
|
||||
if(m_free_mode && CheckPointer(m_data[dest+i])==POINTER_DYNAMIC)
|
||||
delete m_data[dest+i];
|
||||
//---
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
m_data[src+i]=NULL;
|
||||
}
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
//--- explicitly zeroize all the loose items in the array
|
||||
for(int i=m_data_total;i<m_data_max;i++)
|
||||
m_data[i]=NULL;
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_total>size)
|
||||
{
|
||||
//--- "physical" removal of the object (if necessary and possible)
|
||||
if(m_free_mode)
|
||||
for(int i=size;i<m_data_total;i++)
|
||||
if(CheckPointer(m_data[i])==POINTER_DYNAMIC)
|
||||
delete m_data[i];
|
||||
m_data_total=size;
|
||||
}
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
Clear();
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::Add(CObject *element)
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(element))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::AddArray(const CArrayObj *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::Insert(CObject *element,const int pos)
|
||||
{
|
||||
//--- check
|
||||
if(pos<0 || !CheckPointer(element))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::InsertArray(const CArrayObj *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num)) return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::AssignArray(const CArrayObj *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
CObject *CArrayObj::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(NULL);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::Update(const int index,CObject *element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || !CheckPointer(element) || index>=m_data_total)
|
||||
return(false);
|
||||
//--- "physical" removal of the object (if necessary and possible)
|
||||
if(m_free_mode && CheckPointer(m_data[index])==POINTER_DYNAMIC)
|
||||
delete m_data[index];
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::Shift(const int index,const int shift)
|
||||
{
|
||||
CObject *tmp_node;
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
tmp_node=m_data[index];
|
||||
m_data[index]=NULL;
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
m_data[index+shift]=tmp_node;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1)
|
||||
{
|
||||
if(index>=0 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
if(m_free_mode && CheckPointer(m_data[index])==POINTER_DYNAMIC)
|
||||
delete m_data[index];
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detach element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
CObject *CArrayObj::Detach(const int index)
|
||||
{
|
||||
CObject *result;
|
||||
//--- check
|
||||
if(index>=m_data_total)
|
||||
return(NULL);
|
||||
//--- detach
|
||||
result=m_data[index];
|
||||
//--- reset the array element, so as not remove the method MemMove
|
||||
m_data[index]=NULL;
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(NULL);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
for(int i=to-from+1;i>0;i--,m_data_total--)
|
||||
if(m_free_mode && CheckPointer(m_data[m_data_total-1])==POINTER_DYNAMIC)
|
||||
delete m_data[m_data_total-1];
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Clearing of array without the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayObj::Clear(void)
|
||||
{
|
||||
//--- "physical" removal of the object (if necessary and possible)
|
||||
if(m_free_mode)
|
||||
{
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
{
|
||||
if(CheckPointer(m_data[i])==POINTER_DYNAMIC)
|
||||
delete m_data[i];
|
||||
m_data[i]=NULL;
|
||||
}
|
||||
}
|
||||
m_data_total=0;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::CompareArray(const CArrayObj *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i].Compare(array.m_data[i],0)!=0)
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayObj::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
int i,j;
|
||||
CObject *p_node;
|
||||
CObject *t_node;
|
||||
//--- sort
|
||||
i=beg;
|
||||
j=end;
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
p_node=m_data[(beg+end)>>1];
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i].Compare(p_node,mode)<0)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j].Compare(p_node,mode)>0)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
t_node=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_node;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j,mode);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::InsertSort(CObject *element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!CheckPointer(element) || m_sort_mode==-1)
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- find position and insert
|
||||
int mode=m_sort_mode;
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos].Compare(element,m_sort_mode)>0)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=mode;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayObj::QuickSearch(const CObject *element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
CObject *t_node;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m==m_data_total-1)
|
||||
break;
|
||||
t_node=m_data[m];
|
||||
if(t_node.Compare(element,m_sort_mode)==0)
|
||||
break;
|
||||
if(t_node.Compare(element,m_sort_mode)>0)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayObj::Search(const CObject *element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos].Compare(element,m_sort_mode)==0)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayObj::SearchGreat(const CObject *element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos].Compare(element,m_sort_mode)<=0)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayObj::SearchLess(const CObject *element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos].Compare(element,m_sort_mode)>=0)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayObj::SearchGreatOrEqual(const CObject *element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos].Compare(element,m_sort_mode)>=0)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayObj::SearchLessOrEqual(const CObject *element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos].Compare(element,m_sort_mode)<=0)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayObj::SearchFirst(const CObject *element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos].Compare(element,m_sort_mode)==0)
|
||||
{
|
||||
while(m_data[pos].Compare(element,m_sort_mode)==0)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayObj::SearchLast(const CObject *element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos].Compare(element,m_sort_mode)==0)
|
||||
{
|
||||
while(m_data[pos].Compare(element,m_sort_mode)==0)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(m_data[i].Save(file_handle)!=true)
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayObj::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
//--- create new element
|
||||
if(!CreateElement(i))
|
||||
break;
|
||||
if(m_data[i].Load(file_handle)!=true)
|
||||
break;
|
||||
m_data_total++;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,769 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayShort.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayShort. |
|
||||
//| Pupose: Class of dynamic array of short type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayShort : public CArray
|
||||
{
|
||||
protected:
|
||||
short m_data[]; // data array
|
||||
|
||||
public:
|
||||
CArrayShort(void);
|
||||
~CArrayShort(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_SHORT); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const short element);
|
||||
bool AddArray(const short &src[]);
|
||||
bool AddArray(const CArrayShort *src);
|
||||
bool Insert(const short element,const int pos);
|
||||
bool InsertArray(const short &src[],const int pos);
|
||||
bool InsertArray(const CArrayShort *src,const int pos);
|
||||
bool AssignArray(const short &src[]);
|
||||
bool AssignArray(const CArrayShort *src);
|
||||
//--- method of access to the array
|
||||
short At(const int index) const;
|
||||
short operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods of changing
|
||||
bool Update(const int index,const short element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods of deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for comparing arrays
|
||||
bool CompareArray(const short &array[]) const;
|
||||
bool CompareArray(const CArrayShort *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const short element);
|
||||
int Search(const short element) const;
|
||||
int SearchGreat(const short element) const;
|
||||
int SearchLess(const short element) const;
|
||||
int SearchGreatOrEqual(const short element) const;
|
||||
int SearchLessOrEqual(const short element) const;
|
||||
int SearchFirst(const short element) const;
|
||||
int SearchLast(const short element) const;
|
||||
int SearchLinear(const short element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const short element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayShort::CArrayShort(void)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayShort::~CArrayShort(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayShort::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::Add(const short element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::AddArray(const short &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::AddArray(const CArrayShort *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::Insert(const short element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::InsertArray(const short &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::InsertArray(const CArrayShort *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::AssignArray(const short &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::AssignArray(const CArrayShort *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
short CArrayShort::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(SHORT_MAX);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::Update(const int index,const short element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::Shift(const int index,const int shift)
|
||||
{
|
||||
short tmp_short;
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
tmp_short=m_data[index];
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
m_data[index+shift]=tmp_short;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::CompareArray(const short &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::CompareArray(const CArrayShort *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayShort::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
int i,j;
|
||||
short p_short,t_short;
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
i=beg;
|
||||
j=end;
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
p_short=m_data[(beg+end)>>1];
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_short)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_short)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
t_short=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_short;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::InsertSort(const short element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- find position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayShort::SearchLinear(const short element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]==element)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayShort::QuickSearch(const short element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
short t_short;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_short=m_data[m];
|
||||
if(t_short==element)
|
||||
break;
|
||||
if(t_short>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayShort::Search(const short element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayShort::SearchGreat(const short element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]<=element)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayShort::SearchLess(const short element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]>=element)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayShort::SearchGreatOrEqual(const short element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayShort::SearchLessOrEqual(const short element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayShort::SearchFirst(const short element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayShort::SearchLast(const short element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteInteger(file_handle,m_data[i],SHORT_VALUE)!=SHORT_VALUE)
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayShort::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=(short)FileReadInteger(file_handle,SHORT_VALUE);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,780 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayString.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayString. |
|
||||
//| Purpose: Class of dynamic array of string type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayString : public CArray
|
||||
{
|
||||
protected:
|
||||
string m_data[]; // data array
|
||||
|
||||
public:
|
||||
CArrayString(void);
|
||||
~CArrayString(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_STRING); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const string element);
|
||||
bool AddArray(const string &src[]);
|
||||
bool AddArray(const CArrayString *src);
|
||||
bool Insert(const string element,const int pos);
|
||||
bool InsertArray(const string &src[],const int pos);
|
||||
bool InsertArray(const CArrayString *src,const int pos);
|
||||
bool AssignArray(const string &src[]);
|
||||
bool AssignArray(const CArrayString *src);
|
||||
//--- method of access to the array
|
||||
string At(const int index) const;
|
||||
string operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of changing
|
||||
bool Update(const int index,const string element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods of deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for comparing arrays
|
||||
bool CompareArray(const string &array[]) const;
|
||||
bool CompareArray(const CArrayString *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const string element);
|
||||
int Search(const string element) const;
|
||||
int SearchGreat(const string element) const;
|
||||
int SearchLess(const string element) const;
|
||||
int SearchGreatOrEqual(const string element) const;
|
||||
int SearchLessOrEqual(const string element) const;
|
||||
int SearchFirst(const string element) const;
|
||||
int SearchLast(const string element) const;
|
||||
int SearchLinear(const string element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const string element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayString::CArrayString(void)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayString::~CArrayString(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayString::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::Add(const string element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::AddArray(const string &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::AddArray(const CArrayString *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::Insert(const string element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::InsertArray(const string &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::InsertArray(const CArrayString *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::AssignArray(const string &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::AssignArray(const CArrayString *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
string CArrayString::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return("");
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::Update(const int index,const string element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::Shift(const int index,const int shift)
|
||||
{
|
||||
string tmp_string;
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
tmp_string=m_data[index];
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
m_data[index+shift]=tmp_string;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::CompareArray(const string &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::CompareArray(const CArrayString *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayString::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
int i,j;
|
||||
string p_string;
|
||||
string t_string;
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
i=beg;
|
||||
j=end;
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
p_string=m_data[(beg+end)>>1];
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_string)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_string)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
t_string=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_string;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::InsertSort(const string element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- find position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayString::SearchLinear(const string element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]==element)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayString::QuickSearch(const string element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
string t_string;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_string=m_data[m];
|
||||
if(t_string==element)
|
||||
break;
|
||||
if(t_string>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayString::Search(const string element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayString::SearchGreat(const string element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]<=element)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayString::SearchLess(const string element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]>=element)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayString::SearchGreatOrEqual(const string element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayString::SearchLessOrEqual(const string element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayString::SearchFirst(const string element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayString::SearchLast(const string element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::Save(const int file_handle)
|
||||
{
|
||||
int i=0,len;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
{
|
||||
len=StringLen(m_data[i]);
|
||||
//--- write string length
|
||||
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write string
|
||||
if(len!=0) if(FileWriteString(file_handle,m_data[i],len)!=len)
|
||||
break;
|
||||
}
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayString::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num,len;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
//--- read string length
|
||||
len=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read string
|
||||
if(len!=0)
|
||||
m_data[i]=FileReadString(file_handle,len);
|
||||
else
|
||||
m_data[i]="";
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,770 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayUChar.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayUChar. |
|
||||
//| Purpose: Class of dynamic array of uchar type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayUChar : public CArray
|
||||
{
|
||||
protected:
|
||||
uchar m_data[]; // data array
|
||||
|
||||
public:
|
||||
CArrayUChar(void);
|
||||
~CArrayUChar(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_UCHAR); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const uchar element);
|
||||
bool AddArray(const uchar &src[]);
|
||||
bool AddArray(const CArrayUChar *src);
|
||||
bool Insert(const uchar element,const int pos);
|
||||
bool InsertArray(const uchar &src[],const int pos);
|
||||
bool InsertArray(const CArrayUChar *src,const int pos);
|
||||
bool AssignArray(const uchar &src[]);
|
||||
bool AssignArray(const CArrayUChar *src);
|
||||
//--- method of access to the array
|
||||
uchar At(const int index) const;
|
||||
uchar operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods of changing
|
||||
bool Update(const int index,const uchar element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods of deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for comparing arrays
|
||||
bool CompareArray(const uchar &array[]) const;
|
||||
bool CompareArray(const CArrayUChar *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const uchar element);
|
||||
int Search(const uchar element) const;
|
||||
int SearchGreat(const uchar element) const;
|
||||
int SearchLess(const uchar element) const;
|
||||
int SearchGreatOrEqual(const uchar element) const;
|
||||
int SearchLessOrEqual(const uchar element) const;
|
||||
int SearchFirst(const uchar element) const;
|
||||
int SearchLast(const uchar element) const;
|
||||
int SearchLinear(const uchar element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const uchar element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayUChar::CArrayUChar(void)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayUChar::~CArrayUChar(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUChar::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::Add(const uchar element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::AddArray(const uchar &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::AddArray(const CArrayUChar *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::Insert(const uchar element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::InsertArray(const uchar &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::InsertArray(const CArrayUChar *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::AssignArray(const uchar &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::AssignArray(const CArrayUChar *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
uchar CArrayUChar::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(CHAR_MAX);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::Update(const int index,const uchar element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::Shift(const int index,const int shift)
|
||||
{
|
||||
uchar tmp_char;
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
tmp_char=m_data[index];
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
m_data[index+shift]=tmp_char;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::CompareArray(const uchar &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::CompareArray(const CArrayUChar *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayUChar::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
int i,j;
|
||||
uchar p_char;
|
||||
uchar t_char;
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
i=beg;
|
||||
j=end;
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
p_char=m_data[(beg+end)>>1];
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_char)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_char)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
t_char=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_char;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::InsertSort(const uchar element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- find position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUChar::SearchLinear(const uchar element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]==element)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUChar::QuickSearch(const uchar element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
uchar t_char;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_char=m_data[m];
|
||||
if(t_char==element)
|
||||
break;
|
||||
if(t_char>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUChar::Search(const uchar element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUChar::SearchGreat(const uchar element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]<=element)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUChar::SearchLess(const uchar element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]>=element)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUChar::SearchGreatOrEqual(const uchar element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUChar::SearchLessOrEqual(const uchar element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUChar::SearchFirst(const uchar element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUChar::SearchLast(const uchar element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteInteger(file_handle,m_data[i],CHAR_VALUE)!=CHAR_VALUE)
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUChar::Load(const int file_handle)
|
||||
{
|
||||
int i,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=(uchar)FileReadInteger(file_handle,CHAR_VALUE);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,774 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayUInt.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayUInt. |
|
||||
//| Puprose: Class of dynamic array of uint type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayUInt : public CArray
|
||||
{
|
||||
protected:
|
||||
uint m_data[]; // data array
|
||||
|
||||
public:
|
||||
CArrayUInt(void);
|
||||
~CArrayUInt(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_UINT); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const uint element);
|
||||
bool AddArray(const uint &src[]);
|
||||
bool AddArray(const CArrayUInt *src);
|
||||
bool Insert(const uint element,const int pos);
|
||||
bool InsertArray(const uint &src[],const int pos);
|
||||
bool InsertArray(const CArrayUInt *src,const int pos);
|
||||
bool AssignArray(const uint &src[]);
|
||||
bool AssignArray(const CArrayUInt *src);
|
||||
//--- method of access to the array
|
||||
uint At(const int index) const;
|
||||
uint operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods of changing
|
||||
bool Update(const int index,const uint element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods of deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for comparing arrays
|
||||
bool CompareArray(const uint &array[]) const;
|
||||
bool CompareArray(const CArrayUInt *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const uint element);
|
||||
int Search(const uint element) const;
|
||||
int SearchGreat(const uint element) const;
|
||||
int SearchLess(const uint element) const;
|
||||
int SearchGreatOrEqual(const uint element) const;
|
||||
int SearchLessOrEqual(const uint element) const;
|
||||
int SearchFirst(const uint element) const;
|
||||
int SearchLast(const uint element) const;
|
||||
int SearchLinear(const uint element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const uint element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayUInt::CArrayUInt(void)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayUInt::~CArrayUInt(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUInt::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::Add(const uint element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::AddArray(const uint &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::AddArray(const CArrayUInt *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::Insert(const uint element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::InsertArray(const uint &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::InsertArray(const CArrayUInt *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::AssignArray(const uint &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::AssignArray(const CArrayUInt *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
uint CArrayUInt::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(INT_MAX);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::Update(const int index,const uint element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::Shift(const int index,const int shift)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
uint tmp_int=m_data[index];
|
||||
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
|
||||
m_data[index+shift]=tmp_int;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::CompareArray(const uint &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::CompareArray(const CArrayUInt *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayUInt::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
int i=beg;
|
||||
int j=end;
|
||||
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
uint p_int=m_data[(beg+end)>>1];
|
||||
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_int)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_int)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
uint t_uint=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_uint;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::InsertSort(const uint element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- find position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUInt::SearchLinear(const uint element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]==element)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUInt::QuickSearch(const uint element) const
|
||||
{
|
||||
//--- search
|
||||
int m=-1;
|
||||
int i=0;
|
||||
int j=m_data_total-1;
|
||||
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
|
||||
uint t_int=m_data[m];
|
||||
|
||||
if(t_int==element)
|
||||
break;
|
||||
if(t_int>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUInt::Search(const uint element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUInt::SearchGreat(const uint element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]<=element)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUInt::SearchLess(const uint element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]>=element)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUInt::SearchGreatOrEqual(const uint element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUInt::SearchLessOrEqual(const uint element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUInt::SearchFirst(const uint element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUInt::SearchLast(const uint element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteInteger(file_handle,m_data[i],INT_VALUE)!=INT_VALUE)
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUInt::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=FileReadInteger(file_handle,INT_VALUE);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,769 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayULong.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayULong. |
|
||||
//| Purpose: Class of dynamic array of ulong type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayULong : public CArray
|
||||
{
|
||||
protected:
|
||||
ulong m_data[]; // data array
|
||||
|
||||
public:
|
||||
CArrayULong(void);
|
||||
~CArrayULong(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_ULONG); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const ulong element);
|
||||
bool AddArray(const ulong &src[]);
|
||||
bool AddArray(const CArrayULong *src);
|
||||
bool Insert(const ulong element,const int pos);
|
||||
bool InsertArray(const ulong &src[],const int pos);
|
||||
bool InsertArray(const CArrayULong *src,const int pos);
|
||||
bool AssignArray(const ulong &src[]);
|
||||
bool AssignArray(const CArrayULong *src);
|
||||
//--- method of access to the array
|
||||
ulong At(const int index) const;
|
||||
ulong operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods change
|
||||
bool Update(const int index,const ulong element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods for deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for compare arrays
|
||||
bool CompareArray(const ulong &array[]) const;
|
||||
bool CompareArray(const CArrayULong *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const ulong element);
|
||||
int Search(const ulong element) const;
|
||||
int SearchGreat(const ulong element) const;
|
||||
int SearchLess(const ulong element) const;
|
||||
int SearchGreatOrEqual(const ulong element) const;
|
||||
int SearchLessOrEqual(const ulong element) const;
|
||||
int SearchFirst(const ulong element) const;
|
||||
int SearchLast(const ulong element) const;
|
||||
int SearchLinear(const ulong element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const ulong element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayULong::CArrayULong(void)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayULong::~CArrayULong(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayULong::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::Add(const ulong element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::AddArray(const ulong &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::AddArray(const CArrayULong *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::Insert(const ulong element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::InsertArray(const ulong &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::InsertArray(const CArrayULong *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::AssignArray(const ulong &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::AssignArray(const CArrayULong *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
ulong CArrayULong::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(LONG_MAX);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::Update(const int index,const ulong element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::Shift(const int index,const int shift)
|
||||
{
|
||||
ulong tmp_long;
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
tmp_long=m_data[index];
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
m_data[index+shift]=tmp_long;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::CompareArray(const ulong &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::CompareArray(const CArrayULong *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayULong::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
int i,j;
|
||||
ulong p_long,t_long;
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
i=beg;
|
||||
j=end;
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
p_long=m_data[(beg+end)>>1];
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_long)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_long)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
t_long=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_long;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::InsertSort(const ulong element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- search position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayULong::SearchLinear(const ulong element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]==element)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayULong::QuickSearch(const ulong element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
ulong t_long;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_long=m_data[m];
|
||||
if(t_long==element)
|
||||
break;
|
||||
if(t_long>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayULong::Search(const ulong element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayULong::SearchGreat(const ulong element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]<=element)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayULong::SearchLess(const ulong element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]>=element)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayULong::SearchGreatOrEqual(const ulong element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayULong::SearchLessOrEqual(const ulong element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayULong::SearchFirst(const ulong element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayULong::SearchLast(const ulong element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteLong(file_handle,m_data[i])!=sizeof(ulong))
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayULong::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=FileReadLong(file_handle);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,769 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayUShort.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Array.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CArrayUShort. |
|
||||
//| Pupose: Class of dynamic array of ushort type values. |
|
||||
//| Derives from class CArray. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CArrayUShort : public CArray
|
||||
{
|
||||
protected:
|
||||
ushort m_data[]; // data array
|
||||
|
||||
public:
|
||||
CArrayUShort(void);
|
||||
~CArrayUShort(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(TYPE_USHORT); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- methods of managing dynamic memory
|
||||
bool Reserve(const int size);
|
||||
bool Resize(const int size);
|
||||
bool Shutdown(void);
|
||||
//--- methods of filling the array
|
||||
bool Add(const ushort element);
|
||||
bool AddArray(const ushort &src[]);
|
||||
bool AddArray(const CArrayUShort *src);
|
||||
bool Insert(const ushort element,const int pos);
|
||||
bool InsertArray(const ushort &src[],const int pos);
|
||||
bool InsertArray(const CArrayUShort *src,const int pos);
|
||||
bool AssignArray(const ushort &src[]);
|
||||
bool AssignArray(const CArrayUShort *src);
|
||||
//--- method of access to the array
|
||||
ushort At(const int index) const;
|
||||
ushort operator[](const int index) const { return(At(index)); }
|
||||
//--- methods of searching for minimum and maximum
|
||||
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
|
||||
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
|
||||
//--- methods of changing
|
||||
bool Update(const int index,const ushort element);
|
||||
bool Shift(const int index,const int shift);
|
||||
//--- methods of deleting
|
||||
bool Delete(const int index);
|
||||
bool DeleteRange(int from,int to);
|
||||
//--- methods for comparing arrays
|
||||
bool CompareArray(const ushort &array[]) const;
|
||||
bool CompareArray(const CArrayUShort *array) const;
|
||||
//--- methods for working with the sorted array
|
||||
bool InsertSort(const ushort element);
|
||||
int Search(const ushort element) const;
|
||||
int SearchGreat(const ushort element) const;
|
||||
int SearchLess(const ushort element) const;
|
||||
int SearchGreatOrEqual(const ushort element) const;
|
||||
int SearchLessOrEqual(const ushort element) const;
|
||||
int SearchFirst(const ushort element) const;
|
||||
int SearchLast(const ushort element) const;
|
||||
int SearchLinear(const ushort element) const;
|
||||
|
||||
protected:
|
||||
virtual void QuickSort(int beg,int end,const int mode=0);
|
||||
int QuickSearch(const ushort element) const;
|
||||
int MemMove(const int dest,const int src,int count);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayUShort::CArrayUShort(void)
|
||||
{
|
||||
//--- initialize protected data
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CArrayUShort::~CArrayUShort(void)
|
||||
{
|
||||
if(m_data_max!=0)
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving the memory within a single array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUShort::MemMove(const int dest,const int src,int count)
|
||||
{
|
||||
int i;
|
||||
//--- check parameters
|
||||
if(dest<0 || src<0 || count<0)
|
||||
return(-1);
|
||||
//--- check count
|
||||
if(src+count>m_data_total)
|
||||
count=m_data_total-src;
|
||||
if(count<0)
|
||||
return(-1);
|
||||
//--- no need to copy
|
||||
if(dest==src || count==0)
|
||||
return(dest);
|
||||
//--- check data total
|
||||
if(dest+count>m_data_total)
|
||||
{
|
||||
if(m_data_max<dest+count)
|
||||
return(-1);
|
||||
m_data_total=dest+count;
|
||||
}
|
||||
//--- copy
|
||||
if(dest<src)
|
||||
{
|
||||
//--- copy from left to right
|
||||
for(i=0;i<count;i++)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- copy from right to left
|
||||
for(i=count-1;i>=0;i--)
|
||||
m_data[dest+i]=m_data[src+i];
|
||||
}
|
||||
//--- successful
|
||||
return(dest);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request for more memory in an array. Checks if the requested |
|
||||
//| number of free elements already exists; allocates additional |
|
||||
//| memory with a given step |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::Reserve(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<=0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
if(Available()<size)
|
||||
{
|
||||
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
|
||||
if(new_size<0)
|
||||
//--- overflow occurred when calculating new_size
|
||||
return(false);
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
m_data_max=ArraySize(m_data);
|
||||
}
|
||||
//--- result
|
||||
return(Available()>=size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resizing (with removal of elements on the right) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::Resize(const int size)
|
||||
{
|
||||
int new_size;
|
||||
//--- check
|
||||
if(size<0)
|
||||
return(false);
|
||||
//--- resize array
|
||||
new_size=m_step_resize*(1+size/m_step_resize);
|
||||
if(m_data_max!=new_size)
|
||||
{
|
||||
if((m_data_max=ArrayResize(m_data,new_size))==-1)
|
||||
{
|
||||
m_data_max=ArraySize(m_data);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if(m_data_total>size)
|
||||
m_data_total=size;
|
||||
//--- result
|
||||
return(m_data_max==new_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Complete cleaning of the array with the release of memory |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::Shutdown(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_max==0)
|
||||
return(true);
|
||||
//--- clean
|
||||
if(ArrayResize(m_data,0)==-1)
|
||||
return(false);
|
||||
m_data_total=0;
|
||||
m_data_max=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::Add(const ushort element)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- add
|
||||
m_data[m_data_total++]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::AddArray(const ushort &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding an element to the end of the array from another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::AddArray(const CArrayUShort *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- add
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[m_data_total++]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting an element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::Insert(const ushort element,const int pos)
|
||||
{
|
||||
//--- check/reserve elements of array
|
||||
if(pos<0 || !Reserve(1))
|
||||
return(false);
|
||||
//--- insert
|
||||
m_data_total++;
|
||||
if(pos<m_data_total-1)
|
||||
{
|
||||
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
|
||||
return(false);
|
||||
m_data[pos]=element;
|
||||
}
|
||||
else
|
||||
m_data[m_data_total-1]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::InsertArray(const ushort &src[],const int pos)
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting elements in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::InsertArray(const CArrayUShort *src,const int pos)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.Total();
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(MemMove(num+pos,pos,m_data_total-pos)<0)
|
||||
return(false);
|
||||
for(int i=0;i<num;i++)
|
||||
m_data[i+pos]=src.m_data[i];
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::AssignArray(const ushort &src[])
|
||||
{
|
||||
int num=ArraySize(src);
|
||||
//--- check/reserve elements of array
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Assignment (copying) of another array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::AssignArray(const CArrayUShort *src)
|
||||
{
|
||||
int num;
|
||||
//--- check
|
||||
if(!CheckPointer(src))
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
num=src.m_data_total;
|
||||
Clear();
|
||||
if(m_data_max<num)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
Resize(num);
|
||||
//--- copy array
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=src.m_data[i];
|
||||
m_data_total++;
|
||||
}
|
||||
m_sort_mode=src.SortMode();
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Access to data in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
ushort CArrayUShort::At(const int index) const
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(SHORT_MAX);
|
||||
//--- result
|
||||
return(m_data[index]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updating element in the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::Update(const int index,const ushort element)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- update
|
||||
m_data[index]=element;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Moving element from the specified position |
|
||||
//| on the specified shift |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::Shift(const int index,const int shift)
|
||||
{
|
||||
ushort tmp_short;
|
||||
//--- check
|
||||
if(index<0 || index+shift<0 || index+shift>=m_data_total)
|
||||
return(false);
|
||||
if(shift==0)
|
||||
return(true);
|
||||
//--- move
|
||||
tmp_short=m_data[index];
|
||||
if(shift>0)
|
||||
{
|
||||
if(MemMove(index,index+1,shift)<0)
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(MemMove(index+shift+1,index+shift,-shift)<0)
|
||||
return(false);
|
||||
}
|
||||
m_data[index+shift]=tmp_short;
|
||||
m_sort_mode=-1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting element from the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::Delete(const int index)
|
||||
{
|
||||
//--- check
|
||||
if(index<0 || index>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
|
||||
return(false);
|
||||
m_data_total--;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deleting range of elements |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::DeleteRange(int from,int to)
|
||||
{
|
||||
//--- check
|
||||
if(from<0 || to<0)
|
||||
return(false);
|
||||
if(from>to || from>=m_data_total)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(to>=m_data_total-1)
|
||||
to=m_data_total-1;
|
||||
if(MemMove(from,to+1,m_data_total-to-1)<0)
|
||||
return(false);
|
||||
m_data_total-=to-from+1;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::CompareArray(const ushort &array[]) const
|
||||
{
|
||||
//--- compare
|
||||
if(m_data_total!=ArraySize(array))
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparison of two arrays |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::CompareArray(const CArrayUShort *array) const
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(array))
|
||||
return(false);
|
||||
//--- compare
|
||||
if(m_data_total!=array.m_data_total)
|
||||
return(false);
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]!=array.m_data[i])
|
||||
return(false);
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CArrayUShort::QuickSort(int beg,int end,const int mode)
|
||||
{
|
||||
int i,j;
|
||||
ushort p_short,t_short;
|
||||
//--- check
|
||||
if(beg<0 || end<0)
|
||||
return;
|
||||
//--- sort
|
||||
i=beg;
|
||||
j=end;
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
p_short=m_data[(beg+end)>>1];
|
||||
while(i<j)
|
||||
{
|
||||
while(m_data[i]<p_short)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
while(m_data[j]>p_short)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
t_short=m_data[i];
|
||||
m_data[i++]=m_data[j];
|
||||
m_data[j]=t_short;
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j);
|
||||
beg=i;
|
||||
j=end;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::InsertSort(const ushort element)
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(!IsSorted())
|
||||
return(false);
|
||||
//--- check/reserve elements of array
|
||||
if(!Reserve(1))
|
||||
return(false);
|
||||
//--- if the array is empty, add an element
|
||||
if(m_data_total==0)
|
||||
{
|
||||
m_data[m_data_total++]=element;
|
||||
return(true);
|
||||
}
|
||||
//--- find position and insert
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]>element)
|
||||
Insert(element,pos);
|
||||
else
|
||||
Insert(element,pos+1);
|
||||
//--- restore the sorting flag after Insert(...)
|
||||
m_sort_mode=0;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUShort::SearchLinear(const ushort element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(-1);
|
||||
//---
|
||||
for(int i=0;i<m_data_total;i++)
|
||||
if(m_data[i]==element)
|
||||
return(i);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Quick search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUShort::QuickSearch(const ushort element) const
|
||||
{
|
||||
int i,j,m=-1;
|
||||
ushort t_short;
|
||||
//--- search
|
||||
i=0;
|
||||
j=m_data_total-1;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_short=m_data[m];
|
||||
if(t_short==element)
|
||||
break;
|
||||
if(t_short>element)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
}
|
||||
//--- position
|
||||
return(m);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search of position of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUShort::Search(const ushort element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than |
|
||||
//| specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUShort::SearchGreat(const ushort element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]<=element)
|
||||
if(++pos==m_data_total)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than |
|
||||
//| specified in the sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUShort::SearchLess(const ushort element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
while(m_data[pos]>=element)
|
||||
if(pos--==0)
|
||||
return(-1);
|
||||
//--- position
|
||||
return(pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is greater than or |
|
||||
//| equal to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUShort::SearchGreatOrEqual(const ushort element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
|
||||
if(m_data[pos]>=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of the first element which is less than or equal |
|
||||
//| to the specified in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUShort::SearchLessOrEqual(const ushort element) const
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
for(int pos=QuickSearch(element);pos>=0;pos--)
|
||||
if(m_data[pos]<=element)
|
||||
return(pos);
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of first appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUShort::SearchFirst(const ushort element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(pos--==0)
|
||||
break;
|
||||
return(pos+1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find position of last appearance of element in a sorted array |
|
||||
//+------------------------------------------------------------------+
|
||||
int CArrayUShort::SearchLast(const ushort element) const
|
||||
{
|
||||
int pos;
|
||||
//--- check
|
||||
if(m_data_total==0 || !IsSorted())
|
||||
return(-1);
|
||||
//--- search
|
||||
pos=QuickSearch(element);
|
||||
if(m_data[pos]==element)
|
||||
{
|
||||
while(m_data[pos]==element)
|
||||
if(++pos==m_data_total)
|
||||
break;
|
||||
return(pos-1);
|
||||
}
|
||||
//--- not found
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing array to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::Save(const int file_handle)
|
||||
{
|
||||
int i=0;
|
||||
//--- check
|
||||
if(!CArray::Save(file_handle))
|
||||
return(false);
|
||||
//--- write array length
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write array
|
||||
for(i=0;i<m_data_total;i++)
|
||||
if(FileWriteInteger(file_handle,m_data[i],SHORT_VALUE)!=SHORT_VALUE)
|
||||
break;
|
||||
//--- result
|
||||
return(i==m_data_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading array from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CArrayUShort::Load(const int file_handle)
|
||||
{
|
||||
int i=0,num;
|
||||
//--- check
|
||||
if(!CArray::Load(file_handle))
|
||||
return(false);
|
||||
//--- read array length
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- read array
|
||||
Clear();
|
||||
if(num!=0)
|
||||
{
|
||||
if(!Reserve(num))
|
||||
return(false);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
m_data[i]=(ushort)FileReadInteger(file_handle,SHORT_VALUE);
|
||||
m_data_total++;
|
||||
if(FileIsEnding(file_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_sort_mode=-1;
|
||||
//--- result
|
||||
return(m_data_total==num);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,657 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| List.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CList. |
|
||||
//| Purpose: Provides the possibility of working with the list of |
|
||||
//| CObject instances and its dervivatives |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CList : public CObject
|
||||
{
|
||||
protected:
|
||||
CObject *m_first_node; // pointer to the first element of the list
|
||||
CObject *m_last_node; // pointer to the last element of the list
|
||||
CObject *m_curr_node; // pointer to the current element of the list
|
||||
int m_curr_idx; // index of the current list item
|
||||
int m_data_total; // number of elements
|
||||
bool m_free_mode; // flag of the necessity of "physical" deletion of object
|
||||
bool m_data_sort; // flag if the list is sorted or not
|
||||
int m_sort_mode; // mode of sorting of array
|
||||
|
||||
public:
|
||||
CList(void);
|
||||
~CList(void);
|
||||
//--- methods of access to protected data
|
||||
bool FreeMode(void) const { return(m_free_mode); }
|
||||
void FreeMode(bool mode) { m_free_mode=mode; }
|
||||
int Total(void) const { return(m_data_total); }
|
||||
bool IsSorted(void) const { return(m_data_sort); }
|
||||
int SortMode(void) const { return(m_sort_mode); }
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(0x7779); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
//--- method of creating an element of the list
|
||||
virtual CObject *CreateElement(void) { return(NULL); }
|
||||
//--- methods of filling the list
|
||||
int Add(CObject *new_node);
|
||||
int Insert(CObject *new_node,int index);
|
||||
//--- methods for navigating
|
||||
int IndexOf(CObject *node);
|
||||
CObject *GetNodeAtIndex(int index);
|
||||
CObject *GetFirstNode(void);
|
||||
CObject *GetPrevNode(void);
|
||||
CObject *GetCurrentNode(void);
|
||||
CObject *GetNextNode(void);
|
||||
CObject *GetLastNode(void);
|
||||
//--- methods for deleting
|
||||
CObject *DetachCurrent(void);
|
||||
bool DeleteCurrent(void);
|
||||
bool Delete(int index);
|
||||
void Clear(void);
|
||||
//--- method for comparing lists
|
||||
bool CompareList(CList *List);
|
||||
//--- methods for changing
|
||||
void Sort(int mode);
|
||||
bool MoveToIndex(int index);
|
||||
bool Exchange(CObject *node1,CObject *node2);
|
||||
//--- method for searching
|
||||
CObject *Search(CObject *element);
|
||||
protected:
|
||||
void QuickSort(int beg,int end,int mode);
|
||||
CObject *QuickSearch(CObject *element);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CList::CList(void) : m_first_node(NULL),
|
||||
m_last_node(NULL),
|
||||
m_curr_node(NULL),
|
||||
m_curr_idx(-1),
|
||||
m_data_total(0),
|
||||
m_free_mode(true),
|
||||
m_data_sort(false),
|
||||
m_sort_mode(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CList::~CList(void)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method QuickSort |
|
||||
//+------------------------------------------------------------------+
|
||||
void CList::QuickSort(int beg,int end,int mode)
|
||||
{
|
||||
int i,j,k;
|
||||
CObject *i_ptr,*j_ptr,*k_ptr;
|
||||
//---
|
||||
i_ptr=GetNodeAtIndex(i=beg);
|
||||
j_ptr=GetNodeAtIndex(j=end);
|
||||
while(i<end)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
k_ptr=GetNodeAtIndex(k=(beg+end)>>1);
|
||||
while(i<j)
|
||||
{
|
||||
while(i_ptr.Compare(k_ptr,mode)<0)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(i==m_data_total-1)
|
||||
break;
|
||||
i++;
|
||||
i_ptr=i_ptr.Next();
|
||||
}
|
||||
while(j_ptr.Compare(k_ptr,mode)>0)
|
||||
{
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
j--;
|
||||
j_ptr=j_ptr.Prev();
|
||||
}
|
||||
if(i<=j)
|
||||
{
|
||||
Exchange(i_ptr,j_ptr);
|
||||
i++;
|
||||
i_ptr=GetNodeAtIndex(i);
|
||||
//--- control the output of the array bounds
|
||||
if(j==0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
j--;
|
||||
j_ptr=GetNodeAtIndex(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(beg<j)
|
||||
QuickSort(beg,j,mode);
|
||||
beg=i;
|
||||
i_ptr=GetNodeAtIndex(i=beg);
|
||||
j_ptr=GetNodeAtIndex(j=end);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Index of element specified via the pointer to the list item |
|
||||
//+------------------------------------------------------------------+
|
||||
int CList::IndexOf(CObject *node)
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(node) || !CheckPointer(m_curr_node))
|
||||
return(-1);
|
||||
//--- searching index
|
||||
if(node==m_curr_node)
|
||||
return(m_curr_idx);
|
||||
if(GetFirstNode()==node)
|
||||
return(0);
|
||||
for(int i=1;i<m_data_total;i++)
|
||||
if(GetNextNode()==node)
|
||||
return(i);
|
||||
//---
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adding a new element to the end of the list |
|
||||
//+------------------------------------------------------------------+
|
||||
int CList::Add(CObject *new_node)
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(new_node))
|
||||
return(-1);
|
||||
//--- add
|
||||
if(m_first_node==NULL)
|
||||
m_first_node=new_node;
|
||||
else
|
||||
{
|
||||
m_last_node.Next(new_node);
|
||||
new_node.Prev(m_last_node);
|
||||
}
|
||||
m_curr_node=new_node;
|
||||
m_curr_idx=m_data_total;
|
||||
m_last_node=new_node;
|
||||
m_data_sort=false;
|
||||
//--- result
|
||||
return(m_data_total++);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserting a new element to the specified position in the list. |
|
||||
//| Inserting element to the current position of the list if index=-1|
|
||||
//+------------------------------------------------------------------+
|
||||
int CList::Insert(CObject *new_node,int index)
|
||||
{
|
||||
CObject *tmp_node;
|
||||
//--- check
|
||||
if(!CheckPointer(new_node))
|
||||
return(-1);
|
||||
if(index>m_data_total || index<0)
|
||||
return(-1);
|
||||
//--- adjust
|
||||
if(index==-1)
|
||||
{
|
||||
if(m_curr_node==NULL)
|
||||
return(Add(new_node));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(GetNodeAtIndex(index)==NULL)
|
||||
return(Add(new_node));
|
||||
}
|
||||
//--- no need to check m_curr_node
|
||||
tmp_node=m_curr_node.Prev();
|
||||
new_node.Prev(tmp_node);
|
||||
if(tmp_node!=NULL)
|
||||
tmp_node.Next(new_node);
|
||||
else
|
||||
m_first_node=new_node;
|
||||
new_node.Next(m_curr_node);
|
||||
m_curr_node.Prev(new_node);
|
||||
m_data_total++;
|
||||
m_data_sort=false;
|
||||
m_curr_node=new_node;
|
||||
//--- result
|
||||
return(index);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get a pointer to the position of element in the list |
|
||||
//+------------------------------------------------------------------+
|
||||
CObject *CList::GetNodeAtIndex(int index)
|
||||
{
|
||||
int i;
|
||||
bool revers;
|
||||
CObject *result;
|
||||
//--- check
|
||||
if(index>=m_data_total)
|
||||
return(NULL);
|
||||
if(index==m_curr_idx)
|
||||
return(m_curr_node);
|
||||
//--- optimize bust list
|
||||
if(index<m_curr_idx)
|
||||
{
|
||||
//--- index to the left of the current
|
||||
if(m_curr_idx-index<index)
|
||||
{
|
||||
//--- closer to the current index
|
||||
i=m_curr_idx;
|
||||
revers=true;
|
||||
result=m_curr_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- closer to the top of the list
|
||||
i=0;
|
||||
revers=false;
|
||||
result=m_first_node;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- index to the right of the current
|
||||
if(index-m_curr_idx<m_data_total-index-1)
|
||||
{
|
||||
//--- closer to the current index
|
||||
i=m_curr_idx;
|
||||
revers=false;
|
||||
result=m_curr_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- closer to the end of the list
|
||||
i=m_data_total-1;
|
||||
revers=true;
|
||||
result=m_last_node;
|
||||
}
|
||||
}
|
||||
if(!CheckPointer(result))
|
||||
return(NULL);
|
||||
//---
|
||||
if(revers)
|
||||
{
|
||||
//--- search from right to left
|
||||
for(;i>index;i--)
|
||||
{
|
||||
result=result.Prev();
|
||||
if(result==NULL)
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- search from left to right
|
||||
for(;i<index;i++)
|
||||
{
|
||||
result=result.Next();
|
||||
if(result==NULL)
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
m_curr_idx=index;
|
||||
//--- result
|
||||
return(m_curr_node=result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get a pointer to the first itme of the list |
|
||||
//+------------------------------------------------------------------+
|
||||
CObject *CList::GetFirstNode(void)
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(m_first_node))
|
||||
return(NULL);
|
||||
//--- save
|
||||
m_curr_idx=0;
|
||||
//--- result
|
||||
return(m_curr_node=m_first_node);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get a pointer to the previous itme of the list |
|
||||
//+------------------------------------------------------------------+
|
||||
CObject *CList::GetPrevNode(void)
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(m_curr_node) || m_curr_node.Prev()==NULL)
|
||||
return(NULL);
|
||||
//--- decrement
|
||||
m_curr_idx--;
|
||||
//--- result
|
||||
return(m_curr_node=m_curr_node.Prev());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get a pointer to the current item of the list |
|
||||
//+------------------------------------------------------------------+
|
||||
CObject *CList::GetCurrentNode(void)
|
||||
{
|
||||
return(m_curr_node);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get a pointer to the next item of the list |
|
||||
//+------------------------------------------------------------------+
|
||||
CObject *CList::GetNextNode(void)
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(m_curr_node) || m_curr_node.Next()==NULL)
|
||||
return(NULL);
|
||||
//--- increment
|
||||
m_curr_idx++;
|
||||
//--- result
|
||||
return(m_curr_node=m_curr_node.Next());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get a pointer to the last itme of the list |
|
||||
//+------------------------------------------------------------------+
|
||||
CObject *CList::GetLastNode(void)
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(m_last_node))
|
||||
return(NULL);
|
||||
//---
|
||||
m_curr_idx=m_data_total-1;
|
||||
//--- result
|
||||
return(m_curr_node=m_last_node);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Detach current item in the list |
|
||||
//+------------------------------------------------------------------+
|
||||
CObject *CList::DetachCurrent(void)
|
||||
{
|
||||
CObject *tmp_node,*result=NULL;
|
||||
//--- check
|
||||
if(!CheckPointer(m_curr_node))
|
||||
return(result);
|
||||
//--- "explode" list
|
||||
result=m_curr_node;
|
||||
m_curr_node=NULL;
|
||||
//--- if the deleted item was not the last one, pull up the "tail" of the list
|
||||
if((tmp_node=result.Next())!=NULL)
|
||||
{
|
||||
tmp_node.Prev(result.Prev());
|
||||
m_curr_node=tmp_node;
|
||||
}
|
||||
//--- if the deleted item was not the first one, pull up "head" list
|
||||
if((tmp_node=result.Prev())!=NULL)
|
||||
{
|
||||
tmp_node.Next(result.Next());
|
||||
//--- if "last_node" is removed, move the current pointer to the end of the list
|
||||
if(m_curr_node==NULL)
|
||||
{
|
||||
m_curr_node=tmp_node;
|
||||
m_curr_idx=m_data_total-2;
|
||||
}
|
||||
}
|
||||
m_data_total--;
|
||||
//--- if necessary, adjust the settings of the first and last elements
|
||||
if(m_first_node==result)
|
||||
m_first_node=result.Next();
|
||||
if(m_last_node==result)
|
||||
m_last_node=result.Prev();
|
||||
//--- complete the processing of element removed from the list
|
||||
//--- remove references to the list
|
||||
result.Prev(NULL);
|
||||
result.Next(NULL);
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete current item of list item |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CList::DeleteCurrent(void)
|
||||
{
|
||||
CObject *result=DetachCurrent();
|
||||
//--- check
|
||||
if(result==NULL)
|
||||
return(false);
|
||||
//--- complete the processing of element removed from the list
|
||||
if(m_free_mode)
|
||||
{
|
||||
//--- delete it "physically"
|
||||
if(CheckPointer(result)==POINTER_DYNAMIC)
|
||||
delete result;
|
||||
}
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete an item from a given position in the list |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CList::Delete(int index)
|
||||
{
|
||||
if(GetNodeAtIndex(index)==NULL)
|
||||
return(false);
|
||||
//--- result
|
||||
return(DeleteCurrent());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Remove all items from the list |
|
||||
//+------------------------------------------------------------------+
|
||||
void CList::Clear(void)
|
||||
{
|
||||
GetFirstNode();
|
||||
while(m_data_total!=0)
|
||||
if(!DeleteCurrent())
|
||||
break;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Equality comparing of two lists |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CList::CompareList(CList *List)
|
||||
{
|
||||
CObject *node,*lnode;
|
||||
//--- check
|
||||
if(!CheckPointer(List))
|
||||
return(false);
|
||||
if((node=GetFirstNode())==NULL)
|
||||
return(false);
|
||||
if((lnode=List.GetFirstNode())==NULL)
|
||||
return(false);
|
||||
//--- compare
|
||||
if(node.Compare(lnode)!=0)
|
||||
return(false);
|
||||
while((node=GetNextNode())!=NULL)
|
||||
{
|
||||
if((lnode=List.GetNextNode())==NULL)
|
||||
return(false);
|
||||
if(node.Compare(lnode)!=0)
|
||||
return(false);
|
||||
}
|
||||
//--- equal
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sorting an array in ascending order |
|
||||
//+------------------------------------------------------------------+
|
||||
void CList::Sort(int mode)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return;
|
||||
if(m_data_sort && m_sort_mode==mode)
|
||||
return;
|
||||
//--- sort
|
||||
QuickSort(0,m_data_total-1,mode);
|
||||
m_sort_mode=mode;
|
||||
m_data_sort=true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Move the current item of list to the specified position |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CList::MoveToIndex(int index)
|
||||
{
|
||||
//--- check
|
||||
if(index>=m_data_total || !CheckPointer(m_curr_node))
|
||||
return(false);
|
||||
//--- tune
|
||||
if(m_curr_idx==index)
|
||||
return(true);
|
||||
if(m_curr_idx<index)
|
||||
index--;
|
||||
//--- move
|
||||
Insert(DetachCurrent(),index);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Move an item of the list from the specified position to the |
|
||||
//| current one |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CList::Exchange(CObject *node1,CObject *node2)
|
||||
{
|
||||
CObject *tmp_node,*node;
|
||||
//--- check
|
||||
if(!CheckPointer(node1) || !CheckPointer(node2))
|
||||
return(false);
|
||||
//---
|
||||
tmp_node=node1.Prev();
|
||||
node1.Prev(node2.Prev());
|
||||
if(node1.Prev()!=NULL)
|
||||
{
|
||||
node=node1.Prev();
|
||||
node.Next(node1);
|
||||
}
|
||||
else
|
||||
m_first_node=node1;
|
||||
node2.Prev(tmp_node);
|
||||
if(node2.Prev()!=NULL)
|
||||
{
|
||||
node=node2.Prev();
|
||||
node.Next(node2);
|
||||
}
|
||||
else
|
||||
m_first_node=node2;
|
||||
tmp_node=node1.Next();
|
||||
node1.Next(node2.Next());
|
||||
if(node1.Next()!=NULL)
|
||||
{
|
||||
node=node1.Next();
|
||||
node.Prev(node1);
|
||||
}
|
||||
else
|
||||
m_last_node=node1;
|
||||
node2.Next(tmp_node);
|
||||
if(node2.Next()!=NULL)
|
||||
{
|
||||
node=node2.Next();
|
||||
node.Prev(node2);
|
||||
}
|
||||
else
|
||||
m_last_node=node2;
|
||||
//---
|
||||
m_curr_idx=0;
|
||||
m_curr_node=m_first_node;
|
||||
m_data_sort=false;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of an element in a sorted list |
|
||||
//+------------------------------------------------------------------+
|
||||
CObject *CList::QuickSearch(CObject *element)
|
||||
{
|
||||
int i,j,m;
|
||||
CObject *t_node=NULL;
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return(NULL);
|
||||
//--- check the pointer is not needed
|
||||
i=0;
|
||||
j=m_data_total;
|
||||
while(j>=i)
|
||||
{
|
||||
//--- ">>1" is quick division by 2
|
||||
m=(j+i)>>1;
|
||||
if(m<0 || m>=m_data_total)
|
||||
break;
|
||||
t_node=GetNodeAtIndex(m);
|
||||
if(t_node.Compare(element,m_sort_mode)==0)
|
||||
break;
|
||||
if(t_node.Compare(element,m_sort_mode)>0)
|
||||
j=m-1;
|
||||
else
|
||||
i=m+1;
|
||||
t_node=NULL;
|
||||
}
|
||||
//--- result
|
||||
return(t_node);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Search position of an element in a sorted list |
|
||||
//+------------------------------------------------------------------+
|
||||
CObject *CList::Search(CObject *element)
|
||||
{
|
||||
CObject *result;
|
||||
//--- check
|
||||
if(!CheckPointer(element) || !m_data_sort)
|
||||
return(NULL);
|
||||
//--- search
|
||||
result=QuickSearch(element);
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing list to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CList::Save(const int file_handle)
|
||||
{
|
||||
CObject *node;
|
||||
bool result=true;
|
||||
//--- check
|
||||
if(!CheckPointer(m_curr_node) || file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//--- write start marker - 0xFFFFFFFFFFFFFFFF
|
||||
if(FileWriteLong(file_handle,-1)!=sizeof(long))
|
||||
return(false);
|
||||
//--- write type
|
||||
if(FileWriteInteger(file_handle,Type(),INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- write list size
|
||||
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
//--- sequential scannning of elements in the list using the call of method Save()
|
||||
node=m_first_node;
|
||||
while(node!=NULL)
|
||||
{
|
||||
result&=node.Save(file_handle);
|
||||
node=node.Next();
|
||||
}
|
||||
//--- successful
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading list from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CList::Load(const int file_handle)
|
||||
{
|
||||
uint i,num;
|
||||
CObject *node;
|
||||
bool result=true;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//--- read and checking begin marker - 0xFFFFFFFFFFFFFFFF
|
||||
if(FileReadLong(file_handle)!=-1)
|
||||
return(false);
|
||||
//--- read and checking type
|
||||
if(FileReadInteger(file_handle,INT_VALUE)!=Type())
|
||||
return(false);
|
||||
//--- read list size
|
||||
num=FileReadInteger(file_handle,INT_VALUE);
|
||||
//--- sequential creation of list items using the call of method Load()
|
||||
Clear();
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
node=CreateElement();
|
||||
if(node==NULL)
|
||||
return(false);
|
||||
Add(node);
|
||||
result&=node.Load(file_handle);
|
||||
}
|
||||
//--- successful
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,415 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Tree.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "TreeNode.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CTree. |
|
||||
//| Purpose: Building a binary tree of instances of CTreeNode class |
|
||||
//| and its derviatives. |
|
||||
//| Derives from class CTreeNode. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CTree : public CTreeNode
|
||||
{
|
||||
protected:
|
||||
CTreeNode *m_root_node; // root node of the tree
|
||||
|
||||
public:
|
||||
CTree(void);
|
||||
~CTree(void);
|
||||
//--- methods of access to protected data
|
||||
CTreeNode *Root(void) const { return(m_root_node); }
|
||||
//--- method of identifying the object
|
||||
virtual int Type() const { return(0x9999); }
|
||||
//--- method of filling the tree
|
||||
CTreeNode *Insert(CTreeNode *new_node);
|
||||
//--- methods of removing tree nodes
|
||||
bool Detach(CTreeNode *node);
|
||||
bool Delete(CTreeNode *node);
|
||||
void Clear(void);
|
||||
//--- method of searching data in the tree
|
||||
CTreeNode *Find(const CTreeNode *node);
|
||||
//--- method to create elements in the tree
|
||||
virtual CTreeNode *CreateElement() { return(NULL); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
|
||||
protected:
|
||||
void Balance(CTreeNode *node);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CTree::CTree(void) : m_root_node(NULL)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CTree::~CTree(void)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method of adding a node to the tree |
|
||||
//+------------------------------------------------------------------+
|
||||
CTreeNode *CTree::Insert(CTreeNode *new_node)
|
||||
{
|
||||
CTreeNode *p_node;
|
||||
CTreeNode *result=m_root_node;
|
||||
//--- check
|
||||
if(!CheckPointer(new_node))
|
||||
return(NULL);
|
||||
//--- add
|
||||
if(result!=NULL)
|
||||
{
|
||||
p_node=NULL;
|
||||
result=m_root_node;
|
||||
while(result!=NULL && result.Compare(new_node)!=0)
|
||||
{
|
||||
p_node=result;
|
||||
result=result.GetNext(new_node);
|
||||
}
|
||||
if(result!=NULL)
|
||||
return(result);
|
||||
if(p_node.Compare(new_node)>0)
|
||||
p_node.Left(new_node);
|
||||
else
|
||||
p_node.Right(new_node);
|
||||
new_node.Parent(p_node);
|
||||
Balance(p_node);
|
||||
}
|
||||
else
|
||||
m_root_node=new_node;
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method of removing a node from the tree |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTree::Delete(CTreeNode *node)
|
||||
{
|
||||
//--- check
|
||||
if(!CheckPointer(node))
|
||||
return(false);
|
||||
//--- delete
|
||||
if(Detach(node) && CheckPointer(node)==POINTER_DYNAMIC)
|
||||
delete node;
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method of detaching node from the tree |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTree::Detach(CTreeNode *node)
|
||||
{
|
||||
CTreeNode *curr_node,*tmp_node;
|
||||
CTreeNode *nodeA,*nodeB;
|
||||
//--- check
|
||||
curr_node=node;
|
||||
if(!CheckPointer(curr_node))
|
||||
return(false);
|
||||
//--- detach
|
||||
if(curr_node.BalanceL()>curr_node.BalanceR())
|
||||
{
|
||||
nodeA=curr_node.Left();
|
||||
while(nodeA.Right()!=NULL)
|
||||
nodeA=nodeA.Right();
|
||||
nodeB=nodeA.Parent();
|
||||
if(nodeB!=curr_node)
|
||||
{
|
||||
nodeB.Right(nodeA.Left());
|
||||
tmp_node=nodeB.Right();
|
||||
if(tmp_node!=NULL)
|
||||
tmp_node.Parent(nodeB);
|
||||
tmp_node=curr_node.Left();
|
||||
nodeA.Left(tmp_node);
|
||||
tmp_node.Parent(nodeA);
|
||||
}
|
||||
//--- left link of curr_node is already installed as it should be
|
||||
curr_node.Left(NULL);
|
||||
//--- transferring the right link of curr_node to nodeA
|
||||
nodeA.Right(curr_node.Right());
|
||||
tmp_node=curr_node.Right();
|
||||
if(tmp_node!=NULL)
|
||||
tmp_node.Parent(nodeA);
|
||||
curr_node.Right(NULL);
|
||||
//--- transferring the root link of curr_node to nodeA
|
||||
tmp_node=curr_node.Parent();
|
||||
nodeA.Parent(tmp_node);
|
||||
if(tmp_node!=NULL)
|
||||
{
|
||||
if(tmp_node.Left()==curr_node)
|
||||
tmp_node.Left(nodeA);
|
||||
else
|
||||
tmp_node.Right(nodeA);
|
||||
}
|
||||
else
|
||||
{
|
||||
curr_node.Parent(NULL);
|
||||
m_root_node=nodeA;
|
||||
tmp_node=nodeA;
|
||||
}
|
||||
Balance(tmp_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(curr_node.BalanceR()>0)
|
||||
{
|
||||
nodeA=curr_node.Right();
|
||||
while(nodeA.Left()!=NULL)
|
||||
nodeA=nodeA.Left();
|
||||
nodeB=nodeA.Parent();
|
||||
if(nodeB!=curr_node)
|
||||
{
|
||||
nodeB.Left(nodeA.Right());
|
||||
tmp_node=nodeB.Left();
|
||||
if(tmp_node!=NULL)
|
||||
tmp_node.Parent(nodeB);
|
||||
tmp_node=curr_node.Right();
|
||||
nodeA.Right(tmp_node);
|
||||
tmp_node.Parent(nodeA);
|
||||
}
|
||||
//--- right link of curr_node is already installed as it should be
|
||||
curr_node.Right(NULL);
|
||||
//--- transferring the left link of curr_node to nodeA
|
||||
nodeA.Left(curr_node.Left());
|
||||
tmp_node=curr_node.Left();
|
||||
if(tmp_node!=NULL)
|
||||
tmp_node.Parent(nodeA);
|
||||
curr_node.Left(NULL);
|
||||
//--- transferring the root link of curr_node to nodeA
|
||||
tmp_node=curr_node.Parent();
|
||||
nodeA.Parent(tmp_node);
|
||||
if(tmp_node!=NULL)
|
||||
{
|
||||
if(tmp_node.Left()==curr_node)
|
||||
tmp_node.Left(nodeA);
|
||||
else
|
||||
tmp_node.Right(nodeA);
|
||||
}
|
||||
else
|
||||
{
|
||||
curr_node.Parent(NULL);
|
||||
m_root_node=nodeA;
|
||||
tmp_node=nodeA;
|
||||
}
|
||||
Balance(tmp_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- node list
|
||||
if(curr_node.Parent()==NULL)
|
||||
m_root_node=NULL;
|
||||
else
|
||||
{
|
||||
tmp_node=curr_node.Parent();
|
||||
if(tmp_node.Left()==curr_node)
|
||||
tmp_node.Left(NULL);
|
||||
else
|
||||
tmp_node.Right(NULL);
|
||||
curr_node.Parent(NULL);
|
||||
}
|
||||
Balance(curr_node.Parent());
|
||||
}
|
||||
}
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method of cleaning the tree |
|
||||
//+------------------------------------------------------------------+
|
||||
void CTree::Clear(void)
|
||||
{
|
||||
if(CheckPointer(m_root_node)==POINTER_DYNAMIC)
|
||||
delete m_root_node;
|
||||
m_root_node=NULL;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method of searching for a node in the tree |
|
||||
//+------------------------------------------------------------------+
|
||||
CTreeNode *CTree::Find(const CTreeNode *node)
|
||||
{
|
||||
CTreeNode *result=m_root_node;
|
||||
//--- find
|
||||
while(result!=NULL && result.Compare(node)!=0)
|
||||
result=result.GetNext(node);
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method of balancing the tree |
|
||||
//+------------------------------------------------------------------+
|
||||
void CTree::Balance(CTreeNode *node)
|
||||
{
|
||||
CTreeNode *nodeA,*nodeB,*nodeC,*curr_node,*tmp_node;
|
||||
//---
|
||||
curr_node=node;
|
||||
while(curr_node!=NULL)
|
||||
{
|
||||
curr_node.RefreshBalance();
|
||||
if(MathAbs(curr_node.BalanceL()-curr_node.BalanceR())<=1)
|
||||
curr_node=curr_node.Parent();
|
||||
else
|
||||
{
|
||||
if(curr_node.BalanceR()>curr_node.BalanceL())
|
||||
{
|
||||
//--- rotation to the right
|
||||
tmp_node=curr_node.Right();
|
||||
if(tmp_node.BalanceL()>tmp_node.BalanceR())
|
||||
{
|
||||
//--- great rotation to the right
|
||||
nodeA=curr_node;
|
||||
nodeB=nodeA.Right();
|
||||
nodeC=nodeB.Left();
|
||||
nodeC.Parent(nodeA.Parent());
|
||||
tmp_node=nodeC.Parent();
|
||||
if(tmp_node!=NULL)
|
||||
{
|
||||
if(tmp_node.Right()==nodeA)
|
||||
tmp_node.Right(nodeC);
|
||||
else
|
||||
tmp_node.Left(nodeC);
|
||||
}
|
||||
else
|
||||
m_root_node=nodeC;
|
||||
nodeA.Parent(nodeC);
|
||||
nodeB.Parent(nodeC);
|
||||
nodeA.Right(nodeC.Left());
|
||||
tmp_node=nodeA.Right();
|
||||
if(tmp_node!=NULL)
|
||||
tmp_node.Parent(nodeA);
|
||||
nodeC.Left(nodeA);
|
||||
nodeB.Left(nodeC.Right());
|
||||
tmp_node=nodeB.Left();
|
||||
if(tmp_node!=NULL)
|
||||
tmp_node.Parent(nodeB);
|
||||
nodeC.Right(nodeB);
|
||||
if(m_root_node==nodeA)
|
||||
m_root_node=nodeC;
|
||||
curr_node=nodeC.Parent();
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- slight rotation to the right
|
||||
nodeA=curr_node;
|
||||
nodeB=nodeA.Right();
|
||||
nodeB.Parent(nodeA.Parent());
|
||||
tmp_node=nodeB.Parent();
|
||||
if(tmp_node!=NULL)
|
||||
{
|
||||
if(tmp_node.Right()==nodeA)
|
||||
tmp_node.Right(nodeB);
|
||||
else
|
||||
tmp_node.Left(nodeB);
|
||||
}
|
||||
else
|
||||
m_root_node=nodeB;
|
||||
nodeA.Parent(nodeB);
|
||||
nodeA.Right(nodeB.Left());
|
||||
tmp_node=nodeA.Right();
|
||||
if(tmp_node!=NULL)
|
||||
tmp_node.Parent(nodeA);
|
||||
nodeB.Left(nodeA);
|
||||
if(m_root_node==nodeA)
|
||||
m_root_node=nodeB;
|
||||
curr_node=nodeB.Parent();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- rotation to the left
|
||||
tmp_node=curr_node.Left();
|
||||
if(tmp_node.BalanceR()>tmp_node.BalanceL())
|
||||
{
|
||||
//--- great rotation to the left
|
||||
nodeA=curr_node;
|
||||
nodeB=nodeA.Left();
|
||||
nodeC=nodeB.Right();
|
||||
nodeC.Parent(nodeA.Parent());
|
||||
tmp_node=nodeC.Parent();
|
||||
if(tmp_node!=NULL)
|
||||
{
|
||||
if(tmp_node.Right()==nodeA)
|
||||
tmp_node.Right(nodeC);
|
||||
else
|
||||
tmp_node.Left(nodeC);
|
||||
}
|
||||
else
|
||||
m_root_node=nodeC;
|
||||
nodeA.Parent(nodeC);
|
||||
nodeB.Parent(nodeC);
|
||||
nodeA.Left(nodeC.Right());
|
||||
tmp_node=nodeA.Left();
|
||||
if(tmp_node!=NULL)
|
||||
tmp_node.Parent(nodeA);
|
||||
nodeC.Right(nodeA);
|
||||
nodeB.Right(nodeC.Left());
|
||||
tmp_node=nodeB.Right();
|
||||
if(tmp_node!=NULL)
|
||||
tmp_node.Parent(nodeB);
|
||||
nodeC.Left(nodeB);
|
||||
if(m_root_node==nodeA)
|
||||
m_root_node=nodeC;
|
||||
curr_node=nodeC.Parent();
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- small rotation to the left
|
||||
nodeA=curr_node;
|
||||
nodeB=nodeA.Left();
|
||||
nodeB.Parent(nodeA.Parent());
|
||||
tmp_node=nodeB.Parent();
|
||||
if(tmp_node!=NULL)
|
||||
{
|
||||
if(tmp_node.Right()==nodeA)
|
||||
tmp_node.Right(nodeB);
|
||||
else
|
||||
tmp_node.Left(nodeB);
|
||||
}
|
||||
else
|
||||
m_root_node=nodeB;
|
||||
nodeA.Parent(nodeB);
|
||||
nodeA.Left(nodeB.Right());
|
||||
tmp_node=nodeA.Left();
|
||||
if(tmp_node!=NULL)
|
||||
tmp_node.Parent(nodeA);
|
||||
nodeB.Right(nodeA);
|
||||
if(m_root_node==nodeA)
|
||||
m_root_node=nodeB;
|
||||
curr_node=nodeB.Parent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing tree to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTree::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
if(m_root_node==NULL)
|
||||
return(true);
|
||||
//--- result
|
||||
return(m_root_node.SaveNode(file_handle));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading tree from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTree::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//--- create root node only
|
||||
Clear();
|
||||
Insert(CreateElement());
|
||||
//--- result
|
||||
return(m_root_node.LoadNode(file_handle,m_root_node));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,174 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| TreeNode.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Object.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CTreeNode. |
|
||||
//| Purpose: Base class of node of binary tree CTree. |
|
||||
//| Derives from class CObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CTreeNode : public CObject
|
||||
{
|
||||
private:
|
||||
CTreeNode *m_p_node; // link to node up
|
||||
CTreeNode *m_l_node; // link to node left
|
||||
CTreeNode *m_r_node; // link to node right
|
||||
//--- variables
|
||||
int m_balance; // balance of node
|
||||
int m_l_balance; // balance of the left branch
|
||||
int m_r_balance; // balance of the right branch
|
||||
|
||||
public:
|
||||
CTreeNode(void);
|
||||
~CTreeNode(void);
|
||||
//--- methods of access to protected data
|
||||
CTreeNode* Parent(void) const { return(m_p_node); }
|
||||
void Parent(CTreeNode *node) { m_p_node=node; }
|
||||
CTreeNode* Left(void) const { return(m_l_node); }
|
||||
void Left(CTreeNode *node) { m_l_node=node; }
|
||||
CTreeNode* Right(void) const { return(m_r_node); }
|
||||
void Right(CTreeNode *node) { m_r_node=node; }
|
||||
int Balance(void) const { return(m_balance); }
|
||||
int BalanceL(void) const { return(m_l_balance); }
|
||||
int BalanceR(void) const { return(m_r_balance); }
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(0x8888); }
|
||||
//--- methods for controlling
|
||||
int RefreshBalance(void);
|
||||
CTreeNode *GetNext(const CTreeNode *node);
|
||||
//--- methods for working with files
|
||||
bool SaveNode(const int file_handle);
|
||||
bool LoadNode(const int file_handle,CTreeNode *main);
|
||||
|
||||
protected:
|
||||
//--- method for creating an instance of class
|
||||
virtual CTreeNode *CreateSample(void) { return(NULL); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CTreeNode::CTreeNode(void) : m_p_node(NULL),
|
||||
m_l_node(NULL),
|
||||
m_r_node(NULL),
|
||||
m_balance(0),
|
||||
m_l_balance(0),
|
||||
m_r_balance(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CTreeNode::~CTreeNode(void)
|
||||
{
|
||||
//--- delete nodes of the next level
|
||||
if(m_l_node!=NULL)
|
||||
delete m_l_node;
|
||||
if(m_r_node!=NULL)
|
||||
delete m_r_node;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Calculating the balance of the node |
|
||||
//+------------------------------------------------------------------+
|
||||
int CTreeNode::RefreshBalance(void)
|
||||
{
|
||||
//--- calculate the balance of the left branch
|
||||
if(m_l_node==NULL)
|
||||
m_l_balance=0;
|
||||
else
|
||||
m_l_balance=m_l_node.RefreshBalance();
|
||||
//--- calculate the balance of the right branch
|
||||
if(m_r_node==NULL)
|
||||
m_r_balance=0;
|
||||
else
|
||||
m_r_balance=m_r_node.RefreshBalance();
|
||||
//--- calculate the balance of the node
|
||||
if(m_r_balance>m_l_balance)
|
||||
m_balance=m_r_balance+1;
|
||||
else
|
||||
m_balance=m_l_balance+1;
|
||||
//--- result
|
||||
return(m_balance);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Selecting next node |
|
||||
//+------------------------------------------------------------------+
|
||||
CTreeNode *CTreeNode::GetNext(const CTreeNode *node)
|
||||
{
|
||||
if(Compare(node)>0)
|
||||
return(m_l_node);
|
||||
//--- result
|
||||
return(m_r_node);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing node data to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTreeNode::SaveNode(const int file_handle)
|
||||
{
|
||||
bool result=true;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//--- write left node (if it is available)
|
||||
if(m_l_node!=NULL)
|
||||
{
|
||||
FileWriteInteger(file_handle,'L',SHORT_VALUE);
|
||||
result&=m_l_node.SaveNode(file_handle);
|
||||
}
|
||||
else
|
||||
FileWriteInteger(file_handle,'X',SHORT_VALUE);
|
||||
//--- write data of current node
|
||||
result&=Save(file_handle);
|
||||
//--- write right node (if it is available)
|
||||
if(m_r_node!=NULL)
|
||||
{
|
||||
FileWriteInteger(file_handle,'R',SHORT_VALUE);
|
||||
result&=m_r_node.SaveNode(file_handle);
|
||||
}
|
||||
else
|
||||
FileWriteInteger(file_handle,'X',SHORT_VALUE);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading node data from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CTreeNode::LoadNode(const int file_handle,CTreeNode *main)
|
||||
{
|
||||
bool result=true;
|
||||
short s_val;
|
||||
CTreeNode *node;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//--- read directions
|
||||
s_val=(short)FileReadInteger(file_handle,SHORT_VALUE);
|
||||
if(s_val=='L')
|
||||
{
|
||||
//--- read left node (if there is data)
|
||||
node=CreateSample();
|
||||
if(node==NULL)
|
||||
return(false);
|
||||
m_l_node=node;
|
||||
node.Parent(main);
|
||||
result&=node.LoadNode(file_handle,node);
|
||||
}
|
||||
//--- read data of current node
|
||||
result&=Load(file_handle);
|
||||
//--- read directions
|
||||
s_val=(short)FileReadInteger(file_handle,SHORT_VALUE);
|
||||
if(s_val=='R')
|
||||
{
|
||||
//--- read right node (if there is data)
|
||||
node=CreateSample();
|
||||
if(node==NULL)
|
||||
return(false);
|
||||
m_r_node=node;
|
||||
node.Parent(main);
|
||||
result&=node.LoadNode(file_handle,node);
|
||||
}
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,347 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HistogramChart.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartCanvas.mqh"
|
||||
#include <Arrays\ArrayObj.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CHistogramChart |
|
||||
//| Usage: generates histogram chart |
|
||||
//+------------------------------------------------------------------+
|
||||
class CHistogramChart : public CChartCanvas
|
||||
{
|
||||
private:
|
||||
//--- colors
|
||||
uint m_fill_brush[];
|
||||
//--- adjusted parameters
|
||||
bool m_gradient;
|
||||
uint m_bar_gap;
|
||||
uint m_bar_min_size;
|
||||
uint m_bar_border;
|
||||
//--- data
|
||||
CArrayObj *m_values;
|
||||
|
||||
public:
|
||||
CHistogramChart(void);
|
||||
~CHistogramChart(void);
|
||||
//--- create
|
||||
virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_ARGB_NORMALIZE);
|
||||
//--- adjusted parameters
|
||||
void Gradient(const bool flag=true) { m_gradient=flag; }
|
||||
void BarGap(const uint value) { m_bar_gap=value; }
|
||||
void BarMinSize(const uint value) { m_bar_min_size=value; }
|
||||
void BarBorder(const uint value) { m_bar_border=value; }
|
||||
//--- data
|
||||
bool SeriesAdd(const double &value[],const string descr="",const uint clr=0);
|
||||
bool SeriesInsert(const uint pos,const double &value[],const string descr="",const uint clr=0);
|
||||
bool SeriesUpdate(const uint pos,const double &value[],const string descr=NULL,const uint clr=0);
|
||||
bool SeriesDelete(const uint pos);
|
||||
bool ValueUpdate(const uint series,const uint pos,double value);
|
||||
|
||||
protected:
|
||||
virtual void DrawData(const uint idx);
|
||||
void DrawBar(const int x,const int y,const int w,const int h,const uint clr);
|
||||
void GradientBrush(const int size,const uint fill_clr);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CHistogramChart::CHistogramChart(void) : m_gradient(true),
|
||||
m_bar_gap(3),
|
||||
m_bar_min_size(5),
|
||||
m_bar_border(0)
|
||||
{
|
||||
ShowFlags(FLAG_SHOW_LEGEND|FLAGS_SHOW_SCALES|FLAG_SHOW_GRID);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CHistogramChart::~CHistogramChart(void)
|
||||
{
|
||||
if(ArraySize(m_fill_brush)!=0)
|
||||
ArrayFree(m_fill_brush);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create dynamic resource |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
|
||||
{
|
||||
//--- create object to store data
|
||||
if((m_values=new CArrayObj)==NULL)
|
||||
return(false);
|
||||
//--- pass responsibility for its destruction to the parent class
|
||||
m_data=m_values;
|
||||
//--- call method of parent class
|
||||
if(!CChartCanvas::Create(name,width,height,clrfmt))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::SeriesAdd(const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==m_max_data)
|
||||
return(false);
|
||||
//--- add
|
||||
CArrayDouble *arr=new CArrayDouble;
|
||||
if(!m_values.Add(arr))
|
||||
return(false);
|
||||
if(!arr.AssignArray(value))
|
||||
return(false);
|
||||
if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr))
|
||||
return(false);
|
||||
if(!m_descriptors.Add(descr))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserts data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::SeriesInsert(const uint pos,const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==m_max_data)
|
||||
return(false);
|
||||
if(pos>=m_data_total)
|
||||
return(false);
|
||||
//--- insert
|
||||
CArrayDouble *arr=new CArrayDouble;
|
||||
if(!m_values.Insert(arr,pos))
|
||||
return(false);
|
||||
if(!arr.AssignArray(value))
|
||||
return(false);
|
||||
if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos))
|
||||
return(false);
|
||||
if(!m_descriptors.Insert(descr,pos))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updates data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::SeriesUpdate(const uint pos,const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(pos>=m_data_total)
|
||||
return(false);
|
||||
CArrayDouble *data=m_values.At(pos);
|
||||
if(data==NULL)
|
||||
return(false);
|
||||
//--- update
|
||||
if(!data.AssignArray(value))
|
||||
return(false);
|
||||
if(clr!=0 && !m_colors.Update(pos,clr))
|
||||
return(false);
|
||||
if(descr!=NULL && !m_descriptors.Update(pos,descr))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deletes data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::SeriesDelete(const uint pos)
|
||||
{
|
||||
//--- check
|
||||
if(pos>=m_data_total && m_data_total!=0)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(!m_values.Delete(pos))
|
||||
return(false);
|
||||
m_data_total--;
|
||||
if(!m_colors.Delete(pos))
|
||||
return(false);
|
||||
if(!m_descriptors.Delete(pos))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updates element in data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::ValueUpdate(const uint series,const uint pos,double value)
|
||||
{
|
||||
CArrayDouble *data=m_values.At(series);
|
||||
//--- check
|
||||
if(data==NULL)
|
||||
return(false);
|
||||
//--- update
|
||||
if(!data.Update(pos,value))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws histogram |
|
||||
//+------------------------------------------------------------------+
|
||||
void CHistogramChart::DrawData(const uint idx)
|
||||
{
|
||||
double value=0.0;
|
||||
//--- check
|
||||
CArrayDouble *data=m_values.At(idx);
|
||||
if(data==NULL)
|
||||
return;
|
||||
int total=data.Total();
|
||||
if(total==0 || (int)idx>=total)
|
||||
return;
|
||||
//--- calculate
|
||||
int x1=m_data_area.left;
|
||||
int x2=m_data_area.right;
|
||||
int dx=(x2-x1)/total;
|
||||
uint clr=m_colors[idx];
|
||||
uint w=dx/m_data_total;
|
||||
if(w<m_bar_min_size)
|
||||
w=m_bar_min_size;
|
||||
int x=x1+(int)(m_bar_gap+w*idx);
|
||||
//--- set font
|
||||
string fontname;
|
||||
int fontsize=0;
|
||||
uint fontflags=0;
|
||||
uint fontangle=0;
|
||||
if(IS_SHOW_VALUE)
|
||||
{
|
||||
FontGet(fontname,fontsize,fontflags,fontangle);
|
||||
FontSet(fontname,-10*(w-3),fontflags,900);
|
||||
}
|
||||
//--- prepare gradient fill
|
||||
GradientBrush(w,clr);
|
||||
//--- draw
|
||||
for(int i=0;i<total;i++,x+=dx)
|
||||
{
|
||||
int y,h = 0;
|
||||
double val=data[i];
|
||||
if(val==EMPTY_VALUE)
|
||||
continue;
|
||||
if(m_accumulative)
|
||||
value+=val;
|
||||
else
|
||||
value=val;
|
||||
// int val=(int)(value*m_scale_y);
|
||||
if(value>0)
|
||||
{
|
||||
y=(m_y_0+(int)(value*m_scale_y));
|
||||
h=m_y_0-y;
|
||||
}
|
||||
else
|
||||
{
|
||||
y=m_y_0;
|
||||
h=(int)(value*m_scale_y);
|
||||
}
|
||||
DrawBar(x,y,w,h,clr);
|
||||
//--- draw text of value
|
||||
if(IS_SHOW_VALUE)
|
||||
{
|
||||
string text =DoubleToString(value,2);
|
||||
int width=(int)(TextWidth(text)+w);
|
||||
if(value>0)
|
||||
{
|
||||
if(width>y-m_y_max)
|
||||
TextOut(x+w/2,y+w,text,m_color_text,TA_RIGHT|TA_VCENTER);
|
||||
else
|
||||
TextOut(x+w/2,y-w,text,m_color_text,TA_LEFT|TA_VCENTER);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(width>m_y_min-y-h)
|
||||
TextOut(x+w/2,y+h-w,text,m_color_text,TA_LEFT|TA_VCENTER);
|
||||
else
|
||||
TextOut(x+w/2,y+h+w,text,m_color_text,TA_RIGHT|TA_VCENTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(IS_SHOW_VALUE)
|
||||
FontSet(fontname,fontsize,fontflags,fontangle);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws bar |
|
||||
//+------------------------------------------------------------------+
|
||||
void CHistogramChart::DrawBar(const int x,const int y,const int w,const int h,const uint clr)
|
||||
{
|
||||
//--- draw bar
|
||||
if(!m_gradient || ArraySize(m_fill_brush)<w)
|
||||
FillRectangle(x+1,y+1,w-x-2,h-y-2,clr);
|
||||
else
|
||||
{
|
||||
for(int i=1;i<h;i++)
|
||||
ArrayCopy(m_pixels,m_fill_brush,(y+i)*m_width+x+1,0,w);
|
||||
}
|
||||
//--- draw bar border
|
||||
if(m_bar_border!=0)
|
||||
Rectangle(x,y,x+w-1,y+h-1,m_color_border);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Creates brush for gradient fill |
|
||||
//+------------------------------------------------------------------+
|
||||
void CHistogramChart::GradientBrush(const int size,const uint fill_clr)
|
||||
{
|
||||
//--- to prepare gradient fill, we will use Bresenham's circle algorithm
|
||||
//--- X coordinate - size of the fill,
|
||||
//--- Y coordinate - color brightness
|
||||
if(m_gradient)
|
||||
{
|
||||
//--- adjust gradient radius if necessary
|
||||
int r=size;
|
||||
//--- check
|
||||
if(r<1)
|
||||
return;
|
||||
if(r!=ArrayResize(m_fill_brush,r))
|
||||
return;
|
||||
//--- initialize brush
|
||||
ArrayInitialize(m_fill_brush,m_color_background);
|
||||
//--- variables
|
||||
int f =1-r;
|
||||
int dd_x=1;
|
||||
int dd_y=-2*r;
|
||||
int dx =0;
|
||||
int dy =r;
|
||||
int i1,i2;
|
||||
uint clr,dclr;
|
||||
//---
|
||||
i1=i2=r>>1;
|
||||
if((r&1)==0)
|
||||
i1--;
|
||||
//--- calculate
|
||||
while(dy>=dx)
|
||||
{
|
||||
clr=fill_clr;
|
||||
dclr=GETRGB(XRGB((r-dy)*GETRGBR(clr)/r,(r-dy)*GETRGBG(clr)/r,(r-dy)*GETRGBB(clr)/r));
|
||||
clr-=dclr;
|
||||
m_fill_brush[i1]=clr;
|
||||
m_fill_brush[i2]=clr;
|
||||
//---
|
||||
if(f>=0)
|
||||
{
|
||||
dy--;
|
||||
dd_y+=2;
|
||||
f+=dd_y;
|
||||
}
|
||||
dx++;
|
||||
if(--i1<0)
|
||||
break;
|
||||
i2++;
|
||||
dd_x+=2;
|
||||
f+=dd_x;
|
||||
}
|
||||
}
|
||||
else
|
||||
ArrayFree(m_fill_brush);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,383 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| LineChart.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartCanvas.mqh"
|
||||
#include <Arrays\ArrayObj.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CLineChart |
|
||||
//| Usage: generates line chart |
|
||||
//+------------------------------------------------------------------+
|
||||
class CLineChart : public CChartCanvas
|
||||
{
|
||||
private:
|
||||
//--- data
|
||||
CArrayObj* m_values;
|
||||
//--- adjusted parameters
|
||||
bool m_filled;
|
||||
|
||||
public:
|
||||
CLineChart(void);
|
||||
~CLineChart(void);
|
||||
//--- create
|
||||
virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_ARGB_NORMALIZE);
|
||||
//--- adjusted parameters
|
||||
void Filled(const bool flag=true) { m_filled=flag; }
|
||||
//--- set up
|
||||
bool SeriesAdd(const double &value[],const string descr="",const uint clr=0);
|
||||
bool SeriesInsert(const uint pos,const double &value[],const string descr="",const uint clr=0);
|
||||
bool SeriesUpdate(const uint pos,const double &value[],const string descr=NULL,const uint clr=0);
|
||||
bool SeriesDelete(const uint pos);
|
||||
bool ValueUpdate(const uint series,const uint pos,double value);
|
||||
|
||||
protected:
|
||||
virtual void DrawChart(void);
|
||||
virtual void DrawData(const uint index=0);
|
||||
|
||||
private:
|
||||
double CalcArea(const uint index);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CLineChart::CLineChart(void) : m_filled(false)
|
||||
{
|
||||
ShowFlags(FLAG_SHOW_LEGEND|FLAGS_SHOW_SCALES|FLAG_SHOW_GRID);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CLineChart::~CLineChart(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create dynamic resource |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
|
||||
{
|
||||
//--- create object to store data
|
||||
if((m_values=new CArrayObj)==NULL)
|
||||
return(false);
|
||||
//--- pass responsibility for its destruction to the parent class
|
||||
m_data=m_values;
|
||||
//--- call method of parent class
|
||||
if(!CChartCanvas::Create(name,width,height,clrfmt))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::SeriesAdd(const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==m_max_data)
|
||||
return(false);
|
||||
//--- add
|
||||
CArrayDouble *arr=new CArrayDouble;
|
||||
if(!m_values.Add(arr))
|
||||
return(false);
|
||||
if(!arr.AssignArray(value))
|
||||
return(false);
|
||||
if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr))
|
||||
return(false);
|
||||
if(!m_descriptors.Add(descr))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserts data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::SeriesInsert(const uint pos,const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==m_max_data)
|
||||
return(false);
|
||||
if(pos>=m_data_total)
|
||||
return(false);
|
||||
//--- insert
|
||||
CArrayDouble *arr=new CArrayDouble;
|
||||
if(!m_values.Insert(arr,pos))
|
||||
return(false);
|
||||
if(!arr.AssignArray(value))
|
||||
return(false);
|
||||
if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos))
|
||||
return(false);
|
||||
if(!m_descriptors.Insert(descr,pos))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updates data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::SeriesUpdate(const uint pos,const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(pos>=m_data_total)
|
||||
return(false);
|
||||
CArrayDouble *data=m_values.At(pos);
|
||||
if(data==NULL)
|
||||
return(false);
|
||||
//--- update
|
||||
if(!data.AssignArray(value))
|
||||
return(false);
|
||||
if(clr!=0 && !m_colors.Update(pos,clr))
|
||||
return(false);
|
||||
if(descr!=NULL && !m_descriptors.Update(pos,descr))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deletes data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::SeriesDelete(const uint pos)
|
||||
{
|
||||
//--- check
|
||||
if(pos>=m_data_total && m_data_total!=0)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(!m_values.Delete(pos))
|
||||
return(false);
|
||||
m_data_total--;
|
||||
if(!m_colors.Delete(pos))
|
||||
return(false);
|
||||
if(!m_descriptors.Delete(pos))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updates element in data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::ValueUpdate(const uint series,const uint pos,double value)
|
||||
{
|
||||
CArrayDouble *data=m_values.At(series);
|
||||
//--- check
|
||||
if(data==NULL)
|
||||
return(false);
|
||||
//--- update
|
||||
if(!data.Update(pos,value))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Redraws data |
|
||||
//+------------------------------------------------------------------+
|
||||
void CLineChart::DrawChart(void)
|
||||
{
|
||||
if(m_filled)
|
||||
{
|
||||
//--- calculate areas of filling
|
||||
double s[];
|
||||
ArrayResize(s,m_data_total);
|
||||
ArrayInitialize(s,0);
|
||||
for(uint i=0;i<m_data_total;i++)
|
||||
{
|
||||
CArrayDouble *data=m_values.At(i);
|
||||
if(data==NULL)
|
||||
continue;
|
||||
int total=data.Total();
|
||||
if(total<=1)
|
||||
continue;
|
||||
s[i]=CalcArea(i);
|
||||
}
|
||||
int index=ArrayMaximum(s);
|
||||
while(index!=-1 && s[index]!=0.0)
|
||||
{
|
||||
//--- draw in area descending order
|
||||
DrawData(index);
|
||||
s[index]=0.0;
|
||||
index=ArrayMaximum(s);
|
||||
}
|
||||
}
|
||||
else
|
||||
for(uint i=0;i<m_data_total;i++)
|
||||
DrawData(i);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws lines |
|
||||
//+------------------------------------------------------------------+
|
||||
void CLineChart::DrawData(const uint index)
|
||||
{
|
||||
double value=0.0;
|
||||
//--- check
|
||||
CArrayDouble *data=m_values.At(index);
|
||||
if(data==NULL)
|
||||
return;
|
||||
int total=data.Total();
|
||||
if(total<=1)
|
||||
return;
|
||||
//--- calculate
|
||||
int dx=m_data_area.Width()/(total-1);
|
||||
int x=m_data_area.left+1;
|
||||
int y1=0;
|
||||
int y2=(int)(m_y_min+(data[0]-m_v_scale_min)*m_scale_y);
|
||||
//--- draw
|
||||
for(int i=1;i<total;i++,x+=dx)
|
||||
{
|
||||
y1=y2;
|
||||
double val=data[i];
|
||||
if(val==EMPTY_VALUE)
|
||||
continue;
|
||||
if(m_accumulative)
|
||||
value+=val;
|
||||
else
|
||||
value=val;
|
||||
y2=(int)(m_y_min+(value-m_v_scale_min)*m_scale_y);
|
||||
if(m_filled)
|
||||
{
|
||||
if((y1>m_y_0 && y2<m_y_0) || (y1<m_y_0 && y2>m_y_0))
|
||||
{
|
||||
//--- draw two triangles
|
||||
int x3;
|
||||
if(y1>y2)
|
||||
{
|
||||
x3=x+dx*(y1-m_y_0)/(y1-y2);
|
||||
FillTriangle(x,y1,x3,m_y_0,x,m_y_0,(uint)m_colors[index]);
|
||||
FillTriangle(x+dx,y2,x3,m_y_0,x+dx,m_y_0,(uint)m_colors[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
x3=x+dx*(m_y_0-y1)/(y2-y1);
|
||||
FillTriangle(x,y1,x3,m_y_0,x,m_y_0,(uint)m_colors[index]);
|
||||
FillTriangle(x+dx,y2,x3,m_y_0,x+dx,m_y_0,(uint)m_colors[index]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(y1<m_y_0 || y2<m_y_0)
|
||||
{
|
||||
if(y1>y2)
|
||||
FillTriangle(x,y1,x+dx,y2,x+dx,y1,(uint)m_colors[index]);
|
||||
if(y1<y2)
|
||||
{
|
||||
FillTriangle(x,y1,x+dx,y2,x,y2,(uint)m_colors[index]);
|
||||
y1=y2;
|
||||
}
|
||||
}
|
||||
if(y1>m_y_0 || y2>m_y_0)
|
||||
{
|
||||
if(y1<y2)
|
||||
FillTriangle(x,y1,x+dx,y2,x+dx,y1,(uint)m_colors[index]);
|
||||
if(y1>y2)
|
||||
{
|
||||
FillTriangle(x,y1,x+dx,y2,x,y2,(uint)m_colors[index]);
|
||||
y1=y2;
|
||||
}
|
||||
}
|
||||
FillRectangle(x,m_y_0,x+dx,y1,(uint)m_colors[index]);
|
||||
}
|
||||
else
|
||||
LineAA(x,y1,x+dx,y2,(uint)m_colors[index],STYLE_SOLID);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Area of filling |
|
||||
//+------------------------------------------------------------------+
|
||||
double CLineChart::CalcArea(const uint index)
|
||||
{
|
||||
double area =0;
|
||||
double value=0;
|
||||
int dx =100;
|
||||
//---
|
||||
CArrayDouble *data=m_values.At(index);
|
||||
if(data==NULL)
|
||||
return(0);
|
||||
int total=data.Total();
|
||||
if(total<=1)
|
||||
return(0);
|
||||
int y1=0;
|
||||
int y2=(int)(m_y_0-data[0]*m_scale_y);
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
y1=y2;
|
||||
double val=data[i];
|
||||
if(val==EMPTY_VALUE)
|
||||
continue;
|
||||
if(m_accumulative)
|
||||
value+=val;
|
||||
else
|
||||
value=val;
|
||||
y2=(int)(m_y_0-value*m_scale_y);
|
||||
if((y1>m_y_0 && y2<m_y_0) || (y1<m_y_0 && y2>m_y_0))
|
||||
{
|
||||
//--- line of values crosses the Y axis
|
||||
int x;
|
||||
if(y1>y2)
|
||||
{
|
||||
//--- from the bottom up
|
||||
x=dx*(y1-m_y_0)/(y1-y2);
|
||||
//--- add area of lower triangle
|
||||
area+=x*(y1-m_y_0)/2;
|
||||
//--- add area of upper triangle
|
||||
area+=(dx-x)*(m_y_0-y2)/2;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- from top down
|
||||
x=dx*(m_y_0-y1)/(y2-y1);
|
||||
//--- add area of upper triangle
|
||||
area+=x*(m_y_0-y1)/2;
|
||||
//--- add area of lower triangle
|
||||
area+=(dx-x)*(y2-m_y_0)/2;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(y1<m_y_0 || y2<m_y_0)
|
||||
{
|
||||
//--- both values are greater than zero
|
||||
if(y1>y2)
|
||||
{
|
||||
//--- add area of triangle
|
||||
area+=dx*(y1-y2)/2;
|
||||
//--- add area of rectangle
|
||||
area+=dx*(m_y_0-y2);
|
||||
}
|
||||
if(y1<y2)
|
||||
{
|
||||
//--- add area of triangle
|
||||
area+=dx*(y2-y1)/2;
|
||||
//--- add area of rectangle
|
||||
area+=dx*(m_y_0-y1);
|
||||
}
|
||||
}
|
||||
if(y1>m_y_0 || y2>m_y_0)
|
||||
{
|
||||
//--- both values are less than zero
|
||||
if(y1<y2)
|
||||
{
|
||||
//--- add area of triangle
|
||||
area+=dx*(y2-y1)/2;
|
||||
//--- add area of rectangle
|
||||
area+=dx*(y1-m_y_0);
|
||||
}
|
||||
if(y1>y2)
|
||||
{
|
||||
//--- add area of triangle
|
||||
area+=dx*(y1-y2)/2;
|
||||
//--- add area of rectangle
|
||||
area+=dx*(y2-m_y_0);
|
||||
}
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(area);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,414 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| PieChart.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartCanvas.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CPieChart |
|
||||
//| Usage: generates pie chart |
|
||||
//+------------------------------------------------------------------+
|
||||
class CPieChart : public CChartCanvas
|
||||
{
|
||||
private:
|
||||
//--- data
|
||||
CArrayDouble *m_values;
|
||||
//--- for draw
|
||||
int m_x0;
|
||||
int m_y0;
|
||||
int m_r;
|
||||
|
||||
public:
|
||||
CPieChart(void);
|
||||
~CPieChart(void);
|
||||
//--- create
|
||||
virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
|
||||
//--- data
|
||||
bool SeriesSet(const double &value[],const string &text[],const uint &clr[]);
|
||||
bool ValueAdd(const double value,const string descr="",const uint clr=0);
|
||||
bool ValueInsert(const uint pos,const double value,const string descr="",const uint clr=0);
|
||||
bool ValueUpdate(const uint pos,const double value,const string descr=NULL,const uint clr=0);
|
||||
bool ValueDelete(const uint pos);
|
||||
|
||||
protected:
|
||||
virtual void DrawChart(void);
|
||||
void DrawPie(double fi3,double fi4,int idx,CPoint &p[],const uint clr);
|
||||
string LabelMake(const string text,const double value,const bool to_left);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CPieChart::CPieChart(void)
|
||||
{
|
||||
uint flags=FLAG_SHOW_LEGEND|FLAG_SHOW_DESCRIPTORS|FLAG_SHOW_VALUE|FLAG_SHOW_PERCENT;
|
||||
AllowedShowFlags(flags);
|
||||
ShowFlags(flags);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CPieChart::~CPieChart(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create dynamic resource |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
|
||||
{
|
||||
//--- create object to store data
|
||||
if((m_values=new CArrayDouble)==NULL)
|
||||
return(false);
|
||||
//--- pass responsibility for its destruction to the parent class
|
||||
m_data=m_values;
|
||||
//--- call method of parent class
|
||||
if(!CChartCanvas::Create(name,width,height,clrfmt))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets displayed parameters |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::SeriesSet(const double &value[],const string &text[],const uint &clr[])
|
||||
{
|
||||
//--- !!! user is responsible for correct filling of arrays !!!
|
||||
//--- check
|
||||
if(m_values==NULL)
|
||||
return(false);
|
||||
//--- set
|
||||
if(!m_values.AssignArray(value))
|
||||
return(false);
|
||||
if(!m_descriptors.AssignArray(text))
|
||||
return(false);
|
||||
if(!m_colors.AssignArray(clr))
|
||||
return(false);
|
||||
m_data_total=m_values.Total();
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds displayed parameter (to the end) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::ValueAdd(const double value,const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if((value<=0))
|
||||
return(false);
|
||||
//--- add
|
||||
if(!m_values.Add(value))
|
||||
return(false);
|
||||
if(!m_descriptors.Add(descr))
|
||||
return(false);
|
||||
if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserts displayed parameter (to specified position) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::ValueInsert(const uint pos,const double value,const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if((value<=0))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(!m_values.Insert(value,pos))
|
||||
return(false);
|
||||
if(!m_descriptors.Insert(descr,pos))
|
||||
return(false);
|
||||
if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updates displayed parameter (in specified position) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::ValueUpdate(const uint pos,const double value,const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if((value<=0))
|
||||
return(false);
|
||||
//--- update
|
||||
if(!m_values.Update(pos,value))
|
||||
return(false);
|
||||
if(descr!=NULL && !m_descriptors.Update(pos,descr))
|
||||
return(false);
|
||||
if(clr!=0 && !m_colors.Update(pos,clr))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deletes displayed parameter (from specified position) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::ValueDelete(const uint pos)
|
||||
{
|
||||
//--- delete
|
||||
if(!m_values.Delete(pos))
|
||||
return(false);
|
||||
m_data_total--;
|
||||
if(!m_descriptors.Delete(pos))
|
||||
return(false);
|
||||
if(!m_colors.Delete(pos))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws |
|
||||
//+------------------------------------------------------------------+
|
||||
void CPieChart::DrawChart(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return;
|
||||
//--- variables
|
||||
string text="";
|
||||
double angle=M_PI*(m_data_offset%360)/180;
|
||||
int width,height;
|
||||
int dw=0;
|
||||
int dh=0;
|
||||
int index;
|
||||
CPoint p0[];
|
||||
CPoint p1[];
|
||||
//--- calculate geometry
|
||||
width =(m_data_area.Width()<<3)/10;
|
||||
height=(m_data_area.Height()<<3)/10;
|
||||
if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS)
|
||||
{
|
||||
if(IS_SHOW_VALUE)
|
||||
dw=(int)m_max_value_width;
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
dw=TextWidth("100.00%");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_DESCRIPTORS)
|
||||
{
|
||||
if(IS_SHOW_VALUE)
|
||||
dw=(int)m_max_value_width+TextWidth(" ()");
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
dw=TextWidth(" (100.00%)");
|
||||
}
|
||||
dw+=(int)m_max_descr_width;
|
||||
}
|
||||
}
|
||||
//--- pie chart will always be round
|
||||
width -=2*dw+10;
|
||||
height-=20;
|
||||
m_x0=m_data_area.left+(m_data_area.Width()>>1);
|
||||
m_y0=m_data_area.top+(m_data_area.Height()>>1);
|
||||
m_r =(((width>height) ? height : width)>>1);
|
||||
//--- draw pie chart
|
||||
if(ArrayResize(p0,m_data_total+1)==-1)
|
||||
return;
|
||||
if(m_data_total==1)
|
||||
{
|
||||
FillCircle(m_x0,m_y0,m_r,m_colors[0]);
|
||||
Circle(m_x0,m_y0,m_r,m_color_border);
|
||||
}
|
||||
else
|
||||
{
|
||||
Circle(m_x0,m_y0,m_r,m_color_border);
|
||||
for(uint i=0;i<m_index_size;i++)
|
||||
{
|
||||
index=m_index[i];
|
||||
double val=m_values[index];
|
||||
double d_a=2*M_PI*val/m_sum;
|
||||
DrawPie(angle,angle+d_a,i,p0,m_colors[index]);
|
||||
angle+=d_a;
|
||||
angle=MathMod(angle,2*M_PI);
|
||||
}
|
||||
if(m_data_total!=m_index_size)
|
||||
DrawPie(angle,angle+2*M_PI*m_others/m_sum,m_index_size,p0,COLOR2RGB(clrBlack));
|
||||
for(uint i=0;i<=m_index_size;i++)
|
||||
Line(m_x0,m_y0,p0[i].x,p0[i].y,m_color_border);
|
||||
Circle(m_x0,m_y0,m_r,m_color_border);
|
||||
}
|
||||
//--- draw descriptors
|
||||
angle=M_PI*(m_data_offset%360)/180;
|
||||
int r1=(int)round(1.1*m_r);
|
||||
if(ArrayResize(p1,m_data_total)==-1)
|
||||
return;
|
||||
//--- calculations
|
||||
for(uint i=0;i<m_index_size;i++)
|
||||
{
|
||||
index=m_index[i];
|
||||
angle+=M_PI*m_values[index]/m_sum;
|
||||
//--- lines
|
||||
p0[i].x=m_x0+(int)round(m_r*cos(angle));
|
||||
p0[i].y=m_y0-(int)round(m_r*sin(angle));
|
||||
p1[i].x=m_x0+(int)round(r1*cos(angle));
|
||||
p1[i].y=m_y0-(int)round(r1*sin(angle));
|
||||
angle+=M_PI*m_values[index]/m_sum;
|
||||
}
|
||||
if(m_data_total!=m_index_size)
|
||||
{
|
||||
index=(int)m_data_total-1;
|
||||
angle+=M_PI*m_others/m_sum;
|
||||
p0[index].x=m_x0+(int)round(m_r*cos(angle));
|
||||
p0[index].y=m_y0-(int)round(m_r*sin(angle));
|
||||
p1[index].x=m_x0+(int)round(r1*cos(angle));
|
||||
p1[index].y=m_y0-(int)round(r1*sin(angle));
|
||||
}
|
||||
int x,y;
|
||||
//--- draw descriptors to the left
|
||||
for(uint i=0;i<m_index_size;i++)
|
||||
if(p0[i].x<m_x0)
|
||||
{
|
||||
x=p1[i].x-10;
|
||||
y=p1[i].y;
|
||||
index=m_index[i];
|
||||
text=LabelMake(m_descriptors[index],m_values[index],true);
|
||||
if(text!="")
|
||||
{
|
||||
Line(p0[i].x,p0[i].y,p1[i].x,p1[i].y,m_color_border);
|
||||
Line(p1[i].x,p1[i].y,x,y,m_color_border);
|
||||
TextOut(x-5,y,text,m_color_text,TA_RIGHT|TA_VCENTER);
|
||||
}
|
||||
}
|
||||
//--- draw descriptors to the right
|
||||
for(uint i=0;i<m_index_size;i++)
|
||||
if(p0[i].x>=m_x0)
|
||||
{
|
||||
x=p1[i].x+10;
|
||||
y=p1[i].y;
|
||||
index=m_index[i];
|
||||
text=LabelMake(m_descriptors[index],m_values[index],false);
|
||||
if(text!="")
|
||||
{
|
||||
Line(p0[i].x,p0[i].y,p1[i].x,p1[i].y,m_color_border);
|
||||
Line(p1[i].x,p1[i].y,x,y,m_color_border);
|
||||
TextOut(x+5,y,text,m_color_text,TA_LEFT|TA_VCENTER);
|
||||
}
|
||||
}
|
||||
if(m_data_total!=m_index_size)
|
||||
{
|
||||
index=(int)m_data_total-1;
|
||||
if(p0[index].x>=m_x0)
|
||||
{
|
||||
x=p1[index].x+10;
|
||||
y=p1[index].y;
|
||||
text=LabelMake("Others",m_others,true);
|
||||
TextOut(x+5,y,text,m_color_text,TA_LEFT|TA_VCENTER);
|
||||
}
|
||||
else
|
||||
{
|
||||
x=p1[index].x-10;
|
||||
y=p1[index].y;
|
||||
text=LabelMake("Others",m_others,false);
|
||||
TextOut(x-5,y,text,m_color_text,TA_RIGHT|TA_VCENTER);
|
||||
}
|
||||
if(text!="")
|
||||
{
|
||||
Line(p0[index].x,p0[index].y,p1[index].x,p1[index].y,m_color_border);
|
||||
Line(p1[index].x,p1[index].y,x,y,m_color_border);
|
||||
}
|
||||
}
|
||||
ArrayFree(p1);
|
||||
ArrayFree(p0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draw pie |
|
||||
//+------------------------------------------------------------------+
|
||||
void CPieChart::DrawPie(double fi3,double fi4,int idx,CPoint &p[],const uint clr)
|
||||
{
|
||||
//--- draw arc
|
||||
Arc(m_x0,m_y0,m_r,m_r,fi3,fi4,p[idx].x,p[idx].y,p[idx+1].x,p[idx+1].y,clr);
|
||||
//--- variables
|
||||
int x3=p[idx].x;
|
||||
int y3=p[idx].y;
|
||||
int x4=p[idx+1].x;
|
||||
int y4=p[idx+1].y;
|
||||
//--- draw radii
|
||||
if(idx==0)
|
||||
Line(m_x0,m_y0,x3,y3,clr);
|
||||
if(idx!=m_data_total-1)
|
||||
Line(m_x0,m_y0,x4,y4,clr);
|
||||
//--- fill
|
||||
double fi=(fi3+fi4)/2;
|
||||
int xf=m_x0+(int)(0.99*m_r*cos(fi));
|
||||
int yf=m_y0-(int)(0.99*m_r*sin(fi));
|
||||
Fill(xf,yf,clr);
|
||||
//--- for small pie
|
||||
if(fi4-fi3<=M_PI_4)
|
||||
Line(m_x0,m_y0,xf,yf,clr);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Make label for pie |
|
||||
//+------------------------------------------------------------------+
|
||||
string CPieChart::LabelMake(const string text,const double value,const bool to_left)
|
||||
{
|
||||
string label="";
|
||||
//---
|
||||
if(to_left)
|
||||
{
|
||||
if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS)
|
||||
{
|
||||
if(IS_SHOW_VALUE)
|
||||
label=DoubleToString(value,2);
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
label=DoubleToString(100*value/m_sum,2)+"%";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
label=text;
|
||||
if(IS_SHOW_VALUE)
|
||||
label+=" ("+DoubleToString(value,2)+")";
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
label+=" ("+DoubleToString(100*value/m_sum,2)+"%)";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS)
|
||||
{
|
||||
if(IS_SHOW_VALUE)
|
||||
label=DoubleToString(value,2);
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
label=DoubleToString(100*value/m_sum,2)+"%";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_VALUE)
|
||||
label="("+DoubleToString(value,2)+") ";
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
label="("+DoubleToString(100*value/m_sum,2)+"%) ";
|
||||
}
|
||||
label+=text;
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(label);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,75 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DXBox.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
//---
|
||||
#include "DXMesh.mqh"
|
||||
#include "DXMath.mqh"
|
||||
#include "DXUtils.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| 3D Box object |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDXBox : public CDXMesh
|
||||
{
|
||||
public:
|
||||
CDXBox();
|
||||
~CDXBox();
|
||||
//--- create bon in specified context
|
||||
bool Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,const DXVector3 &from,const DXVector3 &to);
|
||||
//--- update box
|
||||
bool Update(const DXVector3 &from,const DXVector3 &to);
|
||||
|
||||
private:
|
||||
//---
|
||||
void PrepareVertices(const DXVector3 &from,const DXVector3 &to);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDXBox::CDXBox() : CDXMesh()
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDXBox::~CDXBox(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create box in specified context |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDXBox::Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,const DXVector3 &from,const DXVector3 &to)
|
||||
{
|
||||
//--- release previous buffers
|
||||
Shutdown();
|
||||
//---
|
||||
DXVertex vertices[];
|
||||
uint indices[];
|
||||
//--- prepare box vertices and indices
|
||||
if(!DXComputeBox(from,to,vertices,indices))
|
||||
return(false);
|
||||
for(int i=0; i<ArraySize(vertices); i++)
|
||||
vertices[i].vcolor=DXColor(1.0f,1.0f,1.0f,1.0f);
|
||||
//--- create mesh
|
||||
return(CDXMesh::Create(dispatcher,buffer_scene,vertices,indices));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update box bounds |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDXBox::Update(const DXVector3 &from,const DXVector3 &to)
|
||||
{
|
||||
//---
|
||||
DXVertex vertices[];
|
||||
uint indices[];
|
||||
//--- prepare box vertices and indices
|
||||
if(!DXComputeBox(from,to,vertices,indices))
|
||||
return(false);
|
||||
for(int i=0; i<ArraySize(vertices); i++)
|
||||
vertices[i].vcolor=DXColor(1.0f,1.0f,1.0f,1.0f);
|
||||
//--- update mesh vertices, indices are the same
|
||||
return(CDXMesh::VerticesSet(vertices));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,92 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DXVertexBuffer.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#include "DXHandle.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| DX vertex buffer |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDXVertexBuffer : public CDXHandleShared
|
||||
{
|
||||
public:
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
virtual ~CDXVertexBuffer(void)
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create vertex buffer in specified context |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TVertex>
|
||||
bool Create(int context_handle,const TVertex &vertices[],uint start=0,uint count=WHOLE_ARRAY)
|
||||
{
|
||||
Shutdown();
|
||||
m_context=context_handle;
|
||||
m_handle=DXBufferCreate(m_context,DX_BUFFER_VERTEX,vertices,start,count);
|
||||
return(m_handle!=INVALID_HANDLE);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Render |
|
||||
//+------------------------------------------------------------------+
|
||||
bool Render(uint start=0,uint count=WHOLE_ARRAY)
|
||||
{
|
||||
return(DXBufferSet(m_context,m_handle,start,count));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Shutdown |
|
||||
//+------------------------------------------------------------------+
|
||||
void Shutdown(void)
|
||||
{
|
||||
//--- relase handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
DXRelease(m_handle);
|
||||
m_handle=INVALID_HANDLE;
|
||||
}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| DX index buffer |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDXIndexBuffer : public CDXHandleShared
|
||||
{
|
||||
public:
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
virtual ~CDXIndexBuffer(void)
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create index buffer in specified context |
|
||||
//+------------------------------------------------------------------+
|
||||
bool Create(int context_handle,const uint &indices[],uint start=0,uint count=WHOLE_ARRAY)
|
||||
{
|
||||
Shutdown();
|
||||
m_context=context_handle;
|
||||
m_handle=DXBufferCreate(m_context,DX_BUFFER_INDEX,indices,start,count);
|
||||
return(m_handle!=INVALID_HANDLE);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Render |
|
||||
//+------------------------------------------------------------------+
|
||||
bool Render(uint start=0,uint count=WHOLE_ARRAY)
|
||||
{
|
||||
return(DXBufferSet(m_context,m_handle,start,count));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Shutdown |
|
||||
//+------------------------------------------------------------------+
|
||||
void Shutdown(void)
|
||||
{
|
||||
//--- relase handle
|
||||
if(m_handle!=INVALID_HANDLE)
|
||||
DXRelease(m_handle);
|
||||
m_handle=INVALID_HANDLE;
|
||||
}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
@@ -0,0 +1,373 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DXDispatcher.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
//---
|
||||
#include "DXObjectBase.mqh"
|
||||
#include "DXData.mqh"
|
||||
#include "DXBuffers.mqh"
|
||||
#include "DXInput.mqh"
|
||||
#include "DXTexture.mqh"
|
||||
#include "DXShader.mqh"
|
||||
//--- default shaders
|
||||
#resource "Shaders/DefaultShaderVertex.hlsl" as string ExtDefaultShaderVertex;
|
||||
#resource "Shaders/DefaultShaderPixel.hlsl" as string ExtDefaultShaderPixel;
|
||||
//+------------------------------------------------------------------+
|
||||
//| DX dispatcher which holds all resources |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDXDispatcher : public CDXObjectBase
|
||||
{
|
||||
protected:
|
||||
CDXObjectBase m_dx_resources; // DX resources list (Textures, Shaders, etc.)
|
||||
//--- default shaders
|
||||
CDXShader* m_default_vs;
|
||||
CDXShader* m_default_ps;
|
||||
|
||||
public:
|
||||
CDXDispatcher(void);
|
||||
~CDXDispatcher(void);
|
||||
//--- create/destroy
|
||||
bool Create(int context);
|
||||
void Destroy(void);
|
||||
//--- check resources
|
||||
void Check(void);
|
||||
//--- get DX Context Handle
|
||||
int DXContext(void) const { return(m_context); }
|
||||
//--- create shaders
|
||||
CDXShader* ShaderCreateDefault(ENUM_DX_SHADER_TYPE shader_type);
|
||||
CDXShader* ShaderCreateFromFile(ENUM_DX_SHADER_TYPE shader_type,string path,string entry_point);
|
||||
CDXShader* ShaderCreateFromSource(ENUM_DX_SHADER_TYPE shader_type,string source,string entry_point);
|
||||
//--- create buffers
|
||||
template<typename TVertex>
|
||||
CDXVertexBuffer* VertexBufferCreate(const TVertex &vertices[],uint start=0,uint count=WHOLE_ARRAY);
|
||||
CDXIndexBuffer* IndexBufferCreate(const uint &indicies[],uint start=0,uint count=WHOLE_ARRAY);
|
||||
//--- create shader inputs
|
||||
template<typename TInput>
|
||||
CDXInput* InputCreate(void);
|
||||
CDXTexture* TextureCreateFromFile(string path,uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0);
|
||||
CDXTexture* TextureCreateFromData(ENUM_DX_FORMAT format,uint width,uint height,const uint &data[],uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0);
|
||||
|
||||
private:
|
||||
//--- add resource to list
|
||||
bool ResourceAdd(CDXObjectBase *resource);
|
||||
//--- check resources
|
||||
void ResourcesCheck(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDXDispatcher::CDXDispatcher(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDXDispatcher::~CDXDispatcher(void)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDXDispatcher::Create(int context)
|
||||
{
|
||||
//--- check if context already exist
|
||||
if(m_context!=INVALID_HANDLE)
|
||||
return(false);
|
||||
//--- save context
|
||||
m_context=context;
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destroy |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDXDispatcher::Destroy(void)
|
||||
{
|
||||
//--- release default shaders
|
||||
if(m_default_ps)
|
||||
{
|
||||
m_default_ps.Release();
|
||||
m_default_ps=NULL;
|
||||
}
|
||||
if(m_default_vs)
|
||||
{
|
||||
m_default_vs.Release();
|
||||
m_default_vs=NULL;
|
||||
}
|
||||
//--- release and delete all DX resources
|
||||
while(m_dx_resources.Next())
|
||||
{
|
||||
CDXHandleShared* resource=(CDXHandleShared*)m_dx_resources.Next();
|
||||
resource.Release();
|
||||
}
|
||||
//--- forget context
|
||||
m_context=INVALID_HANDLE;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check resources |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDXDispatcher::Check(void)
|
||||
{
|
||||
//---
|
||||
CDXHandleShared* resource=(CDXHandleShared*)m_dx_resources.Next();
|
||||
//--- release and delete all DX resources
|
||||
while(CheckPointer(resource)!=POINTER_INVALID)
|
||||
{
|
||||
CDXHandleShared* next=(CDXHandleShared*)resource.Next();
|
||||
//--- if references count 1 or less, then only we hold the resource
|
||||
if(resource.References()<=1)
|
||||
resource.Release();
|
||||
//---
|
||||
resource=next;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create default shader of specified type |
|
||||
//+------------------------------------------------------------------+
|
||||
CDXShader* CDXDispatcher::ShaderCreateDefault(ENUM_DX_SHADER_TYPE shader_type)
|
||||
{
|
||||
switch(shader_type)
|
||||
{
|
||||
//--- default pixel shader
|
||||
case DX_SHADER_PIXEL:
|
||||
{
|
||||
if(m_default_ps==NULL)
|
||||
m_default_ps=ShaderCreateFromSource(DX_SHADER_PIXEL,ExtDefaultShaderPixel,"PSMain");
|
||||
return(m_default_ps);
|
||||
}
|
||||
//--- default vertex shader
|
||||
case DX_SHADER_VERTEX:
|
||||
{
|
||||
if(m_default_vs==NULL)
|
||||
{
|
||||
m_default_vs=ShaderCreateFromSource(DX_SHADER_VERTEX,ExtDefaultShaderVertex,"VSMain");
|
||||
if(m_default_vs && !m_default_vs.LayoutSet<DXVertex>())
|
||||
{
|
||||
m_default_vs.Release();
|
||||
m_default_vs=NULL;
|
||||
}
|
||||
}
|
||||
return(m_default_vs);
|
||||
}
|
||||
}
|
||||
//--- return result
|
||||
return(NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create new shader of specified type from file |
|
||||
//+------------------------------------------------------------------+
|
||||
CDXShader* CDXDispatcher::ShaderCreateFromFile(ENUM_DX_SHADER_TYPE shader_type,string path,string entry_point)
|
||||
{
|
||||
//--- open source file
|
||||
int file=FileOpen(path,FILE_READ);
|
||||
if(file==INVALID_HANDLE)
|
||||
return(NULL);
|
||||
//--- check file size
|
||||
uint size=(uint)FileSize(file);
|
||||
FileClose(file);
|
||||
if(size>16*1024*1024)
|
||||
return(NULL);
|
||||
//--- prepare buffer
|
||||
char buffer[];
|
||||
ArrayResize(buffer,size);
|
||||
//--- read file into buffer
|
||||
int read=(int)FileLoad(path,buffer);
|
||||
if(read<=0)
|
||||
return(NULL);
|
||||
//--- convert vuffer to string
|
||||
string source=CharArrayToString(buffer,0,WHOLE_ARRAY,CP_UTF8);
|
||||
//--- add shader by source
|
||||
return(ShaderCreateFromSource(shader_type,source,entry_point));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create new shader of specified type from source code |
|
||||
//+------------------------------------------------------------------+
|
||||
CDXShader* CDXDispatcher::ShaderCreateFromSource(ENUM_DX_SHADER_TYPE shader_type,string source,string entry_point)
|
||||
{
|
||||
//--- check context
|
||||
if(m_context==INVALID_HANDLE)
|
||||
return(NULL);
|
||||
//--- allocate new shader
|
||||
CDXShader* shader=new CDXShader();
|
||||
if(shader==NULL)
|
||||
return(NULL);
|
||||
//--- create shader
|
||||
if(!shader.Create(m_context,shader_type,source,entry_point))
|
||||
{
|
||||
shader.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- add shader to resources list
|
||||
if(!ResourceAdd(shader))
|
||||
{
|
||||
shader.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- return shader
|
||||
return(shader);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create vertex buffer |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TVertex>
|
||||
CDXVertexBuffer* CDXDispatcher::VertexBufferCreate(const TVertex &vertices[],uint start=0,uint count=WHOLE_ARRAY)
|
||||
{
|
||||
//--- check context
|
||||
if(m_context==INVALID_HANDLE)
|
||||
return(NULL);
|
||||
//--- allocate new buffer
|
||||
CDXVertexBuffer* buffer=new CDXVertexBuffer();
|
||||
if(buffer==NULL)
|
||||
return(NULL);
|
||||
//--- create buffer
|
||||
if(!buffer.Create(m_context,vertices,start,count))
|
||||
{
|
||||
buffer.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- add buffer to resources list
|
||||
if(!ResourceAdd(buffer))
|
||||
{
|
||||
buffer.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- return buffer
|
||||
return(buffer);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create vertex buffer |
|
||||
//+------------------------------------------------------------------+
|
||||
CDXIndexBuffer* CDXDispatcher::IndexBufferCreate(const uint &indicies[],uint start=0,uint count=WHOLE_ARRAY)
|
||||
{
|
||||
//--- check context
|
||||
if(m_context==INVALID_HANDLE)
|
||||
return(NULL);
|
||||
//--- allocate new buffer
|
||||
CDXIndexBuffer* buffer=new CDXIndexBuffer();
|
||||
if(buffer==NULL)
|
||||
return(NULL);
|
||||
//--- create buffer
|
||||
if(!buffer.Create(m_context,indicies,start,count))
|
||||
{
|
||||
buffer.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- add buffer to resources list
|
||||
if(!ResourceAdd(buffer))
|
||||
{
|
||||
buffer.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- return input buffer
|
||||
return(buffer);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create shader input buffer |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TInput>
|
||||
CDXInput* CDXDispatcher::InputCreate(void)
|
||||
{
|
||||
//--- check context
|
||||
if(m_context==INVALID_HANDLE)
|
||||
return(NULL);
|
||||
//--- allocate new input buffer
|
||||
CDXInput* input_buffer=new CDXInput();
|
||||
if(input_buffer==NULL)
|
||||
return(NULL);
|
||||
//--- create buffer
|
||||
if(!input_buffer.Create<TInput>(m_context))
|
||||
{
|
||||
input_buffer.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- add buffer to resources list
|
||||
if(!ResourceAdd(input_buffer))
|
||||
{
|
||||
input_buffer.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- return shader
|
||||
return(input_buffer);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create texture from bitmap file |
|
||||
//+------------------------------------------------------------------+
|
||||
CDXTexture* CDXDispatcher::TextureCreateFromFile(string path,uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0)
|
||||
{
|
||||
//--- check context
|
||||
if(m_context==INVALID_HANDLE)
|
||||
return(NULL);
|
||||
//--- allocate new texture
|
||||
CDXTexture* texture=new CDXTexture();
|
||||
if(texture==NULL)
|
||||
return(NULL);
|
||||
//--- create texture
|
||||
if(!texture.Create(m_context,path,data_x,data_y,data_width,data_height))
|
||||
{
|
||||
texture.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- add texture to resources list
|
||||
if(!ResourceAdd(texture))
|
||||
{
|
||||
texture.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- return shader
|
||||
return(texture);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create texture from raw data, only 32-bit pixel formats supported|
|
||||
//+------------------------------------------------------------------+
|
||||
CDXTexture* CDXDispatcher::TextureCreateFromData(ENUM_DX_FORMAT format,uint width,uint height,const uint &data[],uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0)
|
||||
{
|
||||
//--- check context
|
||||
if(m_context==INVALID_HANDLE)
|
||||
return(NULL);
|
||||
//--- allocate new texture
|
||||
CDXTexture* texture=new CDXTexture();
|
||||
if(texture==NULL)
|
||||
return(NULL);
|
||||
//--- create texture
|
||||
if(!texture.Create(m_context,format,width,height,data,data_x,data_y,data_width,data_height))
|
||||
{
|
||||
texture.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- add texture to resources list
|
||||
if(!ResourceAdd(texture))
|
||||
{
|
||||
texture.Release();
|
||||
return(NULL);
|
||||
}
|
||||
//--- return shader
|
||||
return(texture);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add DX resource |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDXDispatcher::ResourceAdd(CDXObjectBase *resource)
|
||||
{
|
||||
//--- add resource
|
||||
if(!CheckPointer(resource))
|
||||
return(false);
|
||||
//---
|
||||
CDXObjectBase *last=&m_dx_resources;
|
||||
while(CheckPointer(last.Next())!=POINTER_INVALID)
|
||||
{
|
||||
if(last==resource)
|
||||
return(false);
|
||||
//---
|
||||
last=last.Next();
|
||||
}
|
||||
//---
|
||||
resource.Next(NULL);
|
||||
resource.Prev(last);
|
||||
last.Next(resource);
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,374 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DXMesh.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
#include "DXObject.mqh"
|
||||
#include "DXDispatcher.mqh"
|
||||
#include "DXData.mqh"
|
||||
#include "DXUtils.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| DX simple mesh object with default shader |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDXMesh : public CDXObject
|
||||
{
|
||||
protected:
|
||||
//--- DX resources
|
||||
CDXVertexBuffer* m_buffer_vertex;
|
||||
CDXIndexBuffer* m_buffer_index;
|
||||
CDXInput* m_buffer_object;
|
||||
CDXInput* m_buffer_scene;
|
||||
CDXShader* m_shader_vertex;
|
||||
CDXShader* m_shader_pixel;
|
||||
CDXTexture* m_texture;
|
||||
//--- object data
|
||||
DXMatrix m_transform_matrix;
|
||||
DXColor m_diffuse_color;
|
||||
DXColor m_emission_color;
|
||||
DXColor m_specular_color;
|
||||
float m_specular_power;
|
||||
|
||||
ENUM_DX_PRIMITIVE_TOPOLOGY m_topology;
|
||||
|
||||
public:
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDXMesh(void):m_buffer_vertex(NULL),m_buffer_index(NULL),m_buffer_object(NULL),m_buffer_scene(NULL),m_shader_vertex(NULL),m_shader_pixel(NULL),m_topology(WRONG_VALUE)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
~CDXMesh(void)
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create mesh object from vertices and indices list |
|
||||
//+------------------------------------------------------------------+
|
||||
bool Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,const DXVertex &vertices[],const uint &indices[],ENUM_DX_PRIMITIVE_TOPOLOGY topology=DX_PRIMITIVE_TOPOLOGY_TRIANGLELIST)
|
||||
{
|
||||
Shutdown();
|
||||
//--- check data
|
||||
if(buffer_scene==NULL || buffer_scene.Handle()==INVALID_HANDLE ||
|
||||
ArraySize(vertices)<1 || ArraySize(indices)<1)
|
||||
return(false);
|
||||
//--- update context
|
||||
m_context=dispatcher.DXContext();
|
||||
//--- initialize default parameters
|
||||
DXMatrixIdentity(m_transform_matrix);
|
||||
m_diffuse_color =DXColor(1.0,1.0,1.0,1.0);
|
||||
m_emission_color=DXColor(0.0,0.0,0.0,0.0);
|
||||
m_specular_color=DXColor(0.0,0.0,0.0,0.0);
|
||||
m_specular_power=16.0f;
|
||||
//--- create object input
|
||||
m_buffer_object=dispatcher.InputCreate<DXInputObject>();
|
||||
if(m_buffer_object!=NULL)
|
||||
{
|
||||
m_buffer_object.AddRef();
|
||||
//--- use default vertex shader
|
||||
m_shader_vertex=dispatcher.ShaderCreateDefault(DX_SHADER_VERTEX);
|
||||
if(m_shader_vertex!=NULL)
|
||||
{
|
||||
m_shader_vertex.AddRef();
|
||||
//--- use default pixel shader
|
||||
m_shader_pixel=dispatcher.ShaderCreateDefault(DX_SHADER_PIXEL);
|
||||
if(m_shader_pixel!=NULL)
|
||||
{
|
||||
m_shader_pixel.AddRef();
|
||||
//--- create vertex buffer
|
||||
m_buffer_vertex=dispatcher.VertexBufferCreate(vertices);
|
||||
if(m_buffer_vertex!=NULL)
|
||||
{
|
||||
m_buffer_vertex.AddRef();
|
||||
//--- create index buffer
|
||||
m_buffer_index=dispatcher.IndexBufferCreate(indices);
|
||||
if(m_buffer_index!=NULL)
|
||||
m_buffer_index.AddRef();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- set object buffer to shaders
|
||||
if(m_buffer_object==NULL || m_shader_vertex==NULL || m_shader_pixel==NULL || m_buffer_vertex==NULL || m_buffer_index==NULL)
|
||||
{
|
||||
Shutdown();
|
||||
return(false);
|
||||
}
|
||||
//--- save scene buffer
|
||||
m_buffer_scene=buffer_scene;
|
||||
m_buffer_scene.AddRef();
|
||||
//--- save topology
|
||||
m_topology=topology;
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create mesh object from OBJ mesh file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,string obj_path,float scale=1.0f,bool inverse_winding=false)
|
||||
{
|
||||
DXVertex vertices[];
|
||||
uint indices[];
|
||||
//--- load model
|
||||
if(!DXLoadObjModel(obj_path,vertices,indices,scale))
|
||||
return(false);
|
||||
//--- set white vertices color
|
||||
int count=ArraySize(vertices);
|
||||
for(int i=0; i<count; i++)
|
||||
vertices[i].vcolor=DXColor(1.0f,1.0f,1.0f,1.0f);
|
||||
//--- inverse winding
|
||||
if(inverse_winding)
|
||||
DXInverseWinding(vertices,indices);
|
||||
//--- create mesh
|
||||
return(Create(dispatcher,buffer_scene,vertices,indices));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update vertices |
|
||||
//+------------------------------------------------------------------+
|
||||
bool VerticesSet(const DXVertex &vertices[])
|
||||
{
|
||||
//--- check size
|
||||
if(ArraySize(vertices)<1)
|
||||
return(false);
|
||||
//--- create new vertex buffer
|
||||
if(!m_buffer_vertex.Create(m_context,vertices))
|
||||
{
|
||||
Shutdown();
|
||||
return(false);
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update indices |
|
||||
//+------------------------------------------------------------------+
|
||||
bool IndicesSet(const uint &indices[])
|
||||
{
|
||||
//--- check size
|
||||
if(ArraySize(indices)<1)
|
||||
return(false);
|
||||
//--- create new index buffer
|
||||
if(!m_buffer_index.Create(m_context,indices))
|
||||
{
|
||||
Shutdown();
|
||||
return(false);
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update indices |
|
||||
//+------------------------------------------------------------------+
|
||||
bool TopologySet(ENUM_DX_PRIMITIVE_TOPOLOGY topology)
|
||||
{
|
||||
m_topology=topology;
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get transform matrix |
|
||||
//+------------------------------------------------------------------+
|
||||
void TransformMatrixGet(DXMatrix &mat) const
|
||||
{
|
||||
mat=m_transform_matrix;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set transform matrix |
|
||||
//+------------------------------------------------------------------+
|
||||
void TransformMatrixSet(const DXMatrix &mat)
|
||||
{
|
||||
m_transform_matrix=mat;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get diffuse color |
|
||||
//+------------------------------------------------------------------+
|
||||
void DiffuseColorGet(DXColor &clr) const
|
||||
{
|
||||
clr=m_diffuse_color;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set diffuse color |
|
||||
//+------------------------------------------------------------------+
|
||||
void DiffuseColorSet(const DXColor &clr)
|
||||
{
|
||||
m_diffuse_color=clr;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get specular color |
|
||||
//+------------------------------------------------------------------+
|
||||
void SpecularColorGet(DXColor &clr) const
|
||||
{
|
||||
clr=m_specular_color;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set specular color |
|
||||
//+------------------------------------------------------------------+
|
||||
void SpecularColorSet(const DXColor &clr)
|
||||
{
|
||||
m_specular_color=clr;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get specular power |
|
||||
//+------------------------------------------------------------------+
|
||||
void SpecularPowerGet(float &power) const
|
||||
{
|
||||
power=m_specular_power;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set specular power |
|
||||
//+------------------------------------------------------------------+
|
||||
void SpecularPowerSet(float power)
|
||||
{
|
||||
m_specular_power=power;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get emission color |
|
||||
//+------------------------------------------------------------------+
|
||||
void EmissionColorGet(DXColor &clr) const
|
||||
{
|
||||
clr=m_emission_color;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set emission color |
|
||||
//+------------------------------------------------------------------+
|
||||
void EmissionColorSet(const DXColor &clr)
|
||||
{
|
||||
m_emission_color=clr;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Render mesh |
|
||||
//+------------------------------------------------------------------+
|
||||
virtual bool Render(void) override
|
||||
{
|
||||
//--- update object buffer
|
||||
DXInputObject input_data;
|
||||
DXMatrixTranspose(input_data.transform,m_transform_matrix);
|
||||
input_data.diffuse_color =m_diffuse_color;
|
||||
input_data.emission_color=m_emission_color;
|
||||
input_data.specular_color=m_specular_color;
|
||||
input_data.specular_power=m_specular_power;
|
||||
//--- clear shader textures
|
||||
m_shader_pixel.TexturesClear();
|
||||
//--- set buffers, shaders, topology and render
|
||||
if(m_buffer_object.InputSet(input_data))
|
||||
if(m_buffer_vertex.Render())
|
||||
if(m_buffer_index.Render())
|
||||
if(m_shader_vertex.InputSet(0,m_buffer_scene) && m_shader_vertex.InputSet(1,m_buffer_object))
|
||||
if(m_shader_pixel.InputSet(0,m_buffer_scene) && m_shader_pixel.InputSet(1,m_buffer_object))
|
||||
if(CheckPointer(m_texture)==POINTER_INVALID || m_shader_pixel.TextureSet(0,m_texture))
|
||||
if(m_shader_vertex.Render())
|
||||
if(m_shader_pixel.Render())
|
||||
if(DXPrimiveTopologySet(m_context,m_topology))
|
||||
return(DXDrawIndexed(m_context));
|
||||
//---
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set texture from image file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool TextureSet(CDXDispatcher &dispatcher,string path,uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0)
|
||||
{
|
||||
//--- check if texture already exist
|
||||
if(CheckPointer(m_texture)==POINTER_INVALID)
|
||||
{
|
||||
m_texture=dispatcher.TextureCreateFromFile(path,data_x,data_y,data_width,data_height);
|
||||
if(m_texture==NULL)
|
||||
return(false);
|
||||
m_texture.AddRef();
|
||||
return(true);
|
||||
}
|
||||
//--- update texture data
|
||||
if(!m_texture.Create(m_context,path,data_x,data_y,data_width,data_height))
|
||||
{
|
||||
m_texture.Release();
|
||||
m_texture=NULL;
|
||||
return(false);
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set texture from image data |
|
||||
//+------------------------------------------------------------------+
|
||||
bool TextureSet(CDXDispatcher &dispatcher,ENUM_DX_FORMAT format,uint width,uint height,const uint &data[],uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0)
|
||||
{
|
||||
//--- check if texture already exist
|
||||
if(CheckPointer(m_texture)==POINTER_INVALID)
|
||||
{
|
||||
m_texture=dispatcher.TextureCreateFromData(format,width,height,data,data_x,data_y,data_width,data_height);
|
||||
if(m_texture==NULL)
|
||||
return(false);
|
||||
m_texture.AddRef();
|
||||
return(true);
|
||||
}
|
||||
//--- update texture data
|
||||
if(!m_texture.Create(m_context,format,width,height,data,data_x,data_y,data_width,data_height))
|
||||
{
|
||||
m_texture.Release();
|
||||
m_texture=NULL;
|
||||
return(false);
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete used texture |
|
||||
//+------------------------------------------------------------------+
|
||||
void TextureDelete()
|
||||
{
|
||||
//--- release texture
|
||||
if(CheckPointer(m_texture)!=POINTER_INVALID)
|
||||
{
|
||||
m_texture.Release();
|
||||
m_texture=NULL;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Shutdown |
|
||||
//+------------------------------------------------------------------+
|
||||
virtual void Shutdown(void)
|
||||
{
|
||||
//--- release all dx resources
|
||||
if(CheckPointer(m_buffer_vertex)!=POINTER_INVALID)
|
||||
{
|
||||
m_buffer_vertex.Release();
|
||||
m_buffer_vertex=NULL;
|
||||
}
|
||||
if(CheckPointer(m_buffer_index)!=POINTER_INVALID)
|
||||
{
|
||||
m_buffer_index.Release();
|
||||
m_buffer_index=NULL;
|
||||
}
|
||||
if(CheckPointer(m_buffer_object)!=POINTER_INVALID)
|
||||
{
|
||||
m_buffer_object.Release();
|
||||
m_buffer_object=NULL;
|
||||
}
|
||||
if(CheckPointer(m_texture)!=POINTER_INVALID)
|
||||
{
|
||||
m_texture.Release();
|
||||
m_texture=NULL;
|
||||
}
|
||||
if(CheckPointer(m_buffer_scene)!=POINTER_INVALID)
|
||||
{
|
||||
m_buffer_scene.Release();
|
||||
m_buffer_scene=NULL;
|
||||
}
|
||||
if(CheckPointer(m_shader_pixel)!=POINTER_INVALID)
|
||||
{
|
||||
m_shader_pixel.Release();
|
||||
m_shader_pixel=NULL;
|
||||
}
|
||||
if(CheckPointer(m_shader_vertex)!=POINTER_INVALID)
|
||||
{
|
||||
m_shader_vertex.Release();
|
||||
m_shader_vertex=NULL;
|
||||
}
|
||||
m_topology =WRONG_VALUE;
|
||||
}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,159 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DXSurface.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
//---
|
||||
#include "DXMesh.mqh"
|
||||
#include "DXMath.mqh"
|
||||
#include "DXUtils.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| 3D Box object |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDXSurface : public CDXMesh
|
||||
{
|
||||
public:
|
||||
//--- surface creation flags
|
||||
enum EN_SURFACE_FLAGS
|
||||
{
|
||||
SF_NONE =0x0,
|
||||
SF_TWO_SIDED =0x1,
|
||||
SF_USE_NORMALS =0x2,
|
||||
};
|
||||
//--- surface color scheme
|
||||
enum EN_COLOR_SCHEME
|
||||
{
|
||||
CS_NONE =0,
|
||||
CS_JET =1,
|
||||
CS_COLD_TO_HOT =2,
|
||||
CS_RED_TO_GREEN=3
|
||||
};
|
||||
|
||||
protected:
|
||||
uint m_data_width;
|
||||
uint m_data_height;
|
||||
uint m_flags;
|
||||
EN_COLOR_SCHEME m_color_scheme;
|
||||
|
||||
public:
|
||||
CDXSurface();
|
||||
~CDXSurface();
|
||||
//--- create bon in specified context
|
||||
bool Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,double &data[],uint m_data_widht,uint m_data_height,float data_range,const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,uint flags=SF_NONE,EN_COLOR_SCHEME color_scheme=CS_NONE);
|
||||
//--- update box
|
||||
bool Update(double &data[],uint m_data_widht,uint m_data_height,float data_range,const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,uint flags=0,EN_COLOR_SCHEME color_scheme=CS_NONE);
|
||||
|
||||
private:
|
||||
//---
|
||||
void PrepareColors(DXVertex &vertices[],const DXVector3 &from,const DXVector3 &to);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDXSurface::CDXSurface() : CDXMesh()
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDXSurface::~CDXSurface(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create box in specified context |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDXSurface::Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,
|
||||
double &data[],uint data_width,uint data_height,float data_range,
|
||||
const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,
|
||||
uint flags=SF_NONE,EN_COLOR_SCHEME color_scheme=CS_NONE)
|
||||
{
|
||||
//--- release previous buffers
|
||||
Shutdown();
|
||||
//--- save parameters
|
||||
m_data_width =data_width;
|
||||
m_data_height =data_height;
|
||||
m_flags =flags;
|
||||
m_color_scheme=color_scheme;
|
||||
//---
|
||||
DXVertex vertices[];
|
||||
uint indices[];
|
||||
//--- prepare surface vertices and indices
|
||||
if(!DXComputeSurface(data,data_width,data_height,data_range,from,to,texture_size,flags&SF_TWO_SIDED,flags&SF_USE_NORMALS,vertices,indices))
|
||||
return(false);
|
||||
//--- calculate colors
|
||||
PrepareColors(vertices,from,to);
|
||||
//--- create mesh
|
||||
return(CDXMesh::Create(dispatcher,buffer_scene,vertices,indices));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update box bounds |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDXSurface::Update(double &data[],uint data_width,uint data_height,float data_range,
|
||||
const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,
|
||||
uint flags=0,EN_COLOR_SCHEME color_scheme=CS_NONE)
|
||||
{
|
||||
//---
|
||||
DXVertex vertices[];
|
||||
uint indices[];
|
||||
//--- prepare surface vertices and indices
|
||||
if(!DXComputeSurface(data,data_width,data_height,data_range,from,to,texture_size,flags&SF_TWO_SIDED,flags&SF_USE_NORMALS,vertices,indices))
|
||||
return(false);
|
||||
//--- calculate colors
|
||||
m_color_scheme=color_scheme;
|
||||
PrepareColors(vertices,from,to);
|
||||
//--- update vertices
|
||||
bool res=CDXMesh::VerticesSet(vertices);
|
||||
//--- do not update indices if vertices relations are the same
|
||||
if(m_data_width!=data_width || m_data_height!=data_height || (m_flags&SF_TWO_SIDED)!=(flags&SF_TWO_SIDED))
|
||||
res=res && CDXMesh::IndicesSet(indices);
|
||||
//--- check result
|
||||
if(!res)
|
||||
{
|
||||
Shutdown();
|
||||
return(false);
|
||||
}
|
||||
//--- save parameters
|
||||
m_data_width =data_width;
|
||||
m_data_height =data_height;
|
||||
m_flags =flags;
|
||||
//--- success
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update box bounds |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDXSurface::PrepareColors(DXVertex &vertices[],const DXVector3 &from,const DXVector3 &to)
|
||||
{
|
||||
uint count=ArraySize(vertices);
|
||||
float scale=1.0f/(fmax(FLT_EPSILON,to.y-from.y));
|
||||
switch(m_color_scheme)
|
||||
{
|
||||
case CS_JET:
|
||||
{
|
||||
for(uint i=0; i<count; i++)
|
||||
DXComputeColorJet((vertices[i].position.y-from.y)*scale,vertices[i].vcolor);
|
||||
break;
|
||||
}
|
||||
case CS_COLD_TO_HOT:
|
||||
{
|
||||
for(uint i=0; i<count; i++)
|
||||
DXComputeColorColdToHot((vertices[i].position.y-from.y)*scale,vertices[i].vcolor);
|
||||
break;
|
||||
}
|
||||
case CS_RED_TO_GREEN:
|
||||
{
|
||||
for(uint i=0; i<count; i++)
|
||||
DXComputeColorRedToGreen((vertices[i].position.y-from.y)*scale,vertices[i].vcolor);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
for(uint i=0; i<count; i++)
|
||||
vertices[i].vcolor=DXColor(1.0f,1.0f,1.0f,1.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
@@ -0,0 +1,942 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DXUtils.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
//---
|
||||
#include "DXMath.mqh"
|
||||
#include "DXData.mqh"
|
||||
//--- data types in Wavefront OBJ file format
|
||||
#define OBJ_DATA_UNKNOWN 0
|
||||
#define OBJ_DATA_V 1
|
||||
#define OBJ_DATA_VT 2
|
||||
#define OBJ_DATA_VN 3
|
||||
#define OBJ_DATA_F 4
|
||||
//+------------------------------------------------------------------+
|
||||
//| OBJFaceType |
|
||||
//+------------------------------------------------------------------+
|
||||
struct OBJFaceType
|
||||
{
|
||||
int total;
|
||||
int v[4];
|
||||
int t[4];
|
||||
int n[4];
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Transforms right to left hand system, or backward |
|
||||
//| TVertex must have |
|
||||
//| DXVector4 normal and DXVector2 tcoord members |
|
||||
//+------------------------------------------------------------------+
|
||||
template <typename TVertex>
|
||||
void DXInverseWinding(TVertex &vertices[],uint &indices[])
|
||||
{
|
||||
//--- proccess vertices
|
||||
uint count=ArraySize(vertices);
|
||||
for(uint i=0; i<count; i++)
|
||||
{
|
||||
//--- invert normals
|
||||
vertices[i].normal.x=-vertices[i].normal.x;
|
||||
vertices[i].normal.y=-vertices[i].normal.y;
|
||||
vertices[i].normal.z=-vertices[i].normal.z;
|
||||
//--- flip texture coordinates
|
||||
vertices[i].tcoord.x=1.0f-vertices[i].tcoord.x;
|
||||
}
|
||||
//--- change indices order
|
||||
count=ArraySize(indices);
|
||||
for(uint i=2; i<count; i+=3)
|
||||
{
|
||||
uint tmp =indices[i];
|
||||
indices[i] =indices[i-2];
|
||||
indices[i-2]=tmp;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Load static 3D models from Maya 2011 |
|
||||
//| https://en.wikibooks.org/wiki/DirectX/10.0/Direct3D/Loading_Maya |
|
||||
//+------------------------------------------------------------------+
|
||||
bool DXLoadObjData(const string filename,DXVector4 &v_positions[],DXVector2 &v_tcoords[],DXVector4 &v_normals[],OBJFaceType &faces[],bool show_debug=false)
|
||||
{
|
||||
int total_positions=0;
|
||||
int total_tcoords=0;
|
||||
int total_normals=0;
|
||||
int total_faces=0;
|
||||
//---
|
||||
ResetLastError();
|
||||
int file_handle=FileOpen(filename,FILE_READ|FILE_TXT|FILE_ANSI);
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
{
|
||||
printf("FileOpen %s failed, error code=%d",filename,GetLastError());
|
||||
return(false);
|
||||
}
|
||||
int str_length=0;
|
||||
string str="";
|
||||
int total_lines=0;
|
||||
string str_parsed[];
|
||||
string str_parsed_faces[];
|
||||
//---
|
||||
while(!FileIsEnding(file_handle))
|
||||
{
|
||||
str=FileReadString(file_handle,str_length);
|
||||
total_lines++;
|
||||
//--- replace two spaces to one
|
||||
StringReplace(str,"\t"," ");
|
||||
while(StringFind(str," ",0)!=-1)
|
||||
StringReplace(str," "," ");
|
||||
//--- split string to tokens
|
||||
int total_items=StringSplit(str,' ',str_parsed);
|
||||
if(total_items<1)
|
||||
continue;
|
||||
//--- when examining the file you can ignore every line unless it starts with a "V", "VT", "VN", or "F".
|
||||
//--- the extra information in the file will not be needed for converting .obj to our file format.
|
||||
StringToUpper(str_parsed[0]);
|
||||
//--- parse data type
|
||||
int data_type=OBJ_DATA_UNKNOWN;
|
||||
if(str_parsed[0]=="V")
|
||||
data_type=OBJ_DATA_V;
|
||||
else
|
||||
if(str_parsed[0]=="VT")
|
||||
data_type=OBJ_DATA_VT;
|
||||
else
|
||||
if(str_parsed[0]=="VN")
|
||||
data_type=OBJ_DATA_VN;
|
||||
else
|
||||
if(str_parsed[0]=="F")
|
||||
data_type=OBJ_DATA_F;
|
||||
//--- proceed data type
|
||||
switch(data_type)
|
||||
{
|
||||
//--- 1. "V" lines are for the vertices, each is listed in X, Y, Z float format.
|
||||
case OBJ_DATA_V:
|
||||
{
|
||||
total_positions++;
|
||||
if(total_items<4)
|
||||
{
|
||||
PrintFormat("obj data error at line=%d: %s",total_lines,str);
|
||||
FileClose(file_handle);
|
||||
return(false);
|
||||
}
|
||||
ArrayResize(v_positions,total_positions,total_positions+1000);
|
||||
int idx=total_positions-1;
|
||||
v_positions[idx].x=(float)StringToDouble(str_parsed[1]);
|
||||
v_positions[idx].y=(float)StringToDouble(str_parsed[2]);
|
||||
v_positions[idx].z=(float)StringToDouble(str_parsed[3]);
|
||||
v_positions[idx].w=1.0f;
|
||||
//--- debug message
|
||||
if(show_debug)
|
||||
printf("posiiton %d: %f %f %f",idx,v_positions[idx].x,v_positions[idx].y,v_positions[idx].z);
|
||||
//---
|
||||
break;
|
||||
}
|
||||
//--- 2. "VT" lines are for the texture coordinates, they are listed in TU, TV float format.
|
||||
case OBJ_DATA_VT:
|
||||
{
|
||||
total_tcoords++;
|
||||
if(total_items<3)
|
||||
{
|
||||
PrintFormat("obj data error at line=%d: %s",total_lines,str);
|
||||
FileClose(file_handle);
|
||||
return(false);
|
||||
}
|
||||
ArrayResize(v_tcoords,total_tcoords,total_tcoords+1000);
|
||||
int idx=total_tcoords-1;
|
||||
v_tcoords[idx].x=(float)StringToDouble(str_parsed[1]);
|
||||
v_tcoords[idx].y=(float)StringToDouble(str_parsed[2]);
|
||||
//--- debug message
|
||||
if(show_debug)
|
||||
printf("tcoord %d: %f %f",idx,v_tcoords[idx].x,v_tcoords[idx].y);
|
||||
//---
|
||||
break;
|
||||
}
|
||||
//--- 3. "VN" lines are for the normal vectors, most of them are duplicated again
|
||||
//--- since it records them for every vertex in every triangle in the model, they are listed in NX, NY, NZ float format.
|
||||
case OBJ_DATA_VN:
|
||||
{
|
||||
total_normals++;
|
||||
if(total_items<4)
|
||||
{
|
||||
PrintFormat("obj data error at line=%d: %s",total_lines,str);
|
||||
FileClose(file_handle);
|
||||
return(false);
|
||||
}
|
||||
//---
|
||||
ArrayResize(v_normals,total_normals,total_normals+1000);
|
||||
int idx=total_normals-1;
|
||||
v_normals[idx].x=(float)StringToDouble(str_parsed[1]);
|
||||
v_normals[idx].y=(float)StringToDouble(str_parsed[2]);
|
||||
v_normals[idx].z=(float)StringToDouble(str_parsed[3]);
|
||||
v_normals[idx].w=0.0f;
|
||||
//--- debug message
|
||||
if(show_debug)
|
||||
printf("normal %d: %f %f %f",idx,v_normals[idx].x,v_normals[idx].y,v_normals[idx].z);
|
||||
//---
|
||||
break;
|
||||
}
|
||||
//--- 4. "F" lines are for each face in the model.
|
||||
//--- the values listed are indexes into the vertices, texture coordinates, and normal vectors. The format of each face is:
|
||||
//--- f Vertex1/Texture1/Normal1 Vertex2/Texture2/Normal2 Vertex3/Texture3/Normal3
|
||||
//--- so a line that says "f 3/13/5 4/14/6 5/15/7" then translates to "Vertex3/Texture13/Normal5 Vertex4/Texture14/Normal6 Vertex5/Texture15/Normal7".
|
||||
case OBJ_DATA_F:
|
||||
{
|
||||
total_faces++;
|
||||
//--- check size
|
||||
if(total_items<4)
|
||||
{
|
||||
PrintFormat("obj data error at line=%d: %s",total_lines,str);
|
||||
FileClose(file_handle);
|
||||
return(false);
|
||||
}
|
||||
//---
|
||||
ArrayResize(faces,total_faces,total_faces+1000);
|
||||
int idx=total_faces-1;
|
||||
//--- clear all face indices
|
||||
for(uint i=0; i<4; i++)
|
||||
{
|
||||
faces[idx].v[0]=0;
|
||||
faces[idx].t[0]=0;
|
||||
faces[idx].n[0]=0;
|
||||
}
|
||||
//--- read indices
|
||||
faces[idx].total=MathMin(total_items-1,4);
|
||||
for(int i=0; i<faces[idx].total; i++)
|
||||
{
|
||||
int elements=StringSplit(str_parsed[i+1],'/',str_parsed_faces);
|
||||
if(elements>0)
|
||||
faces[idx].v[i]=(int)StringToInteger(str_parsed_faces[0]);
|
||||
if(elements>1)
|
||||
faces[idx].t[i]=(int)StringToInteger(str_parsed_faces[1]);
|
||||
if(elements>2)
|
||||
faces[idx].n[i]=(int)StringToInteger(str_parsed_faces[2]);
|
||||
}
|
||||
//--- debug message
|
||||
if(show_debug)
|
||||
printf("%face d: %d vertex(%d,%d,%d,%d) texture(%d,%d,%d,%d) normal(%d,%d,%d,%d)",idx+1,
|
||||
faces[idx].v[0],faces[idx].v[1],faces[idx].v[2],faces[idx].v[3],
|
||||
faces[idx].t[0],faces[idx].t[1],faces[idx].t[2],faces[idx].t[3],
|
||||
faces[idx].n[0],faces[idx].n[1],faces[idx].n[2],faces[idx].n[3]);
|
||||
//---
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- close the file
|
||||
FileClose(file_handle);
|
||||
//---
|
||||
if(show_debug)
|
||||
{
|
||||
printf("File %s loaded successfully. Total lines: %d",filename,total_lines);
|
||||
printf("total v_positions=%d",total_positions);
|
||||
printf("total v_normals=%d",total_normals);
|
||||
printf("total v_tcoords=%d",total_tcoords);
|
||||
printf("total faces=%d",total_faces);
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Load static 3D models from Maya 2011 |
|
||||
//| https://en.wikibooks.org/wiki/DirectX/10.0/Direct3D/Loading_Maya |
|
||||
//| TVertex must have |
|
||||
//| DXVector4 position, normal and DXVector2 tcoord members |
|
||||
//+------------------------------------------------------------------+
|
||||
template <typename TVertex>
|
||||
bool DXLoadObjModel(const string filename,TVertex &vertices[],uint &indices[],float scale=1.0f)
|
||||
{
|
||||
//--- intermediate data arrays
|
||||
DXVector4 v_positions[];
|
||||
DXVector2 v_tcoords[];
|
||||
DXVector4 v_normals[];
|
||||
OBJFaceType faces[];
|
||||
//--- load data
|
||||
if(!DXLoadObjData(filename,v_positions,v_tcoords,v_normals,faces,false))
|
||||
{
|
||||
printf("Error loading model data from %s",filename);
|
||||
return(false);
|
||||
}
|
||||
//---
|
||||
int total_v_positions=ArraySize(v_positions);
|
||||
int total_v_tcoords =ArraySize(v_tcoords);
|
||||
int total_v_normals =ArraySize(v_normals);
|
||||
int total_faces =ArraySize(faces);
|
||||
//--- check faces
|
||||
if(total_faces==0)
|
||||
{
|
||||
printf("No model data.");
|
||||
return(false);
|
||||
}
|
||||
//--- check consistency of the indices
|
||||
int vertices_count=0;
|
||||
int indices_count =0;
|
||||
bool split_vertices=false;
|
||||
for(int i=0; i<total_faces; i++)
|
||||
{
|
||||
//--- each face have to be 3 or 4 sided
|
||||
if(faces[i].total<3 || faces[i].total>4)
|
||||
{
|
||||
printf("Error in %d face, face vertices count is %d",i,faces[i].total);
|
||||
return(false);
|
||||
}
|
||||
//---
|
||||
for(int j=0; j<faces[i].total; j++)
|
||||
{
|
||||
if(faces[i].v[j]<=0 || faces[i].v[j]>total_v_positions)
|
||||
{
|
||||
printf("Error in %d face, %d vertext index is %d. Total posiitons=%d",i,j,faces[i].v[j],total_v_positions);
|
||||
return(false);
|
||||
}
|
||||
if(total_v_tcoords>0)
|
||||
{
|
||||
if(faces[i].t[j]<=0 || faces[i].t[j]>total_v_tcoords)
|
||||
{
|
||||
printf("Error in %d face, %d tcoord index is %d. Total tcoords=%d",i,j,faces[i].v[j],total_v_positions);
|
||||
return(false);
|
||||
}
|
||||
if(faces[i].t[j]!=faces[i].v[j])
|
||||
split_vertices=true;
|
||||
}
|
||||
if(total_v_normals>0)
|
||||
{
|
||||
if(faces[i].n[j]<=0 || faces[i].n[j]>total_v_normals)
|
||||
{
|
||||
printf("Error in %d face, %d normal index is %d. Total normals=%d",i,j,faces[i].v[j],total_v_positions);
|
||||
return(false);
|
||||
}
|
||||
if(faces[i].n[j]!=faces[i].v[j])
|
||||
split_vertices=true;
|
||||
}
|
||||
}
|
||||
//--- calc counts
|
||||
vertices_count+=faces[i].total;
|
||||
if(faces[i].total<4)
|
||||
indices_count+=3;
|
||||
else
|
||||
indices_count+=6;
|
||||
}
|
||||
printf("Data consistency checked.");
|
||||
//--- prepare arrays
|
||||
if(!split_vertices)
|
||||
vertices_count=total_v_positions;
|
||||
ArrayResize(vertices,vertices_count);
|
||||
ArrayResize(indices, indices_count);
|
||||
int v_idx=0,i_idx=0;
|
||||
for(int i=0; i<total_faces; i++)
|
||||
{
|
||||
for(int j=0; j<faces[i].total; j++)
|
||||
{
|
||||
if(!split_vertices)
|
||||
v_idx=faces[i].v[j]-1;
|
||||
//--- posiitons
|
||||
vertices[v_idx].position.x=v_positions[faces[i].v[j]-1].x*scale;
|
||||
vertices[v_idx].position.y=v_positions[faces[i].v[j]-1].y*scale;
|
||||
vertices[v_idx].position.z=v_positions[faces[i].v[j]-1].z*scale;
|
||||
vertices[v_idx].position.w=1.0f;
|
||||
//--- normal
|
||||
if(faces[i].n[j])
|
||||
DXVec4Normalize(vertices[v_idx].normal,v_normals[faces[i].n[j]-1]);
|
||||
//--- tcoord
|
||||
if(faces[i].t[j])
|
||||
vertices[v_idx].tcoord=v_tcoords[faces[i].t[j]-1];
|
||||
//--- indices
|
||||
indices[i_idx++]=v_idx;
|
||||
//--- increment indx
|
||||
if(split_vertices)
|
||||
v_idx++;
|
||||
}
|
||||
//--- the end of second triangle in 4-sided face
|
||||
if(faces[i].total==4)
|
||||
{
|
||||
indices[i_idx]=indices[i_idx-4];
|
||||
i_idx++;
|
||||
indices[i_idx]=indices[i_idx-3];
|
||||
i_idx++;
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Box |
|
||||
//| TVertex must have |
|
||||
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
|
||||
//+------------------------------------------------------------------+
|
||||
template <typename TVertex>
|
||||
bool DXComputeBox(const DXVector3 &from,const DXVector3 &to,TVertex &vertices[],uint &indices[])
|
||||
{
|
||||
//--- prepare arrays
|
||||
const int faces=6;
|
||||
if(ArrayResize(vertices,4*faces)!=4*faces)
|
||||
return(false);
|
||||
//--- set indices
|
||||
uint ind[]= {0,1,2, 2,3,0, 4,5,6, 6,7,4, 8,9,10, 10,11,8, 12,13,14, 14,15,12, 16,17,18, 18,19,16, 20,21,22, 22,23,20};
|
||||
ArrayResize(indices,0);
|
||||
if(ArrayCopy(indices,ind)!=ArraySize(ind))
|
||||
return(false);
|
||||
//--- prepare boundaries
|
||||
float left=from.x,right=to.x,bottom=from.y,top=to.y,near=from.z,far=to.z;
|
||||
if(from.x>to.x)
|
||||
{
|
||||
right=from.x;
|
||||
left= to.x;
|
||||
}
|
||||
if(from.y>to.y)
|
||||
{
|
||||
top= from.y;
|
||||
bottom=to.y;
|
||||
}
|
||||
if(from.z>to.z)
|
||||
{
|
||||
far=from.z;
|
||||
near=to.z;
|
||||
}
|
||||
//--- left face
|
||||
vertices[0].position=DXVector4(left,top, far, 1.0);
|
||||
vertices[1].position=DXVector4(left,top, near,1.0);
|
||||
vertices[2].position=DXVector4(left,bottom,near,1.0);
|
||||
vertices[3].position=DXVector4(left,bottom,far, 1.0);
|
||||
for(int i=0; i<4; i++)
|
||||
vertices[i].normal=DXVector4(-1.0,0.0,0.0,0.0);
|
||||
//--- right face
|
||||
vertices[4].position=DXVector4(right,top, near,1.0);
|
||||
vertices[5].position=DXVector4(right,top, far, 1.0);
|
||||
vertices[6].position=DXVector4(right,bottom,far, 1.0);
|
||||
vertices[7].position=DXVector4(right,bottom,near,1.0);
|
||||
for(int i=4; i<8; i++)
|
||||
vertices[i].normal=DXVector4(1.0,0.0,0.0,0.0);
|
||||
//--- front face
|
||||
vertices[8].position =DXVector4(left, top, near,1.0);
|
||||
vertices[9].position =DXVector4(right,top, near,1.0);
|
||||
vertices[10].position=DXVector4(right,bottom,near,1.0);
|
||||
vertices[11].position=DXVector4(left, bottom,near,1.0);
|
||||
for(int i=8; i<12; i++)
|
||||
vertices[i].normal=DXVector4(0.0,0.0,-1.0,0.0);
|
||||
//--- back face
|
||||
vertices[12].position=DXVector4(right,top, far,1.0);
|
||||
vertices[13].position=DXVector4(left, top, far,1.0);
|
||||
vertices[14].position=DXVector4(left, bottom,far,1.0);
|
||||
vertices[15].position=DXVector4(right,bottom,far,1.0);
|
||||
for(int i=12; i<16; i++)
|
||||
vertices[i].normal=DXVector4(0.0,0.0,1.0,0.0);
|
||||
//--- top face
|
||||
vertices[16].position=DXVector4(left, top,far, 1.0);
|
||||
vertices[17].position=DXVector4(right,top,far, 1.0);
|
||||
vertices[18].position=DXVector4(right,top,near,1.0);
|
||||
vertices[19].position=DXVector4(left, top,near,1.0);
|
||||
for(int i=16; i<20; i++)
|
||||
vertices[i].normal=DXVector4(0.0,1.0,0.0,0.0);
|
||||
//--- bottom face
|
||||
vertices[20].position=DXVector4(left, bottom,near,1.0);
|
||||
vertices[21].position=DXVector4(right,bottom,near,1.0);
|
||||
vertices[22].position=DXVector4(right,bottom,far, 1.0);
|
||||
vertices[23].position=DXVector4(left, bottom,far, 1.0);
|
||||
for(int i=20; i<24; i++)
|
||||
vertices[i].normal=DXVector4(0.0,-1.0,0.0,0.0);
|
||||
//--- texture coordinates
|
||||
for(int i=0; i<faces; i++)
|
||||
{
|
||||
vertices[i*4+0].tcoord=DXVector2(0.0f,0.0f);
|
||||
vertices[i*4+1].tcoord=DXVector2(1.0f,0.0f);
|
||||
vertices[i*4+2].tcoord=DXVector2(1.0f,1.0f);
|
||||
vertices[i*4+3].tcoord=DXVector2(0.0f,1.0f);
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sphere |
|
||||
//| TVertex must have |
|
||||
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
|
||||
//+------------------------------------------------------------------+
|
||||
template <typename TVertex>
|
||||
bool DXComputeSphere(float radius,uint tessellation,TVertex &vertices[],uint &indices[])
|
||||
{
|
||||
if(tessellation<3)
|
||||
tessellation=3;
|
||||
uint segments_y =tessellation;
|
||||
uint segments_xz=tessellation*2;
|
||||
//--- prepare arrays
|
||||
uint count=(segments_y+1)*(segments_xz+1);
|
||||
if(ArrayResize(vertices,count)!=count)
|
||||
return(false);
|
||||
count=6*segments_y*(segments_xz);
|
||||
if(ArrayResize(indices,count)!=count)
|
||||
return(false);
|
||||
//--- create rings of vertices at progressively higher latitudes.
|
||||
for(uint i=0,idx=0; i<=segments_y; i++)
|
||||
{
|
||||
DXVector2 tcoord=DXVector2(0.0f,1.0f-(float)i/segments_y);
|
||||
float latitude=(i*DX_PI/segments_y)-DX_PI_DIV2;
|
||||
float dy =(float)sin(latitude);
|
||||
float dxz=(float)cos(latitude);
|
||||
//--- create a single ring of vertices at this latitude.
|
||||
for(uint j=0; j<=segments_xz; j++,idx++)
|
||||
{
|
||||
float longitude=(j%segments_xz)*DX_PI_MUL2/segments_xz;
|
||||
//--- normal
|
||||
DXVector3 normal=DXVector3((float)sin(longitude)*dxz,dy,(float)cos(longitude)*dxz);
|
||||
vertices[idx].normal =DXVector4(normal.x,normal.y,normal.z,0.0);
|
||||
//--- position
|
||||
DXVec3Scale(normal,normal,radius);
|
||||
vertices[idx].position=DXVector4(normal.x,normal.y,normal.z,1.0);
|
||||
//--- texture coords
|
||||
tcoord.x = float(j)/segments_xz;
|
||||
vertices[idx].tcoord =tcoord;
|
||||
}
|
||||
}
|
||||
//--- fill the index buffer with triangles joining each pair of latitude rings.
|
||||
uint stride=segments_xz+1;
|
||||
uint idx=0;
|
||||
for(uint i=0; i<segments_y; i++)
|
||||
{
|
||||
for(uint j=0; j<segments_xz; j++)
|
||||
{
|
||||
uint next_i=i+1;
|
||||
uint next_j=(j+1)%stride;
|
||||
|
||||
indices[idx++]=next_i*stride + next_j;
|
||||
indices[idx++]=next_i*stride + j;
|
||||
indices[idx++]= i*stride + j;
|
||||
|
||||
indices[idx++]= i*stride + j;
|
||||
indices[idx++]= i*stride + next_j;
|
||||
indices[idx++]=next_i*stride + next_j;
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Torus |
|
||||
//| TVertex must have |
|
||||
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
|
||||
//+------------------------------------------------------------------+
|
||||
template <typename TVertex>
|
||||
bool DXComputeTorus(float outer_radius,float inner_radius,uint tessellation,TVertex &vertices[],uint &indices[])
|
||||
{
|
||||
if(tessellation<3)
|
||||
tessellation=3;
|
||||
//--- prepare arrays
|
||||
uint count=(tessellation+1)*(tessellation+1);
|
||||
if(ArrayResize(vertices,count)!=count)
|
||||
return(false);
|
||||
count=6*tessellation*tessellation;
|
||||
if(ArrayResize(indices,count)!=count)
|
||||
return(false);
|
||||
//---
|
||||
uint v=0,idx=0;
|
||||
uint stride=tessellation+1;
|
||||
//--- first we loop around the main ring of the torus.
|
||||
for(uint i=0; i<=tessellation; i++)
|
||||
{
|
||||
DXVector2 tcoord=DXVector2(float(i)/tessellation,0.0f);
|
||||
//--- create a transform matrix that will align geometry to slice perpendicularly though the current ring position.
|
||||
DXMatrix rotation,transform;
|
||||
DXMatrixRotationY(rotation,-1.0f*(i%tessellation)*DX_PI_MUL2/tessellation-DX_PI_DIV2);
|
||||
DXMatrixTranslation(transform,outer_radius,0.0f,0.0f);
|
||||
DXMatrixMultiply(transform,transform,rotation);
|
||||
//--- now we loop along the other axis, around the side of the tube.
|
||||
for(uint j=0; j<=tessellation; j++)
|
||||
{
|
||||
//--- calc normal and position
|
||||
float angle=(j%tessellation)*DX_PI_MUL2/tessellation+DX_PI;
|
||||
vertices[v].normal=DXVector4((float)cos(angle),(float)sin(angle),0.0f,0.0f);
|
||||
vertices[v].position=DXVector4(vertices[v].normal.x*inner_radius,vertices[v].normal.y*inner_radius,0.0f,1.0f);
|
||||
DXVec4Transform(vertices[v].normal, vertices[v].normal, transform);
|
||||
DXVec4Transform(vertices[v].position,vertices[v].position,transform);
|
||||
//--- calc texture coord
|
||||
tcoord.y=1-float(j)/tessellation;
|
||||
vertices[v].tcoord=tcoord;
|
||||
v++;
|
||||
//--- create indices for two triangles.
|
||||
if(i<tessellation && j<tessellation)
|
||||
{
|
||||
uint next_i=i+1;
|
||||
uint next_j=j+1;
|
||||
|
||||
indices[idx++]=next_i*stride + next_j;
|
||||
indices[idx++]=next_i*stride + j;
|
||||
indices[idx++]= i*stride + j;
|
||||
|
||||
indices[idx++]= i*stride + j;
|
||||
indices[idx++]= i*stride + next_j;
|
||||
indices[idx++]=next_i*stride + next_j;
|
||||
}
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Cylinder |
|
||||
//| TVertex must have |
|
||||
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
|
||||
//+------------------------------------------------------------------+
|
||||
template <typename TVertex>
|
||||
bool DXComputeCylinder(float radius,float height,uint tessellation,TVertex &vertices[],uint &indices[])
|
||||
{
|
||||
return(DXComputeTruncatedCone(radius,radius,height,tessellation,vertices,indices));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Truncated Cone |
|
||||
//| TVertex must have |
|
||||
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
|
||||
//+------------------------------------------------------------------+
|
||||
template <typename TVertex>
|
||||
bool DXComputeTruncatedCone(float radius_top,float radius_bottom,float height,uint tessellation,TVertex &vertices[],uint &indices[])
|
||||
{
|
||||
if(tessellation<3)
|
||||
tessellation=3;
|
||||
//--- prepare arrays
|
||||
uint count=2*(tessellation+1)+2*tessellation;
|
||||
if(ArrayResize(vertices,count)!=count)
|
||||
return(false);
|
||||
count=6*tessellation+6*(tessellation-1);
|
||||
if(ArrayResize(indices,count)!=count)
|
||||
return(false);
|
||||
//--- prepare normal
|
||||
DXVector2 normal=DXVector2(height,radius_bottom-radius_top);
|
||||
DXVec2Normalize(normal,normal);
|
||||
float dy=height/2.0f;
|
||||
uint v=0,idx=0;
|
||||
uint stride=2;
|
||||
//--- create top and bottom rings of vertices
|
||||
for(uint i=0; i<=tessellation; i++)
|
||||
{
|
||||
float u=1.0f-(float)i/tessellation;
|
||||
float angle=(i*DX_PI_MUL2/tessellation);
|
||||
float dx=(float)sin(angle);
|
||||
float dz=(float)cos(angle);
|
||||
//---
|
||||
vertices[v].normal =DXVector4(dx*normal.x,normal.y,dz*normal.x,0.0f);
|
||||
vertices[v].position=DXVector4(dx*radius_bottom,-dy,dz*radius_bottom,1.0f);
|
||||
vertices[v].tcoord =DXVector2(u,1.0f);
|
||||
v++;
|
||||
vertices[v].normal =vertices[v-1].normal;
|
||||
vertices[v].position=DXVector4(dx*radius_top,dy,dz*radius_top,1.0f);
|
||||
vertices[v].tcoord =DXVector2(u,0.0f);
|
||||
v++;
|
||||
//--- creater side surface
|
||||
if(i<tessellation)
|
||||
{
|
||||
uint next_i=i+1;
|
||||
|
||||
indices[idx++]=next_i*stride + 1;
|
||||
indices[idx++]= i*stride + 0;
|
||||
indices[idx++]=next_i*stride + 0;
|
||||
|
||||
|
||||
indices[idx++]= i*stride + 0;
|
||||
indices[idx++]=next_i*stride + 1;
|
||||
indices[idx++]= i*stride + 1;
|
||||
}
|
||||
}
|
||||
//--- first cap vertex
|
||||
uint cap_first=v;
|
||||
//--- create caps
|
||||
for(uint i=0; i<tessellation; i++)
|
||||
{
|
||||
float angle=(i*DX_PI_MUL2/tessellation);
|
||||
float dx=(float)sin(angle);
|
||||
float dz=(float)cos(angle);
|
||||
|
||||
vertices[v].normal =DXVector4(0.0f,-1.0f,0.0f,0.0f);
|
||||
vertices[v].position=DXVector4(dx*radius_bottom,-dy,dz*radius_bottom,1.0f);
|
||||
vertices[v].tcoord =DXVector2(0.5f+0.5f*dx,0.5f+0.5f*dz);
|
||||
v++;
|
||||
vertices[v].normal =DXVector4(0.0f,1.0f,0.0f,0.0f);
|
||||
vertices[v].position=DXVector4(dx*radius_top,dy,dz*radius_top,1.0f);
|
||||
vertices[v].tcoord =DXVector2(0.5f+0.5f*dx,0.5f-0.5f*dz);
|
||||
v++;
|
||||
//--- creater caps surface
|
||||
if(i>0 && i<tessellation-1)
|
||||
{
|
||||
uint next_i=i+1;
|
||||
|
||||
indices[idx++]=cap_first;
|
||||
indices[idx++]=cap_first+next_i*stride;
|
||||
indices[idx++]=cap_first+ i*stride;
|
||||
|
||||
indices[idx++]=cap_first+1;
|
||||
indices[idx++]=cap_first+ i*stride+1;
|
||||
indices[idx++]=cap_first+next_i*stride+1;
|
||||
}
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Cone |
|
||||
//| TVertex must have |
|
||||
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
|
||||
//+------------------------------------------------------------------+
|
||||
template <typename TVertex>
|
||||
bool DXComputeCone(float radius,float height,uint tessellation,TVertex &vertices[],uint &indices[])
|
||||
{
|
||||
if(tessellation<3)
|
||||
tessellation=3;
|
||||
//--- prepare arrays
|
||||
uint count=2*(tessellation+1)+tessellation;
|
||||
if(ArrayResize(vertices,count)!=count)
|
||||
return(false);
|
||||
count=3*tessellation+3*(tessellation-1);
|
||||
if(ArrayResize(indices,count)!=count)
|
||||
return(false);
|
||||
//--- prepare normal
|
||||
DXVector2 normal=DXVector2(height,radius);
|
||||
DXVec2Normalize(normal,normal);
|
||||
float dy=height/2.0f;
|
||||
uint v=0,idx=0;
|
||||
uint stride=2;
|
||||
//--- create top and bottom rings of vertices
|
||||
for(uint i=0; i<=tessellation; i++)
|
||||
{
|
||||
float u=1.0f-(float)i/tessellation;
|
||||
float angle=(i*DX_PI_MUL2/tessellation);
|
||||
float dx=(float)sin(angle);
|
||||
float dz=(float)cos(angle);
|
||||
//---
|
||||
vertices[v].normal =DXVector4(dx*normal.x,normal.y,dz*normal.x,0.0f);
|
||||
vertices[v].position=DXVector4(dx*radius,-dy,dz*radius,1.0f);
|
||||
vertices[v].tcoord =DXVector2(u,1.0f);
|
||||
v++;
|
||||
vertices[v].normal =vertices[v-1].normal;
|
||||
vertices[v].position=DXVector4(0.0f,dy,0.0f,1.0f);
|
||||
vertices[v].tcoord =DXVector2(u,0.0f);
|
||||
v++;
|
||||
//--- creater side surface
|
||||
if(i<tessellation)
|
||||
{
|
||||
uint next_i=i+1;
|
||||
|
||||
indices[idx++]=next_i*stride + 1;
|
||||
indices[idx++]= i*stride + 0;
|
||||
indices[idx++]=next_i*stride + 0;
|
||||
}
|
||||
}
|
||||
//--- first cap vertex
|
||||
uint cap_first=v;
|
||||
//--- create caps
|
||||
for(uint i=0; i<tessellation; i++)
|
||||
{
|
||||
float angle=(i*DX_PI_MUL2/tessellation);
|
||||
float dx=(float)sin(angle);
|
||||
float dz=(float)cos(angle);
|
||||
|
||||
vertices[v].normal =DXVector4(0.0f,-1.0f,0.0f,0.0f);
|
||||
vertices[v].position=DXVector4(dx*radius,-dy,dz*radius,1.0f);
|
||||
vertices[v].tcoord =DXVector2(0.5f+0.5f*dx,0.5f+0.5f*dz);
|
||||
v++;
|
||||
//--- creater caps surface
|
||||
if(i>0 && i<tessellation-1)
|
||||
{
|
||||
indices[idx++]=cap_first;
|
||||
indices[idx++]=cap_first+i+1;
|
||||
indices[idx++]=cap_first+i;
|
||||
}
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Surface |
|
||||
//| TVertex must have |
|
||||
//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members|
|
||||
//+------------------------------------------------------------------+
|
||||
template <typename TVertex>
|
||||
bool DXComputeSurface(double &data[],uint data_width,uint data_height,double data_range,
|
||||
const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,
|
||||
bool two_sided,bool use_normals,
|
||||
TVertex &vertices[],uint &indices[])
|
||||
{
|
||||
//---
|
||||
if(data_width<2 || data_height<2)
|
||||
return(false);
|
||||
//--- prepare arrays for vertices and triangles
|
||||
uint count=data_width*data_height*(two_sided?2:1);
|
||||
if(!ArrayResize(vertices,count))
|
||||
return(false);
|
||||
count=6*(data_width-1)*(data_height-1)*(two_sided?2:1);
|
||||
if(!ArrayResize(indices,count))
|
||||
return(false);
|
||||
//--- find min and max value
|
||||
float min_value=+FLT_MAX;
|
||||
float max_value=-FLT_MAX;
|
||||
for(uint j=0; j<data_height; j++)
|
||||
for(uint i=0; i<data_width; i++)
|
||||
{
|
||||
float value=(float)data[j*data_width+i];
|
||||
if(min_value>value)
|
||||
min_value=value;
|
||||
if(max_value<value)
|
||||
max_value=value;
|
||||
}
|
||||
//--- check and fix data range
|
||||
float avg_value=0.5f*(max_value+min_value);
|
||||
float range=(float)data_range;
|
||||
if(range<=0.0f)
|
||||
range=max_value-min_value;
|
||||
if(range<FLT_EPSILON)
|
||||
range=FLT_EPSILON;
|
||||
//---
|
||||
min_value=avg_value-0.5f*range;
|
||||
max_value=avg_value+0.5f*range;
|
||||
//---
|
||||
DXVector3 range_3d;
|
||||
DXVec3Subtract(range_3d,to,from);
|
||||
float step_x=range_3d.x/(data_width-1);
|
||||
float step_y=range_3d.y/range;
|
||||
float step_z=range_3d.z/(data_height-1);
|
||||
//--- calculate vertices positions and colors
|
||||
for(uint j=0; j<data_height; j++)
|
||||
{
|
||||
for(uint i=0; i<data_width; i++)
|
||||
{
|
||||
uint idx=j*data_width+i;
|
||||
//--- calc value
|
||||
float value=(float)data[idx]-min_value;
|
||||
//--- calc position
|
||||
vertices[idx].position.x = from.x+i *step_x;
|
||||
vertices[idx].position.y = from.y+value*step_y;
|
||||
vertices[idx].position.z = from.z+j *step_z;
|
||||
vertices[idx].position.w = 1.0f;
|
||||
//--- set texture coordinates
|
||||
vertices[idx].tcoord=DXVector2(i*step_x/texture_size.x,j*step_z/texture_size.y);
|
||||
}
|
||||
}
|
||||
//--- calculate normals
|
||||
if(use_normals)
|
||||
{
|
||||
for(uint j=0; j<data_height; j++)
|
||||
{
|
||||
for(uint i=0; i<data_width; i++)
|
||||
{
|
||||
DXVector4 v1,v2,normal;
|
||||
//--- v1
|
||||
if(i<=0)
|
||||
DXVec4Subtract(v1,vertices[j*data_width+i].position,vertices[j*data_width+i+1].position);
|
||||
else
|
||||
if(i>=data_width-1)
|
||||
DXVec4Subtract(v1,vertices[j*data_width+i-1].position,vertices[j*data_width+i].position);
|
||||
else
|
||||
DXVec4Subtract(v1,vertices[j*data_width+i-1].position,vertices[j*data_width+i+1].position);
|
||||
//--- v2
|
||||
if(j<=0)
|
||||
DXVec4Subtract(v2,vertices[j*data_width+i].position,vertices[(j+1)*data_width+i].position);
|
||||
else
|
||||
if(j>=data_height-1)
|
||||
DXVec4Subtract(v2,vertices[(j-1)*data_width+i].position,vertices[j*data_width+i].position);
|
||||
else
|
||||
DXVec4Subtract(v2,vertices[(j-1)*data_width+i].position,vertices[(j+1)*data_width+i].position);
|
||||
//--- normal
|
||||
DXVec4Cross(normal,v2,v1,DXVector4(0.0f,0.0f,0.0f,1.0f));
|
||||
float inv_len=(float)(1.0/sqrt(normal.x*normal.x+normal.y*normal.y+normal.z*normal.z));
|
||||
vertices[j*data_width+i].normal.x=normal.x*inv_len;
|
||||
vertices[j*data_width+i].normal.y=normal.y*inv_len;
|
||||
vertices[j*data_width+i].normal.z=normal.z*inv_len;
|
||||
vertices[j*data_width+i].normal.w=0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DXVector4 n=DXVector4(0.0f,0.0f,0.0f,0.0f);
|
||||
for(int i=0; i<ArraySize(vertices); i++)
|
||||
vertices[i].normal=n;
|
||||
}
|
||||
//--- calculate triangles for every rectangle
|
||||
int n=0;
|
||||
for(uint i=0; i<data_width-1; i++)
|
||||
{
|
||||
for(uint j=0; j<data_height-1; j++)
|
||||
{
|
||||
//--- left triangle
|
||||
indices[n++]=j*data_width+(i+1);
|
||||
indices[n++]=j*data_width+i;
|
||||
indices[n++]=(j+1)*data_width+i;
|
||||
//--- right triangle
|
||||
indices[n++]=(j+1)*data_width+(i+1);
|
||||
indices[n++]=j*data_width+(i+1);
|
||||
indices[n++]=(j+1)*data_width+(i);
|
||||
}
|
||||
}
|
||||
//--- generate back side
|
||||
if(two_sided)
|
||||
{
|
||||
uint offset=data_height*data_width;
|
||||
for(uint j=0; j<data_height; j++)
|
||||
{
|
||||
for(uint i=0; i<data_width; i++)
|
||||
{
|
||||
uint idx=offset+j*data_width+i;
|
||||
//--- copy vertices in backward direction
|
||||
vertices[idx]=vertices[j*data_width+data_width-i-1];
|
||||
//--- inverse normals
|
||||
DXVec4Scale(vertices[idx].normal,vertices[idx].normal,-1.0f);
|
||||
}
|
||||
}
|
||||
//--- calculate triangles for opposit side
|
||||
for(uint i=0; i<data_width-1; i++)
|
||||
{
|
||||
for(uint j=0; j<data_height-1; j++)
|
||||
{
|
||||
//--- left triangle
|
||||
indices[n++]=offset+j*data_width+(i+1);
|
||||
indices[n++]=offset+j*data_width+i;
|
||||
indices[n++]=offset+(j+1)*data_width+i;
|
||||
//--- right triangle
|
||||
indices[n++]=offset+(j+1)*data_width+(i+1);
|
||||
indices[n++]=offset+j*data_width+(i+1);
|
||||
indices[n++]=offset+(j+1)*data_width+(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+---------------------------------------------------------------------+
|
||||
//| Computes Matlab jet color scheme colors on [0;1] range |
|
||||
//| dark blue > blue > light blue > green > yellow > red > dark red |
|
||||
//+---------------------------------------------------------------------+
|
||||
void DXComputeColorJet(const float value,DXColor &cout)
|
||||
{
|
||||
float v=value*1.1f-0.05f;
|
||||
cout.r = fmin(fmax(v<0.75f ? 4*v-1.5f : 4.5f-4*v,0.0f),1.0f);
|
||||
cout.g = fmin(fmax(v<0.5f ? 4*v-0.5f : 3.5f-4*v,0.0f),1.0f);
|
||||
cout.b = fmin(fmax(v<0.25f ? 4*v+0.5f : 2.5f-4*v,0.0f),1.0f);
|
||||
cout.a = 1.0;
|
||||
}
|
||||
//+---------------------------------------------------------------------+
|
||||
//| Computes hot to cold color scheme colors on [0;1] range |
|
||||
//| blue > light blue > green > yellow > red |
|
||||
//+---------------------------------------------------------------------+
|
||||
void DXComputeColorColdToHot(const float value,DXColor &cout)
|
||||
{
|
||||
float v=2*value-1.0f;
|
||||
cout.r = fmin(fmax(2*v,0.0f),1.0f);
|
||||
cout.g = fmin(fmax(2.0f-2*fabs(v),0.0f),1.0f);
|
||||
cout.b = fmin(fmax(-2*v,0.0f),1.0f);
|
||||
cout.a = 1.0;
|
||||
}
|
||||
//+---------------------------------------------------------------------+
|
||||
//| Computes red to green color scheme colors on [0;1] range |
|
||||
//| red > yellow > dark green |
|
||||
//+---------------------------------------------------------------------+
|
||||
void DXComputeColorRedToGreen(const float value,DXColor &cout)
|
||||
{
|
||||
if(value<=0.5)
|
||||
{
|
||||
cout.r=1.0f;
|
||||
cout.g=DXScalarLerp(0.01f,0.95f,fmin(fmax(2*value,0.0f),1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
cout.r=DXScalarLerp(0.1f,1.0f, fmin(fmax(2.0f-2*value,0.0f),1.0f));
|
||||
cout.g=DXScalarLerp(0.6f,0.95f,fmin(fmax(2.0f-2*value,0.0f),1.0f));
|
||||
}
|
||||
cout.b=0.0f;
|
||||
cout.a=1.0f;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,71 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Default Pixel Shader |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inputs for whole scene |
|
||||
//+------------------------------------------------------------------+
|
||||
cbuffer InputScene : register(b0)
|
||||
{
|
||||
matrix view;
|
||||
matrix projection;
|
||||
float4 light_direction;
|
||||
float4 light_color;
|
||||
float4 ambient_color;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inputs for single object |
|
||||
//+------------------------------------------------------------------+
|
||||
cbuffer InputObject : register(b1)
|
||||
{
|
||||
matrix transform;
|
||||
float4 diffuse_color;
|
||||
float4 emission_color;
|
||||
float4 specular_color;
|
||||
float specular_power;
|
||||
float dummy[3];
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Input texture |
|
||||
//+------------------------------------------------------------------+
|
||||
Texture2D<float4> diffuse_tex : register(t0);
|
||||
//+------------------------------------------------------------------+
|
||||
//| Texture sampler |
|
||||
//+------------------------------------------------------------------+
|
||||
SamplerState diffuse_samp
|
||||
{
|
||||
Filter =MIN_MAG_MIP_LINEAR;
|
||||
AddressU=Wrap;
|
||||
AddressV=Wrap;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Pixel shader input type |
|
||||
//+------------------------------------------------------------------+
|
||||
struct PSInput
|
||||
{
|
||||
float4 position : SV_POSITION;
|
||||
float4 camera : CAMERA;
|
||||
float4 normal : NORMAL;
|
||||
float2 tcoord : TEXCOORD;
|
||||
float4 color : COLOR;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Pixel shader entry point |
|
||||
//+------------------------------------------------------------------+
|
||||
float4 PSMain(PSInput input) : SV_TARGET
|
||||
{
|
||||
float3 diffuse =saturate(-dot(light_direction.xyz,input.normal.xyz))*light_color.rgb*light_color.a;
|
||||
float3 ambient =ambient_color.rgb *ambient_color.a;
|
||||
float3 light =(diffuse+ambient)*diffuse_color.rgb*diffuse_color.a+emission_color.rgb*emission_color.a;
|
||||
float4 specular=float4(light_color.rgb*specular_color.rgb,pow(saturate(dot(reflect(normalize(light_direction.xyz),input.normal.xyz),normalize(input.camera.xyz))),specular_power)*light_color.a*specular_color.a);
|
||||
float4 clr=input.color;
|
||||
//--- use texture if it exist
|
||||
uint width,height;
|
||||
diffuse_tex.GetDimensions(width,height);
|
||||
if(width*height>0)
|
||||
clr*=diffuse_tex.Sample(diffuse_samp,frac(input.tcoord));
|
||||
//--- combine light with colors
|
||||
return(lerp(float4(light*clr.rgb,clr.a),float4(specular.rgb,1.0),specular.a));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,72 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Default Vertex Shader |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inputs for whole scene |
|
||||
//+------------------------------------------------------------------+
|
||||
cbuffer InputScene : register(b0)
|
||||
{
|
||||
matrix view;
|
||||
matrix projection;
|
||||
float4 light_direction;
|
||||
float4 light_color;
|
||||
float4 ambient_color;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inputs for single object |
|
||||
//+------------------------------------------------------------------+
|
||||
cbuffer InputObject : register(b1)
|
||||
{
|
||||
matrix transform;
|
||||
float4 diffuse_color;
|
||||
float4 emission_color;
|
||||
float4 specular_color;
|
||||
float specular_power;
|
||||
float dummy[3];
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Vertex shader input type |
|
||||
//+------------------------------------------------------------------+
|
||||
struct VSInput
|
||||
{
|
||||
float4 position : POSITION;
|
||||
float4 normal : NORMAL;
|
||||
float2 tcoord : TEXCOORD;
|
||||
float4 color : COLOR;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Pixel shader input type |
|
||||
//+------------------------------------------------------------------+
|
||||
struct PSInput
|
||||
{
|
||||
float4 position : SV_POSITION;
|
||||
float4 camera : CAMERA;
|
||||
float4 normal : NORMAL;
|
||||
float2 tcoord : TEXCOORD;
|
||||
float4 color : COLOR;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Vertex shader entry point |
|
||||
//+------------------------------------------------------------------+
|
||||
PSInput VSMain(VSInput input)
|
||||
{
|
||||
PSInput output;
|
||||
//--- posiiton and camera direction
|
||||
output.position=mul(input .position,transform);
|
||||
output.position=mul(output.position,view);
|
||||
output.camera =-output.position;
|
||||
output.position=mul(output.position,projection);
|
||||
//--- transform normals
|
||||
output.normal = mul(input.normal, transform);
|
||||
output.normal = mul(output.normal, view);
|
||||
output.normal = normalize(output.normal);
|
||||
//--- color and texture coordinates
|
||||
output.tcoord =input.tcoord;
|
||||
output.color =input.color;
|
||||
//---
|
||||
return(output);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,751 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| FlameCanvas.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Canvas.mqh"
|
||||
#include <Controls\Defines.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gradient descriptors |
|
||||
//+------------------------------------------------------------------+
|
||||
struct GRADIENT_COLOR
|
||||
{
|
||||
uint clr; // color in ARGB format
|
||||
uint pos; // position of color in percentage of gradient range
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
struct GRADIENT_SIZE
|
||||
{
|
||||
uint size; // width of gradient fill in percentage of base fill
|
||||
uint pos; // position of color in percentage of gradient length
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CFlameCanvas |
|
||||
//| Usage: generates flame |
|
||||
//+------------------------------------------------------------------+
|
||||
class CFlameCanvas : public CCanvas
|
||||
{
|
||||
private:
|
||||
//--- parameters
|
||||
uint m_bar_gap;
|
||||
uint m_bar_width;
|
||||
uint m_chart_scale;
|
||||
double m_chart_price_min;
|
||||
double m_chart_price_max;
|
||||
ENUM_TIMEFRAMES m_timeframe;
|
||||
string m_symbol;
|
||||
int m_future_bars;
|
||||
int m_back_bars;
|
||||
int m_rates_total;
|
||||
uint m_palette[256]; // flame palette
|
||||
uchar m_flame[]; // buffer for calculation of flame
|
||||
uint m_time_redraw;
|
||||
uint m_delay;
|
||||
// bool m_resize_flag;
|
||||
// int m_tick_cnt;
|
||||
//--- flame parameters
|
||||
datetime m_tb1;
|
||||
double m_pb1;
|
||||
datetime m_te1;
|
||||
double m_pe1;
|
||||
datetime m_tb2;
|
||||
double m_pb2;
|
||||
datetime m_te2;
|
||||
double m_pe2;
|
||||
//--- equation parameters for flame
|
||||
int m_cloud_axis[100];
|
||||
double m_a1;
|
||||
double m_b1;
|
||||
double m_a2;
|
||||
double m_b2;
|
||||
int m_xb1;
|
||||
int m_yb1;
|
||||
int m_xe1;
|
||||
int m_ye1;
|
||||
int m_xb2;
|
||||
int m_yb2;
|
||||
int m_xe2;
|
||||
int m_ye2;
|
||||
|
||||
public:
|
||||
CFlameCanvas(void);
|
||||
~CFlameCanvas(void);
|
||||
//--- create
|
||||
bool FlameCreate(const string name,const datetime time,const int future_bars,const int back_bars=0);
|
||||
void RatesTotal(const int value);
|
||||
//--- setting
|
||||
void PaletteSet(uint clr=0xFF0000);
|
||||
//--- draw
|
||||
void FlameDraw(const double &prices[],const int width,const int lenght);
|
||||
void FlameSet(datetime xb1,double yb1,datetime xe1,double ye1,datetime xb2,double yb2,datetime xe2,double ye2);
|
||||
//--- event handler
|
||||
void ChartEventHandler(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
|
||||
protected:
|
||||
bool Resize(void);
|
||||
void ChartScale(void);
|
||||
void FlameSet(void);
|
||||
void CloudDraw(const double &prices[],const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[],const uchar t_level=255,const bool custom_gradient=true);
|
||||
void FlameDraw(const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[]);
|
||||
void GradientVertical(const int xb,const int xe,const int yb1,const int ye1,const int yb2,const int ye2,const GRADIENT_COLOR &gradient[]);
|
||||
void GradientVerticalLine(int x,int y1,int y2,const GRADIENT_COLOR &gradient[]);
|
||||
void GradientVerticalLineMonochrome(int x,int y1,int y2,uint clr1,uint clr2);
|
||||
void FlameCreate(void);
|
||||
void FlameCalculate(void);
|
||||
void Delay(const uint value);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFlameCanvas::CFlameCanvas(void) : m_bar_gap(16),
|
||||
m_bar_width(8),
|
||||
m_chart_scale(1),
|
||||
m_chart_price_min(0.0),
|
||||
m_chart_price_max(0.0),
|
||||
m_timeframe(PERIOD_CURRENT),
|
||||
m_symbol(NULL),
|
||||
m_future_bars(0),
|
||||
m_back_bars(0),
|
||||
m_rates_total(0),
|
||||
m_time_redraw(0),
|
||||
m_delay(50),
|
||||
m_tb1(0),
|
||||
m_pb1(0),
|
||||
m_te1(0),
|
||||
m_pe1(0),
|
||||
m_tb2(0),
|
||||
m_pb2(0),
|
||||
m_te2(0),
|
||||
m_pe2(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CFlameCanvas::~CFlameCanvas(void)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Creates dynamic resource with object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFlameCanvas::FlameCreate(const string name,const datetime time,const int future_bars,const int back_bars)
|
||||
{
|
||||
//--- get chart parameters
|
||||
ChartScale();
|
||||
//--- create
|
||||
int width =(int)m_bar_gap*(future_bars+back_bars);
|
||||
int height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS);
|
||||
if(!CreateBitmap(0,0,name,time-back_bars*PeriodSeconds(),m_chart_price_max,width,height,COLOR_FORMAT_ARGB_NORMALIZE))
|
||||
return(false);
|
||||
ArrayResize(m_flame,width*height);
|
||||
//--- save parameters
|
||||
m_future_bars=future_bars;
|
||||
m_back_bars =back_bars;
|
||||
//--- settings
|
||||
PaletteSet();
|
||||
m_timeframe =Period();
|
||||
m_symbol =Symbol();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resize |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CFlameCanvas::Resize(void)
|
||||
{
|
||||
int x,y;
|
||||
//--- get limits
|
||||
double min=ChartGetDouble(0,CHART_PRICE_MIN);
|
||||
double max=ChartGetDouble(0,CHART_PRICE_MAX);
|
||||
if(m_chart_price_max!=max)
|
||||
{
|
||||
//--- move object
|
||||
ObjectSetDouble(0,m_objname,OBJPROP_PRICE,0,max);
|
||||
}
|
||||
//--- check
|
||||
if(m_chart_price_min==min && m_chart_price_max==max)
|
||||
return(false);
|
||||
m_chart_price_min=min;
|
||||
m_chart_price_max=max;
|
||||
//--- grt size
|
||||
ChartTimePriceToXY(0,0,m_tb1,min,x,y);
|
||||
int width =(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS)-x;
|
||||
int height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS);
|
||||
//--- resize
|
||||
if(width<m_width)
|
||||
width=m_width;
|
||||
if(width<=0)
|
||||
return(false);
|
||||
CCanvas::Resize(width,height);
|
||||
//--- resize flame buffer
|
||||
ArrayResize(m_flame,width*height);
|
||||
ArrayInitialize(m_flame,0);
|
||||
ArrayInitialize(m_pixels,0);
|
||||
//--- restore parameters
|
||||
if(m_pb1!=0.0)
|
||||
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::RatesTotal(const int value)
|
||||
{
|
||||
if(value==0)
|
||||
return;
|
||||
if(m_rates_total==0)
|
||||
m_rates_total=value;
|
||||
else
|
||||
{
|
||||
if(m_rates_total!=value)
|
||||
{
|
||||
//--- move object
|
||||
ObjectSetInteger(0,m_objname,OBJPROP_TIME,0,
|
||||
ObjectGetInteger(0,m_objname,OBJPROP_TIME)+(value-m_rates_total)*PeriodSeconds());
|
||||
m_rates_total=value;
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adjusts to the chart scale |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::ChartScale(void)
|
||||
{
|
||||
m_chart_scale=(uint)ChartGetInteger(0,CHART_SCALE);
|
||||
//--- set params
|
||||
switch(m_chart_scale)
|
||||
{
|
||||
case 0:
|
||||
m_bar_gap =1;
|
||||
m_bar_width=1;
|
||||
break;
|
||||
case 1:
|
||||
m_bar_gap =2;
|
||||
m_bar_width=1;
|
||||
break;
|
||||
case 2:
|
||||
m_bar_gap =4;
|
||||
m_bar_width=2;
|
||||
break;
|
||||
case 3:
|
||||
m_bar_gap =8;
|
||||
m_bar_width=4;
|
||||
break;
|
||||
case 4:
|
||||
m_bar_gap =16;
|
||||
m_bar_width=10;
|
||||
break;
|
||||
case 5:
|
||||
m_bar_gap =32;
|
||||
m_bar_width=22;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets palette |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::PaletteSet(uint clr)
|
||||
{
|
||||
//--- create palette
|
||||
double g=0,b=0,dg=1.45,db=0.63;
|
||||
//---
|
||||
for(uint a,i=0;i<256;i++)
|
||||
{
|
||||
//--- the first 32 values ??of flame are completely transparent
|
||||
a=uchar(i<32?0:i-32);
|
||||
//--- generate color for the i value of flame
|
||||
m_palette[i]=(a<<24)|(uint(255)<<16)|(uint(g+0.5)<<8)|uint(b+0.5);
|
||||
//--- increment the color components
|
||||
//--- the red color gets gradient due to transparency
|
||||
if(i>80) g+=dg;
|
||||
if(i>160) b+=db;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws the flame |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::FlameDraw(const double &prices[],const int width,const int lenght)
|
||||
{
|
||||
static GRADIENT_SIZE sword[]={{100,0},{150,70},{0,100}};
|
||||
static GRADIENT_COLOR flame[]={{0x00,0},{0x7F7F7F,12},{0xCCCCCC,30},{0xFFFFFF,45},{0xFFFFFF,55},{0xCCCCCC,70},{0x7F7F7F,88},{0x00,100}};
|
||||
//--- draw
|
||||
CloudDraw(prices,width,lenght,sword,flame);
|
||||
//--- copy flame buffer
|
||||
FlameCalculate();
|
||||
//--- start timer
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::FlameDraw(const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[])
|
||||
{
|
||||
//--- check
|
||||
int total=ArraySize(m_cloud_axis);
|
||||
if(total<2)
|
||||
return;
|
||||
if(total>lenght)
|
||||
total=lenght;
|
||||
//--- draw
|
||||
int xb,xe; // coordinates of the segment
|
||||
int ybm,yem; // coordinates of the center line
|
||||
int yb1,ye1; // coordinates of the first line
|
||||
int yb2,ye2; // coordinates of the second line
|
||||
//--- for implementation of variable width
|
||||
int w_total=ArraySize(size);
|
||||
if(w_total<2)
|
||||
return;
|
||||
int w_i =0;
|
||||
int w_is=(int)size[w_i].pos*total/100;
|
||||
int w_ie=(int)size[w_i+1].pos*total/100;
|
||||
double w =size[w_i].size*width/100;
|
||||
double dw =(size[w_i+1].size*width/100-w)/(w_ie-w_is);
|
||||
//--- draw from left to right
|
||||
xb=0;
|
||||
ybm=m_cloud_axis[0];
|
||||
yb1=ybm-(int)(w/2);
|
||||
yb2=ybm+(int)(w/2);
|
||||
//--- draw
|
||||
for(int i=1;i<total;i++)
|
||||
{
|
||||
xe=(int)(i*m_bar_gap);
|
||||
if(m_cloud_axis[i]==DBL_MAX)
|
||||
continue;
|
||||
yem=m_cloud_axis[i];
|
||||
w+=dw;
|
||||
ye1=yem-(int)(w/2);
|
||||
ye2=yem+(int)(w/2);
|
||||
//--- draw the segment of 'cloud'
|
||||
GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient);
|
||||
xb=xe;
|
||||
if(xb>=m_width)
|
||||
break;
|
||||
yb1=ye1;
|
||||
yb2=ye2;
|
||||
while(i>=w_ie-1 && i!=total-1)
|
||||
{
|
||||
w_i++;
|
||||
w_is=(int)size[w_i].pos*total/100;
|
||||
w_ie=(int)size[w_i+1].pos*total/100;
|
||||
w =size[w_i].size*width/100;
|
||||
if(w_ie==w_is)
|
||||
{
|
||||
//--- for "instant" resize
|
||||
dw=size[w_i+1].size*width/100-w;
|
||||
w+=dw;
|
||||
ye1=yem-(int)(w/2);
|
||||
ye2=yem+(int)(w/2);
|
||||
//--- draw the segment of 'cloud'
|
||||
GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient);
|
||||
yb1=ye1;
|
||||
yb2=ye2;
|
||||
}
|
||||
else
|
||||
{
|
||||
dw=(size[w_i+1].size*width/100-w)/(w_ie-w_is);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//--- copy flame buffer
|
||||
FlameCalculate();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets parameters of the flame and starts to draw |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::FlameSet(void)
|
||||
{
|
||||
m_a1=m_bar_gap*((m_ye1-m_yb1)/((double)m_xe1-m_xb1));
|
||||
m_a2=m_bar_gap*((m_ye2-m_yb2)/((double)m_xe2-m_xb2));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets parameters of the flame and starts to draw |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::FlameSet(datetime tb1,double pb1,
|
||||
datetime te1,double pe1,
|
||||
datetime tb2,double pb2,
|
||||
datetime te2,double pe2)
|
||||
{
|
||||
datetime obj_time =(datetime)ObjectGetInteger(0,m_objname,OBJPROP_TIME);
|
||||
double obj_price=ObjectGetDouble(0,m_objname,OBJPROP_PRICE);
|
||||
int dx,dy;
|
||||
//--- save parameters
|
||||
m_tb1=tb1;
|
||||
m_pb1=pb1;
|
||||
m_te1=te1;
|
||||
m_pe1=pe1;
|
||||
m_tb2=tb2;
|
||||
m_pb2=pb2;
|
||||
m_te2=te2;
|
||||
m_pe2=pe2;
|
||||
//--- resize
|
||||
Resize();
|
||||
//--- convert
|
||||
if(ChartTimePriceToXY(0,0,obj_time,obj_price,dx,dy))
|
||||
{
|
||||
dy=m_yb1;
|
||||
if(ChartTimePriceToXY(0,0,tb1,pb1,m_xb1,m_yb1))
|
||||
if(ChartTimePriceToXY(0,0,te1,pe1,m_xe1,m_ye1))
|
||||
if(ChartTimePriceToXY(0,0,tb2,pb2,m_xb2,m_yb2))
|
||||
if(ChartTimePriceToXY(0,0,te2,pe2,m_xe2,m_ye2))
|
||||
{
|
||||
//--- convert to canvas coordinates
|
||||
m_xb1-=dx;
|
||||
m_xe1-=dx;
|
||||
m_xb2-=dx;
|
||||
m_xe2-=dx;
|
||||
//---
|
||||
FlameSet();
|
||||
}
|
||||
}
|
||||
//--- start timer
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Generate array that describes the body of flame |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::FlameCreate(void)
|
||||
{
|
||||
static GRADIENT_SIZE sword[]={{100,0},{150,70},{0,100}};
|
||||
static GRADIENT_COLOR flame[]={{0x00,0},{0x7F7F7F,12},{0xCCCCCC,30},{0xFFFFFF,45},{0xFFFFFF,55},{0xCCCCCC,70},{0x7F7F7F,88},{0x00,100}};
|
||||
//---
|
||||
double a=rand(); // parameter of line a*x+b
|
||||
double b=rand(); // parameter of line a*x+b
|
||||
double c=rand(); // parameter of sine c*Sin(d*x)
|
||||
double d=rand(); // parameter of sine c*Sin(d*x)
|
||||
int w=rand(); // width at the base
|
||||
int l=rand(); // length
|
||||
//--- normalize
|
||||
a=fmod(a,(m_a2-m_a1))+m_a1;
|
||||
b=(m_yb1+m_yb2)/2;
|
||||
c=fmod(c,20);
|
||||
d=fmod(d,3*M_PI)+M_PI;
|
||||
//--- shape
|
||||
w%=150;
|
||||
if(w<10)
|
||||
w=10; // but no less than 10
|
||||
sword[1].size=w;
|
||||
w=rand();
|
||||
l%=50;
|
||||
sword[1].pos=l+30;
|
||||
l=rand();
|
||||
//--- sizes
|
||||
w=(m_yb2-m_yb1!=0) ? w%(m_yb2-m_yb1) : 10; // proportional to the starting width
|
||||
if(w<10)
|
||||
w=10; // but no less than 10
|
||||
l=l%((m_xe1-m_xb1)/(int)m_bar_gap-20)+20; // proportional to length
|
||||
//--- create
|
||||
int total=ArraySize(m_cloud_axis);
|
||||
for(int i=0;i<total;i++)
|
||||
m_cloud_axis[i]=int(a*i+b+c*sin(i/d));
|
||||
//--- draw
|
||||
FlameDraw(w,l,sword,flame);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Calculates and renders frame |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::FlameCalculate(void)
|
||||
{
|
||||
//--- calculate new frame
|
||||
int c;
|
||||
int idx;
|
||||
//--- draw body of flame to the right
|
||||
for(int x=0,x_tot=m_width-1;x<x_tot;x++)
|
||||
{
|
||||
//--- separately for y==0
|
||||
c=m_flame[x]+m_flame[x+m_width];
|
||||
c+=+m_flame[x]+m_flame[x+m_width];
|
||||
m_flame[x]=uchar(c/4);
|
||||
//---
|
||||
for(int y=1,y_tot=m_height-1;y<y_tot;y++)
|
||||
{
|
||||
idx=y*m_width+x;
|
||||
c=m_flame[idx-m_width]+m_flame[idx]+m_flame[idx+m_width];
|
||||
idx++;
|
||||
c+=m_flame[idx-m_width]+m_flame[idx]+m_flame[idx+m_width];
|
||||
m_flame[idx]=uchar(c/6);
|
||||
}
|
||||
//--- separately for y==m_height-1
|
||||
idx=(m_height-1)*m_width+x;
|
||||
c=m_flame[idx-m_width]+m_flame[idx];
|
||||
idx++;
|
||||
c+=m_flame[idx-m_width]+m_flame[idx];
|
||||
m_flame[idx]=uchar(c/4);
|
||||
}
|
||||
//--- move flame to the resource buffer
|
||||
for(int y=0;y<m_height;y++)
|
||||
{
|
||||
for(int x=0;x<m_width;x++)
|
||||
{
|
||||
idx=y*m_width+x;
|
||||
m_pixels[idx]=m_palette[m_flame[idx]];
|
||||
}
|
||||
}
|
||||
//---
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws "cloud" |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::CloudDraw(const double &prices[],const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[],const uchar t_level,const bool custom_gradient)
|
||||
{
|
||||
//--- check
|
||||
int total=ArraySize(prices);
|
||||
if(total<2)
|
||||
return;
|
||||
if(total>lenght)
|
||||
total=lenght;
|
||||
//--- draw
|
||||
int xb,xe; // coordinates of the segment
|
||||
int ybm,yem; // coordinates of the center line
|
||||
int yb1,ye1; // coordinates of the first line
|
||||
int yb2,ye2; // coordinates of the second line
|
||||
int xx;
|
||||
//--- for implementation of variable width
|
||||
int w_total=ArraySize(size);
|
||||
if(w_total<2)
|
||||
return;
|
||||
int w_i =0;
|
||||
int w_is=(int)size[w_i].pos*total/100;
|
||||
int w_ie=(int)size[w_i+1].pos*total/100;
|
||||
double w =size[w_i].size*width/100;
|
||||
double dw =(size[w_i+1].size*width/100-w)/(w_ie-w_is);
|
||||
//--- draw from left to right
|
||||
xb=0;
|
||||
ChartTimePriceToXY(0,0,0,prices[0],xx,ybm);
|
||||
yb1=ybm-(int)(w/2);
|
||||
yb2=ybm+(int)(w/2);
|
||||
//--- draw
|
||||
for(int i=1;i<total;i++)
|
||||
{
|
||||
xe=(int)(i*m_bar_gap);
|
||||
if(prices[i]==DBL_MAX)
|
||||
continue;
|
||||
ChartTimePriceToXY(0,0,0,prices[i],xx,yem);
|
||||
w+=dw;
|
||||
ye1=yem-(int)(w/2);
|
||||
ye2=yem+(int)(w/2);
|
||||
//--- draw the segment of 'cloud'
|
||||
GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient);
|
||||
xb=xe;
|
||||
if(xb>=m_width)
|
||||
break;
|
||||
yb1=ye1;
|
||||
yb2=ye2;
|
||||
while(i>=w_ie-1 && i!=total-1)
|
||||
{
|
||||
w_i++;
|
||||
w_is=(int)size[w_i].pos*total/100;
|
||||
w_ie=(int)size[w_i+1].pos*total/100;
|
||||
w =size[w_i].size*width/100;
|
||||
if(w_ie==w_is)
|
||||
{
|
||||
//--- for "instant" resize
|
||||
dw=size[w_i+1].size*width/100-w;
|
||||
w+=dw;
|
||||
ye1=yem-(int)(w/2);
|
||||
ye2=yem+(int)(w/2);
|
||||
//--- draw the segment of 'cloud'
|
||||
GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient);
|
||||
yb1=ye1;
|
||||
yb2=ye2;
|
||||
}
|
||||
else
|
||||
{
|
||||
dw=(size[w_i+1].size*width/100-w)/(w_ie-w_is);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws area with vertical fill using specified gradient |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::GradientVertical(const int xb,const int xe,const int yb1,const int ye1,const int yb2,const int ye2,const GRADIENT_COLOR &gradient[])
|
||||
{
|
||||
//--- it is assumed that the colors array has sufficient size and positions are already sorted in ascending order
|
||||
//--- get length by X and Y
|
||||
int x1 =xb;
|
||||
int y1 =yb1;
|
||||
int x2 =xb;
|
||||
int y2 =yb2;
|
||||
int dx =(xe>xb)? xe-xb : xb-xe;
|
||||
int dy1=(ye1>yb1)? ye1-yb1 : yb1-ye1;
|
||||
int dy2=(ye2>yb2)? ye2-yb2 : yb2-ye2;
|
||||
//--- get direction by X and Y
|
||||
int sx =(xb<xe)? 1 : -1;
|
||||
int sy1=(yb1<ye1)? 1 : -1;
|
||||
int sy2=(yb2<ye2)? 1 : -1;
|
||||
int er1=dx-dy1;
|
||||
int er2=dx-dy2;
|
||||
//--- extreme colors
|
||||
uint clr_first=gradient[0].clr;
|
||||
uint clr_last =gradient[ArraySize(gradient)-1].clr;
|
||||
//--- draw the first line
|
||||
while(x1!=xe || y1!=ye1)
|
||||
{
|
||||
//--- calculate coordinates of next pixel of the first line
|
||||
if((er1<<1)>-dy1)
|
||||
{
|
||||
//--- try to change X coordinate of the first line
|
||||
//--- draw the second line
|
||||
while(x2!=xe || y2!=ye2)
|
||||
{
|
||||
//--- calculate coordinates of next pixel of the second line
|
||||
if((er2<<1)>-dy2)
|
||||
{
|
||||
//--- try to change X coordinate of the second line
|
||||
//--- gradient fill
|
||||
GradientVerticalLine(x1,y1,y2,gradient);
|
||||
er2-=dy2;
|
||||
if(x2!=xe)
|
||||
x2+=sx;
|
||||
}
|
||||
if((er2<<1)<dx)
|
||||
{
|
||||
er2+=dx;
|
||||
if(y2!=ye2)
|
||||
y2+=sy2;
|
||||
}
|
||||
//--- draw the first line
|
||||
if(x1!=x2)
|
||||
break;
|
||||
}
|
||||
er1-=dy1;
|
||||
if(x1!=xe)
|
||||
x1+=sx;
|
||||
}
|
||||
if((er1<<1)<dx)
|
||||
{
|
||||
er1+=dx;
|
||||
if(y1!=ye1)
|
||||
y1+=sy1;
|
||||
}
|
||||
}
|
||||
//--- gradient fill
|
||||
GradientVerticalLine(x1,ye1,ye2,gradient);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws gradient vertical line |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::GradientVerticalLineMonochrome(int x,int y1,int y2,uint clr1,uint clr2)
|
||||
{
|
||||
//---
|
||||
double dc;
|
||||
int dd,dy=y2-y1;
|
||||
//--- check
|
||||
if(dy==0)
|
||||
return;
|
||||
//--- extract components from the first color
|
||||
uchar clr=(uchar)clr1;
|
||||
//--- parameters of pixels iteration
|
||||
if(dy>0)
|
||||
{
|
||||
dd=dy;
|
||||
dy=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dd=-dy;
|
||||
dy=-1;
|
||||
}
|
||||
//--- increments for the color components
|
||||
dc=(double)((uchar)clr2-clr)/dd;
|
||||
//--- draw
|
||||
for(int i=0;y1!=y2;i++,y1+=dy)
|
||||
{
|
||||
int idx=y1*m_width+x;
|
||||
//--- check range
|
||||
if(idx<0 || idx>=ArraySize(m_flame))
|
||||
continue;
|
||||
if(x>=0 && x<m_width && y1>=0 && y1<m_height)
|
||||
if(m_flame[idx]<(uchar)(clr+dc*i))
|
||||
m_flame[idx]=(uchar)(clr+dc*i);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws vertical line with specified gradient |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::GradientVerticalLine(int x,int y1,int y2,const GRADIENT_COLOR &gradient[])
|
||||
{
|
||||
//--- it is assumed that the colors array has sufficient size and positions are already sorted in ascending order
|
||||
int total=ArraySize(gradient);
|
||||
int dy=y2-y1;
|
||||
//--- draw segments
|
||||
for(int i=0;i<total-1;i++)
|
||||
GradientVerticalLineMonochrome(x,y1+dy*gradient[i].pos/100,y1+dy*gradient[i+1].pos/100,gradient[i].clr,gradient[i+1].clr);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Event handler |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::ChartEventHandler(const int id,const long &lparam,const double &dparam,const string &sparam)
|
||||
{
|
||||
//--- events filter
|
||||
switch(id)
|
||||
{
|
||||
case CHARTEVENT_CHART_CHANGE:
|
||||
//--- handle only chart modification events
|
||||
if(m_chart_scale!=(uint)ChartGetInteger(0,CHART_SCALE))
|
||||
{
|
||||
Delay(20);
|
||||
//--- changed horizontal scale
|
||||
ChartScale();
|
||||
if(m_pb1!=0.0)
|
||||
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
|
||||
return;
|
||||
}
|
||||
if(m_height!=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS))
|
||||
{
|
||||
//--- changed vertical size
|
||||
Delay(20);
|
||||
if(m_pb1!=0.0)
|
||||
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
|
||||
return;
|
||||
}
|
||||
if(m_chart_price_min!=ChartGetDouble(0,CHART_PRICE_MIN) ||
|
||||
m_chart_price_max!=ChartGetDouble(0,CHART_PRICE_MAX))
|
||||
{
|
||||
//--- changed vertical scale
|
||||
Delay(20);
|
||||
if(m_pb1!=0.0)
|
||||
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
//--- organize custom timer
|
||||
case CHARTEVENT_CUSTOM+1302:
|
||||
//--- time to draw the new frame?
|
||||
if(GetTickCount()>m_time_redraw)
|
||||
{
|
||||
//--- add the body of flame
|
||||
FlameCreate();
|
||||
//--- draw frame
|
||||
FlameCalculate();
|
||||
Update();
|
||||
//--- calculate time for the next frame
|
||||
m_time_redraw=GetTickCount()+m_delay;
|
||||
}
|
||||
//--- generate next event for custom timer
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delay |
|
||||
//+------------------------------------------------------------------+
|
||||
void CFlameCanvas::Delay(const uint value)
|
||||
{
|
||||
//--- too small
|
||||
if(value<10)
|
||||
return;
|
||||
//--- start delay
|
||||
uint cnt=GetTickCount()+value;
|
||||
//--- delay
|
||||
while(cnt>=GetTickCount());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,211 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartObjectPanel.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <ChartObjects\ChartObjectsTxtControls.mqh>
|
||||
#include <Arrays\ArrayObj.mqh>
|
||||
#include <Arrays\ArrayInt.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectPanel. |
|
||||
//| Purpose: Class for grouping objects for managing a chart |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectPanel : public CChartObjectButton
|
||||
{
|
||||
protected:
|
||||
CArrayObj m_attachment; // array of attached objects
|
||||
CArrayInt m_dX; // array of dX attached objects
|
||||
CArrayInt m_dY; // array of dY attached objects
|
||||
bool m_expanded; // collapsed/expanded flag
|
||||
|
||||
public:
|
||||
CChartObjectPanel();
|
||||
~CChartObjectPanel();
|
||||
//--- method for attaching objects
|
||||
bool Attach(CChartObjectLabel *chart_object);
|
||||
bool X_Distance(const int X);
|
||||
int X_Distance(void) const { return(CChartObjectButton::X_Distance()); }
|
||||
bool Y_Distance(const int Y);
|
||||
int Y_Distance(void) const { return(CChartObjectButton::Y_Distance()); }
|
||||
int X_Size() const;
|
||||
int X_Size(const int Y) const { return(CChartObjectButton::X_Size()); }
|
||||
int Y_Size() const;
|
||||
int Y_Size(const int Y) const { return(CChartObjectButton::Y_Size()); }
|
||||
|
||||
int Timeframes(void) const { return(CChartObjectButton::Timeframes()); }
|
||||
virtual bool Timeframes(const int timeframes);
|
||||
bool State(const bool state);
|
||||
bool State(void) const { return(CChartObjectButton::State()); }
|
||||
bool CheckState();
|
||||
|
||||
protected:
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
void CChartObjectPanel::CChartObjectPanel(void) : m_expanded(true)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
void CChartObjectPanel::~CChartObjectPanel(void)
|
||||
{
|
||||
//--- All objects added by the method Add(), deleted automatically
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method Attach |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectPanel::Attach(CChartObjectLabel *chart_object)
|
||||
{
|
||||
if(m_attachment.Add(chart_object))
|
||||
{
|
||||
int x,y;
|
||||
x=chart_object.X_Distance();
|
||||
m_dX.Add(chart_object.X_Distance());
|
||||
x+=X_Distance();
|
||||
chart_object.X_Distance(X_Distance()+chart_object.X_Distance());
|
||||
y=CChartObjectButton::Y_Size();
|
||||
y+=chart_object.Y_Distance();
|
||||
m_dY.Add(chart_object.Y_Distance()+CChartObjectButton::Y_Size()+2);
|
||||
chart_object.Y_Distance(Y_Distance()+chart_object.Y_Distance()+CChartObjectButton::Y_Size()+2);
|
||||
return(true);
|
||||
}
|
||||
//---
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method X_Distance |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectPanel::X_Distance(const int X)
|
||||
{
|
||||
CChartObjectLabel *chart_object;
|
||||
//---
|
||||
for(int i=0;i<m_attachment.Total();i++)
|
||||
{
|
||||
chart_object=m_attachment.At(i);
|
||||
chart_object.X_Distance(X+m_dX.At(i));
|
||||
}
|
||||
//---
|
||||
return(CChartObjectButton::X_Distance(X));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method Y_Distance |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectPanel::Y_Distance(const int Y)
|
||||
{
|
||||
CChartObjectLabel *chart_object;
|
||||
//---
|
||||
for(int i=0;i<m_attachment.Total();i++)
|
||||
{
|
||||
chart_object=m_attachment.At(i);
|
||||
chart_object.Y_Distance(Y+m_dY.At(i));
|
||||
}
|
||||
//---
|
||||
return(CChartObjectButton::Y_Distance(Y));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method X_Size |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectPanel::X_Size() const
|
||||
{
|
||||
int max_x=CChartObjectButton::X_Size()+X_Distance();
|
||||
CChartObjectLabel *chart_object;
|
||||
//---
|
||||
if(m_expanded)
|
||||
{
|
||||
for(int i=0;i<m_attachment.Total();i++)
|
||||
if((chart_object=m_attachment.At(i))!=NULL)
|
||||
if(max_x<chart_object.X_Distance()+chart_object.X_Size())
|
||||
max_x=chart_object.X_Distance()+chart_object.X_Size();
|
||||
return(max_x-X_Distance()+2);
|
||||
}
|
||||
//---
|
||||
return(CChartObjectButton::X_Size()+2);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method Y_Size |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectPanel::Y_Size() const
|
||||
{
|
||||
int max_y=CChartObjectButton::Y_Size()+Y_Distance();
|
||||
CChartObjectLabel *chart_object;
|
||||
//---
|
||||
if(m_expanded)
|
||||
{
|
||||
for(int i=0;i<m_attachment.Total();i++)
|
||||
if((chart_object=m_attachment.At(i))!=NULL)
|
||||
if(max_y<chart_object.Y_Distance()+chart_object.Y_Size())
|
||||
max_y=chart_object.Y_Distance()+chart_object.Y_Size();
|
||||
return(max_y-Y_Distance()+2);
|
||||
}
|
||||
//---
|
||||
return(CChartObjectButton::Y_Size()+2);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method Timeframes |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectPanel::Timeframes(const int timeframes)
|
||||
{
|
||||
int i;
|
||||
bool res=CChartObject::Timeframes(timeframes);
|
||||
CChartObjectLabel *chart_object;
|
||||
//---
|
||||
if(m_expanded)
|
||||
for(i=0;i<m_attachment.Total();i++)
|
||||
{
|
||||
chart_object=m_attachment.At(i);
|
||||
res&=chart_object.Timeframes(timeframes);
|
||||
}
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method State |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectPanel::State(const bool state)
|
||||
{
|
||||
if(CChartObjectButton::State(state))
|
||||
{
|
||||
m_expanded=state;
|
||||
return(true);
|
||||
}
|
||||
//---
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Method CheckState |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectPanel::CheckState(void)
|
||||
{
|
||||
//--- state changed
|
||||
if(m_expanded!=State())
|
||||
{
|
||||
//--- apply new state
|
||||
m_expanded=State();
|
||||
|
||||
if(m_expanded)
|
||||
{
|
||||
//--- make all objects visible
|
||||
for(int i=0;i<m_attachment.Total();i++)
|
||||
{
|
||||
CChartObjectLabel *chart_object=m_attachment.At(i);
|
||||
chart_object.Timeframes(-1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- make all objects invisible
|
||||
for(int i=0;i<m_attachment.Total();i++)
|
||||
{
|
||||
CChartObjectLabel *chart_object=m_attachment.At(i);
|
||||
chart_object.Timeframes(0x100000);
|
||||
}
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
//---
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,398 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartObjectSubChart.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartObject.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectSubChart. |
|
||||
//| Purpose: Class of the "SubChart" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectSubChart : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectSubChart(void);
|
||||
~CChartObjectSubChart(void);
|
||||
//--- method of creating object
|
||||
bool Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_CHART); }
|
||||
//--- methods of access to properties of the object
|
||||
int X_Distance(void) const;
|
||||
bool X_Distance(const int X) const;
|
||||
int Y_Distance(void) const;
|
||||
bool Y_Distance(const int Y) const;
|
||||
ENUM_BASE_CORNER Corner(void) const;
|
||||
bool Corner(const ENUM_BASE_CORNER corner) const;
|
||||
int X_Size(void) const;
|
||||
bool X_Size(const int size) const;
|
||||
int Y_Size(void) const;
|
||||
bool Y_Size(const int size) const;
|
||||
string Symbol(void) const;
|
||||
bool Symbol(const string symbol) const;
|
||||
int Period(void) const;
|
||||
bool Period(const int period) const;
|
||||
int Scale(void) const;
|
||||
bool Scale(const int scale) const;
|
||||
bool DateScale(void) const;
|
||||
bool DateScale(const bool scale) const;
|
||||
bool PriceScale(void) const;
|
||||
bool PriceScale(const bool scale) const;
|
||||
//--- change of time/price coordinates is blocked
|
||||
datetime Time(const int point) const { return(CChartObject::Time(point)); }
|
||||
bool Time(const int point,const datetime time) const { return(false); }
|
||||
double Price(const int point) const { return(CChartObject::Price(point)); }
|
||||
bool Price(const int point,const double price) const { return(false); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectSubChart::CChartObjectSubChart(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectSubChart::~CChartObjectSubChart(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "SubChart" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::Create(long chart_id,const string name,const int window,
|
||||
const int X,const int Y,const int sizeX,const int sizeY)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_CHART,window,0,0,0))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
if(!X_Distance(X) || !Y_Distance(Y))
|
||||
return(false);
|
||||
if(!X_Size(sizeX) || !Y_Size(sizeY))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the X-distance |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectSubChart::X_Distance(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the X-distance |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::X_Distance(const int X) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,X));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the Y-distance |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectSubChart::Y_Distance(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the Y-distance |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::Y_Distance(const int Y) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,Y));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get base corner |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_BASE_CORNER CChartObjectSubChart::Corner(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(WRONG_VALUE);
|
||||
//--- result
|
||||
return((ENUM_BASE_CORNER)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set base corner |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::Corner(const ENUM_BASE_CORNER corner) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,corner));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the X-size |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectSubChart::X_Size(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set X-size |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::X_Size(const int size) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,size));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the Y-size |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectSubChart::Y_Size(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the Y-size |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::Y_Size(const int size) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,size));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get chart symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
string CChartObjectSubChart::Symbol(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return("");
|
||||
//--- result
|
||||
return(ObjectGetString(m_chart_id,m_name,OBJPROP_SYMBOL));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set chart symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::Symbol(const string symbol) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetString(m_chart_id,m_name,OBJPROP_SYMBOL,symbol));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get chart period |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectSubChart::Period(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_PERIOD));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set chart period |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::Period(const int period) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_PERIOD,period));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get chart scale |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectSubChart::Scale(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(-1);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CHART_SCALE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set chart scale |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::Scale(const int scale) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_CHART_SCALE,scale));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the "time scale" flag |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::DateScale(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DATE_SCALE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "time scale" flag |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::DateScale(const bool scale) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_DATE_SCALE,scale));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the "price scale" flag |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::PriceScale(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_PRICE_SCALE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "price scale" flag |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::PriceScale(const bool scale) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_PRICE_SCALE,scale));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::Save(const int file_handle)
|
||||
{
|
||||
int len;
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObject::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "X-distance" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "Y-distance" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "corner" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "X-size" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "Y-size" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "symbol" property
|
||||
str=ObjectGetString(m_chart_id,m_name,OBJPROP_SYMBOL);
|
||||
len=StringLen(str);
|
||||
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
|
||||
return(false);
|
||||
//--- write value of the "period" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_PERIOD),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "scale" property
|
||||
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE))!=sizeof(double))
|
||||
return(false);
|
||||
//--- write value of the "time scale" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DATE_SCALE),CHAR_VALUE)!=sizeof(char))
|
||||
return(false);
|
||||
//--- write value of the "price scale" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_PRICE_SCALE),CHAR_VALUE)!=sizeof(char))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectSubChart::Load(const int file_handle)
|
||||
{
|
||||
int len;
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObject::Load(file_handle))
|
||||
return(false);
|
||||
//--- read value of the "X-distance" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "Y-distance" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "corner" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "X-size" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "Y-size" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "symbol" property
|
||||
len=FileReadInteger(file_handle,INT_VALUE);
|
||||
str=(len!=0) ? FileReadString(file_handle,len) : "";
|
||||
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_SYMBOL,str))
|
||||
return(false);
|
||||
//--- read value of the "period" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_PERIOD,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "scale" property
|
||||
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,FileReadDatetime(file_handle)))
|
||||
return(false);
|
||||
//--- read value of the "time scale" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_DATE_SCALE,FileReadInteger(file_handle,CHAR_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "price scale" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_PRICE_SCALE,FileReadInteger(file_handle,CHAR_VALUE)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,479 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartObjectsArrows.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//| All arrows. |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartObject.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectArrow. |
|
||||
//| Purpose: Class of the "Arrow" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectArrow : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectArrow(void);
|
||||
~CChartObjectArrow(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time,const double price,const char code);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_ARROW); }
|
||||
//--- methods of access to properties of the object
|
||||
char ArrowCode(void) const;
|
||||
virtual bool ArrowCode(const char code) const;
|
||||
ENUM_ARROW_ANCHOR Anchor(void) const;
|
||||
virtual bool Anchor(const ENUM_ARROW_ANCHOR anchor) const;
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrow::CChartObjectArrow(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrow::~CChartObjectArrow(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Arrow" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrow::Create(long chart_id,const string name,const int window,const datetime time,const double price,const char code)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ARROW,window,time,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
if(!ArrowCode(code))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get code of "arrow" symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
char CChartObjectArrow::ArrowCode(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((char)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ARROWCODE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set code of "arrow" symbol |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrow::ArrowCode(const char code) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ARROWCODE,code));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get anchor type |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ARROW_ANCHOR CChartObjectArrow::Anchor(void) const
|
||||
{
|
||||
//--- result
|
||||
return((ENUM_ARROW_ANCHOR)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ANCHOR));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set anchor type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrow::Anchor(const ENUM_ARROW_ANCHOR anchor) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ANCHOR,anchor));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrow::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- writing
|
||||
if(!CObject::Save(file_handle))
|
||||
return(false);
|
||||
//--- write code of "arrow" symbol
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ARROWCODE),CHAR_VALUE)!=sizeof(char))
|
||||
return(false);
|
||||
//--- write anchor type
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ANCHOR),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrow::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- reading
|
||||
if(!CObject::Load(file_handle))
|
||||
return(false);
|
||||
//--- read code of "arrow" symbol
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_ARROWCODE,FileReadInteger(file_handle,CHAR_VALUE)))
|
||||
return(false);
|
||||
//--- read anchor type
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_ANCHOR,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectArrowThumbUp. |
|
||||
//| Purpose: Class of the "Thumbs Up" object of chart. |
|
||||
//| Derives from class CChartObjectArrow. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectArrowThumbUp : public CChartObjectArrow
|
||||
{
|
||||
public:
|
||||
CChartObjectArrowThumbUp(void);
|
||||
~CChartObjectArrowThumbUp(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const override { return(OBJ_ARROW_THUMB_UP); }
|
||||
//--- change of arrow code is blocked
|
||||
virtual bool ArrowCode(const char code) const override { return(false); }
|
||||
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowThumbUp::CChartObjectArrowThumbUp(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowThumbUp::~CChartObjectArrowThumbUp(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Thumbs Up" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrowThumbUp::Create(long chart_id,const string name,const int window,const datetime time,const double price)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_UP,window,time,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectArrowThumbDown. |
|
||||
//| Purpose: Class of the "Thumbs Down" object of chart. |
|
||||
//| Derives from class CChartObjectArrow. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectArrowThumbDown : public CChartObjectArrow
|
||||
{
|
||||
public:
|
||||
CChartObjectArrowThumbDown(void);
|
||||
~CChartObjectArrowThumbDown(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const override { return(OBJ_ARROW_THUMB_DOWN); }
|
||||
//--- change of arrow code is blocked
|
||||
virtual bool ArrowCode(const char code) const override { return(false); }
|
||||
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowThumbDown::CChartObjectArrowThumbDown(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowThumbDown::~CChartObjectArrowThumbDown(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "ThumbsDown" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrowThumbDown::Create(long chart_id,const string name,const int window,const datetime time,const double price)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_DOWN,window,time,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectArrowUp. |
|
||||
//| Purpose: Class of the "Arrow Up" object of chart. |
|
||||
//| Derives from class CChartObjectArrow. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectArrowUp : public CChartObjectArrow
|
||||
{
|
||||
public:
|
||||
CChartObjectArrowUp(void);
|
||||
~CChartObjectArrowUp(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const override { return(OBJ_ARROW_UP); }
|
||||
//--- change of arrow code is blocked
|
||||
virtual bool ArrowCode(const char code) const override { return(false); }
|
||||
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowUp::CChartObjectArrowUp(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowUp::~CChartObjectArrowUp(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Arrow Up" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrowUp::Create(long chart_id,const string name,const int window,const datetime time,const double price)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ARROW_UP,window,time,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectArrowDown. |
|
||||
//| Purpose: Class of the "Arrow Down" object of chart. |
|
||||
//| Derives from class CChartObjectArrow. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectArrowDown : public CChartObjectArrow
|
||||
{
|
||||
public:
|
||||
CChartObjectArrowDown(void);
|
||||
~CChartObjectArrowDown(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const override { return(OBJ_ARROW_DOWN); }
|
||||
//--- change of arrow code is blocked
|
||||
virtual bool ArrowCode(const char code) const override { return(false); }
|
||||
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowDown::CChartObjectArrowDown(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowDown::~CChartObjectArrowDown(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Arrow Down" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrowDown::Create(long chart_id,const string name,const int window,const datetime time,const double price)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ARROW_DOWN,window,time,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectArrowStop. |
|
||||
//| Purpose: Class of the "Stop Sign" object of chart. |
|
||||
//| Derives from class CChartObjectArrow. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectArrowStop : public CChartObjectArrow
|
||||
{
|
||||
public:
|
||||
CChartObjectArrowStop(void);
|
||||
~CChartObjectArrowStop(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const override { return(OBJ_ARROW_STOP); }
|
||||
//--- change of arrow code is blocked
|
||||
virtual bool ArrowCode(const char code) const override { return(false); }
|
||||
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowStop::CChartObjectArrowStop(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowStop::~CChartObjectArrowStop(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Stop Sign" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrowStop::Create(long chart_id,const string name,const int window,const datetime time,const double price)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ARROW_STOP,window,time,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectArrowCheck. |
|
||||
//| Purpose: Class of the "Check Sign" object of chart. |
|
||||
//| Derives from class CChartObjectArrow. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectArrowCheck : public CChartObjectArrow
|
||||
{
|
||||
public:
|
||||
CChartObjectArrowCheck(void);
|
||||
~CChartObjectArrowCheck(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const override { return(OBJ_ARROW_CHECK); }
|
||||
//--- change of arrow code is blocked
|
||||
virtual bool ArrowCode(const char code) const override { return(false); }
|
||||
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowCheck::CChartObjectArrowCheck(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowCheck::~CChartObjectArrowCheck(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Check Sign" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrowCheck::Create(long chart_id,const string name,const int window,const datetime time,const double price)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ARROW_CHECK,window,time,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectArrowLeftPrice. |
|
||||
//| Purpose: Class of the "Left Price Label" object of chart. |
|
||||
//| Derives from class CChartObjectArrow. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectArrowLeftPrice : public CChartObjectArrow
|
||||
{
|
||||
public:
|
||||
CChartObjectArrowLeftPrice(void);
|
||||
~CChartObjectArrowLeftPrice(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const override { return(OBJ_ARROW_LEFT_PRICE); }
|
||||
//--- change of arrow code and anchor point is blocked
|
||||
virtual bool ArrowCode(const char code) const override { return(false); }
|
||||
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
|
||||
virtual bool Anchor(const ENUM_ARROW_ANCHOR anchor) const override { return(false); }
|
||||
ENUM_ARROW_ANCHOR Anchor(void) const { return(CChartObjectArrow::Anchor()); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowLeftPrice::CChartObjectArrowLeftPrice(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowLeftPrice::~CChartObjectArrowLeftPrice(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Left Price Label" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrowLeftPrice::Create(long chart_id,const string name,const int window,const datetime time,const double price)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ARROW_LEFT_PRICE,window,time,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectArrowRightPrice. |
|
||||
//| Purpose: Class of the "Right Price Label" object of chart. |
|
||||
//| Derives from class CChartObjectArrow. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectArrowRightPrice : public CChartObjectArrow
|
||||
{
|
||||
public:
|
||||
CChartObjectArrowRightPrice(void);
|
||||
~CChartObjectArrowRightPrice(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const override { return(OBJ_ARROW_RIGHT_PRICE); }
|
||||
//--- change of arrow code and anchor point is blocked
|
||||
virtual bool ArrowCode(const char code) const override { return(false); }
|
||||
char ArrowCode(void) const { return(CChartObjectArrow::ArrowCode()); }
|
||||
virtual bool Anchor(const ENUM_ARROW_ANCHOR anchor) const override { return(false); }
|
||||
ENUM_ARROW_ANCHOR Anchor(void) const { return(CChartObjectArrow::Anchor()); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowRightPrice::CChartObjectArrowRightPrice(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectArrowRightPrice::~CChartObjectArrowRightPrice(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Right Price Label" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectArrowRightPrice::Create(long chart_id,const string name,const int window,const datetime time,const double price)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ARROW_RIGHT_PRICE,window,time,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,512 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartObjectsBmpControls.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//| All objects with "bmp" pictures. |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartObject.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectBitmap. |
|
||||
//| Purpose: Class of the "Bitmap" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectBitmap : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectBitmap(void);
|
||||
~CChartObjectBitmap(void);
|
||||
//--- methods of access to properties of the object
|
||||
string BmpFile(void) const;
|
||||
bool BmpFile(const string name) const;
|
||||
int X_Offset(void) const;
|
||||
bool X_Offset(const int X) const;
|
||||
int Y_Offset(void) const;
|
||||
bool Y_Offset(const int Y) const;
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_BITMAP); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectBitmap::CChartObjectBitmap(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectBitmap::~CChartObjectBitmap(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Bitmapp" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBitmap::Create(long chart_id,const string name,const int window,const datetime time,const double price)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_BITMAP,window,time,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get name of bmp-file |
|
||||
//+------------------------------------------------------------------+
|
||||
string CChartObjectBitmap::BmpFile(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return("");
|
||||
//--- result
|
||||
return(ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set name of bmp-file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBitmap::BmpFile(const string name) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,name));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the XOffset property |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectBitmap::X_Offset(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XOFFSET));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the XOffset property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBitmap::X_Offset(const int X) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XOFFSET,X));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the YOffset property |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectBitmap::Y_Offset(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YOFFSET));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the YOffset property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBitmap::Y_Offset(const int Y) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YOFFSET,Y));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBitmap::Save(const int file_handle)
|
||||
{
|
||||
int len;
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObject::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "name of bmp-file" property
|
||||
str=ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE);
|
||||
len=StringLen(str);
|
||||
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBitmap::Load(const int file_handle)
|
||||
{
|
||||
int len;
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObject::Load(file_handle))
|
||||
return(false);
|
||||
//--- read value of the "name of bmp-file" property
|
||||
len=FileReadInteger(file_handle,INT_VALUE);
|
||||
str=(len!=0) ? FileReadString(file_handle,len) : "";
|
||||
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,str))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectBmpLabel. |
|
||||
//| Purpose: Class of the "Bitmap label" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectBmpLabel : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectBmpLabel(void);
|
||||
~CChartObjectBmpLabel(void);
|
||||
//--- methods of access to properties of the object
|
||||
int X_Distance(void) const;
|
||||
bool X_Distance(const int X) const;
|
||||
int Y_Distance(void) const;
|
||||
bool Y_Distance(const int Y) const;
|
||||
int X_Size(void) const;
|
||||
int Y_Size(void) const;
|
||||
ENUM_BASE_CORNER Corner(void) const;
|
||||
bool Corner(const ENUM_BASE_CORNER corner) const;
|
||||
string BmpFileOn(void) const;
|
||||
bool BmpFileOn(const string name) const;
|
||||
string BmpFileOff(void) const;
|
||||
bool BmpFileOff(const string name) const;
|
||||
bool State(void) const;
|
||||
bool State(const bool state) const;
|
||||
int X_Offset(void) const;
|
||||
bool X_Offset(const int X) const;
|
||||
int Y_Offset(void) const;
|
||||
bool Y_Offset(const int Y) const;
|
||||
//--- change of time/price coordinates is blocked
|
||||
bool Time(const datetime time) const { return(false); }
|
||||
bool Price(const double price) const { return(false); }
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const int X,const int Y);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_BITMAP_LABEL); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectBmpLabel::CChartObjectBmpLabel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectBmpLabel::~CChartObjectBmpLabel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Bitmap label" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::Create(long chart_id,const string name,const int window,const int X,const int Y)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_BITMAP_LABEL,window,0,0.0))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
if(!X_Distance(X) || !Y_Distance(Y))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the X-distance property |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectBmpLabel::X_Distance(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the X-distance property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::X_Distance(const int X) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,X));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the Y-distance property |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectBmpLabel::Y_Distance(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the Y-distance property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::Y_Distance(const int Y) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,Y));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the X-size |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectBmpLabel::X_Size(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the Y-size |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectBmpLabel::Y_Size(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the Corner property |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_BASE_CORNER CChartObjectBmpLabel::Corner(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(WRONG_VALUE);
|
||||
//--- result
|
||||
return((ENUM_BASE_CORNER)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the Corner property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::Corner(const ENUM_BASE_CORNER corner) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,corner));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get filename of the "bmp-ON" property |
|
||||
//+------------------------------------------------------------------+
|
||||
string CChartObjectBmpLabel::BmpFileOn(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return("");
|
||||
//--- result
|
||||
return(ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,0));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set filename for the "bmp-ON" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::BmpFileOn(const string name) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,0,name));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get filename of the "bmp-OFF" property |
|
||||
//+------------------------------------------------------------------+
|
||||
string CChartObjectBmpLabel::BmpFileOff(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return("");
|
||||
//--- result
|
||||
return(ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,1));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set filename for the "bmp-OFF" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::BmpFileOff(const string name) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,1,name));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the State property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::State(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the State property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::State(const bool state) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,state));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the XOffset property |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectBmpLabel::X_Offset(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XOFFSET));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the XOffset property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::X_Offset(const int X) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XOFFSET,X));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the YOffset property |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectBmpLabel::Y_Offset(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YOFFSET));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the YOffset property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::Y_Offset(const int Y) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YOFFSET,Y));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::Save(const int file_handle)
|
||||
{
|
||||
int len;
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObject::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "X-distance" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "Y-distance" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "Corner" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "filename bmp-ON" property
|
||||
str=ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,0);
|
||||
len=StringLen(str);
|
||||
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
|
||||
return(false);
|
||||
//--- write value of the "filename bmp-OFF" property
|
||||
str=ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,1);
|
||||
len=StringLen(str);
|
||||
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
|
||||
return(false);
|
||||
//--- write state
|
||||
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE))!=sizeof(long))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading object parameters from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectBmpLabel::Load(const int file_handle)
|
||||
{
|
||||
int len;
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObject::Load(file_handle))
|
||||
return(false);
|
||||
//--- read value of the "X-distance" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "Y-distance" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of "Corner" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "filename bmp-ON" property
|
||||
len=FileReadInteger(file_handle,INT_VALUE);
|
||||
str=(len!=0) ? FileReadString(file_handle,len) : "";
|
||||
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,0,str))
|
||||
return(false);
|
||||
//--- read value of the "filename bmp-OFF" property
|
||||
len=FileReadInteger(file_handle,INT_VALUE);
|
||||
str=(len!=0) ? FileReadString(file_handle,len) : "";
|
||||
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,1,str))
|
||||
return(false);
|
||||
//--- read state
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,FileReadLong(file_handle)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,246 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartObjectsChannels.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//| All channels. |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartObjectsLines.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectChannel. |
|
||||
//| Purpose: Class of the "Equidistant channel" object of chart. |
|
||||
//| Derives from class CChartObjectTrend. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectChannel : public CChartObjectTrend
|
||||
{
|
||||
public:
|
||||
CChartObjectChannel(void);
|
||||
~CChartObjectChannel(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_CHANNEL); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectChannel::CChartObjectChannel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectChannel::~CChartObjectChannel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Equidistant channel" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectChannel::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_CHANNEL,window,time1,price1,time2,price2,time3,price3))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,3))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectStdDevChannel. |
|
||||
//| Purpose: Class of the "Standrad deviation channel" |
|
||||
//| object of chart. |
|
||||
//| Derives from class CChartObjectTrend. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectStdDevChannel : public CChartObjectTrend
|
||||
{
|
||||
public:
|
||||
CChartObjectStdDevChannel(void);
|
||||
~CChartObjectStdDevChannel(void);
|
||||
//--- methods of access to properties of the object
|
||||
double Deviations(void) const;
|
||||
bool Deviations(const double deviation) const;
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const datetime time2,const double deviation);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_STDDEVCHANNEL); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectStdDevChannel::CChartObjectStdDevChannel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectStdDevChannel::~CChartObjectStdDevChannel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Standard deviation channel" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectStdDevChannel::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const datetime time2,const double deviation)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_STDDEVCHANNEL,window,time1,0.0,time2,0.0))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
if(!Deviations(deviation))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get value of the "Deviations" property |
|
||||
//+------------------------------------------------------------------+
|
||||
double CChartObjectStdDevChannel::Deviations(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(EMPTY_VALUE);
|
||||
//--- result
|
||||
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_DEVIATION));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set value for the "Deviations" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectStdDevChannel::Deviations(const double deviation) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_DEVIATION,deviation));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectStdDevChannel::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObjectTrend::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "Deviations" property
|
||||
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_DEVIATION))!=sizeof(double))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectStdDevChannel::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObjectTrend::Load(file_handle))
|
||||
return(false);
|
||||
//--- read value of the "Deviations" property
|
||||
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_DEVIATION,FileReadDouble(file_handle)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectRegression. |
|
||||
//| Purpose: Class of the "Regression channel" object of chart. |
|
||||
//| Derives from class CChartObjectTrend. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectRegression : public CChartObjectTrend
|
||||
{
|
||||
public:
|
||||
CChartObjectRegression(void);
|
||||
~CChartObjectRegression(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const datetime time2);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_REGRESSION); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectRegression::CChartObjectRegression(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectRegression::~CChartObjectRegression(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Regression channel" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectRegression::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const datetime time2)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_REGRESSION,window,time1,0.0,time2,0.0))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectPitchfork. |
|
||||
//| Purpose: Class of the "Andrews pitchfork" object of chart |
|
||||
//| Derives from class CChartObjectTrend. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectPitchfork : public CChartObjectTrend
|
||||
{
|
||||
public:
|
||||
CChartObjectPitchfork(void);
|
||||
~CChartObjectPitchfork(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_CHANNEL); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectPitchfork::CChartObjectPitchfork(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectPitchfork::~CChartObjectPitchfork(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Andrews pitchfork" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectPitchfork::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_PITCHFORK,window,time1,price1,time2,price2,time3,price3))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,3))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,201 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartObjectsElliott.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//| All Elliott tools. |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartObject.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectElliottWave3. |
|
||||
//| Purpose: Class of the "ElliottCorrectiveWave" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectElliottWave3 : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectElliottWave3(void);
|
||||
~CChartObjectElliottWave3(void);
|
||||
//--- methods of access to properties of the object
|
||||
ENUM_ELLIOT_WAVE_DEGREE Degree(void) const;
|
||||
bool Degree(const ENUM_ELLIOT_WAVE_DEGREE degree) const;
|
||||
bool Lines(void) const;
|
||||
bool Lines(const bool lines) const;
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_ELLIOTWAVE3); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectElliottWave3::CChartObjectElliottWave3(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectElliottWave3::~CChartObjectElliottWave3(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "ElliottCorrectiveWave" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectElliottWave3::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE3,window,time1,price1,time2,price2,time3,price3))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,3))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get value of the "Degree" property |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ELLIOT_WAVE_DEGREE CChartObjectElliottWave3::Degree(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(WRONG_VALUE);
|
||||
//--- result
|
||||
return((ENUM_ELLIOT_WAVE_DEGREE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DEGREE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set value for the "Degree" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectElliottWave3::Degree(const ENUM_ELLIOT_WAVE_DEGREE degree) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_DEGREE,degree));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get value of the "Lines" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectElliottWave3::Lines(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DRAWLINES));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set value for the "Lines" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectElliottWave3::Lines(const bool lines) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_DRAWLINES,lines));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectElliottWave3::Save(const int file_handle)
|
||||
{
|
||||
bool result;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
result=CChartObject::Save(file_handle);
|
||||
if(result)
|
||||
{
|
||||
//--- write value of the "Degree" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DEGREE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "Lines" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DRAWLINES),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
}
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectElliottWave3::Load(const int file_handle)
|
||||
{
|
||||
bool result;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
result=CChartObject::Load(file_handle);
|
||||
if(result)
|
||||
{
|
||||
//--- read value of the "Degree" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_DEGREE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "Lines" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_DRAWLINES,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
}
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectElliottWave5. |
|
||||
//| Purpose: Class of the "ElliottMotiveWave" object of chart. |
|
||||
//| Derives from class CChartObjectElliottWave3. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectElliottWave5 : public CChartObjectElliottWave3
|
||||
{
|
||||
public:
|
||||
CChartObjectElliottWave5(void);
|
||||
~CChartObjectElliottWave5(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3,
|
||||
const datetime time4,const double price4,
|
||||
const datetime time5,const double price5);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_ELLIOTWAVE5); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectElliottWave5::CChartObjectElliottWave5(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectElliottWave5::~CChartObjectElliottWave5(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "ElliottMotiveWave" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectElliottWave5::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3,
|
||||
const datetime time4,const double price4,
|
||||
const datetime time5,const double price5)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE5,window,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,5))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,365 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartObjectsFibo.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//| All Fibonacci tools. |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartObjectsLines.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectFibo. |
|
||||
//| Purpose: Class of the "Fibonacci Lines" object. |
|
||||
//| Derives from class CChartObjectTrend. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectFibo : public CChartObjectTrend
|
||||
{
|
||||
public:
|
||||
CChartObjectFibo(void);
|
||||
~CChartObjectFibo(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_FIBO); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFibo::CChartObjectFibo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFibo::~CChartObjectFibo(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Fibonacci Lines" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectFibo::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_FIBO,window,time1,price1,time2,price2))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectFiboTimes. |
|
||||
//| Purpose: Class of the "Fibonacci Time Zones" object of chart |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectFiboTimes : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectFiboTimes(void);
|
||||
~CChartObjectFiboTimes(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_FIBOTIMES); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFiboTimes::CChartObjectFiboTimes(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFiboTimes::~CChartObjectFiboTimes(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Fibonacci Time Zones" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectFiboTimes::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_FIBOTIMES,window,time1,price1,time2,price2))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectFiboFan. |
|
||||
//| Purpose: Class of the "Fibonacci Fan" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectFiboFan : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectFiboFan(void);
|
||||
~CChartObjectFiboFan(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_FIBOFAN); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFiboFan::CChartObjectFiboFan(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFiboFan::~CChartObjectFiboFan(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Fibonacci Fan" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectFiboFan::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_FIBOFAN,window,time1,price1,time2,price2))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectFiboArc. |
|
||||
//| Purpose: Class of the "Fibonacci Arcs" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectFiboArc : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectFiboArc(void);
|
||||
~CChartObjectFiboArc(void);
|
||||
//--- methods of access to properties of the object
|
||||
double Scale(void) const;
|
||||
bool Scale(const double scale) const;
|
||||
bool Ellipse(void) const;
|
||||
bool Ellipse(const bool ellipse) const;
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,const double scale);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_FIBOARC); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFiboArc::CChartObjectFiboArc(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFiboArc::~CChartObjectFiboArc(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Fibonacci Arcs" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectFiboArc::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,const double scale)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_FIBOARC,window,time1,price1,time2,price2))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
if(!Scale(scale))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get value of the "Scale" property |
|
||||
//+------------------------------------------------------------------+
|
||||
double CChartObjectFiboArc::Scale(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(EMPTY_VALUE);
|
||||
//--- result
|
||||
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set value for the "Scale" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectFiboArc::Scale(const double scale) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,scale));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get value of the "Ellipse" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectFiboArc::Ellipse(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ELLIPSE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set value for the "Ellipse" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectFiboArc::Ellipse(const bool ellipse) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ELLIPSE,ellipse));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameter of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectFiboArc::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObject::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "Scale" property
|
||||
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE))!=sizeof(double))
|
||||
return(false);
|
||||
//--- write value of the "Ellipse" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ELLIPSE),CHAR_VALUE)!=sizeof(char))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectFiboArc::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObject::Load(file_handle))
|
||||
return(false);
|
||||
//--- read value of the "Scale" property
|
||||
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,FileReadDouble(file_handle)))
|
||||
return(false);
|
||||
//--- read value of the "Ellipse" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_ELLIPSE,FileReadInteger(file_handle,CHAR_VALUE)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectFiboChannel. |
|
||||
//| Purpose: Class of the "Fibonacci Channel" object of chart. |
|
||||
//| Derives from class CChartObjectTrend. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectFiboChannel : public CChartObjectTrend
|
||||
{
|
||||
public:
|
||||
CChartObjectFiboChannel(void);
|
||||
~CChartObjectFiboChannel(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_FIBOCHANNEL); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFiboChannel::CChartObjectFiboChannel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFiboChannel::~CChartObjectFiboChannel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Fibonacci Channel" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectFiboChannel::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_FIBOCHANNEL,window,time1,price1,time2,price2,time3,price3))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,3))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectFiboExpansion. |
|
||||
//| Purpose: Class of the "Fibonacci Expansion" object. |
|
||||
//| Derives from class CChartObjectTrend. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectFiboExpansion : public CChartObjectTrend
|
||||
{
|
||||
public:
|
||||
CChartObjectFiboExpansion(void);
|
||||
~CChartObjectFiboExpansion(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_EXPANSION); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFiboExpansion::CChartObjectFiboExpansion(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectFiboExpansion::~CChartObjectFiboExpansion(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Fibonacci Expansion" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectFiboExpansion::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_EXPANSION,window,time1,price1,time2,price2,time3,price3))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,3))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,390 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartObjectsGann.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//| All Gann tools. |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartObjectsLines.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectGannLine. |
|
||||
//| Purpose: Class of the "Gann Line" object of chart. |
|
||||
//| Derives from class CChartObjectTrendByAngle. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectGannLine : public CChartObjectTrendByAngle
|
||||
{
|
||||
public:
|
||||
CChartObjectGannLine(void);
|
||||
~CChartObjectGannLine(void);
|
||||
//--- methods of access to properties of the object
|
||||
double PipsPerBar(void) const;
|
||||
bool PipsPerBar(const double ppb) const;
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double ppb);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_GANNLINE); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectGannLine::CChartObjectGannLine(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectGannLine::~CChartObjectGannLine(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Gann Line" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannLine::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double ppb)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_GANNLINE,window,time1,price1,time2,0.0))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
if(!PipsPerBar(ppb))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get value of the "PipsPerBar" property |
|
||||
//+------------------------------------------------------------------+
|
||||
double CChartObjectGannLine::PipsPerBar(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(EMPTY_VALUE);
|
||||
//--- result
|
||||
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set value for the "PipsPerBar" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannLine::PipsPerBar(const double ppb) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,ppb));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannLine::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObjectTrend::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "PipsPerBar"
|
||||
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE))!=sizeof(double))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannLine::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObjectTrend::Load(file_handle))
|
||||
return(false);
|
||||
//--- read value of the "PipsPerBar" property
|
||||
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,FileReadDouble(file_handle)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectGannFan. |
|
||||
//| Purpose: Class of the "Gann Fan" object of chart. |
|
||||
//| Derives from class CChartObjectTrend. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectGannFan : public CChartObjectTrend
|
||||
{
|
||||
public:
|
||||
CChartObjectGannFan(void);
|
||||
~CChartObjectGannFan(void);
|
||||
//--- methods of access to properties of the object
|
||||
double PipsPerBar(void) const;
|
||||
bool PipsPerBar(const double ppb) const;
|
||||
bool Downtrend(void) const;
|
||||
bool Downtrend(const bool downtrend) const;
|
||||
//--- method of create the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double ppb);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_GANNFAN); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectGannFan::CChartObjectGannFan(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectGannFan::~CChartObjectGannFan(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Gann Fan" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannFan::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double ppb)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_GANNFAN,window,time1,price1,time2,0.0))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
if(!PipsPerBar(ppb))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get value of the "PipsPerBar" property |
|
||||
//+------------------------------------------------------------------+
|
||||
double CChartObjectGannFan::PipsPerBar(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(EMPTY_VALUE);
|
||||
//--- result
|
||||
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set value for the "PipsPerBar" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannFan::PipsPerBar(const double ppb) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,ppb));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get value of the "Downtrend" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannFan::Downtrend(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DIRECTION));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set value for the "Downtrend" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannFan::Downtrend(const bool downtrend) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_DIRECTION,downtrend));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannFan::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObjectTrend::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "PipsPerBar" property
|
||||
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE))!=sizeof(double))
|
||||
return(false);
|
||||
//--- write value of the "Downtrend" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DIRECTION),CHAR_VALUE)!=sizeof(char))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading object parameters from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannFan::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObjectTrend::Load(file_handle))
|
||||
return(false);
|
||||
//--- read value of the "PipsPerBar" property
|
||||
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,FileReadDouble(file_handle)))
|
||||
return(false);
|
||||
//--- read value of the "Downtrend" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_DIRECTION,FileReadInteger(file_handle,CHAR_VALUE)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectGannGrid. |
|
||||
//| Purpose: Class of the "Gann Grid" object of chart. |
|
||||
//| Derives from class CChartObjectTrend. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectGannGrid : public CChartObjectTrend
|
||||
{
|
||||
public:
|
||||
CChartObjectGannGrid(void);
|
||||
~CChartObjectGannGrid(void);
|
||||
//--- methods of access to properties of the object
|
||||
double PipsPerBar(void) const;
|
||||
bool PipsPerBar(const double ppb) const;
|
||||
bool Downtrend(void) const;
|
||||
bool Downtrend(const bool downtrend) const;
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double ppb);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_GANNGRID); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectGannGrid::CChartObjectGannGrid(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectGannGrid::~CChartObjectGannGrid(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Gann Grid" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannGrid::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double ppb)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_GANNGRID,window,time1,price1,time2,0.0))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
if(!PipsPerBar(ppb))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get value of the"PipsPerBar" property |
|
||||
//+------------------------------------------------------------------+
|
||||
double CChartObjectGannGrid::PipsPerBar(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(EMPTY_VALUE);
|
||||
//--- result
|
||||
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set value for the "PipsPerBar" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannGrid::PipsPerBar(const double ppb) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,ppb));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the property value "Downtrend" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannGrid::Downtrend(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DIRECTION));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the property value "Downtrend" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannGrid::Downtrend(const bool downtrend) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_DIRECTION,downtrend));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannGrid::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObjectTrend::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "PipsPerBar" property
|
||||
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_SCALE))!=sizeof(double))
|
||||
return(false);
|
||||
//--- write value of the "Downtrend" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_DIRECTION),CHAR_VALUE)!=sizeof(char))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading paprameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectGannGrid::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObjectTrend::Load(file_handle))
|
||||
return(false);
|
||||
//--- read value of the "PipsPerBar" property
|
||||
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_SCALE,FileReadDouble(file_handle)))
|
||||
return(false);
|
||||
//--- read value of the "Downtrend" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_DIRECTION,FileReadInteger(file_handle,CHAR_VALUE)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,335 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartObjectsLines.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//| All lines. |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartObject.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectVLine. |
|
||||
//| Purpose: Class of the "Vertical line" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectVLine : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectVLine(void);
|
||||
~CChartObjectVLine(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_VLINE); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectVLine::CChartObjectVLine(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectVLine::~CChartObjectVLine(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Vertical line" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectVLine::Create(long chart_id,const string name,const int window,const datetime time)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_VLINE,window,time,0.0))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectHLine. |
|
||||
//| Purpose: Class of the "Horizontal line" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectHLine : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectHLine(void);
|
||||
~CChartObjectHLine(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const double price);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_HLINE); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectHLine::CChartObjectHLine(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectHLine::~CChartObjectHLine(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Horizontal line" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectHLine::Create(long chart_id,const string name,const int window,const double price)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_HLINE,window,0,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectTrend. |
|
||||
//| Purpose: Class of the "Trendline" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//| It is the parent class for all objects that have properties |
|
||||
//| RAY_LEFT and RAY_RIGHT. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectTrend : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectTrend(void);
|
||||
~CChartObjectTrend(void);
|
||||
//--- methods of access to properties of the object
|
||||
bool RayLeft(void) const;
|
||||
bool RayLeft(const bool new_sel) const;
|
||||
bool RayRight(void) const;
|
||||
bool RayRight(const bool new_sel) const;
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_TREND); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectTrend::CChartObjectTrend(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectTrend::~CChartObjectTrend(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Trendline" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectTrend::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_TREND,window,time1,price1,time2,price2))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the "Ray left" flag |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectTrend::RayLeft(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Ray left" flag |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectTrend::RayLeft(const bool new_ray) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT,new_ray));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the "Ray right" flag |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectTrend::RayRight(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_RAY_RIGHT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Ray right" flag |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectTrend::RayRight(const bool new_ray) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_RIGHT,new_ray));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectTrend::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObject::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "Ray left" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT),CHAR_VALUE)!=sizeof(char))
|
||||
return(false);
|
||||
//--- write value of the "Ray right" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_RAY_RIGHT),CHAR_VALUE)!=sizeof(char))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectTrend::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObject::Load(file_handle))
|
||||
return(false);
|
||||
//--- read value of the "Ray left" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT,FileReadInteger(file_handle,CHAR_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "Ray right" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_RIGHT,FileReadInteger(file_handle,CHAR_VALUE)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectTrendByAngle. |
|
||||
//| Puprose: Class of the "Trendline by angle" object of chart. |
|
||||
//| Derives from class CChartObjectTrend. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectTrendByAngle : public CChartObjectTrend
|
||||
{
|
||||
public:
|
||||
CChartObjectTrendByAngle(void);
|
||||
~CChartObjectTrendByAngle(void);
|
||||
//--- methods of access to properties of the object
|
||||
double Angle(void) const;
|
||||
bool Angle(const double angle) const;
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_TRENDBYANGLE); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectTrendByAngle::CChartObjectTrendByAngle(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectTrendByAngle::~CChartObjectTrendByAngle(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Trendline by angle" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectTrendByAngle::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_TRENDBYANGLE,window,time1,price1,time2,price2))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the "Angle" property |
|
||||
//+------------------------------------------------------------------+
|
||||
double CChartObjectTrendByAngle::Angle(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(EMPTY_VALUE);
|
||||
//---
|
||||
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_ANGLE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Angle" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectTrendByAngle::Angle(const double angle) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_ANGLE,angle));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectCycles. |
|
||||
//| Purpose: Class of the "Cycle lines" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectCycles : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectCycles(void);
|
||||
~CChartObjectCycles(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_CYCLES); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectCycles::CChartObjectCycles(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectCycles::~CChartObjectCycles(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Cycle lines" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectCycles::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_CYCLES,window,time1,price1,time2,price2))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,142 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartObjectsShapes.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//| All shapes. |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartObject.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectRectangle. |
|
||||
//| Purpose: Class of the "Rectangle" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectRectangle : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectRectangle(void);
|
||||
~CChartObjectRectangle(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_RECTANGLE); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectRectangle::CChartObjectRectangle(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectRectangle::~CChartObjectRectangle(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Rectangle" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectRectangle::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_RECTANGLE,window,time1,price1,time2,price2))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,2))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectTriangle. |
|
||||
//| Purpose: Class of the "Triangle" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectTriangle : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectTriangle(void);
|
||||
~CChartObjectTriangle(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_TRIANGLE); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectTriangle::CChartObjectTriangle(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectTriangle::~CChartObjectTriangle(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Triangle" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectTriangle::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_TRIANGLE,window,time1,price1,time2,price2,time3,price3))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,3))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectEllipse. |
|
||||
//| Purpose: Class of the "Ellipse" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectEllipse : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectEllipse(void);
|
||||
~CChartObjectEllipse(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_ELLIPSE); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectEllipse::CChartObjectEllipse(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectEllipse::~CChartObjectEllipse(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Ellipse" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectEllipse::Create(long chart_id,const string name,const int window,
|
||||
const datetime time1,const double price1,
|
||||
const datetime time2,const double price2,
|
||||
const datetime time3,const double price3)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_ELLIPSE,window,time1,price1,time2,price2,time3,price3))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,3))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,895 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartObjectsTxtControls.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//| All text objects. |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartObject.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectText. |
|
||||
//| Purpose: Class of the "Text" object of chart. |
|
||||
//| Derives from class CChartObject. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectText : public CChartObject
|
||||
{
|
||||
public:
|
||||
CChartObjectText(void);
|
||||
~CChartObjectText(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const override { return(OBJ_TEXT); }
|
||||
//--- methods of access to properties of the object
|
||||
double Angle(void) const;
|
||||
bool Angle(const double angle) const;
|
||||
string Font(void) const;
|
||||
bool Font(const string font) const;
|
||||
int FontSize(void) const;
|
||||
bool FontSize(const int size) const;
|
||||
ENUM_ANCHOR_POINT Anchor(void) const;
|
||||
bool Anchor(const ENUM_ANCHOR_POINT anchor) const;
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle) override;
|
||||
virtual bool Load(const int file_handle) override;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectText::CChartObjectText(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectText::~CChartObjectText(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Text" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectText::Create(long chart_id,const string name,const int window,
|
||||
const datetime time,const double price)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_TEXT,window,time,price))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get value of the "Angle" property |
|
||||
//+------------------------------------------------------------------+
|
||||
double CChartObjectText::Angle(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(EMPTY_VALUE);
|
||||
//--- result
|
||||
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_ANGLE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set value of the "Angle" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectText::Angle(const double angle) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_ANGLE,angle));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get font name |
|
||||
//+------------------------------------------------------------------+
|
||||
string CChartObjectText::Font(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return("");
|
||||
//--- result
|
||||
return(ObjectGetString(m_chart_id,m_name,OBJPROP_FONT));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set font name |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectText::Font(const string font) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetString(m_chart_id,m_name,OBJPROP_FONT,font));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get font size |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectText::FontSize(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set font size |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectText::FontSize(const int size) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE,size));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get anchor point |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ANCHOR_POINT CChartObjectText::Anchor(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(WRONG_VALUE);
|
||||
//--- result
|
||||
return((ENUM_ANCHOR_POINT)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ANCHOR));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set anchor point |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectText::Anchor(const ENUM_ANCHOR_POINT anchor) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ANCHOR,anchor));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectText::Save(const int file_handle)
|
||||
{
|
||||
int len;
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObject::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "Angle" property
|
||||
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_ANGLE))!=sizeof(double))
|
||||
return(false);
|
||||
//--- write value of the "Font Name" property
|
||||
str=ObjectGetString(m_chart_id,m_name,OBJPROP_FONT);
|
||||
len=StringLen(str);
|
||||
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
|
||||
return(false);
|
||||
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
|
||||
return(false);
|
||||
//--- write value of the "Font Size" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "Anchor Point" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ANCHOR),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectText::Load(const int file_handle)
|
||||
{
|
||||
int len;
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObject::Load(file_handle))
|
||||
return(false);
|
||||
//--- reading value of the "Angle" property
|
||||
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_ANGLE,0,FileReadDouble(file_handle)))
|
||||
return(false);
|
||||
//--- read value of the "Font Name" property
|
||||
len=FileReadInteger(file_handle,INT_VALUE);
|
||||
str=(len!=0) ? FileReadString(file_handle,len) : "";
|
||||
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_FONT,str))
|
||||
return(false);
|
||||
//--- read value of the "Font Size" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "Anchor Point" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_ANCHOR,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectLabel. |
|
||||
//| Purpose: Class of the "Label" object of chart. |
|
||||
//| Derives from class CChartObjectText. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectLabel : public CChartObjectText
|
||||
{
|
||||
public:
|
||||
CChartObjectLabel(void);
|
||||
~CChartObjectLabel(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const int X,const int Y);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_LABEL); }
|
||||
//--- methods of access to properties of the object
|
||||
int X_Distance(void) const;
|
||||
bool X_Distance(const int X) const;
|
||||
int Y_Distance(void) const;
|
||||
bool Y_Distance(const int Y) const;
|
||||
int X_Size(void) const;
|
||||
int Y_Size(void) const;
|
||||
|
||||
ENUM_BASE_CORNER Corner(void) const;
|
||||
bool Corner(const ENUM_BASE_CORNER corner) const;
|
||||
//--- change of time/price coordinates is blocked
|
||||
datetime Time(const int point) const { return(CChartObjectText::Time(point)); }
|
||||
bool Time(const int point,const datetime time) const { return(false); }
|
||||
double Price(const int point) const { return(CChartObjectText::Price(point)); }
|
||||
bool Price(const int point,const double price) const { return(false); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectLabel::CChartObjectLabel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectLabel::~CChartObjectLabel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Label" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectLabel::Create(long chart_id,const string name,const int window,const int X,const int Y)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,OBJ_LABEL,window,0,0.0))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
if(!Description(name))
|
||||
return(false);
|
||||
if(!X_Distance(X) || !Y_Distance(Y))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the X-distance |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectLabel::X_Distance(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the X-distance |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectLabel::X_Distance(const int X) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,X));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the Y-distance |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectLabel::Y_Distance(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the Y-distance |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectLabel::Y_Distance(const int Y) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,Y));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the X-size |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectLabel::X_Size(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the Y-size |
|
||||
//+------------------------------------------------------------------+
|
||||
int CChartObjectLabel::Y_Size(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(0);
|
||||
//--- result
|
||||
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get base corner |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_BASE_CORNER CChartObjectLabel::Corner(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(WRONG_VALUE);
|
||||
//--- result
|
||||
return((ENUM_BASE_CORNER)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set base corner |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectLabel::Corner(const ENUM_BASE_CORNER corner) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,corner));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectLabel::Save(const int file_handle)
|
||||
{
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObjectText::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "X-distance" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "Y-distance" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "Corner" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectLabel::Load(const int file_handle)
|
||||
{
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObjectText::Load(file_handle))
|
||||
return(false);
|
||||
//--- reading value of the "X-distance" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "Y-distance" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "Corner" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectEdit. |
|
||||
//| Purpose: Class of the "Edit" object of chart. |
|
||||
//| Derives from class CChartObjectLabel. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectEdit : public CChartObjectLabel
|
||||
{
|
||||
public:
|
||||
CChartObjectEdit(void);
|
||||
~CChartObjectEdit(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const override { return(OBJ_EDIT); }
|
||||
//--- methods of access to properties of the object
|
||||
bool X_Size(const int X) const;
|
||||
int X_Size(void) const { return(CChartObjectLabel::X_Size()); }
|
||||
bool Y_Size(const int Y) const;
|
||||
int Y_Size(void) const { return(CChartObjectLabel::Y_Size()); }
|
||||
color BackColor(void) const;
|
||||
bool BackColor(const color new_color) const;
|
||||
color BorderColor(void) const;
|
||||
bool BorderColor(const color new_color) const;
|
||||
bool ReadOnly(void) const;
|
||||
bool ReadOnly(const bool flag) const;
|
||||
ENUM_ALIGN_MODE TextAlign(void) const;
|
||||
bool TextAlign(const ENUM_ALIGN_MODE align) const;
|
||||
//--- change of angle is blocked
|
||||
bool Angle(const double angle) const { return(false); }
|
||||
double Angle(void) const { return(CChartObjectLabel::Angle()); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle) override;
|
||||
virtual bool Load(const int file_handle) override;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectEdit::CChartObjectEdit(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectEdit::~CChartObjectEdit(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Edit" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectEdit::Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,(ENUM_OBJECT)Type(),window,0,0,0))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
if(!X_Distance(X) || !Y_Distance(Y))
|
||||
return(false);
|
||||
if(!X_Size(sizeX) || !Y_Size(sizeY))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set X-size |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectEdit::X_Size(const int X) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,X));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set Y-size |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectEdit::Y_Size(const int Y) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,Y));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get background color |
|
||||
//+------------------------------------------------------------------+
|
||||
color CChartObjectEdit::BackColor(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(clrNONE);
|
||||
//--- result
|
||||
return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set background color |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectEdit::BackColor(const color new_color) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,new_color));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get border color |
|
||||
//+------------------------------------------------------------------+
|
||||
color CChartObjectEdit::BorderColor(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(clrNONE);
|
||||
//--- result
|
||||
return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BORDER_COLOR));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set border color |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectEdit::BorderColor(const color new_color) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BORDER_COLOR,new_color));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the "Read only" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectEdit::ReadOnly(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_READONLY));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Read only" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectEdit::ReadOnly(const bool flag) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_READONLY,flag));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the "Align" property |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ALIGN_MODE CChartObjectEdit::TextAlign(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((ENUM_ALIGN_MODE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ALIGN));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Align" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectEdit::TextAlign(const ENUM_ALIGN_MODE align) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ALIGN,align));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectEdit::Save(const int file_handle)
|
||||
{
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObjectLabel::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "X-size" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "Y-size" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write background color
|
||||
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR))!=sizeof(long))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectEdit::Load(const int file_handle)
|
||||
{
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObjectLabel::Load(file_handle))
|
||||
return(false);
|
||||
//--- read value of the "X-size" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "Y-size" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read background color
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,FileReadLong(file_handle)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectButton. |
|
||||
//| Purpose: Class of the "Button" object of chart. |
|
||||
//| Derives from class CChartObjectEdit. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectButton : public CChartObjectEdit
|
||||
{
|
||||
public:
|
||||
CChartObjectButton(void);
|
||||
~CChartObjectButton(void);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const override { return(OBJ_BUTTON); }
|
||||
//--- methods of access to properties of the object
|
||||
bool State(void) const;
|
||||
bool State(const bool state) const;
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle) override;
|
||||
virtual bool Load(const int file_handle) override;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectButton::CChartObjectButton(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectButton::~CChartObjectButton(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectButton::State(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectButton::State(const bool state) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,state));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectButton::Save(const int file_handle)
|
||||
{
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObjectEdit::Save(file_handle))
|
||||
return(false);
|
||||
//--- write state
|
||||
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE))!=sizeof(long))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectButton::Load(const int file_handle)
|
||||
{
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObjectEdit::Load(file_handle))
|
||||
return(false);
|
||||
//--- read state
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,FileReadLong(file_handle)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CChartObjectRectLabel. |
|
||||
//| Purpose: Class of the "Rectangle Label" object of chart. |
|
||||
//| Derives from class CChartObjectLabel. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CChartObjectRectLabel : public CChartObjectLabel
|
||||
{
|
||||
public:
|
||||
CChartObjectRectLabel(void);
|
||||
~CChartObjectRectLabel(void);
|
||||
//--- method of creating the object
|
||||
bool Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY);
|
||||
//--- method of identifying the object
|
||||
virtual int Type(void) const { return(OBJ_RECTANGLE_LABEL); }
|
||||
//--- methods of access to properties of the object
|
||||
bool X_Size(const int X) const;
|
||||
int X_Size(void)const { return(CChartObjectLabel::X_Size()); }
|
||||
bool Y_Size(const int Y) const;
|
||||
int Y_Size(void)const { return(CChartObjectLabel::Y_Size()); }
|
||||
color BackColor(void) const;
|
||||
bool BackColor(const color new_color) const;
|
||||
ENUM_BORDER_TYPE BorderType(void) const;
|
||||
bool BorderType(const ENUM_BORDER_TYPE flag) const;
|
||||
//--- change of angle is blocked
|
||||
bool Angle(const double angle) const { return(false); }
|
||||
double Angle(void) const { return(CChartObjectLabel::Angle()); }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectRectLabel::CChartObjectRectLabel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CChartObjectRectLabel::~CChartObjectRectLabel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object "Ractangle Label" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectRectLabel::Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY)
|
||||
{
|
||||
if(!ObjectCreate(chart_id,name,(ENUM_OBJECT)Type(),window,0,0,0))
|
||||
return(false);
|
||||
if(!Attach(chart_id,name,window,1))
|
||||
return(false);
|
||||
if(!X_Distance(X) || !Y_Distance(Y))
|
||||
return(false);
|
||||
if(!X_Size(sizeX) || !Y_Size(sizeY))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set X-size |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectRectLabel::X_Size(const int X) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,X));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set Y-size |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectRectLabel::Y_Size(const int Y) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,Y));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get background color |
|
||||
//+------------------------------------------------------------------+
|
||||
color CChartObjectRectLabel::BackColor(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(clrNONE);
|
||||
//--- result
|
||||
return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set background color |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectRectLabel::BackColor(const color new_color) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,new_color));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get the "Border type" property |
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_BORDER_TYPE CChartObjectRectLabel::BorderType(void) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return((ENUM_BORDER_TYPE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Border type" property |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectRectLabel::BorderType(const ENUM_BORDER_TYPE type) const
|
||||
{
|
||||
//--- check
|
||||
if(m_chart_id==-1)
|
||||
return(false);
|
||||
//--- result
|
||||
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE,type));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Writing parameters of object to file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectRectLabel::Save(const int file_handle)
|
||||
{
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- write
|
||||
if(!CChartObjectLabel::Save(file_handle))
|
||||
return(false);
|
||||
//--- write value of the "X-size" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write value of the "Y-size" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- write background color
|
||||
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR))!=sizeof(long))
|
||||
return(false);
|
||||
//--- write value of the "Border type" property
|
||||
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE),INT_VALUE)!=sizeof(int))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reading parameters of object from file |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CChartObjectRectLabel::Load(const int file_handle)
|
||||
{
|
||||
string str;
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
|
||||
return(false);
|
||||
//--- read
|
||||
if(!CChartObjectLabel::Load(file_handle))
|
||||
return(false);
|
||||
//--- read value of the "X-size" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read value of the "Y-size" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- read background color
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,FileReadLong(file_handle)))
|
||||
return(false);
|
||||
//--- read value of the "Border type" property
|
||||
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE,FileReadInteger(file_handle,INT_VALUE)))
|
||||
return(false);
|
||||
//--- successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,268 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| BmpButton.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndObj.mqh"
|
||||
#include <ChartObjects\ChartObjectsBmpControls.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CBmpButton |
|
||||
//| Usage: control that is displayed by |
|
||||
//| the CChartObjectBmpLabel object |
|
||||
//+------------------------------------------------------------------+
|
||||
class CBmpButton : public CWndObj
|
||||
{
|
||||
private:
|
||||
CChartObjectBmpLabel m_button; // chart object
|
||||
//--- parameters of the chart object
|
||||
int m_border; // border width
|
||||
string m_bmp_off_name; // name of BMP file for the "OFF" state (default state)
|
||||
string m_bmp_on_name; // name of BMP file for the "ON" state
|
||||
string m_bmp_passive_name;
|
||||
string m_bmp_active_name;
|
||||
|
||||
public:
|
||||
CBmpButton(void);
|
||||
~CBmpButton(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- parameters of the chart object
|
||||
int Border(void) const { return(m_border); }
|
||||
bool Border(const int value);
|
||||
bool BmpNames(const string off="",const string on="");
|
||||
string BmpOffName(void) const { return(m_bmp_off_name); }
|
||||
bool BmpOffName(const string name);
|
||||
string BmpOnName(void) const { return(m_bmp_on_name); }
|
||||
bool BmpOnName(const string name);
|
||||
string BmpPassiveName(void) const { return(m_bmp_passive_name); }
|
||||
bool BmpPassiveName(const string name);
|
||||
string BmpActiveName(void) const { return(m_bmp_active_name); }
|
||||
bool BmpActiveName(const string name);
|
||||
//--- state
|
||||
bool Pressed(void) const { return(m_button.State()); }
|
||||
bool Pressed(const bool pressed) { return(m_button.State(pressed)); }
|
||||
//--- properties
|
||||
bool Locking(void) const { return(IS_CAN_LOCK); }
|
||||
void Locking(const bool locking);
|
||||
|
||||
protected:
|
||||
//--- handlers of object settings
|
||||
virtual bool OnSetZOrder(void) { return(m_button.Z_Order(m_zorder)); }
|
||||
//--- internal event handlers
|
||||
virtual bool OnCreate(void);
|
||||
virtual bool OnShow(void);
|
||||
virtual bool OnHide(void);
|
||||
virtual bool OnMove(void);
|
||||
virtual bool OnChange(void);
|
||||
//--- íîâûå îáðàáîò÷èêè
|
||||
virtual bool OnActivate(void);
|
||||
virtual bool OnDeactivate(void);
|
||||
virtual bool OnMouseDown(void);
|
||||
virtual bool OnMouseUp(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CBmpButton::CBmpButton(void) : m_border(0),
|
||||
m_bmp_off_name(NULL),
|
||||
m_bmp_on_name(NULL),
|
||||
m_bmp_passive_name(NULL),
|
||||
m_bmp_active_name(NULL)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CBmpButton::~CBmpButton(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call method of the parent class
|
||||
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create the chart object
|
||||
if(!m_button.Create(chart,name,subwin,x1,y1))
|
||||
return(false);
|
||||
//--- call the settings handler
|
||||
return(OnChange());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set border width |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::Border(const int value)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_border=value;
|
||||
//--- set up the chart object
|
||||
return(m_button.Width(value));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set two images at once |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::BmpNames(const string off,const string on)
|
||||
{
|
||||
//--- save new values of parameters
|
||||
m_bmp_off_name=off;
|
||||
m_bmp_on_name =on;
|
||||
//--- set up the chart object
|
||||
if(!m_button.BmpFileOff(off))
|
||||
return(false);
|
||||
if(!m_button.BmpFileOn(on))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set image for the "OFF" state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::BmpOffName(const string name)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_bmp_off_name=name;
|
||||
//--- set up the chart object
|
||||
if(!m_button.BmpFileOff(name))
|
||||
return(false);
|
||||
//--- set size by image dimensions
|
||||
Width(m_button.X_Size());
|
||||
Height(m_button.Y_Size());
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set image for the "ON" state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::BmpOnName(const string name)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_bmp_on_name=name;
|
||||
//--- set up the chart object
|
||||
if(!m_button.BmpFileOn(name))
|
||||
return(false);
|
||||
//--- set size by image dimensions
|
||||
Width(m_button.X_Size());
|
||||
Height(m_button.Y_Size());
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set image for the "OFF" state (passive) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::BmpPassiveName(const string name)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_bmp_passive_name=name;
|
||||
//--- set up the chart object
|
||||
if(!IS_ACTIVE)
|
||||
return(BmpOffName(name));
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set image for the "OFF" state (active) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::BmpActiveName(const string name)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_bmp_active_name=name;
|
||||
//--- set up the chart object
|
||||
if(IS_ACTIVE)
|
||||
return(BmpOffName(name));
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Locking flag |
|
||||
//+------------------------------------------------------------------+
|
||||
void CBmpButton::Locking(const bool flag)
|
||||
{
|
||||
if(flag)
|
||||
PropFlagsSet(WND_PROP_FLAG_CAN_LOCK);
|
||||
else
|
||||
PropFlagsReset(WND_PROP_FLAG_CAN_LOCK);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::OnCreate(void)
|
||||
{
|
||||
//--- create the chart object by previously set parameters
|
||||
return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Display object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::OnShow(void)
|
||||
{
|
||||
return(m_button.Timeframes(OBJ_ALL_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Hide object from chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::OnHide(void)
|
||||
{
|
||||
return(m_button.Timeframes(OBJ_NO_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::OnMove(void)
|
||||
{
|
||||
//--- position the chart object
|
||||
return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set up the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::OnChange(void)
|
||||
{
|
||||
//--- set up the chart object
|
||||
return(m_button.Width(m_border) && m_button.BmpFileOff(m_bmp_off_name) && m_button.BmpFileOn(m_bmp_on_name));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of activating the group of controls |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::OnActivate(void)
|
||||
{
|
||||
if(m_bmp_active_name!=NULL)
|
||||
BmpOffName(m_bmp_active_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of deactivating the group of controls |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::OnDeactivate(void)
|
||||
{
|
||||
if(m_bmp_passive_name!=NULL)
|
||||
BmpOffName(m_bmp_passive_name);
|
||||
if(!IS_CAN_LOCK)
|
||||
Pressed(false);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the left mouse button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::OnMouseDown(void)
|
||||
{
|
||||
if(!IS_CAN_LOCK)
|
||||
Pressed(!Pressed());
|
||||
//--- call of the method of the parent class
|
||||
return(CWnd::OnMouseDown());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the left mouse button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CBmpButton::OnMouseUp(void)
|
||||
{
|
||||
//--- depress the button if it is not fixed
|
||||
if(m_button.State() && !IS_CAN_LOCK)
|
||||
m_button.State(false);
|
||||
//--- call of the method of the parent class
|
||||
return(CWnd::OnMouseUp());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,146 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Button.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndObj.mqh"
|
||||
#include <ChartObjects\ChartObjectsTxtControls.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CButton |
|
||||
//| Usage: control that is displayed by |
|
||||
//| the CChartObjectButton object |
|
||||
//+------------------------------------------------------------------+
|
||||
class CButton : public CWndObj
|
||||
{
|
||||
private:
|
||||
CChartObjectButton m_button; // chart object
|
||||
|
||||
public:
|
||||
CButton(void);
|
||||
~CButton(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- state
|
||||
bool Pressed(void) const { return(m_button.State()); }
|
||||
bool Pressed(const bool pressed) { return(m_button.State(pressed)); }
|
||||
//--- properties
|
||||
bool Locking(void) const { return(IS_CAN_LOCK); }
|
||||
void Locking(const bool flag);
|
||||
|
||||
protected:
|
||||
//--- handlers of object settings
|
||||
virtual bool OnSetText(void) { return(m_button.Description(m_text)); }
|
||||
virtual bool OnSetColor(void) { return(m_button.Color(m_color)); }
|
||||
virtual bool OnSetColorBackground(void) { return(m_button.BackColor(m_color_background)); }
|
||||
virtual bool OnSetColorBorder(void) { return(m_button.BorderColor(m_color_border)); }
|
||||
virtual bool OnSetFont(void) { return(m_button.Font(m_font)); }
|
||||
virtual bool OnSetFontSize(void) { return(m_button.FontSize(m_font_size)); }
|
||||
//--- internal event handlers
|
||||
virtual bool OnCreate(void);
|
||||
virtual bool OnShow(void);
|
||||
virtual bool OnHide(void);
|
||||
virtual bool OnMove(void);
|
||||
virtual bool OnResize(void);
|
||||
//--- íîâûå îáðàáîò÷èêè
|
||||
virtual bool OnMouseDown(void);
|
||||
virtual bool OnMouseUp(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CButton::CButton(void)
|
||||
{
|
||||
m_color =CONTROLS_BUTTON_COLOR;
|
||||
m_color_background=CONTROLS_BUTTON_COLOR_BG;
|
||||
m_color_border =CONTROLS_BUTTON_COLOR_BORDER;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CButton::~CButton(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call method of the parent class
|
||||
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create the chart object
|
||||
if(!m_button.Create(chart,name,subwin,x1,y1,Width(),Height()))
|
||||
return(false);
|
||||
//--- call the settings handler
|
||||
return(OnChange());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Locking flag |
|
||||
//+------------------------------------------------------------------+
|
||||
void CButton::Locking(const bool flag)
|
||||
{
|
||||
if(flag)
|
||||
PropFlagsSet(WND_PROP_FLAG_CAN_LOCK);
|
||||
else
|
||||
PropFlagsReset(WND_PROP_FLAG_CAN_LOCK);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CButton::OnCreate(void)
|
||||
{
|
||||
//--- create the chart object by previously set parameters
|
||||
return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Display object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CButton::OnShow(void)
|
||||
{
|
||||
return(m_button.Timeframes(OBJ_ALL_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Hide object from chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CButton::OnHide(void)
|
||||
{
|
||||
return(m_button.Timeframes(OBJ_NO_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CButton::OnMove(void)
|
||||
{
|
||||
//--- position the chart object
|
||||
return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resize the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CButton::OnResize(void)
|
||||
{
|
||||
//--- resize the chart object
|
||||
return(m_button.X_Size(m_rect.Width()) && m_button.Y_Size(m_rect.Height()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the left mouse button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CButton::OnMouseDown(void)
|
||||
{
|
||||
if(!IS_CAN_LOCK)
|
||||
Pressed(!Pressed());
|
||||
//--- call of the method of the parent class
|
||||
return(CWnd::OnMouseDown());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the left mouse button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CButton::OnMouseUp(void)
|
||||
{
|
||||
//--- depress the button if it is not fixed
|
||||
if(m_button.State() && !IS_CAN_LOCK)
|
||||
m_button.State(false);
|
||||
//--- call of the method of the parent class
|
||||
return(CWnd::OnMouseUp());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,183 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| CheckBox.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndContainer.mqh"
|
||||
#include "BmpButton.mqh"
|
||||
#include "Edit.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resources |
|
||||
//+------------------------------------------------------------------+
|
||||
#resource "res\\CheckBoxOn.bmp"
|
||||
#resource "res\\CheckBoxOff.bmp"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CCheckBox |
|
||||
//| Usage: class that implements the "CheckBox" control |
|
||||
//+------------------------------------------------------------------+
|
||||
class CCheckBox : public CWndContainer
|
||||
{
|
||||
private:
|
||||
//--- dependent controls
|
||||
CBmpButton m_button; // button object
|
||||
CEdit m_label; // label object
|
||||
//--- data
|
||||
int m_value; // value
|
||||
|
||||
public:
|
||||
CCheckBox(void);
|
||||
~CCheckBox(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- settings
|
||||
string Text(void) const { return(m_label.Text()); }
|
||||
bool Text(const string value) { return(m_label.Text(value)); }
|
||||
color Color(void) const { return(m_label.Color()); }
|
||||
bool Color(const color value) { return(m_label.Color(value)); }
|
||||
//--- state
|
||||
bool Checked(void) const { return(m_button.Pressed()); }
|
||||
bool Checked(const bool flag) { return(m_button.Pressed(flag)); }
|
||||
//--- data
|
||||
int Value(void) const { return(m_value); }
|
||||
void Value(const int value) { m_value=value; }
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
virtual bool CreateButton(void);
|
||||
virtual bool CreateLabel(void);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual bool OnClickButton(void);
|
||||
virtual bool OnClickLabel(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CCheckBox)
|
||||
ON_EVENT(ON_CLICK,m_button,OnClickButton)
|
||||
ON_EVENT(ON_CLICK,m_label,OnClickLabel)
|
||||
EVENT_MAP_END(CWndContainer)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CCheckBox::CCheckBox(void) : m_value(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CCheckBox::~CCheckBox(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckBox::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call method of the parent class
|
||||
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
if(!CreateButton())
|
||||
return(false);
|
||||
if(!CreateLabel())
|
||||
return(false);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckBox::CreateButton(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_CHECK_BUTTON_X_OFF;
|
||||
int y1=CONTROLS_CHECK_BUTTON_Y_OFF;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE-CONTROLS_BORDER_WIDTH;
|
||||
//--- create
|
||||
if(!m_button.Create(m_chart_id,m_name+"Button",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_button.BmpNames("::res\\CheckBoxOff.bmp","::res\\CheckBoxOn.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_button))
|
||||
return(false);
|
||||
m_button.Locking(true);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create label |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckBox::CreateLabel(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_CHECK_LABEL_X_OFF;
|
||||
int y1=CONTROLS_CHECK_LABEL_Y_OFF;
|
||||
int x2=Width();
|
||||
int y2=Height();
|
||||
//--- create
|
||||
if(!m_label.Create(m_chart_id,m_name+"Label",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_label.Text(m_name))
|
||||
return(false);
|
||||
if(!Add(m_label))
|
||||
return(false);
|
||||
m_label.ReadOnly(true);
|
||||
m_label.ColorBackground(CONTROLS_CHECKGROUP_COLOR_BG);
|
||||
m_label.ColorBorder(CONTROLS_CHECKGROUP_COLOR_BG);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckBox::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//---
|
||||
FileWriteInteger(file_handle,Checked());
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckBox::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//---
|
||||
if(!FileIsEnding(file_handle))
|
||||
Checked(FileReadInteger(file_handle));
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckBox::OnClickButton(void)
|
||||
{
|
||||
//--- send the "changed state" event
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on label |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckBox::OnClickLabel(void)
|
||||
{
|
||||
//--- change button state
|
||||
m_button.Pressed(!m_button.Pressed());
|
||||
//--- return the result of the button click handler
|
||||
return(OnClickButton());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,377 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| CheckGroup.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndClient.mqh"
|
||||
#include "CheckBox.mqh"
|
||||
#include <Arrays\ArrayString.mqh>
|
||||
#include <Arrays\ArrayLong.mqh>
|
||||
#include <Arrays\ArrayInt.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CCheckGroup |
|
||||
//| Usage: view and edit group of flags |
|
||||
//+------------------------------------------------------------------+
|
||||
class CCheckGroup : public CWndClient
|
||||
{
|
||||
private:
|
||||
//--- dependent controls
|
||||
CCheckBox m_rows[]; // array of the row objects
|
||||
//--- set up
|
||||
int m_offset; // index of first visible row in array of rows
|
||||
int m_total_view; // number of visible rows
|
||||
int m_item_height; // height of visible row
|
||||
//--- data
|
||||
CArrayString m_strings; // array of rows
|
||||
CArrayLong m_values; // array of values
|
||||
CArrayInt m_states; // array of states
|
||||
long m_value; // current value
|
||||
int m_current; // index of current row in array of rows
|
||||
|
||||
public:
|
||||
CCheckGroup(void);
|
||||
~CCheckGroup(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
virtual void Destroy(const int reason=0);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- fill
|
||||
virtual bool AddItem(const string item,const long value=0);
|
||||
//--- data
|
||||
long Value(void) const;
|
||||
bool Value(const long value);
|
||||
int Check(const int idx) const;
|
||||
bool Check(const int idx,const int value);
|
||||
//--- state
|
||||
virtual bool Show(void);
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
bool CreateButton(int index);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual bool OnVScrollShow(void);
|
||||
virtual bool OnVScrollHide(void);
|
||||
virtual bool OnScrollLineDown(void);
|
||||
virtual bool OnScrollLineUp(void);
|
||||
virtual bool OnChangeItem(const int row_index);
|
||||
//--- redraw
|
||||
bool Redraw(void);
|
||||
bool RowState(const int index,const bool select);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CCheckGroup)
|
||||
ON_INDEXED_EVENT(ON_CHANGE,m_rows,OnChangeItem)
|
||||
EVENT_MAP_END(CWndClient)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CCheckGroup::CCheckGroup(void) : m_offset(0),
|
||||
m_total_view(0),
|
||||
m_item_height(CONTROLS_LIST_ITEM_HEIGHT),
|
||||
m_current(CONTROLS_INVALID_INDEX),
|
||||
m_value(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CCheckGroup::~CCheckGroup(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- determine the number of visible rows
|
||||
m_total_view=(y2-y1)/m_item_height;
|
||||
//--- check the number of visible rows
|
||||
if(m_total_view<1)
|
||||
return(false);
|
||||
//--- call method of the parent class
|
||||
if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- set up
|
||||
if(!m_background.ColorBackground(CONTROLS_CHECKGROUP_COLOR_BG))
|
||||
return(false);
|
||||
if(!m_background.ColorBorder(CONTROLS_CHECKGROUP_COLOR_BORDER))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
ArrayResize(m_rows,m_total_view);
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
if(!CreateButton(i))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete group of controls |
|
||||
//+------------------------------------------------------------------+
|
||||
void CCheckGroup::Destroy(const int reason)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
CWndClient::Destroy(reason);
|
||||
//--- clear items
|
||||
m_strings.Clear();
|
||||
m_values.Clear();
|
||||
m_states.Clear();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create "row" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::CreateButton(int index)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_BORDER_WIDTH;
|
||||
int y1=CONTROLS_BORDER_WIDTH+m_item_height*index;
|
||||
int x2=Width()-CONTROLS_BORDER_WIDTH;
|
||||
int y2=y1+m_item_height;
|
||||
//--- create
|
||||
if(!m_rows[index].Create(m_chart_id,m_name+"Item"+IntegerToString(index),m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_rows[index].Text(""))
|
||||
return(false);
|
||||
if(!Add(m_rows[index]))
|
||||
return(false);
|
||||
m_rows[index].Hide();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add item (row) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::AddItem(const string item,const long value)
|
||||
{
|
||||
//--- add
|
||||
if(!m_strings.Add(item))
|
||||
return(false);
|
||||
if(!m_values.Add(value))
|
||||
return(false);
|
||||
if(!m_states.Add(0))
|
||||
return(false);
|
||||
//--- number of items
|
||||
int total=m_strings.Total();
|
||||
//--- exit if number of items does not exceed the size of visible area
|
||||
if(total<m_total_view+1)
|
||||
{
|
||||
if(IS_VISIBLE && total!=0)
|
||||
m_rows[total-1].Show();
|
||||
return(Redraw());
|
||||
}
|
||||
//--- if number of items exceeded the size of visible area
|
||||
if(total==m_total_view+1)
|
||||
{
|
||||
//--- enable vertical scrollbar
|
||||
if(!VScrolled(true))
|
||||
return(false);
|
||||
//--- and immediately make it invisible (if needed)
|
||||
if(!IS_VISIBLE)
|
||||
m_scroll_v.Visible(false);
|
||||
}
|
||||
//--- set up the scrollbar
|
||||
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
long CCheckGroup::Value(void) const
|
||||
{
|
||||
return(m_value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::Value(const long value)
|
||||
{
|
||||
m_value=value;
|
||||
//---
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
int CCheckGroup::Check(const int idx) const
|
||||
{
|
||||
//--- check
|
||||
if(idx>=m_values.Total())
|
||||
return(0);
|
||||
//---
|
||||
return(m_states[idx]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::Check(const int idx,const int value)
|
||||
{
|
||||
//--- check
|
||||
if(idx>=m_values.Total())
|
||||
return(false);
|
||||
//---
|
||||
bool res=(m_states.Update(idx,value) && Redraw());
|
||||
//--- change value
|
||||
if(res && idx<64)
|
||||
{
|
||||
if(m_rows[idx].Checked())
|
||||
Value(m_value|m_values.At(idx));
|
||||
else
|
||||
Value(m_value&(~m_values.At(idx)));
|
||||
}
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the group visible |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::Show(void)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
if(!CWndClient::Show())
|
||||
return(false);
|
||||
//--- loop by rows
|
||||
int total=m_values.Total();
|
||||
for(int i=total;i<m_total_view;i++)
|
||||
m_rows[i].Hide();
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//---
|
||||
FileWriteLong(file_handle,Value());
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//---
|
||||
if(!FileIsEnding(file_handle))
|
||||
Value(FileReadLong(file_handle));
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Redraw |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::Redraw(void)
|
||||
{
|
||||
//--- loop by "rows"
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
{
|
||||
//--- copy text
|
||||
if(!m_rows[i].Text(m_strings[i+m_offset]))
|
||||
return(false);
|
||||
//--- select
|
||||
if(!RowState(i,m_states[i+m_offset]!=0))
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Change state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::RowState(const int index,const bool select)
|
||||
{
|
||||
//--- check index
|
||||
if(index<0 || index>=ArraySize(m_rows))
|
||||
return(true);
|
||||
//--- change state
|
||||
return(m_rows[index].Checked(select));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Show vertical scrollbar" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::OnVScrollShow(void)
|
||||
{
|
||||
//--- loop by "rows"
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
{
|
||||
//--- resize "rows" according to shown vertical scrollbar
|
||||
m_rows[i].Width(Width()-(CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH));
|
||||
}
|
||||
//--- check visibility
|
||||
if(!IS_VISIBLE)
|
||||
{
|
||||
m_scroll_v.Visible(false);
|
||||
return(true);
|
||||
}
|
||||
//--- event is handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Hide vertical scrollbar" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::OnVScrollHide(void)
|
||||
{
|
||||
//--- check visibility
|
||||
if(!IS_VISIBLE)
|
||||
return(true);
|
||||
//--- loop by "rows"
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
{
|
||||
//--- resize "rows" according to hidden vertical scroll bar
|
||||
m_rows[i].Width(Width()-CONTROLS_BORDER_WIDTH);
|
||||
}
|
||||
//--- event is handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Scroll up for one row" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::OnScrollLineUp(void)
|
||||
{
|
||||
//--- get new offset
|
||||
m_offset=m_scroll_v.CurrPos();
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Scroll down for one row" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::OnScrollLineDown(void)
|
||||
{
|
||||
//--- get new offset
|
||||
m_offset=m_scroll_v.CurrPos();
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of changing a "row" state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CCheckGroup::OnChangeItem(const int row_index)
|
||||
{
|
||||
//--- change value
|
||||
m_states.Update(row_index+m_offset,m_rows[row_index].Checked());
|
||||
if(row_index+m_offset<64)
|
||||
{
|
||||
if(m_rows[row_index].Checked())
|
||||
Value(m_value|m_values.At(row_index+m_offset));
|
||||
else
|
||||
Value(m_value&(~m_values.At(row_index+m_offset)));
|
||||
}
|
||||
//--- send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,324 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ComboBox.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndContainer.mqh"
|
||||
#include "Edit.mqh"
|
||||
#include "BmpButton.mqh"
|
||||
#include "ListView.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resources |
|
||||
//+------------------------------------------------------------------+
|
||||
//--- Can not place the same file into resource twice
|
||||
#resource "res\\DropOn.bmp" // image file
|
||||
#resource "res\\DropOff.bmp" // image file
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CComboBox |
|
||||
//| Usage: drop-down list |
|
||||
//+------------------------------------------------------------------+
|
||||
class CComboBox : public CWndContainer
|
||||
{
|
||||
private:
|
||||
//--- dependent controls
|
||||
CEdit m_edit; // the entry field object
|
||||
CBmpButton m_drop; // the button object
|
||||
CListView m_list; // the drop-down list object
|
||||
//--- set up
|
||||
int m_item_height; // height of visible row
|
||||
int m_view_items; // number of visible rows in the drop-down list
|
||||
|
||||
public:
|
||||
CComboBox(void);
|
||||
~CComboBox(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- fill
|
||||
bool AddItem(const string item,const long value=0);
|
||||
//--- set up
|
||||
void ListViewItems(const int value) { m_view_items=value; }
|
||||
//--- data
|
||||
virtual bool ItemAdd(const string item,const long value=0) { return(m_list.ItemAdd(item,value)); }
|
||||
virtual bool ItemInsert(const int index,const string item,const long value=0) { return(m_list.ItemInsert(index,item,value)); }
|
||||
virtual bool ItemUpdate(const int index,const string item,const long value=0) { return(m_list.ItemUpdate(index,item,value)); }
|
||||
virtual bool ItemDelete(const int index) { return(m_list.ItemDelete(index)); }
|
||||
virtual bool ItemsClear(void) { return(m_list.ItemsClear()); }
|
||||
//--- data
|
||||
string Select(void) { return(m_edit.Text()); }
|
||||
bool Select(const int index);
|
||||
bool SelectByText(const string text);
|
||||
bool SelectByValue(const long value);
|
||||
//--- data (read only)
|
||||
long Value(void) { return(m_list.Value()); }
|
||||
//--- state
|
||||
virtual bool Show(void);
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
virtual bool CreateEdit(void);
|
||||
virtual bool CreateButton(void);
|
||||
virtual bool CreateList(void);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual bool OnClickEdit(void);
|
||||
virtual bool OnClickButton(void);
|
||||
virtual bool OnChangeList(void);
|
||||
//--- show drop-down list
|
||||
bool ListShow(void);
|
||||
bool ListHide(void);
|
||||
void CheckListHide(const int id,int x,int y);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CComboBox)
|
||||
ON_EVENT(ON_CLICK,m_edit,OnClickEdit)
|
||||
ON_EVENT(ON_CLICK,m_drop,OnClickButton)
|
||||
ON_EVENT(ON_CHANGE,m_list,OnChangeList)
|
||||
CheckListHide(id,(int)lparam,(int)dparam);
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_END(CWndContainer)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CComboBox::CComboBox(void) : m_item_height(CONTROLS_COMBO_ITEM_HEIGHT),
|
||||
m_view_items(CONTROLS_COMBO_ITEMS_VIEW)
|
||||
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CComboBox::~CComboBox(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- check height
|
||||
if(y2-y1<CONTROLS_COMBO_MIN_HEIGHT)
|
||||
return(false);
|
||||
//--- call method of the parent class
|
||||
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
if(!CreateEdit())
|
||||
return(false);
|
||||
if(!CreateButton())
|
||||
return(false);
|
||||
if(!CreateList())
|
||||
return(false);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create main entry field |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::CreateEdit(void)
|
||||
{
|
||||
//--- create
|
||||
if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,0,0,Width(),Height()))
|
||||
return(false);
|
||||
if(!m_edit.Text(""))
|
||||
return(false);
|
||||
if(!m_edit.ReadOnly(true))
|
||||
return(false);
|
||||
if(!Add(m_edit))
|
||||
return(false);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::CreateButton(void)
|
||||
{
|
||||
//--- right align button (try to make equal offsets from top and bottom)
|
||||
int x1=Width()-(CONTROLS_BUTTON_SIZE+CONTROLS_COMBO_BUTTON_X_OFF);
|
||||
int y1=(Height()-CONTROLS_BUTTON_SIZE)/2;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE;
|
||||
//--- create
|
||||
if(!m_drop.Create(m_chart_id,m_name+"Drop",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_drop.BmpNames("::res\\DropOff.bmp","::res\\DropOn.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_drop))
|
||||
return(false);
|
||||
m_drop.Locking(true);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create drop-down list |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::CreateList(void)
|
||||
{
|
||||
//--- create
|
||||
if(m_list.TotalView(m_view_items))
|
||||
{
|
||||
if(!m_list.Create(m_chart_id,m_name+"List",m_subwin,0,Height(),Width(),0))
|
||||
return(false);
|
||||
if(!Add(m_list))
|
||||
return(false);
|
||||
m_list.Hide();
|
||||
}
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add item (row) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::AddItem(const string item,const long value)
|
||||
{
|
||||
//--- add item to list
|
||||
return(m_list.AddItem(item,value));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select item |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::Select(const int index)
|
||||
{
|
||||
if(!m_list.Select(index))
|
||||
return(false);
|
||||
//--- call the handler
|
||||
return(OnChangeList());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select item (by text) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::SelectByText(const string text)
|
||||
{
|
||||
if(!m_list.SelectByText(text))
|
||||
return(false);
|
||||
//--- call the handler
|
||||
return(OnChangeList());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Select item (by value) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::SelectByValue(const long value)
|
||||
{
|
||||
if(!m_list.SelectByValue(value))
|
||||
return(false);
|
||||
//--- call the handler
|
||||
return(OnChangeList());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the control visible |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::Show(void)
|
||||
{
|
||||
m_edit.Show();
|
||||
m_drop.Show();
|
||||
m_list.Hide();
|
||||
//--- call of the method of the parent class
|
||||
return(CWnd::Show());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//---
|
||||
FileWriteLong(file_handle,Value());
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//---
|
||||
if(!FileIsEnding(file_handle))
|
||||
SelectByValue(FileReadLong(file_handle));
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on main entry field |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::OnClickEdit(void)
|
||||
{
|
||||
//--- change button state
|
||||
if(!m_drop.Pressed(!m_drop.Pressed()))
|
||||
return(false);
|
||||
//--- call the click on button handler
|
||||
return(OnClickButton());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::OnClickButton(void)
|
||||
{
|
||||
//--- show or hide the drop-down list depending on the button state
|
||||
return((m_drop.Pressed()) ? ListShow() : ListHide());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on drop-down list |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::OnChangeList(void)
|
||||
{
|
||||
string text=m_list.Select();
|
||||
//--- hide the list, depress the button
|
||||
ListHide();
|
||||
m_drop.Pressed(false);
|
||||
//--- set text in the main entry field
|
||||
m_edit.Text(text);
|
||||
//--- send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Show the drop-down list |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::ListShow(void)
|
||||
{
|
||||
BringToTop();
|
||||
//--- show the list
|
||||
return(m_list.Show());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Hide drop-down list |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CComboBox::ListHide(void)
|
||||
{
|
||||
//--- hide the list
|
||||
return(m_list.Hide());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Hide the drop-down element if necessary |
|
||||
//+------------------------------------------------------------------+
|
||||
void CComboBox::CheckListHide(const int id,int x,int y)
|
||||
{
|
||||
//--- check event ID
|
||||
if(id!=CHARTEVENT_CLICK)
|
||||
return;
|
||||
//--- check visibility of the drop-down element
|
||||
if(!m_list.IsVisible())
|
||||
return;
|
||||
//--- check mouse cursor's position
|
||||
y-=(int)ChartGetInteger(m_chart_id,CHART_WINDOW_YDISTANCE,m_subwin);
|
||||
if(!m_edit.Contains(x,y) && !m_list.Contains(x,y))
|
||||
{
|
||||
m_drop.Pressed(false);
|
||||
m_list.Hide();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,413 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DateDropList.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndContainer.mqh"
|
||||
#include "BmpButton.mqh"
|
||||
#include "Picture.mqh"
|
||||
#include <Canvas\Canvas.mqh>
|
||||
#include <Tools\DateTime.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Enumerations |
|
||||
//+------------------------------------------------------------------+
|
||||
//--- date modes
|
||||
enum ENUM_DATE_MODES
|
||||
{
|
||||
DATE_MODE_MON, // month mode
|
||||
DATE_MODE_YEAR // year mode
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resources |
|
||||
//+------------------------------------------------------------------+
|
||||
//--- Can not place the same file into resource twice
|
||||
#resource "res\\LeftTransp.bmp"
|
||||
#resource "res\\RightTransp.bmp"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CDateDropList |
|
||||
//| Usage: drop-down list |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDateDropList : public CWndContainer
|
||||
{
|
||||
private:
|
||||
//--- dependent controls
|
||||
CBmpButton m_dec; // the button object
|
||||
CBmpButton m_inc; // the button object
|
||||
CPicture m_list; // the drop-down list object
|
||||
CCanvas m_canvas; // and its canvas
|
||||
//--- data
|
||||
CDateTime m_value; // current value
|
||||
//--- variable
|
||||
ENUM_DATE_MODES m_mode; // operation mode
|
||||
CRect m_click_rect[32]; // array of click sensibility areas on canvas
|
||||
|
||||
public:
|
||||
CDateDropList(void);
|
||||
~CDateDropList(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- data
|
||||
datetime Value(void) { return(StructToTime(m_value)); }
|
||||
void Value(datetime value) { m_value.Date(value); }
|
||||
void Value(MqlDateTime& value) { (MqlDateTime&)m_value=value; }
|
||||
//--- state
|
||||
virtual bool Show(void);
|
||||
|
||||
protected:
|
||||
//--- internal event handlers
|
||||
virtual bool OnClick(void);
|
||||
//--- create dependent controls
|
||||
virtual bool CreateButtons(void);
|
||||
virtual bool CreateList(void);
|
||||
//--- draw
|
||||
void DrawCanvas(void);
|
||||
void DrawClickRect(const int idx,int x,int y,string text,const uint clr,uint alignment=0);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual bool OnClickDec(void);
|
||||
virtual bool OnClickInc(void);
|
||||
virtual bool OnClickList(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CDateDropList)
|
||||
ON_EVENT(ON_CLICK,m_dec,OnClickDec)
|
||||
ON_EVENT(ON_CLICK,m_inc,OnClickInc)
|
||||
ON_EVENT(ON_CLICK,m_list,OnClickList)
|
||||
EVENT_MAP_END(CWndContainer)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDateDropList::CDateDropList(void) : m_mode(DATE_MODE_MON)
|
||||
{
|
||||
ZeroMemory(m_value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDateDropList::~CDateDropList(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDateDropList::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- need to find dimensions depending on font size
|
||||
//--- width 7 columns + 2 offsets
|
||||
int w=7*(2*CONTROLS_FONT_SIZE)+2*CONTROLS_FONT_SIZE;
|
||||
//--- header height + 7 rows
|
||||
int h=(CONTROLS_BUTTON_SIZE+4*CONTROLS_BORDER_WIDTH)+7*(2*CONTROLS_FONT_SIZE);
|
||||
//--- call method of the parent class
|
||||
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x1+w,y1+h))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
if(!CreateList())
|
||||
return(false);
|
||||
if(!CreateButtons())
|
||||
return(false);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create drop-down list |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDateDropList::CreateList(void)
|
||||
{
|
||||
//--- create object
|
||||
if(!m_list.Create(m_chart_id,m_name+"List",m_subwin,0,0,Width(),Height()))
|
||||
return(false);
|
||||
if(!Add(m_list))
|
||||
return(false);
|
||||
//--- create canvas
|
||||
if(!m_canvas.Create(m_name,Width(),Height()))
|
||||
return(false);
|
||||
m_canvas.FontSet(CONTROLS_FONT_NAME,CONTROLS_FONT_SIZE*(-10));
|
||||
m_list.BmpName(m_canvas.ResourceName());
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create buttons |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDateDropList::CreateButtons(void)
|
||||
{
|
||||
//--- right align button (try to make equal offsets from top and bottom)
|
||||
int x1=2*CONTROLS_BORDER_WIDTH;
|
||||
int y1=2*CONTROLS_BORDER_WIDTH;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE;
|
||||
//--- create "Dec" button
|
||||
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_dec.BmpNames("::res\\LeftTransp.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_dec))
|
||||
return(false);
|
||||
//---
|
||||
x2=Width()-2*CONTROLS_BORDER_WIDTH;
|
||||
x1=x2-CONTROLS_BUTTON_SIZE;
|
||||
//--- create "Inc" button
|
||||
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_inc.BmpNames("::res\\RightTransp.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_inc))
|
||||
return(false);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the control visible |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDateDropList::Show(void)
|
||||
{
|
||||
//--- draw canvas
|
||||
DrawCanvas();
|
||||
//--- call method of the parent class
|
||||
return(CWndContainer::Show());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDateDropList::OnClickDec(void)
|
||||
{
|
||||
switch(m_mode)
|
||||
{
|
||||
//--- within the month
|
||||
case DATE_MODE_MON:
|
||||
m_value.MonDec();
|
||||
break;
|
||||
//--- within the year
|
||||
case DATE_MODE_YEAR:
|
||||
m_value.YearDec();
|
||||
break;
|
||||
}
|
||||
DrawCanvas();
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDateDropList::OnClickInc(void)
|
||||
{
|
||||
switch(m_mode)
|
||||
{
|
||||
//--- within the month
|
||||
case DATE_MODE_MON:
|
||||
m_value.MonInc();
|
||||
break;
|
||||
//--- within the year
|
||||
case DATE_MODE_YEAR:
|
||||
m_value.YearInc();
|
||||
break;
|
||||
}
|
||||
DrawCanvas();
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on picture |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDateDropList::OnClickList(void)
|
||||
{
|
||||
m_mouse_x=m_list.MouseX();
|
||||
m_mouse_y=m_list.MouseY();
|
||||
//---
|
||||
OnClick();
|
||||
//---
|
||||
m_mouse_x=0;
|
||||
m_mouse_y=0;
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "click" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDateDropList::OnClick(void)
|
||||
{
|
||||
for(int i=0;i<32;i++)
|
||||
{
|
||||
if(m_click_rect[i].Contains(m_mouse_x,m_mouse_y))
|
||||
{
|
||||
if(i==0)
|
||||
{
|
||||
//--- clicked on the header
|
||||
switch(m_mode)
|
||||
{
|
||||
//--- within the month
|
||||
case DATE_MODE_MON:
|
||||
//--- switch to the "within the year" mode
|
||||
m_mode=DATE_MODE_YEAR;
|
||||
DrawCanvas();
|
||||
break;
|
||||
//--- within the year
|
||||
case DATE_MODE_YEAR:
|
||||
//--- do nothing for now
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- selected
|
||||
switch(m_mode)
|
||||
{
|
||||
//--- within the month
|
||||
case DATE_MODE_MON:
|
||||
m_value.Day(i);
|
||||
Hide();
|
||||
//--- send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
|
||||
break;
|
||||
//--- within the year
|
||||
case DATE_MODE_YEAR:
|
||||
m_value.Mon(i);
|
||||
m_mode=DATE_MODE_MON;
|
||||
DrawCanvas();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draw canvas |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateDropList::DrawCanvas(void)
|
||||
{
|
||||
int x,y;
|
||||
int dx,dy;
|
||||
string text;
|
||||
uint text_al=TA_CENTER|TA_VCENTER;
|
||||
CDateTime tmp_date;
|
||||
int rows,cols;
|
||||
int idx;
|
||||
//--- zero out array of areas
|
||||
for(int i=0;i<32;i++)
|
||||
ZeroMemory(m_click_rect[i]);
|
||||
//---
|
||||
m_canvas.Erase(COLOR2RGB(CONTROLS_EDIT_COLOR_BG));
|
||||
m_canvas.Rectangle(0,0,Width()-1,Height()-1,COLOR2RGB(CONTROLS_EDIT_COLOR_BORDER));
|
||||
x=Width()/2;
|
||||
y=CONTROLS_BUTTON_SIZE/2+2*CONTROLS_BORDER_WIDTH;
|
||||
switch(m_mode)
|
||||
{
|
||||
//--- within the month
|
||||
case DATE_MODE_MON:
|
||||
text=m_value.MonthName()+" "+IntegerToString(m_value.year);
|
||||
DrawClickRect(0,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
|
||||
rows=6;
|
||||
cols=7;
|
||||
x=dx=Width()/(cols+1);
|
||||
y+=y;
|
||||
dy=(Height()-y-2*CONTROLS_BORDER_WIDTH)/(rows+1);
|
||||
y+=dy/2;
|
||||
for(int i=0;i<cols;i++,x+=dx)
|
||||
m_canvas.TextOut(x,y,m_value.ShortDayName(i),COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
|
||||
//--- backup data
|
||||
tmp_date=m_value;
|
||||
//--- find the beginning of the first displayed week
|
||||
tmp_date.DayDec(tmp_date.day_of_week);
|
||||
while(tmp_date.mon==m_value.mon && tmp_date.day!=1)
|
||||
tmp_date.DayDec(cols);
|
||||
//--- draw
|
||||
idx=1;
|
||||
y+=dy;
|
||||
for(int i=0;i<rows;i++,y+=dy)
|
||||
{
|
||||
x=dx;
|
||||
for(int j=0;j<cols;j++,x+=dx)
|
||||
{
|
||||
text=IntegerToString(tmp_date.day);
|
||||
if(tmp_date.mon==m_value.mon)
|
||||
{
|
||||
if(tmp_date.day==m_value.day)
|
||||
m_canvas.FillRectangle(x-dx/2,y-dy/2,x+dx/2,y+dy/2,COLOR2RGB(CONTROLS_COLOR_BG_SEL));
|
||||
DrawClickRect(idx++,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
|
||||
}
|
||||
else
|
||||
m_canvas.TextOut(x,y,text,COLOR2RGB(CONTROLS_BUTTON_COLOR_BORDER),text_al);
|
||||
tmp_date.DayInc();
|
||||
}
|
||||
}
|
||||
break;
|
||||
//--- within the year
|
||||
case DATE_MODE_YEAR:
|
||||
text=IntegerToString(m_value.year);
|
||||
DrawClickRect(0,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
|
||||
rows=3;
|
||||
cols=4;
|
||||
x=dx=Width()/(cols+1);
|
||||
y+=y;
|
||||
dy=(Height()-y)/rows;
|
||||
y+=dy/2;
|
||||
for(int i=0;i<rows*cols;i++)
|
||||
{
|
||||
if(i+1==m_value.mon)
|
||||
m_canvas.FillRectangle(x-dx/2,y-dy/4,x+dx/2,y+dy/4,COLOR2RGB(CONTROLS_COLOR_BG_SEL));
|
||||
DrawClickRect(i+1,x,y,m_value.ShortMonthName(i+1),COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
|
||||
if(i%cols==cols-1)
|
||||
{
|
||||
x=dx;
|
||||
y+=dy;
|
||||
}
|
||||
else
|
||||
x+=dx;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_canvas.Update();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDateDropList::DrawClickRect(const int idx,int x,int y,string text,const uint clr,uint alignment)
|
||||
{
|
||||
int text_w,text_h;
|
||||
//--- display the text
|
||||
m_canvas.TextOut(x,y,text,clr,alignment);
|
||||
//--- determine area occupied by text
|
||||
m_canvas.TextSize(text,text_w,text_h);
|
||||
//--- convert relative coordinated to absolute ones
|
||||
x+=Left();
|
||||
y+=Top();
|
||||
//--- check flags of horizontal alignment
|
||||
switch(alignment&(TA_LEFT|TA_CENTER|TA_RIGHT))
|
||||
{
|
||||
case TA_LEFT:
|
||||
m_click_rect[idx].left=x;
|
||||
break;
|
||||
case TA_CENTER:
|
||||
m_click_rect[idx].left=x-text_w/2;
|
||||
break;
|
||||
case TA_RIGHT:
|
||||
m_click_rect[idx].left=x-text_w;
|
||||
break;
|
||||
}
|
||||
m_click_rect[idx].Width(text_w);
|
||||
//--- check flags of vertical alignment
|
||||
switch(alignment&(TA_TOP|TA_VCENTER|TA_BOTTOM))
|
||||
{
|
||||
case TA_TOP:
|
||||
m_click_rect[idx].top=y;
|
||||
break;
|
||||
case TA_VCENTER:
|
||||
m_click_rect[idx].top=y-text_h/2;
|
||||
break;
|
||||
case TA_BOTTOM:
|
||||
m_click_rect[idx].top=y-text_h;
|
||||
break;
|
||||
}
|
||||
m_click_rect[idx].Height(text_h);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,264 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DatePicker.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndContainer.mqh"
|
||||
#include "Edit.mqh"
|
||||
#include "BmpButton.mqh"
|
||||
#include "DateDropList.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resources |
|
||||
//+------------------------------------------------------------------+
|
||||
//--- Can not place the same file into resource twice
|
||||
#resource "res\\DateDropOn.bmp" // image file
|
||||
#resource "res\\DateDropOff.bmp" // image file
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CDatePicker |
|
||||
//| Usage: date picker |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDatePicker : public CWndContainer
|
||||
{
|
||||
private:
|
||||
//--- dependent controls
|
||||
CEdit m_edit; // the entry field object
|
||||
CBmpButton m_drop; // the button object
|
||||
CDateDropList m_list; // the drop-down list object
|
||||
//--- data
|
||||
datetime m_value; // current value
|
||||
|
||||
public:
|
||||
CDatePicker(void);
|
||||
~CDatePicker(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- data
|
||||
datetime Value(void) const { return(m_value); }
|
||||
void Value(datetime value) { m_edit.Text(TimeToString(m_value=value,TIME_DATE)); }
|
||||
//--- state
|
||||
virtual bool Show(void);
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
virtual bool CreateEdit(void);
|
||||
virtual bool CreateButton(void);
|
||||
virtual bool CreateList(void);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual bool OnClickEdit(void);
|
||||
virtual bool OnClickButton(void);
|
||||
virtual bool OnChangeList(void);
|
||||
//--- show drop-down list
|
||||
bool ListShow(void);
|
||||
bool ListHide(void);
|
||||
void CheckListHide(const int id,int x,int y);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CDatePicker)
|
||||
ON_EVENT(ON_CLICK,m_edit,OnClickEdit)
|
||||
ON_EVENT(ON_CLICK,m_drop,OnClickButton)
|
||||
ON_EVENT(ON_CHANGE,m_list,OnChangeList)
|
||||
CheckListHide(id,(int)lparam,(int)dparam);
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_END(CWndContainer)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDatePicker::CDatePicker(void) : m_value(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDatePicker::~CDatePicker(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call method of the parent class
|
||||
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
if(!CreateEdit())
|
||||
return(false);
|
||||
if(!CreateButton())
|
||||
return(false);
|
||||
if(!CreateList())
|
||||
return(false);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create main entry field |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::CreateEdit(void)
|
||||
{
|
||||
//--- create
|
||||
if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,0,0,Width(),Height()))
|
||||
return(false);
|
||||
if(!m_edit.Text(""))
|
||||
return(false);
|
||||
if(!m_edit.ReadOnly(true))
|
||||
return(false);
|
||||
if(!Add(m_edit))
|
||||
return(false);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::CreateButton(void)
|
||||
{
|
||||
//--- right align button (try to make equal offsets from top and bottom)
|
||||
int x1=Width()-(2*CONTROLS_BUTTON_SIZE+CONTROLS_COMBO_BUTTON_X_OFF);
|
||||
int y1=(Height()-CONTROLS_BUTTON_SIZE)/2;
|
||||
int x2=x1+2*CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE;
|
||||
//--- create
|
||||
if(!m_drop.Create(m_chart_id,m_name+"Drop",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_drop.BmpNames("::res\\DateDropOff.bmp","::res\\DateDropOn.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_drop))
|
||||
return(false);
|
||||
m_drop.Locking(true);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create drop-down list |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::CreateList(void)
|
||||
{
|
||||
//--- create
|
||||
if(!m_list.Create(m_chart_id,m_name+"List",m_subwin,0,Height()-1,Width(),0))
|
||||
return(false);
|
||||
if(!Add(m_list))
|
||||
return(false);
|
||||
m_list.Hide();
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the control visible |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::Show(void)
|
||||
{
|
||||
m_edit.Show();
|
||||
m_drop.Show();
|
||||
m_list.Hide();
|
||||
//--- call method of the parent class
|
||||
return(CWnd::Show());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| save |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//--- write
|
||||
FileWriteLong(file_handle,Value());
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| load |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//--- load
|
||||
if(!FileIsEnding(file_handle))
|
||||
Value(FileReadLong(file_handle));
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on main entry field |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::OnClickEdit(void)
|
||||
{
|
||||
//--- change button state
|
||||
if(!m_drop.Pressed(!m_drop.Pressed()))
|
||||
return(false);
|
||||
//--- call the click on button handler
|
||||
return(OnClickButton());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::OnClickButton(void)
|
||||
{
|
||||
//--- show or hide the drop-down list depending on the button state
|
||||
return((m_drop.Pressed()) ? ListShow():ListHide());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of change on drop-down list |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::OnChangeList(void)
|
||||
{
|
||||
string text=TimeToString(m_value=m_list.Value(),TIME_DATE);
|
||||
//--- hide the list, depress the button
|
||||
ListHide();
|
||||
m_drop.Pressed(false);
|
||||
//--- set text in the main entry field
|
||||
m_edit.Text(text);
|
||||
//--- send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Show the drop-down list |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::ListShow(void)
|
||||
{
|
||||
//--- set value
|
||||
m_list.Value(m_value);
|
||||
//--- show the list
|
||||
return(m_list.Show());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Hide drop-down list |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDatePicker::ListHide(void)
|
||||
{
|
||||
//--- hide the list
|
||||
return(m_list.Hide());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Hide the drop-down element if necessary |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDatePicker::CheckListHide(const int id,int x,int y)
|
||||
{
|
||||
//--- check event ID
|
||||
if(id!=CHARTEVENT_CLICK)
|
||||
return;
|
||||
//--- check visibility of the drop-down element
|
||||
if(!m_list.IsVisible())
|
||||
return;
|
||||
//--- check mouse cursor's position
|
||||
y-=(int)ChartGetInteger(m_chart_id,CHART_WINDOW_YDISTANCE,m_subwin);
|
||||
if(!m_edit.Contains(x,y) && !m_list.Contains(x,y))
|
||||
{
|
||||
m_drop.Pressed(false);
|
||||
m_list.Hide();
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,190 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Defines.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Enumerations |
|
||||
//+------------------------------------------------------------------+
|
||||
//--- properties flags
|
||||
enum ENUM_WND_PROP_FLAGS
|
||||
{
|
||||
WND_PROP_FLAG_CAN_DBL_CLICK = 1, // can be double clicked by mouse
|
||||
WND_PROP_FLAG_CAN_DRAG = 2, // can be dragged by mouse
|
||||
WND_PROP_FLAG_CLICKS_BY_PRESS= 4, // generates the "click" event series on pressing left mouse button
|
||||
WND_PROP_FLAG_CAN_LOCK = 8, // control with fixed state (usually it is a button)
|
||||
WND_PROP_FLAG_READ_ONLY =16 // read only (usually it is a edit)
|
||||
};
|
||||
//--- state flags
|
||||
enum ENUM_WND_STATE_FLAGS
|
||||
{
|
||||
WND_STATE_FLAG_ENABLE = 1, // "object is enabled" flag
|
||||
WND_STATE_FLAG_VISIBLE = 2, // "object is visible" flag
|
||||
WND_STATE_FLAG_ACTIVE = 4, // "object is active" flag
|
||||
};
|
||||
//--- mouse flags
|
||||
enum ENUM_MOUSE_FLAGS
|
||||
{
|
||||
MOUSE_INVALID_FLAGS =-1, // no buttons state
|
||||
MOUSE_EMPTY = 0, // buttons are not pressed
|
||||
MOUSE_LEFT = 1, // left button pressed
|
||||
MOUSE_RIGHT = 2 // right button pressed
|
||||
};
|
||||
//--- alignment flags
|
||||
enum ENUM_WND_ALIGN_FLAGS
|
||||
{
|
||||
WND_ALIGN_NONE = 0, // no alignment
|
||||
WND_ALIGN_LEFT = 1, // align by left border
|
||||
WND_ALIGN_TOP = 2, // align by top border
|
||||
WND_ALIGN_RIGHT = 4, // align by right border
|
||||
WND_ALIGN_BOTTOM = 8, // align by bottom border
|
||||
WND_ALIGN_WIDTH = WND_ALIGN_LEFT|WND_ALIGN_RIGHT, // justify
|
||||
WND_ALIGN_HEIGHT = WND_ALIGN_TOP|WND_ALIGN_BOTTOM, // align by top and bottom border
|
||||
WND_ALIGN_CLIENT = WND_ALIGN_WIDTH|WND_ALIGN_HEIGHT // align by all sides
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Drawing styles and colors |
|
||||
//+------------------------------------------------------------------+
|
||||
//--- common
|
||||
#define CONTROLS_FONT_NAME "Trebuchet MS"
|
||||
#define CONTROLS_FONT_SIZE (10)
|
||||
//--- Text
|
||||
#define CONTROLS_COLOR_TEXT C'0x3B,0x29,0x28'
|
||||
#define CONTROLS_COLOR_TEXT_SEL clrWhite
|
||||
#define CONTROLS_COLOR_BG clrWhite
|
||||
#define CONTROLS_COLOR_BG_SEL C'0x33,0x99,0xFF'
|
||||
//--- Button
|
||||
#define CONTROLS_BUTTON_COLOR C'0x3B,0x29,0x28'
|
||||
#define CONTROLS_BUTTON_COLOR_BG C'0xDD,0xE2,0xEB'
|
||||
#define CONTROLS_BUTTON_COLOR_BORDER C'0xB2,0xC3,0xCF'
|
||||
//--- Label
|
||||
#define CONTROLS_LABEL_COLOR C'0x3B,0x29,0x28'
|
||||
//--- Edit
|
||||
#define CONTROLS_EDIT_COLOR C'0x3B,0x29,0x28'
|
||||
#define CONTROLS_EDIT_COLOR_BG clrWhite
|
||||
#define CONTROLS_EDIT_COLOR_BORDER C'0xB2,0xC3,0xCF'
|
||||
//--- Scrolls
|
||||
#define CONTROLS_SCROLL_COLOR_BG C'0xEC,0xEC,0xEC'
|
||||
#define CONTROLS_SCROLL_COLOR_BORDER C'0xD3,0xD3,0xD3'
|
||||
//--- Client
|
||||
#define CONTROLS_CLIENT_COLOR_BG C'0xDE,0xDE,0xDE'
|
||||
#define CONTROLS_CLIENT_COLOR_BORDER C'0x2C,0x2C,0x2C'
|
||||
//--- ListView
|
||||
#define CONTROLS_LISTITEM_COLOR_TEXT C'0x3B,0x29,0x28'
|
||||
#define CONTROLS_LISTITEM_COLOR_TEXT_SEL clrWhite
|
||||
#define CONTROLS_LISTITEM_COLOR_BG clrWhite
|
||||
#define CONTROLS_LISTITEM_COLOR_BG_SEL C'0x33,0x99,0xFF'
|
||||
#define CONTROLS_LIST_COLOR_BG clrWhite
|
||||
#define CONTROLS_LIST_COLOR_BORDER C'0xB2,0xC3,0xCF'
|
||||
//--- CheckGroup
|
||||
#define CONTROLS_CHECKGROUP_COLOR_BG C'0xF7,0xF7,0xF7'
|
||||
#define CONTROLS_CHECKGROUP_COLOR_BORDER C'0xB2,0xC3,0xCF'
|
||||
//--- RadioGroup
|
||||
#define CONTROLS_RADIOGROUP_COLOR_BG C'0xF7,0xF7,0xF7'
|
||||
#define CONTROLS_RADIOGROUP_COLOR_BORDER C'0xB2,0xC3,0xCF'
|
||||
//--- Dialog
|
||||
#define CONTROLS_DIALOG_COLOR_BORDER_LIGHT clrWhite
|
||||
#define CONTROLS_DIALOG_COLOR_BORDER_DARK C'0xB6,0xB6,0xB6'
|
||||
#define CONTROLS_DIALOG_COLOR_BG C'0xF0,0xF0,0xF0'
|
||||
#define CONTROLS_DIALOG_COLOR_CAPTION_TEXT C'0x28,0x29,0x3B'
|
||||
#define CONTROLS_DIALOG_COLOR_CLIENT_BG C'0xF7,0xF7,0xF7'
|
||||
#define CONTROLS_DIALOG_COLOR_CLIENT_BORDER C'0xC8,0xC8,0xC8'
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constants for the controls |
|
||||
//+------------------------------------------------------------------+
|
||||
//--- common
|
||||
#define CONTROLS_INVALID_ID (-1) // invalid ID
|
||||
#define CONTROLS_INVALID_INDEX (-1) // invalid index of array
|
||||
#define CONTROLS_SELF_MESSAGE (-1) // message to oneself
|
||||
#define CONTROLS_MAXIMUM_ID (10000) // maximum number of IDs in application
|
||||
#define CONTROLS_BORDER_WIDTH (1) // border width
|
||||
#define CONTROLS_SUBWINDOW_GAP (3) // gap between sub-windows along the Y axis
|
||||
#define CONTROLS_DRAG_SPACING (50) // sensitivity threshold for dragging
|
||||
#define CONTROLS_DBL_CLICK_TIME (100) // double click interval
|
||||
//--- BmpButton
|
||||
#define CONTROLS_BUTTON_SIZE (16) // default size of button (16 x 16)
|
||||
//--- Scrolls
|
||||
#define CONTROLS_SCROLL_SIZE (18) // default lateral size of scrollbar
|
||||
#define CONTROLS_SCROLL_THUMB_SIZE (22) // default length of scroll box
|
||||
//--- RadioButton
|
||||
#define CONTROLS_RADIO_BUTTON_X_OFF (3) // X offset of radio button (for RadioButton)
|
||||
#define CONTROLS_RADIO_BUTTON_Y_OFF (3) // Y offset of radio button (for RadioButton)
|
||||
#define CONTROLS_RADIO_LABEL_X_OFF (20) // X offset of label (for RadioButton)
|
||||
#define CONTROLS_RADIO_LABEL_Y_OFF (0) // Y offset of label (for RadioButton)
|
||||
//--- CheckBox
|
||||
#define CONTROLS_CHECK_BUTTON_X_OFF (3) // X offset of check button (for CheckBox)
|
||||
#define CONTROLS_CHECK_BUTTON_Y_OFF (3) // Y offset of check button (for CheckBox)
|
||||
#define CONTROLS_CHECK_LABEL_X_OFF (20) // X offset of label (for CheckBox)
|
||||
#define CONTROLS_CHECK_LABEL_Y_OFF (0) // Y offset of label (for CheckBox)
|
||||
//--- Spin
|
||||
#define CONTROLS_SPIN_BUTTON_X_OFF (2) // X offset of button from right (for SpinEdit)
|
||||
#define CONTROLS_SPIN_MIN_HEIGHT (18) // minimal height (for SpinEdit)
|
||||
#define CONTROLS_SPIN_BUTTON_SIZE (8) // default size of button (16 x 8) (for SpinEdit)
|
||||
//--- Combo
|
||||
#define CONTROLS_COMBO_BUTTON_X_OFF (2) // X offset of button from right (for ComboBox)
|
||||
#define CONTROLS_COMBO_MIN_HEIGHT (18) // minimal height (for ComboBox)
|
||||
#define CONTROLS_COMBO_ITEM_HEIGHT (18) // height of combo box item (for ComboBox)
|
||||
#define CONTROLS_COMBO_ITEMS_VIEW (8) // number of items in combo box (for ComboBox)
|
||||
//--- ListView
|
||||
#define CONTROLS_LIST_ITEM_HEIGHT (18) // height of list item (for ListView)
|
||||
//--- Dialog
|
||||
#define CONTROLS_DIALOG_CAPTION_HEIGHT (22) // height of dialog header
|
||||
#define CONTROLS_DIALOG_BUTTON_OFF (3) // offset of dialog buttons
|
||||
#define CONTROLS_DIALOG_CLIENT_OFF (2) // offset of dialog client area
|
||||
#define CONTROLS_DIALOG_MINIMIZE_LEFT (10) // left coordinate of dialog in minimized state
|
||||
#define CONTROLS_DIALOG_MINIMIZE_TOP (10) // top coordinate of dialog in minimized state
|
||||
#define CONTROLS_DIALOG_MINIMIZE_WIDTH (100) // width of dialog in minimized state
|
||||
#define CONTROLS_DIALOG_MINIMIZE_HEIGHT (4*CONTROLS_BORDER_WIDTH+CONTROLS_DIALOG_CAPTION_HEIGHT) // height of dialog in minimized state
|
||||
//+------------------------------------------------------------------+
|
||||
//| Macro |
|
||||
//+------------------------------------------------------------------+
|
||||
//--- check properties
|
||||
#define IS_CAN_DBL_CLICK ((m_prop_flags&WND_PROP_FLAG_CAN_DBL_CLICK)!=0)
|
||||
#define IS_CAN_DRAG ((m_prop_flags&WND_PROP_FLAG_CAN_DRAG)!=0)
|
||||
#define IS_CLICKS_BY_PRESS ((m_prop_flags&WND_PROP_FLAG_CLICKS_BY_PRESS)!=0)
|
||||
#define IS_CAN_LOCK ((m_prop_flags&WND_PROP_FLAG_CAN_LOCK)!=0)
|
||||
#define IS_READ_ONLY ((m_prop_flags&WND_PROP_FLAG_READ_ONLY)!=0)
|
||||
//--- check state
|
||||
#define IS_ENABLED ((m_state_flags&WND_STATE_FLAG_ENABLE)!=0)
|
||||
#define IS_VISIBLE ((m_state_flags&WND_STATE_FLAG_VISIBLE)!=0)
|
||||
#define IS_ACTIVE ((m_state_flags&WND_STATE_FLAG_ACTIVE)!=0)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Macro of event handling map |
|
||||
//+------------------------------------------------------------------+
|
||||
#define INTERNAL_EVENT (-1)
|
||||
//--- beginning of map
|
||||
#define EVENT_MAP_BEGIN(class_name) bool class_name::OnEvent(const int id,const long& lparam,const double& dparam,const string& sparam) {
|
||||
//--- end of map
|
||||
#define EVENT_MAP_END(parent_class_name) return(parent_class_name::OnEvent(id,lparam,dparam,sparam)); }
|
||||
//--- event handling by numeric ID
|
||||
#define ON_EVENT(event,control,handler) if(id==(event+CHARTEVENT_CUSTOM) && lparam==control.Id()) { handler(); return(true); }
|
||||
//--- event handling by numeric ID by pointer of control
|
||||
#define ON_EVENT_PTR(event,control,handler) if(control!=NULL && id==(event+CHARTEVENT_CUSTOM) && lparam==control.Id()) { handler(); return(true); }
|
||||
//--- event handling without ID analysis
|
||||
#define ON_NO_ID_EVENT(event,handler) if(id==(event+CHARTEVENT_CUSTOM)) { return(handler()); }
|
||||
//--- event handling by row ID
|
||||
#define ON_NAMED_EVENT(event,control,handler) if(id==(event+CHARTEVENT_CUSTOM) && sparam==control.Name()) { handler(); return(true); }
|
||||
//--- handling of indexed event
|
||||
#define ON_INDEXED_EVENT(event,controls,handler) { int total=ArraySize(controls); for(int i=0;i<total;i++) if(id==(event+CHARTEVENT_CUSTOM) && lparam==controls[i].Id()) return(handler(i)); }
|
||||
//--- handling of external event
|
||||
#define ON_EXTERNAL_EVENT(event,handler) if(id==(event+CHARTEVENT_CUSTOM)) { handler(lparam,dparam,sparam); return(true); }
|
||||
//+------------------------------------------------------------------+
|
||||
//| Events |
|
||||
//+------------------------------------------------------------------+
|
||||
#define ON_CLICK (0) // clicking on control event
|
||||
#define ON_DBL_CLICK (1) // double clicking on control event
|
||||
#define ON_SHOW (2) // showing control event
|
||||
#define ON_HIDE (3) // hiding control event
|
||||
#define ON_CHANGE (4) // changing control event
|
||||
#define ON_START_EDIT (5) // start of editing event
|
||||
#define ON_END_EDIT (6) // end of editing event
|
||||
#define ON_SCROLL_INC (7) // increment of scrollbar event
|
||||
#define ON_SCROLL_DEC (8) // decrement of scrollbar event
|
||||
#define ON_MOUSE_FOCUS_SET (9) // the "mouse cursor entered the control" event
|
||||
#define ON_MOUSE_FOCUS_KILL (10) // the "mouse cursor exited the control" event
|
||||
#define ON_DRAG_START (11) // the "control dragging start" event
|
||||
#define ON_DRAG_PROCESS (12) // the "control is being dragged" event
|
||||
#define ON_DRAG_END (13) // the "control dragging end" event
|
||||
#define ON_BRING_TO_TOP (14) // the "mouse events priority increase" event
|
||||
#define ON_APP_CLOSE (100) // "closing the application" event
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,971 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Dialog.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndContainer.mqh"
|
||||
#include "WndClient.mqh"
|
||||
#include "Panel.mqh"
|
||||
#include "Edit.mqh"
|
||||
#include "BmpButton.mqh"
|
||||
#include <Charts\Chart.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resources |
|
||||
//+------------------------------------------------------------------+
|
||||
#resource "res\\Close.bmp"
|
||||
#resource "res\\Restore.bmp"
|
||||
#resource "res\\Turn.bmp"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CDialog |
|
||||
//| Usage: base class to create dialog boxes |
|
||||
//| and indicator panels |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDialog : public CWndContainer
|
||||
{
|
||||
private:
|
||||
//--- dependent controls
|
||||
CPanel m_white_border; // the "white border" object
|
||||
CPanel m_background; // the background object
|
||||
CEdit m_caption; // the window title object
|
||||
CBmpButton m_button_close; // the "Close" button object
|
||||
CWndClient m_client_area; // the client area object
|
||||
|
||||
protected:
|
||||
//--- flags
|
||||
bool m_panel_flag; // the "panel in a separate window" flag
|
||||
//--- flags
|
||||
bool m_minimized; // "create in minimized state" flag
|
||||
//--- additional areas
|
||||
CRect m_min_rect; // minimal area coordinates
|
||||
CRect m_norm_rect; // normal area coordinates
|
||||
|
||||
public:
|
||||
CDialog(void);
|
||||
~CDialog(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- set up
|
||||
string Caption(void) const { return(m_caption.Text()); }
|
||||
bool Caption(const string text) { return(m_caption.Text(text)); }
|
||||
//--- fill
|
||||
bool Add(CWnd *control);
|
||||
bool Add(CWnd &control);
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
virtual bool CreateWhiteBorder(void);
|
||||
virtual bool CreateBackground(void);
|
||||
virtual bool CreateCaption(void);
|
||||
virtual bool CreateButtonClose(void);
|
||||
virtual bool CreateClientArea(void);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual void OnClickCaption(void);
|
||||
virtual void OnClickButtonClose(void);
|
||||
//--- access properties of caption
|
||||
void CaptionAlignment(const int flags,const int left,const int top,const int right,const int bottom)
|
||||
{ m_caption.Alignment(flags,left,top,right,bottom); }
|
||||
//--- access properties of client area
|
||||
bool ClientAreaVisible(const bool visible) { return(m_client_area.Visible(visible)); }
|
||||
int ClientAreaLeft(void) const { return(m_client_area.Left()); }
|
||||
int ClientAreaTop(void) const { return(m_client_area.Top()); }
|
||||
int ClientAreaRight(void) const { return(m_client_area.Right()); }
|
||||
int ClientAreaBottom(void) const { return(m_client_area.Bottom()); }
|
||||
int ClientAreaWidth(void) const { return(m_client_area.Width()); }
|
||||
int ClientAreaHeight(void) const { return(m_client_area.Height()); }
|
||||
//--- handlers of drag
|
||||
virtual bool OnDialogDragStart(void);
|
||||
virtual bool OnDialogDragProcess(void);
|
||||
virtual bool OnDialogDragEnd(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CDialog)
|
||||
ON_EVENT(ON_CLICK,m_button_close,OnClickButtonClose)
|
||||
ON_EVENT(ON_CLICK,m_caption,OnClickCaption)
|
||||
ON_EVENT(ON_DRAG_START,m_caption,OnDialogDragStart)
|
||||
ON_EVENT_PTR(ON_DRAG_PROCESS,m_drag_object,OnDialogDragProcess)
|
||||
ON_EVENT_PTR(ON_DRAG_END,m_drag_object,OnDialogDragEnd)
|
||||
EVENT_MAP_END(CWndContainer)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDialog::CDialog(void) : m_panel_flag(false),
|
||||
m_minimized(false)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDialog::~CDialog(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call method of parent class
|
||||
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
if(!m_panel_flag && !CreateWhiteBorder())
|
||||
return(false);
|
||||
if(!CreateBackground())
|
||||
return(false);
|
||||
if(!CreateCaption())
|
||||
return(false);
|
||||
if(!CreateButtonClose())
|
||||
return(false);
|
||||
if(!CreateClientArea())
|
||||
return(false);
|
||||
//--- set up additional areas
|
||||
m_norm_rect.SetBound(m_rect);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add control to the client area (by pointer) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::Add(CWnd *control)
|
||||
{
|
||||
return(m_client_area.Add(control));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add control to the client area (by reference) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::Add(CWnd &control)
|
||||
{
|
||||
return(m_client_area.Add(control));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Save |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//--- save
|
||||
FileWriteStruct(file_handle,m_norm_rect);
|
||||
FileWriteInteger(file_handle,m_min_rect.left);
|
||||
FileWriteInteger(file_handle,m_min_rect.top);
|
||||
FileWriteInteger(file_handle,m_minimized);
|
||||
//--- result
|
||||
return(CWndContainer::Save(file_handle));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Load |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::Load(const int file_handle)
|
||||
{
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//--- load
|
||||
if(!FileIsEnding(file_handle))
|
||||
{
|
||||
FileReadStruct(file_handle,m_norm_rect);
|
||||
int left=FileReadInteger(file_handle);
|
||||
int top=FileReadInteger(file_handle);
|
||||
m_min_rect.Move(left,top);
|
||||
m_minimized=FileReadInteger(file_handle);
|
||||
}
|
||||
//--- result
|
||||
return(CWndContainer::Load(file_handle));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create "white border" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::CreateWhiteBorder(void)
|
||||
{
|
||||
//--- coordinates
|
||||
int x1=0;
|
||||
int y1=0;
|
||||
int x2=Width();
|
||||
int y2=Height();
|
||||
//--- create
|
||||
if(!m_white_border.Create(m_chart_id,m_name+"Border",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_white_border.ColorBackground(CONTROLS_DIALOG_COLOR_BG))
|
||||
return(false);
|
||||
if(!m_white_border.ColorBorder(CONTROLS_DIALOG_COLOR_BORDER_LIGHT))
|
||||
return(false);
|
||||
if(!CWndContainer::Add(m_white_border))
|
||||
return(false);
|
||||
m_white_border.Alignment(WND_ALIGN_CLIENT,0,0,0,0);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create background |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::CreateBackground(void)
|
||||
{
|
||||
int off=(m_panel_flag) ? 0:CONTROLS_BORDER_WIDTH;
|
||||
//--- coordinates
|
||||
int x1=off;
|
||||
int y1=off;
|
||||
int x2=Width()-off;
|
||||
int y2=Height()-off;
|
||||
//--- create
|
||||
if(!m_background.Create(m_chart_id,m_name+"Back",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_background.ColorBackground(CONTROLS_DIALOG_COLOR_BG))
|
||||
return(false);
|
||||
color border=(m_panel_flag) ? CONTROLS_DIALOG_COLOR_BG : CONTROLS_DIALOG_COLOR_BORDER_DARK;
|
||||
if(!m_background.ColorBorder(border))
|
||||
return(false);
|
||||
if(!CWndContainer::Add(m_background))
|
||||
return(false);
|
||||
m_background.Alignment(WND_ALIGN_CLIENT,off,off,off,off);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create window title |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::CreateCaption(void)
|
||||
{
|
||||
int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH;
|
||||
//--- coordinates
|
||||
int x1=off;
|
||||
int y1=off;
|
||||
int x2=Width()-off;
|
||||
int y2=y1+CONTROLS_DIALOG_CAPTION_HEIGHT;
|
||||
//--- create
|
||||
if(!m_caption.Create(m_chart_id,m_name+"Caption",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_caption.Color(CONTROLS_DIALOG_COLOR_CAPTION_TEXT))
|
||||
return(false);
|
||||
if(!m_caption.ColorBackground(CONTROLS_DIALOG_COLOR_BG))
|
||||
return(false);
|
||||
if(!m_caption.ColorBorder(CONTROLS_DIALOG_COLOR_BG))
|
||||
return(false);
|
||||
if(!m_caption.ReadOnly(true))
|
||||
return(false);
|
||||
if(!m_caption.Text(m_name))
|
||||
return(false);
|
||||
if(!CWndContainer::Add(m_caption))
|
||||
return(false);
|
||||
m_caption.Alignment(WND_ALIGN_WIDTH,off,0,off,0);
|
||||
if(!m_panel_flag)
|
||||
m_caption.PropFlags(WND_PROP_FLAG_CAN_DRAG);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create the "Close" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::CreateButtonClose(void)
|
||||
{
|
||||
int off=(m_panel_flag) ? 0 : 2*CONTROLS_BORDER_WIDTH;
|
||||
//--- coordinates
|
||||
int x1=Width()-off-(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF);
|
||||
int y1=off+CONTROLS_DIALOG_BUTTON_OFF;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE;
|
||||
//--- create
|
||||
if(!m_button_close.Create(m_chart_id,m_name+"Close",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_button_close.BmpNames("::res\\Close.bmp"))
|
||||
return(false);
|
||||
if(!CWndContainer::Add(m_button_close))
|
||||
return(false);
|
||||
m_button_close.Alignment(WND_ALIGN_RIGHT,0,0,off+CONTROLS_DIALOG_BUTTON_OFF,0);
|
||||
//--- change caption
|
||||
CaptionAlignment(WND_ALIGN_WIDTH,off,0,off+(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF),0);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create client area |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::CreateClientArea(void)
|
||||
{
|
||||
int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH;
|
||||
//--- coordinates
|
||||
int x1=off+CONTROLS_DIALOG_CLIENT_OFF;
|
||||
int y1=off+CONTROLS_DIALOG_CAPTION_HEIGHT;
|
||||
int x2=Width()-(off+CONTROLS_DIALOG_CLIENT_OFF);
|
||||
int y2=Height()-(off+CONTROLS_DIALOG_CLIENT_OFF);
|
||||
//--- create
|
||||
if(!m_client_area.Create(m_chart_id,m_name+"Client",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_client_area.ColorBackground(CONTROLS_DIALOG_COLOR_CLIENT_BG))
|
||||
return(false);
|
||||
if(!m_client_area.ColorBorder(CONTROLS_DIALOG_COLOR_CLIENT_BORDER))
|
||||
return(false);
|
||||
CWndContainer::Add(m_client_area);
|
||||
m_client_area.Alignment(WND_ALIGN_CLIENT,x1,y1,x1,x1);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the window title |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDialog::OnClickCaption(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the "Close" button |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDialog::OnClickButtonClose(void)
|
||||
{
|
||||
Visible(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Start dragging the dialog box |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::OnDialogDragStart(void)
|
||||
{
|
||||
if(m_drag_object==NULL)
|
||||
{
|
||||
m_drag_object=new CDragWnd;
|
||||
if(m_drag_object==NULL)
|
||||
return(false);
|
||||
}
|
||||
//--- calculate coordinates
|
||||
int x1=Left()-CONTROLS_DRAG_SPACING;
|
||||
int y1=Top()-CONTROLS_DRAG_SPACING;
|
||||
int x2=Right()+CONTROLS_DRAG_SPACING;
|
||||
int y2=Bottom()+CONTROLS_DRAG_SPACING;
|
||||
//--- create
|
||||
m_drag_object.Create(m_chart_id,"",m_subwin,x1,y1,x2,y2);
|
||||
m_drag_object.PropFlags(WND_PROP_FLAG_CAN_DRAG);
|
||||
//--- constraints
|
||||
CChart chart;
|
||||
chart.Attach(m_chart_id);
|
||||
m_drag_object.Limits(-CONTROLS_DRAG_SPACING,-CONTROLS_DRAG_SPACING,
|
||||
chart.WidthInPixels()+CONTROLS_DRAG_SPACING,
|
||||
chart.HeightInPixels(m_subwin)+CONTROLS_DRAG_SPACING);
|
||||
chart.Detach();
|
||||
//--- set mouse params
|
||||
m_drag_object.MouseX(m_caption.MouseX());
|
||||
m_drag_object.MouseY(m_caption.MouseY());
|
||||
m_drag_object.MouseFlags(m_caption.MouseFlags());
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Continue dragging the dialog box |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::OnDialogDragProcess(void)
|
||||
{
|
||||
//--- checking
|
||||
if(m_drag_object==NULL)
|
||||
return(false);
|
||||
//--- calculate coordinates
|
||||
int x=m_drag_object.Left()+50;
|
||||
int y=m_drag_object.Top()+50;
|
||||
//--- move dialog
|
||||
Move(x,y);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| End dragging the dialog box |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDialog::OnDialogDragEnd(void)
|
||||
{
|
||||
if(m_drag_object!=NULL)
|
||||
{
|
||||
m_caption.MouseFlags(m_drag_object.MouseFlags());
|
||||
delete m_drag_object;
|
||||
m_drag_object=NULL;
|
||||
}
|
||||
//--- set up additional areas
|
||||
if(m_minimized)
|
||||
m_min_rect.SetBound(m_rect);
|
||||
else
|
||||
m_norm_rect.SetBound(m_rect);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CAppDialog |
|
||||
//| Usage: main dialog box of MQL5 application |
|
||||
//+------------------------------------------------------------------+
|
||||
class CAppDialog : public CDialog
|
||||
{
|
||||
private:
|
||||
//--- dependent controls
|
||||
CBmpButton m_button_minmax; // the "Minimize/Maximize" button object
|
||||
//--- variables
|
||||
string m_program_name; // name of program
|
||||
string m_instance_id; // unique string ID
|
||||
ENUM_PROGRAM_TYPE m_program_type; // type of program
|
||||
string m_indicator_name;
|
||||
int m_deinit_reason;
|
||||
//--- for mouse
|
||||
int m_subwin_Yoff; // subwindow Y offset
|
||||
CWnd* m_focused_wnd; // pointer to object that has mouse focus
|
||||
CWnd* m_top_wnd; // pointer to object that has priority over mouse events handling
|
||||
|
||||
protected:
|
||||
CChart m_chart; // object to access chart
|
||||
|
||||
public:
|
||||
CAppDialog(void);
|
||||
~CAppDialog(void);
|
||||
//--- main application dialog creation and destroy
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
virtual void Destroy(const int reason=REASON_PROGRAM);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- dialog run
|
||||
bool Run(void);
|
||||
//--- chart events processing
|
||||
void ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- set up
|
||||
void Minimized(const bool flag) { m_minimized=flag; }
|
||||
//--- to save/restore state
|
||||
void IniFileSave(void);
|
||||
void IniFileLoad(void);
|
||||
virtual string IniFileName(void) const;
|
||||
virtual string IniFileExt(void) const { return(".dat"); }
|
||||
virtual bool Load(const int file_handle);
|
||||
virtual bool Save(const int file_handle);
|
||||
|
||||
private:
|
||||
bool CreateCommon(const long chart,const string name,const int subwin);
|
||||
bool CreateExpert(const int x1,const int y1,const int x2,const int y2);
|
||||
bool CreateIndicator(const int x1,const int y1,const int x2,const int y2);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
virtual bool CreateButtonMinMax(void);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual void OnClickButtonClose(void);
|
||||
virtual void OnClickButtonMinMax(void);
|
||||
//--- external event handlers
|
||||
virtual void OnAnotherApplicationClose(const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- methods
|
||||
virtual bool Rebound(const CRect &rect);
|
||||
virtual void Minimize(void);
|
||||
virtual void Maximize(void);
|
||||
string CreateInstanceId(void);
|
||||
string ProgramName(void) const { return(m_program_name); }
|
||||
void SubwinOff(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CAppDialog)
|
||||
ON_EVENT(ON_CLICK,m_button_minmax,OnClickButtonMinMax)
|
||||
ON_EXTERNAL_EVENT(ON_APP_CLOSE,OnAnotherApplicationClose)
|
||||
EVENT_MAP_END(CDialog)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CAppDialog::CAppDialog(void) : m_program_type(WRONG_VALUE),
|
||||
m_deinit_reason(WRONG_VALUE),
|
||||
m_subwin_Yoff(0),
|
||||
m_focused_wnd(NULL),
|
||||
m_top_wnd(NULL)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CAppDialog::~CAppDialog(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Application dialog initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CAppDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
if(!CreateCommon(chart,name,subwin))
|
||||
return(false);
|
||||
//---
|
||||
switch(m_program_type)
|
||||
{
|
||||
case PROGRAM_EXPERT:
|
||||
if(!CreateExpert(x1,y1,x2,y2))
|
||||
return(false);
|
||||
break;
|
||||
case PROGRAM_INDICATOR:
|
||||
if(!CreateIndicator(x1,y1,x2,y2))
|
||||
return(false);
|
||||
break;
|
||||
default:
|
||||
Print("CAppDialog: invalid program type");
|
||||
return(false);
|
||||
}
|
||||
//--- Title of dialog window
|
||||
if(!Caption(m_program_name))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
if(!CreateButtonMinMax())
|
||||
return(false);
|
||||
//--- get subwindow offset
|
||||
SubwinOff();
|
||||
//--- if flag is set, minimize the dialog
|
||||
if(m_minimized)
|
||||
Minimize();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize common area |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CAppDialog::CreateCommon(const long chart,const string name,const int subwin)
|
||||
{
|
||||
//--- save parameters
|
||||
m_chart_id =chart;
|
||||
m_name =name;
|
||||
m_subwin =subwin;
|
||||
m_program_name =name;
|
||||
m_deinit_reason=WRONG_VALUE;
|
||||
//--- get unique ID
|
||||
m_instance_id=CreateInstanceId();
|
||||
//--- initialize chart object
|
||||
m_chart.Attach(chart);
|
||||
//--- determine type of program
|
||||
m_program_type=(ENUM_PROGRAM_TYPE)MQLInfoInteger(MQL_PROGRAM_TYPE);
|
||||
//--- specify object and mouse events
|
||||
if(!m_chart.EventObjectCreate() || !m_chart.EventObjectDelete() || !m_chart.EventMouseMove())
|
||||
{
|
||||
Print("CAppDialog: object events specify error");
|
||||
m_chart.Detach();
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize in Expert Advisor |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CAppDialog::CreateExpert(const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- EA works only in main window
|
||||
m_subwin=0;
|
||||
//--- geometry for the minimized state
|
||||
m_min_rect.SetBound(CONTROLS_DIALOG_MINIMIZE_LEFT,
|
||||
CONTROLS_DIALOG_MINIMIZE_TOP,
|
||||
CONTROLS_DIALOG_MINIMIZE_LEFT+CONTROLS_DIALOG_MINIMIZE_WIDTH,
|
||||
CONTROLS_DIALOG_MINIMIZE_TOP+CONTROLS_DIALOG_MINIMIZE_HEIGHT);
|
||||
//--- call method of the parent class
|
||||
if(!CDialog::Create(m_chart.ChartId(),m_instance_id,m_subwin,x1,y1,x2,y2))
|
||||
{
|
||||
Print("CAppDialog: expert dialog create error");
|
||||
m_chart.Detach();
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize in Indicator |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CAppDialog::CreateIndicator(const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
int width=m_chart.WidthInPixels();
|
||||
//--- geometry for the minimized state
|
||||
m_min_rect.LeftTop(0,0);
|
||||
m_min_rect.Width(width);
|
||||
m_min_rect.Height(CONTROLS_DIALOG_MINIMIZE_HEIGHT-2*CONTROLS_BORDER_WIDTH);
|
||||
//--- determine subwindow
|
||||
m_subwin=ChartWindowFind();
|
||||
if(m_subwin==-1)
|
||||
{
|
||||
Print("CAppDialog: find subwindow error");
|
||||
m_chart.Detach();
|
||||
return(false);
|
||||
}
|
||||
//---
|
||||
int total=ChartIndicatorsTotal(m_chart.ChartId(),m_subwin);
|
||||
m_indicator_name=ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1);
|
||||
//--- if subwindow number is 0 (main window), then our program is
|
||||
//--- not an indicator panel, but is an indicator with built-in settings dialog
|
||||
//--- dialog of such an indicator should behave as an Expert Advisor dialog
|
||||
if(m_subwin==0)
|
||||
return(CreateExpert(x1,y1,x2,y2));
|
||||
//--- if subwindow number is not 0, then our program is an indicator panel
|
||||
//--- check if subwindow is not occupied by other indicators
|
||||
if(total!=1)
|
||||
{
|
||||
Print("CAppDialog: subwindow busy");
|
||||
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
|
||||
m_chart.Detach();
|
||||
return(false);
|
||||
}
|
||||
//--- resize subwindow by dialog height
|
||||
if(!IndicatorSetInteger(INDICATOR_HEIGHT,(y2-y1)+1))
|
||||
{
|
||||
Print("CAppDialog: subwindow resize error");
|
||||
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
|
||||
m_chart.Detach();
|
||||
return(false);
|
||||
}
|
||||
//--- indicator short name
|
||||
m_indicator_name=m_program_name+IntegerToString(m_subwin);
|
||||
if(!IndicatorSetString(INDICATOR_SHORTNAME,m_indicator_name))
|
||||
{
|
||||
Print("CAppDialog: shortname error");
|
||||
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
|
||||
m_chart.Detach();
|
||||
return(false);
|
||||
}
|
||||
//--- set flag
|
||||
m_panel_flag=true;
|
||||
//--- call method of the parent class
|
||||
if(!CDialog::Create(m_chart.ChartId(),m_instance_id,m_subwin,0,0,width,y2-y1))
|
||||
{
|
||||
Print("CAppDialog: indicator dialog create error");
|
||||
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
|
||||
m_chart.Detach();
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Application dialog deinitialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
void CAppDialog::Destroy(const int reason)
|
||||
{
|
||||
//--- destroyed already?
|
||||
if(m_deinit_reason!=WRONG_VALUE)
|
||||
return;
|
||||
//---
|
||||
m_deinit_reason=reason;
|
||||
IniFileSave();
|
||||
//--- detach chart object from chart
|
||||
m_chart.Detach();
|
||||
//--- call parent destroy
|
||||
CDialog::Destroy();
|
||||
//---
|
||||
if(reason==REASON_PROGRAM)
|
||||
{
|
||||
if(m_program_type==PROGRAM_EXPERT)
|
||||
ExpertRemove();
|
||||
if(m_program_type==PROGRAM_INDICATOR)
|
||||
ChartIndicatorDelete(m_chart_id,m_subwin,m_indicator_name);
|
||||
}
|
||||
//--- send message
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_APP_CLOSE,m_subwin,0.0,m_program_name);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Calculate subwindow offset |
|
||||
//+------------------------------------------------------------------+
|
||||
void CAppDialog::SubwinOff(void)
|
||||
{
|
||||
m_subwin_Yoff=m_chart.SubwindowY(m_subwin);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create the "Minimize/Maximize" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CAppDialog::CreateButtonMinMax(void)
|
||||
{
|
||||
int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH;
|
||||
//--- coordinates
|
||||
int x1=Width()-off-2*(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF);
|
||||
int y1=off+CONTROLS_DIALOG_BUTTON_OFF;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE;
|
||||
//--- create
|
||||
if(!m_button_minmax.Create(m_chart_id,m_name+"MinMax",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_button_minmax.BmpNames("::res\\Turn.bmp","::res\\Restore.bmp"))
|
||||
return(false);
|
||||
if(!CWndContainer::Add(m_button_minmax))
|
||||
return(false);
|
||||
m_button_minmax.Locking(true);
|
||||
m_button_minmax.Alignment(WND_ALIGN_RIGHT,0,0,off+CONTROLS_BUTTON_SIZE+2*CONTROLS_DIALOG_BUTTON_OFF,0);
|
||||
//--- change caption
|
||||
CaptionAlignment(WND_ALIGN_WIDTH,off,0,off+2*(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF),0);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Charts event processing |
|
||||
//+------------------------------------------------------------------+
|
||||
void CAppDialog::ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
|
||||
{
|
||||
int mouse_x=(int)lparam;
|
||||
int mouse_y=(int)dparam-m_subwin_Yoff;
|
||||
//--- separate mouse events from others
|
||||
switch(id)
|
||||
{
|
||||
case CHARTEVENT_CHART_CHANGE:
|
||||
//--- assumed that the CHARTEVENT_CHART_CHANGE event can handle only the application dialog
|
||||
break;
|
||||
case CHARTEVENT_OBJECT_CLICK:
|
||||
//--- we won't handle the CHARTEVENT_OBJECT_CLICK event, as we are working with the CHARTEVENT_MOUSE_MOVE events
|
||||
return;
|
||||
case CHARTEVENT_CUSTOM+ON_MOUSE_FOCUS_SET:
|
||||
//--- the CHARTEVENT_CUSTOM + ON_MOUSE_FOCUS_SET event
|
||||
if(CheckPointer(m_focused_wnd)!=POINTER_INVALID)
|
||||
{
|
||||
//--- if there is an element with focus, try to take its focus away
|
||||
if(!m_focused_wnd.MouseFocusKill(lparam))
|
||||
return;
|
||||
}
|
||||
m_focused_wnd=ControlFind(lparam);
|
||||
return;
|
||||
case CHARTEVENT_CUSTOM+ON_BRING_TO_TOP:
|
||||
m_top_wnd=ControlFind(lparam);
|
||||
return;
|
||||
case CHARTEVENT_MOUSE_MOVE:
|
||||
//--- the CHARTEVENT_MOUSE_MOVE event
|
||||
if(CheckPointer(m_top_wnd)!=POINTER_INVALID)
|
||||
{
|
||||
//--- if a priority element already exists, pass control to it
|
||||
if(m_top_wnd.OnMouseEvent(mouse_x,mouse_y,(int)StringToInteger(sparam)))
|
||||
{
|
||||
//--- event handled
|
||||
m_chart.Redraw();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(OnMouseEvent(mouse_x,mouse_y,(int)StringToInteger(sparam)))
|
||||
m_chart.Redraw();
|
||||
return;
|
||||
default:
|
||||
//--- call event processing and redraw chart if event handled
|
||||
if(OnEvent(id,lparam,dparam,sparam))
|
||||
m_chart.Redraw();
|
||||
return;
|
||||
}
|
||||
//--- if event was not handled, try to handle the CHARTEVENT_CHART_CHANGE event
|
||||
if(id==CHARTEVENT_CHART_CHANGE)
|
||||
{
|
||||
//--- if subwindow number is not 0, and dialog subwindow has changed its number, then restart
|
||||
if(m_subwin!=0 && m_subwin!=ChartWindowFind())
|
||||
{
|
||||
long fiction=1;
|
||||
OnAnotherApplicationClose(fiction,dparam,sparam);
|
||||
}
|
||||
//--- if subwindow height is less that dialog height, minimize application window (always)
|
||||
if(m_chart.HeightInPixels(m_subwin)<Height()+CONTROLS_BORDER_WIDTH)
|
||||
{
|
||||
m_button_minmax.Pressed(true);
|
||||
Minimize();
|
||||
m_chart.Redraw();
|
||||
}
|
||||
//--- if chart width is less that dialog width, and subwindow number is not 0, try to modify dialog width
|
||||
if(m_chart.WidthInPixels()!=Width() && m_subwin!=0)
|
||||
{
|
||||
Width(m_chart.WidthInPixels());
|
||||
m_chart.Redraw();
|
||||
}
|
||||
//--- get subwindow offset
|
||||
SubwinOff();
|
||||
return;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Run application |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CAppDialog::Run(void)
|
||||
{
|
||||
//--- redraw chart for dialog invalidate
|
||||
m_chart.Redraw();
|
||||
//--- here we begin to assign IDs to controls
|
||||
if(Id(m_subwin*CONTROLS_MAXIMUM_ID)>CONTROLS_MAXIMUM_ID)
|
||||
{
|
||||
Print("CAppDialog: too many objects");
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Stop application |
|
||||
//+------------------------------------------------------------------+
|
||||
void CAppDialog::OnClickButtonClose(void)
|
||||
{
|
||||
//--- destroy application
|
||||
Destroy();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the "Minimize/Maximize" button |
|
||||
//+------------------------------------------------------------------+
|
||||
void CAppDialog::OnClickButtonMinMax(void)
|
||||
{
|
||||
if(m_button_minmax.Pressed())
|
||||
Minimize();
|
||||
else
|
||||
Maximize();
|
||||
//--- get subwindow offset
|
||||
SubwinOff();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resize |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CAppDialog::Rebound(const CRect &rect)
|
||||
{
|
||||
if(!Move(rect.LeftTop()))
|
||||
return(false);
|
||||
if(!Size(rect.Size()))
|
||||
return(false);
|
||||
//--- resize subwindow
|
||||
if(m_program_type==PROGRAM_INDICATOR && !IndicatorSetInteger(INDICATOR_HEIGHT,rect.Height()+1))
|
||||
{
|
||||
Print("CAppDialog: subwindow resize error");
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Minimize dialog window |
|
||||
//+------------------------------------------------------------------+
|
||||
void CAppDialog::Minimize(void)
|
||||
{
|
||||
//--- set flag
|
||||
m_minimized=true;
|
||||
//--- resize
|
||||
Rebound(m_min_rect);
|
||||
//--- hide client area
|
||||
ClientAreaVisible(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Restore dialog window |
|
||||
//+------------------------------------------------------------------+
|
||||
void CAppDialog::Maximize(void)
|
||||
{
|
||||
//--- reset flag
|
||||
m_minimized=false;
|
||||
//--- resize
|
||||
Rebound(m_norm_rect);
|
||||
//--- show client area
|
||||
ClientAreaVisible(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create unique prefix for object names |
|
||||
//+------------------------------------------------------------------+
|
||||
string CAppDialog::CreateInstanceId(void)
|
||||
{
|
||||
return(IntegerToString(rand(),5,'0'));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the ON_APP_CLOSE external event |
|
||||
//+------------------------------------------------------------------+
|
||||
void CAppDialog::OnAnotherApplicationClose(const long &lparam,const double &dparam,const string &sparam)
|
||||
{
|
||||
//--- exit if we are in the main window
|
||||
if(m_subwin==0)
|
||||
return;
|
||||
//--- exit if external program was closed in main window
|
||||
if(lparam==0)
|
||||
return;
|
||||
//--- get subwindow offset
|
||||
SubwinOff();
|
||||
//--- exit if external program was closed in subwindow with greater number
|
||||
if(lparam>=m_subwin)
|
||||
return;
|
||||
//--- after all the checks we must change the subwindow
|
||||
//--- get the new number of subwindow
|
||||
m_subwin=ChartWindowFind();
|
||||
//--- change short name
|
||||
m_indicator_name=m_program_name+IntegerToString(m_subwin);
|
||||
IndicatorSetString(INDICATOR_SHORTNAME,m_indicator_name);
|
||||
//--- change dialog title
|
||||
Caption(m_program_name);
|
||||
//--- reassign IDs
|
||||
Run();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Save the current state of the program |
|
||||
//+------------------------------------------------------------------+
|
||||
void CAppDialog::IniFileSave(void)
|
||||
{
|
||||
string filename=IniFileName()+IniFileExt();
|
||||
int handle=FileOpen(filename,FILE_WRITE|FILE_BIN|FILE_ANSI);
|
||||
//---
|
||||
if(handle!=INVALID_HANDLE)
|
||||
{
|
||||
Save(handle);
|
||||
FileClose(handle);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Read the previous state of the program |
|
||||
//+------------------------------------------------------------------+
|
||||
void CAppDialog::IniFileLoad(void)
|
||||
{
|
||||
string filename=IniFileName()+IniFileExt();
|
||||
int handle=FileOpen(filename,FILE_READ|FILE_BIN|FILE_ANSI);
|
||||
//---
|
||||
if(handle!=INVALID_HANDLE)
|
||||
{
|
||||
Load(handle);
|
||||
FileClose(handle);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Generate the filename |
|
||||
//+------------------------------------------------------------------+
|
||||
string CAppDialog::IniFileName(void) const
|
||||
{
|
||||
string name;
|
||||
//---
|
||||
name=(m_indicator_name!=NULL) ? m_indicator_name : m_program_name;
|
||||
//---
|
||||
name+="_"+Symbol();
|
||||
name+="_Ini";
|
||||
//---
|
||||
return(name);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Load data |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CAppDialog::Load(const int file_handle)
|
||||
{
|
||||
if(CDialog::Load(file_handle))
|
||||
{
|
||||
if(m_minimized)
|
||||
{
|
||||
m_button_minmax.Pressed(true);
|
||||
Minimize();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_button_minmax.Pressed(false);
|
||||
Maximize();
|
||||
}
|
||||
int prev_deinit_reason=FileReadInteger(file_handle);
|
||||
if(prev_deinit_reason==REASON_CHARTCLOSE || prev_deinit_reason==REASON_CLOSE)
|
||||
{
|
||||
//--- if the previous time program ended after closing the chart window,
|
||||
//--- delete object left since the last start of the program
|
||||
string prev_instance_id=IntegerToString(FileReadInteger(file_handle),5,'0');
|
||||
if(prev_instance_id!=m_instance_id)
|
||||
{
|
||||
long chart_id=m_chart.ChartId();
|
||||
int total=ObjectsTotal(chart_id,m_subwin);
|
||||
for(int i=total-1;i>=0;i--)
|
||||
{
|
||||
string obj_name=ObjectName(chart_id,i,m_subwin);
|
||||
if(StringFind(obj_name,prev_instance_id)==0)
|
||||
ObjectDelete(chart_id,obj_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Save data |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CAppDialog::Save(const int file_handle)
|
||||
{
|
||||
if(CDialog::Save(file_handle))
|
||||
{
|
||||
FileWriteInteger(file_handle,m_deinit_reason);
|
||||
FileWriteInteger(file_handle,(int)StringToInteger(m_instance_id));
|
||||
return(true);
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,188 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Edit.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndObj.mqh"
|
||||
#include <ChartObjects\ChartObjectsTxtControls.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CEdit |
|
||||
//| Usage: control that is displayed by |
|
||||
//| the CChartObjectEdit object |
|
||||
//+------------------------------------------------------------------+
|
||||
class CEdit : public CWndObj
|
||||
{
|
||||
private:
|
||||
CChartObjectEdit m_edit; // chart object
|
||||
//--- parameters of the chart object
|
||||
bool m_read_only; // "read-only" mode flag
|
||||
ENUM_ALIGN_MODE m_align_mode; // align mode
|
||||
|
||||
public:
|
||||
CEdit(void);
|
||||
~CEdit(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- parameters of the chart object
|
||||
bool ReadOnly(void) const { return(m_read_only); }
|
||||
bool ReadOnly(const bool flag);
|
||||
ENUM_ALIGN_MODE TextAlign(void) const { return(m_align_mode); }
|
||||
bool TextAlign(const ENUM_ALIGN_MODE align);
|
||||
//--- data access
|
||||
string Text(void) const { return(m_edit.Description()); }
|
||||
bool Text(const string value) { return(CWndObj::Text(value)); }
|
||||
|
||||
protected:
|
||||
//--- handlers of object events
|
||||
virtual bool OnObjectEndEdit(void);
|
||||
//--- handlers of object settings
|
||||
virtual bool OnSetText(void) { return(m_edit.Description(m_text)); }
|
||||
virtual bool OnSetColor(void) { return(m_edit.Color(m_color)); }
|
||||
virtual bool OnSetColorBackground(void) { return(m_edit.BackColor(m_color_background)); }
|
||||
virtual bool OnSetColorBorder(void) { return(m_edit.BorderColor(m_color_border)); }
|
||||
virtual bool OnSetFont(void) { return(m_edit.Font(m_font)); }
|
||||
virtual bool OnSetFontSize(void) { return(m_edit.FontSize(m_font_size)); }
|
||||
virtual bool OnSetZOrder(void) { return(m_edit.Z_Order(m_zorder)); }
|
||||
//--- internal event handlers
|
||||
virtual bool OnCreate(void);
|
||||
virtual bool OnShow(void);
|
||||
virtual bool OnHide(void);
|
||||
virtual bool OnMove(void);
|
||||
virtual bool OnResize(void);
|
||||
virtual bool OnChange(void);
|
||||
virtual bool OnClick(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
|
||||
{
|
||||
if(m_name==sparam && id==CHARTEVENT_OBJECT_ENDEDIT)
|
||||
return(OnObjectEndEdit());
|
||||
//--- event was not handled
|
||||
return(CWndObj::OnEvent(id,lparam,dparam,sparam));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CEdit::CEdit(void) : m_read_only(false),
|
||||
m_align_mode(ALIGN_LEFT)
|
||||
{
|
||||
m_color =CONTROLS_EDIT_COLOR;
|
||||
m_color_background=CONTROLS_EDIT_COLOR_BG;
|
||||
m_color_border =CONTROLS_EDIT_COLOR_BORDER;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CEdit::~CEdit(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call method of the parent class
|
||||
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create the chart object
|
||||
if(!m_edit.Create(chart,name,subwin,x1,y1,Width(),Height()))
|
||||
return(false);
|
||||
//--- call the settings handler
|
||||
return(OnChange());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::ReadOnly(const bool flag)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_read_only=flag;
|
||||
//--- set up the chart object
|
||||
return(m_edit.ReadOnly(flag));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::TextAlign(const ENUM_ALIGN_MODE align)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_align_mode=align;
|
||||
//--- set up the chart object
|
||||
return(m_edit.TextAlign(align));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::OnCreate(void)
|
||||
{
|
||||
//--- create the chart object by previously set parameters
|
||||
return(m_edit.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Display object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::OnShow(void)
|
||||
{
|
||||
return(m_edit.Timeframes(OBJ_ALL_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Hide object from chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::OnHide(void)
|
||||
{
|
||||
return(m_edit.Timeframes(OBJ_NO_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::OnMove(void)
|
||||
{
|
||||
//--- position the chart object
|
||||
return(m_edit.X_Distance(m_rect.left) && m_edit.Y_Distance(m_rect.top));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resize the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::OnResize(void)
|
||||
{
|
||||
//--- resize the chart object
|
||||
return(m_edit.X_Size(m_rect.Width()) && m_edit.Y_Size(m_rect.Height()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set up the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::OnChange(void)
|
||||
{
|
||||
//--- set up the chart object
|
||||
return(CWndObj::OnChange() && ReadOnly(m_read_only) && TextAlign(m_align_mode));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "End of editing" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::OnObjectEndEdit(void)
|
||||
{
|
||||
//--- send the ON_END_EDIT notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_END_EDIT,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "click" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CEdit::OnClick(void)
|
||||
{
|
||||
//--- if editing is enabled, send the ON_START_EDIT notification
|
||||
if(!m_read_only)
|
||||
{
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_START_EDIT,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//--- else send the ON_CLICK notification
|
||||
return(CWnd::OnClick());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,93 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Label.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndObj.mqh"
|
||||
#include <ChartObjects\ChartObjectsTxtControls.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CLabel |
|
||||
//| Usage: control that is displayed by |
|
||||
//| the CChartObjectLabel object |
|
||||
//+------------------------------------------------------------------+
|
||||
class CLabel : public CWndObj
|
||||
{
|
||||
private:
|
||||
CChartObjectLabel m_label; // chart object
|
||||
|
||||
public:
|
||||
CLabel(void);
|
||||
~CLabel(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
|
||||
protected:
|
||||
//--- handlers of object settings
|
||||
virtual bool OnSetText(void) { return(m_label.Description(m_text)); }
|
||||
virtual bool OnSetColor(void) { return(m_label.Color(m_color)); }
|
||||
virtual bool OnSetFont(void) { return(m_label.Font(m_font)); }
|
||||
virtual bool OnSetFontSize(void) { return(m_label.FontSize(m_font_size)); }
|
||||
//--- internal event handlers
|
||||
virtual bool OnCreate(void);
|
||||
virtual bool OnShow(void);
|
||||
virtual bool OnHide(void);
|
||||
virtual bool OnMove(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CLabel::CLabel(void)
|
||||
{
|
||||
m_color=CONTROLS_LABEL_COLOR;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CLabel::~CLabel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLabel::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call method of the parent class
|
||||
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create the chart object
|
||||
if(!m_label.Create(chart,name,subwin,x1,y1))
|
||||
return(false);
|
||||
//--- call the settings handler
|
||||
return(OnChange());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLabel::OnCreate(void)
|
||||
{
|
||||
//--- create the chart object by previously set parameters
|
||||
return(m_label.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Display object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLabel::OnShow(void)
|
||||
{
|
||||
return(m_label.Timeframes(OBJ_ALL_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Hide object from chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLabel::OnHide(void)
|
||||
{
|
||||
return(m_label.Timeframes(OBJ_NO_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLabel::OnMove(void)
|
||||
{
|
||||
//--- position the chart object
|
||||
return(m_label.X_Distance(m_rect.left) && m_label.Y_Distance(m_rect.top));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,544 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ListView.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndClient.mqh"
|
||||
#include "Edit.mqh"
|
||||
#include <Arrays\ArrayString.mqh>
|
||||
#include <Arrays\ArrayLong.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CListView |
|
||||
//| Usage: display lists |
|
||||
//+------------------------------------------------------------------+
|
||||
class CListView : public CWndClient
|
||||
{
|
||||
private:
|
||||
//--- dependent controls
|
||||
CEdit m_rows[]; // array of the row objects
|
||||
//--- set up
|
||||
int m_offset; // index of first visible row in array of rows
|
||||
int m_total_view; // number of visible rows
|
||||
int m_item_height; // height of visible row
|
||||
bool m_height_variable; // ïðèçíàê ïåðåìåííîé âûñîòû ñïèñêà
|
||||
//--- data
|
||||
CArrayString m_strings; // array of rows
|
||||
CArrayLong m_values; // array of values
|
||||
int m_current; // index of current row in array of rows
|
||||
|
||||
public:
|
||||
CListView(void);
|
||||
~CListView(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
virtual void Destroy(const int reason=0);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- set up
|
||||
bool TotalView(const int value);
|
||||
//--- fill
|
||||
virtual bool AddItem(const string item,const long value=0);
|
||||
//--- data
|
||||
virtual bool ItemAdd(const string item,const long value=0);
|
||||
virtual bool ItemInsert(const int index,const string item,const long value=0);
|
||||
virtual bool ItemUpdate(const int index,const string item,const long value=0);
|
||||
virtual bool ItemDelete(const int index);
|
||||
virtual bool ItemsClear(void);
|
||||
//--- data
|
||||
int Current(void) { return(m_current); }
|
||||
string Select(void) { return(m_strings.At(m_current)); }
|
||||
bool Select(const int index);
|
||||
bool SelectByText(const string text);
|
||||
bool SelectByValue(const long value);
|
||||
//--- data (read only)
|
||||
long Value(void) { return(m_values.At(m_current)); }
|
||||
//--- state
|
||||
virtual bool Show(void);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
bool CreateRow(const int index);
|
||||
//--- event handlers
|
||||
virtual bool OnResize(void);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual bool OnVScrollShow(void);
|
||||
virtual bool OnVScrollHide(void);
|
||||
virtual bool OnScrollLineDown(void);
|
||||
virtual bool OnScrollLineUp(void);
|
||||
virtual bool OnItemClick(const int index);
|
||||
//--- redraw
|
||||
bool Redraw(void);
|
||||
bool RowState(const int index,const bool select);
|
||||
bool CheckView(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CListView)
|
||||
ON_INDEXED_EVENT(ON_CLICK,m_rows,OnItemClick)
|
||||
EVENT_MAP_END(CWndClient)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CListView::CListView(void) : m_offset(0),
|
||||
m_total_view(0),
|
||||
m_item_height(CONTROLS_LIST_ITEM_HEIGHT),
|
||||
m_current(CONTROLS_INVALID_INDEX),
|
||||
m_height_variable(false)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CListView::~CListView(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
int y=y2;
|
||||
//--- if the number of visible rows is previously determined, adjust the vertical size
|
||||
if(!TotalView((y2-y1)/m_item_height))
|
||||
y=m_item_height+y1+2*CONTROLS_BORDER_WIDTH;
|
||||
//--- check the number of visible rows
|
||||
if(m_total_view<1)
|
||||
return(false);
|
||||
//--- call method of the parent class
|
||||
if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y))
|
||||
return(false);
|
||||
//--- set up
|
||||
if(!m_background.ColorBackground(CONTROLS_LIST_COLOR_BG))
|
||||
return(false);
|
||||
if(!m_background.ColorBorder(CONTROLS_LIST_COLOR_BORDER))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
ArrayResize(m_rows,m_total_view);
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
{
|
||||
if(!CreateRow(i))
|
||||
return(false);
|
||||
if(m_height_variable && i>0)
|
||||
m_rows[i].Hide();
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete group of controls |
|
||||
//+------------------------------------------------------------------+
|
||||
void CListView::Destroy(const int reason)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
CWndClient::Destroy(reason);
|
||||
//--- clear items
|
||||
m_strings.Clear();
|
||||
m_values.Clear();
|
||||
//---
|
||||
m_offset =0;
|
||||
m_total_view=0;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::TotalView(const int value)
|
||||
{
|
||||
//--- if parameter is not equal to 0, modifications are not possible
|
||||
if(m_total_view!=0)
|
||||
{
|
||||
m_height_variable=true;
|
||||
return(false);
|
||||
}
|
||||
//--- save value
|
||||
m_total_view=value;
|
||||
//--- parameter has been changed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the control visible |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::Show(void)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
CWndClient::Show();
|
||||
//--- number of items
|
||||
int total=m_strings.Total();
|
||||
//---
|
||||
if(total==0)
|
||||
total=1;
|
||||
//---
|
||||
if(m_height_variable && total<m_total_view)
|
||||
for(int i=total;i<m_total_view;i++)
|
||||
m_rows[i].Hide();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create "row" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::CreateRow(const int index)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_BORDER_WIDTH;
|
||||
int y1=CONTROLS_BORDER_WIDTH+m_item_height*index;
|
||||
int x2=Width()-2*CONTROLS_BORDER_WIDTH;
|
||||
int y2=y1+m_item_height;
|
||||
//--- create
|
||||
if(!m_rows[index].Create(m_chart_id,m_name+"Item"+IntegerToString(index),m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_rows[index].Text(""))
|
||||
return(false);
|
||||
if(!m_rows[index].ReadOnly(true))
|
||||
return(false);
|
||||
if(!RowState(index,false))
|
||||
return(false);
|
||||
if(!Add(m_rows[index]))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add item (row) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::AddItem(const string item,const long value)
|
||||
{
|
||||
//--- method left for compatibility with previous version
|
||||
return(ItemAdd(item,value));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add item (row) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::ItemAdd(const string item,const long value)
|
||||
{
|
||||
//--- add
|
||||
if(!m_strings.Add(item))
|
||||
return(false);
|
||||
if(!m_values.Add((value)?value:m_values.Total()))
|
||||
return(false);
|
||||
//--- number of items
|
||||
int total=m_strings.Total();
|
||||
//--- exit if number of items does not exceed the size of visible area
|
||||
if(total<m_total_view+1)
|
||||
{
|
||||
if(m_height_variable && total!=1)
|
||||
{
|
||||
Height(total*m_item_height+2*CONTROLS_BORDER_WIDTH);
|
||||
if(IS_VISIBLE)
|
||||
m_rows[total-1].Show();
|
||||
}
|
||||
return(Redraw());
|
||||
}
|
||||
//--- if number of items exceeded the size of visible area
|
||||
if(total==m_total_view+1)
|
||||
{
|
||||
//--- enable vertical scrollbar
|
||||
if(!VScrolled(true))
|
||||
return(false);
|
||||
//--- and immediately make it invisible (if needed)
|
||||
if(IS_VISIBLE && !OnVScrollShow())
|
||||
return(false);
|
||||
}
|
||||
//--- set up the scrollbar
|
||||
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Insert item (row) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::ItemInsert(const int index,const string item,const long value)
|
||||
{
|
||||
//--- insert
|
||||
if(!m_strings.Insert(item,index))
|
||||
return(false);
|
||||
if(!m_values.Insert(value,index))
|
||||
return(false);
|
||||
//--- number of items
|
||||
int total=m_strings.Total();
|
||||
//--- exit if number of items does not exceed the size of visible area
|
||||
if(total<m_total_view+1)
|
||||
{
|
||||
if(m_height_variable && total!=1)
|
||||
{
|
||||
Height(total*m_item_height+2*CONTROLS_BORDER_WIDTH);
|
||||
if(IS_VISIBLE)
|
||||
m_rows[total-1].Show();
|
||||
}
|
||||
return(Redraw());
|
||||
}
|
||||
//--- if number of items exceeded the size of visible area
|
||||
if(total==m_total_view+1)
|
||||
{
|
||||
//--- enable vertical scrollbar
|
||||
if(!VScrolled(true))
|
||||
return(false);
|
||||
//--- and immediately make it invisible (if needed)
|
||||
if(IS_VISIBLE && !OnVScrollShow())
|
||||
return(false);
|
||||
}
|
||||
//--- set up the scrollbar
|
||||
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update item (row) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::ItemUpdate(const int index,const string item,const long value)
|
||||
{
|
||||
//--- update
|
||||
if(!m_strings.Update(index,item))
|
||||
return(false);
|
||||
if(!m_values.Update(index,value))
|
||||
return(false);
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete item (row) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::ItemDelete(const int index)
|
||||
{
|
||||
//--- delete
|
||||
if(!m_strings.Delete(index))
|
||||
return(false);
|
||||
if(!m_values.Delete(index))
|
||||
return(false);
|
||||
//--- number of items
|
||||
int total=m_strings.Total();
|
||||
//--- exit if number of items does not exceed the size of visible area
|
||||
if(total<m_total_view)
|
||||
{
|
||||
if(m_height_variable && total!=0)
|
||||
{
|
||||
Height(total*m_item_height+2*CONTROLS_BORDER_WIDTH);
|
||||
m_rows[total].Hide();
|
||||
}
|
||||
return(Redraw());
|
||||
}
|
||||
//--- if number of items exceeded the size of visible area
|
||||
if(total==m_total_view)
|
||||
{
|
||||
//--- disable vertical scrollbar
|
||||
if(!VScrolled(false))
|
||||
return(false);
|
||||
//--- and immediately make it unvisible
|
||||
if(!OnVScrollHide())
|
||||
return(false);
|
||||
}
|
||||
//--- set up the scrollbar
|
||||
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete all items |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::ItemsClear(void)
|
||||
{
|
||||
m_offset=0;
|
||||
//--- clear
|
||||
if(!m_strings.Shutdown())
|
||||
return(false);
|
||||
if(!m_values.Shutdown())
|
||||
return(false);
|
||||
//---
|
||||
if(m_height_variable)
|
||||
{
|
||||
Height(m_item_height+2*CONTROLS_BORDER_WIDTH);
|
||||
for(int i=1;i<m_total_view;i++)
|
||||
m_rows[i].Hide();
|
||||
}
|
||||
//--- disable vertical scrollbar
|
||||
if(!VScrolled(false))
|
||||
return(false);
|
||||
//--- and immediately make it unvisible (if needed)
|
||||
if(!OnVScrollHide())
|
||||
return(false);
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sett current item |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::Select(const int index)
|
||||
{
|
||||
//--- check index
|
||||
if(index>=m_strings.Total())
|
||||
return(false);
|
||||
if(index<0 && index!=CONTROLS_INVALID_INDEX)
|
||||
return(false);
|
||||
//--- unselect
|
||||
if(m_current!=CONTROLS_INVALID_INDEX)
|
||||
RowState(m_current-m_offset,false);
|
||||
//--- select
|
||||
if(index!=CONTROLS_INVALID_INDEX)
|
||||
RowState(index-m_offset,true);
|
||||
//--- save value
|
||||
m_current=index;
|
||||
//--- succeed
|
||||
return(CheckView());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set current item (by text) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::SelectByText(const string text)
|
||||
{
|
||||
//--- find text
|
||||
int index=m_strings.SearchLinear(text);
|
||||
//--- if text is not found, exit without changing the selection
|
||||
if(index==CONTROLS_INVALID_INDEX)
|
||||
return(false);
|
||||
//--- change selection
|
||||
return(Select(index));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set current item (by value) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::SelectByValue(const long value)
|
||||
{
|
||||
//--- find value
|
||||
int index=m_values.SearchLinear(value);
|
||||
//--- if value is not found, exit without changing the selection
|
||||
if(index==CONTROLS_INVALID_INDEX)
|
||||
return(false);
|
||||
//--- change selection
|
||||
return(Select(index));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Redraw |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::Redraw(void)
|
||||
{
|
||||
//--- loop by "rows"
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
{
|
||||
//--- copy text
|
||||
if(!m_rows[i].Text(m_strings.At(i+m_offset)))
|
||||
return(false);
|
||||
//--- select
|
||||
if(!RowState(i,(m_current==i+m_offset)))
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Change state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::RowState(const int index,const bool select)
|
||||
{
|
||||
//--- check index
|
||||
if(index<0 || index>=ArraySize(m_rows))
|
||||
return(true);
|
||||
//--- determine colors
|
||||
color text_color=(select) ? CONTROLS_LISTITEM_COLOR_TEXT_SEL : CONTROLS_LISTITEM_COLOR_TEXT;
|
||||
color back_color=(select) ? CONTROLS_LISTITEM_COLOR_BG_SEL : CONTROLS_LISTITEM_COLOR_BG;
|
||||
//--- get pointer
|
||||
CEdit *item=GetPointer(m_rows[index]);
|
||||
//--- recolor the "row"
|
||||
return(item.Color(text_color) && item.ColorBackground(back_color) && item.ColorBorder(back_color));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check visibility of selected row |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::CheckView(void)
|
||||
{
|
||||
//--- check visibility
|
||||
if(m_current>=m_offset && m_current<m_offset+m_total_view)
|
||||
return(true);
|
||||
//--- selected row is not visible
|
||||
int total=m_strings.Total();
|
||||
m_offset=(total-m_current>m_total_view) ? m_current : total-m_total_view;
|
||||
//--- adjust the scrollbar
|
||||
m_scroll_v.CurrPos(m_offset);
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of resizing |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::OnResize(void)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
if(!CWndClient::OnResize())
|
||||
return(false);
|
||||
//--- set up the size of "row"
|
||||
if(VScrolled())
|
||||
OnVScrollShow();
|
||||
else
|
||||
OnVScrollHide();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Show vertical scrollbar" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::OnVScrollShow(void)
|
||||
{
|
||||
//--- loop by "rows"
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
{
|
||||
//--- resize "rows" according to shown vertical scrollbar
|
||||
m_rows[i].Width(Width()-(CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH));
|
||||
}
|
||||
//--- check visibility
|
||||
if(!IS_VISIBLE)
|
||||
{
|
||||
m_scroll_v.Visible(false);
|
||||
return(true);
|
||||
}
|
||||
//--- event is handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Hide vertical scrollbar" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::OnVScrollHide(void)
|
||||
{
|
||||
//--- check visibility
|
||||
if(!IS_VISIBLE)
|
||||
return(true);
|
||||
//--- loop by "rows"
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
{
|
||||
//--- resize "rows" according to hidden vertical scroll bar
|
||||
m_rows[i].Width(Width()-2*CONTROLS_BORDER_WIDTH);
|
||||
}
|
||||
//--- event is handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Scroll up for one row" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::OnScrollLineUp(void)
|
||||
{
|
||||
//--- get new offset
|
||||
m_offset=m_scroll_v.CurrPos();
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Scroll down for one row" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::OnScrollLineDown(void)
|
||||
{
|
||||
//--- get new offset
|
||||
m_offset=m_scroll_v.CurrPos();
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on row |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CListView::OnItemClick(const int index)
|
||||
{
|
||||
//--- select "row"
|
||||
Select(index+m_offset);
|
||||
//--- send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,124 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Panel.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndObj.mqh"
|
||||
#include <ChartObjects\ChartObjectsTxtControls.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CPanel |
|
||||
//| Usage: control that is displayed by |
|
||||
//| the CChartObjectRectLabel object |
|
||||
//+------------------------------------------------------------------+
|
||||
class CPanel : public CWndObj
|
||||
{
|
||||
private:
|
||||
CChartObjectRectLabel m_rectangle; // chart object
|
||||
//--- parameters of the chart object
|
||||
ENUM_BORDER_TYPE m_border; // border type
|
||||
|
||||
public:
|
||||
CPanel(void);
|
||||
~CPanel(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- parameters of the chart object
|
||||
ENUM_BORDER_TYPE BorderType(void) const { return(m_border); }
|
||||
bool BorderType(const ENUM_BORDER_TYPE type);
|
||||
|
||||
protected:
|
||||
//--- handlers of object settings
|
||||
virtual bool OnSetText(void) { return(m_rectangle.Description(m_text)); }
|
||||
virtual bool OnSetColorBackground(void) { return(m_rectangle.BackColor(m_color_background)); }
|
||||
virtual bool OnSetColorBorder(void) { return(m_rectangle.Color(m_color_border)); }
|
||||
//--- internal event handlers
|
||||
virtual bool OnCreate(void);
|
||||
virtual bool OnShow(void);
|
||||
virtual bool OnHide(void);
|
||||
virtual bool OnMove(void);
|
||||
virtual bool OnResize(void);
|
||||
virtual bool OnChange(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CPanel::CPanel(void) : m_border(BORDER_FLAT)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CPanel::~CPanel(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPanel::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call method of the parent class
|
||||
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create the chart object
|
||||
if(!m_rectangle.Create(chart,name,subwin,x1,y1,Width(),Height()))
|
||||
return(false);
|
||||
//--- call the settings handler
|
||||
return(OnChange());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set border type |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPanel::BorderType(const ENUM_BORDER_TYPE type)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_border=type;
|
||||
//--- set up the chart object
|
||||
return(m_rectangle.BorderType(type));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPanel::OnCreate(void)
|
||||
{
|
||||
//--- create the chart object by previously set parameters
|
||||
return(m_rectangle.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Display object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPanel::OnShow(void)
|
||||
{
|
||||
return(m_rectangle.Timeframes(OBJ_ALL_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Hide object from chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPanel::OnHide(void)
|
||||
{
|
||||
return(m_rectangle.Timeframes(OBJ_NO_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPanel::OnMove(void)
|
||||
{
|
||||
//--- position the chart object
|
||||
return(m_rectangle.X_Distance(m_rect.left) && m_rectangle.Y_Distance(m_rect.top));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resize the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPanel::OnResize(void)
|
||||
{
|
||||
//--- resize the chart object
|
||||
return(m_rectangle.X_Size(m_rect.Width()) && m_rectangle.Y_Size(m_rect.Height()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set up the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPanel::OnChange(void)
|
||||
{
|
||||
//--- set up the chart object
|
||||
return(CWndObj::OnChange() && m_rectangle.BorderType(m_border));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,125 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Picture.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndObj.mqh"
|
||||
#include <ChartObjects\ChartObjectsBmpControls.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CPicture |
|
||||
//| Note: image displayed by |
|
||||
//| the CChartObjectBmpLabel object |
|
||||
//+------------------------------------------------------------------+
|
||||
class CPicture : public CWndObj
|
||||
{
|
||||
private:
|
||||
CChartObjectBmpLabel m_picture; // chart object
|
||||
//--- parameters of the chart object
|
||||
int m_border; // border width
|
||||
string m_bmp_name; // filename
|
||||
|
||||
public:
|
||||
CPicture(void);
|
||||
~CPicture(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- parameters of the chart object
|
||||
int Border(void) const { return(m_border); }
|
||||
bool Border(const int value);
|
||||
string BmpName(void) const { return(m_bmp_name); }
|
||||
bool BmpName(const string name);
|
||||
|
||||
protected:
|
||||
//--- internal event handlers
|
||||
virtual bool OnCreate(void);
|
||||
virtual bool OnShow(void);
|
||||
virtual bool OnHide(void);
|
||||
virtual bool OnMove(void);
|
||||
virtual bool OnChange(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CPicture::CPicture(void) : m_border(0),
|
||||
m_bmp_name(NULL)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CPicture::~CPicture(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPicture::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call method of the parent class
|
||||
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create the chart object
|
||||
if(!m_picture.Create(chart,name,subwin,x1,y1))
|
||||
return(false);
|
||||
//--- call the settings handler
|
||||
return(OnChange());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set border width |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPicture::Border(const int value)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_border=value;
|
||||
//--- set up the chart object
|
||||
return(m_picture.Width(value));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set image |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPicture::BmpName(const string name)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_bmp_name=name;
|
||||
//--- set up the chart object
|
||||
return(m_picture.BmpFileOn(name));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPicture::OnCreate(void)
|
||||
{
|
||||
//--- create the chart object by previously set parameters
|
||||
return(m_picture.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Display object on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPicture::OnShow(void)
|
||||
{
|
||||
return(m_picture.Timeframes(OBJ_ALL_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Hide object from chart |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPicture::OnHide(void)
|
||||
{
|
||||
return(m_picture.Timeframes(OBJ_NO_PERIODS));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPicture::OnMove(void)
|
||||
{
|
||||
//--- position the chart object
|
||||
return(m_picture.X_Distance(m_rect.left) && m_picture.Y_Distance(m_rect.top));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set up the chart object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPicture::OnChange(void)
|
||||
{
|
||||
//--- set up the chart object
|
||||
return(m_picture.Width(m_border) && m_picture.BmpFileOn(m_bmp_name));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,160 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RadioButton.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndContainer.mqh"
|
||||
#include "BmpButton.mqh"
|
||||
#include "Edit.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resources |
|
||||
//+------------------------------------------------------------------+
|
||||
#resource "res\\RadioButtonOn.bmp"
|
||||
#resource "res\\RadioButtonOff.bmp"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CRadioButton |
|
||||
//| Usage: class that implements the "RadioButton" control |
|
||||
//+------------------------------------------------------------------+
|
||||
class CRadioButton : public CWndContainer
|
||||
{
|
||||
private:
|
||||
//--- dependent controls
|
||||
CBmpButton m_button; // button object
|
||||
CEdit m_label; // label object
|
||||
|
||||
public:
|
||||
CRadioButton(void);
|
||||
~CRadioButton(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- settings
|
||||
string Text(void) const { return(m_label.Text()); }
|
||||
bool Text(const string value) { return(m_label.Text(value)); }
|
||||
color Color(void) const { return(m_label.Color()); }
|
||||
bool Color(const color value) { return(m_label.Color(value)); }
|
||||
//--- state
|
||||
bool State(void) const { return(m_button.Pressed()); }
|
||||
bool State(const bool flag) { return(m_button.Pressed(flag)); }
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
virtual bool CreateButton(void);
|
||||
virtual bool CreateLabel(void);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual bool OnClickButton(void);
|
||||
virtual bool OnClickLabel(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CRadioButton)
|
||||
ON_EVENT(ON_CLICK,m_button,OnClickButton)
|
||||
ON_EVENT(ON_CLICK,m_label,OnClickLabel)
|
||||
EVENT_MAP_END(CWndContainer)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CRadioButton::CRadioButton(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CRadioButton::~CRadioButton(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call method of the parent class
|
||||
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
if(!CreateButton())
|
||||
return(false);
|
||||
if(!CreateLabel())
|
||||
return(false);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioButton::CreateButton(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_RADIO_BUTTON_X_OFF;
|
||||
int y1=CONTROLS_RADIO_BUTTON_Y_OFF;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE-CONTROLS_BORDER_WIDTH;
|
||||
//--- create
|
||||
if(!m_button.Create(m_chart_id,m_name+"Button",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_button.BmpNames("::res\\RadioButtonOff.bmp","::res\\RadioButtonOn.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_button))
|
||||
return(false);
|
||||
m_button.Locking(true);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create label |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioButton::CreateLabel(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_RADIO_LABEL_X_OFF;
|
||||
int y1=CONTROLS_RADIO_LABEL_Y_OFF;
|
||||
int x2=Width();
|
||||
int y2=Height();
|
||||
//--- create
|
||||
if(!m_label.Create(m_chart_id,m_name+"Label",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_label.Text(m_name))
|
||||
return(false);
|
||||
if(!Add(m_label))
|
||||
return(false);
|
||||
m_label.ReadOnly(true);
|
||||
m_label.ColorBackground(CONTROLS_CHECKGROUP_COLOR_BG);
|
||||
m_label.ColorBorder(CONTROLS_CHECKGROUP_COLOR_BG);
|
||||
//--- succeeded
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioButton::OnClickButton(void)
|
||||
{
|
||||
//--- if button is in the "turned off" state, turn it on again and complete the handling
|
||||
//--- this is due to that radio button can not be turned off by clicking on it (it can be only turned on)
|
||||
if(!m_button.Pressed())
|
||||
{
|
||||
//--- turn on the radio button
|
||||
if(!m_button.Pressed(true))
|
||||
return(false);
|
||||
}
|
||||
//--- send the "changed state" event
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on label |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioButton::OnClickLabel(void)
|
||||
{
|
||||
//--- if button is in the "turned on" state, simply complete the handling
|
||||
//--- this is due to that radio button can not be turned off by clicking on it (it can be only turned on)
|
||||
if(m_button.Pressed())
|
||||
return(true);
|
||||
//--- turn on the radio button
|
||||
m_button.Pressed(true);
|
||||
//--- return the result of the button click handler
|
||||
return(OnClickButton());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,361 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| RadioGroup.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndClient.mqh"
|
||||
#include "RadioButton.mqh"
|
||||
#include <Arrays\ArrayString.mqh>
|
||||
#include <Arrays\ArrayLong.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CRadioGroup |
|
||||
//| Usage: view and edit radio buttons |
|
||||
//+------------------------------------------------------------------+
|
||||
class CRadioGroup : public CWndClient
|
||||
{
|
||||
private:
|
||||
//--- dependent controls
|
||||
CRadioButton m_rows[]; // array of the row objects
|
||||
//--- set up
|
||||
int m_offset; // index of first visible row in array of rows
|
||||
int m_total_view; // number of visible rows
|
||||
int m_item_height; // height of visible row
|
||||
//--- data
|
||||
CArrayString m_strings; // array of rows
|
||||
CArrayLong m_values; // array of values
|
||||
int m_current; // index of current row in array of rows
|
||||
|
||||
public:
|
||||
CRadioGroup(void);
|
||||
~CRadioGroup(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
virtual void Destroy(const int reason=0);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- fill
|
||||
virtual bool AddItem(const string item,const long value=0);
|
||||
//--- data
|
||||
long Value(void) const { return(m_values.At(m_current)); }
|
||||
bool Value(const long value);
|
||||
bool ValueCheck(long value) const;
|
||||
//--- state
|
||||
virtual bool Show(void);
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
bool CreateButton(const int index);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual bool OnVScrollShow(void);
|
||||
virtual bool OnVScrollHide(void);
|
||||
virtual bool OnScrollLineDown(void);
|
||||
virtual bool OnScrollLineUp(void);
|
||||
virtual bool OnChangeItem(const int row_index);
|
||||
//--- redraw
|
||||
bool Redraw(void);
|
||||
bool RowState(const int index,const bool select);
|
||||
void Select(const int index);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CRadioGroup)
|
||||
ON_INDEXED_EVENT(ON_CHANGE,m_rows,OnChangeItem)
|
||||
EVENT_MAP_END(CWndClient)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CRadioGroup::CRadioGroup(void) : m_offset(0),
|
||||
m_total_view(0),
|
||||
m_item_height(CONTROLS_LIST_ITEM_HEIGHT),
|
||||
m_current(CONTROLS_INVALID_INDEX)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CRadioGroup::~CRadioGroup(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- determine the number of visible rows
|
||||
m_total_view=(y2-y1)/m_item_height;
|
||||
//--- check the number of visible rows
|
||||
if(m_total_view<1)
|
||||
return(false);
|
||||
//--- call method of the parent class
|
||||
if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- set up
|
||||
if(!m_background.ColorBackground(CONTROLS_RADIOGROUP_COLOR_BG))
|
||||
return(false);
|
||||
if(!m_background.ColorBorder(CONTROLS_RADIOGROUP_COLOR_BORDER))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
ArrayResize(m_rows,m_total_view);
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
if(!CreateButton(i))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete group of controls |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRadioGroup::Destroy(const int reason)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
CWndClient::Destroy(reason);
|
||||
//--- clear items
|
||||
m_strings.Clear();
|
||||
m_values.Clear();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create "row" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::CreateButton(const int index)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_BORDER_WIDTH;
|
||||
int y1=CONTROLS_BORDER_WIDTH+m_item_height*index;
|
||||
int x2=Width()-CONTROLS_BORDER_WIDTH;
|
||||
int y2=y1+m_item_height;
|
||||
//--- create
|
||||
if(!m_rows[index].Create(m_chart_id,m_name+"Item"+IntegerToString(index),m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_rows[index].Text(""))
|
||||
return(false);
|
||||
if(!Add(m_rows[index]))
|
||||
return(false);
|
||||
m_rows[index].Hide();
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add item (row) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::AddItem(const string item,const long value)
|
||||
{
|
||||
//--- check value
|
||||
if(value!=0 && !ValueCheck(value))
|
||||
return(false);
|
||||
//--- add
|
||||
if(!m_strings.Add(item))
|
||||
return(false);
|
||||
if(!m_values.Add(value))
|
||||
return(false);
|
||||
//--- number of items
|
||||
int total=m_strings.Total();
|
||||
//--- exit if number of items does not exceed the size of visible area
|
||||
if(total<m_total_view+1)
|
||||
{
|
||||
if(IS_VISIBLE && total!=0)
|
||||
m_rows[total-1].Show();
|
||||
return(Redraw());
|
||||
}
|
||||
//--- if number of items exceeded the size of visible area
|
||||
if(total==m_total_view+1)
|
||||
{
|
||||
//--- enable vertical scrollbar
|
||||
if(!VScrolled(true))
|
||||
return(false);
|
||||
//--- and immediately make it invisible (if needed)
|
||||
if(!IS_VISIBLE)
|
||||
m_scroll_v.Visible(false);
|
||||
|
||||
}
|
||||
//--- set up the scrollbar
|
||||
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::Value(const long value)
|
||||
{
|
||||
//--- çíà÷åíèå äîëæíî ïðèñóòñòâîâàòü â íàáîðå
|
||||
int total=m_values.Total();
|
||||
//---
|
||||
for(int i=0;i<total;i++)
|
||||
if(m_values.At(i)==value)
|
||||
Select(i+m_offset);
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::ValueCheck(long value) const
|
||||
{
|
||||
//--- ïðîâåðÿåìîå çíà÷åíèå íå äîëæíî äóáëèðîâàòü óæå ñóùåñòâóþùåå
|
||||
int total=m_values.Total();
|
||||
//---
|
||||
for(int i=0;i<total;i++)
|
||||
if(m_values.At(i)==value)
|
||||
return(false);
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the group visible |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::Show(void)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
if(!CWndClient::Show())
|
||||
return(false);
|
||||
//--- loop by rows
|
||||
int total=m_values.Total();
|
||||
for(int i=total;i<m_total_view;i++)
|
||||
m_rows[i].Hide();
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//---
|
||||
FileWriteLong(file_handle,Value());
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//---
|
||||
if(!FileIsEnding(file_handle))
|
||||
Value(FileReadLong(file_handle));
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sett current item |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRadioGroup::Select(const int index)
|
||||
{
|
||||
//--- disable the "ON" state
|
||||
if(m_current!=-1)
|
||||
RowState(m_current-m_offset,false);
|
||||
//--- enable the "ON" state
|
||||
if(index!=-1)
|
||||
RowState(index-m_offset,true);
|
||||
//--- save value
|
||||
m_current=index;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Redraw |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::Redraw(void)
|
||||
{
|
||||
//--- loop by "rows"
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
{
|
||||
//--- copy text
|
||||
if(!m_rows[i].Text(m_strings.At(i+m_offset)))
|
||||
return(false);
|
||||
//--- select
|
||||
if(!RowState(i,(m_current==i+m_offset)))
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Change state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::RowState(const int index,const bool select)
|
||||
{
|
||||
//--- check index
|
||||
if(index<0 || index>=ArraySize(m_rows))
|
||||
return(true);
|
||||
//--- change state
|
||||
return(m_rows[index].State(select));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Show vertical scrollbar" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::OnVScrollShow(void)
|
||||
{
|
||||
//--- loop by "rows"
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
{
|
||||
//--- resize "rows" according to shown vertical scrollbar
|
||||
m_rows[i].Width(Width()-(CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH));
|
||||
}
|
||||
//--- check visibility
|
||||
if(!IS_VISIBLE)
|
||||
{
|
||||
m_scroll_v.Visible(false);
|
||||
return(true);
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Hide vertical scrollbar" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::OnVScrollHide(void)
|
||||
{
|
||||
//--- check visibility
|
||||
if(!IS_VISIBLE)
|
||||
return(true);
|
||||
//--- loop by "rows"
|
||||
for(int i=0;i<m_total_view;i++)
|
||||
{
|
||||
//--- resize "rows" according to hidden vertical scroll bar
|
||||
m_rows[i].Width(Width()-CONTROLS_BORDER_WIDTH);
|
||||
}
|
||||
//---
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Scroll up for one row" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::OnScrollLineUp(void)
|
||||
{
|
||||
//--- get new offset
|
||||
m_offset=m_scroll_v.CurrPos();
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Scroll down for one row" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::OnScrollLineDown(void)
|
||||
{
|
||||
//--- get new offset
|
||||
m_offset=m_scroll_v.CurrPos();
|
||||
//--- redraw
|
||||
return(Redraw());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of changing a "row" state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRadioGroup::OnChangeItem(const int row_index)
|
||||
{
|
||||
//--- select "row"
|
||||
Select(row_index+m_offset);
|
||||
//--- send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,279 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Rect.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Structure CPoint |
|
||||
//| Usage: point of chart in Cartesian coordinates |
|
||||
//+------------------------------------------------------------------+
|
||||
struct CPoint
|
||||
{
|
||||
int x; // horizontal coordinate
|
||||
int y; // vertical coordinate
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Structure CSize |
|
||||
//| Usage: size of area of chart in Cartesian coordinates |
|
||||
//+------------------------------------------------------------------+
|
||||
struct CSize
|
||||
{
|
||||
int cx; // horizontal size
|
||||
int cy; // vertical size
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Structure CRect |
|
||||
//| Usage: area of chart in Cartesian coordinates |
|
||||
//+------------------------------------------------------------------+
|
||||
struct CRect
|
||||
{
|
||||
int left; // left coordinate
|
||||
int top; // top coordinate
|
||||
int right; // right coordinate
|
||||
int bottom; // bottom coordinate
|
||||
|
||||
//--- methods
|
||||
CPoint LeftTop(void) const;
|
||||
void LeftTop(const int x,const int y);
|
||||
void LeftTop(const CPoint& point);
|
||||
CPoint RightBottom(void) const;
|
||||
void RightBottom(const int x,const int y);
|
||||
void RightBottom(const CPoint& point);
|
||||
CPoint CenterPoint(void) const;
|
||||
int Width(void) const { return(right-left); }
|
||||
void Width(const int w) { right=left+w; }
|
||||
int Height(void) const { return(bottom-top); }
|
||||
void Height(const int h) { bottom=top+h; }
|
||||
CSize Size(void) const;
|
||||
void Size(const int cx,const int cy);
|
||||
void Size(const CSize& size);
|
||||
void SetBound(const int l,const int t,const int r,const int b);
|
||||
void SetBound(const CRect& rect);
|
||||
void SetBound(const CPoint& point,const CSize& size);
|
||||
void SetBound(const CPoint& left_top,const CPoint& right_bottom);
|
||||
void Move(const int x,const int y);
|
||||
void Move(const CPoint& point);
|
||||
void Shift(const int dx,const int dy);
|
||||
void Shift(const CPoint& point);
|
||||
void Shift(const CSize& size);
|
||||
bool Contains(const int x,const int y) const;
|
||||
bool Contains(const CPoint& point) const;
|
||||
void Normalize(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
CPoint CRect::LeftTop(void) const
|
||||
{
|
||||
CPoint point;
|
||||
//--- action
|
||||
point.x=left;
|
||||
point.y=top;
|
||||
//--- result
|
||||
return(point);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::LeftTop(const int x,const int y)
|
||||
{
|
||||
left=x;
|
||||
top =y;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::LeftTop(const CPoint& point)
|
||||
{
|
||||
left=point.x;
|
||||
top =point.y;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
CPoint CRect::RightBottom(void) const
|
||||
{
|
||||
CPoint point;
|
||||
//--- action
|
||||
point.x=right;
|
||||
point.y=bottom;
|
||||
//--- result
|
||||
return(point);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::RightBottom(const int x,const int y)
|
||||
{
|
||||
right =x;
|
||||
bottom=y;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::RightBottom(const CPoint& point)
|
||||
{
|
||||
right =point.x;
|
||||
bottom=point.y;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
CPoint CRect::CenterPoint(void) const
|
||||
{
|
||||
CPoint point;
|
||||
//--- action
|
||||
point.x=left+Width()/2;
|
||||
point.y=top+Height()/2;
|
||||
//--- result
|
||||
return(point);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
CSize CRect::Size(void) const
|
||||
{
|
||||
CSize size;
|
||||
//--- action
|
||||
size.cx=right-left;
|
||||
size.cy=bottom-top;
|
||||
//--- result
|
||||
return(size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::Size(const int cx,const int cy)
|
||||
{
|
||||
right =left+cx;
|
||||
bottom=top+cy;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::Size(const CSize& size)
|
||||
{
|
||||
right =left+size.cx;
|
||||
bottom=top+size.cy;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::SetBound(const int l,const int t,const int r,const int b)
|
||||
{
|
||||
left =l;
|
||||
top =t;
|
||||
right =r;
|
||||
bottom=b;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::SetBound(const CRect& rect)
|
||||
{
|
||||
left =rect.left;
|
||||
top =rect.top;
|
||||
right =rect.right;
|
||||
bottom=rect.bottom;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::SetBound(const CPoint& point,const CSize& size)
|
||||
{
|
||||
LeftTop(point);
|
||||
Size(size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameters of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::SetBound(const CPoint& left_top,const CPoint& right_bottom)
|
||||
{
|
||||
LeftTop(left_top);
|
||||
RightBottom(right_bottom);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::Move(const int x,const int y)
|
||||
{
|
||||
right +=x-left;
|
||||
bottom+=y-top;
|
||||
left =x;
|
||||
top =y;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::Move(const CPoint& point)
|
||||
{
|
||||
right +=point.x-left;
|
||||
bottom+=point.y-top;
|
||||
left =point.x;
|
||||
top =point.y;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Relative movement of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::Shift(const int dx,const int dy)
|
||||
{
|
||||
left +=dx;
|
||||
top +=dy;
|
||||
right +=dx;
|
||||
bottom+=dy;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Relative movement of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::Shift(const CPoint& point)
|
||||
{
|
||||
left +=point.x;
|
||||
top +=point.y;
|
||||
right +=point.x;
|
||||
bottom+=point.y;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Relative movement of area |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::Shift(const CSize& size)
|
||||
{
|
||||
left +=size.cx;
|
||||
top +=size.cy;
|
||||
right +=size.cx;
|
||||
bottom+=size.cy;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if a point is within the area |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRect::Contains(const int x,const int y) const
|
||||
{
|
||||
//--- check and return the result
|
||||
return(x>=left && x<=right && y>=top && y<=bottom);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if a point is within the area |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CRect::Contains(const CPoint& point) const
|
||||
{
|
||||
//--- check and return the result
|
||||
return(point.x>=left && point.x<=right && point.y>=top && point.y<=bottom);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Standardizes the height and width |
|
||||
//+------------------------------------------------------------------+
|
||||
void CRect::Normalize(void)
|
||||
{
|
||||
if(left>right)
|
||||
{
|
||||
int tmp1=left;
|
||||
left=right;
|
||||
right=tmp1;
|
||||
}
|
||||
if(top>bottom)
|
||||
{
|
||||
int tmp2=top;
|
||||
top=bottom;
|
||||
bottom=tmp2;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,675 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Scrolls.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndContainer.mqh"
|
||||
#include "Panel.mqh"
|
||||
#include "BmpButton.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resources |
|
||||
//+------------------------------------------------------------------+
|
||||
#resource "res\\Up.bmp"
|
||||
#resource "res\\ThumbVert.bmp"
|
||||
#resource "res\\Down.bmp"
|
||||
#resource "res\\Left.bmp"
|
||||
#resource "res\\ThumbHor.bmp"
|
||||
#resource "res\\Right.bmp"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CScroll |
|
||||
//| Usage: base class for scrollbars |
|
||||
//+------------------------------------------------------------------+
|
||||
class CScroll : public CWndContainer
|
||||
{
|
||||
protected:
|
||||
//--- dependent controls
|
||||
CPanel m_back; // the "scrollbar background" object
|
||||
CBmpButton m_inc; // the "increment button" object ("down" for vertical scrollbar, "right" for horizontal scrollbar)
|
||||
CBmpButton m_dec; // the "decrement button" object ("up" for vertical scrollbar, "left" for horizontal scrollbar)
|
||||
CBmpButton m_thumb; // the "scroll box" object
|
||||
//--- set up
|
||||
int m_min_pos; // minimum value
|
||||
int m_max_pos; // maximum value
|
||||
//--- state
|
||||
int m_curr_pos; // current value
|
||||
|
||||
public:
|
||||
CScroll(void);
|
||||
~CScroll(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- set up
|
||||
int MinPos(void) const { return(m_min_pos); }
|
||||
void MinPos(const int value);
|
||||
int MaxPos(void) const { return(m_max_pos); }
|
||||
void MaxPos(const int value);
|
||||
//--- state
|
||||
int CurrPos(void) const { return(m_curr_pos); }
|
||||
bool CurrPos(int value);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
virtual bool CreateBack(void);
|
||||
virtual bool CreateInc(void) { return(true); }
|
||||
virtual bool CreateDec(void) { return(true); }
|
||||
virtual bool CreateThumb(void) { return(true); }
|
||||
//--- handlers of the dependent controls events
|
||||
virtual bool OnClickInc(void);
|
||||
virtual bool OnClickDec(void);
|
||||
//--- internal event handlers
|
||||
virtual bool OnShow(void);
|
||||
virtual bool OnHide(void);
|
||||
virtual bool OnChangePos(void) { return(true); }
|
||||
//--- handlers of dragging
|
||||
virtual bool OnThumbDragStart(void) { return(true); }
|
||||
virtual bool OnThumbDragProcess(void) { return(true); }
|
||||
virtual bool OnThumbDragEnd(void) { return(true); }
|
||||
//--- calculate position by coordinate
|
||||
virtual int CalcPos(const int coord) { return(0); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CScroll)
|
||||
ON_EVENT(ON_CLICK,m_inc,OnClickInc)
|
||||
ON_EVENT(ON_CLICK,m_dec,OnClickDec)
|
||||
ON_EVENT(ON_DRAG_START,m_thumb,OnThumbDragStart)
|
||||
ON_EVENT_PTR(ON_DRAG_PROCESS,m_drag_object,OnThumbDragProcess)
|
||||
ON_EVENT_PTR(ON_DRAG_END,m_drag_object,OnThumbDragEnd)
|
||||
EVENT_MAP_END(CWndContainer)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CScroll::CScroll(void) : m_curr_pos(0),
|
||||
m_min_pos(0),
|
||||
m_max_pos(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CScroll::~CScroll(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScroll::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call method of the parent class
|
||||
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
if(!CreateBack())
|
||||
return(false);
|
||||
if(!CreateInc())
|
||||
return(false);
|
||||
if(!CreateDec())
|
||||
return(false);
|
||||
if(!CreateThumb())
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create scrollbar background |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScroll::CreateBack(void)
|
||||
{
|
||||
//--- create
|
||||
if(!m_back.Create(m_chart_id,m_name+"Back",m_subwin,0,0,Width(),Height()))
|
||||
return(false);
|
||||
if(!m_back.ColorBackground(CONTROLS_SCROLL_COLOR_BG))
|
||||
return(false);
|
||||
if(!m_back.ColorBorder(CONTROLS_SCROLL_COLOR_BORDER))
|
||||
return(false);
|
||||
if(!Add(m_back))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set current value |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScroll::CurrPos(int value)
|
||||
{
|
||||
//--- check value
|
||||
if(value<m_min_pos)
|
||||
value=m_min_pos;
|
||||
if(value>m_max_pos)
|
||||
value=m_max_pos;
|
||||
//--- if value was changed
|
||||
if(m_curr_pos!=value)
|
||||
{
|
||||
m_curr_pos=value;
|
||||
//--- call virtual handler
|
||||
return(OnChangePos());
|
||||
}
|
||||
//--- value has not been changed
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set minimum value |
|
||||
//+------------------------------------------------------------------+
|
||||
void CScroll::MinPos(const int value)
|
||||
{
|
||||
//--- if value was changed
|
||||
if(m_min_pos!=value)
|
||||
{
|
||||
m_min_pos=value;
|
||||
//--- adjust the scroll box position
|
||||
CurrPos(m_curr_pos);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set maximum value |
|
||||
//+------------------------------------------------------------------+
|
||||
void CScroll::MaxPos(const int value)
|
||||
{
|
||||
//--- if value was changed
|
||||
if(m_max_pos!=value)
|
||||
{
|
||||
m_max_pos=value;
|
||||
//--- adjust the scroll box position
|
||||
CurrPos(m_curr_pos);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Show scrollbar" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScroll::OnShow(void)
|
||||
{
|
||||
if(m_id==CONTROLS_INVALID_ID)
|
||||
return(true);
|
||||
//--- send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_SHOW,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Hide scrollbar" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScroll::OnHide(void)
|
||||
{
|
||||
if(m_id==CONTROLS_INVALID_ID)
|
||||
return(true);
|
||||
//--- send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_HIDE,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the "increment" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScroll::OnClickInc(void)
|
||||
{
|
||||
//--- try to increment current value
|
||||
if(!CurrPos(m_curr_pos+1))
|
||||
return(true);
|
||||
//--- if value was changed, send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_SCROLL_INC,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the "decrement" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScroll::OnClickDec(void)
|
||||
{
|
||||
//--- try to decrement current value
|
||||
if(!CurrPos(m_curr_pos-1))
|
||||
return(true);
|
||||
//--- if value was changed, send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_SCROLL_DEC,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CScrollV |
|
||||
//| Usage: class of vertical scrollbar |
|
||||
//+------------------------------------------------------------------+
|
||||
class CScrollV : public CScroll
|
||||
{
|
||||
public:
|
||||
CScrollV(void);
|
||||
~CScrollV(void);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
virtual bool CreateInc(void);
|
||||
virtual bool CreateDec(void);
|
||||
virtual bool CreateThumb(void);
|
||||
//--- internal event handlers
|
||||
virtual bool OnResize(void);
|
||||
virtual bool OnChangePos(void);
|
||||
//--- handlers of dragging
|
||||
virtual bool OnThumbDragStart(void);
|
||||
virtual bool OnThumbDragProcess(void);
|
||||
virtual bool OnThumbDragEnd(void);
|
||||
//--- calculate position by coordinate
|
||||
virtual int CalcPos(const int coord);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CScrollV::CScrollV(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CScrollV::~CScrollV(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create the "Increment" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollV::CreateInc(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_BORDER_WIDTH;
|
||||
int y1=Height()-CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE;
|
||||
//--- create
|
||||
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_inc.BmpNames("::res\\Down.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_inc))
|
||||
return(false);
|
||||
//--- property
|
||||
m_inc.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create the "Decrement" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollV::CreateDec(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_BORDER_WIDTH;
|
||||
int y1=CONTROLS_BORDER_WIDTH;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE;
|
||||
//--- create
|
||||
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_dec.BmpNames("::res\\Up.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_dec))
|
||||
return(false);
|
||||
//--- property
|
||||
m_dec.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create scroll box |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollV::CreateThumb(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_BORDER_WIDTH;
|
||||
int y1=CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_SCROLL_THUMB_SIZE;
|
||||
//--- create
|
||||
if(!m_thumb.Create(m_chart_id,m_name+"Thumb",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_thumb.BmpNames("::res\\ThumbVert.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_thumb))
|
||||
return(false);
|
||||
m_thumb.PropFlags(WND_PROP_FLAG_CAN_DRAG);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of changing current state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollV::OnChangePos(void)
|
||||
{
|
||||
//--- check if scrolling is possible
|
||||
if(m_max_pos-m_min_pos<=0)
|
||||
return(Visible(false));
|
||||
else
|
||||
if(!Visible(true))
|
||||
return(false);
|
||||
//--- calculate new coordinated of the scrollbar
|
||||
int steps =m_max_pos-m_min_pos; // number of steps to change position
|
||||
int min_coord=m_dec.Bottom(); // minimum possible coordinate (corresponds to the m_min_pos value)
|
||||
int max_coord=m_inc.Top()-m_thumb.Height(); // maximum possible coordinate (corresponds to the m_max_pos value)
|
||||
int new_coord=min_coord+(max_coord-min_coord)*m_curr_pos/steps; // new coordinate
|
||||
//--- adjust the scroll box position
|
||||
return(m_thumb.Move(m_thumb.Left(),new_coord));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of resizing |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollV::OnResize(void)
|
||||
{
|
||||
//--- can not change the lateral size
|
||||
if(Width()!=CONTROLS_SCROLL_SIZE)
|
||||
m_rect.Width(CONTROLS_SCROLL_SIZE);
|
||||
//--- resize the scrollbar background
|
||||
if(!m_back.Size(Size()))
|
||||
return(false);
|
||||
//--- move the "Increment" button
|
||||
if(!m_inc.Move(m_inc.Left(),Bottom()-CONTROLS_SCROLL_SIZE))
|
||||
return(false);
|
||||
//--- adjust the scroll box position
|
||||
return(OnChangePos());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Start dragging the "slider" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollV::OnThumbDragStart(void)
|
||||
{
|
||||
if(m_drag_object==NULL)
|
||||
{
|
||||
m_drag_object=new CDragWnd;
|
||||
if(m_drag_object==NULL)
|
||||
return(false);
|
||||
}
|
||||
//--- calculate coordinates
|
||||
int x1=m_thumb.Left()-CONTROLS_DRAG_SPACING;
|
||||
int y1=m_thumb.Top()-CONTROLS_DRAG_SPACING;
|
||||
int x2=m_thumb.Right()+CONTROLS_DRAG_SPACING;
|
||||
int y2=m_thumb.Bottom()+CONTROLS_DRAG_SPACING;
|
||||
//--- create
|
||||
m_drag_object.Create(m_chart_id,"",m_subwin,x1,y1,x2,y2);
|
||||
m_drag_object.PropFlags(WND_PROP_FLAG_CAN_DRAG);
|
||||
//--- îãðàíè÷åíèÿ
|
||||
m_drag_object.Limits(x1,m_dec.Bottom()-CONTROLS_DRAG_SPACING,x2,m_inc.Top()+CONTROLS_DRAG_SPACING);
|
||||
//--- set mouse params
|
||||
m_drag_object.MouseX(m_thumb.MouseX());
|
||||
m_drag_object.MouseY(m_thumb.MouseY());
|
||||
m_drag_object.MouseFlags(m_thumb.MouseFlags());
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Continue dragging the "slider" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollV::OnThumbDragProcess(void)
|
||||
{
|
||||
//--- checking
|
||||
if(m_drag_object==NULL)
|
||||
return(false);
|
||||
//--- calculate coordinates
|
||||
int x=m_drag_object.Left()+CONTROLS_DRAG_SPACING;
|
||||
int y=m_drag_object.Top()+CONTROLS_DRAG_SPACING;
|
||||
//--- calculate new position
|
||||
int new_pos=CalcPos(y);
|
||||
if(new_pos!=m_curr_pos)
|
||||
{
|
||||
ushort event_id=(m_curr_pos<new_pos) ? ON_SCROLL_INC : ON_SCROLL_DEC;
|
||||
m_curr_pos=new_pos;
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,event_id,m_id,0.0,m_name);
|
||||
}
|
||||
//--- move thumb
|
||||
m_thumb.Move(x,y);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| End dragging the "slider" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollV::OnThumbDragEnd(void)
|
||||
{
|
||||
if(m_drag_object!=NULL)
|
||||
{
|
||||
m_thumb.MouseFlags(m_drag_object.MouseFlags());
|
||||
delete m_drag_object;
|
||||
m_drag_object=NULL;
|
||||
}
|
||||
//--- succeed
|
||||
return(m_thumb.Pressed(false));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Calculate position by coordinate |
|
||||
//+------------------------------------------------------------------+
|
||||
int CScrollV::CalcPos(const int coord)
|
||||
{
|
||||
//--- calculate new position of the scrollbar
|
||||
int steps =m_max_pos-m_min_pos; // number of steps to change position
|
||||
int min_coord=m_dec.Bottom(); // minimum possible coordinate (corresponds to the m_min_pos value)
|
||||
int max_coord=m_inc.Top()-m_thumb.Height(); // maximum possible coordinate (corresponds to the m_max_pos value)
|
||||
//--- checkeng
|
||||
if(max_coord==min_coord)
|
||||
return(0);
|
||||
if(coord<min_coord || coord>max_coord)
|
||||
return(m_curr_pos);
|
||||
//---
|
||||
int new_pos=(int)MathRound((((double)(coord-min_coord))/(max_coord-min_coord))*steps); // new position
|
||||
//---
|
||||
return(new_pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CScrollH |
|
||||
//| Usage: class of horizontal scrollbar |
|
||||
//+------------------------------------------------------------------+
|
||||
class CScrollH : public CScroll
|
||||
{
|
||||
public:
|
||||
CScrollH(void);
|
||||
~CScrollH(void);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
virtual bool CreateInc(void);
|
||||
virtual bool CreateDec(void);
|
||||
virtual bool CreateThumb(void);
|
||||
//--- internal event handlers
|
||||
virtual bool OnResize(void);
|
||||
virtual bool OnChangePos(void);
|
||||
//--- handlers of dragging
|
||||
virtual bool OnThumbDragStart(void);
|
||||
virtual bool OnThumbDragProcess(void);
|
||||
virtual bool OnThumbDragEnd(void);
|
||||
//--- calculate position by coordinate
|
||||
virtual int CalcPos(const int coord);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CScrollH::CScrollH(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CScrollH::~CScrollH(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create the "Increment" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollH::CreateInc(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=Width()-CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH;
|
||||
int y1=CONTROLS_BORDER_WIDTH;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE;
|
||||
//--- create
|
||||
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_inc.BmpNames("::res\\Right.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_inc))
|
||||
return(false);
|
||||
//--- property
|
||||
m_inc.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create the "Decrement" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollH::CreateDec(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_BORDER_WIDTH;
|
||||
int y1=CONTROLS_BORDER_WIDTH;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE;
|
||||
//--- create
|
||||
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_dec.BmpNames("::res\\Left.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_dec))
|
||||
return(false);
|
||||
//--- property
|
||||
m_dec.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create scroll box |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollH::CreateThumb(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
|
||||
int y1=CONTROLS_BORDER_WIDTH;
|
||||
int x2=x1+CONTROLS_SCROLL_THUMB_SIZE;
|
||||
int y2=y1+CONTROLS_BUTTON_SIZE;
|
||||
//--- create
|
||||
if(!m_thumb.Create(m_chart_id,m_name+"Thumb",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_thumb.BmpNames("::res\\ThumbHor.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_thumb))
|
||||
return(false);
|
||||
m_thumb.PropFlags(WND_PROP_FLAG_CAN_DRAG);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of changing current state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollH::OnChangePos(void)
|
||||
{
|
||||
//--- check if scrolling is possible
|
||||
if(m_max_pos-m_min_pos<=0)
|
||||
return(Visible(false));
|
||||
else
|
||||
if(!Visible(true))
|
||||
return(false);
|
||||
//--- calculate new coordinated of the scrollbar
|
||||
int steps=m_max_pos-m_min_pos; // number of steps to change position
|
||||
int min_coord=m_dec.Right(); // minimum possible coordinate (corresponds to the m_min_pos value)
|
||||
int max_coord=m_inc.Left()-m_thumb.Width(); // maximum possible coordinate (corresponds to the m_max_pos value)
|
||||
int new_coord=min_coord+(max_coord-min_coord)*m_curr_pos/steps; // new coordinate
|
||||
//--- adjust the scroll box position
|
||||
return(m_thumb.Move(new_coord,m_thumb.Top()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of resizing |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollH::OnResize(void)
|
||||
{
|
||||
//--- can not change the lateral size
|
||||
if(Height()!=CONTROLS_SCROLL_SIZE)
|
||||
m_rect.Height(CONTROLS_SCROLL_SIZE);
|
||||
//--- resize the scrollbar background
|
||||
if(!m_back.Size(Size()))
|
||||
return(false);
|
||||
//--- move the "Increment" button
|
||||
if(!m_inc.Move(Right()-CONTROLS_SCROLL_SIZE,m_inc.Top()))
|
||||
return(false);
|
||||
//--- adjust the scroll box position
|
||||
return(OnChangePos());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Start dragging the "slider" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollH::OnThumbDragStart(void)
|
||||
{
|
||||
if(m_drag_object==NULL)
|
||||
{
|
||||
m_drag_object=new CDragWnd;
|
||||
if(m_drag_object==NULL)
|
||||
return(false);
|
||||
}
|
||||
//--- calculate coordinates
|
||||
int x1=m_thumb.Left()-CONTROLS_DRAG_SPACING;
|
||||
int y1=m_thumb.Top()-CONTROLS_DRAG_SPACING;
|
||||
int x2=m_thumb.Right()+CONTROLS_DRAG_SPACING;
|
||||
int y2=m_thumb.Bottom()+CONTROLS_DRAG_SPACING;
|
||||
//--- create
|
||||
m_drag_object.Create(m_chart_id,"",m_subwin,x1,y1,x2,y2);
|
||||
m_drag_object.PropFlags(WND_PROP_FLAG_CAN_DRAG);
|
||||
//--- îãðàíè÷åíèÿ
|
||||
m_drag_object.Limits(m_dec.Right()-CONTROLS_DRAG_SPACING,y1,m_inc.Left()+CONTROLS_DRAG_SPACING,y2);
|
||||
//--- set mouse params
|
||||
m_drag_object.MouseX(m_thumb.MouseX());
|
||||
m_drag_object.MouseY(m_thumb.MouseY());
|
||||
m_drag_object.MouseFlags(m_thumb.MouseFlags());
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Continue dragging the "slider" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollH::OnThumbDragProcess(void)
|
||||
{
|
||||
//--- checking
|
||||
if(m_drag_object==NULL)
|
||||
return(false);
|
||||
//--- calculate coordinates
|
||||
int x=m_drag_object.Left()+CONTROLS_DRAG_SPACING;
|
||||
int y=m_drag_object.Top()+CONTROLS_DRAG_SPACING;
|
||||
//--- calculate new position
|
||||
int new_pos=CalcPos(x);
|
||||
if(new_pos!=m_curr_pos)
|
||||
{
|
||||
ushort event_id=(m_curr_pos<new_pos)?ON_SCROLL_INC:ON_SCROLL_DEC;
|
||||
m_curr_pos=new_pos;
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,event_id,m_id,0.0,m_name);
|
||||
}
|
||||
//--- move thumb
|
||||
m_thumb.Move(x,y);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| End dragging the "slider" |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CScrollH::OnThumbDragEnd(void)
|
||||
{
|
||||
if(m_drag_object!=NULL)
|
||||
{
|
||||
m_thumb.MouseFlags(m_drag_object.MouseFlags());
|
||||
delete m_drag_object;
|
||||
m_drag_object=NULL;
|
||||
}
|
||||
//--- succeed
|
||||
return(m_thumb.Pressed(false));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Calculate position by coordinate |
|
||||
//+------------------------------------------------------------------+
|
||||
int CScrollH::CalcPos(const int coord)
|
||||
{
|
||||
//--- calculate new position of the scrollbar
|
||||
int steps =m_max_pos-m_min_pos; // number of steps to change position
|
||||
int min_coord=m_dec.Right(); // minimum possible coordinate (corresponds to the m_min_pos value)
|
||||
int max_coord=m_inc.Left()-m_thumb.Width(); // maximum possible coordinate (corresponds to the m_max_pos value)
|
||||
//--- checkeng
|
||||
if(max_coord==min_coord)
|
||||
return(0);
|
||||
if(coord<min_coord || coord>max_coord)
|
||||
return(m_curr_pos);
|
||||
//---
|
||||
int new_pos=(int)MathRound((((double)(coord-min_coord))/(max_coord-min_coord))*steps); // new position
|
||||
//---
|
||||
return(new_pos);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,265 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SpinEdit.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndContainer.mqh"
|
||||
#include "Edit.mqh"
|
||||
#include "BmpButton.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resources |
|
||||
//+------------------------------------------------------------------+
|
||||
#resource "res\\SpinInc.bmp"
|
||||
#resource "res\\SpinDec.bmp"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSpinEdit |
|
||||
//| Usage: class that implements the "Up-Down" control |
|
||||
//+------------------------------------------------------------------+
|
||||
class CSpinEdit : public CWndContainer
|
||||
{
|
||||
private:
|
||||
//--- dependent controls
|
||||
CEdit m_edit; // the entry field object
|
||||
CBmpButton m_inc; // the "Increment button" object
|
||||
CBmpButton m_dec; // the "Decrement button" object
|
||||
//--- adjusted parameters
|
||||
int m_min_value; // minimum value
|
||||
int m_max_value; // maximum value
|
||||
//--- state
|
||||
int m_value; // current value
|
||||
|
||||
public:
|
||||
CSpinEdit(void);
|
||||
~CSpinEdit(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- set up
|
||||
int MinValue(void) const { return(m_min_value); }
|
||||
void MinValue(const int value);
|
||||
int MaxValue(void) const { return(m_max_value); }
|
||||
void MaxValue(const int value);
|
||||
//--- state
|
||||
int Value(void) const { return(m_value); }
|
||||
bool Value(int value);
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
virtual bool CreateEdit(void);
|
||||
virtual bool CreateInc(void);
|
||||
virtual bool CreateDec(void);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual bool OnClickInc(void);
|
||||
virtual bool OnClickDec(void);
|
||||
//--- internal event handlers
|
||||
virtual bool OnChangeValue(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CSpinEdit)
|
||||
ON_EVENT(ON_CLICK,m_inc,OnClickInc)
|
||||
ON_EVENT(ON_CLICK,m_dec,OnClickDec)
|
||||
EVENT_MAP_END(CWndContainer)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSpinEdit::CSpinEdit(void) : m_min_value(0),
|
||||
m_max_value(0),
|
||||
m_value(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CSpinEdit::~CSpinEdit(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSpinEdit::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- check height
|
||||
if(y2-y1<CONTROLS_SPIN_MIN_HEIGHT)
|
||||
return(false);
|
||||
//--- call method of the parent class
|
||||
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
if(!CreateEdit())
|
||||
return(false);
|
||||
if(!CreateInc())
|
||||
return(false);
|
||||
if(!CreateDec())
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set current value |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSpinEdit::Value(int value)
|
||||
{
|
||||
//--- check value
|
||||
if(value<m_min_value)
|
||||
value=m_min_value;
|
||||
if(value>m_max_value)
|
||||
value=m_max_value;
|
||||
//--- if value was changed
|
||||
if(m_value!=value)
|
||||
{
|
||||
m_value=value;
|
||||
//--- call virtual handler
|
||||
return(OnChangeValue());
|
||||
}
|
||||
//--- value has not been changed
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSpinEdit::Save(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//---
|
||||
FileWriteInteger(file_handle,m_value);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSpinEdit::Load(const int file_handle)
|
||||
{
|
||||
//--- check
|
||||
if(file_handle==INVALID_HANDLE)
|
||||
return(false);
|
||||
//---
|
||||
if(!FileIsEnding(file_handle))
|
||||
Value(FileReadInteger(file_handle));
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set minimum value |
|
||||
//+------------------------------------------------------------------+
|
||||
void CSpinEdit::MinValue(const int value)
|
||||
{
|
||||
//--- if value was changed
|
||||
if(m_min_value!=value)
|
||||
{
|
||||
m_min_value=value;
|
||||
//--- adjust the edit value
|
||||
Value(m_value);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set maximum value |
|
||||
//+------------------------------------------------------------------+
|
||||
void CSpinEdit::MaxValue(const int value)
|
||||
{
|
||||
//--- if value was changed
|
||||
if(m_max_value!=value)
|
||||
{
|
||||
m_max_value=value;
|
||||
//--- adjust the edit value
|
||||
Value(m_value);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create the edit field |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSpinEdit::CreateEdit(void)
|
||||
{
|
||||
//--- create
|
||||
if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,0,0,Width(),Height()))
|
||||
return(false);
|
||||
if(!m_edit.Text(""))
|
||||
return(false);
|
||||
if(!m_edit.ReadOnly(true))
|
||||
return(false);
|
||||
if(!Add(m_edit))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create the "Increment" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSpinEdit::CreateInc(void)
|
||||
{
|
||||
//--- right align button (try to make equal offsets from top and bottom)
|
||||
int x1=Width()-(CONTROLS_BUTTON_SIZE+CONTROLS_SPIN_BUTTON_X_OFF);
|
||||
int y1=(Height()-2*CONTROLS_SPIN_BUTTON_SIZE)/2;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_SPIN_BUTTON_SIZE;
|
||||
//--- create
|
||||
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_inc.BmpNames("::res\\SpinInc.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_inc))
|
||||
return(false);
|
||||
//--- property
|
||||
m_inc.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create the "Decrement" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSpinEdit::CreateDec(void)
|
||||
{
|
||||
//--- right align button (try to make equal offsets from top and bottom)
|
||||
int x1=Width()-(CONTROLS_BUTTON_SIZE+CONTROLS_SPIN_BUTTON_X_OFF);
|
||||
int y1=(Height()-2*CONTROLS_SPIN_BUTTON_SIZE)/2+CONTROLS_SPIN_BUTTON_SIZE;
|
||||
int x2=x1+CONTROLS_BUTTON_SIZE;
|
||||
int y2=y1+CONTROLS_SPIN_BUTTON_SIZE;
|
||||
//--- create
|
||||
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!m_dec.BmpNames("::res\\SpinDec.bmp"))
|
||||
return(false);
|
||||
if(!Add(m_dec))
|
||||
return(false);
|
||||
//--- property
|
||||
m_dec.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the "increment" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSpinEdit::OnClickInc(void)
|
||||
{
|
||||
//--- try to increment current value
|
||||
return(Value(m_value+1));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the "decrement" button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSpinEdit::OnClickDec(void)
|
||||
{
|
||||
//--- try to decrement current value
|
||||
return(Value(m_value-1));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of changing current state |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CSpinEdit::OnChangeValue(void)
|
||||
{
|
||||
//--- copy text to the edit field edit
|
||||
m_edit.Text(IntegerToString(m_value));
|
||||
//--- send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,755 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Wnd.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Rect.mqh"
|
||||
#include "Defines.mqh"
|
||||
#include <Object.mqh>
|
||||
class CDragWnd;
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CWnd |
|
||||
//| Usage: base class of the control object that creates |
|
||||
//| control panels and indicator panels |
|
||||
//+------------------------------------------------------------------+
|
||||
class CWnd : public CObject
|
||||
{
|
||||
protected:
|
||||
//--- parameters of creation
|
||||
long m_chart_id; // chart ID
|
||||
int m_subwin; // chart subwindow
|
||||
string m_name; // object name
|
||||
//--- geometry
|
||||
CRect m_rect; // chart area
|
||||
//--- ID
|
||||
long m_id; // object ID
|
||||
//--- state flags
|
||||
int m_state_flags;
|
||||
//--- properties flags
|
||||
int m_prop_flags;
|
||||
//--- alignment
|
||||
int m_align_flags; // alignment flags
|
||||
int m_align_left; // fixed offset from left border
|
||||
int m_align_top; // fixed offset from top border
|
||||
int m_align_right; // fixed offset from right border
|
||||
int m_align_bottom; // fixed offset from bottom border
|
||||
//--- the last saved state of mouse
|
||||
int m_mouse_x; // X coordinate
|
||||
int m_mouse_y; // Y coordinate
|
||||
int m_mouse_flags; // state of buttons
|
||||
uint m_last_click; // last click time
|
||||
//--- drag object
|
||||
CDragWnd *m_drag_object; // pointer to the dragged object
|
||||
|
||||
public:
|
||||
CWnd(void);
|
||||
~CWnd(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- release memory
|
||||
virtual void Destroy(const int reason=0);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
virtual bool OnMouseEvent(const int x,const int y,const int flags);
|
||||
//--- naming (read only)
|
||||
string Name(void) const { return(m_name); }
|
||||
//--- access the contents of container
|
||||
int ControlsTotal(void) const { return(0); }
|
||||
CWnd* Control(const int ind) const { return(NULL); }
|
||||
virtual CWnd* ControlFind(const long id);
|
||||
//--- geometry
|
||||
const CRect Rect(void) const { return(m_rect); }
|
||||
int Left(void) const { return(m_rect.left); }
|
||||
virtual void Left(const int x) { m_rect.left=x; }
|
||||
int Top(void) const { return(m_rect.top); }
|
||||
virtual void Top(const int y) { m_rect.top=y; }
|
||||
int Right(void) const { return(m_rect.right); }
|
||||
virtual void Right(const int x) { m_rect.right=x; }
|
||||
int Bottom(void) const { return(m_rect.bottom); }
|
||||
virtual void Bottom(const int y) { m_rect.bottom=y; }
|
||||
int Width(void) const { return(m_rect.Width()); }
|
||||
virtual bool Width(const int w);
|
||||
int Height(void) const { return(m_rect.Height()); }
|
||||
virtual bool Height(const int h);
|
||||
CSize Size(void) const { return(m_rect.Size()); }
|
||||
virtual bool Size(const int w,const int h);
|
||||
virtual bool Size(const CSize &size);
|
||||
virtual bool Move(const int x,const int y);
|
||||
virtual bool Move(const CPoint &point);
|
||||
virtual bool Shift(const int dx,const int dy);
|
||||
bool Contains(const int x,const int y) const { return(m_rect.Contains(x,y)); }
|
||||
bool Contains(CWnd *control) const;
|
||||
//--- alignment
|
||||
void Alignment(const int flags,const int left,const int top,const int right,const int bottom);
|
||||
virtual bool Align(const CRect &rect);
|
||||
//--- ID
|
||||
virtual long Id(const long id);
|
||||
long Id(void) const { return(m_id); }
|
||||
//--- state
|
||||
bool IsEnabled(void) const { return(IS_ENABLED); }
|
||||
virtual bool Enable(void);
|
||||
virtual bool Disable(void);
|
||||
bool IsVisible(void) const { return(IS_VISIBLE); }
|
||||
virtual bool Visible(const bool flag);
|
||||
virtual bool Show(void);
|
||||
virtual bool Hide(void);
|
||||
bool IsActive(void) const { return(IS_ACTIVE); }
|
||||
virtual bool Activate(void);
|
||||
virtual bool Deactivate(void);
|
||||
//--- state flags
|
||||
int StateFlags(void) const { return(m_state_flags); }
|
||||
void StateFlags(const int flags) { m_state_flags=flags; }
|
||||
void StateFlagsSet(const int flags) { m_state_flags|=flags; }
|
||||
void StateFlagsReset(const int flags) { m_state_flags&=~flags; }
|
||||
//--- properties flags
|
||||
int PropFlags(void) const { return(m_prop_flags); }
|
||||
void PropFlags(const int flags) { m_prop_flags=flags; }
|
||||
void PropFlagsSet(const int flags) { m_prop_flags|=flags; }
|
||||
void PropFlagsReset(const int flags) { m_prop_flags&=~flags; }
|
||||
//--- for mouse operations
|
||||
int MouseX(void) const { return(m_mouse_x); }
|
||||
void MouseX(const int value) { m_mouse_x=value; }
|
||||
int MouseY(void) const { return(m_mouse_y); }
|
||||
void MouseY(const int value) { m_mouse_y=value; }
|
||||
int MouseFlags(void) const { return(m_mouse_flags); }
|
||||
virtual void MouseFlags(const int value) { m_mouse_flags=value; }
|
||||
bool MouseFocusKill(const long id=CONTROLS_INVALID_ID);
|
||||
bool BringToTop(void);
|
||||
|
||||
protected:
|
||||
//--- internal event handlers
|
||||
virtual bool OnCreate(void) { return(true); }
|
||||
virtual bool OnDestroy(void) { return(true); }
|
||||
virtual bool OnMove(void) { return(true); }
|
||||
virtual bool OnResize(void) { return(true); }
|
||||
virtual bool OnEnable(void) { return(true); }
|
||||
virtual bool OnDisable(void) { return(true); }
|
||||
virtual bool OnShow(void) { return(true); }
|
||||
virtual bool OnHide(void) { return(true); }
|
||||
virtual bool OnActivate(void) { return(true); }
|
||||
virtual bool OnDeactivate(void) { return(true); }
|
||||
virtual bool OnClick(void);
|
||||
virtual bool OnDblClick(void);
|
||||
virtual bool OnChange(void) { return(true); }
|
||||
//--- mouse event handlers
|
||||
virtual bool OnMouseDown(void);
|
||||
virtual bool OnMouseUp(void);
|
||||
//--- handlers of dragging
|
||||
virtual bool OnDragStart(void);
|
||||
virtual bool OnDragProcess(const int x,const int y);
|
||||
virtual bool OnDragEnd(void);
|
||||
//--- methods for drag-object
|
||||
virtual bool DragObjectCreate(void) { return(false); }
|
||||
virtual bool DragObjectDestroy(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
|
||||
{
|
||||
if((id!=CHARTEVENT_MOUSE_MOVE))
|
||||
return(false);
|
||||
if(!IS_VISIBLE)
|
||||
return(false);
|
||||
int x=(int)lparam;
|
||||
int y=(int)dparam;
|
||||
int flags=(int)StringToInteger(sparam);
|
||||
//---
|
||||
if(m_drag_object!=NULL)
|
||||
return(m_drag_object.OnMouseEvent(x,y,flags));
|
||||
//---
|
||||
return(OnMouseEvent(x,y,flags));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of mouse events |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::OnMouseEvent(const int x,const int y,const int flags)
|
||||
{
|
||||
if(!Contains(x,y))
|
||||
{
|
||||
//--- if cursor is not inside the element and this element is active - deactivate
|
||||
if(IS_ACTIVE)
|
||||
{
|
||||
//--- reset state and coordinates
|
||||
m_mouse_x =0;
|
||||
m_mouse_y =0;
|
||||
m_mouse_flags=MOUSE_INVALID_FLAGS;
|
||||
//--- deactivate
|
||||
Deactivate();
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//--- check the state of the left mouse button
|
||||
if((flags&MOUSE_LEFT)!=0)
|
||||
{
|
||||
//--- left mouse button is pressed
|
||||
if(m_mouse_flags==MOUSE_INVALID_FLAGS)
|
||||
{
|
||||
//--- but not in this control (i.e., cursor entered the element with mouse button pressed)
|
||||
//--- activate the control, but there will be no click
|
||||
if(!IS_ACTIVE)
|
||||
{
|
||||
//--- generate event
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_MOUSE_FOCUS_SET,m_id,0.0,m_name);
|
||||
//--- activate
|
||||
return(Activate());
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
if((m_mouse_flags&MOUSE_LEFT)!=0)
|
||||
{
|
||||
//--- mouse button has already been pressed
|
||||
if(IS_CAN_DRAG)
|
||||
return(OnDragProcess(x,y));
|
||||
if(IS_CLICKS_BY_PRESS)
|
||||
{
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CLICK,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- mouse button has been released (pressing)
|
||||
//--- save the state and coordinates
|
||||
m_mouse_flags=flags;
|
||||
m_mouse_x =x;
|
||||
m_mouse_y =y;
|
||||
//--- call the handler
|
||||
return(OnMouseDown());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- left mouse button is released
|
||||
if(m_mouse_flags==MOUSE_INVALID_FLAGS)
|
||||
{
|
||||
//--- cursor entered the control with mouse button released
|
||||
//--- activate control and save state to the member
|
||||
m_mouse_flags=flags;
|
||||
//--- generate event
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_MOUSE_FOCUS_SET,m_id,0.0,m_name);
|
||||
//--- activate
|
||||
return(Activate());
|
||||
}
|
||||
if((m_mouse_flags&MOUSE_LEFT)!=0)
|
||||
{
|
||||
//--- mouse button has been pressed (clicking)
|
||||
//--- save the state and coordinates
|
||||
m_mouse_flags=flags;
|
||||
m_mouse_x =x;
|
||||
m_mouse_y =y;
|
||||
//--- call the handler
|
||||
return(OnMouseUp());
|
||||
}
|
||||
}
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CWnd::CWnd(void) : m_chart_id(CONTROLS_INVALID_ID),
|
||||
m_subwin(CONTROLS_INVALID_ID),
|
||||
m_name(NULL),
|
||||
m_id(CONTROLS_INVALID_ID),
|
||||
m_state_flags(WND_STATE_FLAG_ENABLE+WND_STATE_FLAG_VISIBLE),
|
||||
m_prop_flags(0),
|
||||
m_align_flags(WND_ALIGN_NONE),
|
||||
m_align_left(0),
|
||||
m_align_top(0),
|
||||
m_align_right(0),
|
||||
m_align_bottom(0),
|
||||
m_mouse_x(0),
|
||||
m_mouse_y(0),
|
||||
m_mouse_flags(MOUSE_INVALID_FLAGS),
|
||||
m_last_click(0),
|
||||
m_drag_object(NULL)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CWnd::~CWnd(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- attach to chart
|
||||
m_chart_id=chart;
|
||||
m_name =name;
|
||||
m_subwin =subwin;
|
||||
//--- set coordinates of area
|
||||
Left(x1);
|
||||
Top(y1);
|
||||
Right(x2);
|
||||
Bottom(y2);
|
||||
//--- always successful
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destruction of the control |
|
||||
//+------------------------------------------------------------------+
|
||||
void CWnd::Destroy(const int reason)
|
||||
{
|
||||
//--- call virtual event handler
|
||||
if(OnDestroy())
|
||||
m_name="";
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find control by specified ID |
|
||||
//+------------------------------------------------------------------+
|
||||
CWnd* CWnd::ControlFind(const long id)
|
||||
{
|
||||
CWnd *result=NULL;
|
||||
//--- check
|
||||
if(id==m_id)
|
||||
result=GetPointer(this);
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Change width of control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Width(const int w)
|
||||
{
|
||||
//--- change width
|
||||
m_rect.Width(w);
|
||||
//--- call virtual event handler
|
||||
return(OnResize());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Change height of control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Height(const int h)
|
||||
{
|
||||
//--- change height
|
||||
m_rect.Height(h);
|
||||
//--- call virtual event handler
|
||||
return(OnResize());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resize control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Size(const int w,const int h)
|
||||
{
|
||||
//--- change size
|
||||
m_rect.Size(w,h);
|
||||
//--- call virtual event handler
|
||||
return(OnResize());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resize control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Size(const CSize &size)
|
||||
{
|
||||
//--- change size
|
||||
m_rect.Size(size);
|
||||
//--- call virtual event handler
|
||||
return(OnResize());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of the control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Move(const int x,const int y)
|
||||
{
|
||||
//--- moving
|
||||
m_rect.Move(x,y);
|
||||
//--- call virtual event handler
|
||||
return(OnMove());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of the control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Move(const CPoint &point)
|
||||
{
|
||||
//--- moving
|
||||
m_rect.Move(point);
|
||||
//--- call virtual event handler
|
||||
return(OnMove());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Relative movement of the control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Shift(const int dx,const int dy)
|
||||
{
|
||||
//--- moving
|
||||
m_rect.Shift(dx,dy);
|
||||
//--- call virtual event handler
|
||||
return(OnMove());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check contains |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Contains(CWnd *control) const
|
||||
{
|
||||
//--- check
|
||||
if(control==NULL)
|
||||
return(false);
|
||||
//--- result
|
||||
return(Contains(control.Left(),control.Top()) && Contains(control.Right(),control.Bottom()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Enables event handling by the control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Enable(void)
|
||||
{
|
||||
//--- if there are now changes, then succeed
|
||||
if(IS_ENABLED)
|
||||
return(true);
|
||||
//--- change flag
|
||||
StateFlagsSet(WND_STATE_FLAG_ENABLE);
|
||||
//--- call virtual event handler
|
||||
return(OnEnable());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Disables event handling by the control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Disable(void)
|
||||
{
|
||||
//--- if there are now changes, then succeed
|
||||
if(!IS_ENABLED)
|
||||
return(true);
|
||||
//--- change flag
|
||||
StateFlagsReset(WND_STATE_FLAG_ENABLE);
|
||||
//--- call virtual event handler
|
||||
return(OnDisable());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "object is visible" flag for the control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Visible(const bool flag)
|
||||
{
|
||||
//--- if there are now changes, then succeed
|
||||
if(IS_VISIBLE==flag)
|
||||
return(true);
|
||||
//--- call virtual event handler
|
||||
return(flag ? Show() : Hide());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the control visible |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Show(void)
|
||||
{
|
||||
//--- change flag
|
||||
StateFlagsSet(WND_STATE_FLAG_VISIBLE);
|
||||
//--- call virtual event handler
|
||||
return(OnShow());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the control hidden |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Hide(void)
|
||||
{
|
||||
//--- change flag
|
||||
StateFlagsReset(WND_STATE_FLAG_VISIBLE);
|
||||
//--- call virtual event handler
|
||||
return(OnHide());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the control active |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Activate(void)
|
||||
{
|
||||
//--- if there are now changes, then succeed
|
||||
if(IS_ACTIVE)
|
||||
return(true);
|
||||
//--- change flag
|
||||
StateFlagsSet(WND_STATE_FLAG_ACTIVE);
|
||||
//--- call virtual event handler
|
||||
return(OnActivate());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the control inactive |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Deactivate(void)
|
||||
{
|
||||
//--- if there are now changes, then succeed
|
||||
if(!IS_ACTIVE)
|
||||
return(true);
|
||||
//--- change flag
|
||||
StateFlagsReset(WND_STATE_FLAG_ACTIVE);
|
||||
//--- call virtual event handler
|
||||
return(OnDeactivate());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set ID of control |
|
||||
//+------------------------------------------------------------------+
|
||||
long CWnd::Id(const long id)
|
||||
{
|
||||
m_id=id;
|
||||
//--- always use only one ID
|
||||
return(1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set parameters of alignment |
|
||||
//+------------------------------------------------------------------+
|
||||
void CWnd::Alignment(const int flags,const int left,const int top,const int right,const int bottom)
|
||||
{
|
||||
m_align_flags =flags;
|
||||
m_align_left =left;
|
||||
m_align_top =top;
|
||||
m_align_right =right;
|
||||
m_align_bottom=bottom;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Align element in specified chart area |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::Align(const CRect &rect)
|
||||
{
|
||||
int new_value=0;
|
||||
//--- check
|
||||
if(m_align_flags==WND_ALIGN_NONE)
|
||||
return(true);
|
||||
//--- we are interested only in alignment by right and bottom borders,
|
||||
//--- as left and right borders are processed in the OnMove()
|
||||
if((m_align_flags&WND_ALIGN_RIGHT)!=0)
|
||||
{
|
||||
//--- there is alignment by right border,
|
||||
if((m_align_flags&WND_ALIGN_LEFT)!=0)
|
||||
{
|
||||
//--- and by left border (change size)
|
||||
new_value=rect.Width()-m_align_left-m_align_right;
|
||||
if(!Size(new_value,Height()))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- no alignment by left border (move)
|
||||
new_value=rect.right-Width()-m_align_right;
|
||||
if(!Move(new_value,Top()))
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if((m_align_flags&WND_ALIGN_BOTTOM)!=0)
|
||||
{
|
||||
//--- there is alignment by bottom border,
|
||||
if((m_align_flags&WND_ALIGN_TOP)!=0)
|
||||
{
|
||||
//--- and by top border (change size)
|
||||
new_value=rect.Height()-m_align_top-m_align_bottom;
|
||||
if(!Size(Width(),new_value))
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- no alignment by top border (move)
|
||||
new_value=rect.bottom-Height()-m_align_bottom;
|
||||
if(!Move(Left(),new_value))
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Remove the mouse focus from control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::MouseFocusKill(const long id)
|
||||
{
|
||||
//--- check
|
||||
if(id==m_id)
|
||||
return(false);
|
||||
//--- reset flag
|
||||
Deactivate();
|
||||
//--- clean
|
||||
m_mouse_x =0;
|
||||
m_mouse_y =0;
|
||||
m_mouse_flags=MOUSE_INVALID_FLAGS;
|
||||
//--- call the handler
|
||||
return(OnDeactivate());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Increases the priority of an element |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::BringToTop(void)
|
||||
{
|
||||
//--- generate event
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_BRING_TO_TOP,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "click" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::OnClick(void)
|
||||
{
|
||||
//--- send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CLICK,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "doubl click" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::OnDblClick(void)
|
||||
{
|
||||
//--- send notification
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DBL_CLICK,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of click on the left mouse button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::OnMouseDown(void)
|
||||
{
|
||||
if(IS_CAN_DRAG)
|
||||
return(OnDragStart());
|
||||
if(IS_CLICKS_BY_PRESS)
|
||||
return(OnClick());
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of releasing the left mouse button |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::OnMouseUp(void)
|
||||
{
|
||||
if(IS_CAN_DBL_CLICK)
|
||||
{
|
||||
uint last_time=GetTickCount();
|
||||
if(m_last_click==0 || last_time-m_last_click>CONTROLS_DBL_CLICK_TIME)
|
||||
{
|
||||
m_last_click=(last_time==0) ? 1 : last_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_last_click=0;
|
||||
return(OnDblClick());
|
||||
}
|
||||
}
|
||||
if(IS_CAN_DRAG)
|
||||
return(OnDragEnd());
|
||||
if(!IS_CLICKS_BY_PRESS)
|
||||
return(OnClick());
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the control dragging start |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::OnDragStart(void)
|
||||
{
|
||||
if(!IS_CAN_DRAG)
|
||||
return(true);
|
||||
//--- disable scrolling of chart with mouse
|
||||
ChartSetInteger(m_chart_id,CHART_MOUSE_SCROLL,false);
|
||||
//--- generate event
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DRAG_START,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of control dragging process |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::OnDragProcess(const int x,const int y)
|
||||
{
|
||||
Shift(x-m_mouse_x,y-m_mouse_y);
|
||||
//--- save
|
||||
m_mouse_x=x;
|
||||
m_mouse_y=y;
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the control dragging end |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::OnDragEnd(void)
|
||||
{
|
||||
if(!IS_CAN_DRAG)
|
||||
return(true);
|
||||
//--- enable scrolling of chart with mouse
|
||||
ChartSetInteger(m_chart_id,CHART_MOUSE_SCROLL,true);
|
||||
//--- generate event
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DRAG_END,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destroy the dragged object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWnd::DragObjectDestroy(void)
|
||||
{
|
||||
if(m_drag_object!=NULL)
|
||||
{
|
||||
delete m_drag_object;
|
||||
m_drag_object=NULL;
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CDragWnd |
|
||||
//| Usage: base class for drag |
|
||||
//+------------------------------------------------------------------+
|
||||
class CDragWnd : public CWnd
|
||||
{
|
||||
protected:
|
||||
int m_limit_left; // left constraint
|
||||
int m_limit_top; // top constraint
|
||||
int m_limit_right; // right constraint
|
||||
int m_limit_bottom; // bottom constraint
|
||||
|
||||
public:
|
||||
CDragWnd(void);
|
||||
~CDragWnd(void);
|
||||
//--- constraints
|
||||
void Limits(const int l,const int t,const int r,const int b);
|
||||
|
||||
protected:
|
||||
virtual bool OnDragProcess(const int x,const int y);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDragWnd::CDragWnd(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CDragWnd::~CDragWnd(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constrain the control dragging |
|
||||
//+------------------------------------------------------------------+
|
||||
void CDragWnd::Limits(const int l,const int t,const int r,const int b)
|
||||
{
|
||||
//--- save
|
||||
m_limit_left =l;
|
||||
m_limit_top =t;
|
||||
m_limit_right =r;
|
||||
m_limit_bottom=b;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of control dragging process |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CDragWnd::OnDragProcess(const int x,const int y)
|
||||
{
|
||||
int dx=x-m_mouse_x;
|
||||
int dy=y-m_mouse_y;
|
||||
//--- check shift
|
||||
if(Right()+dx>m_limit_right)
|
||||
dx=m_limit_right-Right();
|
||||
if(Left()+dx<m_limit_left)
|
||||
dx=m_limit_left-Left();
|
||||
if(Bottom()+dy>m_limit_bottom)
|
||||
dy=m_limit_bottom-Bottom();
|
||||
if(Top()+dy<m_limit_top)
|
||||
dy=m_limit_top-Top();
|
||||
//--- shift
|
||||
Shift(dx,dy);
|
||||
//--- save
|
||||
m_mouse_x=x;
|
||||
m_mouse_y=y;
|
||||
//--- generate event
|
||||
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DRAG_PROCESS,m_id,0.0,m_name);
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,308 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| WndClient.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "WndContainer.mqh"
|
||||
#include "Panel.mqh"
|
||||
#include "Scrolls.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CWndClient |
|
||||
//| Usage: base class to create areas with |
|
||||
//| the scrollbars |
|
||||
//+------------------------------------------------------------------+
|
||||
class CWndClient : public CWndContainer
|
||||
{
|
||||
protected:
|
||||
//--- flags
|
||||
bool m_v_scrolled; // "vertical scrolling is possible" flag
|
||||
bool m_h_scrolled; // "horizontal scrolling is possible" flag
|
||||
//--- dependent controls
|
||||
CPanel m_background; // the "scrollbar background" object
|
||||
CScrollV m_scroll_v; // the vertical scrollbar object
|
||||
CScrollH m_scroll_h; // the horizontal scrollbar object
|
||||
|
||||
public:
|
||||
CWndClient(void);
|
||||
~CWndClient(void);
|
||||
//--- create
|
||||
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- parameters
|
||||
virtual bool ColorBackground(const color value) { return(m_background.ColorBackground(value)); }
|
||||
virtual bool ColorBorder(const color value) { return(m_background.ColorBorder(value)); }
|
||||
virtual bool BorderType(const ENUM_BORDER_TYPE flag) { return(m_background.BorderType(flag)); }
|
||||
//--- settings
|
||||
virtual bool VScrolled(void) { return(m_v_scrolled); }
|
||||
virtual bool VScrolled(const bool flag);
|
||||
virtual bool HScrolled(void) { return(m_h_scrolled); }
|
||||
virtual bool HScrolled(const bool flag);
|
||||
//--- ID
|
||||
virtual long Id(const long id);
|
||||
virtual long Id(void) const { return(CWnd::Id()); }
|
||||
//--- state
|
||||
virtual bool Show(void);
|
||||
|
||||
protected:
|
||||
//--- create dependent controls
|
||||
virtual bool CreateBack(void);
|
||||
virtual bool CreateScrollV(void);
|
||||
virtual bool CreateScrollH(void);
|
||||
//--- internal event handlers
|
||||
virtual bool OnResize(void);
|
||||
//--- handlers of the dependent controls events
|
||||
virtual bool OnVScrollShow(void) { return(true); }
|
||||
virtual bool OnVScrollHide(void) { return(true); }
|
||||
virtual bool OnHScrollShow(void) { return(true); }
|
||||
virtual bool OnHScrollHide(void) { return(true); }
|
||||
virtual bool OnScrollLineDown(void) { return(true); }
|
||||
virtual bool OnScrollLineUp(void) { return(true); }
|
||||
virtual bool OnScrollLineLeft(void) { return(true); }
|
||||
virtual bool OnScrollLineRight(void) { return(true); }
|
||||
//--- resize
|
||||
virtual bool Rebound(const CRect &rect);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
EVENT_MAP_BEGIN(CWndClient)
|
||||
ON_NAMED_EVENT(ON_SHOW,m_scroll_v,OnVScrollShow)
|
||||
ON_NAMED_EVENT(ON_HIDE,m_scroll_v,OnVScrollHide)
|
||||
ON_EVENT(ON_SCROLL_DEC,m_scroll_v,OnScrollLineUp)
|
||||
ON_EVENT(ON_SCROLL_INC,m_scroll_v,OnScrollLineDown)
|
||||
ON_NAMED_EVENT(ON_SHOW,m_scroll_h,OnHScrollShow)
|
||||
ON_NAMED_EVENT(ON_HIDE,m_scroll_h,OnHScrollHide)
|
||||
ON_EVENT(ON_SCROLL_DEC,m_scroll_h,OnScrollLineLeft)
|
||||
ON_EVENT(ON_SCROLL_INC,m_scroll_h,OnScrollLineRight)
|
||||
EVENT_MAP_END(CWndContainer)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CWndClient::CWndClient(void) : m_v_scrolled(false),
|
||||
m_h_scrolled(false)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CWndClient::~CWndClient(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create a control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndClient::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
//--- create dependent controls
|
||||
if(!CreateBack())
|
||||
return(false);
|
||||
if(m_v_scrolled && !CreateScrollV())
|
||||
return(false);
|
||||
if(m_h_scrolled && !CreateScrollH())
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create scrollbar background |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndClient::CreateBack(void)
|
||||
{
|
||||
//--- create
|
||||
if(!m_background.Create(m_chart_id,m_name+"Back",m_subwin,0,0,Width(),Height()))
|
||||
return(false);
|
||||
if(!m_background.ColorBorder(CONTROLS_CLIENT_COLOR_BORDER))
|
||||
return(false);
|
||||
if(!m_background.ColorBackground(CONTROLS_CLIENT_COLOR_BG))
|
||||
return(false);
|
||||
if(!Add(m_background))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create vertical scrollbar |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndClient::CreateScrollV(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=Width()-CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
|
||||
int y1=CONTROLS_BORDER_WIDTH;
|
||||
int x2=Width()-CONTROLS_BORDER_WIDTH;
|
||||
int y2=Height()-CONTROLS_BORDER_WIDTH;
|
||||
if(m_h_scrolled) y2-=CONTROLS_SCROLL_SIZE;
|
||||
//--- create
|
||||
if(!m_scroll_v.Create(m_chart_id,m_name+"VScroll",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!Add(m_scroll_v))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create horizontal scrollbar |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndClient::CreateScrollH(void)
|
||||
{
|
||||
//--- calculate coordinates
|
||||
int x1=CONTROLS_BORDER_WIDTH;
|
||||
int y1=Height()-CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
|
||||
int x2=Width()-CONTROLS_BORDER_WIDTH;
|
||||
int y2=Height()-CONTROLS_BORDER_WIDTH;
|
||||
if(m_v_scrolled) x2-=CONTROLS_SCROLL_SIZE;
|
||||
//--- create
|
||||
if(!m_scroll_h.Create(m_chart_id,m_name+"HScroll",m_subwin,x1,y1,x2,y2))
|
||||
return(false);
|
||||
if(!Add(m_scroll_h))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set up vertical scrollbar |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndClient::VScrolled(const bool flag)
|
||||
{
|
||||
if(m_v_scrolled==flag)
|
||||
return(true);
|
||||
//--- there are changes
|
||||
int d_size=0;
|
||||
if(flag)
|
||||
{
|
||||
//--- create vertical scrollbar
|
||||
if(!CreateScrollV())
|
||||
return(false);
|
||||
//--- need to shorten horizontal scrollbar (if there is one)
|
||||
d_size=-CONTROLS_SCROLL_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- delete vertical scrollbar
|
||||
m_scroll_v.Destroy();
|
||||
if(!Delete(m_scroll_v))
|
||||
return(false);
|
||||
//--- need to lengthen horizontal scrollbar (if there is one)
|
||||
d_size=CONTROLS_SCROLL_SIZE;
|
||||
}
|
||||
m_v_scrolled=flag;
|
||||
//--- change width of horizontal scrollbar (if there is one)
|
||||
if(m_h_scrolled)
|
||||
{
|
||||
if(!m_scroll_h.Width(m_scroll_h.Width()+d_size))
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set up horizontal scrollbar |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndClient::HScrolled(const bool flag)
|
||||
{
|
||||
if(m_h_scrolled==flag)
|
||||
return(true);
|
||||
//--- there are changes
|
||||
int d_size=0;
|
||||
if(flag)
|
||||
{
|
||||
//--- create horizontal scrollbar
|
||||
if(!CreateScrollH())
|
||||
return(false);
|
||||
//--- need to shorten vertical scrollbar (if there is one)
|
||||
d_size=-CONTROLS_SCROLL_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- delete horizontal scrollbar
|
||||
m_scroll_h.Destroy();
|
||||
if(!Delete(m_scroll_h))
|
||||
return(false);
|
||||
//--- need to lengthen vertical scrollbar (if there is one)
|
||||
d_size=CONTROLS_SCROLL_SIZE;
|
||||
}
|
||||
m_h_scrolled=flag;
|
||||
//--- change width of vertical scrollbar (if there is one)
|
||||
if(m_v_scrolled)
|
||||
{
|
||||
if(!m_scroll_v.Height(m_scroll_v.Height()+d_size))
|
||||
return(false);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set ID of control |
|
||||
//+------------------------------------------------------------------+
|
||||
long CWndClient::Id(const long id)
|
||||
{
|
||||
//--- reserve ID for container
|
||||
long id_used=CWndContainer::Id(id);
|
||||
//---
|
||||
if(!m_v_scrolled)
|
||||
id_used+=m_scroll_v.Id(id+id_used);
|
||||
if(!m_h_scrolled)
|
||||
id_used+=m_scroll_h.Id(id+id_used);
|
||||
//--- return number of used IDs
|
||||
return(id_used);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the control visible |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndClient::Show(void)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
CWndContainer::Show();
|
||||
//---
|
||||
if(!m_v_scrolled)
|
||||
m_scroll_v.Hide();
|
||||
if(!m_h_scrolled)
|
||||
m_scroll_h.Hide();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of resizing |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndClient::OnResize(void)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
if(!CWndContainer::OnResize())
|
||||
return(false);
|
||||
//--- resize background
|
||||
int d_size=0;
|
||||
m_background.Width(Width());
|
||||
m_background.Height(Height());
|
||||
//---
|
||||
if(m_v_scrolled)
|
||||
{
|
||||
//--- move vertical scrollbar
|
||||
m_scroll_v.Move(Right()-CONTROLS_SCROLL_SIZE,Top());
|
||||
//--- modify vertical scrollbar
|
||||
d_size=(m_h_scrolled) ? CONTROLS_SCROLL_SIZE : 0;
|
||||
m_scroll_v.Height(Height()-d_size);
|
||||
}
|
||||
if(m_h_scrolled)
|
||||
{
|
||||
//--- move horizontal scrollbar
|
||||
m_scroll_h.Move(Left(),Bottom()-CONTROLS_SCROLL_SIZE);
|
||||
//--- modify horizontal scrollbar
|
||||
d_size=(m_v_scrolled) ? CONTROLS_SCROLL_SIZE : 0;
|
||||
m_scroll_h.Width(Width()-d_size);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resize |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndClient::Rebound(const CRect &rect)
|
||||
{
|
||||
m_rect.SetBound(rect);
|
||||
//--- call virtual event handler
|
||||
return(OnResize());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,473 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| WndContainer.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Wnd.mqh"
|
||||
#include <Arrays\ArrayObj.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CWndContainer |
|
||||
//| Usage: base class of the combined control |
|
||||
//+------------------------------------------------------------------+
|
||||
class CWndContainer : public CWnd
|
||||
{
|
||||
private:
|
||||
CArrayObj m_controls; // container of the control
|
||||
|
||||
public:
|
||||
CWndContainer(void);
|
||||
~CWndContainer(void);
|
||||
//--- release memory
|
||||
virtual void Destroy(const int reason=0);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
virtual bool OnMouseEvent(const int x,const int y,const int flags);
|
||||
//--- access the contents of container
|
||||
int ControlsTotal(void) const { return(m_controls.Total()); }
|
||||
CWnd* Control(const int ind) const { return(dynamic_cast<CWnd *>(m_controls.At(ind))); }
|
||||
virtual CWnd* ControlFind(const long id);
|
||||
//--- for mouse cursor focus
|
||||
virtual bool MouseFocusKill(const long id=-1);
|
||||
//--- fill
|
||||
bool Add(CWnd *control);
|
||||
bool Add(CWnd &control);
|
||||
//--- underflowing
|
||||
bool Delete(CWnd *control);
|
||||
bool Delete(CWnd &control);
|
||||
//--- geometry
|
||||
virtual bool Move(const int x,const int y);
|
||||
virtual bool Move(const CPoint &point);
|
||||
virtual bool Shift(const int dx,const int dy);
|
||||
//--- ID
|
||||
virtual long Id(const long id);
|
||||
long Id(void) const { return(CWnd::Id()); }
|
||||
//--- state
|
||||
virtual bool Enable(void);
|
||||
virtual bool Disable(void);
|
||||
virtual bool Show(void);
|
||||
virtual bool Hide(void);
|
||||
//--- methods for working with files
|
||||
virtual bool Save(const int file_handle);
|
||||
virtual bool Load(const int file_handle);
|
||||
|
||||
protected:
|
||||
//--- internal event handlers
|
||||
virtual bool OnResize(void);
|
||||
virtual bool OnActivate(void);
|
||||
virtual bool OnDeactivate(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
|
||||
{
|
||||
//--- if an object is being dragged, pass control to the special drag object
|
||||
if(m_drag_object!=NULL && m_drag_object.OnEvent(id,lparam,dparam,sparam))
|
||||
return(true);
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=total-1;i>=0;i--)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
if(control.OnEvent(id,lparam,dparam,sparam))
|
||||
return(true);
|
||||
}
|
||||
//--- not handled
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of mouse events |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::OnMouseEvent(const int x,const int y,const int flags)
|
||||
{
|
||||
if(!IS_VISIBLE)
|
||||
return(false);
|
||||
//--- if an object is being dragged, pass control to the special drag object
|
||||
if(m_drag_object!=NULL && m_drag_object.OnMouseEvent(x,y,flags))
|
||||
return(true);
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=total-1;i>=0;i--)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
if(control.OnMouseEvent(x,y,flags))
|
||||
return(true);
|
||||
}
|
||||
//--- call of the method of the parent class
|
||||
return(CWnd::OnMouseEvent(x,y,flags));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CWndContainer::CWndContainer(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CWndContainer::~CWndContainer(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete group of controls |
|
||||
//+------------------------------------------------------------------+
|
||||
void CWndContainer::Destroy(const int reason)
|
||||
{
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(0);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
control.Destroy();
|
||||
m_controls.Delete(0);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find control by specified ID |
|
||||
//+------------------------------------------------------------------+
|
||||
CWnd* CWndContainer::ControlFind(const long id)
|
||||
{
|
||||
CWnd *result=CWnd::ControlFind(id);
|
||||
//---
|
||||
if(result!=NULL)
|
||||
return(result);
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
result=control.ControlFind(id);
|
||||
if(result!=NULL)
|
||||
break;
|
||||
}
|
||||
//--- return the result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Remove the mouse focus from control |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::MouseFocusKill(const long id=-1)
|
||||
{
|
||||
if(!IS_ACTIVE)
|
||||
return(false);
|
||||
Deactivate();
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
control.MouseFocusKill();
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add control to the group (by pointer) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Add(CWnd *control)
|
||||
{
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
return(false);
|
||||
//--- correct the coordinates of added control
|
||||
control.Shift(Left(),Top());
|
||||
//--- "projecting" the group flag "visibility" to the added element
|
||||
if(IS_VISIBLE && control.IsVisible())
|
||||
{
|
||||
//--- element will be "visible" only if the group is "visible" and the element is completely "within" this group
|
||||
control.Visible(Contains(control));
|
||||
}
|
||||
else
|
||||
control.Hide();
|
||||
//--- "projecting" the group flag "enabled" to the added element
|
||||
if(IS_ENABLED)
|
||||
control.Enable();
|
||||
else
|
||||
control.Disable();
|
||||
//--- adding
|
||||
return(m_controls.Add(control));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add control to the group (by reference) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Add(CWnd &control)
|
||||
{
|
||||
//--- add by pointer
|
||||
return(Add((CWnd*)GetPointer(control)));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete control from the group (by pointer) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Delete(CWnd *control)
|
||||
{
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
return(false);
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *pointer=Control(i);
|
||||
//--- check of pointer
|
||||
if(pointer==NULL)
|
||||
continue;
|
||||
//--- delete item from group
|
||||
if(pointer==control)
|
||||
return(m_controls.Delete(i));
|
||||
}
|
||||
//--- failure
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Delete control from the group (by reference) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Delete(CWnd &control)
|
||||
{
|
||||
//--- delete by pointer
|
||||
return(Delete((CWnd*)GetPointer(control)));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of the controls group |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Move(const int x,const int y)
|
||||
{
|
||||
//--- relative movement
|
||||
return(Shift(x-Left(),y-Top()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Absolute movement of the controls group |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Move(const CPoint &point)
|
||||
{
|
||||
//--- relative movement
|
||||
return(Shift(point.x-Left(),point.y-Top()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Relative movement of the controls group |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Shift(const int dx,const int dy)
|
||||
{
|
||||
//--- call of the method of the parent class
|
||||
if(!CWnd::Shift(dx,dy)) return(false);
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
//--- move the group item
|
||||
control.Shift(dx,dy);
|
||||
}
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set ID of control |
|
||||
//+------------------------------------------------------------------+
|
||||
long CWndContainer::Id(const long id)
|
||||
{
|
||||
//--- reserve ID for container
|
||||
long id_used=1;
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
id_used+=control.Id(id+id_used);
|
||||
}
|
||||
m_id=id;
|
||||
//--- return number of used IDs
|
||||
return(id_used);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Enables event handling by the group of controls |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Enable(void)
|
||||
{
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
control.Enable();
|
||||
}
|
||||
//--- call of the method of the parent class
|
||||
return(CWnd::Enable());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Disables event handling by the group of controls |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Disable(void)
|
||||
{
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
control.Disable();
|
||||
}
|
||||
//--- call of the method of the parent class
|
||||
return(CWnd::Disable());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the group of controls visible |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Show(void)
|
||||
{
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
control.Show();
|
||||
}
|
||||
//--- call of the method of the parent class
|
||||
return(CWnd::Show());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Makes the group of controls hidden |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Hide(void)
|
||||
{
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
control.Hide();
|
||||
}
|
||||
//--- call of the method of the parent class
|
||||
return(CWnd::Hide());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of resizing |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::OnResize()
|
||||
{
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
if(!control.Align(Rect()))
|
||||
return(false);
|
||||
}
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of activating the group of controls |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::OnActivate(void)
|
||||
{
|
||||
if(IS_ACTIVE)
|
||||
return(false);
|
||||
Activate();
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
control.Activate();
|
||||
}
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of deactivating the group of controls |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::OnDeactivate(void)
|
||||
{
|
||||
if(!IS_ACTIVE)
|
||||
return(false);
|
||||
Deactivate();
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
control.Deactivate();
|
||||
}
|
||||
//--- handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Save |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Save(const int file_handle)
|
||||
{
|
||||
bool result=true;
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
result&=control.Save(file_handle);
|
||||
}
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Load |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndContainer::Load(const int file_handle)
|
||||
{
|
||||
bool result=true;
|
||||
//--- loop by elements of group
|
||||
int total=m_controls.Total();
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
CWnd *control=Control(i);
|
||||
//--- check of pointer
|
||||
if(control==NULL)
|
||||
continue;
|
||||
result&=control.Load(file_handle);
|
||||
}
|
||||
//--- result
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,262 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| WndObj.mqh |
|
||||
//| Copyright 2000-2026, MetaQuotes Ltd. |
|
||||
//| www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Wnd.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CWndObj |
|
||||
//| Usage: base class to work with chart objects |
|
||||
//+------------------------------------------------------------------+
|
||||
class CWndObj : public CWnd
|
||||
{
|
||||
private:
|
||||
//--- flags of object
|
||||
bool m_undeletable; // "object is not deletable" flag
|
||||
bool m_unchangeable; // "object is not changeable" flag
|
||||
bool m_unmoveable; // "object is not movable" flag
|
||||
|
||||
protected:
|
||||
//--- parameters of the chart object
|
||||
string m_text; // object text
|
||||
color m_color; // object color
|
||||
color m_color_background; // object background color
|
||||
color m_color_border; // object border color
|
||||
string m_font; // object font
|
||||
int m_font_size; // object font size
|
||||
long m_zorder; // Z order
|
||||
|
||||
public:
|
||||
CWndObj(void);
|
||||
~CWndObj(void);
|
||||
//--- chart event handler
|
||||
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
|
||||
//--- set up the object
|
||||
string Text(void) const { return(m_text); }
|
||||
bool Text(const string value);
|
||||
color Color(void) const { return(m_color); }
|
||||
bool Color(const color value);
|
||||
color ColorBackground(void) const { return(m_color_background); }
|
||||
bool ColorBackground(const color value);
|
||||
color ColorBorder(void) const { return(m_color_border); }
|
||||
bool ColorBorder(const color value);
|
||||
string Font(void) const { return(m_font); }
|
||||
bool Font(const string value);
|
||||
int FontSize(void) const { return(m_font_size); }
|
||||
bool FontSize(const int value);
|
||||
long ZOrder(void) const { return(m_zorder); }
|
||||
bool ZOrder(const long value);
|
||||
|
||||
protected:
|
||||
//--- handlers of object events
|
||||
virtual bool OnObjectCreate(void);
|
||||
virtual bool OnObjectChange(void);
|
||||
virtual bool OnObjectDelete(void);
|
||||
virtual bool OnObjectDrag(void);
|
||||
//--- handlers of object settings
|
||||
virtual bool OnSetText(void) { return(true); }
|
||||
virtual bool OnSetColor(void) { return(true); }
|
||||
virtual bool OnSetColorBackground(void) { return(true); }
|
||||
virtual bool OnSetColorBorder(void) { return(true); }
|
||||
virtual bool OnSetFont(void) { return(true); }
|
||||
virtual bool OnSetFontSize(void) { return(true); }
|
||||
virtual bool OnSetZOrder(void) { return(true); }
|
||||
//--- internal event handlers
|
||||
virtual bool OnDestroy(void) { return(ObjectDelete(m_chart_id,m_name)); }
|
||||
virtual bool OnChange(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Common handler of chart events |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
|
||||
{
|
||||
if(m_name==sparam)
|
||||
{
|
||||
//--- object name and string parameters are equal
|
||||
//--- this means that event should be handled
|
||||
switch(id)
|
||||
{
|
||||
case CHARTEVENT_OBJECT_CREATE: return(OnObjectCreate());
|
||||
case CHARTEVENT_OBJECT_CHANGE: return(OnObjectChange());
|
||||
case CHARTEVENT_OBJECT_DELETE: return(OnObjectDelete());
|
||||
case CHARTEVENT_OBJECT_DRAG : return(OnObjectDrag());
|
||||
}
|
||||
}
|
||||
//--- event was not handled
|
||||
return(CWnd::OnEvent(id,lparam,dparam,sparam));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CWndObj::CWndObj(void) : m_color(clrNONE),
|
||||
m_color_background(clrNONE),
|
||||
m_color_border(clrNONE),
|
||||
m_font(CONTROLS_FONT_NAME),
|
||||
m_font_size(CONTROLS_FONT_SIZE),
|
||||
m_zorder(0),
|
||||
m_undeletable(true),
|
||||
m_unchangeable(true),
|
||||
m_unmoveable(true)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CWndObj::~CWndObj(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Text" parameter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::Text(const string value)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_text=value;
|
||||
//--- call virtual event handler
|
||||
return(OnSetText());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Color" parameter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::Color(const color value)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_color=value;
|
||||
//--- call virtual event handler
|
||||
return(OnSetColor());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Setting the "Background color" parameter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::ColorBackground(const color value)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_color_background=value;
|
||||
//--- call virtual event handler
|
||||
return(OnSetColorBackground());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Border color" parameter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::ColorBorder(const color value)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_color_border=value;
|
||||
//--- call virtual event handler
|
||||
return(OnSetColorBorder());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Font" parameter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::Font(const string value)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_font=value;
|
||||
//--- call virtual event handler
|
||||
return(OnSetFont());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Font size" parameter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::FontSize(const int value)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_font_size=value;
|
||||
//--- call virtual event handler
|
||||
return(OnSetFontSize());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the "Z order" parameter |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::ZOrder(const long value)
|
||||
{
|
||||
//--- save new value of parameter
|
||||
m_zorder=value;
|
||||
//--- call virtual event handler
|
||||
return(OnSetZOrder());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Object creation" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::OnObjectCreate(void)
|
||||
{
|
||||
//--- event is handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Object modification" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::OnObjectChange(void)
|
||||
{
|
||||
//--- if object is not changeable
|
||||
if(m_unchangeable)
|
||||
{
|
||||
//--- restore position
|
||||
if(!OnMove())
|
||||
return(false);
|
||||
//--- restore size
|
||||
if(!OnResize())
|
||||
return(false);
|
||||
//--- restore settings
|
||||
if(!OnChange())
|
||||
return(false);
|
||||
}
|
||||
//--- event is handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Object deletion" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::OnObjectDelete(void)
|
||||
{
|
||||
//--- if object is not deletable
|
||||
if(m_undeletable)
|
||||
{
|
||||
//--- restore the object
|
||||
if(!OnCreate())
|
||||
return(false);
|
||||
//--- restore settings
|
||||
if(!OnChange())
|
||||
return(false);
|
||||
//--- restore visibility
|
||||
return(IS_VISIBLE ? OnShow():OnHide());
|
||||
}
|
||||
//--- event is handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Handler of the "Object dragging" event |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::OnObjectDrag(void)
|
||||
{
|
||||
//--- if object is not movable
|
||||
if(m_unmoveable)
|
||||
{
|
||||
//--- restore position
|
||||
return(OnMove());
|
||||
}
|
||||
//--- event is handled
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set up the object |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CWndObj::OnChange(void)
|
||||
{
|
||||
//--- set up the chart object according to previously set parameters
|
||||
if(!OnSetText())
|
||||
return(false);
|
||||
if(!OnSetFont())
|
||||
return(false);
|
||||
if(!OnSetFontSize())
|
||||
return(false);
|
||||
if(!OnSetColor())
|
||||
return(false);
|
||||
if(!OnSetColorBackground())
|
||||
return(false);
|
||||
if(!OnSetColorBorder())
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 576 B |
Binary file not shown.
|
After Width: | Height: | Size: 576 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user