├── images
├── debug.png
├── main.png
├── explorer.png
└── options.png
├── src
├── BipEmulator.Proxy
│ ├── libbip.h
│ ├── ProxyLib.cpp
│ ├── BipEmulator.Proxy.vcxproj.filters
│ ├── calend.h
│ ├── BipEmulator.Proxy.vcxproj
│ └── calend.cpp
├── BipEmulator.Host
│ ├── App.config
│ ├── packages.config
│ ├── ResParam.cs
│ ├── GestureEnum.cs
│ ├── Properties
│ │ ├── Settings.settings
│ │ ├── Settings.Designer.cs
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ └── Resources.resx
│ ├── ColorIndexEnum.cs
│ ├── ColorArray.cs
│ ├── HrmData.cs
│ ├── LocaleEnum.cs
│ ├── Program.cs
│ ├── NaviData.cs
│ ├── DisplayNameAttribute.cs
│ ├── WatchScreen.Designer.cs
│ ├── ResFile.cs
│ ├── ColorSelectionForm.cs
│ ├── FunctionNames.cs
│ ├── LocalSettings.cs
│ ├── BitReader.cs
│ ├── FtFile.cs
│ ├── FtMaker.cs
│ ├── MainForm.resx
│ ├── WatchScreen.resx
│ ├── ColorSelectionForm.resx
│ ├── UnsafeBitmapContext.cs
│ ├── BipEmulator.Host.csproj
│ ├── WatchScreen.cs
│ ├── ResImage.cs
│ ├── ColorSelectionForm.Designer.cs
│ ├── SymbolSet.cs
│ └── MainForm.cs
└── BipEmulator.sln
├── .gitattributes
├── README.md
└── .gitignore
/images/debug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freebip/BipEmulator/HEAD/images/debug.png
--------------------------------------------------------------------------------
/images/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freebip/BipEmulator/HEAD/images/main.png
--------------------------------------------------------------------------------
/images/explorer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freebip/BipEmulator/HEAD/images/explorer.png
--------------------------------------------------------------------------------
/images/options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freebip/BipEmulator/HEAD/images/options.png
--------------------------------------------------------------------------------
/src/BipEmulator.Proxy/libbip.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freebip/BipEmulator/HEAD/src/BipEmulator.Proxy/libbip.h
--------------------------------------------------------------------------------
/src/BipEmulator.Proxy/ProxyLib.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freebip/BipEmulator/HEAD/src/BipEmulator.Proxy/ProxyLib.cpp
--------------------------------------------------------------------------------
/src/BipEmulator.Host/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/ResParam.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace BipEmulator.Host
4 | {
5 | [StructLayout(LayoutKind.Sequential, Pack = 0)]
6 | public struct ResParam
7 | {
8 | public short Width;
9 | public short Height;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/GestureEnum.cs:
--------------------------------------------------------------------------------
1 | namespace BipEmulator.Host
2 | {
3 | public enum GestureEnum
4 | {
5 | GESTURE_CLICK = 1,
6 | GESTURE_SWIPE_UP = 2,
7 | GESTURE_SWIPE_DOWN = 3,
8 | GESTURE_SWIPE_LEFT = 4,
9 | GESTURE_SWIPE_RIGHT = 5,
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/ColorIndexEnum.cs:
--------------------------------------------------------------------------------
1 | namespace BipEmulator.Host
2 | {
3 | public enum ColorIndexEnum
4 | {
5 | Black = 0,
6 | Blue = 1,
7 | Green = 2,
8 | Aqua = 3,
9 | Red = 4,
10 | Purple = 5,
11 | Yellow = 6,
12 | White = 7,
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/ColorArray.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 |
3 | namespace BipEmulator.Host
4 | {
5 | public struct ColorArray
6 | {
7 | public Color Black;
8 | public Color Red;
9 | public Color Green;
10 | public Color Blue;
11 | public Color Yellow;
12 | public Color Aqua;
13 | public Color Purple;
14 | public Color White;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/HrmData.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace BipEmulator.Host
4 | {
5 | [StructLayout(LayoutKind.Sequential, Pack = 0)]
6 | public struct HrmData
7 | {
8 | int t_start;
9 | public short last_hr;
10 | byte field_2;
11 | byte field_3;
12 | byte field_4;
13 | public byte heart_rate;
14 | public byte ret_code;
15 | byte field_5;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/LocaleEnum.cs:
--------------------------------------------------------------------------------
1 | namespace BipEmulator.Host
2 | {
3 | public enum LocaleEnum
4 | {
5 | [DisplayName("Русский (ru_RU)")]
6 | ru_RU = 1049,
7 | [DisplayName("U.S. English (en_US)")]
8 | en_US = 1033,
9 | [DisplayName("Italiano (it_IT)")]
10 | it_IT = 1040,
11 | [DisplayName("Español (es_ES)")]
12 | es_ES = 3082,
13 | [DisplayName("Français (fr_FR)")]
14 | fr_FR = 1036,
15 | [DisplayName("Deutsch (de_DE)")]
16 | de_DE = 1031,
17 | [DisplayName("Ελληνικά (el_GR)")]
18 | el_GR = 1032
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using System.Windows.Forms;
6 |
7 | namespace BipEmulator.Host
8 | {
9 | static class Program
10 | {
11 | ///
12 | /// Главная точка входа для приложения.
13 | ///
14 | [STAThread]
15 | static void Main()
16 | {
17 | Application.EnableVisualStyles();
18 | Application.SetCompatibleTextRenderingDefault(false);
19 | Application.Run(new MainForm());
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/NaviData.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace BipEmulator.Host
4 | {
5 | [StructLayout(LayoutKind.Sequential, Pack = 0)]
6 | public struct NaviData
7 | {
8 | public int ready; // Готовность данных: bit 0: давление ; bit 1: высота ; bit 2: широта ; bit 3: долгота
9 | public uint pressure; // значение давления в Паскалях
10 | public float altitude; // значение высоты в метрах
11 | public int latitude; // модуль значения долготы в градусах, умноженное на 3000000
12 | public int ns; // ns: 0-северное полушарие; 1-южное
13 | public int longitude; // модуль знаения долготы в градусах, умноженное на 3000000
14 | public int ew; // ew: 2-западное полушарие; 3-восточное;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace BipEmulator.Host.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/BipEmulator.Proxy/BipEmulator.Proxy.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Файлы заголовков
20 |
21 |
22 | Файлы заголовков
23 |
24 |
25 |
26 |
27 | Исходные файлы
28 |
29 |
30 | Исходные файлы
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // Общие сведения об этой сборке предоставляются следующим набором
6 | // набора атрибутов. Измените значения этих атрибутов для изменения сведений,
7 | // связанных со сборкой.
8 | [assembly: AssemblyTitle("BipEmulator.Host")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("BipEmulator.Host")]
13 | [assembly: AssemblyCopyright("Copyright © 2020")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми
18 | // для компонентов COM. Если необходимо обратиться к типу в этой сборке через
19 | // COM, следует установить атрибут ComVisible в TRUE для этого типа.
20 | [assembly: ComVisible(false)]
21 |
22 | // Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM
23 | [assembly: Guid("71dd5d93-2f61-47e9-a0a3-8d0d3bc685fd")]
24 |
25 | // Сведения о версии сборки состоят из указанных ниже четырех значений:
26 | //
27 | // Основной номер версии
28 | // Дополнительный номер версии
29 | // Номер сборки
30 | // Редакция
31 | //
32 | // Можно задать все значения или принять номера сборки и редакции по умолчанию
33 | // используя "*", как показано ниже:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/DisplayNameAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace BipEmulator.Host
4 | {
5 | [AttributeUsage(AttributeTargets.All)]
6 | public class DisplayNameAttribute : System.ComponentModel.DisplayNameAttribute
7 | {
8 | public DisplayNameAttribute(string name)
9 | {
10 | DisplayNameValue = name;
11 | }
12 |
13 | public string Name { get { return DisplayName; } }
14 |
15 | public static string GetName(Object o)
16 | {
17 | if (o == null) return String.Empty;
18 |
19 | var t = o.GetType();
20 | if (t.IsEnum)
21 | {
22 | var fi = t.GetFields();
23 | foreach (var fieldInfo in fi)
24 | {
25 | if (fieldInfo.Name == o.ToString())
26 | {
27 | var a = (DisplayNameAttribute)GetCustomAttribute(fieldInfo, typeof(DisplayNameAttribute));
28 | return a == null ? fieldInfo.Name : a.Name;
29 | }
30 | }
31 | }
32 | else
33 | {
34 | var a = (DisplayNameAttribute)GetCustomAttribute(t, typeof(DisplayNameAttribute));
35 | if (a != null)
36 | return a.Name;
37 |
38 | }
39 | return String.Empty;
40 | }
41 |
42 | public static string GetName(Type t)
43 | {
44 | if (t == null) return String.Empty;
45 |
46 | var a = (DisplayNameAttribute)GetCustomAttribute(t, typeof(DisplayNameAttribute));
47 | return a != null ? a.Name : String.Empty;
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/src/BipEmulator.Host/WatchScreen.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace BipEmulator.Host
2 | {
3 | partial class WatchScreen
4 | {
5 | ///
6 | /// Обязательная переменная конструктора.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Освободить все используемые ресурсы.
12 | ///
13 | /// истинно, если управляемый ресурс должен быть удален; иначе ложно.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Код, автоматически созданный конструктором компонентов
24 |
25 | ///
26 | /// Требуемый метод для поддержки конструктора — не изменяйте
27 | /// содержимое этого метода с помощью редактора кода.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.SuspendLayout();
32 | //
33 | // WatchScreen
34 | //
35 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
36 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
37 | this.MaximumSize = new System.Drawing.Size(176, 176);
38 | this.MinimumSize = new System.Drawing.Size(176, 176);
39 | this.Name = "WatchScreen";
40 | this.Size = new System.Drawing.Size(176, 176);
41 | this.ResumeLayout(false);
42 |
43 | }
44 |
45 | #endregion
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/ResFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 |
6 | namespace BipEmulator.Host
7 | {
8 | public class ResFile
9 | {
10 | const string SIGNATURE = "NERES";
11 |
12 | public byte Version { get; private set; }
13 | public List Resources { get; private set; }
14 |
15 | public static ResFile Load(string fileName)
16 | {
17 | var resFile = new ResFile();
18 | using (var br = new BinaryReader(File.OpenRead(fileName)))
19 | {
20 | var signature = Encoding.ASCII.GetString(br.ReadBytes(5));
21 | if (signature != SIGNATURE)
22 | throw new ArgumentException($"Unknown signature: {signature}");
23 | resFile.Version = br.ReadByte();
24 |
25 | br.BaseStream.Position = 0x20;
26 | var resCount = br.ReadUInt32();
27 |
28 | var offsetTable = new uint[resCount];
29 | for (var i = 0; i < resCount; i++)
30 | offsetTable[i] = br.ReadUInt32();
31 |
32 | var resourceFileOffset = br.BaseStream.Position;
33 | var fileLength = br.BaseStream.Length;
34 |
35 | resFile.Resources = new List();
36 | for (var i = 0; i < resCount; i++)
37 | {
38 | var offset = resourceFileOffset + offsetTable[i];
39 | var nextOffset = i + 1 < resCount ? resourceFileOffset + offsetTable[i+1] : fileLength;
40 | var resLength = nextOffset - offset;
41 | if (resLength < 0 || resLength > fileLength)
42 | throw new ArgumentException($"Format error. Offset: {offset}");
43 | resFile.Resources.Add(br.ReadBytes((int)resLength));
44 | }
45 | }
46 |
47 | return resFile;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/ColorSelectionForm.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using System.Windows.Forms;
3 |
4 | namespace BipEmulator.Host
5 | {
6 | public partial class ColorSelectionForm : Form
7 | {
8 | public ColorArray Colors { get; set; }
9 |
10 | public ColorSelectionForm(ColorArray colors)
11 | {
12 | InitializeComponent();
13 |
14 | Colors = colors;
15 |
16 | SetColor(lblBlack, Colors.Black);
17 | SetColor(lblRed, Colors.Red);
18 | SetColor(lblGreen, Colors.Green);
19 | SetColor(lblYellow, Colors.Yellow);
20 | SetColor(lblAqua, Colors.Aqua);
21 | SetColor(lblPurple,Colors.Purple);
22 | SetColor(lblWhite,Colors.White);
23 | SetColor(lblBlue,Colors.Blue);
24 | }
25 |
26 | private void SetColor(Label label, Color color)
27 | {
28 | label.BackColor = color;
29 | label.ForeColor = Color.FromArgb(~color.ToArgb());
30 | }
31 |
32 | private void ColorLabel_Click(object sender, System.EventArgs e)
33 | {
34 | var label = (Label)sender;
35 |
36 | var frm = new ColorDialog();
37 | frm.FullOpen = true;
38 | frm.Color = label.BackColor;
39 | if (frm.ShowDialog() == DialogResult.OK)
40 | {
41 | SetColor(label, frm.Color);
42 | }
43 | }
44 |
45 | private void btnOK_Click(object sender, System.EventArgs e)
46 | {
47 | Colors = new ColorArray
48 | {
49 | Black = lblBlack.BackColor,
50 | Red = lblRed.BackColor,
51 | Green = lblGreen.BackColor,
52 | Yellow = lblYellow.BackColor,
53 | Aqua = lblAqua.BackColor,
54 | Purple = lblPurple.BackColor,
55 | White = lblWhite.BackColor,
56 | Blue = lblBlue.BackColor
57 | };
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/FunctionNames.cs:
--------------------------------------------------------------------------------
1 | namespace BipEmulator.Host
2 | {
3 | public static class FunctionNames
4 | {
5 | public const string GET_HRM_STRUCT = "get_hrm_struct";
6 | public const string GET_LAST_HEARTRATE = "get_last_heartrate";
7 | public const string GET_NAVI_DATA = "get_navi_data";
8 | public const string GET_RES_PARAMS = "get_res_params";
9 | public const string GET_SELECTED_LOCALE = "get_selected_locale";
10 | public const string GET_TEXT_HEIGHT = "get_text_height";
11 | public const string DRAW_FILLED_RECT = "draw_filled_rect";
12 | public const string DRAW_FILLED_RECT_BG = "draw_filled_rect_bg";
13 | public const string DRAW_HORIZONTAL_LINE = "draw_horizontal_line";
14 | public const string DRAW_RECT = "draw_rect";
15 | public const string DRAW_VERTICAL_LINE = "draw_vertical_line";
16 | public const string IS_GPS_FIXED = "is_gps_fixed";
17 | public const string FILL_SCREEN_BG = "fill_screen_bg";
18 | public const string LOAD_FONT = "load_font";
19 | public const string LOG_PRINTF = "log_printf";
20 | public const string REG_MENU = "reg_menu";
21 | public const string REPAINT_SCREEN_LINES = "repaint_screen_lines";
22 | public const string READ_ELF_RES_BY_ID = "read_elf_res_by_id";
23 | public const string SET_BG_COLOR = "set_bg_color";
24 | public const string SET_FG_COLOR = "set_fg_color";
25 | public const string SET_UPDATE_PERIOD = "set_update_period";
26 | public const string SHOW_BIG_DIGITS = "show_big_digit";
27 | public const string SHOW_ELF_RES_BY_ID = "show_elf_res_by_id";
28 | public const string SHOW_RES_BY_ID = "show_res_by_id";
29 | public const string TEXT_OUT = "text_out";
30 | public const string TEXT_OUT_CENTER = "text_out_center";
31 | public const string TEXT_WIDTH = "text_width";
32 | public const string VIBRATE = "vibrate";
33 |
34 | // special emulator functions
35 | public const string SHARED_MEMORY_ENABLED = "__shared_memory_enabled__";
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/LocalSettings.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Drawing;
3 | using System.IO;
4 |
5 | namespace BipEmulator.Host
6 | {
7 | [System.Serializable]
8 | public class LocalSettings
9 | {
10 | const string SettingsFilename = "settings.json";
11 |
12 | public int HeartRate = 70;
13 | public bool HeartRateMeasurementCompleted = false;
14 | public double Latitude = 37.401583;
15 | public double Longitude = -116.867808;
16 | public double Altitude = 1592.12;
17 | public bool GeoLocationMeasurementCompleted = false;
18 | public int Pressure = 760;
19 | public bool PressureMeasurementCompleted = false;
20 | public LocaleEnum Locale = LocaleEnum.ru_RU;
21 | public int MaxDistanceClick = 5;
22 |
23 | public ColorArray Colors = new ColorArray
24 | {
25 | Black = Color.FromArgb(56, 56, 56),
26 | Red = Color.FromArgb(187, 113, 136),
27 | Green = Color.FromArgb(89, 181, 132),
28 | Blue = Color.FromArgb(28, 110, 194),
29 | Yellow = Color.FromArgb(221, 214, 133),
30 | Aqua = Color.FromArgb(70, 198, 207),
31 | Purple = Color.FromArgb(173, 147, 208),
32 | White = Color.FromArgb(220, 220, 220)
33 | };
34 |
35 | public string FontFilename = "Presets//Mili_chaohu.ft.latin";
36 | public string SystemResourceFilename = "Presets//Mili_chaohu.res.latin";
37 | public string UserResourceFilename = "assert.res";
38 |
39 | public static LocalSettings Load()
40 | {
41 | try
42 | {
43 | return JsonConvert.DeserializeObject(File.ReadAllText(SettingsFilename));
44 | }
45 | catch
46 | {
47 | return new LocalSettings();
48 | }
49 | }
50 |
51 | public void Save()
52 | {
53 | try
54 | {
55 | File.WriteAllText(SettingsFilename, JsonConvert.SerializeObject(this));
56 | }
57 | catch
58 | {
59 | }
60 | }
61 |
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/BitReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace BipEmulator.Host
5 | {
6 | public class BitReader
7 | {
8 | private readonly byte[] _masks = { 128, 192, 224, 240, 248, 252, 254, 255 };
9 | private readonly Stream _stream;
10 |
11 | private int _bitsRemaining;
12 | private int _currentByte;
13 | private bool _isDataPresent = true;
14 |
15 | public BitReader(Stream stream)
16 | {
17 | _stream = stream;
18 | }
19 |
20 | public BitReader(byte[] arrayBytes)
21 | {
22 | _stream = new MemoryStream(arrayBytes);
23 | }
24 |
25 | public bool IsDataPresent
26 | {
27 | get
28 | {
29 | if (_bitsRemaining > 0) return true;
30 |
31 | TryReadNext();
32 | return _isDataPresent;
33 | }
34 | }
35 |
36 | public bool ReadBit()
37 | {
38 | return ReadBits(1) != 0;
39 | }
40 |
41 | public byte ReadByte()
42 | {
43 | return (byte)ReadBits(8);
44 | }
45 |
46 | public ulong ReadBits(int length)
47 | {
48 | ulong data = 0;
49 | while (length > 0)
50 | {
51 | if (_bitsRemaining == 0 && _isDataPresent)
52 | TryReadNext();
53 |
54 | var dataLength = Math.Min(length, _bitsRemaining);
55 |
56 | var currentData = (ulong)(_currentByte & _masks[dataLength - 1]);
57 | if (length > 8)
58 | currentData = currentData << (length - 8);
59 | else
60 | currentData = currentData >> (8 - length);
61 | data = data | currentData;
62 |
63 | _currentByte = _currentByte << dataLength;
64 | length -= dataLength;
65 | _bitsRemaining -= dataLength;
66 | }
67 | return data;
68 | }
69 |
70 | private void TryReadNext()
71 | {
72 | _currentByte = _stream.ReadByte();
73 | _isDataPresent = _currentByte > -1;
74 | if (_isDataPresent)
75 | _bitsRemaining = 8;
76 | }
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/FtFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.IO;
4 | using System.Text;
5 |
6 | namespace BipEmulator.Host
7 | {
8 | public class FtFile
9 | {
10 | const string SIGNATURE = "NEZK";
11 | public byte Version { get; private set; }
12 | public Hashtable Letters { get; } = new Hashtable();
13 |
14 | public static FtFile Load(string filename)
15 | {
16 | var ftFile = new FtFile();
17 |
18 | using (var br = new BinaryReader(File.OpenRead(filename)))
19 | {
20 | var signature = Encoding.ASCII.GetString(br.ReadBytes(4));
21 | if (signature != SIGNATURE)
22 | throw new ArgumentException($"Wrong signature: {signature}");
23 |
24 | ftFile.Version = br.ReadByte();
25 | br.BaseStream.Position = 0x20;
26 | int letterBlockCount = br.ReadUInt16();
27 | var hashLen = ftFile.Version == 8 ? 1 : 2;
28 |
29 | for (var block = 0; block < 6 * letterBlockCount; block += 6)
30 | {
31 | int letterCodeStart = br.ReadUInt16();
32 | int letterCodeStop = br.ReadUInt16();
33 | int lettersOffset = br.ReadUInt16();
34 |
35 | var saveOffset = br.BaseStream.Position;
36 | // устанавливаем смещение дял чтения блока данных набора символов
37 | // с кодами от letterCodeStart до letterCodeStop
38 | br.BaseStream.Position = 6 * letterBlockCount + 0x22 + (34 - hashLen) * lettersOffset;
39 |
40 | for (var l = letterCodeStart; l <= letterCodeStop; l++)
41 | {
42 | // 33 байт блок
43 | if (ftFile.Version == 8)
44 | {
45 | ftFile.Letters.Add(l, br.ReadBytes(32));
46 | // hash???
47 | br.ReadByte();
48 | }
49 | // 32 байт блок
50 | else
51 | {
52 | ftFile.Letters.Add(l, br.ReadBytes(30));
53 | // hash???
54 | br.ReadUInt16();
55 | }
56 | }
57 | br.BaseStream.Position = saveOffset;
58 | }
59 | }
60 |
61 | return ftFile;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/src/BipEmulator.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30320.27
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BipEmulator.Host", "BipEmulator.Host\BipEmulator.Host.csproj", "{71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BipEmulator.Proxy", "BipEmulator.Proxy\BipEmulator.Proxy.vcxproj", "{D2090F65-51DB-4643-8E60-25AFF97321AF}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|x64 = Debug|x64
14 | Debug|x86 = Debug|x86
15 | Release|Any CPU = Release|Any CPU
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Debug|x64.ActiveCfg = Debug|Any CPU
23 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Debug|x64.Build.0 = Debug|Any CPU
24 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Debug|x86.ActiveCfg = Debug|Any CPU
25 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Debug|x86.Build.0 = Debug|Any CPU
26 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Release|x64.ActiveCfg = Release|Any CPU
29 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Release|x64.Build.0 = Release|Any CPU
30 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Release|x86.ActiveCfg = Release|Any CPU
31 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}.Release|x86.Build.0 = Release|Any CPU
32 | {D2090F65-51DB-4643-8E60-25AFF97321AF}.Debug|Any CPU.ActiveCfg = Debug|Win32
33 | {D2090F65-51DB-4643-8E60-25AFF97321AF}.Debug|x64.ActiveCfg = Debug|x64
34 | {D2090F65-51DB-4643-8E60-25AFF97321AF}.Debug|x64.Build.0 = Debug|x64
35 | {D2090F65-51DB-4643-8E60-25AFF97321AF}.Debug|x86.ActiveCfg = Debug|Win32
36 | {D2090F65-51DB-4643-8E60-25AFF97321AF}.Debug|x86.Build.0 = Debug|Win32
37 | {D2090F65-51DB-4643-8E60-25AFF97321AF}.Release|Any CPU.ActiveCfg = Release|Win32
38 | {D2090F65-51DB-4643-8E60-25AFF97321AF}.Release|x64.ActiveCfg = Release|x64
39 | {D2090F65-51DB-4643-8E60-25AFF97321AF}.Release|x64.Build.0 = Release|x64
40 | {D2090F65-51DB-4643-8E60-25AFF97321AF}.Release|x86.ActiveCfg = Release|Win32
41 | {D2090F65-51DB-4643-8E60-25AFF97321AF}.Release|x86.Build.0 = Release|Win32
42 | EndGlobalSection
43 | GlobalSection(SolutionProperties) = preSolution
44 | HideSolutionNode = FALSE
45 | EndGlobalSection
46 | GlobalSection(ExtensibilityGlobals) = postSolution
47 | SolutionGuid = {FD4270FB-74B3-4190-BBB6-EB647469ADA1}
48 | EndGlobalSection
49 | EndGlobal
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Bip Emulator
2 |
3 | Эмулятор окружения BipOS для часов Amazfit Bip
4 |
5 | ## Назначение
6 |
7 | Написание и отладка приложений для часов Amazfit Bip под управлением мода BipOS (0.5.X)
8 | в среде Microsoft Visual Studio 2019
9 |
10 | 
11 |
12 | ## Описание
13 |
14 | Эмулятор состоит из двух модулей: Host и Proxy.
15 | Proxy обрабатывает вызовы функций библиотеки Libbip поступающие от программы, работа которой
16 | происходит в эмуляторе. Часть этих вызовов модуль Proxy обрабатывает сам, часть перенаправляет
17 | модулю Host.
18 | На модуль Host возложены более высокоуровневые задачи:
19 | * Обработка вызовов графических функций и отображение результата их работы на пользовательском интерфейсе.
20 | * Обработка ввода команд пользователя, специфичных для эмулируемого устройства.
21 | * Эмуляция специфичных данных эмулируемого устройства (Давление, Геолокационные координаты и пр.)
22 | * Отображение отладочных данных программы
23 |
24 | ## Изображения
25 |
26 |
27 | 
28 |
29 | 
30 |
31 |
32 | ## Использование
33 |
34 | * Добавьте исходный код в Proxy модуль.
35 | * Откомпилируйте Proxy модуль.
36 | * Запустите Host модуль.
37 | * Завершите исполнение эмулятора
38 | * Исправьте исходный код
39 | * Повторять со второго пункта бесконечное кол-во раз
40 |
41 | ## Особенности использования
42 |
43 | В данном проекте используется связка C# <-> CLI/C++.
44 | Поэтому добавляемые исходные файлы должны иметь расширение .cpp (не относится к заголовочным файлам)
45 |
46 | ***Но*** код должен быть написан в соответствии со стандартами чистого Си т.к. в последствии его предстоит
47 | собирать с помощью gnu toolchain под Си.
48 |
49 | Так как при использовании расширения .cpp мы переводим исходные файлы в разряд C++, то на код накладываются
50 | более суровые ограничения (например, в плане приведения типов по-умолчанию)
51 |
52 | Было так:
53 | ```
54 | void* get_ptr_temp_buf_2();
55 | struct calend_** calend_p = get_ptr_temp_buf_2();
56 | ```
57 | Надо так:
58 | ```
59 | void* get_ptr_temp_buf_2();
60 | struct calend_** calend_p = (struct calend_**) get_ptr_temp_buf_2();
61 | ```
62 |
63 | Proxy модуль является динамически линкуемой библиотекой (.dll), от которой зависит компиляция Host модуля.
64 | Поэтому после всех изменений принудительно откомпилируйте Proxy модуль, а после этого запускайте программу.
65 |
66 | После первого запуска необходимо на закладке Options указать файл стандартных ресурсов и
67 | файл шрифтов. Иначе Календарь не будет отображаться, т.к. шрифты ему взять не откуда.
68 |
69 |
70 | ## Пример
71 |
72 | Для демонстрации возможностей эмулятора в него добавлено приложение [Календарь](https://github.com/MNVolkov/Calend)
73 |
74 | 
75 |
76 | ## Примечание
77 |
78 | У проекта WIP статус. Обработка части функций библиотеки Libbip не реализована.
79 |
80 |
81 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // Этот код создан программным средством.
4 | // Версия среды выполнения: 4.0.30319.42000
5 | //
6 | // Изменения в этом файле могут привести к неправильному поведению и будут утрачены, если
7 | // код создан повторно.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace BipEmulator.Host.Properties
12 | {
13 |
14 |
15 | ///
16 | /// Класс ресурсов со строгим типом для поиска локализованных строк и пр.
17 | ///
18 | // Этот класс был автоматически создан при помощи StronglyTypedResourceBuilder
19 | // класс с помощью таких средств, как ResGen или Visual Studio.
20 | // Для добавления или удаления члена измените файл .ResX, а затем перезапустите ResGen
21 | // с параметром /str или заново постройте свой VS-проект.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Возврат кэшированного экземпляра ResourceManager, используемого этим классом.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BipEmulator.Host.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Переопределяет свойство CurrentUICulture текущего потока для всех
56 | /// подстановки ресурсов с помощью этого класса ресурсов со строгим типом.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/BipEmulator.Proxy/calend.h:
--------------------------------------------------------------------------------
1 | /*
2 | (С) Волков Максим 2019 ( mr-volkov+bip@yandex.ru )
3 | Календарь для Amazfit Bip
4 |
5 | */
6 | #ifndef __CALEND_H__
7 | #define __CALEND_H__
8 |
9 | #include "libbip.h"
10 |
11 | // Значения цветовой схемы
12 | #define CALEND_COLOR_BG 0 // фон календаря
13 | #define CALEND_COLOR_MONTH 1 // цвет названия текущего месяца
14 | #define CALEND_COLOR_YEAR 2 // цвет текущего года
15 | #define CALEND_COLOR_WORK_NAME 3 // цвет названий дней будни
16 | #define CALEND_COLOR_HOLY_NAME_BG 4 // фон названий дней выходные
17 | #define CALEND_COLOR_HOLY_NAME_FG 5 // цвет названий дней выходные
18 | #define CALEND_COLOR_SEPAR 6 // цвет разделителей календаря
19 | #define CALEND_COLOR_NOT_CUR_WORK 7 // цвет чисел НЕ текущего месяца будни
20 | #define CALEND_COLOR_NOT_CUR_HOLY_BG 8 // фон чисел НЕ текущего месяца выходные
21 | #define CALEND_COLOR_NOT_CUR_HOLY_FG 9 // цвет чисел НЕ текущего месяца выходные
22 | #define CALEND_COLOR_CUR_WORK 10 // цвет чисел текущего месяца будни
23 | #define CALEND_COLOR_CUR_HOLY_BG 11 // фон чисел текущего месяца выходные
24 | #define CALEND_COLOR_CUR_HOLY_FG 12 // цвет чисел текущего месяца выходные
25 | #define CALEND_COLOR_TODAY_BG 13 // цвет чисел текущего дня
26 | #define CALEND_COLOR_TODAY_FG 14 // фон чисел текущего дня
27 |
28 | // количество цыетовых схем
29 | #define COLOR_SCHEME_COUNT 5
30 |
31 | // смещение адреса для хранения настроек календаря
32 | #define OPT_OFFSET_CALEND_OPT 0
33 |
34 | #if FW_VERSION==latin_1_1_5_12 || FW_VERSION==latin_1_1_5_36
35 | // параметры рисования цифр календаря
36 | // строка: от 7 до 169 = 162рх в ширину 7 чисел по 24рх на число 7+(24)*6+22+3
37 | // строки: от 57 до 174 = 117рх в высоту 6 строк по 22рх на строку 1+(22)*5+22
38 |
39 | #define CALEND_Y_BASE 30 // базовая высота начала отрисовки календаря
40 | //#define CALEND_NAME_HEIGHT 19 // высота строки названий дней недели
41 | //#define CALEND_DAYS_Y_BASE CALEND_Y_BASE+1+V_MARGIN+CALEND_NAME_HEIGHT+V_MARGIN+1 // высота базы чисел месяца
42 | #define WIDTH 24 // ширина цифр числа
43 | #define HEIGHT 19 // высота цифр числа
44 | #define V_SPACE 0 // вертикальный отступ между строками чисел
45 | #define H_SPACE 0 // горизонтальный отступ между колонками чисел
46 | #define H_MARGIN 4 // горизонтальный отступ от края экрана
47 | #define V_MARGIN 1 // вертикальный отступ от заголовка (базы)
48 |
49 | #elif FW_VERSION==not_latin_1_1_2_05
50 | // параметры рисования цифр календаря
51 | // строка: от 7 до 169 = 162рх в ширину 7 чисел по 24рх на число 7+(24)*6+24+3
52 | // строки: от 57 до 174 = 117рх в высоту 6 строк по 22рх на строку 1+(22)*5+20
53 |
54 | #define CALEND_Y_BASE 25 // базовая высота начала отрисовки календаря
55 | //#define CALEND_NAME_HEIGHT FONT_HEIGHT+2 // высота строки названий дней недели
56 | //#define CALEND_DAYS_Y_BASE CALEND_Y_BASE+1+V_MARGIN+CALEND_NAME_HEIGHT+V_MARGIN+1 // высота базы чисел месяца 56
57 | #define WIDTH 24 // ширина цифр числа
58 | #define HEIGHT 20 // высота цифр числа
59 | #define V_SPACE 0 // вертикальный отступ между строками чисел
60 | #define H_SPACE 0 // горизонтальный отступ между колонками чисел
61 | #define H_MARGIN 4 // горизонтальный отступ от края экрана
62 | #define V_MARGIN 1 // вертикальный отступ от заголовка (базы)
63 | #endif
64 |
65 |
66 | #define INACTIVITY_PERIOD 30000 // время по прошествии которого выходим
67 |
68 | // сохраняемые опции календаря
69 | struct calend_opt_ {
70 | unsigned char color_scheme; // цветовая схема
71 | };
72 |
73 | // текущие данные просматриваемого/редактируемого календаря
74 | struct calend_ {
75 | Elf_proc_* proc; // указатель на данные запущенного процесса
76 | void* ret_f; // адрес функции возврата
77 | unsigned char color_scheme; // цветовая схема
78 | // отображаемый месяц
79 | unsigned int day; // день
80 | unsigned int month; // месяц
81 | unsigned int year; // год
82 | };
83 |
84 |
85 | void show_calend_screen (void *return_screen);
86 | void key_press_calend_screen();
87 | int dispatch_calend_screen (void *param);
88 | void calend_screen_job();
89 |
90 | void draw_month(unsigned int day, unsigned int month, unsigned int year);
91 | unsigned char wday(unsigned int day,unsigned int month,unsigned int year);
92 | unsigned char isLeapYear(unsigned int year);
93 |
94 | #endif
--------------------------------------------------------------------------------
/src/BipEmulator.Host/FtMaker.cs:
--------------------------------------------------------------------------------
1 | using FastBitmapLib;
2 | using System;
3 | using System.Drawing;
4 |
5 | namespace BipEmulator.Host
6 | {
7 | public class FtMaker
8 | {
9 | const int EMPTY_LETTER_WIDTH = 9;
10 | const int LETTER_SPACING = 2;
11 |
12 | private FtFile _ftFile;
13 | public FtMaker(FtFile ftFile)
14 | {
15 | _ftFile = ftFile;
16 | }
17 |
18 | public Bitmap GetImage(string text)
19 | {
20 | var bmp = new Bitmap(GetTextWidth(text), GetTextHeight());
21 | TextOutCenter(bmp, text, 0, 0, Color.White, Color.Black);
22 | return bmp;
23 | }
24 |
25 | private void SetPixel(FastBitmap fbmp, int x, int y, Color color)
26 | {
27 | if (x < 0 || y < 0 || x >= fbmp.Width || y >= fbmp.Height)
28 | return;
29 | fbmp.SetPixel(x, y, color);
30 | }
31 |
32 | public void TextOutCenter(Bitmap bmp, string text, int x, int y, Color fgColor, Color bgColor, bool bgTransparent = false)
33 | {
34 | var h = GetTextHeight();
35 | var w = GetTextWidth(text);
36 | TextOut(bmp, text, x - w / 2, y, fgColor, bgColor, bgTransparent);
37 | }
38 |
39 |
40 | public void TextOut(Bitmap bmp, string text, int x, int y, Color fgColor, Color bgColor, bool bgTransparent = false)
41 | {
42 | var fbmp = new FastBitmap(bmp);
43 | fbmp.Lock();
44 | var xCurrent = x;
45 |
46 | for (var i = 0; i < text.Length; i++)
47 | {
48 | var key = (int)text[i];
49 | var letterWidth = GetLetterWidth(text[i]);
50 |
51 | if (_ftFile.Letters.ContainsKey(key))
52 | {
53 | var data = (byte[])_ftFile.Letters[key];
54 | for (var j = 0; j < data.Length / 2; j++)
55 | {
56 | var line = Swap(BitConverter.ToUInt16(data, 2 * j));
57 |
58 | for (var k = 0; k < letterWidth; k++)
59 | {
60 | if ((line & 0x8000) != 0)
61 | SetPixel(fbmp, xCurrent + k, y + j, fgColor);
62 | else if (!bgTransparent)
63 | SetPixel(fbmp, xCurrent + k, y + j, bgColor);
64 | line = (ushort)(line << 1);
65 | }
66 |
67 | // для пропорционального шрифта добавляем межбуквенный интервал
68 | if (!bgTransparent && _ftFile.Version == 8)
69 | {
70 | for (var k = 0; k < LETTER_SPACING; k++)
71 | {
72 | SetPixel(fbmp, xCurrent + letterWidth + k, y + j, bgColor);
73 | }
74 | }
75 | }
76 | }
77 | else
78 | {
79 | if (!bgTransparent)
80 | {
81 | for (var j = 0; j < GetTextHeight(); j++)
82 | for (var k = 0; k < EMPTY_LETTER_WIDTH + LETTER_SPACING; k++)
83 | SetPixel(fbmp, xCurrent + k, y + j, bgColor);
84 | }
85 | }
86 | xCurrent += letterWidth + (_ftFile.Version == 8 ? LETTER_SPACING : 0);
87 | }
88 | fbmp.Unlock();
89 | }
90 |
91 | private ushort Swap(ushort value)
92 | {
93 | return (ushort)((value >> 8) | (value << 8));
94 | }
95 |
96 | private int GetLetterWidth(char letter)
97 | {
98 | if (_ftFile.Version == 9)
99 | return 9;
100 |
101 | int width = 0;
102 | if (_ftFile.Letters.ContainsKey((int)letter))
103 | {
104 | var data = (byte[])_ftFile.Letters[(int)letter];
105 | var maxLen = 0;
106 | for (var j = 0; j < data.Length / 2; j++)
107 | {
108 | var line = Swap(BitConverter.ToUInt16(data, 2 * j));
109 | var count = 16;
110 | while (count > 0)
111 | {
112 | if ((line & 1) != 0)
113 | break;
114 |
115 | line = (ushort)(line >> 1);
116 | count--;
117 |
118 | }
119 | maxLen = maxLen > count ? maxLen : count;
120 | }
121 | width = maxLen == 0 ? EMPTY_LETTER_WIDTH : maxLen;
122 | }
123 | else
124 | {
125 | width = EMPTY_LETTER_WIDTH;
126 | }
127 | return width;
128 | }
129 |
130 | public int GetTextWidth(string text)
131 | {
132 | if (_ftFile.Version == 9)
133 | return text.Length * 9;
134 |
135 | var width = 0;
136 | for (var i = 0; i < text.Length; i++)
137 | {
138 | width += GetLetterWidth(text[i]) + LETTER_SPACING;
139 | }
140 |
141 | return width;
142 | }
143 |
144 | public int GetTextHeight()
145 | {
146 | return _ftFile.Version == 8 ? 16 : 15;
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/MainForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/WatchScreen.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/ColorSelectionForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/UnsafeBitmapContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using System.Drawing.Imaging;
4 | using System.IO;
5 |
6 | namespace BipEmulator.Host
7 | {
8 | public static class ImageExtensions
9 | {
10 | public static UnsafeBitmapContext CreateUnsafeContext(this Image image)
11 | {
12 | return new UnsafeBitmapContext(image);
13 | }
14 | }
15 |
16 | ///
17 | /// Provides quick but unsafe access to a bitmap's bits.
18 | /// ALWAYS ALWAYS ALWAYS wire this in a using block.
19 | /// DO NOT EVER access the bitmap directly while in this unsafe context.
20 | ///
21 | public sealed unsafe class UnsafeBitmapContext : IDisposable
22 | {
23 | private Stream _originalStream;
24 | private Bitmap _bitmap;
25 | private BitmapData _lockData;
26 | private Byte* _ptrBase;
27 | private int _pixelWidth;
28 |
29 | public int Width { get; private set; }
30 | public int Height { get; private set; }
31 |
32 | ///
33 | /// Provides quick but unsafe access to a bitmap's bits.
34 | /// ALWAYS ALWAYS ALWAYS wire this in a using block.
35 | /// DO NOT EVER access the bitmap directly while in this unsafe context.
36 | ///
37 | /// The bitmap to access
38 | public UnsafeBitmapContext(Bitmap bitmap)
39 | {
40 | _bitmap = bitmap;
41 | LockBits();
42 | }
43 |
44 | ///
45 | /// Provides quick but unsafe access to a bitmap's bits.
46 | /// ALWAYS ALWAYS ALWAYS wire this in a using block.
47 | /// DO NOT EVER access the bitmap directly while in this unsafe context.
48 | ///
49 | /// The bitmap to access
50 | public UnsafeBitmapContext(Image image)
51 | {
52 | if (!(image is Bitmap))
53 | {
54 | throw new ArgumentException("Image must be convertable to a bitmap.");
55 | }
56 | _bitmap = (Bitmap)image;
57 | LockBits();
58 | }
59 |
60 | ///
61 | /// Provides quick but unsafe access to a bitmap's bits.
62 | /// The stream will be updated upon disposal.
63 | /// ALWAYS ALWAYS ALWAYS wire this in a using block.
64 | /// DO NOT EVER access the bitmap directly while in this unsafe context.
65 | ///
66 | /// The stream to read and write to.
67 | public UnsafeBitmapContext(Stream stream)
68 | {
69 | try
70 | {
71 | _originalStream = stream;
72 | stream.Position = 0;
73 | _bitmap = (Bitmap)Image.FromStream(stream);
74 | }
75 | catch { throw new ArgumentException("Stream did not contain a valid image format."); }
76 | LockBits();
77 | }
78 |
79 | private void LockBits()
80 | {
81 | Width = _bitmap.Width;
82 | Height = _bitmap.Height;
83 | _pixelWidth = sizeof(Pixel);
84 | _lockData = _bitmap.LockBits(new Rectangle(0, 0, _bitmap.Width, _bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
85 | _ptrBase = (Byte*)_lockData.Scan0.ToPointer();
86 | }
87 |
88 | public void Dispose()
89 | {
90 | _bitmap.UnlockBits(_lockData);
91 | _lockData = null;
92 | if (_originalStream != null)
93 | {
94 | _originalStream.SetLength(0);
95 | _originalStream.Position = 0;
96 | _bitmap.Save(_originalStream, _bitmap.RawFormat);
97 | _bitmap.Dispose();
98 | _originalStream.Position = 0;
99 | }
100 | _originalStream = null;
101 | _bitmap = null;
102 | }
103 |
104 | ///
105 | /// Access a pixel from the bitmap's memory (slower than GetRawPixel)
106 | ///
107 | public Color GetPixel(int x, int y)
108 | {
109 | var pixel = GetRawPixel(x, y);
110 | return Color.FromArgb(pixel.Alpha, pixel.Red, pixel.Green, pixel.Blue);
111 | }
112 |
113 | ///
114 | /// Access a pixel from the bitmap's memory (faster than GetPixel)
115 | ///
116 | public Pixel GetRawPixel(int x, int y)
117 | {
118 | return *Pointer(x, y);
119 | }
120 |
121 | ///
122 | /// Replace a pixel in the bitmap's memory (slower than by bytes)
123 | ///
124 | public void SetPixel(int x, int y, Color color)
125 | {
126 | SetPixel(x, y, color.A, color.R, color.G, color.B);
127 | }
128 |
129 | ///
130 | /// Replace a pixel in the bitmap's memory (faster than by Color)
131 | ///
132 | public void SetPixel(int x, int y, byte alpha, byte red, byte green, byte blue)
133 | {
134 | var pixel = Pointer(x, y);
135 | (*pixel).Alpha = alpha;
136 | (*pixel).Red = red;
137 | (*pixel).Green = green;
138 | (*pixel).Blue = blue;
139 | }
140 |
141 | private Pixel* Pointer(int x, int y)
142 | {
143 | if (x >= Width || x < 0 || y >= Height || y < 0)
144 | {
145 | Dispose();
146 | throw new ArgumentException("The X and Y parameters must be within the scope of the image pixel ranges.");
147 | }
148 | return (Pixel*)(_ptrBase + y * _lockData.Stride + x * _pixelWidth);
149 | }
150 |
151 | ///
152 | /// Represents raw pixel data.
153 | ///
154 | public struct Pixel
155 | {
156 | public byte Blue;
157 | public byte Green;
158 | public byte Red;
159 | public byte Alpha;
160 | }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/BipEmulator.Host.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {71DD5D93-2F61-47E9-A0A3-8D0D3BC685FD}
8 | WinExe
9 | BipEmulator.Host
10 | BipEmulator.Host
11 | v4.6.1
12 | 512
13 | true
14 | true
15 |
16 |
17 | x86
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | true
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | true
36 |
37 |
38 |
39 | ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
40 |
41 |
42 |
43 |
44 | ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | Form
63 |
64 |
65 | ColorSelectionForm.cs
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | Form
83 |
84 |
85 | MainForm.cs
86 |
87 |
88 |
89 |
90 | UserControl
91 |
92 |
93 | WatchScreen.cs
94 |
95 |
96 | ColorSelectionForm.cs
97 |
98 |
99 | MainForm.cs
100 |
101 |
102 | ResXFileCodeGenerator
103 | Resources.Designer.cs
104 | Designer
105 |
106 |
107 | True
108 | Resources.resx
109 |
110 |
111 | WatchScreen.cs
112 |
113 |
114 |
115 | SettingsSingleFileGenerator
116 | Settings.Designer.cs
117 |
118 |
119 | True
120 | Settings.settings
121 | True
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | {d2090f65-51db-4643-8e60-25aff97321af}
130 | BipEmulator.Proxy
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/src/BipEmulator.Proxy/BipEmulator.Proxy.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | {D2090F65-51DB-4643-8E60-25AFF97321AF}
24 | v4.6.1
25 | ManagedCProj
26 | BipEmulatorProxy
27 | 10.0
28 |
29 |
30 |
31 | DynamicLibrary
32 | true
33 | v142
34 | true
35 | Unicode
36 |
37 |
38 | DynamicLibrary
39 | false
40 | v142
41 | true
42 | Unicode
43 |
44 |
45 | DynamicLibrary
46 | true
47 | v142
48 | true
49 | Unicode
50 |
51 |
52 | DynamicLibrary
53 | false
54 | v142
55 | true
56 | Unicode
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | NotUsing
80 |
81 |
82 | Level3
83 | WIN32;_DEBUG;%(PreprocessorDefinitions)
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | Use
92 | pch.h
93 | Level3
94 | _DEBUG;%(PreprocessorDefinitions)
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | NotUsing
103 |
104 |
105 | Level3
106 | WIN32;NDEBUG;%(PreprocessorDefinitions)
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | Use
115 | pch.h
116 | Level3
117 | NDEBUG;%(PreprocessorDefinitions)
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | [Aa][Rr][Mm]/
24 | [Aa][Rr][Mm]64/
25 | bld/
26 | [Bb]in/
27 | [Oo]bj/
28 | [Ll]og/
29 |
30 | # Visual Studio 2015/2017 cache/options directory
31 | .vs/
32 | # Uncomment if you have tasks that create the project's static files in wwwroot
33 | #wwwroot/
34 |
35 | # Visual Studio 2017 auto generated files
36 | Generated\ Files/
37 |
38 | # MSTest test Results
39 | [Tt]est[Rr]esult*/
40 | [Bb]uild[Ll]og.*
41 |
42 | # NUNIT
43 | *.VisualState.xml
44 | TestResult.xml
45 |
46 | # Build Results of an ATL Project
47 | [Dd]ebugPS/
48 | [Rr]eleasePS/
49 | dlldata.c
50 |
51 | # Benchmark Results
52 | BenchmarkDotNet.Artifacts/
53 |
54 | # .NET Core
55 | project.lock.json
56 | project.fragment.lock.json
57 | artifacts/
58 |
59 | # StyleCop
60 | StyleCopReport.xml
61 |
62 | # Files built by Visual Studio
63 | *_i.c
64 | *_p.c
65 | *_h.h
66 | *.ilk
67 | *.meta
68 | *.obj
69 | *.iobj
70 | *.pch
71 | *.pdb
72 | *.ipdb
73 | *.pgc
74 | *.pgd
75 | *.rsp
76 | *.sbr
77 | *.tlb
78 | *.tli
79 | *.tlh
80 | *.tmp
81 | *.tmp_proj
82 | *_wpftmp.csproj
83 | *.log
84 | *.vspscc
85 | *.vssscc
86 | .builds
87 | *.pidb
88 | *.svclog
89 | *.scc
90 |
91 | # Chutzpah Test files
92 | _Chutzpah*
93 |
94 | # Visual C++ cache files
95 | ipch/
96 | *.aps
97 | *.ncb
98 | *.opendb
99 | *.opensdf
100 | *.sdf
101 | *.cachefile
102 | *.VC.db
103 | *.VC.VC.opendb
104 |
105 | # Visual Studio profiler
106 | *.psess
107 | *.vsp
108 | *.vspx
109 | *.sap
110 |
111 | # Visual Studio Trace Files
112 | *.e2e
113 |
114 | # TFS 2012 Local Workspace
115 | $tf/
116 |
117 | # Guidance Automation Toolkit
118 | *.gpState
119 |
120 | # ReSharper is a .NET coding add-in
121 | _ReSharper*/
122 | *.[Rr]e[Ss]harper
123 | *.DotSettings.user
124 |
125 | # JustCode is a .NET coding add-in
126 | .JustCode
127 |
128 | # TeamCity is a build add-in
129 | _TeamCity*
130 |
131 | # DotCover is a Code Coverage Tool
132 | *.dotCover
133 |
134 | # AxoCover is a Code Coverage Tool
135 | .axoCover/*
136 | !.axoCover/settings.json
137 |
138 | # Visual Studio code coverage results
139 | *.coverage
140 | *.coveragexml
141 |
142 | # NCrunch
143 | _NCrunch_*
144 | .*crunch*.local.xml
145 | nCrunchTemp_*
146 |
147 | # MightyMoose
148 | *.mm.*
149 | AutoTest.Net/
150 |
151 | # Web workbench (sass)
152 | .sass-cache/
153 |
154 | # Installshield output folder
155 | [Ee]xpress/
156 |
157 | # DocProject is a documentation generator add-in
158 | DocProject/buildhelp/
159 | DocProject/Help/*.HxT
160 | DocProject/Help/*.HxC
161 | DocProject/Help/*.hhc
162 | DocProject/Help/*.hhk
163 | DocProject/Help/*.hhp
164 | DocProject/Help/Html2
165 | DocProject/Help/html
166 |
167 | # Click-Once directory
168 | publish/
169 |
170 | # Publish Web Output
171 | *.[Pp]ublish.xml
172 | *.azurePubxml
173 | # Note: Comment the next line if you want to checkin your web deploy settings,
174 | # but database connection strings (with potential passwords) will be unencrypted
175 | *.pubxml
176 | *.publishproj
177 |
178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
179 | # checkin your Azure Web App publish settings, but sensitive information contained
180 | # in these scripts will be unencrypted
181 | PublishScripts/
182 |
183 | # NuGet Packages
184 | *.nupkg
185 | # The packages folder can be ignored because of Package Restore
186 | **/[Pp]ackages/*
187 | # except build/, which is used as an MSBuild target.
188 | !**/[Pp]ackages/build/
189 | # Uncomment if necessary however generally it will be regenerated when needed
190 | #!**/[Pp]ackages/repositories.config
191 | # NuGet v3's project.json files produces more ignorable files
192 | *.nuget.props
193 | *.nuget.targets
194 |
195 | # Microsoft Azure Build Output
196 | csx/
197 | *.build.csdef
198 |
199 | # Microsoft Azure Emulator
200 | ecf/
201 | rcf/
202 |
203 | # Windows Store app package directories and files
204 | AppPackages/
205 | BundleArtifacts/
206 | Package.StoreAssociation.xml
207 | _pkginfo.txt
208 | *.appx
209 |
210 | # Visual Studio cache files
211 | # files ending in .cache can be ignored
212 | *.[Cc]ache
213 | # but keep track of directories ending in .cache
214 | !?*.[Cc]ache/
215 |
216 | # Others
217 | ClientBin/
218 | ~$*
219 | *~
220 | *.dbmdl
221 | *.dbproj.schemaview
222 | *.jfm
223 | *.pfx
224 | *.publishsettings
225 | orleans.codegen.cs
226 |
227 | # Including strong name files can present a security risk
228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
229 | #*.snk
230 |
231 | # Since there are multiple workflows, uncomment next line to ignore bower_components
232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
233 | #bower_components/
234 |
235 | # RIA/Silverlight projects
236 | Generated_Code/
237 |
238 | # Backup & report files from converting an old project file
239 | # to a newer Visual Studio version. Backup files are not needed,
240 | # because we have git ;-)
241 | _UpgradeReport_Files/
242 | Backup*/
243 | UpgradeLog*.XML
244 | UpgradeLog*.htm
245 | ServiceFabricBackup/
246 | *.rptproj.bak
247 |
248 | # SQL Server files
249 | *.mdf
250 | *.ldf
251 | *.ndf
252 |
253 | # Business Intelligence projects
254 | *.rdl.data
255 | *.bim.layout
256 | *.bim_*.settings
257 | *.rptproj.rsuser
258 | *- Backup*.rdl
259 |
260 | # Microsoft Fakes
261 | FakesAssemblies/
262 |
263 | # GhostDoc plugin setting file
264 | *.GhostDoc.xml
265 |
266 | # Node.js Tools for Visual Studio
267 | .ntvs_analysis.dat
268 | node_modules/
269 |
270 | # Visual Studio 6 build log
271 | *.plg
272 |
273 | # Visual Studio 6 workspace options file
274 | *.opt
275 |
276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
277 | *.vbw
278 |
279 | # Visual Studio LightSwitch build output
280 | **/*.HTMLClient/GeneratedArtifacts
281 | **/*.DesktopClient/GeneratedArtifacts
282 | **/*.DesktopClient/ModelManifest.xml
283 | **/*.Server/GeneratedArtifacts
284 | **/*.Server/ModelManifest.xml
285 | _Pvt_Extensions
286 |
287 | # Paket dependency manager
288 | .paket/paket.exe
289 | paket-files/
290 |
291 | # FAKE - F# Make
292 | .fake/
293 |
294 | # JetBrains Rider
295 | .idea/
296 | *.sln.iml
297 |
298 | # CodeRush personal settings
299 | .cr/personal
300 |
301 | # Python Tools for Visual Studio (PTVS)
302 | __pycache__/
303 | *.pyc
304 |
305 | # Cake - Uncomment if you are using it
306 | # tools/**
307 | # !tools/packages.config
308 |
309 | # Tabs Studio
310 | *.tss
311 |
312 | # Telerik's JustMock configuration file
313 | *.jmconfig
314 |
315 | # BizTalk build output
316 | *.btp.cs
317 | *.btm.cs
318 | *.odx.cs
319 | *.xsd.cs
320 |
321 | # OpenCover UI analysis results
322 | OpenCover/
323 |
324 | # Azure Stream Analytics local run output
325 | ASALocalRun/
326 |
327 | # MSBuild Binary and Structured Log
328 | *.binlog
329 |
330 | # NVidia Nsight GPU debugger configuration file
331 | *.nvuser
332 |
333 | # MFractors (Xamarin productivity tool) working folder
334 | .mfractor/
335 |
336 | # Local History for Visual Studio
337 | .localhistory/
338 |
339 | # BeatPulse healthcheck temp database
340 | healthchecksdb
--------------------------------------------------------------------------------
/src/BipEmulator.Host/WatchScreen.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using System.Windows.Forms;
4 | using FastBitmapLib;
5 |
6 | namespace BipEmulator.Host
7 | {
8 | public partial class WatchScreen : UserControl
9 | {
10 | const int SIZE = 176;
11 | public Color BackgroundColor { get; set; }
12 | public Color ForegroundColor { get; set; }
13 |
14 | private Bitmap _shadowImage = new Bitmap(SIZE, SIZE);
15 | private Bitmap _primImage = new Bitmap(SIZE, SIZE);
16 |
17 | private Brush _foreBrush;
18 | private Brush _backBrush;
19 | private Pen _forePen;
20 |
21 | private FtFile _ftFile;
22 | private FtMaker _ftMaker;
23 |
24 | public ColorArray Colors { get; set; }
25 |
26 | public WatchScreen()
27 | {
28 | InitializeComponent();
29 | DoubleBuffered = true;
30 | }
31 |
32 | public void SetFontFile(string fontFilename)
33 | {
34 | _ftFile = FtFile.Load(fontFilename);
35 | _ftMaker = new FtMaker(_ftFile);
36 | }
37 |
38 |
39 | protected override void OnSizeChanged(EventArgs e)
40 | {
41 | Width = SIZE;
42 | Height = SIZE;
43 | }
44 |
45 | public void RepaintScreenLines(int from, int to)
46 | {
47 | var r = new Rectangle(0, from, SIZE, to - from);
48 | FastBitmap.CopyRegion(_shadowImage, _primImage, r, r);
49 | }
50 |
51 | public int GetTextHeight()
52 | {
53 | if (_ftMaker == null)
54 | return 0;
55 | return _ftMaker.GetTextHeight();
56 | }
57 |
58 | public int GetTextWidth(string text)
59 | {
60 | if (_ftMaker == null)
61 | return 0;
62 | return _ftMaker.GetTextWidth(text);
63 | }
64 |
65 | public void TextOutCenter(string text, int x, int y)
66 | {
67 | if (_ftMaker == null)
68 | return;
69 |
70 | _ftMaker.TextOutCenter(_shadowImage, text, x, y, ForegroundColor, BackgroundColor);
71 | }
72 |
73 | public void TextOut(string text, int x, int y)
74 | {
75 | if (_ftMaker == null)
76 | return;
77 | _ftMaker.TextOut(_shadowImage, text, x, y, ForegroundColor, BackgroundColor);
78 | }
79 |
80 | public void FillScreenBg()
81 | {
82 | FastBitmap.ClearBitmap(_shadowImage, BackgroundColor);
83 | }
84 | public void FillScreenFg()
85 | {
86 | FastBitmap.ClearBitmap(_shadowImage, ForegroundColor);
87 | }
88 |
89 | public void SetFgColor(Color color)
90 | {
91 | ForegroundColor = GetRealColor(color);
92 | _foreBrush = new SolidBrush(ForegroundColor);
93 | _forePen = new Pen(ForegroundColor);
94 | }
95 | public void SetBgColor(Color color)
96 | {
97 | BackgroundColor = GetRealColor(color);
98 | _backBrush = new SolidBrush(BackgroundColor);
99 | }
100 |
101 | public void DrawLine(int x0, int y0, int x1, int y1)
102 | {
103 | var g = Graphics.FromImage(_shadowImage);
104 | g.DrawLine(_forePen, x0, y0, x1, y1);
105 | }
106 |
107 | public void DrawFilledRectBg(int x0, int y0, int x1, int y1)
108 | {
109 | var g = Graphics.FromImage(_shadowImage);
110 | g.FillRectangle(_backBrush, x0, y0, x1 - x0 + 1, y1 - y0 + 1);
111 | }
112 |
113 | public void DrawFilledRect(int x0, int y0, int x1, int y1)
114 | {
115 | var g = Graphics.FromImage(_shadowImage);
116 | g.FillRectangle(_foreBrush, x0, y0, x1 - x0 + 1, y1 - y0 + 1);
117 | }
118 |
119 | public void DrawRect(int x0, int y0, int x1, int y1)
120 | {
121 | var g = Graphics.FromImage(_shadowImage);
122 | g.DrawRectangle(_forePen, x0, y0, x1 - x0 + 1, y1 - y0 + 1);
123 | }
124 |
125 | public void DrawImage(Bitmap image, int x, int y)
126 | {
127 | var g = Graphics.FromImage(_shadowImage);
128 |
129 | var fastImage = new FastBitmap(image);
130 | fastImage.Lock();
131 | for (var i = 0; i < image.Width; i++)
132 | for (var j = 0; j < image.Height; j++)
133 | fastImage.SetPixel(i, j, GetRealColor(fastImage.GetPixel(i, j)));
134 | fastImage.Unlock();
135 |
136 | g.DrawImage(image, x, y);
137 | }
138 |
139 | protected override void OnPaint(PaintEventArgs e)
140 | {
141 | var g = e.Graphics;
142 | g.DrawImage(_primImage, 0, 0);
143 | }
144 |
145 | private Color GetRealColor(Color color)
146 | {
147 | //return color;
148 | switch ((uint)color.ToArgb())
149 | {
150 | // red
151 | case 0xFFFF0000:
152 | return Colors.Red; // (187, 113, 136)
153 | // green
154 | case 0xFF00FF00:
155 | return Colors.Green; // (89, 181, 132)
156 | // blue
157 | case 0xFF0000FF:
158 | return Colors.Blue; // (28, 110, 194)
159 | // yellow
160 | case 0xFFFFFF00:
161 | return Colors.Yellow; // (221, 214, 133)
162 | // aqua
163 | case 0xFF00FFFF:
164 | return Colors.Aqua; // (70, 198, 207)
165 | // purple
166 | case 0xFFFF00FF:
167 | return Colors.Purple; // (173, 147, 208)
168 | // white
169 | case 0xFFFFFFFF:
170 | return Colors.White; // (220, 220, 220)
171 | // black
172 | case 0xFF000000:
173 | return Colors.Black; // (56, 56, 56)
174 | }
175 | return color;
176 | }
177 |
178 | public static Color GetColorFromGRBInt(int value)
179 | {
180 | return Color.FromArgb(value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff);
181 | }
182 |
183 | private Color GetColorByIndex(int index)
184 | {
185 | switch((ColorIndexEnum)index)
186 | {
187 | case ColorIndexEnum.Black:
188 | return Colors.Black;
189 | case ColorIndexEnum.Blue:
190 | return Colors.Blue;
191 | case ColorIndexEnum.Green:
192 | return Colors.Green;
193 | case ColorIndexEnum.Aqua:
194 | return Colors.Aqua;
195 | case ColorIndexEnum.Purple:
196 | return Colors.Purple;
197 | case ColorIndexEnum.Red:
198 | return Colors.Red;
199 | case ColorIndexEnum.Yellow:
200 | return Colors.Yellow;
201 | default:
202 | return Colors.Black;
203 | }
204 | }
205 |
206 | internal void SetVideoData(byte[] videoMemory)
207 | {
208 | var shadow = new FastBitmap(_shadowImage);
209 | shadow.Lock();
210 | var offset = 0;
211 | for(var y=0;y> 4));
215 | shadow.SetPixel(x+1, y, GetColorByIndex(videoMemory[offset] & 0xf));
216 | offset++;
217 | }
218 | shadow.Unlock();
219 | }
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/ResImage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Drawing;
4 | using System.IO;
5 |
6 | namespace BipEmulator.Host
7 | {
8 | public class ResImage
9 | {
10 | private Bitmap _bitmap = null;
11 |
12 | private ushort _bitsPerPixel;
13 | private ushort _height;
14 | private Color[] _palette;
15 | private ushort _paletteColors;
16 | private ushort _rowLengthInBytes;
17 | private bool _transparency;
18 | private ushort _width;
19 |
20 | public Bitmap Bitmap
21 | {
22 | get
23 | {
24 | if (_bitmap == null)
25 | Read();
26 | return _bitmap;
27 | }
28 | }
29 |
30 | private byte[] _data;
31 |
32 | public ResImage(byte[] data)
33 | {
34 | _data = data;
35 | }
36 |
37 | public void Read()
38 | {
39 | using (var ms = new MemoryStream(_data))
40 | using (var br = new BinaryReader(ms))
41 | {
42 | var signature = br.ReadChars(4);
43 | if (signature[0] != 'B' || signature[1] != 'M')
44 | throw new ArgumentException("Image signature doesn't match.");
45 |
46 | ReadHeader(br);
47 | if (_paletteColors > 256)
48 | throw new ArgumentException("Too many palette colors.");
49 |
50 | if (_paletteColors > 0)
51 | ReadPalette(br);
52 | //else if (_bitsPerPixel == 8 || _bitsPerPixel == 16 || _bitsPerPixel == 24 || _bitsPerPixel == 32)
53 | // Debug.WriteLine("The image doesn't use a palette.");
54 | else
55 | throw new ArgumentException(
56 | "The image format is not supported. Please report the issue on https://bitbucket.org/valeronm/amazfitbiptools");
57 | _bitmap = ReadImage(br);
58 | }
59 | }
60 |
61 | private void ReadHeader(BinaryReader br)
62 | {
63 | //Debug.WriteLine("Reading image header...");
64 | _width = br.ReadUInt16();
65 | _height = br.ReadUInt16();
66 | _rowLengthInBytes = br.ReadUInt16();
67 | _bitsPerPixel = br.ReadUInt16();
68 | _paletteColors = br.ReadUInt16();
69 | _transparency = br.ReadUInt16() > 0;
70 | //Debug.WriteLine("Image header was read:");
71 | //Debug.WriteLine("Width: {0}, Height: {1}, RowLength: {2}", _width, _height, _rowLengthInBytes);
72 | //Debug.WriteLine("BPP: {0}, PaletteColors: {1}, Transaparency: {2}", _bitsPerPixel, _paletteColors, _transparency);
73 | }
74 |
75 | private void ReadPalette(BinaryReader br)
76 | {
77 | //Debug.WriteLine("Reading palette...");
78 | _palette = new Color[_paletteColors];
79 | for (var i = 0; i < _paletteColors; i++)
80 | {
81 | var r = br.ReadByte();
82 | var g = br.ReadByte();
83 | var b = br.ReadByte();
84 | var padding = br.ReadByte(); // always 0 maybe padding
85 |
86 | if (padding != 0) Debug.WriteLine("Palette item {0} last byte is not zero: {1:X2}", i, padding);
87 |
88 | var isColorValid = (r == 0 || r == 0xff) && (g == 0 || g == 0xff) && (b == 0 || b == 0xff);
89 | //if (isColorValid)
90 | // Debug.WriteLine("Palette item {0}: R {1:X2}, G {2:X2}, B {3:X2}", i, r, g, b);
91 | //else
92 | // Debug.WriteLine("Palette item {0}: R {1:X2}, G {2:X2}, B {3:X2}, color isn't supported!", i, r, g, b);
93 |
94 | var alpha = _transparency && i == 0 ? 0x00 : 0xff;
95 | _palette[i] = Color.FromArgb(alpha, r, g, b);
96 | }
97 | }
98 |
99 | private Bitmap ReadImage(BinaryReader br)
100 | {
101 | if (_paletteColors > 0) return ReadPaletteImage(br);
102 | if (_bitsPerPixel == 8) return Read8BitImage(br);
103 | if (_bitsPerPixel == 16) return Read16BitImage(br);
104 | if (_bitsPerPixel == 24) return Read24BitImage(br);
105 | if (_bitsPerPixel == 32) return Read32BitImage(br);
106 | throw new ArgumentException($"Unsupported bits per pixel value: {_bitsPerPixel}");
107 | }
108 |
109 | private Bitmap ReadPaletteImage(BinaryReader br)
110 | {
111 | var image = new Bitmap(_width, _height);
112 | using (var context = image.CreateUnsafeContext())
113 | {
114 | for (var y = 0; y < _height; y++)
115 | {
116 | var rowBytes = br.ReadBytes(_rowLengthInBytes);
117 | var bitReader = new BitReader(rowBytes);
118 | for (var x = 0; x < _width; x++)
119 | {
120 | var pixelColorIndex = bitReader.ReadBits(_bitsPerPixel);
121 | var color = _palette[(int)pixelColorIndex];
122 | context.SetPixel(x, y, color);
123 | }
124 | }
125 | }
126 |
127 | return image;
128 | }
129 |
130 | private Bitmap Read8BitImage(BinaryReader br)
131 | {
132 | var image = new Bitmap(_width, _height);
133 | using (var context = image.CreateUnsafeContext())
134 | {
135 | for (var y = 0; y < _height; y++)
136 | {
137 | var rowBytes = br.ReadBytes(_rowLengthInBytes);
138 | for (var x = 0; x < _width; x++)
139 | {
140 | var data = rowBytes[x];
141 | var color = Color.FromArgb(0xff, data, data, data);
142 | context.SetPixel(x, y, color);
143 | }
144 | }
145 | }
146 |
147 | return image;
148 | }
149 |
150 | private Bitmap Read16BitImage(BinaryReader br)
151 | {
152 | var image = new Bitmap(_width, _height);
153 | using (var context = image.CreateUnsafeContext())
154 | {
155 | for (var y = 0; y < _height; y++)
156 | {
157 | var rowBytes = br.ReadBytes(_rowLengthInBytes);
158 | var bitReader = new BitReader(rowBytes);
159 | for (var x = 0; x < _width; x++)
160 | {
161 | var firstByte = (int)bitReader.ReadByte();
162 | var secondByte = (int)bitReader.ReadByte();
163 | var b = (byte)((secondByte >> 3) & 0x1f) << 3;
164 | var g = (byte)(((firstByte >> 5) & 0x7) | ((secondByte & 0x07) << 3)) << 2;
165 | var r = (byte)(firstByte & 0x1f) << 3;
166 | var color = Color.FromArgb(0xff, r, g, b);
167 | context.SetPixel(x, y, color);
168 | }
169 | }
170 | }
171 |
172 | return image;
173 | }
174 |
175 | private Bitmap Read24BitImage(BinaryReader br)
176 | {
177 | var image = new Bitmap(_width, _height);
178 | using (var context = image.CreateUnsafeContext())
179 | {
180 | for (var y = 0; y < _height; y++)
181 | {
182 | var rowBytes = br.ReadBytes(_rowLengthInBytes);
183 | var bitReader = new BitReader(rowBytes);
184 | for (var x = 0; x < _width; x++)
185 | {
186 | var alpha = (int)bitReader.ReadByte();
187 | var b = (int)(bitReader.ReadBits(5) << 3);
188 | var g = (int)(bitReader.ReadBits(6) << 2);
189 | var r = (int)(bitReader.ReadBits(5) << 3);
190 | var color = Color.FromArgb(0xff - alpha, r, g, b);
191 | context.SetPixel(x, y, color);
192 | }
193 | }
194 | }
195 |
196 | return image;
197 | }
198 |
199 | private Bitmap Read32BitImage(BinaryReader br)
200 | {
201 | var image = new Bitmap(_width, _height);
202 | using (var context = image.CreateUnsafeContext())
203 | {
204 | for (var y = 0; y < _height; y++)
205 | {
206 | var rowBytes = br.ReadBytes(_rowLengthInBytes);
207 | for (var x = 0; x < _width; x++)
208 | {
209 | var r = rowBytes[x * 4];
210 | var g = rowBytes[x * 4 + 1];
211 | var b = rowBytes[x * 4 + 2];
212 | var alpha = rowBytes[x * 4 + 3];
213 | var color = Color.FromArgb(0xff - alpha, r, g, b);
214 | context.SetPixel(x, y, color);
215 | }
216 | }
217 | }
218 |
219 | return image;
220 | }
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/ColorSelectionForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace BipEmulator.Host
2 | {
3 | partial class ColorSelectionForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.groupBox1 = new System.Windows.Forms.GroupBox();
32 | this.btnReset = new System.Windows.Forms.Button();
33 | this.lblWhite = new System.Windows.Forms.Label();
34 | this.lblPurple = new System.Windows.Forms.Label();
35 | this.lblAqua = new System.Windows.Forms.Label();
36 | this.lblYellow = new System.Windows.Forms.Label();
37 | this.lblBlue = new System.Windows.Forms.Label();
38 | this.lblGreen = new System.Windows.Forms.Label();
39 | this.lblRed = new System.Windows.Forms.Label();
40 | this.lblBlack = new System.Windows.Forms.Label();
41 | this.btnClose = new System.Windows.Forms.Button();
42 | this.btnOK = new System.Windows.Forms.Button();
43 | this.groupBox1.SuspendLayout();
44 | this.SuspendLayout();
45 | //
46 | // groupBox1
47 | //
48 | this.groupBox1.Controls.Add(this.btnReset);
49 | this.groupBox1.Controls.Add(this.lblWhite);
50 | this.groupBox1.Controls.Add(this.lblPurple);
51 | this.groupBox1.Controls.Add(this.lblAqua);
52 | this.groupBox1.Controls.Add(this.lblYellow);
53 | this.groupBox1.Controls.Add(this.lblBlue);
54 | this.groupBox1.Controls.Add(this.lblGreen);
55 | this.groupBox1.Controls.Add(this.lblRed);
56 | this.groupBox1.Controls.Add(this.lblBlack);
57 | this.groupBox1.Location = new System.Drawing.Point(12, 12);
58 | this.groupBox1.Name = "groupBox1";
59 | this.groupBox1.Padding = new System.Windows.Forms.Padding(6);
60 | this.groupBox1.Size = new System.Drawing.Size(233, 320);
61 | this.groupBox1.TabIndex = 0;
62 | this.groupBox1.TabStop = false;
63 | this.groupBox1.Text = "Colors";
64 | //
65 | // btnReset
66 | //
67 | this.btnReset.Enabled = false;
68 | this.btnReset.Location = new System.Drawing.Point(9, 288);
69 | this.btnReset.Name = "btnReset";
70 | this.btnReset.Size = new System.Drawing.Size(215, 23);
71 | this.btnReset.TabIndex = 0;
72 | this.btnReset.Text = "Reset";
73 | this.btnReset.UseVisualStyleBackColor = true;
74 | //
75 | // lblWhite
76 | //
77 | this.lblWhite.BackColor = System.Drawing.Color.Red;
78 | this.lblWhite.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
79 | this.lblWhite.Location = new System.Drawing.Point(9, 239);
80 | this.lblWhite.Margin = new System.Windows.Forms.Padding(3);
81 | this.lblWhite.Name = "lblWhite";
82 | this.lblWhite.Size = new System.Drawing.Size(215, 25);
83 | this.lblWhite.TabIndex = 7;
84 | this.lblWhite.Text = "White";
85 | this.lblWhite.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
86 | this.lblWhite.Click += new System.EventHandler(this.ColorLabel_Click);
87 | //
88 | // lblPurple
89 | //
90 | this.lblPurple.BackColor = System.Drawing.Color.Red;
91 | this.lblPurple.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
92 | this.lblPurple.Location = new System.Drawing.Point(9, 208);
93 | this.lblPurple.Margin = new System.Windows.Forms.Padding(3);
94 | this.lblPurple.Name = "lblPurple";
95 | this.lblPurple.Size = new System.Drawing.Size(215, 25);
96 | this.lblPurple.TabIndex = 6;
97 | this.lblPurple.Text = "Purple";
98 | this.lblPurple.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
99 | this.lblPurple.Click += new System.EventHandler(this.ColorLabel_Click);
100 | //
101 | // lblAqua
102 | //
103 | this.lblAqua.BackColor = System.Drawing.Color.Red;
104 | this.lblAqua.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
105 | this.lblAqua.Location = new System.Drawing.Point(9, 177);
106 | this.lblAqua.Margin = new System.Windows.Forms.Padding(3);
107 | this.lblAqua.Name = "lblAqua";
108 | this.lblAqua.Size = new System.Drawing.Size(215, 25);
109 | this.lblAqua.TabIndex = 5;
110 | this.lblAqua.Text = "Aqua";
111 | this.lblAqua.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
112 | this.lblAqua.Click += new System.EventHandler(this.ColorLabel_Click);
113 | //
114 | // lblYellow
115 | //
116 | this.lblYellow.BackColor = System.Drawing.Color.Red;
117 | this.lblYellow.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
118 | this.lblYellow.Location = new System.Drawing.Point(9, 146);
119 | this.lblYellow.Margin = new System.Windows.Forms.Padding(3);
120 | this.lblYellow.Name = "lblYellow";
121 | this.lblYellow.Size = new System.Drawing.Size(215, 25);
122 | this.lblYellow.TabIndex = 4;
123 | this.lblYellow.Text = "Yellow";
124 | this.lblYellow.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
125 | this.lblYellow.Click += new System.EventHandler(this.ColorLabel_Click);
126 | //
127 | // lblBlue
128 | //
129 | this.lblBlue.BackColor = System.Drawing.Color.Red;
130 | this.lblBlue.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
131 | this.lblBlue.Location = new System.Drawing.Point(9, 115);
132 | this.lblBlue.Margin = new System.Windows.Forms.Padding(3);
133 | this.lblBlue.Name = "lblBlue";
134 | this.lblBlue.Size = new System.Drawing.Size(215, 25);
135 | this.lblBlue.TabIndex = 3;
136 | this.lblBlue.Text = "Blue";
137 | this.lblBlue.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
138 | this.lblBlue.Click += new System.EventHandler(this.ColorLabel_Click);
139 | //
140 | // lblGreen
141 | //
142 | this.lblGreen.BackColor = System.Drawing.Color.Red;
143 | this.lblGreen.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
144 | this.lblGreen.Location = new System.Drawing.Point(9, 84);
145 | this.lblGreen.Margin = new System.Windows.Forms.Padding(3);
146 | this.lblGreen.Name = "lblGreen";
147 | this.lblGreen.Size = new System.Drawing.Size(215, 25);
148 | this.lblGreen.TabIndex = 2;
149 | this.lblGreen.Text = "Green";
150 | this.lblGreen.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
151 | this.lblGreen.Click += new System.EventHandler(this.ColorLabel_Click);
152 | //
153 | // lblRed
154 | //
155 | this.lblRed.BackColor = System.Drawing.Color.Red;
156 | this.lblRed.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
157 | this.lblRed.Location = new System.Drawing.Point(9, 53);
158 | this.lblRed.Margin = new System.Windows.Forms.Padding(3);
159 | this.lblRed.Name = "lblRed";
160 | this.lblRed.Size = new System.Drawing.Size(215, 25);
161 | this.lblRed.TabIndex = 1;
162 | this.lblRed.Text = "Red";
163 | this.lblRed.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
164 | this.lblRed.Click += new System.EventHandler(this.ColorLabel_Click);
165 | //
166 | // lblBlack
167 | //
168 | this.lblBlack.BackColor = System.Drawing.Color.Gray;
169 | this.lblBlack.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
170 | this.lblBlack.Location = new System.Drawing.Point(9, 22);
171 | this.lblBlack.Margin = new System.Windows.Forms.Padding(3);
172 | this.lblBlack.Name = "lblBlack";
173 | this.lblBlack.Size = new System.Drawing.Size(215, 25);
174 | this.lblBlack.TabIndex = 0;
175 | this.lblBlack.Text = "Black";
176 | this.lblBlack.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
177 | this.lblBlack.Click += new System.EventHandler(this.ColorLabel_Click);
178 | //
179 | // btnClose
180 | //
181 | this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
182 | this.btnClose.Location = new System.Drawing.Point(12, 338);
183 | this.btnClose.Name = "btnClose";
184 | this.btnClose.Size = new System.Drawing.Size(75, 23);
185 | this.btnClose.TabIndex = 0;
186 | this.btnClose.Text = "Close";
187 | this.btnClose.UseVisualStyleBackColor = true;
188 | //
189 | // btnOK
190 | //
191 | this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
192 | this.btnOK.Location = new System.Drawing.Point(173, 338);
193 | this.btnOK.Name = "btnOK";
194 | this.btnOK.Size = new System.Drawing.Size(75, 23);
195 | this.btnOK.TabIndex = 1;
196 | this.btnOK.Text = "OK";
197 | this.btnOK.UseVisualStyleBackColor = true;
198 | this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
199 | //
200 | // ColorSelectionForm
201 | //
202 | this.AcceptButton = this.btnOK;
203 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
204 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
205 | this.CancelButton = this.btnClose;
206 | this.ClientSize = new System.Drawing.Size(261, 372);
207 | this.Controls.Add(this.btnOK);
208 | this.Controls.Add(this.btnClose);
209 | this.Controls.Add(this.groupBox1);
210 | this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
211 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
212 | this.MaximizeBox = false;
213 | this.MinimizeBox = false;
214 | this.Name = "ColorSelectionForm";
215 | this.ShowIcon = false;
216 | this.ShowInTaskbar = false;
217 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
218 | this.Text = "Color Selection";
219 | this.groupBox1.ResumeLayout(false);
220 | this.ResumeLayout(false);
221 |
222 | }
223 |
224 | #endregion
225 |
226 | private System.Windows.Forms.GroupBox groupBox1;
227 | private System.Windows.Forms.Button btnReset;
228 | private System.Windows.Forms.Label lblWhite;
229 | private System.Windows.Forms.Label lblPurple;
230 | private System.Windows.Forms.Label lblAqua;
231 | private System.Windows.Forms.Label lblYellow;
232 | private System.Windows.Forms.Label lblBlue;
233 | private System.Windows.Forms.Label lblGreen;
234 | private System.Windows.Forms.Label lblRed;
235 | private System.Windows.Forms.Label lblBlack;
236 | private System.Windows.Forms.Button btnClose;
237 | private System.Windows.Forms.Button btnOK;
238 | }
239 | }
--------------------------------------------------------------------------------
/src/BipEmulator.Host/SymbolSet.cs:
--------------------------------------------------------------------------------
1 | namespace BipEmulator.Host
2 | {
3 | public struct SymbolSet
4 | {
5 | public static (int, int) GetResource(int symbolSet, char value)
6 | {
7 | if (symbolSet > 15)
8 | return (-1, - 1);
9 |
10 | var offsetSymbols = 0;
11 | for (var i = 0; i < symbolSet; i++)
12 | offsetSymbols += SymbolSetLengths[i];
13 |
14 | for (var i = 0; i < SymbolSetLengths[symbolSet]; i++)
15 | if (Preset[offsetSymbols + i].Value == value)
16 | return (Preset[offsetSymbols + i].ResId, Preset[offsetSymbols + i].Width);
17 | return (-1, -1);
18 | }
19 |
20 | private static int[] SymbolSetLengths = { 10, 10, 14, 15, 10, 75, 75, 11, 16, 12, 16, 16, 20, 11, 23, 14 };
21 |
22 | private static Symbol[] Preset = new Symbol[]
23 | {
24 | // 0 10
25 | new Symbol ('0', 11, 28),
26 | new Symbol ('1', 11, 29),
27 | new Symbol ('2', 11, 30),
28 | new Symbol ('3', 11, 31),
29 | new Symbol ('4', 11, 32),
30 | new Symbol ('5', 11, 33),
31 | new Symbol ('6', 11, 34),
32 | new Symbol ('7', 11, 35),
33 | new Symbol ('8', 11, 36),
34 | new Symbol ('9', 11, 37),
35 | // 1 10
36 | new Symbol ('0', 8, 170),
37 | new Symbol ('1', 8, 171),
38 | new Symbol ('2', 8, 172),
39 | new Symbol ('3', 8, 173),
40 | new Symbol ('4', 8, 174),
41 | new Symbol ('5', 8, 175),
42 | new Symbol ('6', 8, 176),
43 | new Symbol ('7', 8, 177),
44 | new Symbol ('8', 8, 178),
45 | new Symbol ('9', 8, 179),
46 | // 2 14
47 | new Symbol ((char)0x22, 10, 582),
48 | new Symbol ((char)0x27, 4, 583),
49 | new Symbol ('.', 4, 580),
50 | new Symbol ('0', 14, 584),
51 | new Symbol ('1', 14, 585),
52 | new Symbol ('2', 14, 586),
53 | new Symbol ('3', 14, 587),
54 | new Symbol ('4', 14, 588),
55 | new Symbol ('5', 14, 589),
56 | new Symbol ('6', 14, 590),
57 | new Symbol ('7', 14, 591),
58 | new Symbol ('8', 14, 592),
59 | new Symbol ('9', 14, 593),
60 | new Symbol (':', 4, 581),
61 | // 3 15
62 | new Symbol ((char)0xb0, 12, 594),
63 | new Symbol ('-', 13, 595),
64 | new Symbol ('.', 6, 596),
65 | new Symbol ('/', 12, 597),
66 | new Symbol ('0', 17, 599),
67 | new Symbol ('1', 17, 600),
68 | new Symbol ('2', 17, 601),
69 | new Symbol ('3', 17, 602),
70 | new Symbol ('4', 17, 603),
71 | new Symbol ('5', 17, 604),
72 | new Symbol ('6', 17, 605),
73 | new Symbol ('7', 17, 606),
74 | new Symbol ('8', 17, 607),
75 | new Symbol ('9', 17, 608),
76 | new Symbol (':', 6, 598),
77 | // 4 10
78 | new Symbol ('0', 17, 609),
79 | new Symbol ('1', 17, 610),
80 | new Symbol ('2', 17, 611),
81 | new Symbol ('3', 17, 612),
82 | new Symbol ('4', 17, 613),
83 | new Symbol ('5', 17, 614),
84 | new Symbol ('6', 17, 615),
85 | new Symbol ('7', 17, 616),
86 | new Symbol ('8', 17, 617),
87 | new Symbol ('9', 17, 618),
88 | // 5 75
89 | new Symbol ('0', 9, 619),
90 | new Symbol ('1', 9, 620),
91 | new Symbol ('2', 9, 621),
92 | new Symbol ('3', 9, 622),
93 | new Symbol ('4', 9, 623),
94 | new Symbol ('5', 9, 624),
95 | new Symbol ('6', 9, 625),
96 | new Symbol ('7', 9, 626),
97 | new Symbol ('8', 9, 627),
98 | new Symbol ('9', 9, 628),
99 | new Symbol ('-', 6, 629),
100 | new Symbol ('.', 2, 630),
101 | new Symbol ('/', 6, 631),
102 | new Symbol (':', 2, 632),
103 | new Symbol ('A', 15, 633),
104 | new Symbol ('B', 10, 634),
105 | new Symbol ('C', 11, 635),
106 | new Symbol ('D', 11, 636),
107 | new Symbol ('E', 10, 637),
108 | new Symbol ('F', 10, 638),
109 | new Symbol ('G', 12, 639),
110 | new Symbol ('H', 11, 640),
111 | new Symbol ('I', 6, 641),
112 | new Symbol ('J', 7, 642),
113 | new Symbol ('K', 12, 643),
114 | new Symbol ('L', 10, 644),
115 | new Symbol ('M', 14, 645),
116 | new Symbol ('N', 13, 646),
117 | new Symbol ('O', 13, 647),
118 | new Symbol ('P', 12, 648),
119 | new Symbol ('Q', 13, 649),
120 | new Symbol ('R', 11, 650),
121 | new Symbol ('S', 10, 651),
122 | new Symbol ('T', 12, 652),
123 | new Symbol ('U', 12, 653),
124 | new Symbol ('V', 14, 654),
125 | new Symbol ('W', 14, 655),
126 | new Symbol ('X', 15, 656),
127 | new Symbol ('Y', 14, 657),
128 | new Symbol ('Z', 13, 658),
129 | new Symbol ('a', 9, 659),
130 | new Symbol ('b', 9, 660),
131 | new Symbol ('c', 8, 661),
132 | new Symbol ('d', 9, 662),
133 | new Symbol ('e', 9, 663),
134 | new Symbol ('f', 7, 664),
135 | new Symbol ('g', 9, 665),
136 | new Symbol ('h', 8, 666),
137 | new Symbol ('i', 2, 667),
138 | new Symbol ('j', 5, 668),
139 | new Symbol ('k', 9, 669),
140 | new Symbol ('l', 2, 670),
141 | new Symbol ('m', 14, 671),
142 | new Symbol ('n', 9, 672),
143 | new Symbol ('o', 9, 673),
144 | new Symbol ('p', 9, 674),
145 | new Symbol ('q', 9, 675),
146 | new Symbol ('r', 7, 676),
147 | new Symbol ('s', 8, 677),
148 | new Symbol ('t', 7, 678),
149 | new Symbol ('u', 9, 679),
150 | new Symbol ('v', 9, 680),
151 | new Symbol ('w', 14, 681),
152 | new Symbol ('x', 9, 682),
153 | new Symbol ('y', 9, 683),
154 | new Symbol ('z', 9, 684),
155 | new Symbol ((char)0xa5, 8, 975),
156 | new Symbol ('#', 12, 978),
157 | new Symbol ((char)0x24, 8, 979),
158 | new Symbol ('%', 14, 980),
159 | new Symbol ('(', 7, 981),
160 | new Symbol (')', 7, 982),
161 | new Symbol ('@', 14, 983),
162 | new Symbol (' ', 1, 977),
163 | new Symbol ('?', 13, 976),
164 | // 6 75
165 | new Symbol ('0', 12, 685),
166 | new Symbol ('1', 12, 686),
167 | new Symbol ('2', 12, 687),
168 | new Symbol ('3', 12, 688),
169 | new Symbol ('4', 12, 689),
170 | new Symbol ('5', 12, 690),
171 | new Symbol ('6', 12, 691),
172 | new Symbol ('7', 12, 692),
173 | new Symbol ('8', 12, 693),
174 | new Symbol ('9', 12, 694),
175 | new Symbol ('-', 7, 695),
176 | new Symbol ('.', 3, 696),
177 | new Symbol ('/', 9, 697),
178 | new Symbol (':', 3, 698),
179 | new Symbol ('A', 16, 699),
180 | new Symbol ('B', 15, 700),
181 | new Symbol ('C', 16, 701),
182 | new Symbol ('D', 16, 702),
183 | new Symbol ('E', 13, 703),
184 | new Symbol ('F', 13, 704),
185 | new Symbol ('G', 16, 705),
186 | new Symbol ('H', 15, 706),
187 | new Symbol ('I', 9, 707),
188 | new Symbol ('J', 9, 708),
189 | new Symbol ('K', 17, 709),
190 | new Symbol ('L', 12, 710),
191 | new Symbol ('M', 19, 711),
192 | new Symbol ('N', 16, 712),
193 | new Symbol ('O', 17, 713),
194 | new Symbol ('P', 14, 714),
195 | new Symbol ('Q', 17, 715),
196 | new Symbol ('R', 15, 716),
197 | new Symbol ('S', 14, 717),
198 | new Symbol ('T', 15, 718),
199 | new Symbol ('U', 15, 719),
200 | new Symbol ('V', 20, 720),
201 | new Symbol ('W', 19, 721),
202 | new Symbol ('X', 18, 722),
203 | new Symbol ('Y', 19, 723),
204 | new Symbol ('Z', 17, 724),
205 | new Symbol ('a', 13, 725),
206 | new Symbol ('b', 12, 726),
207 | new Symbol ('c', 12, 727),
208 | new Symbol ('d', 12, 728),
209 | new Symbol ('e', 13, 729),
210 | new Symbol ('f', 9, 730),
211 | new Symbol ('g', 12, 731),
212 | new Symbol ('h', 12, 732),
213 | new Symbol ('i', 3, 733),
214 | new Symbol ('j', 7, 734),
215 | new Symbol ('k', 14, 735),
216 | new Symbol ('l', 3, 736),
217 | new Symbol ('m', 21, 737),
218 | new Symbol ('n', 12, 738),
219 | new Symbol ('o', 13, 739),
220 | new Symbol ('p', 13, 740),
221 | new Symbol ('q', 13, 741),
222 | new Symbol ('r', 9, 742),
223 | new Symbol ('s', 12, 743),
224 | new Symbol ('t', 9, 744),
225 | new Symbol ('u', 12, 745),
226 | new Symbol ('v', 16, 746),
227 | new Symbol ('w', 21, 747),
228 | new Symbol ('x', 15, 748),
229 | new Symbol ('y', 14, 749),
230 | new Symbol ('z', 12, 750),
231 | new Symbol ((char)0xa5, 11, 984),
232 | new Symbol ('#', 12, 987),
233 | new Symbol ((char)0x24, 12, 988),
234 | new Symbol ('%', 16, 989),
235 | new Symbol ('(', 8, 990),
236 | new Symbol (')', 8, 991),
237 | new Symbol ('@', 16, 992),
238 | new Symbol (' ', 1, 986),
239 | new Symbol ('?', 17, 985),
240 | // 7 11
241 | new Symbol ('0', 20, 751),
242 | new Symbol ('1', 20, 752),
243 | new Symbol ('2', 20, 753),
244 | new Symbol ('3', 20, 754),
245 | new Symbol ('4', 20, 755),
246 | new Symbol ('5', 20, 756),
247 | new Symbol ('6', 20, 757),
248 | new Symbol ('7', 20, 758),
249 | new Symbol ('8', 20, 759),
250 | new Symbol ('9', 20, 760),
251 | new Symbol (':', 5, 761),
252 | // 8 16
253 | new Symbol ('0', 12, 762),
254 | new Symbol ('1', 10, 763),
255 | new Symbol ('2', 12, 764),
256 | new Symbol ('3', 12, 765),
257 | new Symbol ('4', 14, 766),
258 | new Symbol ('5', 11, 767),
259 | new Symbol ('6', 12, 768),
260 | new Symbol ('7', 12, 769),
261 | new Symbol ('8', 12, 770),
262 | new Symbol ('9', 12, 771),
263 | new Symbol (':', 4, 772),
264 | new Symbol ((char)0x22, 10, 773),
265 | new Symbol ((char)0x27, 4, 774),
266 | new Symbol ('-', 11, 775),
267 | new Symbol ('.', 4, 776),
268 | new Symbol ((char)0xb0, 9, 777),
269 | // 9 12
270 | new Symbol ('0', 18, 778),
271 | new Symbol ('1', 18, 779),
272 | new Symbol ('2', 18, 780),
273 | new Symbol ('3', 18, 781),
274 | new Symbol ('4', 18, 782),
275 | new Symbol ('5', 18, 783),
276 | new Symbol ('6', 18, 784),
277 | new Symbol ('7', 18, 785),
278 | new Symbol ('8', 18, 786),
279 | new Symbol ('9', 18, 787),
280 | new Symbol (':', 6, 788),
281 | new Symbol ('/', 12, 789),
282 | // 10 16
283 | new Symbol ('0', 10, 790),
284 | new Symbol ('1', 10, 791),
285 | new Symbol ('2', 10, 792),
286 | new Symbol ('3', 10, 793),
287 | new Symbol ('4', 10, 794),
288 | new Symbol ('5', 10, 795),
289 | new Symbol ('6', 10, 796),
290 | new Symbol ('7', 10, 797),
291 | new Symbol ('8', 10, 798),
292 | new Symbol ('9', 10, 799),
293 | new Symbol (':', 2, 800),
294 | new Symbol ((char)0x22, 6, 801),
295 | new Symbol ((char)0x27, 2, 802),
296 | new Symbol ('-', 10, 803),
297 | new Symbol ('.', 2, 804),
298 | new Symbol ('/', 9, 805),
299 | // 11 16
300 | new Symbol ('0', 9, 806),
301 | new Symbol ('1', 9, 807),
302 | new Symbol ('2', 9, 808),
303 | new Symbol ('3', 9, 809),
304 | new Symbol ('4', 9, 810),
305 | new Symbol ('5', 9, 811),
306 | new Symbol ('6', 9, 812),
307 | new Symbol ('7', 9, 813),
308 | new Symbol ('8', 9, 814),
309 | new Symbol ('9', 9, 815),
310 | new Symbol (':', 7, 816),
311 | new Symbol ('-', 5, 817),
312 | new Symbol ('~', 10, 818),
313 | new Symbol ((char)0xb0, 4, 819),
314 | new Symbol ((char)0, 0, 0),
315 | new Symbol ((char)0, 0, 0),
316 | // 12 20
317 | new Symbol ('0', 8, 820),
318 | new Symbol ('1', 6, 821),
319 | new Symbol ('2', 8, 822),
320 | new Symbol ('3', 8, 823),
321 | new Symbol ('4', 8, 824),
322 | new Symbol ('5', 8, 825),
323 | new Symbol ('6', 8, 826),
324 | new Symbol ('7', 8, 827),
325 | new Symbol ('8', 8, 828),
326 | new Symbol ('9', 8, 829),
327 | new Symbol ('/', 8, 830),
328 | new Symbol ((char)0x4e00, 12, 831),
329 | new Symbol ((char)0x4e8c, 12, 832),
330 | new Symbol ((char)0x4e09, 12, 833),
331 | new Symbol ((char)0x4e94, 12, 834),
332 | new Symbol ((char)0x56db, 12, 835),
333 | new Symbol ((char)0x516d, 12, 836),
334 | new Symbol ((char)0x65e5, 12, 837),
335 | new Symbol ((char)0x5468, 12, 838),
336 | new Symbol ((char)0x9031, 15, 839),
337 | // 13 11
338 | new Symbol ('0', 6, 840),
339 | new Symbol ('1', 5, 841),
340 | new Symbol ('2', 6, 842),
341 | new Symbol ('3', 6, 843),
342 | new Symbol ('4', 6, 844),
343 | new Symbol ('5', 6, 845),
344 | new Symbol ('6', 6, 846),
345 | new Symbol ('7', 6, 847),
346 | new Symbol ('8', 6, 848),
347 | new Symbol ('9', 6, 849),
348 | new Symbol ('/', 6, 850),
349 | // 14 23
350 | new Symbol ('0', 7, 851),
351 | new Symbol ('1', 7, 852),
352 | new Symbol ('2', 7, 853),
353 | new Symbol ('3', 7, 854),
354 | new Symbol ('4', 7, 855),
355 | new Symbol ('5', 7, 856),
356 | new Symbol ('6', 7, 857),
357 | new Symbol ('7', 7, 858),
358 | new Symbol ('8', 7, 859),
359 | new Symbol ('9', 7, 860),
360 | new Symbol (':', 1, 861),
361 | new Symbol ('-', 7, 863),
362 | new Symbol ('/', 6, 864),
363 | new Symbol (' ', 1, 862),
364 | new Symbol ((char)0x4e00, 11, 865),
365 | new Symbol ((char)0x4e8c, 11, 866),
366 | new Symbol ((char)0x4e09, 11, 867),
367 | new Symbol ((char)0x4e94, 11, 868),
368 | new Symbol ((char)0x56db, 11, 869),
369 | new Symbol ((char)0x516d, 11, 870),
370 | new Symbol ((char)0x65e5, 11, 871),
371 | new Symbol ((char)0x5468, 11, 872),
372 | new Symbol ((char)0x9031, 14, 873),
373 | // 15 14
374 | new Symbol ('0', 7, 874),
375 | new Symbol ('1', 7, 875),
376 | new Symbol ('2', 7, 876),
377 | new Symbol ('3', 7, 877),
378 | new Symbol ('4', 7, 878),
379 | new Symbol ('5', 7, 879),
380 | new Symbol ('6', 7, 880),
381 | new Symbol ('7', 7, 881),
382 | new Symbol ('8', 7, 882),
383 | new Symbol ('9', 7, 883),
384 | new Symbol ('-', 7, 884),
385 | new Symbol ('/', 7, 885),
386 | new Symbol ('~', 7, 886),
387 | new Symbol ((char)0x2103, 7, 887),
388 | };
389 | }
390 |
391 | public struct Symbol
392 | {
393 | public char Value { get; set; }
394 | public int Width { get; set; }
395 | public int ResId { get; set; }
396 |
397 | public Symbol(char value, int width, int resId)
398 | {
399 | Value = value;
400 | Width = width;
401 | ResId = resId;
402 | }
403 | }
404 | }
405 |
--------------------------------------------------------------------------------
/src/BipEmulator.Proxy/calend.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | (С) Волков Максим 2019 ( Maxim.N.Volkov@ya.ru )
3 |
4 | Календарь v1.0
5 | Приложение простого календаря.
6 | Алгоритм вычисления дня недели работает для любой даты григорианского календаря позднее 1583 года.
7 | Григорианский календарь начал действовать в 1582 — после 4 октября сразу настало 15 октября.
8 |
9 | Календарь от 1600 до 3000 года
10 | Функции перелистывания каленаря вверх-вниз - месяц, стрелками год
11 | При нажатии на название месяца устанавливается текущая дата
12 |
13 |
14 | v.1.1
15 | - исправлены переходы в при запуске из бстрого меню
16 |
17 | */
18 |
19 | #include "libbip.h"
20 | #include "calend.h"
21 | #define DEBUG_LOG
22 |
23 | // структура меню экрана календаря
24 | struct regmenu_ menu_calend_screen = {
25 | 55,
26 | 1,
27 | 0,
28 | dispatch_calend_screen,
29 | key_press_calend_screen,
30 | calend_screen_job,
31 | 0,
32 | show_calend_screen,
33 | 0,
34 | 0
35 | };
36 |
37 | int main(int param0, char** argv){ // переменная argv не определена
38 | show_calend_screen((void*) param0);
39 | }
40 |
41 | void show_calend_screen (void *param0){
42 | struct calend_** calend_p = (calend_ **)get_ptr_temp_buf_2(); // указатель на указатель на данные экрана
43 | struct calend_ * calend; // указатель на данные экрана
44 | struct calend_opt_ calend_opt; // опции календаря
45 |
46 | #ifdef DEBUG_LOG
47 | log_printf(5, "[show_calend_screen] param0=%X; *temp_buf_2=%X; menu_overlay=%d", (int)param0, (int*)get_ptr_temp_buf_2(), get_var_menu_overlay());
48 | log_printf(5, " #calend_p=%X; *calend_p=%X", (int)calend_p, (int)*calend_p);
49 | #endif
50 |
51 | if ( (param0 == *calend_p) && get_var_menu_overlay()){ // возврат из оверлейного экрана (входящий звонок, уведомление, будильник, цель и т.д.)
52 |
53 | #ifdef DEBUG_LOG
54 | log_printf(5, " #from overlay");
55 | log_printf(5, "\r\n");
56 | #endif
57 |
58 | calend = *calend_p; // указатель на данные необходимо сохранить для исключения
59 | // высвобождения памяти функцией reg_menu
60 | *calend_p = (calend_*)NULL; // обнуляем указатель для передачи в функцию reg_menu
61 |
62 | // создаем новый экран, при этом указатели temp_buf_1 и temp_buf_2 были равны 0 и память не была высвобождена
63 | reg_menu(&menu_calend_screen, 0); // menu_overlay=0
64 |
65 | *calend_p = calend; // восстанавливаем указатель на данные после функции reg_menu
66 |
67 | draw_month(0, calend->month, calend->year);
68 |
69 | } else { // если запуск функции произошел из меню,
70 |
71 | #ifdef DEBUG_LOG
72 | log_printf(5, " #from menu");
73 | log_printf(5, "\r\n");
74 | #endif
75 | // создаем экран
76 | reg_menu(&menu_calend_screen, 0);
77 |
78 | // выделяем необходимую память и размещаем в ней данные
79 | *calend_p = (struct calend_ *)pvPortMalloc(sizeof(struct calend_));
80 | calend = *calend_p; // указатель на данные
81 |
82 | // очистим память под данные
83 | _memclr(calend, sizeof(struct calend_));
84 |
85 | calend->proc = (Elf_proc_*)param0;
86 |
87 | // запомним адрес указателя на функцию в которую необходимо вернуться после завершения данного экрана
88 | if ( param0 && calend->proc->elf_finish ) // если указатель на возврат передан, то возвоащаемся на него
89 | calend->ret_f = calend->proc->elf_finish;
90 | else // если нет, то на циферблат
91 | calend->ret_f = show_watchface;
92 |
93 | struct datetime_ datetime;
94 | _memclr(&datetime, sizeof(struct datetime_));
95 |
96 | // получим текущую дату
97 | get_current_date_time(&datetime);
98 |
99 | calend->day = datetime.day;
100 | calend->month = datetime.month;
101 | calend->year = datetime.year;
102 |
103 | // считаем опции из flash памяти, если значение в флэш-памяти некорректное то берем первую схему
104 | // текущая цветовая схема хранится о смещению 0
105 | ElfReadSettings(calend->proc->index_listed, &calend_opt, OPT_OFFSET_CALEND_OPT, sizeof(struct calend_opt_));
106 |
107 | if (calend_opt.color_scheme < COLOR_SCHEME_COUNT)
108 | calend->color_scheme = calend_opt.color_scheme;
109 | else
110 | calend->color_scheme = 0;
111 |
112 | draw_month(calend->day, calend->month, calend->year);
113 | }
114 |
115 | // при бездействии погасить подсветку и не выходить
116 | set_display_state_value(8, 1);
117 | set_display_state_value(2, 1);
118 |
119 | // таймер на job на 20с где выход.
120 | set_update_period(1, INACTIVITY_PERIOD);
121 |
122 | }
123 |
124 | void draw_month(unsigned int day, unsigned int month, unsigned int year){
125 | struct calend_** calend_p = (calend_ **)get_ptr_temp_buf_2(); // указатель на указатель на данные экрана
126 | struct calend_ * calend = *calend_p; // указатель на данные экрана
127 |
128 |
129 | /*
130 | 0: CALEND_COLOR_BG фон календаря
131 | 1: CALEND_COLOR_MONTH цвет названия текущего месяца
132 | 2: CALEND_COLOR_YEAR цвет текущего года
133 | 3: CALEND_COLOR_WORK_NAME цвет названий дней будни
134 | 4: CALEND_COLOR_HOLY_NAME_BG фон названий дней выходные
135 | 5: CALEND_COLOR_HOLY_NAME_FG цвет названий дней выходные
136 | 6: CALEND_COLOR_SEPAR цвет разделителей календаря
137 | 7: CALEND_COLOR_NOT_CUR_WORK цвет чисел НЕ текущего месяца будни
138 | 8: CALEND_COLOR_NOT_CUR_HOLY_BG фон чисел НЕ текущего месяца выходные
139 | 9: CALEND_COLOR_NOT_CUR_HOLY_FG цвет чисел НЕ текущего месяца выходные
140 | 10: CALEND_COLOR_CUR_WORK цвет чисел текущего месяца будни
141 | 11: CALEND_COLOR_CUR_HOLY_BG фон чисел текущего месяца выходные
142 | 12: CALEND_COLOR_CUR_HOLY_FG цвет чисел текущего месяца выходные
143 | 13: CALEND_COLOR_TODAY_BG фон чисел текущего дня; bit 31 - заливка: =0 заливка цветом фона, =1 только рамка, фон как у числа не текущего месяца
144 | 14: CALEND_COLOR_TODAY_FG цвет чисел текущего дня
145 | */
146 |
147 |
148 | static unsigned char short_color_scheme[COLOR_SCHEME_COUNT][15] =
149 | /* черная тема без выделения выходных*/ {// 0 1 2 3 4 5 6
150 | {COLOR_SH_BLACK, COLOR_SH_YELLOW, COLOR_SH_AQUA, COLOR_SH_WHITE, COLOR_SH_RED, COLOR_SH_WHITE, COLOR_SH_WHITE,
151 | COLOR_SH_GREEN, COLOR_SH_BLACK, COLOR_SH_AQUA, COLOR_SH_YELLOW, COLOR_SH_BLACK, COLOR_SH_WHITE, COLOR_SH_YELLOW, COLOR_SH_BLACK},
152 | // 7 8 9 10 11 12 13 14
153 | // 0 1 2 3 4 5 6
154 | /* белая тема без выделения выходных*/ {COLOR_SH_WHITE, COLOR_SH_BLACK, COLOR_SH_BLUE, COLOR_SH_BLACK, COLOR_SH_RED, COLOR_SH_WHITE, COLOR_SH_BLACK,
155 | COLOR_SH_BLUE, COLOR_SH_WHITE, COLOR_SH_AQUA, COLOR_SH_BLACK, COLOR_SH_WHITE, COLOR_SH_RED, COLOR_SH_BLUE, COLOR_SH_WHITE},
156 | // 7 8 9 10 11 12 13 14
157 | // 0 1 2 3 4 5 6
158 | /* черная тема с выделением выходных*/ {COLOR_SH_BLACK, COLOR_SH_YELLOW, COLOR_SH_AQUA, COLOR_SH_WHITE, COLOR_SH_RED, COLOR_SH_WHITE, COLOR_SH_WHITE,
159 | COLOR_SH_GREEN, COLOR_SH_RED, COLOR_SH_AQUA, COLOR_SH_YELLOW, COLOR_SH_RED, COLOR_SH_WHITE, COLOR_SH_AQUA, COLOR_SH_BLACK},
160 | // 7 8 9 10 11 12 13 14
161 | // 0 1 2 3 4 5 6
162 | /* белая тема с выделением выходных*/ {COLOR_SH_WHITE, COLOR_SH_BLACK, COLOR_SH_BLUE, COLOR_SH_BLACK, COLOR_SH_RED, COLOR_SH_WHITE, COLOR_SH_BLACK,
163 | COLOR_SH_BLUE, COLOR_SH_RED, COLOR_SH_BLUE, COLOR_SH_BLACK, COLOR_SH_RED, COLOR_SH_BLACK, COLOR_SH_BLUE, COLOR_SH_WHITE},
164 | // 7 8 9 10 11 12 13 14
165 | // 0 1 2 3 4 5 6
166 | /* черная тема без выделения выходных*/ {COLOR_SH_BLACK, COLOR_SH_YELLOW, COLOR_SH_AQUA, COLOR_SH_WHITE, COLOR_SH_RED, COLOR_SH_WHITE, COLOR_SH_WHITE,
167 | /*с рамкой выделения сегодняшнего дня*/ COLOR_SH_GREEN, COLOR_SH_BLACK, COLOR_SH_AQUA, COLOR_SH_YELLOW, COLOR_SH_BLACK, COLOR_SH_WHITE, COLOR_SH_AQUA|(1<<7), COLOR_SH_BLACK},
168 | // 7 8 9 10 11 12 13 14
169 |
170 | };
171 |
172 | int color_scheme[COLOR_SCHEME_COUNT][15];
173 |
174 |
175 | for (unsigned char i=0;icolor_scheme][CALEND_COLOR_BG]); // фон календаря
268 | fill_screen_bg();
269 |
270 | set_graph_callback_to_ram_1();
271 | load_font(); // подгружаем шрифты
272 |
273 | _sprintf(&text_buffer[0], " %d", year);
274 | int month_text_width = text_width(monthname[month]);
275 | int year_text_width = text_width(&text_buffer[0]);
276 |
277 | set_fg_color(color_scheme[calend->color_scheme][CALEND_COLOR_MONTH]); // цвет месяца
278 | text_out(monthname[month], (176-month_text_width-year_text_width)/2 ,5); // вывод названия месяца
279 |
280 | set_fg_color(color_scheme[calend->color_scheme][CALEND_COLOR_YEAR]); // цвет года
281 | text_out(&text_buffer[0], (176+month_text_width-year_text_width)/2 ,5); // вывод года
282 |
283 | text_out("←", 5 ,5); // вывод стрелки влево
284 | text_out("→", 176-5-text_width("→"),5); // вывод стрелки вправо
285 |
286 | int calend_name_height = get_text_height();
287 |
288 | set_fg_color(color_scheme[calend->color_scheme][CALEND_COLOR_SEPAR]);
289 | draw_horizontal_line(CALEND_Y_BASE, H_MARGIN, 176-H_MARGIN); // Верхний разделитель названий дней недели
290 | draw_horizontal_line(CALEND_Y_BASE+1+V_MARGIN+calend_name_height+1+V_MARGIN, H_MARGIN, 176-H_MARGIN); // Нижний разделитель названий дней недели
291 | //draw_horizontal_line(175, H_MARGIN, 176-H_MARGIN); // Нижний разделитель месяца
292 |
293 | // Названия дней недели
294 | for (unsigned i=1; (i<=7);i++){
295 | if ( i>5 ){ // выходные
296 | set_bg_color(color_scheme[calend->color_scheme][CALEND_COLOR_HOLY_NAME_BG]);
297 | set_fg_color(color_scheme[calend->color_scheme][CALEND_COLOR_HOLY_NAME_FG]);
298 | } else { // рабочие
299 | set_bg_color(color_scheme[calend->color_scheme][CALEND_COLOR_BG]);
300 | set_fg_color(color_scheme[calend->color_scheme][CALEND_COLOR_WORK_NAME]);
301 | }
302 |
303 |
304 | // отрисовка фона названий выходных
305 | int pos_x1 = H_MARGIN +(i-1)*(WIDTH + H_SPACE);
306 | int pos_y1 = CALEND_Y_BASE+V_MARGIN+1;
307 | int pos_x2 = pos_x1 + WIDTH;
308 | int pos_y2 = pos_y1 + calend_name_height;
309 |
310 | // фон для каждого названия дня недели
311 | draw_filled_rect_bg(pos_x1, pos_y1, pos_x2, pos_y2);
312 |
313 | // вывод названий дней недели. если ширина названия больше чем ширина поля, выводим короткие названия
314 | if (text_width(weekday_string[1]) <= (WIDTH - 2))
315 | text_out_center(weekday_string[i], pos_x1 + WIDTH/2, pos_y1 + (calend_name_height-get_text_height())/2 );
316 | else
317 | text_out_center(weekday_string_short[i], pos_x1 + WIDTH/2, pos_y1 + (calend_name_height-get_text_height())/2 );
318 | }
319 |
320 |
321 | int calend_days_y_base = CALEND_Y_BASE+1+V_MARGIN+calend_name_height+V_MARGIN+1;
322 |
323 | if (isLeapYear(year)>0) day_month[2]=29;
324 |
325 | unsigned char d=wday(1,month, year);
326 | unsigned char m=month;
327 | if (d>1) {
328 | m=(month==1)?12:month-1;
329 | d=day_month[m]-d+2;
330 | }
331 |
332 | // числа месяца
333 | for (unsigned i=1; (i<=7*6);i++){
334 |
335 | unsigned char row = (i-1)/7;
336 | unsigned char col = (i-1)%7+1;
337 |
338 | _sprintf (&text_buffer[0], "%2.0d", d);
339 |
340 | int bg_color = 0;
341 | int fg_color = 0;
342 | int frame_color = 0; // цветрамки
343 | int frame = 0; // 1-рамка; 0 - заливка
344 |
345 | // если текущий день текущего месяца
346 | if ( (m==month)&&(d==day) ){
347 |
348 | if ( color_scheme[calend->color_scheme][CALEND_COLOR_TODAY_BG] & (1<<31) ) {// если заливка отключена только рамка
349 |
350 | // цвет рамки устанавливаем CALEND_COLOR_TODAY_BG, фон внутри рамки и цвет текста такой же как был
351 | frame_color = (color_scheme[calend->color_scheme][CALEND_COLOR_TODAY_BG &COLOR_MASK]);
352 | // рисуем рамку
353 | frame = 1;
354 |
355 | if ( col > 5 ){ // если выходные
356 | bg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_CUR_HOLY_BG]);
357 | fg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_CUR_HOLY_FG]);
358 | } else { // если будни
359 | bg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_BG]);
360 | fg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_CUR_WORK]);
361 | };
362 |
363 | } else { // если включена заливка
364 | if ( col > 5 ){ // если выходные
365 | bg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_TODAY_BG] & COLOR_MASK);
366 | fg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_TODAY_FG]);
367 | } else { // если будни
368 | bg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_TODAY_BG] &COLOR_MASK);
369 | fg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_TODAY_FG]);
370 | };
371 | };
372 |
373 |
374 | } else {
375 | if ( col > 5 ){ // если выходные
376 | if (month == m){
377 | bg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_CUR_HOLY_BG]);
378 | fg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_CUR_HOLY_FG]);
379 | } else {
380 | bg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_NOT_CUR_HOLY_BG]);
381 | fg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_NOT_CUR_HOLY_FG]);
382 | }
383 | } else { // если будни
384 | if (month == m){
385 | bg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_BG]);
386 | fg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_CUR_WORK]);
387 | } else {
388 | bg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_BG]);
389 | fg_color = (color_scheme[calend->color_scheme][CALEND_COLOR_NOT_CUR_WORK]);
390 | }
391 | }
392 | }
393 |
394 |
395 |
396 | // строка: от 7 до 169 = 162рх в ширину 7 чисел по 24рх на число 7+(22+2)*6+22+3
397 | // строки: от 57 до 174 = 117рх в высоту 6 строк по 19рх на строку 1+(17+2)*5+18
398 |
399 | // отрисовка фона числа
400 | int pos_x1 = H_MARGIN +(col-1)*(WIDTH + H_SPACE);
401 | int pos_y1 = calend_days_y_base + V_MARGIN + row *(HEIGHT + V_SPACE)+1;
402 | int pos_x2 = pos_x1 + WIDTH;
403 | int pos_y2 = pos_y1 + HEIGHT;
404 |
405 | if (frame){
406 | // выводим число
407 | set_bg_color(bg_color);
408 | set_fg_color(fg_color);
409 | text_out_center(&text_buffer[0], pos_x1+WIDTH/2, pos_y1+(HEIGHT-get_text_height())/2);
410 |
411 | // рисуем рамку
412 | set_fg_color(frame_color);
413 | draw_rect(pos_x1, pos_y1, pos_x2-1, pos_y2-1);
414 | } else {
415 | // рисуем заливку
416 | set_bg_color(bg_color);
417 | draw_filled_rect_bg(pos_x1, pos_y1, pos_x2, pos_y2);
418 |
419 | // выводим число
420 | set_fg_color(fg_color);
421 | text_out_center(&text_buffer[0], pos_x1+WIDTH/2, pos_y1+(HEIGHT-get_text_height())/2);
422 | };
423 |
424 |
425 |
426 |
427 | if ( d < day_month[m] ) {
428 | d++;
429 | } else {
430 | d=1;
431 | m=(m==12)?1:(m+1);
432 | }
433 | }
434 |
435 |
436 |
437 | };
438 |
439 | unsigned char wday(unsigned int day,unsigned int month,unsigned int year)
440 | {
441 | signed int a = (14 - month) / 12;
442 | signed int y = year - a;
443 | signed int m = month + 12 * a - 2;
444 | return 1+(((day + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7) +6)%7;
445 | }
446 |
447 | unsigned char isLeapYear(unsigned int year){
448 | unsigned char result = 0;
449 | if ( (year % 4) == 0 ) result++;
450 | if ( (year % 100) == 0 ) result--;
451 | if ( (year % 400) == 0 ) result++;
452 | return result;
453 | }
454 |
455 | void key_press_calend_screen(){
456 | struct calend_** calend_p = (calend_ **)get_ptr_temp_buf_2(); // указатель на указатель на данные экрана
457 | struct calend_ * calend = *calend_p; // указатель на данные экрана
458 |
459 | show_menu_animate(calend->ret_f, (unsigned int)show_calend_screen, ANIMATE_RIGHT);
460 | };
461 |
462 |
463 | void calend_screen_job(){
464 | struct calend_** calend_p = (calend_ **)get_ptr_temp_buf_2(); // указатель на указатель на данные экрана
465 | struct calend_ * calend = *calend_p; // указатель на данные экрана
466 |
467 | // при достижении таймера обновления выходим
468 | show_menu_animate(calend->ret_f, (unsigned int)show_calend_screen, ANIMATE_LEFT);
469 | }
470 |
471 | int dispatch_calend_screen (void *param){
472 | struct calend_** calend_p = (calend_ **)get_ptr_temp_buf_2(); // указатель на указатель на данные экрана
473 | struct calend_ * calend = *calend_p; // указатель на данные экрана
474 |
475 | struct calend_opt_ calend_opt; // опции календаря
476 |
477 | struct datetime_ datetime;
478 | // получим текущую дату
479 |
480 |
481 | get_current_date_time(&datetime);
482 | unsigned int day;
483 |
484 | // char text_buffer[32];
485 | struct gesture_ *gest = (gesture_*) param;
486 | int result = 0;
487 |
488 | switch (gest->gesture){
489 | case GESTURE_CLICK: {
490 |
491 | // вибрация при любом нажатии на экран
492 | vibrate (1, 40, 0);
493 |
494 |
495 | if ( gest->touch_pos_y < CALEND_Y_BASE ){ // кликнули по верхней строке
496 | if (gest->touch_pos_x < 44){
497 | if ( calend->year > 1600 ) calend->year--;
498 | } else
499 | if (gest->touch_pos_x > (176-44)){
500 | if ( calend->year < 3000 ) calend->year++;
501 | } else {
502 | calend->day = datetime.day;
503 | calend->month = datetime.month;
504 | calend->year = datetime.year;
505 | }
506 |
507 | if ( (calend->year == datetime.year) && (calend->month == datetime.month) ){
508 | day = datetime.day;
509 | } else {
510 | day = 0;
511 | }
512 | draw_month(day, calend->month, calend->year);
513 | repaint_screen_lines(1, 176);
514 |
515 | } else { // кликнули в календарь
516 |
517 | calend->color_scheme = ((calend->color_scheme+1)%COLOR_SCHEME_COUNT);
518 |
519 | // сначала обновим экран
520 | if ( (calend->year == datetime.year) && (calend->month == datetime.month) ){
521 | day = datetime.day;
522 | } else {
523 | day = 0;
524 | }
525 | draw_month(day, calend->month, calend->year);
526 | repaint_screen_lines(1, 176);
527 |
528 | // потом запись опций во flash память, т.к. это долгая операция
529 | // TODO: 1. если опций будет больше чем цветовая схема - переделать сохранение, чтобы сохранять перед выходом.
530 | calend_opt.color_scheme = calend->color_scheme;
531 |
532 | // запишем настройки в флэш память
533 | ElfWriteSettings(calend->proc->index_listed, &calend_opt, OPT_OFFSET_CALEND_OPT, sizeof(struct calend_opt_));
534 | }
535 |
536 | // продлить таймер выхода при бездействии через INACTIVITY_PERIOD с
537 | set_update_period(1, INACTIVITY_PERIOD);
538 | break;
539 | };
540 |
541 | case GESTURE_SWIPE_RIGHT: // свайп направо
542 | case GESTURE_SWIPE_LEFT: { // справа налево
543 |
544 | if ( get_left_side_menu_active()){
545 | set_update_period(0,0);
546 |
547 | void* show_f = get_ptr_show_menu_func();
548 |
549 | // запускаем dispatch_left_side_menu с параметром param в результате произойдет запуск соответствующего бокового экрана
550 | // при этом произойдет выгрузка данных текущего приложения и его деактивация.
551 | dispatch_left_side_menu((gesture_*)param);
552 |
553 | if ( get_ptr_show_menu_func() == show_f ){
554 | // если dispatch_left_side_menu отработал безуспешно (листать некуда) то в show_menu_func по прежнему будет
555 | // содержаться наша функция show_calend_screen, тогда просто игнорируем этот жест
556 |
557 | // продлить таймер выхода при бездействии через INACTIVITY_PERIOD с
558 | set_update_period(1, INACTIVITY_PERIOD);
559 | return 0;
560 | }
561 |
562 |
563 | // если dispatch_left_side_menu отработал, то завершаем наше приложение, т.к. данные экрана уже выгрузились
564 | // на этом этапе уже выполняется новый экран (тот куда свайпнули)
565 |
566 |
567 | Elf_proc_* proc = get_proc_by_addr(main);
568 | proc->ret_f = NULL;
569 |
570 | elf_finish(main); // выгрузить Elf из памяти
571 | return 0;
572 | } else { // если запуск не из быстрого меню, обрабатываем свайпы по отдельности
573 | switch (gest->gesture){
574 | case GESTURE_SWIPE_RIGHT: { // свайп направо
575 | return show_menu_animate(calend->ret_f, (unsigned int)show_calend_screen, ANIMATE_RIGHT);
576 | break;
577 | }
578 | case GESTURE_SWIPE_LEFT: { // справа налево
579 | // действие при запуске из меню и дальнейший свайп влево
580 |
581 |
582 | break;
583 | }
584 | } /// switch (gest->gesture)
585 | }
586 |
587 | break;
588 | }; // case GESTURE_SWIPE_LEFT:
589 |
590 |
591 | case GESTURE_SWIPE_UP: { // свайп вверх
592 | if ( calend->month < 12 )
593 | calend->month++;
594 | else {
595 | calend->month = 1;
596 | calend->year++;
597 | }
598 |
599 | if ( (calend->year == datetime.year) && (calend->month == datetime.month) )
600 | day = datetime.day;
601 | else
602 | day = 0;
603 | draw_month(day, calend->month, calend->year);
604 | repaint_screen_lines(1, 176);
605 |
606 | // продлить таймер выхода при бездействии через INACTIVITY_PERIOD с
607 | set_update_period(1, INACTIVITY_PERIOD);
608 | break;
609 | };
610 | case GESTURE_SWIPE_DOWN: { // свайп вниз
611 | if ( calend->month > 1 )
612 | calend->month--;
613 | else {
614 | calend->month = 12;
615 | calend->year--;
616 | }
617 |
618 | if ( (calend->year == datetime.year) && (calend->month == datetime.month) )
619 | day = datetime.day;
620 | else
621 | day = 0;
622 | draw_month(day, calend->month, calend->year);
623 | repaint_screen_lines(1, 176);
624 |
625 | // продлить таймер выхода при бездействии через INACTIVITY_PERIOD с
626 | set_update_period(1, INACTIVITY_PERIOD);
627 | break;
628 | };
629 | default:{ // что-то пошло не так...
630 | break;
631 | };
632 |
633 | }
634 |
635 |
636 | return result;
637 | };
638 |
--------------------------------------------------------------------------------
/src/BipEmulator.Host/MainForm.cs:
--------------------------------------------------------------------------------
1 | using BipEmulatorProxy;
2 | using System;
3 | using System.Diagnostics;
4 | using System.Drawing;
5 | using System.Globalization;
6 | using System.IO;
7 | using System.IO.MemoryMappedFiles;
8 | using System.Linq;
9 | using System.Reflection;
10 | using System.Runtime.InteropServices;
11 | using System.Text;
12 | using System.Windows.Forms;
13 |
14 | namespace BipEmulator.Host
15 | {
16 | public partial class MainForm : Form, IMessageFilter
17 | {
18 | const int VIDEO_MEMORY_SIZE = 15488;
19 | ///
20 | /// Функция обратного вызова
21 | ///
22 | private static ProxyLib.Callback _callback;
23 |
24 | Point _mouseDownPoint;
25 |
26 | private ResFile _systemResFile = null;
27 | private ResFile _userResFile = null;
28 |
29 | private LocalSettings _settings;
30 |
31 | private int _newDebugOutputLines = 0;
32 |
33 | private IntPtr _hrmDataPointer = IntPtr.Zero;
34 |
35 | private bool _useSharedVideoMemory;
36 | MemoryMappedFile _sharedMemoryFile;
37 | MemoryMappedViewStream _sharedMemoryViewStream;
38 | private byte[] _videoMemory = new byte[VIDEO_MEMORY_SIZE];
39 |
40 | public MainForm()
41 | {
42 | InitializeComponent();
43 | // установим фильтр для отлова клавиатурных сообщений
44 | Application.AddMessageFilter(this);
45 |
46 | // locale
47 | foreach (var locale in Enum.GetValues(typeof(LocaleEnum)))
48 | {
49 | var name = DisplayNameAttribute.GetName(locale);
50 | cbLocale.Items.Add(name);
51 | }
52 |
53 | _settings = LocalSettings.Load();
54 | FillFormValuesFromSettings();
55 |
56 | // устанавливаем обработчики на мышь для
57 | // создания событий по свайпам
58 | ucScreen.MouseDown += WatchScreen_MouseDown;
59 | ucScreen.MouseUp += WatchScreen_MouseUp;
60 | ucScreen.MouseMove += WatchScreen_MouseMove;
61 | ucScreen.MouseLeave += WatchScreen_MouseLeave;
62 |
63 | // информация о версии
64 | var version = Assembly.GetEntryAssembly()?.GetName().Version;
65 | base.Text = $"Bip Emulator v{version.Major}.{version.Minor}";
66 | }
67 |
68 | private void MainForm_Load(object sender, EventArgs e)
69 | {
70 | // пробуем загрузить файл шрифтов
71 | if (string.IsNullOrEmpty(tbFontFilename.Text) || !File.Exists(tbFontFilename.Text))
72 | {
73 | MessageBox.Show("Font file don't exist or not selected!" + Environment.NewLine + "Check Options Tab!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
74 | }
75 |
76 | // регистрируем функцию обратного вызова
77 | _callback = new ProxyLib.Callback(CallbackParser);
78 | ProxyLib.RegisterCallback(_callback);
79 |
80 | // запускаем на выполнение программу, которая эмулируется
81 | ProxyLib.MainRun();
82 | }
83 |
84 | ///
85 | /// Разгребатель прилетевших от прокси обратных вызовов функций
86 | ///
87 | /// аргументы функций
88 | ///
89 | private unsafe object CallbackParser(object[] args)
90 | {
91 | if (args == null || args.Length == 0 || args[0] == null)
92 | return null;
93 |
94 | switch(args[0])
95 | {
96 | // Отрабатываем все функции графического отображения и относящиеся к ним
97 |
98 | case FunctionNames.DRAW_FILLED_RECT:
99 | ucScreen.DrawFilledRect((int)args[1], (int)args[2], (int)args[3], (int)args[4]);
100 | break;
101 |
102 | case FunctionNames.DRAW_FILLED_RECT_BG:
103 | ucScreen.DrawFilledRectBg((int)args[1], (int)args[2], (int)args[3], (int)args[4]);
104 | break;
105 |
106 | case FunctionNames.DRAW_RECT:
107 | ucScreen.DrawRect((int)args[1], (int)args[2], (int)args[3], (int)args[4]);
108 | break;
109 |
110 | case FunctionNames.DRAW_HORIZONTAL_LINE:
111 | ucScreen.DrawLine((int)args[2], (int)args[1], (int)args[3], (int)args[1]);
112 | break;
113 |
114 | case FunctionNames.DRAW_VERTICAL_LINE:
115 | ucScreen.DrawLine((int)args[1], (int)args[2], (int)args[1], (int)args[3]);
116 | break;
117 |
118 | case FunctionNames.FILL_SCREEN_BG:
119 | ucScreen.FillScreenBg();
120 | break;
121 |
122 | case FunctionNames.TEXT_OUT:
123 | ucScreen.TextOut(args[1].ToString(), (int)args[2], (int)args[3]);
124 | break;
125 |
126 | case FunctionNames.TEXT_OUT_CENTER:
127 | ucScreen.TextOutCenter(args[1].ToString(), (int)args[2], (int)args[3]);
128 | break;
129 |
130 | case FunctionNames.SET_FG_COLOR:
131 | ucScreen.SetFgColor(WatchScreen.GetColorFromGRBInt((int)args[1]));
132 | break;
133 |
134 | case FunctionNames.SET_BG_COLOR:
135 | ucScreen.SetBgColor(WatchScreen.GetColorFromGRBInt((int)args[1]));
136 | break;
137 |
138 | case FunctionNames.GET_TEXT_HEIGHT:
139 | return ucScreen.GetTextHeight();
140 |
141 | case FunctionNames.TEXT_WIDTH:
142 | return ucScreen.GetTextWidth(args[1].ToString());
143 |
144 | case FunctionNames.REPAINT_SCREEN_LINES:
145 |
146 | if (_useSharedVideoMemory)
147 | {
148 | _sharedMemoryViewStream.Position = 0;
149 | _sharedMemoryViewStream.Read(_videoMemory, 0, 15488);
150 | ucScreen.SetVideoData(_videoMemory);
151 | }
152 | ucScreen.RepaintScreenLines((int)args[1], (int)args[2]);
153 |
154 | if (ucScreen.InvokeRequired)
155 | {
156 | try
157 | {
158 | Invoke(new Action(() =>
159 | {
160 | ucScreen.Refresh();
161 | }));
162 | }
163 | catch
164 | {
165 | Debug.WriteLine("Exception CallbackParser REPAINT_SCREEN_LINES");
166 | }
167 | }
168 | else
169 | ucScreen.Refresh();
170 | break;
171 |
172 | case FunctionNames.SHOW_ELF_RES_BY_ID:
173 | try
174 | {
175 | if (_userResFile == null)
176 | {
177 | _userResFile = ResFile.Load(tbUserResFile.Text);
178 | }
179 |
180 | var resImage = new ResImage(_userResFile.Resources[(int)args[2]]);
181 | ucScreen.DrawImage(resImage.Bitmap, (int)args[3], (int)args[4]);
182 | }
183 | catch
184 | {
185 | Debug.WriteLine("Exception CallbackParser SHOW_ELF_RES_BY_ID");
186 | }
187 |
188 | return 0;
189 |
190 | case FunctionNames.SHOW_RES_BY_ID:
191 | ShowResById((int)args[1], (int)args[2], (int)args[3]);
192 | return 0;
193 |
194 | case FunctionNames.GET_RES_PARAMS:
195 | {
196 | var res = GetUserResImage((int)args[2]);
197 | if (res == null)
198 | return -1;
199 |
200 | var bmp = res.Bitmap;
201 |
202 | var param = new ResParam { Width = (short)bmp.Width, Height = (short)bmp.Height };
203 | CopyStructToUnmanagedMemory(param, (IntPtr)args[3]);
204 | return 0;
205 | }
206 | case FunctionNames.READ_ELF_RES_BY_ID:
207 | {
208 | // only own resources
209 | if ((int)args[1] != -1)
210 | return -1;
211 |
212 | var data = GetUserResData(/*resId*/(int)args[2],/*offset*/(int)args[3], (int)args[5]/*len*/);
213 | Marshal.Copy(data, 0, (IntPtr)args[4], data.Length);
214 | return 0;
215 | }
216 | case FunctionNames.SHOW_BIG_DIGITS:
217 | ShowBigDigit((int)args[1], args[2].ToString(), (int)args[3], (int)args[4], (int)args[5]);
218 | break;
219 |
220 | case FunctionNames.LOG_PRINTF:
221 | DebugWriteLine(args[1].ToString());
222 | return 0;
223 |
224 | case FunctionNames.GET_LAST_HEARTRATE:
225 | int heartRate = 0;
226 | if (nudHeartRate.InvokeRequired)
227 | Invoke(new Action(() =>
228 | {
229 | heartRate = (int)nudHeartRate.Value;
230 | }));
231 | else
232 | heartRate = (int)nudHeartRate.Value;
233 | return heartRate;
234 |
235 | case FunctionNames.GET_HRM_STRUCT:
236 | HrmData hrmData = new HrmData();
237 | if (nudHeartRate.InvokeRequired)
238 | {
239 | Invoke(new Action(() =>
240 | {
241 | hrmData = new HrmData
242 | {
243 | heart_rate = (byte)nudHeartRate.Value,
244 | last_hr = (byte)nudHeartRate.Value,
245 | ret_code = (byte)(cbHeartRateMeasurementComplited.Checked ? 0 : 5)
246 | };
247 | }));
248 | }
249 | else
250 | hrmData = new HrmData
251 | {
252 | heart_rate = (byte)nudHeartRate.Value,
253 | last_hr = (byte)nudHeartRate.Value,
254 | ret_code = (byte)(cbHeartRateMeasurementComplited.Checked ? 0 : 5)
255 | };
256 |
257 |
258 | if (_hrmDataPointer == IntPtr.Zero)
259 | _hrmDataPointer = Marshal.AllocHGlobal(Marshal.SizeOf(hrmData));
260 | Marshal.StructureToPtr(hrmData, _hrmDataPointer, false);
261 | return _hrmDataPointer.ToInt32();
262 |
263 | case FunctionNames.GET_NAVI_DATA:
264 | NaviData naviData = new NaviData();
265 | if (cbGeoLocationMeasurementComplited.InvokeRequired)
266 | {
267 | Invoke(new Action(() =>
268 | {
269 | var alt = GetFloatFromText(tbAltitude.Text);
270 | var lat = GetFloatFromText(tbLatitude.Text);
271 | var lon = GetFloatFromText(tbLongitude.Text);
272 |
273 | naviData = new NaviData
274 | {
275 | ready = (cbPressureMeasurementComplited.Checked ? 1 : 0) | (cbGeoLocationMeasurementComplited.Checked ? 0x0e : 0),
276 | pressure = (uint)((float)nudPressure.Value * 133.322f),
277 | altitude = alt,
278 | latitude = (int)(3e6 * Math.Abs(lat)),
279 | ns = lat < 0 ? 0 : 1,
280 | longitude = (int)(3e6 * Math.Abs(lon)),
281 | ew = lon < 0 ? 2 : 3
282 | };
283 | }));
284 | }
285 | else
286 | {
287 | var alt = GetFloatFromText(tbAltitude.Text);
288 | var lat = GetFloatFromText(tbLatitude.Text);
289 | var lon = GetFloatFromText(tbLongitude.Text);
290 |
291 | naviData = new NaviData
292 | {
293 | ready = (cbPressureMeasurementComplited.Checked ? 1 : 0) | (cbGeoLocationMeasurementComplited.Checked ? 0x0e : 0),
294 | pressure = (uint)((float)nudPressure.Value * 133.322f),
295 | altitude = alt,
296 | latitude = (int)(3e6 * Math.Abs(lat)),
297 | ns = lat < 0 ? 1 : 0,
298 | longitude = (int)(3e6 * Math.Abs(lon)),
299 | ew = lon < 0 ? 2 : 3
300 | };
301 | }
302 | CopyStructToUnmanagedMemory(naviData, (IntPtr)args[1]);
303 | break;
304 |
305 | case FunctionNames.IS_GPS_FIXED:
306 | int isGpsFixed = 0;
307 | if (cbGeoLocationMeasurementComplited.InvokeRequired)
308 | {
309 | Invoke(new Action(() =>
310 | {
311 | isGpsFixed = cbGeoLocationMeasurementComplited.Checked ? 1 : 0;
312 | }));
313 | }
314 | else
315 | isGpsFixed = cbGeoLocationMeasurementComplited.Checked ? 1 : 0;
316 | return isGpsFixed;
317 |
318 | case FunctionNames.GET_SELECTED_LOCALE:
319 | LocaleEnum locale = LocaleEnum.ru_RU;
320 | if (cbLocale.InvokeRequired)
321 | {
322 | Invoke(new Action(() =>
323 | {
324 | locale = GetCurrentLocale();
325 | }));
326 | }
327 | else
328 | {
329 | locale = GetCurrentLocale();
330 | }
331 | return (int)locale;
332 |
333 | case FunctionNames.SHARED_MEMORY_ENABLED:
334 | _useSharedVideoMemory = OpenFileMapping();
335 | return _useSharedVideoMemory ? 1 : 0;
336 |
337 | // заглушки
338 |
339 | case FunctionNames.VIBRATE:
340 | case FunctionNames.SET_UPDATE_PERIOD:
341 | return 0;
342 |
343 | case FunctionNames.LOAD_FONT:
344 | case FunctionNames.REG_MENU:
345 | break;
346 |
347 | default:
348 | Debug.WriteLine($"UNKNOWN FUNCTION: {args[0]}");
349 | break;
350 |
351 | }
352 | return null;
353 | }
354 |
355 | private bool OpenFileMapping()
356 | {
357 | try
358 | {
359 | _sharedMemoryFile = MemoryMappedFile.OpenExisting("meme", MemoryMappedFileRights.ReadWrite);
360 | _sharedMemoryViewStream = _sharedMemoryFile.CreateViewStream();
361 | }
362 | catch(Exception e)
363 | {
364 | return false;
365 | }
366 |
367 | return true;
368 | }
369 |
370 | private LocaleEnum GetCurrentLocale()
371 | {
372 | foreach (LocaleEnum locale in Enum.GetValues(typeof(LocaleEnum)))
373 | {
374 | if (DisplayNameAttribute.GetName(locale).Equals(cbLocale.SelectedItem))
375 | {
376 | return locale;
377 | }
378 | }
379 | return LocaleEnum.ru_RU;
380 | }
381 |
382 | private float GetFloatFromText(string str)
383 | {
384 | if (string.IsNullOrEmpty(str))
385 | return 0f;
386 |
387 | float res;
388 | if (float.TryParse(str, out res))
389 | return res;
390 |
391 | if (float.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out res))
392 | return res;
393 |
394 | return 0f;
395 | }
396 |
397 | private unsafe void CopyStructToUnmanagedMemory(T t, IntPtr dst) where T : struct
398 | {
399 | IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(t));
400 | Marshal.StructureToPtr(t, pnt, false);
401 | Buffer.MemoryCopy(pnt.ToPointer(), dst.ToPointer(), Marshal.SizeOf(t), Marshal.SizeOf(t));
402 | Marshal.FreeHGlobal(pnt);
403 | }
404 |
405 | private byte[] GetUserResData(int resId, int offset, int len)
406 | {
407 | try
408 | {
409 | if (_userResFile == null)
410 | {
411 | _userResFile = ResFile.Load(tbUserResFile.Text);
412 | var data = new byte[len];
413 | if (offset + len > _userResFile.Resources[resId].Length)
414 | return null;
415 | Buffer.BlockCopy(_userResFile.Resources[resId], 0, data, 0, len);
416 | return data;
417 | }
418 | }
419 | catch
420 | {
421 | Debug.WriteLine("Exception GetUserResData");
422 | }
423 | return null;
424 | }
425 |
426 | private ResImage GetUserResImage(int resId)
427 | {
428 | try
429 | {
430 | if (_userResFile == null)
431 | {
432 | _userResFile = ResFile.Load(tbUserResFile.Text);
433 | }
434 |
435 | return new ResImage(_userResFile.Resources[resId]);
436 | }
437 | catch
438 | {
439 | Debug.WriteLine("Exception GetUserResImage");
440 | }
441 | return null;
442 | }
443 |
444 | private ResImage GetSystemResImage(int resId)
445 | {
446 | try
447 | {
448 | if (_systemResFile == null)
449 | {
450 | _systemResFile = ResFile.Load(tbSystemResFile.Text);
451 | }
452 |
453 | return new ResImage(_systemResFile.Resources[resId]);
454 | }
455 | catch
456 | {
457 | Debug.WriteLine("Exception GetSystemResImage");
458 | }
459 | return null;
460 | }
461 |
462 | private void ShowResById(int resId, int x, int y)
463 | {
464 | var resImage = GetSystemResImage(resId);
465 | if (resImage == null)
466 | return;
467 |
468 | ucScreen.DrawImage(resImage.Bitmap, x, y);
469 | }
470 |
471 | private void ShowBigDigit(int symbolSet, string value, int x, int y, int space)
472 | {
473 | for(var i=0; i
487 | /// Перехватываем сообщения с клавиатуры и передаем их прокси
488 | ///
489 | ///
490 | public bool PreFilterMessage(ref Message m)
491 | {
492 | if (m.Msg != 0x0100)
493 | return false;
494 |
495 | switch ((Keys)m.WParam.ToInt32())
496 | {
497 | case Keys.Up:
498 | lblAction.Text = "Swipe Up";
499 | ProxyLib.RegMenuDispatchScreen((byte)GestureEnum.GESTURE_SWIPE_UP, 0, 0);
500 | btnSwipeUp.Focus();
501 | break;
502 | case Keys.Down:
503 | lblAction.Text = "Swipe Down";
504 | ProxyLib.RegMenuDispatchScreen((byte)GestureEnum.GESTURE_SWIPE_DOWN, 0, 0);
505 | btnSwipeDown.Focus();
506 | break;
507 | case Keys.Left:
508 | lblAction.Text = "Swipe Left";
509 | ProxyLib.RegMenuDispatchScreen((byte)GestureEnum.GESTURE_SWIPE_LEFT, 0, 0);
510 | btnSwipeLeft.Focus();
511 | break;
512 | case Keys.Right:
513 | lblAction.Text = "Swipe Right";
514 | ProxyLib.RegMenuDispatchScreen((byte)GestureEnum.GESTURE_SWIPE_RIGHT, 0, 0);
515 | btnSwipeRight.Focus();
516 | break;
517 | default:
518 | return false;
519 | }
520 |
521 | return true;
522 | }
523 |
524 | private void WatchScreen_MouseUp(object sender, MouseEventArgs e)
525 | {
526 | var dx = e.X - _mouseDownPoint.X;
527 | var dy = e.Y - _mouseDownPoint.Y;
528 |
529 | if (Math.Abs(dx) < _settings.MaxDistanceClick && Math.Abs(dy) < _settings.MaxDistanceClick)
530 | {
531 | lblAction.Text = "Click";
532 | ProxyLib.RegMenuDispatchScreen((byte)GestureEnum.GESTURE_CLICK, _mouseDownPoint.X, _mouseDownPoint.Y);
533 | btnClick.Focus();
534 | }
535 | else if (Math.Abs(dx) > Math.Abs(dy))
536 | {
537 | lblAction.Text = dx < 0 ? "Swipe Left" : "Swipe Right";
538 | ProxyLib.RegMenuDispatchScreen(dx < 0 ? (byte)GestureEnum.GESTURE_SWIPE_LEFT : (byte)GestureEnum.GESTURE_SWIPE_RIGHT, e.X, e.Y);
539 | if (dx < 0)
540 | btnSwipeLeft.Focus();
541 | else
542 | btnSwipeRight.Focus();
543 | }
544 | else
545 | {
546 | lblAction.Text = dy < 0 ? "Swipe Up" : "Swipe Down";
547 | ProxyLib.RegMenuDispatchScreen(dy < 0 ? (byte)GestureEnum.GESTURE_SWIPE_UP : (byte)GestureEnum.GESTURE_SWIPE_DOWN, e.X, e.Y);
548 | if (dy < 0)
549 | btnSwipeUp.Focus();
550 | else
551 | btnSwipeDown.Focus();
552 | }
553 | }
554 |
555 | private void WatchScreen_MouseMove(object sender, MouseEventArgs e)
556 | {
557 | lblMouseLocation.Text = $"X: {e.X}\r\nY: {e.Y}";
558 | }
559 |
560 | private void WatchScreen_MouseLeave(object sender, EventArgs e)
561 | {
562 | lblMouseLocation.Text = string.Empty;
563 | }
564 |
565 | private void WatchScreen_MouseDown(object sender, MouseEventArgs e)
566 | {
567 | _mouseDownPoint = e.Location;
568 | }
569 |
570 | ///
571 | /// При закрытии формы все очищаем и сохраняем настройки
572 | ///
573 | private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
574 | {
575 | ProxyLib.UnregisterCallback();
576 |
577 | FillSettingsFromFormValues();
578 | _settings.Save();
579 | }
580 |
581 | ///
582 | /// Заполняем значения элементов формы параметрами из сохраненных настроек
583 | ///
584 | private void FillFormValuesFromSettings()
585 | {
586 | nudHeartRate.Value = _settings.HeartRate;
587 | cbHeartRateMeasurementComplited.Checked = _settings.HeartRateMeasurementCompleted;
588 | tbLatitude.Text = _settings.Latitude.ToString("F6");
589 | tbLongitude.Text = _settings.Longitude.ToString("F6");
590 | tbAltitude.Text = _settings.Altitude.ToString("F2");
591 | cbGeoLocationMeasurementComplited.Checked = _settings.GeoLocationMeasurementCompleted;
592 | nudPressure.Value = _settings.Pressure;
593 | cbPressureMeasurementComplited.Checked = _settings.PressureMeasurementCompleted;
594 | cbLocale.SelectedItem = DisplayNameAttribute.GetName(_settings.Locale);
595 | tbFontFilename.Text = _settings.FontFilename;
596 | tbSystemResFile.Text = _settings.SystemResourceFilename;
597 | tbUserResFile.Text = _settings.UserResourceFilename;
598 | ucScreen.Colors = _settings.Colors;
599 |
600 | cbLocale.SelectedItem = DisplayNameAttribute.GetName(_settings.Locale);
601 |
602 | if (File.Exists(tbFontFilename.Text))
603 | ucScreen.SetFontFile(tbFontFilename.Text);
604 | }
605 |
606 | ///
607 | /// Заполняем настройки для сохранения параметрами из элементов формы
608 | ///
609 | private void FillSettingsFromFormValues()
610 | {
611 | _settings.HeartRate = (int)nudHeartRate.Value;
612 | _settings.HeartRateMeasurementCompleted = cbHeartRateMeasurementComplited.Checked;
613 | _settings.Latitude = double.Parse(tbLatitude.Text);
614 | _settings.Longitude = double.Parse(tbLongitude.Text);
615 | _settings.Altitude = double.Parse(tbAltitude.Text);
616 | _settings.GeoLocationMeasurementCompleted = cbGeoLocationMeasurementComplited.Checked;
617 | _settings.Pressure = (int)nudPressure.Value;
618 | _settings.PressureMeasurementCompleted = cbPressureMeasurementComplited.Checked;
619 | _settings.Locale = GetCurrentLocale();
620 | _settings.FontFilename = tbFontFilename.Text;
621 | _settings.SystemResourceFilename = tbSystemResFile.Text;
622 | _settings.UserResourceFilename = tbUserResFile.Text;
623 | _settings.Colors = ucScreen.Colors;
624 | }
625 |
626 | private void btnClose_Click(object sender, EventArgs e)
627 | {
628 | Close();
629 | }
630 |
631 | ///
632 | /// Настройка цветовых параметров
633 | ///
634 | private void btnColorsSelect_Click(object sender, EventArgs e)
635 | {
636 | var frm = new ColorSelectionForm(ucScreen.Colors);
637 | if (frm.ShowDialog() == DialogResult.OK)
638 | {
639 | ucScreen.Colors = frm.Colors;
640 | }
641 | }
642 |
643 | ///
644 | /// Выбо файла шрифта
645 | ///
646 | private void btnFontSelect_Click(object sender, EventArgs e)
647 | {
648 | var ofd = new OpenFileDialog
649 | {
650 | Filter = @"Font Files (*.ft)|*.ft|" + @"All files (*.*)|*.*",
651 | FilterIndex = 1,
652 | Multiselect = false,
653 | RestoreDirectory = true,
654 | };
655 |
656 | if (ofd.ShowDialog() == DialogResult.OK)
657 | {
658 | tbFontFilename.Text = ofd.FileName;
659 | ucScreen.SetFontFile(ofd.FileName);
660 | }
661 | }
662 |
663 | ///
664 | /// Выбор системного файла ресурсов
665 | ///
666 | private void btnSystemResFileSelect_Click(object sender, EventArgs e)
667 | {
668 | var ofd = new OpenFileDialog
669 | {
670 | Filter = @"Res Files (*.res)|*.res|" + @"All files (*.*)|*.*",
671 | FilterIndex = 1,
672 | Multiselect = false,
673 | RestoreDirectory = true,
674 | };
675 |
676 | if (ofd.ShowDialog() == DialogResult.OK)
677 | {
678 | _systemResFile = null;
679 | tbSystemResFile.Text = ofd.FileName;
680 | }
681 | }
682 |
683 | ///
684 | /// Выбор пользовательского файла ресурсов
685 | /// относящего к эмулируемой программе
686 | ///
687 | private void btnUserResFileSelect_Click(object sender, EventArgs e)
688 | {
689 | var ofd = new OpenFileDialog
690 | {
691 | Filter = @"Res Files (*.res)|*.res|" + @"All files (*.*)|*.*",
692 | FilterIndex = 1,
693 | Multiselect = false,
694 | RestoreDirectory = true,
695 | };
696 |
697 | if (ofd.ShowDialog() == DialogResult.OK)
698 | {
699 | _userResFile = null;
700 | tbUserResFile.Text = ofd.FileName;
701 | }
702 | }
703 |
704 | ///
705 | /// Отладочный вывод эмулятора
706 | ///
707 | private void DebugWriteLine(string text)
708 | {
709 | if (rtbDebugLog.InvokeRequired)
710 | Invoke(new Action(() =>
711 | {
712 | rtbDebugLog.Text += text + Environment.NewLine;
713 | }));
714 | else
715 | rtbDebugLog.Text += text + Environment.NewLine;
716 |
717 | if (tpDebug.InvokeRequired)
718 | {
719 | Invoke(new Action(() =>
720 | {
721 | if (tcMain.SelectedTab != tpDebug)
722 | _newDebugOutputLines++;
723 | }));
724 | }
725 | else
726 | {
727 | if (tcMain.SelectedTab != tpDebug)
728 | _newDebugOutputLines++;
729 | }
730 |
731 | ShowDebugTabPageTitle();
732 | }
733 |
734 | private void ShowDebugTabPageTitle()
735 | {
736 | var title = "Debug Output";
737 | if (_newDebugOutputLines > 0)
738 | title += $" ({_newDebugOutputLines})";
739 |
740 | if (tpDebug.InvokeRequired)
741 | {
742 | Invoke(new Action(() =>
743 | {
744 | tpDebug.Text = title;
745 | }));
746 | }
747 | else
748 | tpDebug.Text = title;
749 | }
750 |
751 | private void btnControl_Click(object sender, EventArgs e)
752 | {
753 | var btn = (Button)sender;
754 | if (btn == null)
755 | return;
756 |
757 | // bad bad bad practice
758 | switch(btn.Name)
759 | {
760 | case "btnSwipeUp":
761 | lblAction.Text = "Swipe Up";
762 | ProxyLib.RegMenuDispatchScreen((byte)GestureEnum.GESTURE_SWIPE_UP, 0, 0);
763 | btnSwipeUp.Focus();
764 | break;
765 | case "btnSwipeDown":
766 | lblAction.Text = "Swipe Down";
767 | ProxyLib.RegMenuDispatchScreen((byte)GestureEnum.GESTURE_SWIPE_DOWN, 0, 0);
768 | btnSwipeDown.Focus();
769 | break;
770 | case "btnSwipeLeft":
771 | lblAction.Text = "Swipe Left";
772 | ProxyLib.RegMenuDispatchScreen((byte)GestureEnum.GESTURE_SWIPE_LEFT, 0, 0);
773 | btnSwipeLeft.Focus();
774 | break;
775 | case "btnSwipeRight":
776 | lblAction.Text = "Swipe Right";
777 | ProxyLib.RegMenuDispatchScreen((byte)GestureEnum.GESTURE_SWIPE_RIGHT, 0, 0);
778 | btnSwipeRight.Focus();
779 | break;
780 | case "btnClick":
781 | lblAction.Text = "Click";
782 | ProxyLib.RegMenuDispatchScreen((byte)GestureEnum.GESTURE_CLICK, 176 / 2, 176 / 2);
783 | btnClick.Focus();
784 | break;
785 | case "btnShortKeypress":
786 | lblAction.Text = "Short Keypress";
787 | ProxyLib.RegMenuKeyPress();
788 | btnShortKeypress.Focus();
789 | break;
790 | case "btnLongKeypress":
791 | lblAction.Text = "Long Keypress";
792 | ProxyLib.RegMenuLongKeyPress();
793 | btnLongKeypress.Focus();
794 | break;
795 | default:
796 | System.Diagnostics.Debug.WriteLine($"UNKNOWN BUTTON: {btn.Name} IN btnControl_Click");
797 | break;
798 | }
799 | }
800 |
801 | private void tcMain_SelectedIndexChanged(object sender, EventArgs e)
802 | {
803 | if (tcMain.SelectedTab == tpDebug)
804 | _newDebugOutputLines = 0;
805 | ShowDebugTabPageTitle();
806 | }
807 | }
808 | }
809 |
--------------------------------------------------------------------------------