emulthemesoft.pas

Переключить прокрутку окна
Загрузить этот исходный код

{
    EmulThemeSoft реализует тему оформления пользовательского интерфейса «Soft».
    В Малик Эмуляторе эта тема записана под именем «<Обычная для Малик Эмулятора тема>».
    Этот исходный текст является частью Малик Эмулятора.

    Следующие файлы используются этим исходным текстом:
        soft.buttons.png
        soft.buttons.png.inc
        soft.interface.svg
        soft.window.blend
    На них так же распространяются те же права, как и на этот исходный текст.

    Файл soft.buttons.png.inc на самом деле является файлом soft.buttons.png,
    записанным в виде строки для использования в этом исходном тексте.

    Copyright © 2016–2017, 2019–2023 Малик Разработчик

    Малик Эмулятор – свободная программа: вы можете перераспространять её и/или
    изменять её на условиях Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Малик Эмулятор распространяется в надежде, что он может быть полезен,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <http://www.gnu.org/licenses/>.
}

unit EmulThemeSoft;

{$MODE DELPHI}
{$aSMMODE INTEL}

interface

uses
    Lang,
    IOStreams,
    Images,
    EmulThemes;

{%region public }
const
    SCROLLBAR_ORIENTATION_HORIZONTAL = int(0);
    SCROLLBAR_ORIENTATION_VERTICAL = int(1);

const
    SCROLLBAR_ELEMENT_BACK_BUTTON = int(0);
    SCROLLBAR_ELEMENT_NEXT_BUTTON = int(1);
    SCROLLBAR_ELEMENT_SLIDER = int(2);
    SCROLLBAR_ELEMENT_BACK_TRACK = int(3);
    SCROLLBAR_ELEMENT_NEXT_TRACK = int(4);

const
    SCROLLBAR_STATE_NORMAL = int(0);
    SCROLLBAR_STATE_PRESSED = int(1);
    SCROLLBAR_STATE_DISABLED = int(2);

type
    ImageRegion = class;
    GradientData = class;
    ThemeSoft = class;

    ImageRegion_Array1d = packed array of ImageRegion;

    ImageRegion = class(_Object)
    private
        elementType: int;
        left: int;
        top: int;
        width: int;
        height: int;
    public
        constructor create(elementType, left, top, width, height: int);
    end;

    GradientData = class(_Object)
    strict private
        bb: int;
        dd: int;
        color1: int;
        color2: int;
        length: int;
        currentPosition: int;
        currentColor: int;
        coord: int_Array1d;
        delta: int_Array1d;
        incre: int_Array1d;
        error: int_Array1d;
    public
        constructor create();
        function needRepeat(): boolean;
        function getColor1(): int;
        function getColor2(): int;
        function getLength(): int;
        function getCurrentPosition(): int;
        function getCurrentColor(): int;
        procedure next();
        procedure reset(color1, color2, length: int);

    strict private
        class procedure dataToArray(data: long; const a: int_Array1d);
        class function arrayToData(const a: int_Array1d): long;
    end;

    ThemeSoft = class(RefCountInterfacedObject, Theme)
    protected
        procedure putPixel(listener: GraphicListener; x, y, color: int); virtual;
        procedure draw(listener: GraphicListener; left, top, width, height: int; const source); virtual;
        procedure drawHeader(listener: GraphicListener; left, top, width, height: int; const lhdr, chdr, rhdr, hdr); virtual;
        procedure drawHeaderBorder(listener: GraphicListener; left, top, width, height: int; const lcorner, rcorner, tborder, lborder, rborder); virtual;
        procedure drawBorderVert(listener: GraphicListener; left, top, width, height: int; const gdata); virtual;
        procedure drawBorderHorz(listener: GraphicListener; left, top, width, height: int; const gdata, lcorner, rcorner); virtual;
        procedure drawListItem(listener: GraphicListener; left, top, width, height: int; const data); virtual;
        procedure drawTableHeader(listener: GraphicListener; left, top, width, height: int; const data); virtual;
        procedure drawButton(listener: GraphicListener; left, top, width, height: int; const data); virtual;
        procedure drawDropDownButton(listener: GraphicListener; left, top, width, height: int; const data); virtual;
        procedure drawToolButton(listener: GraphicListener; left, top, width, height: int; const data); virtual;
        procedure drawToolDropDown(listener: GraphicListener; left, top, width, height: int; const data); virtual;
        procedure drawTrackbarHorz(listener: GraphicListener; left, top, width, height: int; const data); virtual;
        procedure drawTrackbarVert(listener: GraphicListener; left, top, width, height: int; const data); virtual;
        procedure drawFieldHorz(listener: GraphicListener; left, top, width, height: int; const data); virtual;
        procedure drawFieldVert(listener: GraphicListener; left, top, width, height: int; const data); virtual;
        procedure drawGradientsHorz(listener: GraphicListener; left, top, width, height: int; const data); virtual;
        procedure drawGradientsVert(listener: GraphicListener; left, top, width, height: int; const data); virtual;
    protected
        procedure drawActiveHeader(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawActiveHeaderMaximized(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawActiveBorderLeft(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawActiveBorderRight(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawActiveBorderBottom(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawActiveWindow(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawInactiveHeader(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawInactiveHeaderMaximized(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawInactiveBorderLeft(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawInactiveBorderRight(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawInactiveBorderBottom(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawInactiveWindow(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawDisabledHeader(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawDisabledHeaderMaximized(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawDisabledBorderLeft(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawDisabledBorderRight(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawDisabledBorderBottom(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawDisabledWindow(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawListItemNoFocus(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawListItemWithFocus(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawListItemInactive(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTableHeaderNormal(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTableHeaderPressed(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTableHeaderDisabled(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawButtonNormal(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawButtonPressed(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawButtonDisabled(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawButtonWithFocus(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawDropDownButtonNormal(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawDropDownButtonPressed(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawDropDownButtonDisabled(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolButtonNormal(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolButtonPressed(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolButtonDisabled(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolButtonPushed(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolButtonWithNextNormal(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolButtonWithNextPressed(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolButtonWithNextDisabled(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolButtonWithNextPushed(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolDropDownNormal(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolDropDownPressed(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolDropDownDisabled(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolDropDownPushed(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolHorzSeparator(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawToolVertSeparator(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTextFieldNormal(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTextFieldWithFocus(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTextFieldDisabled(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTextFieldReadOnly(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawProgressHorzBackground(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawProgressHorzFill(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawProgressVertBackground(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawProgressVertFill(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTrackbarHorzNormal(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTrackbarHorzWithFocus(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTrackbarHorzDisabled(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTrackbarVertNormal(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTrackbarVertWithFocus(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawTrackbarVertDisabled(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawScrollbarElement(listener: GraphicListener; left, top, width, height: int; orientation, element, state: int); virtual;
        procedure drawScrollbarSizegrip(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawScrollbarSizegripRight(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawScrollbarSizegripLeft(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawStatusBarSimple(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawStatusBarWithSeparator(listener: GraphicListener; left, top, width, height: int); virtual;
        procedure drawStatusBarWithSizegrip(listener: GraphicListener; left, top, width, height: int); virtual;
    public
        constructor create();
        function getName(): AnsiString; virtual;
        function getSystemColor(index: int): int; virtual;
        function getSizes(element: int): int; virtual;
        procedure drawElement(listener: GraphicListener; element, left, top, width, height: int); virtual;

    strict private const
        COLOR_MASK = int($ff000000);
    strict private
        REGIONS: ImageRegion_Array1d; static;
        ELEMENTS: Image; static;
    private
        class procedure clinit();
        class procedure cldone();
    end;
{%endregion}

{%region routine }
    function toImageRegionArray1d(const arr: array of ImageRegion): ImageRegion_Array1d;
{%endregion}

implementation

{%region routine }
    function toImageRegionArray1d(const arr: array of ImageRegion): ImageRegion_Array1d;
    begin
        setLength(result, length(arr));
        move(arr[0], result[0], length(result) * sizeof(_Object));
    end;
{%endregion}

{%region ImageRegion }
    constructor ImageRegion.create(elementType, left, top, width, height: int);
    begin
        inherited create();
        self.elementType := elementType;
        self.left := left;
        self.top := top;
        self.width := width;
        self.height := height;
    end;
{%endregion}

{%region GradientData }
    class procedure GradientData.dataToArray(data: long; const a: int_Array1d);
    var
        i: int;
        color: int;
        length: int;
    begin
        color := LongRecord(data).lo;
        length := LongRecord(data).hi;
        for i := 0 to 3 do begin
            a[i] := (color shr (i * 8)) and $ff;
        end;
        a[4] := length;
    end;

    class function GradientData.arrayToData(const a: int_Array1d): long; assembler;
    asm
                mov     ecx, [a]
                mov     edx, [ecx+$10]
                mov     ah,  [ecx+$0c]
                mov     al,  [ecx+$08]
                shl     eax, $10
                mov     ah,  [ecx+$04]
                mov     al,  [ecx+$00]
    end;

    constructor GradientData.create();
    begin
        inherited create();
    end;

    function GradientData.needRepeat(): boolean;
    begin
        result := bb < dd;
    end;

    function GradientData.getColor1(): int;
    begin
        result := color1;
    end;

    function GradientData.getColor2(): int;
    begin
        result := color2;
    end;

    function GradientData.getLength(): int;
    begin
        result := length;
    end;

    function GradientData.getCurrentPosition(): int;
    begin
        result := currentPosition;
    end;

    function GradientData.getCurrentColor(): int;
    begin
        result := currentColor;
    end;

    procedure GradientData.next();
    var
        i: int;
        j: int;
        p: LongRecord;
    begin
        inc(bb);
        j := System.length(coord) - 1;
        while bb < dd do begin
            for i := 0 to j do begin
                inc(error[i], delta[i]);
                if error[i] > dd then begin
                    dec(error[i], dd);
                    inc(coord[i], incre[i]);
                    if i = j then begin
                        p.value := arrayToData(coord);
                        currentColor := p.lo;
                        currentPosition := p.hi;
                        exit;
                    end;
                end;
            end;
            inc(bb);
        end;
    end;

    procedure GradientData.reset(color1, color2, length: int);
    var
        i: int;
        d: int;
        p: LongRecord;
        endCoord: int_Array1d;
    begin
        endCoord := int_Array1d_create(5);
        p.lo := color2;
        p.hi := length;
        dataToArray(p.value, endCoord);
        self.color1 := color1;
        self.color2 := color2;
        self.length := length;
        self.currentPosition := 0;
        self.currentColor := color1;
        self.coord := int_Array1d_create(5);
        self.delta := int_Array1d_create(5);
        self.incre := int_Array1d_create(5);
        self.error := int_Array1d_create(5);
        p.lo := color1;
        p.hi := 0;
        dataToArray(p.value, coord);
        dataToArray(0, delta);
        dataToArray(0, incre);
        dataToArray(0, error);
        for i := System.length(coord) - 1 downto 0 do begin
            d := endCoord[i] - coord[i];
            if d >= 0 then begin
                delta[i] := d;
            end else begin
                delta[i] := -d;
            end;
            if d > 0 then begin
                incre[i] := 1;
            end else
            if d < 0 then begin
                incre[i] := -1;
            end else begin
                incre[i] := 0;
            end;
        end;
        bb := -1;
        dd := delta[0];
        for i := 1 to System.length(delta) - 1 do begin
            d := delta[i];
            if d > dd then begin
                dd := d;
            end;
        end;
    end;
{%endregion}

{%region ThemeSoft }
    class procedure ThemeSoft.clinit();
    begin
        REGIONS := toImageRegionArray1d([
            ImageRegion.create($000102, 184, 109, 11, 11),
            ImageRegion.create($000202, 195, 109, 11, 11),
            ImageRegion.create($001006, 144,   0, 40, 20),
            ImageRegion.create($011006, 144,  20, 40, 20),
            ImageRegion.create($021006, 144,  40, 40, 20),
            ImageRegion.create($031006, 144,  60, 40, 20),
            ImageRegion.create($041006, 144,  80, 40, 20),
            ImageRegion.create($051006, 144, 100, 40, 20),
            ImageRegion.create($001106, 120,   0, 24, 20),
            ImageRegion.create($011106, 120,  20, 24, 20),
            ImageRegion.create($021106, 120,  40, 24, 20),
            ImageRegion.create($031106, 120,  60, 24, 20),
            ImageRegion.create($041106, 120,  80, 24, 20),
            ImageRegion.create($051106, 120, 100, 24, 20),
            ImageRegion.create($001206,  72,   0, 24, 20),
            ImageRegion.create($011206,  72,  20, 24, 20),
            ImageRegion.create($021206,  72,  40, 24, 20),
            ImageRegion.create($031206,  72,  60, 24, 20),
            ImageRegion.create($041206,  72,  80, 24, 20),
            ImageRegion.create($051206,  72, 100, 24, 20),
            ImageRegion.create($001306,  96,   0, 24, 20),
            ImageRegion.create($011306,  96,  20, 24, 20),
            ImageRegion.create($021306,  96,  40, 24, 20),
            ImageRegion.create($031306,  96,  60, 24, 20),
            ImageRegion.create($041306,  96,  80, 24, 20),
            ImageRegion.create($051306,  96, 100, 24, 20),
            ImageRegion.create($001406,  24,   0, 24, 20),
            ImageRegion.create($011406,  24,  20, 24, 20),
            ImageRegion.create($021406,  24,  40, 24, 20),
            ImageRegion.create($031406,  24,  60, 24, 20),
            ImageRegion.create($041406,  24,  80, 24, 20),
            ImageRegion.create($051406,  24, 100, 24, 20),
            ImageRegion.create($001506,  48,   0, 24, 20),
            ImageRegion.create($011506,  48,  20, 24, 20),
            ImageRegion.create($021506,  48,  40, 24, 20),
            ImageRegion.create($031506,  48,  60, 24, 20),
            ImageRegion.create($041506,  48,  80, 24, 20),
            ImageRegion.create($051506,  48, 100, 24, 20),
            ImageRegion.create($001606,   0,   0, 24, 20),
            ImageRegion.create($011606,   0,  20, 24, 20),
            ImageRegion.create($021606,   0,  40, 24, 20),
            ImageRegion.create($031606,   0,  60, 24, 20),
            ImageRegion.create($041606,   0,  80, 24, 20),
            ImageRegion.create($051606,   0, 100, 24, 20),
            ImageRegion.create($00000b, 184,  60,  8, 11),
            ImageRegion.create($01000b, 184,  71,  8, 11),
            ImageRegion.create($02000b, 184,  82,  8, 11),
            ImageRegion.create($03000b, 206, 109,  8, 11),
            ImageRegion.create($00010b, 184,   0,  8, 15),
            ImageRegion.create($01010b, 184,  15,  8, 15),
            ImageRegion.create($02010b, 184,  30,  8, 15),
            ImageRegion.create($03010b, 184,  45,  8, 15),
            ImageRegion.create($00020b, 192,  15,  8, 15),
            ImageRegion.create($01020b, 200,  15,  8, 15),
            ImageRegion.create($02020b, 192,  30,  8, 15),
            ImageRegion.create($03020b, 200,  30,  8, 15),
            ImageRegion.create($00040b, 214,  96, 11,  8),
            ImageRegion.create($01040b, 214, 104, 11,  8),
            ImageRegion.create($02040b, 214, 112, 11,  8),
            ImageRegion.create($03040b, 184,  93, 11,  8),
            ImageRegion.create($00050b, 195,  45, 15,  8),
            ImageRegion.create($01050b, 195,  61, 15,  8),
            ImageRegion.create($02050b, 195,  77, 15,  8),
            ImageRegion.create($03050b, 195,  93, 15,  8),
            ImageRegion.create($00060b, 195,  53, 15,  8),
            ImageRegion.create($01060b, 195,  69, 15,  8),
            ImageRegion.create($02060b, 195,  85, 15,  8),
            ImageRegion.create($03060b, 195, 101, 15,  8),
            ImageRegion.create($00000c, 195,   0, 15, 15),
            ImageRegion.create($01000c, 210,  15, 15, 15),
            ImageRegion.create($02000c, 210,  30, 15, 15),
            ImageRegion.create($00010c, 210,  45, 15, 15),
            ImageRegion.create($01010c, 210,  60, 15, 15),
            ImageRegion.create($02010c, 210,  75, 15, 15),
            ImageRegion.create($00000f, 210,   0, 15, 15),
            ImageRegion.create($01000f, 225,  30, 15, 15),
            ImageRegion.create($02000f, 225,  75, 15, 15),
            ImageRegion.create($00020f, 225,  15, 15, 15),
            ImageRegion.create($01020f, 225,  60, 15, 15),
            ImageRegion.create($02020f, 225, 105, 15, 15),
            ImageRegion.create($00010f, 225,   0, 15, 15),
            ImageRegion.create($01010f, 225,  45, 15, 15),
            ImageRegion.create($02010f, 225,  90, 15, 15)
        ]);
        ELEMENTS := ImagePNG.create();
        ELEMENTS.loadFromStream(ByteArrayInputStream.create(stringToByteArray({$I SOFT.BUTTONS.PNG.INC})));
    end;

    class procedure ThemeSoft.cldone();
    var
        i: int;
    begin
        for i := System.length(REGIONS) - 1 downto 0 do begin
            REGIONS[i].free();
        end;
        ELEMENTS.free();
    end;

    constructor ThemeSoft.create();
    begin
        inherited create();
    end;

    procedure ThemeSoft.putPixel(listener: GraphicListener; x, y, color: int);
    begin
        if color >= 0 then begin
            listener.putPixel(x, y, color or COLOR_MASK);
        end;
    end;

    procedure ThemeSoft.draw(listener: GraphicListener; left, top, width, height: int; const source);
    var
        src: array [0..0] of int absolute source;
        x: int;
        y: int;
        i: int;
        c: int;
    begin
        i := 0;
        for y := 0 to height - 1 do for x := 0 to width - 1 do begin
            c := src[i];
            inc(i);
            putPixel(listener, left + x, top + y, c);
        end;
    end;

    procedure ThemeSoft.drawHeader(listener: GraphicListener; left, top, width, height: int; const lhdr, chdr, rhdr, hdr);
    var
        headerLeft: array [0..7, 0..3] of int absolute lhdr;
        headerCenter: array [0..7] of int absolute chdr;
        headerRight: array [0..7, 0..3] of int absolute rhdr;
        header: array [0..2] of int absolute hdr;
        a: GradientData;
        w2: int;
        i: int;
    begin
        if (width < 10) or (height < 10) then begin
            exit;
        end;
        a := GradientData.create();
        try
            w2 := (width shr 1) - 4;
            draw(listener, left, top, 4, 4, headerLeft);
            draw(listener, left, top + height - 4, 4, 4, headerLeft[4]);
            draw(listener, left + width - 4, top, 4, 4, headerRight);
            draw(listener, left + width - 4, top + height - 4, 4, 4, headerRight[4]);
            for i := 0 to 3 do begin
                a.reset(headerLeft[3][i], headerLeft[4][i], height - 8);
                repeat
                    putPixel(listener, left + i, top + a.getCurrentPosition() + 4, a.getCurrentColor());
                    a.next();
                until not a.needRepeat();
                a.reset(headerRight[3][i], headerRight[4][i], height - 8);
                repeat
                    putPixel(listener, left + width + i - 4, top + a.getCurrentPosition() + 4, a.getCurrentColor());
                    a.next();
                until not a.needRepeat();
            end;
            for i := 0 to 7 do begin
                a.reset(headerLeft[i][3], headerCenter[i], w2);
                repeat
                    if i < 4 then begin
                        putPixel(listener, left + a.getCurrentPosition() + 4, top + i, a.getCurrentColor());
                    end else begin
                        putPixel(listener, left + a.getCurrentPosition() + 4, top + height + i - 8, a.getCurrentColor());
                    end;
                    a.next();
                until not a.needRepeat();
                a.reset(headerCenter[i], headerRight[i][0], w2 + (width and 1));
                repeat
                    if i < 4 then begin
                        putPixel(listener, left + w2 + a.getCurrentPosition() + 4, top + i, a.getCurrentColor());
                    end else begin
                        putPixel(listener, left + w2 + a.getCurrentPosition() + 4, top + height + i - 8, a.getCurrentColor());
                    end;
                    a.next();
                until not a.needRepeat();
            end;
            a.reset(header[0], header[1], w2);
            repeat
                for i := 4 to height - 4 do begin
                    putPixel(listener, left + a.getCurrentPosition() + 4, top + i, a.getCurrentColor());
                end;
                a.next();
            until not a.needRepeat();
            a.reset(header[1], header[2], w2 + (width and 1));
            repeat
                for i := 4 to height - 4 do begin
                    putPixel(listener, left + w2 + a.getCurrentPosition() + 4, top + i, a.getCurrentColor());
                end;
                a.next();
            until not a.needRepeat();
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawHeaderBorder(listener: GraphicListener; left, top, width, height: int; const lcorner, rcorner, tborder, lborder, rborder);
    var
        topBorder: array [0..9, 0..2] of int absolute tborder;
        a: GradientData;
        w2: int;
        c: int;
        i: int;
        j: int;
    begin
        if (width < 20) or (height < 10) then begin
            exit;
        end;
        w2 := (width shr 1) - 10;
        a := GradientData.create();
        try
            { верхний левый угол рамки окна }
            draw(listener, left, top, 10, 10, lcorner);
            { верхняя граница рамки окна }
            for j := 0 to 1 do begin
                c := j * w2;
                for i := 0 to 9 do begin
                    a.reset(topBorder[i][j], topBorder[i][j + 1], w2 + (width and 1));
                    repeat
                        putPixel(listener, left + c + a.getCurrentPosition() + 10, top + i, a.getCurrentColor());
                        a.next();
                    until not a.needRepeat();
                end;
            end;
            { верхний правый угол рамки окна }
            draw(listener, left + width - 10, top, 10, 10, rcorner);
            for i := 0 to 9 do begin
                { левая граница рамки окна }
                drawBorderVert(listener, left, top + 10, 10, height - 10, lborder);
                { правая граница рамки окна }
                drawBorderVert(listener, left + width - 10, top + 10, 10, height - 10, rborder);
            end;
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawBorderVert(listener: GraphicListener; left, top, width, height: int; const gdata);
    var
        data: array [0..1, 0..9] of int absolute gdata;
        a: GradientData;
        i: int;
        j: int;
    begin
        if (width < 1) or (height < 1) then begin
            exit;
        end;
        a := GradientData.create();
        try
            j := 10;
            if j > width then begin
                j := width;
            end;
            for i := 0 to j - 1 do begin
                a.reset(data[0][i], data[1][i], height);
                repeat
                    putPixel(listener, left + i, top + a.getCurrentPosition(), a.getCurrentColor());
                    a.next();
                until not a.needRepeat();
            end;
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawBorderHorz(listener: GraphicListener; left, top, width, height: int; const gdata, lcorner, rcorner);
    var
        bottomBorder: array [0..9, 0..1] of int absolute gdata;
        a: GradientData;
        i: int;
    begin
        if (width < 30) or (height < 10) then begin
            exit;
        end;
        a := GradientData.create();
        try
            draw(listener, left, top, 10, 10, lcorner);
            draw(listener, left + width - 10, top, 10, 10, rcorner);
            for i := 0 to 9 do begin
                a.reset(bottomBorder[i][0], bottomBorder[i][1], width - 20);
                repeat
                    putPixel(listener, left + a.getCurrentPosition() + 10, top + i, a.getCurrentColor());
                    a.next();
                until not a.needRepeat();
            end;
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawListItem(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: array [0..6] of int absolute data;
        i: int;
        j: int;
        a: GradientData;
    begin
        if (width < 5) or (height < 5) then begin
            exit;
        end;
        for j := 0 to 1 do for i := 0 to 1 do begin
            putPixel(listener, left + (width - 3) * i + 1, top + (height - 1) * j, drawdata[0]);
            putPixel(listener, left + (width - 1) * i, top + (height - 3) * j + 1, drawdata[0]);
            putPixel(listener, left + (width - 3) * i + 1, top + (height - 3) * j + 1, drawdata[1]);
        end;
        for i := 2 to width - 3 do begin
            putPixel(listener, left + i, top, drawdata[2]);
            putPixel(listener, left + i, top + 1, drawdata[3]);
            putPixel(listener, left + i, top + height - 2, drawdata[3]);
            putPixel(listener, left + i, top + height - 1, drawdata[2]);
        end;
        for i := 2 to height - 3 do begin
            putPixel(listener, left, top + i, drawdata[2]);
            putPixel(listener, left + 1, top + i, drawdata[3]);
            putPixel(listener, left + width - 2, top + i, drawdata[3]);
            putPixel(listener, left + width - 1, top + i, drawdata[2]);
        end;
        a := GradientData.create();
        try
            a.reset(drawdata[4], drawdata[5], height - 4);
            repeat
                for i := 2 to width - 3 do begin
                    putPixel(listener, left + i, top + a.getCurrentPosition() + 2, a.getCurrentColor());
                end;
                a.next();
            until not a.needRepeat();
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawTableHeader(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: array [0..3] of int absolute data;
        a: GradientData;
        i: int;
        j: int;
        x: int;
        y1: int;
        y2: int;
    begin
        if (width < 1) or (height < 1) then begin
            exit;
        end;
        x := int(short(drawdata[0] shr $0010));
        y1 := int(short(drawdata[0] and $ffff));
        y2 := y1 + height - 2;
        a := GradientData.create();
        try
            a.reset(drawdata[1], drawdata[2], height);
            repeat
                for i := 0 to width - 1 do begin
                    j := a.getCurrentPosition();
                    if (i = x) and (j >= y1) and (j < y2) then begin
                        putPixel(listener, left + i, top + j, drawdata[3]);
                    end else begin
                        putPixel(listener, left + i, top + j, a.getCurrentColor());
                    end;
                end;
                a.next();
            until not a.needRepeat();
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawButton(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: array [0..2] of int absolute data;
        a: GradientData;
        i: int;
        j: int;
        x1: int;
        x2: int;
    begin
        if (width < 5) or (height < 5) then begin
            exit;
        end;
        for i := 2 to width - 3 do begin
            putPixel(listener, left + i, top, drawdata[0]);
            putPixel(listener, left + i, top + height - 1, drawdata[0]);
        end;
        for i := 2 to height - 3 do begin
            putPixel(listener, left, top + i, drawdata[0]);
            putPixel(listener, left + width - 1, top + i, drawdata[0]);
        end;
        for j := 0 to 1 do for i := 0 to 1 do begin
            putPixel(listener, left + (width - 3) * i + 1, top + (height - 3) * j + 1, drawdata[0]);
        end;
        a := GradientData.create();
        try
            a.reset(drawdata[1], drawdata[2], height - 2);
            repeat
                j := a.getCurrentPosition() + 1;
                if (j = 1) or (j = height - 2) then begin
                    x1 := 2;
                    x2 := width - 3;
                end else begin
                    x1 := 1;
                    x2 := width - 2;
                end;
                for i := x1 to x2 do begin
                    putPixel(listener, left + i, top + j, a.getCurrentColor());
                end;
                a.next();
            until not a.needRepeat();
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawDropDownButton(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: array [0..3] of int absolute data;
        a: GradientData;
        b: GradientData;
        i: int;
        j: int;
        x: int;
        y: int;
        x1: int;
        x2: int;
    begin
        if (width < 1) or (height < 1) then begin
            exit;
        end;
        x := (width shr 1) + int(short(drawdata[0] shr $0010)) - 5;
        y := (height shr 1) + int(short(drawdata[0] and $ffff)) - 2;
        a := GradientData.create();
        b := GradientData.create();
        try
            a.reset(drawdata[1], drawdata[2], height);
            repeat
                j := a.getCurrentPosition();
                if (j >= y) and (j < y + 6) then begin
                    x1 := x + j - y;
                    x2 := x - j + y + 10;
                    if x1 <> x2 then begin
                        b.reset(a.getCurrentColor(), drawdata[3], 2);
                        b.next();
                        putPixel(listener, left + x1, top + j, b.getCurrentColor());
                        putPixel(listener, left + x2, top + j, b.getCurrentColor());
                        for i := x1 + 1 to x2 - 1 do begin
                            putPixel(listener, left + i, top + j, drawdata[3]);
                        end;
                    end else begin
                        b.reset(a.getCurrentColor(), drawdata[3], 4);
                        b.next();
                        putPixel(listener, left + x1, top + j, b.getCurrentColor());
                    end;
                    for i := 0 to x1 - 1 do begin
                        putPixel(listener, left + i, top + j, a.getCurrentColor());
                    end;
                    for i := x2 + 1 to width - 1 do begin
                        putPixel(listener, left + i, top + j, a.getCurrentColor());
                    end;
                end else begin
                    for i := 0 to width - 1 do begin
                        putPixel(listener, left + i, top + j, a.getCurrentColor());
                    end;
                end;
                a.next();
            until not a.needRepeat();
        finally
            a.free();
            b.free();
        end;
    end;

    procedure ThemeSoft.drawToolButton(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: array [0..3] of int absolute data;
        a: GradientData;
        i: int;
        j: int;
        x1: int;
        x2: int;
    begin
        if (width < 5) or (height < 5) then begin
            exit;
        end;
        for i := 2 to width - 1 do begin
            putPixel(listener, left + i, top, drawdata[0]);
            putPixel(listener, left + i, top + height - 1, drawdata[0]);
        end;
        for i := 2 to height - 3 do begin
            putPixel(listener, left, top + i, drawdata[0]);
        end;
        for i := 0 to 1 do begin
            putPixel(listener, left + 1, top + (height - 3) * i + 1, drawdata[0]);
        end;
        if int(short(drawdata[3] shr $10)) = 0 then begin
            for i := 1 to height - 2 do begin
                putPixel(listener, left + width - 1, top + i, drawdata[0]);
            end;
        end;
        a := GradientData.create();
        try
            if int(short(drawdata[3] shr $10)) = 0 then begin
                x2 := width - 2;
            end else begin
                x2 := width - 1;
            end;
            a.reset(drawdata[1], drawdata[2], height - 2);
            repeat
                j := a.getCurrentPosition() + 1;
                if (j = 1) or (j = height - 2) then begin
                    x1 := 2;
                end else begin
                    x1 := 1;
                end;
                for i := x1 to x2 do begin
                    putPixel(listener, left + i, top + j, a.getCurrentColor());
                end;
                a.next();
            until not a.needRepeat();
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawToolDropDown(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: array [0..3] of int absolute data;
        a: GradientData;
        b: GradientData;
        i: int;
        j: int;
        x1: int;
        x2: int;
        x: int;
        y: int;
        z1: int;
        z2: int;
    begin
        if (width < 5) or (height < 5) then begin
            exit;
        end;
        for i := 0 to width - 3 do begin
            putPixel(listener, left + i, top, drawdata[0]);
            putPixel(listener, left + i, top + height - 1, drawdata[0]);
        end;
        for i := 2 to height - 3 do begin
            putPixel(listener, left + width - 1, top + i, drawdata[0]);
        end;
        for i := 0 to 1 do begin
            putPixel(listener, left + width - 2, top + (height - 3) * i + 1, drawdata[0]);
        end;
        if int(short(drawdata[3] shr $10)) = 1 then begin
            for i := 1 to height - 2 do begin
                putPixel(listener, left, top + i, drawdata[0]);
            end;
        end;
        a := GradientData.create();
        b := GradientData.create();
        try
            if int(short(drawdata[3] shr $10)) = 0 then begin
                x1 := 0;
            end else begin
                x1 := 1;
            end;
            x := ((width - 6) div 2) + int(short(drawdata[3] shr $0010)) - 1;
            y := ((height - 3) div 2) + int(short(drawdata[3] and $ffff));
            a.reset(drawdata[1], drawdata[2], height - 2);
            repeat
                j := a.getCurrentPosition() + 1;
                if (j = 1) or (j = height - 2) then begin
                    x2 := width - 3;
                end else begin
                    x2 := width - 2;
                end;
                if (j >= y) and (j < y + 3) then begin
                    b.reset(drawdata[0], a.getCurrentColor(), 2);
                    b.next();
                end;
                for i := x1 to x2 do begin
                    if (j >= y) and (j < y + 3) then begin
                        z1 := x + j - y;
                        z2 := x - j + y + 5;
                        if (i = z1) or (i = z2) then begin
                            putPixel(listener, left + i, top + j, b.getCurrentColor());
                            continue;
                        end else
                        if (i > z1) and (i < z2) then begin
                            putPixel(listener, left + i, top + j, drawdata[0]);
                            continue;
                        end;
                    end;
                    putPixel(listener, left + i, top + j, a.getCurrentColor());
                end;
                a.next();
            until not a.needRepeat();
        finally
            a.free();
            b.free();
        end;
    end;

    procedure ThemeSoft.drawTrackbarHorz(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: record
            borderColor: int;
            gradientData: byte;
        end absolute data;
        i: int;
        j: int;
    begin
        for i := 1 to width - 2 do begin
            putPixel(listener, left + i, top, drawdata.borderColor);
            putPixel(listener, left + i, top + height - 1, drawdata.borderColor);
        end;
        for i := 1 to height - 2 do begin
            putPixel(listener, left, top + i, drawdata.borderColor);
            putPixel(listener, left + width - 1, top + i, drawdata.borderColor);
        end;
        drawGradientsHorz(listener, left + 1, top + 1, width - 2, height - 2, drawdata.gradientData);
        for j := 0 to 1 do for i := 0 to 1 do begin
            putPixel(listener, left + (width - 3) * i + 1, top + (height - 3) * j + 1, drawdata.borderColor);
        end;
    end;

    procedure ThemeSoft.drawTrackbarVert(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: record
            borderColor: int;
            gradientData: byte;
        end absolute data;
        i: int;
        j: int;
    begin
        for i := 1 to width - 2 do begin
            putPixel(listener, left + i, top, drawdata.borderColor);
            putPixel(listener, left + i, top + height - 1, drawdata.borderColor);
        end;
        for i := 1 to height - 2 do begin
            putPixel(listener, left, top + i, drawdata.borderColor);
            putPixel(listener, left + width - 1, top + i, drawdata.borderColor);
        end;
        drawGradientsVert(listener, left + 1, top + 1, width - 2, height - 2, drawdata.gradientData);
        for j := 0 to 1 do for i := 0 to 1 do begin
            putPixel(listener, left + (width - 3) * i + 1, top + (height - 3) * j + 1, drawdata.borderColor);
        end;
    end;

    procedure ThemeSoft.drawFieldHorz(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: array [0..3] of int absolute data;
        a: GradientData;
        i: int;
    begin
        if (width < 5) or (height < 5) then begin
            exit;
        end;
        for i := 1 to width - 2 do begin
            putPixel(listener, left + i, top, drawdata[0]);
            putPixel(listener, left + i, top + height - 1, drawdata[0]);
            putPixel(listener, left + i, top + 1, drawdata[1]);
            putPixel(listener, left + i, top + height - 2, drawdata[1]);
        end;
        for i := 1 to height - 2 do begin
            putPixel(listener, left, top + i, drawdata[0]);
            putPixel(listener, left + width - 1, top + i, drawdata[0]);
            if (i > 1) and (i < height - 2) then begin
                putPixel(listener, left + 1, top + i, drawdata[1]);
                putPixel(listener, left + width - 2, top + i, drawdata[1]);
            end;
        end;
        a := GradientData.create();
        try
            a.reset(drawdata[2], drawdata[3], height - 4);
            repeat
                for i := 2 to width - 3 do begin
                    putPixel(listener, left + i, top + a.getCurrentPosition() + 2, a.getCurrentColor());
                end;
                a.next();
            until not a.needRepeat();
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawFieldVert(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: array [0..3] of int absolute data;
        a: GradientData;
        i: int;
    begin
        if (width < 5) or (height < 5) then begin
            exit;
        end;
        for i := 1 to width - 2 do begin
            putPixel(listener, left + i, top, drawdata[0]);
            putPixel(listener, left + i, top + height - 1, drawdata[0]);
            putPixel(listener, left + i, top + 1, drawdata[1]);
            putPixel(listener, left + i, top + height - 2, drawdata[1]);
        end;
        for i := 1 to height - 2 do begin
            putPixel(listener, left, top + i, drawdata[0]);
            putPixel(listener, left + width - 1, top + i, drawdata[0]);
            if (i > 1) and (i < height - 2) then begin
                putPixel(listener, left + 1, top + i, drawdata[1]);
                putPixel(listener, left + width - 2, top + i, drawdata[1]);
            end;
        end;
        a := GradientData.create();
        try
            a.reset(drawdata[2], drawdata[3], width - 4);
            repeat
                for i := 2 to height - 3 do begin
                    putPixel(listener, left + a.getCurrentPosition() + 2, top + i, a.getCurrentColor());
                end;
                a.next();
            until not a.needRepeat();
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawGradientsHorz(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: packed record
            length: int;
            a: array [0..0] of int;
        end absolute data;
        i: int;
        j: int;
        y1: int;
        y2: int;
        s: real;
        a: GradientData;
    begin
        if (width < 1) or (height < 1) or (drawdata.length < 2) then begin
            exit;
        end;
        s := height / (drawdata.length - 1);
        a := GradientData.create();
        try
            y2 := 0;
            for i := 1 to drawdata.length - 1 do begin
                y1 := y2;
                y2 := int(round(i * s));
                a.reset(drawdata.a[i - 1], drawdata.a[i], y2 - y1);
                repeat
                    for j := 0 to width - 1 do begin
                        putPixel(listener, left + j, top + y1 + a.getCurrentPosition(), a.getCurrentColor());
                    end;
                    a.next();
                until not a.needRepeat();
            end;
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawGradientsVert(listener: GraphicListener; left, top, width, height: int; const data);
    var
        drawdata: packed record
            length: int;
            a: array [0..0] of int;
        end absolute data;
        i: int;
        j: int;
        x1: int;
        x2: int;
        s: real;
        a: GradientData;
    begin
        if (width < 1) or (height < 1) or (drawdata.length < 2) then begin
            exit;
        end;
        s := width / (drawdata.length - 1);
        a := GradientData.create();
        try
            x2 := 0;
            for i := 1 to drawdata.length - 1 do begin
                x1 := x2;
                x2 := int(round(i * s));
                a.reset(drawdata.a[i - 1], drawdata.a[i], x2 - x1);
                repeat
                    for j := 0 to height - 1 do begin
                        putPixel(listener, left + x1 + a.getCurrentPosition(), top + j, a.getCurrentColor());
                    end;
                    a.next();
                until not a.needRepeat();
            end;
        finally
            a.free();
        end;
    end;

    procedure ThemeSoft.drawActiveHeader(listener: GraphicListener; left, top, width, height: int);
    const
        LEFT_UP_CORNER: array [0..9, 0..9] of int =
        (
            (      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1, $cdebff, $cdebff ),
            (      -1,      -1,      -1,      -1,      -1, $d3f1ff, $d3f1ff, $d3f1ff, $d3f1ff, $d1efff ),
            (      -1,      -1,      -1,      -1, $d6f5ff, $d9f6ff, $d9f6ff, $d6f5ff, $d6f5ff, $d3f1ff ),
            (      -1,      -1,      -1, $d9f6ff, $d9f6ff, $daf8ff, $daf8ff, $d9f6ff, $d4f3ff, $d3f1ff ),
            (      -1,      -1, $d6f5ff, $d9f6ff, $d9f6ff, $defdff, $e1ffff, $dcfbff, $d4f3ff, $d1efff ),
            (      -1, $d1efff, $d6f5ff, $d6f5ff, $dcfbff, $ecffff, $ecffff, $e1ffff, $d6f5ff, $cbe8ff ),
            (      -1, $d1efff, $d3f1ff, $d4f3ff, $dcfbff, $ecffff, $ecffff, $e1ffff, $d1efff, $c6e3fc ),
            (      -1, $cdebff, $cfedff, $d1efff, $d6f5ff, $defdff, $e1ffff, $d3f1ff, $c6e3fc, $bfdbf3 ),
            ( $c6e0f8, $c9e6fe, $cbe8ff, $cbe8ff, $cbe8ff, $cdebff, $c9e6fe, $c1dcf4, $bdd9f1, $b6d2ea ),
            ( $c4def5, $c8e4fc, $c8e4fc, $c6e3fc, $c6e0f8, $bfdbf3, $bad6ee, $b5d0e7, $b2cde5, $afcae2 )
        );
        RIGHT_UP_CORNER: array [0..9, 0..9] of int =
        (
            ( $9fb5c9, $96acbf,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1 ),
            ( $a8c0d4, $a1b8cc, $96acbf, $899cad, $778796,      -1,      -1,      -1,      -1,      -1 ),
            ( $afc7db, $a8c0d4, $9db4c7, $8fa4b7, $7d8f9f, $6e7e8c,      -1,      -1,      -1,      -1 ),
            ( $b2cbe0, $aac2d6, $a1b8cc, $91a7ba, $8294a4, $748594, $687885,      -1,      -1,      -1 ),
            ( $b2cde5, $aac2d6, $9fb5c9, $91a7ba, $8396a6, $778796, $6c7b89, $5d6b77,      -1,      -1 ),
            ( $b8d4ec, $aac2d6, $9db4c7, $8fa4b7, $8095a7, $76899a, $6c7b89, $5d6b77, $4a555f,      -1 ),
            ( $b6d2ea, $a4bfd7, $98aec1, $899eb1, $7e93a5, $738798, $6c7b89, $5d6b77, $4a555f,      -1 ),
            ( $abc6de, $a3bacf, $91a7ba, $8498aa, $788da0, $708496, $6a7a87, $5d6b77, $48535d,      -1 ),
            ( $a1bcd4, $98aec1, $899eb1, $7e93a5, $738798, $6c8092, $677684, $5a6774, $455059, $292f35 ),
            ( $97b1c9, $8da3b6, $8197ac, $778b9c, $6e8294, $687b8c, $5f7283, $566675, $434e57, $21262c )
        );
        TOP_BORDER: array [0..9, 0..2] of int =
        (
            ( $cbe8ff, $c4def5, $9fb5c9 ),
            ( $d1efff, $cbe8ff, $a8c0d4 ),
            ( $d1efff, $cfedff, $afc7db ),
            ( $cfedff, $d1efff, $b2cbe0 ),
            ( $cdebff, $d4f3ff, $b2cde5 ),
            ( $c9e6fe, $d6f5ff, $b8d4ec ),
            ( $c2dff7, $d1efff, $b6d2ea ),
            ( $bad6ee, $c4e1fa, $abc6de ),
            ( $b2cde5, $b3cfe7, $a1bcd4 ),
            ( $a4bfd7, $9fbad2, $97b1c9 )
        );
        LEFT_BORDER: array [0..1, 0..9] of int =
        (
            ( $bdd9f1, $c4def5, $c6e0f8, $c2dff7, $bfdbf3, $bad6ee, $b5d0e7, $afcae2, $aac4dc, $9fbad2 ),
            ( $b4cce2, $bad3e9, $bcd5eb, $b8d4ec, $b5d0e7, $b2cde5, $adc8e0, $abc6de, $aac4dc, $a8c3dc )
        );
        RIGHT_BORDER: array [0..1, 0..9] of int =
        (
            ( $91abc3, $879db1, $7c91a4, $738798, $6c8092, $66798c, $5d6e7e, $54626f, $3f4a54, $14181c ),
            ( $879db1, $7c91a4, $70869a, $697e90, $647789, $5d6e7e, $536474, $485664, $333d46, $000000 )
        );
    begin
        if (width < 30) or (height < 20) then begin
            exit;
        end;
        { рамка }
        drawHeaderBorder(listener, left, top, width, height, LEFT_UP_CORNER, RIGHT_UP_CORNER, TOP_BORDER, LEFT_BORDER, RIGHT_BORDER);
        { заголовок }
        drawActiveHeaderMaximized(listener, left + 10, top + 10, width - 20, height - 10);
    end;

    procedure ThemeSoft.drawActiveHeaderMaximized(listener: GraphicListener; left, top, width, height: int);
    const
        HEADER_LEFT: array [0..7, 0..3] of int =
        (
            ( $8fa9c1, $6f879e, $60768b, $60768b ),
            ( $768ca2, $647b91, $4f6376, $4f6376 ),
            ( $7c91a4, $748a9e, $7f99b1, $819bb3 ),
            ( $8197ac, $768ca2, $95afc7, $97b1c9 ),
            ( $839ab0, $7c91a4, $9db7cf, $9db7cf ),
            ( $8fa6bc, $8fa6bc, $abc6de, $adc8e0 ),
            ( $a4bfd7, $afcae2, $c1dcf4, $c2dff7 ),
            ( $afcae2, $b8d4ec, $c4e1fa, $c4e1fa )
        );
        HEADER_CENTER: array [0..7] of int =
        (
            $6d859c, $566b7e, $93adc5, $a6c1da, $aac4dc, $bad6ee, $cfedff, $cfedff
        );
        HEADER_RIGHT: array [0..7, 0..3] of int =
        (
            ( $70869a, $748a9e, $91abc3, $9db7cf ),
            ( $647789, $647b91, $8fa9c1, $9fbad2 ),
            ( $92adc5, $95afc7, $abc6de, $adc8e0 ),
            ( $a1bcd4, $a4bfd7, $b6d2ea, $b2cde5 ),
            ( $a1bcd4, $a4bfd7, $b6d2ea, $afcae2 ),
            ( $adc8e0, $afcae2, $c2dff7, $b3cfe7 ),
            ( $c1dcf4, $c1dcf4, $c6e3fc, $b6d2ea ),
            ( $bfdbf3, $bfdbf3, $bfdbf3, $aac4dc )
        );
        HEADER: array [0..2] of int =
        (
            $9db7c7, $a8c3dc, $a1bcd4
        );
    begin
        drawHeader(listener, left, top, width, height, HEADER_LEFT, HEADER_CENTER, HEADER_RIGHT, HEADER);
    end;

    procedure ThemeSoft.drawActiveBorderLeft(listener: GraphicListener; left, top, width, height: int);
    const
        LEFT_BORDER: array [0..1, 0..9] of int =
        (
            ( $b4cce2, $bad3e9, $bcd5eb, $b8d4ec, $b5d0e7, $b2cde5, $adc8e0, $abc6de, $aac4dc, $a8c3dc ),
            ( $53606a, $5a6774, $5d6b77, $5f7080, $5f7283, $617486, $617486, $617486, $5b7084, $617486 )
        );
    begin
        drawBorderVert(listener, left, top, width, height, LEFT_BORDER);
    end;

    procedure ThemeSoft.drawActiveBorderRight(listener: GraphicListener; left, top, width, height: int);
    const
        RIGHT_BORDER: array [0..1, 0..9] of int =
        (
            ( $879db1, $7c91a4, $70869a, $697e90, $647789, $5d6e7e, $536474, $485664, $333d46, $000000 ),
            ( $415466, $3e5061, $394c5e, $364758, $304151, $2c3b48, $25323e, $1d272f, $080e14, $000000 )
        );
    begin
        drawBorderVert(listener, left, top, width, height, RIGHT_BORDER);
    end;

    procedure ThemeSoft.drawActiveBorderBottom(listener: GraphicListener; left, top, width, height: int);
    const
        LEFT_DOWN_CORNER: array [0..9, 0..9] of int =
        (
            ( $53606a, $5a6774, $5d6b77, $5f7080, $5f7283, $617486, $617486, $617486, $5b7084, $54687b ),
            ( $4a555f, $4f5b65, $54626f, $566675, $586979, $586979, $586979, $566675, $4d6174, $495c6e ),
            (      -1, $434e57, $4a555f, $495866, $4b5a68, $4b5a68, $485664, $455563, $3e5061, $3b4e60 ),
            (      -1, $2e3840, $333d46, $38424c, $374552, $374552, $304151, $2e3e4d, $304151, $324353 ),
            (      -1, $030508, $06080a, $0e161d, $1c252e, $222f3b, $27333f, $2a3947, $2c3b48, $3e3e4d ),
            (      -1,      -1, $000000, $000000, $0e161d, $1c252e, $202c38, $25323e, $283643, $2a3947 ),
            (      -1,      -1,      -1, $000000, $000000, $0c131a, $18212a, $1f2932, $222f3b, $25323e ),
            (      -1,      -1,      -1,      -1, $000000, $000000, $030508, $101921, $18212a, $1d272f ),
            (      -1,      -1,      -1,      -1,      -1, $000000, $000000, $000000, $000000, $080e14 ),
            (      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1, $000000, $000000 )
        );
        RIGHT_DOWN_CORNER: array [0..9, 0..9] of int =
        (
            ( $415466, $3e5061, $394c5e, $364758, $304151, $2c3b48, $25323e, $1d272f, $080e14, $000000 ),
            ( $3b4e60, $364758, $344657, $304151, $2c3b48, $283643, $222f3b, $18212a, $000000, $000000 ),
            ( $364758, $344657, $324353, $2e3e4d, $2a3947, $25323e, $1f2932, $101921, $000000,      -1 ),
            ( $324353, $304151, $2e3e4d, $2a3947, $27333f, $202c38, $18212a, $030508, $000000,      -1 ),
            ( $2e3e4d, $2c3b48, $2a3947, $27333f, $222f3b, $1c252e, $0c131a, $000000, $000000,      -1 ),
            ( $2a3947, $283643, $25323e, $202c38, $1c252e, $0e161d, $000000, $000000,      -1,      -1 ),
            ( $25323e, $222f3b, $1f2932, $18212a, $0c131a, $000000, $000000,      -1,      -1,      -1 ),
            ( $1d272f, $18212a, $101921, $030508, $000000, $000000,      -1,      -1,      -1,      -1 ),
            ( $080e14, $000000, $000000, $000000, $000000,      -1,      -1,      -1,      -1,      -1 ),
            ( $000000, $000000,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1 )
        );
        BOTTOM_BORDER: array [0..9, 0..1] of int =
        (
            ( $4f6376, $415466 ),
            ( $435769, $3b4e60 ),
            ( $374a5b, $364758 ),
            ( $344657, $324353 ),
            ( $304151, $2e3e4d ),
            ( $2c3b48, $2a3947 ),
            ( $283643, $25323e ),
            ( $1f2932, $1d272f ),
            ( $0e161d, $080e14 ),
            ( $000000, $000000 )
        );
    begin
        drawBorderHorz(listener, left, top, width, height, BOTTOM_BORDER, LEFT_DOWN_CORNER, RIGHT_DOWN_CORNER);
    end;

    procedure ThemeSoft.drawActiveWindow(listener: GraphicListener; left, top, width, height: int);
    const
        DISCR = 4;
    var
        v1: GradientData;
        v2: GradientData;
        v3: GradientData;
        h: GradientData;
        len: int;
        w2: int;
        p: int;
        q: int;
        x: int;
        y: int;
    begin
        if (width <= 0) or (height <= 0) then begin
            exit;
        end;
        v1 := GradientData.create();
        v2 := GradientData.create();
        v3 := GradientData.create();
        h := GradientData.create();
        try
            w2 := width shr 1;
            putPixel(listener, left, top, $abc6de);
            putPixel(listener, left + 1, top, $afcae2);
            putPixel(listener, left + width - 2, top, $9fbad2);
            putPixel(listener, left + width - 1, top, $93adc5);
            h.reset($b5d0e7, $bad6ee, w2 - 2);
            repeat
                putPixel(listener, left + h.getCurrentPosition() + 2, top, h.getCurrentColor());
                h.next();
            until not h.needRepeat();
            h.reset($bad6ee, $9fbad2, w2 + (width and 1) - 2);
            repeat
                putPixel(listener, left + h.getCurrentPosition() + w2, top, h.getCurrentColor());
                h.next();
            until not h.needRepeat();
            len := ((height - 1) div DISCR) + 1;
            v1.reset($a4bfd7, $596e82, len);
            v2.reset($a4bfd7, $586c7f, len);
            v3.reset($8aa0b3, $4a5e71, len);
            repeat
                p := DISCR * v2.getCurrentPosition() + 1;
                h.reset(v1.getCurrentColor(), v2.getCurrentColor(), w2 div DISCR + 1);
                repeat
                    for y := 0 to DISCR - 1 do begin
                        if p + y >= height then begin
                            break;
                        end;
                        q := DISCR * h.getCurrentPosition();
                        for x := 0 to DISCR - 1 do begin
                            if q + x >= w2 then begin
                                break;
                            end;
                            putPixel(listener, left + q + x, top + p + y, h.getCurrentColor());
                        end;
                    end;
                    h.next();
                until not h.needRepeat();
                h.reset(v2.getCurrentColor(), v3.getCurrentColor(), ((w2 + (width and 1)) div DISCR) + 1);
                repeat
                    for y := 0 to DISCR - 1 do begin
                        if p + y >= height then begin
                            break;
                        end;
                        q := DISCR * h.getCurrentPosition() + w2;
                        for x := 0 to DISCR - 1 do begin
                            if q + x >= width then begin
                                break;
                            end;
                            putPixel(listener, left + q + x, top + p + y, h.getCurrentColor());
                        end;
                    end;
                    h.next();
                until not h.needRepeat();
                v1.next();
                v2.next();
                v3.next();
            until not v2.needRepeat();
        finally
            v1.free();
            v2.free();
            v3.free();
            h.free();
        end;
    end;

    procedure ThemeSoft.drawInactiveHeader(listener: GraphicListener; left, top, width, height: int);
    const
        LEFT_UP_CORNER: array [0..9, 0..9] of int =
        (
            (      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1, $e2effb, $deebf7 ),
            (      -1,      -1,      -1,      -1,      -1, $eefcff, $edfaff, $e9f7ff, $e7f4ff, $e5f2fe ),
            (      -1,      -1,      -1,      -1, $f4ffff, $f4ffff, $f1fdff, $eefcff, $e9f7ff, $e7f4ff ),
            (      -1,      -1,      -1, $f4ffff, $f4ffff, $f4ffff, $f4ffff, $eefcff, $e9f7ff, $e5f2fe ),
            (      -1,      -1, $f4ffff, $f4ffff, $f4ffff, $fcffff, $fcffff, $f4ffff, $e9f7ff, $e2effb ),
            (      -1, $eefcff, $f4ffff, $f4ffff, $fcffff, $fcffff, $fcffff, $fcffff, $e9f7ff, $deebf7 ),
            (      -1, $edfaff, $f1fdff, $f4ffff, $fcffff, $fcffff, $fcffff, $fcffff, $e5f2fe, $d6e3ef ),
            (      -1, $e9f7ff, $edfaff, $edfaff, $f4ffff, $fcffff, $fcffff, $e9f7ff, $d8e5f1, $cedbe7 ),
            ( $e0edf9, $e5f2fe, $e7f4ff, $e7f4ff, $e7f4ff, $e9f7ff, $e2effb, $d6e3ef, $d0dde9, $c7d4e0 ),
            ( $deebf7, $e2effb, $e2effb, $e2effb, $deebf7, $dae7f3, $d2dfeb, $c9d6e2, $c4d0dc, $becad6 )
        );
        RIGHT_UP_CORNER: array [0..9, 0..9] of int =
        (
            ( $a8b2bc, $a2acb5,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1 ),
            ( $b4bec7, $acb6bf, $a2acb5, $949ca4, $838b92,      -1,      -1,      -1,      -1,      -1 ),
            ( $b8c4cf, $b4bec7, $a8b2bc, $9aa4ae, $8b939b, $7e868d,      -1,      -1,      -1,      -1 ),
            ( $bac6d2, $b6bfc9, $acb6bf, $9ea8b2, $8e969e, $858d95, $777e86,      -1,      -1,      -1 ),
            ( $becad6, $b3c0cc, $aab4be, $9ea8b2, $8f99a3, $878f97, $798188, $6a7177,      -1,      -1 ),
            ( $c4d0dc, $b3c0cc, $a8b2bc, $9aa4ae, $8f99a3, $878f97, $7b838b, $6a7177, $575d63,      -1 ),
            ( $c4d0dc, $b0bdc9, $a4aeb7, $95a0aa, $8b96a1, $878f97, $7b838b, $6a7177, $565b60,      -1 ),
            ( $b8c4cf, $aab7c4, $9ea8b2, $8f99a3, $87939e, $838b92, $798188, $6a7177, $53585c,      -1 ),
            ( $acb9c6, $9eacba, $929eaa, $8995a0, $838f9a, $7b8792, $757d84, $686e74, $505459, $2f3337 ),
            ( $a0aebc, $97a2ac, $8c98a3, $838f9a, $7d8994, $77838e, $737a80, $636a72, $4e5257, $26292c )
        );
        TOP_BORDER: array [0..9, 0..2] of int =
        (
            ( $dce9f5, $b0b9c2, $b0b9c2 ),
            ( $e2effb, $b8c1cb, $b8c4cf ),
            ( $e2effb, $b8c4cf, $bcc8d4 ),
            ( $e0edf9, $b8c4cf, $c0ccd8 ),
            ( $deebf7, $b6c2cd, $c6d2de ),
            ( $d8e5f1, $b3c0cc, $ccd9e5 ),
            ( $d0dde9, $b0bdc9, $c9d6e2 ),
            ( $c9d6e2, $a8b6c3, $becad6 ),
            ( $c0ccd8, $a0aebc, $b0bdc9 ),
            ( $a4b2bf, $93a2b1, $a8b6c3 )
        );
        LEFT_BORDER: array [0..1, 0..9] of int =
        (
            ( $d8e5f1, $deebf7, $deebf7, $deebf7, $dae7f3, $d4e1ed, $ccd9e5, $c6d2de, $bcc8d4, $aebbc7 ),
            ( $cbd6e1, $d2dfeb, $d2dfeb, $d2dfeb, $d0dde9, $ccd9e5, $c6d2de, $c0ccd8, $bcc8d4, $bac6d2 )
        );
        RIGHT_BORDER: array [0..1, 0..9] of int =
        (
            ( $9baab8, $909ca7, $87939e, $818d98, $7b8792, $737f8a, $6b7680, $5e6872, $474f56, $000000 ),
            ( $909ca7, $87939e, $7b8792, $77839e, $707b86, $69747e, $636a72, $525a61, $3c4147, $000000 )
        );
    begin
        if (width < 30) or (height < 20) then begin
            exit;
        end;
        { рамка }
        drawHeaderBorder(listener, left, top, width, height, LEFT_UP_CORNER, RIGHT_UP_CORNER, TOP_BORDER, LEFT_BORDER, RIGHT_BORDER);
        { заголовок }
        drawInactiveHeaderMaximized(listener, left + 10, top + 10, width - 20, height - 10);
    end;

    procedure ThemeSoft.drawInactiveHeaderMaximized(listener: GraphicListener; left, top, width, height: int);
    const
        HEADER_LEFT: array [0..7, 0..3] of int =
        (
            ( $93a2b1, $6d7c8a, $647280, $657482 ),
            ( $6f7e8d, $5a6875, $4f5e6c, $4e5c69 ),
            ( $6a7988, $5f6d7a, $8090a0, $8494a4 ),
            ( $71808f, $606e7c, $99a8b6, $9baab8 ),
            ( $798590, $647280, $a2b0be, $a4b2bf ),
            ( $87939e, $838f9a, $b3c0cc, $b6c2cd ),
            ( $a6b4c1, $aab7c4, $ccd9e5, $cedbe7 ),
            ( $bac6d2, $c0ccd8, $d0dde9, $d0dde9 )
        );
        HEADER_CENTER: array [0..7] of int =
        (
            $657482, $546270, $8898a8, $99a8b6, $9eacba, $a6b4c1, $b6c2cd, $b6c2cd
        );
        HEADER_RIGHT: array [0..7, 0..3] of int =
        (
            ( $798590, $7b8792, $99a8b6, $a4b2bf ),
            ( $677583, $6a7988, $93a2b1, $a6b4c1 ),
            ( $9baab8, $9eacba, $b0bdc9, $b3c0cc ),
            ( $aab7c4, $acb9c6, $bac6d2, $bac6d2 ),
            ( $aab7c4, $acb9c6, $bcc8d4, $b6c2cd ),
            ( $b6c2cd, $b8c4cf, $c7d4e0, $bac6d2 ),
            ( $ccd9e5, $ccd9e5, $c9d6e2, $bcc8d4 ),
            ( $c9d6e2, $c9d6e2, $c9d6e2, $b3c0cc )
        );
        HEADER: array [0..2] of int = ($a2b0be, $9baab8, $a8b6c3);
    begin
        drawHeader(listener, left, top, width, height, HEADER_LEFT, HEADER_CENTER, HEADER_RIGHT, HEADER);
    end;

    procedure ThemeSoft.drawInactiveBorderLeft(listener: GraphicListener; left, top, width, height: int);
    const
        LEFT_BORDER: array [0..1, 0..9] of int =
        (
            ( $cbd6e1, $d2dfeb, $d2dfeb, $d2dfeb, $d0dde9, $ccd9e5, $c6d2de, $c0ccd8, $bcc8d4, $bac6d2 ),
            ( $60656a, $656c71, $6a7177, $6b7680, $6d7984, $707b86, $707b86, $6d7984, $6b7680, $606e7c )
        );
    begin
        drawBorderVert(listener, left, top, width, height, LEFT_BORDER);
    end;

    procedure ThemeSoft.drawInactiveBorderRight(listener: GraphicListener; left, top, width, height: int);
    const
        RIGHT_BORDER: array [0..1, 0..9] of int =
        (
            ( $909ca7, $87939e, $7b8792, $77838e, $707b86, $69747e, $636a72, $525a61, $3c4147, $000000 ),
            ( $4a5865, $485562, $414f5d, $3d4b57, $384551, $353f49, $2d363f, $202931, $0b0f14, $000000 )
        );
    begin
        drawBorderVert(listener, left, top, width, height, RIGHT_BORDER);
    end;

    procedure ThemeSoft.drawInactiveBorderBottom(listener: GraphicListener; left, top, width, height: int);
    const
        LEFT_DOWN_CORNER: array [0..9, 0..9] of int =
        (
            ( $60656a, $656c71, $6a7177, $6b7680, $6d7984, $707b86, $707b86, $6d7984, $6b7680, $606e7c ),
            ( $565b60, $5b6065, $636a72, $636a72, $636d77, $636d77, $636d77, $636d77, $5a6875, $546270 ),
            (      -1, $4e5257, $525a61, $575d63, $545e67, $545e67, $515c66, $4e5964, $485562, $435260 ),
            (      -1, $363c41, $3a3f45, $40464d, $424a52, $3f4952, $384551, $36424d, $384551, $3c4854 ),
            (      -1, $050506, $08090a, $12181d, $202931, $28323b, $2e3841, $313d48, $353f49, $36424d ),
            (      -1,      -1, $000000, $000000, $12181d, $202931, $262f38, $2d363f, $2f3a44, $313d48 ),
            (      -1,      -1,      -1, $000000, $000000, $0f151a, $1d242a, $252c32, $28323b, $2d363f ),
            (      -1,      -1,      -1,      -1, $000000, $000000, $040709, $141b21, $1d242a, $202931 ),
            (      -1,      -1,      -1,      -1,      -1, $000000, $000000, $000000, $000000, $0b0f14 ),
            (      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1, $000000, $000000 )
        );
        RIGHT_DOWN_CORNER: array [0..9, 0..9] of int =
        (
            ( $4a5865, $485562, $414f5d, $3d4b57, $384551, $353f49, $2d363f, $202931, $0b0f14, $000000 ),
            ( $435260, $404e5b, $3d4b57, $384551, $353f49, $2f3a44, $28323b, $1d242a, $000000, $000000 ),
            ( $404e5b, $3d4b57, $3a4753, $36424d, $313d48, $3d363f, $252c32, $141b21, $000000,      -1 ),
            ( $3c4854, $384551, $36424d, $313d48, $2e3841, $262f38, $1d242a, $040709, $000000,      -1 ),
            ( $36424d, $353f49, $313d48, $2e3841, $28323b, $202931, $0f151f, $000000, $000000,      -1 ),
            ( $313d48, $2f3a44, $2d363f, $262f38, $202931, $12181d, $000000, $000000,      -1,      -1 ),
            ( $2d363f, $28323b, $252c32, $1d242a, $0f151a, $000000, $000000,      -1,      -1,      -1 ),
            ( $202931, $2d242a, $141b21, $040709, $000000, $000000,      -1,      -1,      -1,      -1 ),
            ( $0b0f14, $000000, $000000, $000000, $000000,      -1,      -1,      -1,      -1,      -1 ),
            ( $000000, $000000,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1 )
        );
        BOTTOM_BORDER: array [0..9, 0..1] of int =
        (
            ( $5a6875, $4a5865 ),
            ( $4e5c69, $435260 ),
            ( $404e5b, $404e5b ),
            ( $3d4b57, $3c4854 ),
            ( $384551, $36424d ),
            ( $353f49, $313d48 ),
            ( $2e3841, $2d363f ),
            ( $252c32, $202931 ),
            ( $12181d, $0b0f14 ),
            ( $000000, $000000 )
        );
    begin
        drawBorderHorz(listener, left, top, width, height, BOTTOM_BORDER, LEFT_DOWN_CORNER, RIGHT_DOWN_CORNER);
    end;

    procedure ThemeSoft.drawInactiveWindow(listener: GraphicListener; left, top, width, height: int);
    const
        DISCR = 4;
    var
        v1: GradientData;
        v2: GradientData;
        v3: GradientData;
        h: GradientData;
        len: int;
        w2: int;
        p: int;
        q: int;
        x: int;
        y: int;
    begin
        if (width <= 0) or (height <= 0) then begin
            exit;
        end;
        v1 := GradientData.create();
        v2 := GradientData.create();
        v3 := GradientData.create();
        h := GradientData.create();
        try
            w2 := width shr 1;
            putPixel(listener, left, top, $bac6d2);
            putPixel(listener, left + 1, top, $bcc8d4);
            putPixel(listener, left + width - 2, top, $a8b6c3);
            putPixel(listener, left + width - 1, top, $9baab8);
            h.reset($c2ceda, $a8b6c3, w2 - 2);
            repeat
                putPixel(listener, left + h.getCurrentPosition() + 2, top, h.getCurrentColor());
                h.next();
            until not h.needRepeat();
            h.reset($a8b6c3, $aebbc7, w2 + (width and 1) - 2);
            repeat
                putPixel(listener, left + h.getCurrentPosition() + w2, top, h.getCurrentColor());
                h.next();
            until not h.needRepeat();
            len := (height - 1) div DISCR + 1;
            v1.reset($b3c0cc, $62707e, len);
            v2.reset($99a8b6, $6a7988, len);
            v3.reset($929eaa, $5c6a77, len);
            repeat
                p := DISCR * v2.getCurrentPosition() + 1;
                h.reset(v1.getCurrentColor(), v2.getCurrentColor(), (w2 div DISCR) + 1);
                repeat
                    for y := 0 to DISCR - 1 do begin
                        if p + y >= height then begin
                            break;
                        end;
                        q := DISCR * h.getCurrentPosition();
                        for x := 0 to DISCR - 1 do begin
                            if q + x >= w2 then begin
                                break;
                            end;
                            putPixel(listener, left + q + x, top + p + y, h.getCurrentColor());
                        end;
                    end;
                    h.next();
                until not h.needRepeat();
                h.reset(v2.getCurrentColor(), v3.getCurrentColor(), ((w2 + (width and 1)) div DISCR) + 1);
                repeat
                    for y := 0 to DISCR - 1 do begin
                        if p + y >= height then begin
                            break;
                        end;
                        q := DISCR * h.getCurrentPosition() + w2;
                        for x := 0 to DISCR - 1 do begin
                            if q + x >= width then begin
                                break;
                            end;
                            putPixel(listener, left + q + x, top + p + y, h.getCurrentColor());
                        end;
                    end;
                    h.next();
                until not h.needRepeat();
                v1.next();
                v2.next();
                v3.next();
            until not v2.needRepeat();
        finally
            v1.free();
            v2.free();
            v3.free();
            h.free();
        end;
    end;

    procedure ThemeSoft.drawDisabledHeader(listener: GraphicListener; left, top, width, height: int);
    const
        LEFT_UP_CORNER: array [0..9, 0..9] of int =
        (
            (      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1, $f8f9fa, $f6f7f7 ),
            (      -1,      -1,      -1,      -1,      -1, $feffff, $feffff, $feffff, $feffff, $fcfdfd ),
            (      -1,      -1,      -1,      -1, $feffff, $feffff, $feffff, $feffff, $feffff, $feffff ),
            (      -1,      -1,      -1, $feffff, $feffff, $feffff, $feffff, $feffff, $feffff, $fcfdfd ),
            (      -1,      -1, $feffff, $feffff, $feffff, $feffff, $feffff, $feffff, $feffff, $f8f9fa ),
            (      -1, $feffff, $feffff, $feffff, $feffff, $feffff, $feffff, $feffff, $f9fbfc, $f2f3f4 ),
            (      -1, $feffff, $feffff, $feffff, $feffff, $feffff, $feffff, $f9fbfc, $f2f3f4, $eaebec ),
            (      -1, $feffff, $feffff, $feffff, $feffff, $feffff, $f9fbfc, $f2f3f4, $ecedee, $e3e5e6 ),
            ( $f8f9fa, $feffff, $feffff, $feffff, $fcfdfd, $f8f9fa, $f2f3f4, $eaebec, $e3e5e6, $dbdddf ),
            ( $f4f5f6, $f9fbfc, $fcfdfd, $f8f9fa, $f4f5f6, $eeeff0, $e8e9ea, $dfe1e2, $d9dbdd, $d0d4d7 )
        );
        RIGHT_UP_CORNER: array [0..9, 0..9] of int =
        (
            ( $bbbbbc, $b2b3b3,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1 ),
            ( $c6c6c7, $bebebf, $b4b4b5, $a4a6a7, $929292,      -1,      -1,      -1,      -1,      -1 ),
            ( $ccced0, $c6c6c7, $bbbbbc, $abacad, $999b9c, $8c8c8c,      -1,      -1,      -1,      -1 ),
            ( $ccced0, $c6c8c9, $bebebf, $b0b1b2, $9d9fa1, $929292, $858585,      -1,      -1,      -1 ),
            ( $cdd0d2, $c6c8c9, $bebebf, $b0b1b2, $a0a0a1, $959799, $87888a, $767676,      -1,      -1 ),
            ( $ccced0, $c2c5c8, $bbbbbc, $abaeb0, $a0a0a1, $959799, $8a8a8a, $787878, $626262,      -1 ),
            ( $caccce, $bdc1c5, $b4b4b5, $a7a8a9, $9d9fa1, $929597, $87888a, $767676, $606060,      -1 ),
            ( $c2c5c8, $b9bdc1, $b0b1b2, $9ea1a5, $999b9c, $909396, $858788, $767676, $5a5c5e,      -1 ),
            ( $bbbfc3, $b0b5ba, $a4a6a7, $989ca1, $959799, $898d90, $7f8286, $717374, $595959, $333538 ),
            ( $b2b7bb, $a5abb0, $9aa1a7, $929597, $8d9195, $83888d, $7c7f81, $6c7074, $565757, $2c2c2c )
        );
        TOP_BORDER: array [0..9, 0..2] of int =
        (
            ( $f2f3f4, $c2c2c2, $bbbbbc ),
            ( $f8f9fa, $c9c9c9, $c6c6c7 ),
            ( $f9fbfc, $ccced0, $ccced0 ),
            ( $f8f9fa, $ccced0, $ccced0 ),
            ( $f4f5f6, $caccce, $cdd0d2 ),
            ( $eeeff0, $c7cacc, $ccced0 ),
            ( $e5e7e8, $c2c5c8, $caccce ),
            ( $dddfe0, $bbbfc3, $c2c5c8 ),
            ( $d3d5d7, $b0b5ba, $bbbfc3 ),
            ( $bfc3c6, $9aa1a7, $b2b7bb )
        );
        LEFT_BORDER: array [0..1, 0..9] of int =
        (
            ( $eeeff0, $f6f7f7, $f6f7f7, $f4f5f6, $f0f1f2, $eaebec, $e1e3e4, $d9dbdd, $d0d2d4, $b0b5ba ),
            ( $e1e3e4, $e8e9ea, $eaebec, $e8e9ea, $e5e7e8, $e1e3e4, $dbdddf, $d5d7d9, $d0d2d4, $cdd0d2 )
        );
        RIGHT_BORDER: array [0..1, 0..9] of int =
        (
            ( $a9afb4, $9fa5ab, $97999b, $909396, $8c8f92, $818589, $777c80, $6c6d6f, $4f5358, $000000 ),
            ( $9da3a9, $97999b, $898d90, $83888d, $7f8286, $757a7f, $6a6e73, $5d5f62, $454749, $000000 )
        );
    begin
        if (width < 30) or (height < 20) then begin
            exit;
        end;
        { рамка }
        drawHeaderBorder(listener, left, top, width, height, LEFT_UP_CORNER, RIGHT_UP_CORNER, TOP_BORDER, LEFT_BORDER, RIGHT_BORDER);
        { заголовок }
        drawDisabledHeaderMaximized(listener, left + 10, top + 10, width - 20, height - 10);
    end;

    procedure ThemeSoft.drawDisabledHeaderMaximized(listener: GraphicListener; left, top, width, height: int);
    const
        HEADER_LEFT: array [0..7, 0..3] of int =
        (
            ( $9da3a9, $707981, $6d757d, $6e777f ),
            ( $727b83, $636c74, $56616a, $56616a ),
            ( $747d85, $697179, $878f96, $8b939a ),
            ( $7b838b, $697179, $a5abb0, $a7adb2 ),
            ( $838b92, $6b737b, $b0b5ba, $b4b9bd ),
            ( $9299a0, $878f96, $c7cacc, $c7cacc ),
            ( $b6bbbf, $bbbfc3, $e1e3e4, $e3e5e6 ),
            ( $cdd0d2, $d5d7d9, $e5e7e8, $e8e9ea )
        );
        HEADER_CENTER: array [0..7] of int =
        (
            $707981, $5c6772, $90979e, $a3a9af, $acb1b6, $b9bdc1, $c7cacc, $c7cacc
        );
        HEADER_RIGHT: array [0..7, 0..3] of int =
        (
            ( $838b92, $838b92, $a3a9af, $b0b5ba ),
            ( $727b83, $747d85, $a3a9af, $b2b7bb ),
            ( $a5abb0, $a7adb2, $c3c7ca, $c3c7ca ),
            ( $b6bbbf, $b9bdc1, $cdd0d2, $caccce ),
            ( $b9bdc1, $bbbfc3, $ccced0, $c7cacc ),
            ( $c3c7ca, $c7cacc, $d0d4d7, $caccce ),
            ( $d0d2d4, $d0d2d4, $d7d9db, $ccced0 ),
            ( $ccced0, $ccced0, $d0d2d4, $c2c5c8 )
        );
        HEADER: array [0..2] of int =
        (
            $aeb3b8, $a7adb2, $b6bbbf
        );
    begin
        drawHeader(listener, left, top, width, height, HEADER_LEFT, HEADER_CENTER, HEADER_RIGHT, HEADER);
    end;

    procedure ThemeSoft.drawDisabledBorderLeft(listener: GraphicListener; left, top, width, height: int);
    const
        LEFT_BORDER: array [0..1, 0..9] of int =
        (
            ( $e1e3e4, $e8e9ea, $eaebec, $e8e9ea, $e5e7e8, $e1e3e4, $dbdddf, $d5d7d9, $d0d2d4, $cdd0d2 ),
            ( $6a6a6a, $717171, $787878, $777c80, $7c7f81, $7c8185, $7f8286, $777f87, $777c80, $6d757d )
        );
    begin
        drawBorderVert(listener, left, top, width, height, LEFT_BORDER);
    end;

    procedure ThemeSoft.drawDisabledBorderRight(listener: GraphicListener; left, top, width, height: int);
    const
        RIGHT_BORDER: array [0..1, 0..9] of int =
        (
            ( $9da3a9, $97999b, $898d90, $83888d, $7f8286, $757a7f, $6a6e73, $5d5f62, $454749, $000000 ),
            ( $545e66, $4f5961, $49545d, $454f58, $404a52, $394148, $31383e, $282c30, $0d1114, $000000 )
        );
    begin
        drawBorderVert(listener, left, top, width, height, RIGHT_BORDER);
    end;

    procedure ThemeSoft.drawDisabledBorderBottom(listener: GraphicListener; left, top, width, height: int);
    const
        LEFT_DOWN_CORNER: array [0..9, 0..9] of int =
        (
            ( $6a6a6a, $717171, $787878, $777c80, $7c7f81, $7c8185, $7f8286, $777f87, $777c80, $6d757d ),
            ( $606060, $626567, $6c6d6f, $717374, $6f7478, $6f7478, $6f7478, $6e7276, $636c74, $6c656e ),
            (      -1, $565757, $5a5c5e, $5d6267, $5f6368, $5f6368, $5b6065, $595e63, $4f5961, $4b565f ),
            (      -1, $3d3f41, $424343, $494b4c, $494e52, $464c51, $42484d, $3d464d, $3f4850, $424b53 ),
            (      -1, $050608, $0a0a0a, $151a1d, $23282c, $2d353b, $333a40, $374047, $3b434a, $3d464d ),
            (      -1,      -1, $000000, $000000, $151a1d, $23282c, $2b3339, $333a40, $353d44, $394148 ),
            (      -1,      -1,      -1, $000000, $000000, $12161a, $21262a, $2a2e32, $2d353b, $31383e ),
            (      -1,      -1,      -1,      -1, $000000, $000000, $050608, $181d21, $21262a, $282c30 ),
            (      -1,      -1,      -1,      -1,      -1, $000000, $000000, $000000, $000000, $0d1114 ),
            (      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1, $000000, $000000 )
        );
        RIGHT_DOWN_CORNER: array [0..9, 0..9] of int =
        (
            ( $545e66, $4f5961, $49545d, $454f58, $404a52, $394148, $31383e, $282c30, $0d1114, $000000 ),
            ( $4b565f, $454f58, $444e56, $3f4850, $3b434a, $353d44, $2d353b, $21262a, $000000, $000000 ),
            ( $454f58, $444e56, $404a52, $3d464d, $374047, $333a40, $2a2e32, $181d21, $000000,      -1 ),
            ( $424b53, $3f4850, $3d464d, $374047, $333a40, $2b3339, $21262a, $050608, $000000,      -1 ),
            ( $3d464d, $3b434a, $374047, $333a40, $2d353b, $23282c, $12161a, $000000, $000000,      -1 ),
            ( $394148, $353d44, $333a40, $2b3339, $23282c, $151a1d, $000000, $000000,      -1,      -1 ),
            ( $31383e, $2d353b, $2a2e32, $21262a, $12161a, $000000, $000000,      -1,      -1,      -1 ),
            ( $282c30, $21262a, $181d21, $050608, $000000, $000000,      -1,      -1,      -1,      -1 ),
            ( $0d1114, $000000, $000000, $000000, $000000,      -1,      -1,      -1,      -1,      -1 ),
            ( $000000, $000000,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1 )
        );
        BOTTOM_BORDER: array [0..9, 0..1] of int =
        (
            ( $636c74, $545e66 ),
            ( $596168, $4b565f ),
            ( $47525b, $454f58 ),
            ( $444e56, $424b53 ),
            ( $3f4850, $3d464d ),
            ( $3b434a, $394148 ),
            ( $333a40, $31383e ),
            ( $2a2e32, $282c30 ),
            ( $151a1d, $0d1114 ),
            ( $000000, $000000 )
        );
    begin
        drawBorderHorz(listener, left, top, width, height, BOTTOM_BORDER, LEFT_DOWN_CORNER, RIGHT_DOWN_CORNER);
    end;

    procedure ThemeSoft.drawDisabledWindow(listener: GraphicListener; left, top, width, height: int);
    const
        DISCR = 4;
    var
        v1: GradientData;
        v2: GradientData;
        v3: GradientData;
        h: GradientData;
        len: int;
        w2: int;
        p: int;
        q: int;
        x: int;
        y: int;
    begin
        if (width <= 0) or (height <= 0) then begin
            exit;
        end;
        v1 := GradientData.create();
        v2 := GradientData.create();
        v3 := GradientData.create();
        h := GradientData.create();
        try
            w2 := width shr 1;
            putPixel(listener, left, top, $ccced0);
            putPixel(listener, left + 1, top, $cdd0d2);
            putPixel(listener, left + width - 2, top, $b9bdc1);
            putPixel(listener, left + width - 1, top, $acb1b6);
            h.reset($d7d9db, $b9bdc1, w2 - 2);
            repeat
                putPixel(listener, left + h.getCurrentPosition() + 2, top, h.getCurrentColor());
                h.next();
            until not h.needRepeat();
            h.reset($b9bdc1, $b9bdc1, w2 + (width and 1) - 2);
            repeat
                putPixel(listener, left + h.getCurrentPosition() + w2, top, h.getCurrentColor());
                h.next();
            until not h.needRepeat();
            len := ((height - 1) div DISCR) + 1;
            v1.reset($c3c7ca, $707981, len);
            v2.reset($a7adb2, $6b737b, len);
            v3.reset($9fa5ab, $5c656e, len);
            repeat
                p := (DISCR * v2.getCurrentPosition()) + 1;
                h.reset(v1.getCurrentColor(), v2.getCurrentColor(), (w2 div DISCR) + 1);
                repeat
                    for y := 0 to DISCR - 1 do begin
                        if p + y >= height then begin
                            break;
                        end;
                        q := DISCR * h.getCurrentPosition();
                        for x := 0 to DISCR - 1 do begin
                            if q + x >= w2 then begin
                                break;
                            end;
                            putPixel(listener, left + q + x, top + p + y, h.getCurrentColor());
                        end;
                    end;
                    h.next();
                until not h.needRepeat();
                h.reset(v2.getCurrentColor(), v3.getCurrentColor(), ((w2 + (width and 1)) div DISCR) + 1);
                repeat
                    for y := 0 to DISCR - 1 do begin
                        if p + y >= height then begin
                            break;
                        end;
                        q := (DISCR * h.getCurrentPosition()) + w2;
                        for x := 0 to DISCR - 1 do begin
                            if q + x >= width then begin
                                break;
                            end;
                            putPixel(listener, left + q + x, top + p + y, h.getCurrentColor());
                        end;
                    end;
                    h.next();
                until not h.needRepeat();
                v1.next();
                v2.next();
                v3.next();
            until not v2.needRepeat();
        finally
            v1.free();
            v2.free();
            v3.free();
            h.free();
        end;
    end;

    procedure ThemeSoft.drawListItemNoFocus(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..5] of int =
        (
            $a1c1c9, $d5e4e7, $91b4ba, $eff7f9, $e3f1f4, $c3e3e8
        );
    begin
        drawListItem(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawListItemWithFocus(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..5] of int =
        (
            $99cfd8, $cceaf0, $7dc2ce, $ebfafd, $daf8fd, $b0f0fb
        );
    begin
        drawListItem(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawListItemInactive(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..5] of int =
        (
            $ababab, $dedede, $a5a5a5, $f4f4f4, $ebebeb, $d6d6d6
        );
    begin
        drawListItem(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTableHeaderNormal(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $010001, $daecfd, $b0d7fb, $4c6680
        );
    begin
        drawTableHeader(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTableHeaderPressed(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $020002, $b0d7fb, $daecfd, $4c6680
        );
    begin
        drawTableHeader(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTableHeaderDisabled(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $010001, $ebebeb, $d6d6d6, $909090
        );
    begin
        drawTableHeader(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawButtonNormal(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..2] of int =
        (
            $405468, $c9ddf1, $43576b
        );
    begin
        drawButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawButtonPressed(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..2] of int =
        (
            $405468, $91576b, $cbddf1
        );
    begin
        drawButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawButtonDisabled(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..2] of int =
        (
            $545454, $dddddd, $575757
        );
    begin
        drawButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawButtonWithFocus(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..2] of int =
        (
            $405468, $cbddf1, $91576b
        );
    begin
        drawButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawDropDownButtonNormal(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $000000, $97cafc, $4e6883, $000000
        );
    begin
        drawDropDownButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawDropDownButtonPressed(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $010001, $4e6883, $97cafc, $000000
        );
    begin
        drawDropDownButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawDropDownButtonDisabled(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $000000, $cacaca, $686868, $666666
        );
    begin
        drawDropDownButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolButtonNormal(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..2] of int =
        (
            $405468, $c9ddf1, $43576b
        );
    begin
        drawButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolButtonPressed(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..2] of int =
        (
            $405468, $43576b, $c9ddf1
        );
    begin
        drawButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolButtonDisabled(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..2] of int =
        (
            $545454, $dddddd, $575757
        );
    begin
        drawButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolButtonPushed(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..2] of int =
        (
            $405468, $91576b, $cbddf1
        );
    begin
        drawButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolButtonWithNextNormal(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $405468, $c9ddf1, $43576b, $000000
        );
    begin
        drawToolButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolButtonWithNextPressed(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $405468, $43576b, $c9ddf1, $010001
        );
    begin
        drawToolButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolButtonWithNextDisabled(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $545454, $dddddd, $575757, $000000
        );
    begin
        drawToolButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolButtonWithNextPushed(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $405468, $91576b, $cbddf1, $010001
        );
    begin
        drawToolButton(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolDropDownNormal(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $405468, $c9ddf1, $43576b, $000000
        );
    begin
        drawToolDropDown(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolDropDownPressed(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $405468, $43576b, $c9ddf1, $010001
        );
    begin
        drawToolDropDown(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolDropDownDisabled(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $545454, $dddddd, $575757, $000000
        );
    begin
        drawToolDropDown(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolDropDownPushed(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $405468, $91576b, $cbddf1, $010001
        );
    begin
        drawToolDropDown(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawToolHorzSeparator(listener: GraphicListener; left, top, width, height: int);
    var
        i: int;
        c: int;
    begin
        if width < 1 then begin
            exit;
        end;
        c := left + ((width - 1) shr 1);
        for i := 0 to height - 1 do begin
            putPixel(listener, c, top + i, $9baab8);
        end;
    end;

    procedure ThemeSoft.drawToolVertSeparator(listener: GraphicListener; left, top, width, height: int);
    var
        i: int;
        c: int;
    begin
        if height < 1 then begin
            exit;
        end;
        c := top + ((height - 1) shr 1);
        for i := 0 to width - 1 do begin
            putPixel(listener, left + i, c, $9baab8);
        end;
    end;

    procedure ThemeSoft.drawTextFieldNormal(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $4c6680, $99ccff, $cde7ff, $ffffff
        );
    begin
        drawFieldHorz(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTextFieldWithFocus(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $4c6680, $99ccff, $ffffff, $ffffff
        );
    begin
        drawFieldHorz(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTextFieldDisabled(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $666666, $cccccc, $b5b5b5, $cbcbcb
        );
    begin
        drawFieldHorz(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTextFieldReadOnly(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $4c6680, $99ccff, $c1c1c1, $ffffff
        );
    begin
        drawFieldHorz(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawProgressHorzBackground(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $606060, $c0c0c0, $d6d6d6, $ebebeb
        );
    begin
        drawFieldHorz(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawProgressHorzFill(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..5] of int =
        (
            5,
            $6f6fa4, $adadcb, $7a7aaa, $7171a5, $a7a7c7
        );
    begin
        drawGradientsHorz(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawProgressVertBackground(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..3] of int =
        (
            $606060, $c0c0c0, $d6d6d6, $ebebeb
        );
    begin
        drawFieldVert(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawProgressVertFill(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..5] of int =
        (
            5,
            $6f6fa4, $adadcb, $7a7aaa, $7171a5, $a7a7c7
        );
    begin
        drawGradientsVert(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTrackbarHorzNormal(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..5] of int =
        (
            $405468,
            4,
            $526d87, $779fc6, $6586a7, $405468
        );
    begin
        drawTrackbarHorz(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTrackbarHorzWithFocus(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..5] of int =
        (
            $405468,
            4,
            $9f778b, $bdbdd1, $ae9aae, $405468
        );
    begin
        drawTrackbarHorz(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTrackbarHorzDisabled(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..5] of int =
        (
            $545454,
            4,
            $777777, $bdbdbd, $9a9a9a, $545454
        );
    begin
        drawTrackbarHorz(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTrackbarVertNormal(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..5] of int =
        (
            $405468,
            4,
            $526d87, $779fc6, $6586a7, $405468
        );
    begin
        drawTrackbarVert(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTrackbarVertWithFocus(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..5] of int =
        (
            $405468,
            4,
            $9f778b, $bdbdd1, $ae9aae, $405468
        );
    begin
        drawTrackbarVert(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawTrackbarVertDisabled(listener: GraphicListener; left, top, width, height: int);
    const
        DATA: array [0..5] of int =
        (
            $545454,
            4,
            $777777, $bdbdbd, $9a9a9a, $545454
        );
    begin
        drawTrackbarVert(listener, left, top, width, height, DATA);
    end;

    procedure ThemeSoft.drawScrollbarElement(listener: GraphicListener; left, top, width, height: int; orientation, element, state: int);
    const
        BUTTONS_GRADIENT_DATA: array [0..4] of int =
        (
            4,
            $f0f0f0, $f0f0f0, $b4c4d4, $b4c4d4
        );
        BUTTONS_GRADIENT_DATA_PRESSED: array [0..4] of int =
        (
            4,
            $b4c4d4, $b4c4d4, $f0f0f0, $f0f0f0
        );
        SLIDER_GRADIENT_DATA: array [0..2, 0..5] of int =
        (
            (
                5,
                $cecece, $ececec, $ececec, $ececec, $cecece
            ), (
                5,
                $9c9c9c, $bababa, $bababa, $bababa, $9c9c9c
            ), (
                5,
                $cdcdcd, $e2e2e2, $e2e2e2, $e2e2e2, $cdcdcd
            )
        );
        ARROW_UP: array [0..3, 0..6] of int =
        (
            (      -1,      -1,      -1, $b5bbc1,      -1,      -1,      -1 ),
            (      -1,      -1, $b5bbc1, $606060, $b5bbc1,      -1,      -1 ),
            (      -1, $b5bbc1, $606060, $606060, $606060, $b5bbc1,      -1 ),
            ( $b5bbc1, $606060, $606060, $606060, $606060, $606060, $b5bbc1 )
        );
        ARROW_DOWN: array [0..3, 0..6] of int =
        (
            ( $b5bbc1, $606060, $606060, $606060, $606060, $606060, $b5bbc1 ),
            (      -1, $b5bbc1, $606060, $606060, $606060, $b5bbc1,      -1 ),
            (      -1,      -1, $b5bbc1, $606060, $b5bbc1,      -1,      -1 ),
            (      -1,      -1,      -1, $b5bbc1,      -1,      -1,      -1 )
        );
        ARROW_LEFT: array [0..6, 0..3] of int =
        (
            (      -1,      -1,      -1, $b5bbc1 ),
            (      -1,      -1, $b5bbc1, $606060 ),
            (      -1, $b5bbc1, $606060, $606060 ),
            ( $b5bbc1, $606060, $606060, $606060 ),
            (      -1, $b5bbc1, $606060, $606060 ),
            (      -1,      -1, $b5bbc1, $606060 ),
            (      -1,      -1,      -1, $b5bbc1 )
        );
        ARROW_RIGHT: array [0..6, 0..3] of int =
        (
            ( $b5bbc1,      -1,      -1,      -1 ),
            ( $606060, $b5bbc1,      -1,      -1 ),
            ( $606060, $606060, $b5bbc1,      -1 ),
            ( $606060, $606060, $606060, $b5bbc1 ),
            ( $606060, $606060, $b5bbc1,      -1 ),
            ( $606060, $b5bbc1,      -1,      -1 ),
            ( $b5bbc1,      -1,      -1,      -1 )
        );
        ARROW_UP_DISABLED: array [0..3, 0..6] of int =
        (
            (      -1,      -1,      -1, $c9cfd5,      -1,      -1,      -1 ),
            (      -1,      -1, $c9cfd5, $b0b0b0, $c9cfd5,      -1,      -1 ),
            (      -1, $c9cfd5, $b0b0b0, $b0b0b0, $b0b0b0, $c9cfd5,      -1 ),
            ( $c9cfd5, $b0b0b0, $b0b0b0, $b0b0b0, $b0b0b0, $b0b0b0, $c9cfd5 )
        );
        ARROW_DOWN_DISABLED: array [0..3, 0..6] of int =
        (
            ( $c9cfd5, $b0b0b0, $b0b0b0, $b0b0b0, $b0b0b0, $b0b0b0, $c9cfd5 ),
            (      -1, $c9cfd5, $b0b0b0, $b0b0b0, $b0b0b0, $c9cfd5,      -1 ),
            (      -1,      -1, $c9cfd5, $b0b0b0, $c9cfd5,      -1,      -1 ),
            (      -1,      -1,      -1, $c9cfd5,      -1,      -1,      -1 )
        );
        ARROW_LEFT_DISABLED: array [0..6, 0..3] of int =
        (
            (      -1,      -1,      -1, $c9cfd5 ),
            (      -1,      -1, $c9cfd5, $b0b0b0 ),
            (      -1, $c9cfd5, $b0b0b0, $b0b0b0 ),
            ( $c9cfd5, $b0b0b0, $b0b0b0, $b0b0b0 ),
            (      -1, $c9cfd5, $b0b0b0, $b0b0b0 ),
            (      -1,      -1, $c9cfd5, $b0b0b0 ),
            (      -1,      -1,      -1, $c9cfd5 )
        );
        ARROW_RIGHT_DISABLED: array [0..6, 0..3] of int =
        (
            ( $c9cfd5,      -1,      -1,      -1 ),
            ( $b0b0b0, $c9cfd5,      -1,      -1 ),
            ( $b0b0b0, $b0b0b0, $c9cfd5,      -1 ),
            ( $b0b0b0, $b0b0b0, $b0b0b0, $c9cfd5 ),
            ( $b0b0b0, $b0b0b0, $c9cfd5,      -1 ),
            ( $b0b0b0, $c9cfd5,      -1,      -1 ),
            ( $c9cfd5,      -1,      -1,      -1 )
        );
        BORDER_COLORS: array [0..2] of int =
        (
            $606060, $606060, $b0b0b0
        );
        CORNER_COLORS: array [0..2] of int =
        (
            $707070, $707070, $b8b8b8
        );
    var
        i: int;
        j: int;
        x: int;
        y: int;
        c: int;
    begin
        case element of
        SCROLLBAR_ELEMENT_BACK_BUTTON, SCROLLBAR_ELEMENT_NEXT_BUTTON, SCROLLBAR_ELEMENT_SLIDER: begin
            c := CORNER_COLORS[state];
            for i := 0 to 1 do for j := 0 to 1 do begin
                putPixel(listener, left + (width - 1) * i, top + (height - 1) * j, c);
            end;
            c := BORDER_COLORS[state];
            for i := 1 to width - 2 do begin
                putPixel(listener, left + i, top, c);
                putPixel(listener, left + i, top + height - 1, c);
            end;
            for i := 1 to height - 2 do begin
                putPixel(listener, left, top + i, c);
                putPixel(listener, left + width - 1, top + i, c);
            end;
            if orientation = SCROLLBAR_ORIENTATION_HORIZONTAL then begin
                if state = SCROLLBAR_STATE_PRESSED then begin
                    drawGradientsHorz(listener, left + 1, top + 1, width - 2, height - 2, BUTTONS_GRADIENT_DATA_PRESSED);
                end else begin
                    drawGradientsHorz(listener, left + 1, top + 1, width - 2, height - 2, BUTTONS_GRADIENT_DATA);
                end;
            end else begin
                if state = SCROLLBAR_STATE_PRESSED then begin
                    drawGradientsVert(listener, left + 1, top + 1, width - 2, height - 2, BUTTONS_GRADIENT_DATA_PRESSED);
                end else begin
                    drawGradientsVert(listener, left + 1, top + 1, width - 2, height - 2, BUTTONS_GRADIENT_DATA);
                end;
            end;
            case element of
            SCROLLBAR_ELEMENT_BACK_BUTTON: begin
                if orientation = SCROLLBAR_ORIENTATION_HORIZONTAL then begin
                    x := (width - 5) div 2;
                    y := (height - 7) div 2;
                    if state = SCROLLBAR_STATE_PRESSED then begin
                        inc(x);
                        inc(y);
                    end;
                    if state = SCROLLBAR_STATE_DISABLED then begin
                        draw(listener, left + x, top + y, 4, 7, ARROW_LEFT_DISABLED);
                    end else begin
                        draw(listener, left + x, top + y, 4, 7, ARROW_LEFT);
                    end;
                end else begin
                    x := (width - 7) div 2;
                    y := (height - 5) div 2;
                    if state = SCROLLBAR_STATE_PRESSED then begin
                        inc(x);
                        inc(y);
                    end;
                    if state = SCROLLBAR_STATE_DISABLED then begin
                        draw(listener, left + x, top + y, 7, 4, ARROW_UP_DISABLED);
                    end else begin
                        draw(listener, left + x, top + y, 7, 4, ARROW_UP);
                    end;
                end;
            end;
            SCROLLBAR_ELEMENT_NEXT_BUTTON: begin
                if orientation = SCROLLBAR_ORIENTATION_HORIZONTAL then begin
                    x := (width - 5) div 2 + 1;
                    y := (height - 7) div 2;
                    if state = SCROLLBAR_STATE_PRESSED then begin
                        inc(x);
                        inc(y);
                    end;
                    if state = SCROLLBAR_STATE_DISABLED then begin
                        draw(listener, left + x, top + y, 4, 7, ARROW_RIGHT_DISABLED);
                    end else begin
                        draw(listener, left + x, top + y, 4, 7, ARROW_RIGHT);
                    end;
                end else begin
                    x := (width - 7) div 2;
                    y := (height - 5) div 2 + 1;
                    if state = SCROLLBAR_STATE_PRESSED then begin
                        inc(x);
                        inc(y);
                    end;
                    if state = SCROLLBAR_STATE_DISABLED then begin
                        draw(listener, left + x, top + y, 7, 4, ARROW_DOWN_DISABLED);
                    end else begin
                        draw(listener, left + x, top + y, 7, 4, ARROW_DOWN);
                    end;
                end;
            end;
            end;
        end;
        SCROLLBAR_ELEMENT_BACK_TRACK, SCROLLBAR_ELEMENT_NEXT_TRACK: begin
            if orientation = SCROLLBAR_ORIENTATION_HORIZONTAL then begin
                drawGradientsHorz(listener, left, top, width, height, SLIDER_GRADIENT_DATA[state]);
            end else begin
                drawGradientsVert(listener, left, top, width, height, SLIDER_GRADIENT_DATA[state]);
            end;
        end;
        end;
    end;

    procedure ThemeSoft.drawScrollbarSizegrip(listener: GraphicListener; left, top, width, height: int);
    var
        x: int;
        y: int;
    begin
        for y := 0 to height - 1 do for x := 0 to width - 1 do begin
            putPixel(listener, left + x, top + y, $c0c0c0);
        end;
    end;

    procedure ThemeSoft.drawScrollbarSizegripRight(listener: GraphicListener; left, top, width, height: int);
    const
        SIZEGRIP: array [0..10, 0..10] of int =
        (
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1, $d2d2d2, $c9c9c9, $bababa ),
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1, $c9c9c9, $b8b8b8, $a7a7a7 ),
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1, $bababa, $a7a7a7, $a1a1a1 ),
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1,      -1,      -1,      -1 ),
            (      -1,      -1,      -1, -1, $d2d2d2, $c9c9c9, $bababa, -1, $d2d2d2, $c9c9c9, $bababa ),
            (      -1,      -1,      -1, -1, $c9c9c9, $b8b8b8, $a7a7a7, -1, $c9c9c9, $b8b8b8, $a7a7a7 ),
            (      -1,      -1,      -1, -1, $bababa, $a7a7a7, $a1a1a1, -1, $bababa, $a7a7a7, $a1a1a1 ),
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1,      -1,      -1,      -1 ),
            ( $d2d2d2, $c9c9c9, $bababa, -1, $d2d2d2, $c9c9c9, $bababa, -1, $d2d2d2, $c9c9c9, $bababa ),
            ( $c9c9c9, $b8b8b8, $a7a7a7, -1, $c9c9c9, $b8b8b8, $a7a7a7, -1, $c9c9c9, $b8b8b8, $a7a7a7 ),
            ( $bababa, $a7a7a7, $a1a1a1, -1, $bababa, $a7a7a7, $a1a1a1, -1, $bababa, $a7a7a7, $a1a1a1 )
        );
    begin
        drawScrollbarSizegrip(listener, left, top, width, height);
        draw(listener, left + width - 12, top + height - 12, 11, 11, SIZEGRIP);
    end;

    procedure ThemeSoft.drawScrollbarSizegripLeft(listener: GraphicListener; left, top, width, height: int);
    const
        SIZEGRIP: array [0..10, 0..10] of int =
        (
            ( $d2d2d2, $c9c9c9, $bababa, -1,      -1,      -1,      -1, -1,      -1,      -1,      -1 ),
            ( $c9c9c9, $b8b8b8, $a7a7a7, -1,      -1,      -1,      -1, -1,      -1,      -1,      -1 ),
            ( $bababa, $a7a7a7, $a1a1a1, -1,      -1,      -1,      -1, -1,      -1,      -1,      -1 ),
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1,      -1,      -1,      -1 ),
            ( $d2d2d2, $c9c9c9, $bababa, -1, $d2d2d2, $c9c9c9, $bababa, -1,      -1,      -1,      -1 ),
            ( $c9c9c9, $b8b8b8, $a7a7a7, -1, $c9c9c9, $b8b8b8, $a7a7a7, -1,      -1,      -1,      -1 ),
            ( $bababa, $a7a7a7, $a1a1a1, -1, $bababa, $a7a7a7, $a1a1a1, -1,      -1,      -1,      -1 ),
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1,      -1,      -1,      -1 ),
            ( $d2d2d2, $c9c9c9, $bababa, -1, $d2d2d2, $c9c9c9, $bababa, -1, $d2d2d2, $c9c9c9, $bababa ),
            ( $c9c9c9, $b8b8b8, $a7a7a7, -1, $c9c9c9, $b8b8b8, $a7a7a7, -1, $c9c9c9, $b8b8b8, $a7a7a7 ),
            ( $bababa, $a7a7a7, $a1a1a1, -1, $bababa, $a7a7a7, $a1a1a1, -1, $bababa, $a7a7a7, $a1a1a1 )
        );
    begin
        drawScrollbarSizegrip(listener, left, top, width, height);
        draw(listener, left + 1, top + height - 12, 11, 11, SIZEGRIP);
    end;

    procedure ThemeSoft.drawStatusBarSimple(listener: GraphicListener; left, top, width, height: int);
    const
        TOP_BORDER: array [0..2] of int =
        (
            2,
            $405972, $7f98b1
        );
        CENTER_PANEL: array [0..2] of int =
        (
            2,
            $7f98b1, $7f98b1
        );
        BOTTOM_BORDER: array [0..2] of int =
        (
            2,
            $7f98b1, $bed7f0
        );
    begin
        if (width < 16) or (height < 16) then begin
            exit;
        end;
        drawGradientsHorz(listener, left, top, width, 5, TOP_BORDER);
        drawGradientsHorz(listener, left, top + 5, width, height - 10, CENTER_PANEL);
        drawGradientsHorz(listener, left, top + height - 5, width, 5, BOTTOM_BORDER);
    end;

    procedure ThemeSoft.drawStatusBarWithSeparator(listener: GraphicListener; left, top, width, height: int);
    const
        TOP_BORDER: array [0..2] of int =
        (
            2,
            $405972, $7f98b1
        );
        CENTER_PANEL: array [0..2] of int =
        (
            2,
            $7f98b1, $7f98b1
        );
        BOTTOM_BORDER: array [0..2] of int =
        (
            2,
            $7f98b1, $bed7f0
        );
        SEPARATOR: array [0..2, 0..2] of int =
        (
            ( $63819e, $577390, $46607a ),
            ( $6b8aa9, $577390, $435d77 ),
            ( $7e9cb9, $577390, $617b95 )
        );
    var
        i: int;
    begin
        if (width < 16) or (height < 16) then begin
            exit;
        end;
        drawGradientsHorz(listener, left, top, width, 5, TOP_BORDER);
        drawGradientsHorz(listener, left, top + 5, width, height - 10, CENTER_PANEL);
        drawGradientsHorz(listener, left, top + height - 5, width, 5, BOTTOM_BORDER);
        draw(listener, left + width - 4, top + 1, 3, 2, SEPARATOR);
        draw(listener, left + width - 4, top + height - 3, 3, 2, SEPARATOR[1]);
        for i := 3 to height - 4 do begin
            draw(listener, left + width - 4, top + i, 3, 1, SEPARATOR[1]);
        end;
    end;

    procedure ThemeSoft.drawStatusBarWithSizegrip(listener: GraphicListener; left, top, width, height: int);
    const
        TOP_BORDER: array [0..2] of int =
        (
            2,
            $405972, $7f98b1
        );
        CENTER_PANEL: array [0..2] of int =
        (
            2,
            $7f98b1, $7f98b1
        );
        BOTTOM_BORDER: array [0..2] of int =
        (
            2,
            $7f98b1, $bed7f0
        );
        SIZEGRIP: array [0..10, 0..10] of int =
        (
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1, $7592b0, $6482a0, $627d99 ),
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1, $6482a0, $577390, $4a6580 ),
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1, $627d99, $4a6580, $4f6982 ),
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1,      -1,      -1,      -1 ),
            (      -1,      -1,      -1, -1, $7592b0, $6482a0, $627d99, -1, $7592b0, $6482a0, $627d99 ),
            (      -1,      -1,      -1, -1, $6482a0, $577390, $4a6580, -1, $6482a0, $577390, $4a6580 ),
            (      -1,      -1,      -1, -1, $627d99, $4a6580, $4f6982, -1, $627d99, $4a6580, $4f6982 ),
            (      -1,      -1,      -1, -1,      -1,      -1,      -1, -1,      -1,      -1,      -1 ),
            ( $7b98b6, $6482a0, $68839f, -1, $7b98b6, $6482a0, $68839f, -1, $7b98b6, $6482a0, $68839f ),
            ( $6482a0, $577390, $4a6580, -1, $6482a0, $577390, $4a6580, -1, $6482a0, $577390, $4a6580 ),
            ( $708ba7, $4a6580, $5d7790, -1, $708ba7, $4a6580, $5d7790, -1, $708ba7, $4a6580, $5d7790 )
        );
    begin
        if (width < 16) or (height < 16) then begin
            exit;
        end;
        drawGradientsHorz(listener, left, top, width, 5, TOP_BORDER);
        drawGradientsHorz(listener, left, top + 5, width, height - 10, CENTER_PANEL);
        drawGradientsHorz(listener, left, top + height - 5, width, 5, BOTTOM_BORDER);
        draw(listener, left + width - 12, top + height - 12, 11, 11, SIZEGRIP);
    end;

    function ThemeSoft.getName(): AnsiString;
    begin
        result := '<Обычная для Малик Эмулятора тема>';
    end;

    function ThemeSoft.getSystemColor(index: int): int;
    const
        COLORS_LENGTH = int($2a);
        COLORS: array [0..COLORS_LENGTH - 1] of int =
        (
            $b4c4d4, $3a464a, $a6c1da, $99a8b6, $94b6ca, $7e97af, $3d4c5a, $000000,
            $000000, $000000, $b0c9dd, $c0ccd8, $3a464a, $4f6377, $ffffff, $74889c,
            $405468, $545454, $405468, $000000, $b1c5d9, $405468, $b1c5d9, $000000,
            $e1e1a0, $ffffff,      -1, $a6c1da, $99a8b6, $91a5b9, $7e97af, $7e97af,
            $4c6680, $4c6680, $909090, $4c6680, $405468, $405468, $545454, $405468,
            $202734, $000000
        );
    begin
        if (index >= 0) and (index < COLORS_LENGTH) then begin
            result := COLORS[index] or COLOR_MASK;
            exit;
        end;
        result := 0;
    end;

    function ThemeSoft.getSizes(element: int): int;

        procedure setResult(w, h: int); inline;
        begin
            result := (w and $ffff) + ((h and $ffff) shl 16);
        end;

        procedure findImage(); inline;
        var
            i: int;
        begin
            for i := 0 to length(REGIONS) - 1 do begin
                with REGIONS[i] do begin
                    if elementType <> element then begin
                        continue;
                    end;
                    setResult(width, height);
                    break;
                end;
            end;
        end;

    var
        eltype: int;
        elsubtype: int;
        elstate: int;
    begin
        result := -1;
        findImage();
        if result <> -1 then begin
            exit;
        end;
        element := element and $00ffffff;
        eltype := byte(element);
        elsubtype := byte(element shr 8);
        elstate := byte(element shr 16);
        case eltype of
        $01: begin
            case elsubtype of
            $00..$02: begin
                setResult(5, 5);
            end;
            else
                result := 0;
            end;
        end;
        $02: begin
            case elsubtype of
            $00: begin
                case elstate of
                $00..$02: begin
                    setResult(5, 5);
                end;
                else
                    result := 0;
                end;
            end;
            else
                result := 0;
            end;
        end;
        $03: begin
            case elsubtype of
            $00..$02: begin
                setResult(1, 1);
            end;
            else
                result := 0;
            end;
        end;
        $04: begin
            case elsubtype of
            $00..$03: begin
                setResult(5, 5);
            end;
            else
                result := 0;
            end;
        end;
        $05: begin
            case elsubtype of
            $00..$02: begin
                setResult(1, 1);
            end;
            else
                result := 0;
            end;
        end;
        $06: begin
            case elsubtype of
            $00: begin
                case elstate of
                $00..$02: begin
                    setResult(30, 20);
                end;
                else
                    result := 0;
                end;
            end;
            $01: begin
                case elstate of
                $00..$02: begin
                    setResult(10, 10);
                end;
                else
                    result := 0;
                end;
            end;
            $02..$03: begin
                case elstate of
                $00..$02: begin
                    setResult(10, -1);
                end;
                else
                    result := 0;
                end;
            end;
            $04: begin
                case elstate of
                $00..$02: begin
                    setResult(-1, 10);
                end;
                else
                    result := 0;
                end;
            end;
            $05: begin
                case elstate of
                $00..$02: begin
                    setResult(-1, -1);
                end;
                else
                    result := 0;
                end;
            end;
            else
                result := 0;
            end;
        end;
        $07: begin
            case elsubtype of
            $00..$02: begin
                case elstate of
                $00..$03: begin
                    setResult(5, 5);
                end;
                else
                    result := 0;
                end;
            end;
            $03: begin
                setResult(3, -1);
            end;
            $04: begin
                setResult(-1, 3);
            end;
            else
                result := 0;
            end;
        end;
        $08: begin
            case elsubtype of
            $00..$03: begin
                setResult(5, 5);
            end;
            else
                result := 0;
            end;
        end;
        $09: begin
            case elsubtype of
            $00, $02: begin
                setResult(5, 5);
            end;
            $01, $03: begin
                setResult(1, 1);
            end;
            else
                result := 0;
            end;
        end;
        $0a: begin
            case elsubtype of
            $00..$03: begin
                case elstate of
                $00..$02: begin
                    setResult(15, 15);
                end;
                else
                    result := 0;
                end;
            end;
            $04: begin
                case elstate of
                $00..$02: begin
                    setResult(5, 15);
                end;
                else
                    result := 0;
                end;
            end;
            $05: begin
                case elstate of
                $00: begin
                    setResult(15, 5);
                end;
                else
                    result := 0;
                end;
            end;
            $06..$07: begin
                case elstate of
                $00..$02: begin
                    setResult(-1, 15);
                end;
                else
                    result := 0;
                end;
            end;
            $08..$09: begin
                case elstate of
                $00..$02: begin
                    setResult(15, -1);
                end;
                else
                    result := 0;
                end;
            end;
            $0a..$0b: begin
                setResult(15, 15);
            end;
            $0c: begin
                setResult(-1, -1);
            end;
            else
                result := 0;
            end;
        end;
        $0b: begin
            case elsubtype of
            $03, $07: begin
                case elstate of
                $00..$02: begin
                    setResult(5, 5);
                end;
                else
                    result := 0;
                end;
            end;
            else
                result := 0;
            end;
        end;
        $0d: begin
            case elsubtype of
            $00: begin
                setResult(16, 16);
            end;
            else
                result := 0;
            end;
        end;
        $0e: begin
            case elsubtype of
            $00..$03: begin
                case elstate of
                $00..$02: begin
                    setResult(10, 10);
                end;
                else
                    result := 0;
                end;
            end;
            else
                result := 0;
            end;
        end;
        else
            result := 0;
        end;
    end;

    procedure ThemeSoft.drawElement(listener: GraphicListener; element, left, top, width, height: int);

        function findImageAndDrawIfNecessary(): boolean; inline;
        var
            i: int;
            imgX: int;
            imgY: int;
            imgW: int;
            imgH: int;
            region: ImageRegion;
        begin
            result := false;
            for i := 0 to length(REGIONS) - 1 do begin
                region := REGIONS[i];
                if region.elementType <> element then begin
                    continue;
                end;
                if width >= region.width then begin
                    inc(left, (width - region.width) div 2);
                    imgX := region.left;
                    imgW := region.width;
                end else begin
                    imgX := region.left + ((region.width - width) div 2);
                    imgW := width;
                end;
                if height >= region.height then begin
                    inc(top, (height - region.height) div 2);
                    imgY := region.top;
                    imgH := region.height;
                end else begin
                    imgY := region.top + ((region.height - height) div 2);
                    imgH := height;
                end;
                elements.draw(listener, left, top, imgX, imgY, imgW, imgH);
                result := true;
                break;
            end;
        end;

    var
        eltype: int;
        elsubtype: int;
        elstate: int;
    begin
        if (width <= 0) or (height <= 0) or findImageAndDrawIfNecessary() then begin
            exit;
        end;
        element := element and $00ffffff;
        eltype := byte(element);
        elsubtype := byte(element shr 8);
        elstate := byte(element shr 16);
        case eltype of
        $01: begin
            case elsubtype of
            $00: begin
                drawListItemNoFocus(listener, left, top, width, height);
            end;
            $01: begin
                drawListItemWithFocus(listener, left, top, width, height);
            end;
            $02: begin
                drawListItemInactive(listener, left, top, width, height);
            end;
            end;
        end;
        $02: begin
            case elsubtype of
            $00: begin
                case elstate of
                $00: begin
                    drawListItemNoFocus(listener, left, top, width, height);
                end;
                $01: begin
                    drawListItemWithFocus(listener, left, top, width, height);
                end;
                $02: begin
                    drawListItemInactive(listener, left, top, width, height);
                end;
                end;
            end;
            end;
        end;
        $03: begin
            case elsubtype of
            $00: begin
                drawTableHeaderNormal(listener, left, top, width, height);
            end;
            $01: begin
                drawTableHeaderPressed(listener, left, top, width, height);
            end;
            $02: begin
                drawTableHeaderDisabled(listener, left, top, width, height);
            end;
            end;
        end;
        $04: begin
            case elsubtype of
            $00: begin
                drawButtonNormal(listener, left, top, width, height);
            end;
            $01: begin
                drawButtonPressed(listener, left, top, width, height);
            end;
            $02: begin
                drawButtonDisabled(listener, left, top, width, height);
            end;
            $03: begin
                drawButtonWithFocus(listener, left, top, width, height);
            end;
            end;
        end;
        $05: begin
            case elsubtype of
            $00: begin
                drawDropDownButtonNormal(listener, left, top, width, height);
            end;
            $01: begin
                drawDropDownButtonPressed(listener, left, top, width, height);
            end;
            $02: begin
                drawDropDownButtonDisabled(listener, left, top, width, height);
            end;
            end;
        end;
        $06: begin
            case elsubtype of
            $00: begin
                case elstate of
                $00: begin
                    drawActiveHeader(listener, left, top, width, height);
                end;
                $01: begin
                    drawInactiveHeader(listener, left, top, width, height);
                end;
                $02: begin
                    drawDisabledHeader(listener, left, top, width, height);
                end;
                end;
            end;
            $01: begin
                case elstate of
                $00: begin
                    drawActiveHeaderMaximized(listener, left, top, width, height);
                end;
                $01: begin
                    drawInactiveHeaderMaximized(listener, left, top, width, height);
                end;
                $02: begin
                    drawDisabledHeaderMaximized(listener, left, top, width, height);
                end;
                end;
            end;
            $02: begin
                case elstate of
                $00: begin
                    drawActiveBorderLeft(listener, left, top, width, height);
                end;
                $01: begin
                    drawInactiveBorderLeft(listener, left, top, width, height);
                end;
                $02: begin
                    drawDisabledBorderLeft(listener, left, top, width, height);
                end;
                end;
            end;
            $03: begin
                case elstate of
                $00: begin
                    drawActiveBorderRight(listener, left, top, width, height);
                end;
                $01: begin
                    drawInactiveBorderRight(listener, left, top, width, height);
                end;
                $02: begin
                    drawDisabledBorderRight(listener, left, top, width, height);
                end;
                end;
            end;
            $04: begin
                case elstate of
                $00: begin
                    drawActiveBorderBottom(listener, left, top, width, height);
                end;
                $01: begin
                    drawInactiveBorderBottom(listener, left, top, width, height);
                end;
                $02: begin
                    drawDisabledBorderBottom(listener, left, top, width, height);
                end;
                end;
            end;
            $05: begin
                case elstate of
                $00: begin
                    drawActiveWindow(listener, left, top, width, height);
                end;
                $01: begin
                    drawInactiveWindow(listener, left, top, width, height);
                end;
                $02: begin
                    drawDisabledWindow(listener, left, top, width, height);
                end;
                end;
            end;
            end;
        end;
        $07: begin
            case elsubtype of
            $00: begin
                case elstate of
                $00: begin
                    drawToolButtonNormal(listener, left, top, width, height);
                end;
                $01: begin
                    drawToolButtonPressed(listener, left, top, width, height);
                end;
                $02: begin
                    drawToolButtonDisabled(listener, left, top, width, height);
                end;
                $03: begin
                    drawToolButtonPushed(listener, left, top, width, height);
                end;
                end;
            end;
            $01: begin
                case elstate of
                $00: begin
                    drawToolButtonWithNextNormal(listener, left, top, width, height);
                end;
                $01: begin
                    drawToolButtonWithNextPressed(listener, left, top, width, height);
                end;
                $02: begin
                    drawToolButtonWithNextDisabled(listener, left, top, width, height);
                end;
                $03: begin
                    drawToolButtonWithNextPushed(listener, left, top, width, height);
                end;
                end;
            end;
            $02: begin
                case elstate of
                $00: begin
                    drawToolDropDownNormal(listener, left, top, width, height);
                end;
                $01: begin
                    drawToolDropDownPressed(listener, left, top, width, height);
                end;
                $02: begin
                    drawToolDropDownDisabled(listener, left, top, width, height);
                end;
                $03: begin
                    drawToolDropDownPushed(listener, left, top, width, height);
                end;
                end;
            end;
            $03: begin
                drawToolHorzSeparator(listener, left, top, width, height);
            end;
            $04: begin
                drawToolVertSeparator(listener, left, top, width, height);
            end;
            end;
        end;
        $08: begin
            case elsubtype of
            $00: begin
                drawTextFieldNormal(listener, left, top, width, height);
            end;
            $01: begin
                drawTextFieldWithFocus(listener, left, top, width, height);
            end;
            $02: begin
                drawTextFieldDisabled(listener, left, top, width, height);
            end;
            $03: begin
                drawTextFieldReadOnly(listener, left, top, width, height);
            end;
            end;
        end;
        $09: begin
            case elsubtype of
            $00: begin
                drawProgressHorzBackground(listener, left, top, width, height);
            end;
            $01: begin
                drawProgressHorzFill(listener, left, top, width, height);
            end;
            $02: begin
                drawProgressVertBackground(listener, left, top, width, height);
            end;
            $03: begin
                drawProgressVertFill(listener, left, top, width, height);
            end;
            end;
        end;
        $0a: begin
            case elsubtype of
            $00: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_VERTICAL, SCROLLBAR_ELEMENT_BACK_BUTTON, elstate);
                end;
                end;
            end;
            $01: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_VERTICAL, SCROLLBAR_ELEMENT_NEXT_BUTTON, elstate);
                end;
                end;
            end;
            $02: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_HORIZONTAL, SCROLLBAR_ELEMENT_BACK_BUTTON, elstate);
                end;
                end;
            end;
            $03: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_HORIZONTAL, SCROLLBAR_ELEMENT_NEXT_BUTTON, elstate);
                end;
                end;
            end;
            $04: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_HORIZONTAL, SCROLLBAR_ELEMENT_SLIDER, elstate);
                end;
                end;
            end;
            $05: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_VERTICAL, SCROLLBAR_ELEMENT_SLIDER, elstate);
                end;
                end;
            end;
            $06: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_HORIZONTAL, SCROLLBAR_ELEMENT_BACK_TRACK, elstate);
                end;
                end;
            end;
            $07: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_HORIZONTAL, SCROLLBAR_ELEMENT_NEXT_TRACK, elstate);
                end;
                end;
            end;
            $08: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_VERTICAL, SCROLLBAR_ELEMENT_BACK_TRACK, elstate);
                end;
                end;
            end;
            $09: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_VERTICAL, SCROLLBAR_ELEMENT_NEXT_TRACK, elstate);
                end;
                end;
            end;
            $0a: begin
                drawScrollbarSizegripLeft(listener, left, top, width, height);
            end;
            $0b: begin
                drawScrollbarSizegripRight(listener, left, top, width, height);
            end;
            $0c: begin
                drawScrollbarSizegrip(listener, left, top, width, height);
            end;
            end;
        end;
        $0b: begin
            case elsubtype of
            $03: begin
                case elstate of
                $00: begin
                    drawTrackbarHorzNormal(listener, left, top, width, height);
                end;
                $01: begin
                    drawTrackbarHorzWithFocus(listener, left, top, width, height);
                end;
                $02: begin
                    drawTrackbarHorzDisabled(listener, left, top, width, height);
                end;
                end;
            end;
            $07: begin
                case elstate of
                $00: begin
                    drawTrackbarVertNormal(listener, left, top, width, height);
                end;
                $01: begin
                    drawTrackbarVertWithFocus(listener, left, top, width, height);
                end;
                $02: begin
                    drawTrackbarVertDisabled(listener, left, top, width, height);
                end;
                end;
            end;
            end;
        end;
        $0d: begin
            case elsubtype of
            $00: begin
                drawStatusBarSimple(listener, left, top, width, height);
            end;
            $01: begin
                drawStatusBarWithSeparator(listener, left, top, width, height);
            end;
            $02: begin
                drawStatusBarWithSizegrip(listener, left, top, width, height);
            end;
            end;
        end;
        $0e: begin
            case elsubtype of
            $00: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_VERTICAL, SCROLLBAR_ELEMENT_BACK_BUTTON, elstate);
                end;
                end;
            end;
            $01: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_VERTICAL, SCROLLBAR_ELEMENT_NEXT_BUTTON, elstate);
                end;
                end;
            end;
            $02: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_HORIZONTAL, SCROLLBAR_ELEMENT_BACK_BUTTON, elstate);
                end;
                end;
            end;
            $03: begin
                case elstate of
                $00..$02: begin
                    drawScrollbarElement(listener, left, top, width, height, SCROLLBAR_ORIENTATION_HORIZONTAL, SCROLLBAR_ELEMENT_NEXT_BUTTON, elstate);
                end;
                end;
            end;
            end;
        end;
        end;
    end;
{%endregion}

initialization {%region}
    ThemeSoft.clinit();
    addTheme(ThemeSoft.create());
{%endregion}

finalization {%region}
    ThemeSoft.cldone();
{%endregion}

end.