{
ProgrammesListFrame используется для создания рамки со списком
установленных на Малик Эмулятор программ.
Этот исходный текст является частью Малик Эмулятора.
Следующие файлы используются этим исходным текстом:
programmeslistframe.lfm
На них так же распространяются те же права, как и на этот исходный текст.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Малик Эмулятор – свободная программа: вы можете перераспространять её и/или
изменять её на условиях Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Малик Эмулятор распространяется в надежде, что он может быть полезен,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
общественной лицензии GNU.
Вы должны были получить копию Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<http://www.gnu.org/licenses/>.
}
unit ProgrammesListFrame;
{$MODE DELPHI}
interface
uses
Classes,
SysUtils,
Forms,
Graphics,
Controls,
StdCtrls,
Types,
LCLType,
Lang,
Images,
Manifests,
EmulConstants,
EmulThemes,
EmulProgrammes,
EmulatorInterfaces;
{%region public }
type
TProgrammesList = class(TFrame, _Interface, GraphicListener)
programmesList: TListBox;
procedure programmesListDrawItem(control: TWinControl; index: integer; arect: TRect; state: TOwnerDrawState);
private
cursorWithFocus: TBitmap;
cursorWithoutFocus: TBitmap;
image: TBitmap;
progIcon: TIcon;
info: ProgrammeInfo_Array1d;
manifest: ProgrammeManifest;
guiTheme: Theme;
public
constructor create(theOwner: TComponent); override;
destructor destroy; override;
{ _Interface }
function getClass(): _Class;
function asObject(): TObject;
{ GraphicListener }
procedure putPixel(x, y, argb: int);
{ Собственные методы }
procedure setProgrammesInfo(const info: ProgrammeInfo_Array1d; count: int);
function getProgrammesInfo(): ProgrammeInfo_Array1d;
function getProgrammesCount(): int;
function getSelectedProgrammeInfo(): ProgrammeInfo;
end;
{%endregion}
implementation
{$R *.LFM}
{%region TProgrammesList }
constructor TProgrammesList.create(theOwner: TComponent);
begin
inherited create(theOwner);
cursorWithFocus := TBitmap.create();
cursorWithoutFocus := TBitmap.create();
progIcon := TIcon.create();
manifest := ProgrammeManifest.create();
guiTheme := getTheme(0);
end;
destructor TProgrammesList.destroy;
begin
manifest.free();
progIcon.free();
cursorWithoutFocus.free();
cursorWithFocus.free();
inherited destroy;
end;
procedure TProgrammesList.programmesListDrawItem(control: TWinControl; index: integer; arect: TRect; state: TOwnerDrawState);
var
canvas: TCanvas;
clip: TRect;
m: ProgrammeManifest;
n: TIcon;
i: int;
j: int;
c: int;
w: int;
h: int;
tw: int;
s1: AnsiString;
s2: AnsiString;
s: UnicodeString;
begin
m := manifest;
n := progIcon;
with info[index] do begin
try
loadManifest(m);
loadIcon(n);
except
exit;
end;
end;
canvas := TListBox(control).canvas;
canvas.clipRect := arect;
if TOwnerDrawStateType.odSelected in state then begin
if control.focused() then begin
i := $000101;
image := cursorWithFocus;
end else begin
i := $000001;
image := cursorWithoutFocus;
end;
w := arect.right - arect.left;
h := arect.bottom - arect.top;
if (image.empty) or (image.width <> w) or (image.height <> h) then begin
image.clear();
image.setSize(w, h);
with image.canvas do begin
brush.style := bsSolid;
brush.color := clWindow;
fillRect(0, 0, w, h);
end;
guiTheme.drawElement(self, i, 0, 0, w, h);
end;
canvas.draw(arect.left, arect.top, image);
end else begin
canvas.brush.style := bsSolid;
canvas.brush.color := clWindow;
canvas.fillRect(arect);
end;
clip.left := arect.left + 2;
clip.top := arect.top + 2;
clip.right := clip.left + 48;
clip.bottom := clip.top + 48;
canvas.clipRect := clip;
findBestIconSize(n, 48);
w := n.width;
h := n.height;
if (w > 48) or (h > 48) then begin
if w >= h then begin
h := int(round(48.0 * toReal(h) / toReal(w)));
w := 48;
end else begin
w := int(round(48.0 * toReal(w) / toReal(h)));
h := 48;
end;
canvas.stretchDraw(bounds(clip.left + ((48 - w) div 2), clip.top + ((48 - h) div 2), w, h), n);
end else begin
canvas.draw(clip.left + ((48 - w) div 2), clip.top + ((48 - h) div 2), n);
end;
clip.left := arect.left + 2;
clip.top := arect.top + 2;
clip.right := arect.right - 2;
clip.bottom := arect.bottom - 2;
canvas.clipRect := clip;
s1 := trim(m.getValue(MANIFEST_PROPERTY_PROGRAMME_NAME));
s2 := trim(m.getValue(MANIFEST_PROPERTY_PROGRAMME_DESCRIPTION));
canvas.brush.style := bsClear;
canvas.font.color := clBlack;
if length(s2) > 0 then begin
canvas.textOut(arect.left + 52, arect.top + 2, s1);
end else begin
canvas.textOut(arect.left + 52, arect.top + 18, s1);
end;
canvas.font.color := clGray;
s1 := s2;
s2 := '';
s := toUTF16String(s1);
tw := arect.right - arect.left - 54;
w := 0;
i := 1;
while i <= length(s) do begin
c := int(s[i]);
if (c >= $d800) and (c <= $dbff) and (i < length(s)) then begin
inc(w, canvas.textWidth(toUTF8String(s[i] + s[i + 1])));
inc(i);
end else begin
inc(w, canvas.textWidth(toUTF8String(s[i])));
end;
if w > tw then begin
for j := i downto 1 do begin
if s[j] = #32 then begin
s1 := toUTF8String(copy(s, 1, j - 1));
s2 := toUTF8String(copy(s, j + 1, length(s) - j));
break;
end;
end;
break;
end;
inc(i);
end;
canvas.textOut(arect.left + 52, arect.top + 18, s1);
canvas.textOut(arect.left + 52, arect.top + 34, s2);
end;
function TProgrammesList.getClass(): _Class;
begin
result := ClassData.create(classType());
end;
function TProgrammesList.asObject(): TObject;
begin
result := self;
end;
procedure TProgrammesList.putPixel(x, y, argb: int);
var
canvas: TCanvas;
begin
canvas := image.canvas;
canvas.pixels[x, y] := byteSwap(computePixel(byteSwap(canvas.pixels[x, y]) shr 8, argb, false, true)) shr 8;
end;
procedure TProgrammesList.setProgrammesInfo(const info: ProgrammeInfo_Array1d; count: int);
var
i: int;
m: ProgrammeManifest;
list: TListBox;
items: TStrings;
event: TSelectionChangeEvent;
begin
self.info := ProgrammeInfo_Array1d_create(count);
arraycopy(info, 0, self.info, 0, count);
m := manifest;
list := programmesList;
items := list.items;
items.beginUpdate();
try
items.clear();
for i := 0 to count - 1 do begin
info[i].loadManifest(m);
items.add(m.getValue(MANIFEST_PROPERTY_PROGRAMME_NAME));
end;
if count > 0 then begin
list.itemIndex := 0;
end else begin
list.itemIndex := -1;
end;
event := list.onSelectionChange;
if @event <> nil then begin
event(list, false);
end;
finally
items.endUpdate();
end;
end;
function TProgrammesList.getProgrammesInfo(): ProgrammeInfo_Array1d;
begin
result := info;
end;
function TProgrammesList.getProgrammesCount(): int;
begin
result := length(info);
end;
function TProgrammesList.getSelectedProgrammeInfo(): ProgrammeInfo;
var
i: int;
begin
i := programmesList.itemIndex;
if (i >= 0) and (i < length(info)) then begin
result := info[i];
end else begin
result := nil;
end;
end;
{%endregion}
end.