{
EmulatorInterfaces содержит классы и константы, используемые в настройках и
пользовательском интерфейсе Малик Эмулятора.
Этот исходный текст является частью Малик Эмулятора.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Малик Эмулятор – свободная программа: вы можете перераспространять её и/или
изменять её на условиях Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Малик Эмулятор распространяется в надежде, что он может быть полезен,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
общественной лицензии GNU.
Вы должны были получить копию Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<http://www.gnu.org/licenses/>.
}
unit EmulatorInterfaces;
{$MODE DELPHI}
interface
uses
Classes,
LCLIntf,
InterfaceBase,
Graphics,
Forms,
Controls,
Dialogs,
Menus,
LMessages,
Lang,
EmulMalik;
{%region public }
const
{ коды типов данных }
DATA_TYPE_BOOLEAN = int(1);
DATA_TYPE_BYTE = int(2);
DATA_TYPE_SHORT = int(3);
DATA_TYPE_INT = int(4);
DATA_TYPE_LONG = int(5);
DATA_TYPE_WCHAR = int(6);
DATA_TYPE_ICHAR = int(7);
DATA_TYPE_FLOAT = int(8);
DATA_TYPE_DOUBLE = int(9);
DATA_TYPE_REAL = int(10);
DATA_TYPE_OBJECT = int(11);
const
{ сигнатуры типов данных }
SIGNATURE_VOID = 'V';
SIGNATURE_BOOLEAN = 'Z';
SIGNATURE_BYTE = 'B';
SIGNATURE_SHORT = 'S';
SIGNATURE_INT = 'I';
SIGNATURE_LONG = 'J';
SIGNATURE_WCHAR = 'C';
SIGNATURE_ICHAR = 'G';
SIGNATURE_FLOAT = 'F';
SIGNATURE_DOUBLE = 'D';
SIGNATURE_REAL = 'E';
SIGNATURE_CLASS = 'R';
SIGNATURE_OBJECT = 'L';
SIGNATURE_ARRAY = '[';
SIGNATURE_SUFFIX = ';';
const
{ имена секций и ключей для файла инициализации }
SECTION_PROGRAMMES = 'programmes';
KEY_RECENT = 'recent';
SECTION_WINDOWS = 'windows';
SECTION_CONTENT = 'content';
KEY_MAIN = 'main';
KEY_FILE_BROWSER = 'file browser';
KEY_DIRECTORY_BROWSER = 'directories browser';
KEY_RUNNING_PROGRAMMES = 'running programmes';
SECTION_EMULATOR = 'emulator';
KEY_AUTO_FULLSCREEN = 'auto fullscreen';
KEY_AUTO_CLOSEWND = 'auto closewnd';
KEY_GRAPHIC_SCALING = 'graphic scaling';
KEY_MAXIMUM_FPS = 'maximum frames';
KEY_THEME = 'theme';
SECTION_DEBUGGER_COLORS = 'debugger colors';
KEY_EMPTY_DATA = 'empty data';
KEY_NORMAL_DATA = 'normal data';
KEY_OBJECT_DATA = 'object data';
KEY_EXCEPT_DATA = 'except data';
KEY_OLDEBP_DATA = 'oldebp data';
KEY_RETURN_DATA = 'return data';
KEY_IRETURN_DATA = 'ireturn data';
KEY_NORMAL_TYPE = 'normal type';
KEY_OBJECT_TYPE = 'object type';
KEY_EXCEPT_TYPE = 'except type';
KEY_OLDEBP_TYPE = 'oldebp type';
KEY_RETURN_TYPE = 'return type';
KEY_IRETURN_TYPE = 'ireturn type';
KEY_OVERFLOW_TYPE = 'overflow type';
KEY_FUNCTION_NAME = 'function name';
KEY_SOURCE_LINE = 'source line';
KEY_INHERITED = 'inherited from';
KEY_ALIGNMENT = 'alignment';
KEY_COMPRESSION = 'compression level';
KEY_STACK = 'stack size in MB';
KEY_HEAP = 'heap size in MB';
KEY_EXECUTABLE = 'executable';
const
{ имена папок с программами }
DIRECTORY_GAMES = 'games' + DIRECTORY_SEPARATOR;
DIRECTORY_APPS = 'apps' + DIRECTORY_SEPARATOR;
const
{ цвета отладчика по умолчанию (в формате $RRGGBB) }
DEFAULT_DEBUGGER_COLOR_EMPTY_DATA = int($c0c0c0);
DEFAULT_DEBUGGER_COLOR_NORMAL_DATA = int($000000);
DEFAULT_DEBUGGER_COLOR_OBJECT_DATA = int($800000);
DEFAULT_DEBUGGER_COLOR_EXCEPT_DATA = int($a0a0a0);
DEFAULT_DEBUGGER_COLOR_OLDEBP_DATA = int($40a0ff);
DEFAULT_DEBUGGER_COLOR_RETURN_DATA = int($ffa040);
DEFAULT_DEBUGGER_COLOR_IRETURN_DATA = int($c07830);
DEFAULT_DEBUGGER_COLOR_NORMAL_TYPE = int($3078ff);
DEFAULT_DEBUGGER_COLOR_OBJECT_TYPE = int($3078ff);
DEFAULT_DEBUGGER_COLOR_EXCEPT_TYPE = int($a0a0a0);
DEFAULT_DEBUGGER_COLOR_OLDEBP_TYPE = int($40a0ff);
DEFAULT_DEBUGGER_COLOR_RETURN_TYPE = int($ffa040);
DEFAULT_DEBUGGER_COLOR_IRETURN_TYPE = int($c07830);
DEFAULT_DEBUGGER_COLOR_OVERFLOW_TYPE = int($ff0000);
DEFAULT_DEBUGGER_COLOR_FUNCTION_NAME = int($24905a);
DEFAULT_DEBUGGER_COLOR_SOURCE_LINE = int($000000);
DEFAULT_DEBUGGER_COLOR_INHERITED = int($40a0ff);
const
MAIN_WINDOW_INTERFACE_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C1519}';
EMULATION_WINDOW_INTERFACE_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C151A}';
REPRESENTER_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C151B}';
type
MainWindowInterface = interface;
EmulationWindowInterface = interface;
Representer = interface;
TEmulatorFormWithDialog = class;
EmulationWindowInterface_Array1d = packed array of EmulationWindowInterface;
MainWindowInterface = interface(_Interface) [MAIN_WINDOW_INTERFACE_GUID]
procedure showMainWindow();
procedure notifyTerminated(window: EmulationWindowInterface);
procedure saveSettings();
procedure removeSetting(const section, key: AnsiString);
procedure setSetting(const section, key, value: AnsiString);
function isSectionExists(const section: AnsiString): boolean;
function isKeyExists(const section, key: AnsiString): boolean;
function getSetting(const section, key, defaultValue: AnsiString): AnsiString;
function getSections(): AnsiString_Array1d;
function getKeys(const section: AnsiString): AnsiString_Array1d;
function getEmulatorsCount(): int;
function getEmulator(index: int): EmulationWindowInterface;
end;
EmulationWindowInterface = interface(ProcessorListener) [EMULATION_WINDOW_INTERFACE_GUID]
procedure showEmulationWindow();
procedure showDisassemblerWindow();
procedure setDebug(debug: boolean);
function isNowDebugging(): boolean;
function getMalikProcessor(): MalikProcessor;
function getMainWindow(): MainWindowInterface;
function getProgrammeDirectory(): AnsiString;
end;
Representer = interface(_Interface) [REPRESENTER_GUID]
function getUntypedValueRepresentation(): AnsiString;
function getLongRepresentation(value: long; sourceDataType: int): AnsiString;
function getFloatRepresentation(value: float): AnsiString;
function getDoubleRepresentation(value: double): AnsiString;
function getRealRepresentation(value: real): AnsiString; overload;
function getRealRepresentation(value: real; sourceDataType: int): AnsiString; overload;
function getObjectRepresentation(value: int): AnsiString;
function getHexRepresentation(value: int): AnsiString;
function getTypeRepresentation(const rawRepresentation: AnsiString): AnsiString;
end;
TEmulatorFormWithDialog = class(TForm)
private
openedDialog: TForm;
protected
procedure lmActivate(var message: TLMActivate); message LM_ACTIVATE;
function openDialog(dialog: TForm): int; virtual; overload;
function openDialog(const caption, text: AnsiString; dialogType: TMsgDlgType; buttons: TMsgDlgButtons): int; virtual; overload;
function getOpenedDialog(): TForm; virtual;
public
constructor create(theOwner: TComponent); override;
end;
{%endregion}
{%region routine }
function getEmulatorDirectory(): AnsiString;
function EmulationWindowInterface_Array1d_create(length: int): EmulationWindowInterface_Array1d;
procedure findBestIconSize(progIcon: TIcon; size: int);
procedure arraycopy(const src: EmulationWindowInterface_Array1d; srcOffset: int; const dst: EmulationWindowInterface_Array1d; dstOffset: int; length: int); overload;
{%endregion}
implementation
{%region routine }
function getEmulatorDirectory(): AnsiString;
var
i: int;
s: AnsiString;
begin
result := '';
s := parseParams()[0];
for i := length(s) downto 1 do begin
if s[i] = DIRECTORY_SEPARATOR then begin
result := copy(s, 1, i);
break;
end;
end;
end;
function EmulationWindowInterface_Array1d_create(length: int): EmulationWindowInterface_Array1d;
begin
setLength(result, length);
end;
procedure findBestIconSize(progIcon: TIcon; size: int);
var
i: int;
s: int;
index: int;
bestSize: int;
begin
if progIcon.count <= 0 then begin
exit;
end;
progIcon.current := 0;
index := 0;
bestSize := max(progIcon.width, progIcon.height);
for i := 1 to progIcon.count - 1 do begin
progIcon.current := i;
s := max(progIcon.width, progIcon.height);
if s <= size then begin
index := i;
bestSize := s;
end;
end;
for i := 1 to progIcon.count - 1 do begin
progIcon.current := i;
s := max(progIcon.width, progIcon.height);
if (s > bestSize) and (s <= size) then begin
index := i;
bestSize := s;
end;
end;
progIcon.current := index;
end;
procedure arraycopy(const src: EmulationWindowInterface_Array1d; srcOffset: int; const dst: EmulationWindowInterface_Array1d; dstOffset: int; length: int);
var
lim: int;
len: int;
i: int;
begin
lim := srcOffset + length;
len := System.length(src);
if (lim > len) or (lim < srcOffset) or (srcOffset < 0) or (srcOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
lim := dstOffset + length;
len := System.length(dst);
if (lim > len) or (lim < dstOffset) or (dstOffset < 0) or (dstOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
if (src = dst) and (srcOffset < dstOffset) then begin
for i := length - 1 downto 0 do begin
dst[dstOffset + i] := src[srcOffset + i];
end;
end else begin
for i := 0 to length - 1 do begin
dst[dstOffset + i] := src[srcOffset + i];
end;
end;
end;
{%endregion}
{%region TEmulatorFormWithDialog }
constructor TEmulatorFormWithDialog.create(theOwner: TComponent);
begin
inherited create(theOwner);
end;
procedure TEmulatorFormWithDialog.lmActivate(var message: TLMActivate);
var
dialog: TForm;
begin
dialog := getOpenedDialog();
if (message.active <> 0) and (dialog <> nil) then begin
dialog.showOnTop();
end;
end;
function TEmulatorFormWithDialog.openDialog(dialog: TForm): int;
var
capture: int;
begin
if dialog = nil then begin
raise NullPointerException.create('TEmulatorFormWithDialog.openDialog: dialog = nil.');
end;
if openedDialog <> nil then begin
raise EInvalidOperation.create('TEmulatorFormWithDialog.openDialog: у этой формы уже открыто диалоговое окно.');
end;
if self.enabled = false then begin
raise EInvalidOperation.create('TEmulatorFormWithDialog.openDialog: эта форма недоступна.');
end;
if dialog.visible = true then begin
raise EInvalidOperation.create('TEmulatorFormWithDialog.openDialog: запрашиваемое диалоговое окно уже открыто.');
end;
if dialog.enabled = false then begin
raise EInvalidOperation.create('TEmulatorFormWithDialog.openDialog: запрашиваемое диалоговое окно недоступно.');
end;
if dialog.formStyle = TFormStyle.fsMDIChild then begin
raise EInvalidOperation.create('TEmulatorFormWithDialog.openDialog: запрашиваемое окно не может быть диалоговым по своей природе.');
end;
dragManager.dragStop(false);
if activePopupMenu <> nil then begin
activePopupMenu.close();
end;
capture := getCapture();
if capture <> 0 then begin
sendMessage(capture, LM_CANCELMODE, 0, 0);
end;
releaseCapture();
result := 0;
openedDialog := dialog;
try
dialog.position := poDesigned;
dialog.left := max(0, min(left + ((self.width - dialog.width) div 2), screen.desktopWidth - dialog.width));
dialog.top := max(0, min(top + ((self.height - dialog.height) div 2), screen.desktopHeight - dialog.height));
dialog.modalResult := 0;
dialog.show();
self.enabled := false;
try
repeat
try
widgetSet.appProcessMessages();
except
if application.captureExceptions then begin
application.handleException(self);
end else begin
raise;
end;
end;
if application.terminated then begin
dialog.modalResult := 0;
break;
end;
if dialog.modalResult <> 0 then begin
dialog.hide();
break;
end;
if dialog.visible = false then begin
break;
end;
application.idle(true);
until false;
result := dialog.modalResult;
if result = 0 then begin
result := mrClose;
end;
finally
self.enabled := true;
self.show();
end;
finally
openedDialog := nil;
end;
end;
function TEmulatorFormWithDialog.openDialog(const caption, text: AnsiString; dialogType: TMsgDlgType; buttons: TMsgDlgButtons): int;
var
dialog: TForm;
begin
dialog := createMessageDialog(text, dialogType, buttons);
try
dialog.caption := caption;
result := openDialog(dialog);
finally
dialog.free();
end;
end;
function TEmulatorFormWithDialog.getOpenedDialog(): TForm;
var
dialog: TForm;
begin
result := openedDialog;
while result is TEmulatorFormWithDialog do begin
dialog := TEmulatorFormWithDialog(result).openedDialog;
if dialog = nil then begin
break;
end;
result := dialog;
end;
end;
{%endregion}
end.