├── tests ├── __init__.py └── test_value.py ├── sciter ├── capi │ ├── __init__.py │ ├── sctiscript.py │ ├── scgraphics.py │ ├── screquest.py │ ├── scmsg.py │ ├── scvalue.py │ ├── sctypes.py │ ├── scdom.py │ ├── scdef.py │ ├── scbehavior.py │ └── scapi.py ├── error.py ├── window.py ├── __init__.py ├── host.py ├── platform.py ├── event.py └── value.py ├── setup.cfg ├── examples ├── icon.png ├── archive.zip ├── portable.zip ├── minimal.py ├── insert.py ├── download.py ├── handlers.htm ├── pysciter.py ├── minimal.htm ├── handlers.py ├── plain-win.py └── pysciter.htm ├── .gitignore ├── .editorconfig ├── .github └── workflows │ ├── pylint.yml │ ├── pysciter-tis.yml │ └── pysciter-js.yml ├── LICENSE ├── .appveyor.yml ├── .travis.yml ├── setup.py └── README.md /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sciter/capi/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 160 3 | ignore = F403,F405,N801,E123,D203 4 | -------------------------------------------------------------------------------- /examples/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/pysciter/HEAD/examples/icon.png -------------------------------------------------------------------------------- /examples/archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/pysciter/HEAD/examples/archive.zip -------------------------------------------------------------------------------- /examples/portable.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/pysciter/HEAD/examples/portable.zip -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | env*/* 2 | **/__pycache__/* 3 | *.pyc 4 | *.egg-info/* 5 | /dist/* 6 | /build/* 7 | PySciter.pyproj 8 | PySciter.sln 9 | /.vs/ 10 | /.vscode/ 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | # 4 space indentation 8 | [*.py] 9 | indent_style = space 10 | indent_size = 4 11 | 12 | -------------------------------------------------------------------------------- /examples/minimal.py: -------------------------------------------------------------------------------- 1 | """Minimalistic PySciter sample for Windows.""" 2 | 3 | import sciter 4 | 5 | if __name__ == '__main__': 6 | sciter.runtime_features(file_io=True, allow_sysinfo=True) 7 | 8 | frame = sciter.Window(ismain=True, uni_theme=True) 9 | frame.minimal_menu() 10 | frame.load_file("examples/minimal.htm") 11 | frame.run_app() 12 | -------------------------------------------------------------------------------- /sciter/capi/sctiscript.py: -------------------------------------------------------------------------------- 1 | """TIScript Virtual Machine Runtime. 2 | 3 | Incomplete. 4 | """ 5 | import ctypes 6 | 7 | HVM = ctypes.c_void_p 8 | value = ctypes.c_uint64 9 | 10 | 11 | class tiscript_native_interface(ctypes.Structure): 12 | """.""" 13 | _fields_ = [ 14 | ("create_vm", ctypes.c_void_p), 15 | # TODO: rest of TIScript API 16 | ] 17 | -------------------------------------------------------------------------------- /examples/insert.py: -------------------------------------------------------------------------------- 1 | """Simple DOM example (Go sciter example port).""" 2 | 3 | import sciter, sys 4 | 5 | if __name__ == "__main__": 6 | frame = sciter.Window(ismain=True, uni_theme=False) 7 | frame.set_title("Inserting example") 8 | 9 | # load simple html 10 | frame.load_html(b"""html""") 11 | 12 | # create div and link as child of root node () 13 | div = sciter.Element.create("div", "hello, world") 14 | 15 | root = frame.get_root() 16 | root.insert(div, 0) 17 | 18 | # show window and run app 19 | frame.run_app() 20 | -------------------------------------------------------------------------------- /sciter/capi/scgraphics.py: -------------------------------------------------------------------------------- 1 | """Sciter's platform independent graphics interface. 2 | 3 | Incomplete. 4 | """ 5 | import enum 6 | 7 | from ctypes import Structure, POINTER, c_void_p 8 | from sciter.capi.sctypes import SCFN, UINT, BOOL 9 | 10 | HGFX = c_void_p 11 | HIMG = c_void_p 12 | HPATH = c_void_p 13 | HTEXT = c_void_p 14 | 15 | 16 | class GRAPHIN_RESULT(enum.IntEnum): 17 | """Result value for Sciter Graphics functions.""" 18 | GRAPHIN_PANIC = -1 19 | GRAPHIN_OK = 0 20 | GRAPHIN_BAD_PARAM = 1 21 | GRAPHIN_FAILURE = 2 22 | GRAPHIN_NOTSUPPORTED = 3 23 | # end 24 | 25 | imageCreate = SCFN(GRAPHIN_RESULT, POINTER(HIMG), UINT, UINT, BOOL) 26 | 27 | 28 | class SciterGraphicsAPI(Structure): 29 | """Sciter Graphics ABI.""" 30 | _fields_ = [ 31 | ("imageCreate", imageCreate), 32 | # TODO: rest of Graphics API 33 | ] 34 | 35 | 36 | LPSciterGraphicsAPI = POINTER(SciterGraphicsAPI) 37 | -------------------------------------------------------------------------------- /sciter/error.py: -------------------------------------------------------------------------------- 1 | """Sciter error classes.""" 2 | 3 | 4 | class SciterError(Exception): 5 | """Base class for Sciter exceptions.""" 6 | pass 7 | 8 | 9 | class ScriptError(SciterError): 10 | """Raised by runtime from calling script when script error occured (e.g. bad syntax).""" 11 | def __init__(self, message, script=None): 12 | super().__init__(self, message.replace("\r", "\n")) 13 | self.message = message 14 | self.script = script 15 | 16 | def __repr__(self): 17 | return '%s("%s") at "%s"' % (type(self).__name__, self.message.replace("\r", "\n").rstrip(), self.script if self.script else "<>") 18 | 19 | def __str__(self): 20 | return type(self).__name__ + ": " + self.message.replace("\r", "\n").rstrip() 21 | pass 22 | 23 | 24 | class ScriptException(ScriptError): 25 | """Raised by script by throwing or returning Error instance.""" 26 | def __init__(self, message, script=None): 27 | super().__init__(message, script) 28 | pass 29 | -------------------------------------------------------------------------------- /.github/workflows/pylint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | python-version: ["3.5", "3.6", "3.7", "3.8", "3.9", "3.10"] 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Setup Python ${{ matrix.python-version }} 17 | uses: actions/setup-python@v2 18 | with: 19 | python-version: ${{ matrix.python-version }} 20 | 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install flake8 25 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 26 | 27 | - name: Lint with flake8 28 | run: | 29 | echo stop the build if there are Python syntax errors or undefined names 30 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 31 | 32 | echo exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 33 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 pravic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.6.0.{build} 2 | 3 | branches: 4 | only: 5 | - master 6 | - travis 7 | 8 | image: 9 | - Visual Studio 2019 10 | 11 | environment: 12 | matrix: 13 | # Python versions: 14 | # https://www.appveyor.com/docs/windows-images-software/#python 15 | 16 | - TARGET: Python34 17 | ARCH: 32 18 | 19 | - TARGET: Python34-x64 20 | ARCH: 64 21 | 22 | - TARGET: Python35-x64 23 | ARCH: 64 24 | 25 | - TARGET: Python36-x64 26 | ARCH: 64 27 | 28 | - TARGET: Python37-x64 29 | ARCH: 64 30 | 31 | - TARGET: Python38-x64 32 | ARCH: 64 33 | 34 | - TARGET: Python39-x64 35 | ARCH: 64 36 | 37 | - TARGET: Python310-x64 38 | ARCH: 64 39 | 40 | install: 41 | - cmd: echo Testing sciter%ARCH% with %TARGET%. 42 | - cmd: echo Current directory is %APPVEYOR_BUILD_FOLDER% 43 | - cmd: set PATH=C:\%TARGET%;C:\projects\deps;%PATH%; 44 | - python --version 45 | 46 | - mkdir ..\deps 47 | - curl -so "..\deps\sciter.dll" "https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x%ARCH%/sciter.dll" 48 | 49 | build_script: 50 | - cmd: cd 51 | - python setup.py install 52 | 53 | test_script: 54 | - cmd: cd 55 | - python tests\test_value.py 56 | -------------------------------------------------------------------------------- /sciter/capi/screquest.py: -------------------------------------------------------------------------------- 1 | """Sciter's get resource request object - represents requests made by Element/View.request() functions. 2 | 3 | Incomplete. 4 | """ 5 | 6 | import enum 7 | from ctypes import Structure, POINTER, c_void_p 8 | 9 | from sciter.capi.sctypes import SCFN 10 | 11 | HREQUEST = c_void_p 12 | 13 | 14 | class REQUEST_RESULT(enum.IntEnum): 15 | """.""" 16 | REQUEST_PANIC = -1 # e.g. not enough memory 17 | REQUEST_OK = 0 18 | REQUEST_BAD_PARAM = 1 # bad parameter 19 | REQUEST_FAILURE = 2 # operation failed, e.g. index out of bounds 20 | REQUEST_NOTSUPPORTED = 3 # the platform does not support requested feature 21 | 22 | 23 | class REQUEST_RQ_TYPE(enum.IntEnum): 24 | """.""" 25 | RRT_GET = 1 26 | RRT_POST = 2 27 | RRT_PUT = 3 28 | RRT_DELETE = 4 29 | 30 | 31 | class REQUEST_STATE(enum.IntEnum): 32 | """.""" 33 | RS_PENDING = 0 34 | RS_SUCCESS = 1 35 | RS_FAILURE = 2 36 | 37 | 38 | class SciterResourceType(enum.IntEnum): 39 | """.""" 40 | RT_DATA_HTML = 0 41 | RT_DATA_IMAGE = 1 42 | RT_DATA_STYLE = 2 43 | RT_DATA_CURSOR = 3 44 | RT_DATA_SCRIPT = 4 45 | RT_DATA_RAW = 5 46 | RT_DATA_FONT = 6 47 | RT_DATA_SOUND = 7 48 | 49 | 50 | RequestUse = SCFN(REQUEST_RESULT, HREQUEST) 51 | RequestUnUse = SCFN(REQUEST_RESULT, HREQUEST) 52 | 53 | 54 | class SciterRequestAPI(Structure): 55 | """Sciter Request ABI.""" 56 | _fields_ = [ 57 | ("RequestUse", RequestUse), 58 | ("RequestUnUse", RequestUnUse), 59 | # TODO: rest of Request API 60 | ] 61 | 62 | LPSciterRequestAPI = POINTER(SciterRequestAPI) 63 | -------------------------------------------------------------------------------- /examples/download.py: -------------------------------------------------------------------------------- 1 | """Download http content (Go sciter example port).""" 2 | 3 | import sciter 4 | 5 | class ContentEventHandler(sciter.EventHandler): 6 | """
Url to load: placed here
''', "/") 34 | 35 | # get root element 36 | root = self.get_root() 37 | 38 | # get span#url and frame#content: 39 | span = root.find_first('#url') 40 | content = root.find_first('#content') 41 | 42 | # replace span text with url provided 43 | text = span.get_text() 44 | span.set_text(url) 45 | print("span:", text) 46 | 47 | # install event handler to content frame to print data_arrived events 48 | self.handler = ContentEventHandler(element=content) 49 | 50 | # make http request to download url and place result as inner of #content 51 | print("load content") 52 | content.request_html(url) 53 | pass 54 | pass 55 | 56 | if __name__ == '__main__': 57 | import sys 58 | 59 | print("Sciter version:", sciter.version(as_str=True)) 60 | 61 | url = "http://httpbin.org/html" if len(sys.argv) < 2 else sys.argv[1] 62 | print(url) 63 | 64 | frame = Frame() 65 | frame.load(url) 66 | frame.expand() 67 | frame.run_app(False) 68 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Based on the "trust" template v0.1.2 2 | # https://github.com/japaric/trust/tree/v0.1.2 3 | 4 | # Ubuntu versions: 5 | # https://docs.travis-ci.com/user/reference/linux/ 6 | dist: xenial 7 | sudo: false 8 | language: python 9 | 10 | notifications: 11 | email: change 12 | 13 | matrix: 14 | include: 15 | # Python versions: 16 | # https://docs.travis-ci.com/user/languages/python/#python-versions 17 | 18 | - os: linux 19 | python: "3.4" 20 | - os: linux 21 | python: "3.7" 22 | - os: linux 23 | python: "3.8" 24 | - os: linux 25 | python: "3.9" 26 | - os: linux 27 | python: "3.10" 28 | 29 | - os: osx 30 | # python comes with `osx_image`, see 31 | # https://blog.travis-ci.com/2019-08-07-extensive-python-testing-on-travis-ci 32 | language: shell 33 | osx_image: xcode10.2 34 | 35 | - os: osx 36 | language: shell 37 | osx_image: xcode12.2 38 | 39 | branches: 40 | only: 41 | - master 42 | - travis 43 | 44 | addons: 45 | apt: 46 | sources: 47 | - ubuntu-toolchain-r-test 48 | 49 | packages: 50 | - libgtk-3-dev 51 | - libgtk-3-0 52 | - libstdc++-6-pic 53 | 54 | 55 | before_install: 56 | - set -e 57 | - python3 --version 58 | 59 | install: 60 | - export SDK_PATH=https://raw.githubusercontent.com/c-smile/sciter-sdk/master 61 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -so "$TRAVIS_BUILD_DIR/libsciter-gtk.so" $SDK_PATH/bin.lnx/x64/libsciter-gtk.so; fi 62 | - if [ "$TRAVIS_OS_NAME" = "osx" ]; then curl -so "$TRAVIS_BUILD_DIR/libsciter.dylib" $SDK_PATH/bin.osx/libsciter.dylib; fi 63 | 64 | - pip3 install -U pip 65 | - pip3 install -U pytest 66 | 67 | before_script: 68 | - if [ "$TRAVIS_OS_NAME" = "osx" ]; then export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:$TRAVIS_BUILD_DIR"; fi 69 | - if [ "$TRAVIS_OS_NAME" = "osx" ]; then cp "$TRAVIS_BUILD_DIR/libsciter.dylib" "$TRAVIS_BUILD_DIR/liblibsciter.dylib"; fi 70 | 71 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$TRAVIS_BUILD_DIR"; fi 72 | 73 | - export PATH="$PATH:$TRAVIS_BUILD_DIR" 74 | - export LIBRARY_PATH="$LIBRARY_PATH:$TRAVIS_BUILD_DIR" 75 | 76 | script: 77 | - python3 setup.py develop 78 | - python3 tests/test_value.py 79 | 80 | after_script: set +e 81 | -------------------------------------------------------------------------------- /examples/handlers.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 |Sciter version x.x.x rev N.
122 |Running on machine.
123 | 124 | 125 | 126 | 127 |Sciter version x.x.x rev N.
151 |Running on machine
152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /sciter/capi/sctypes.py: -------------------------------------------------------------------------------- 1 | """Sciter platform-dependent types.""" 2 | 3 | import sys 4 | import ctypes 5 | 6 | from ctypes import (POINTER, 7 | c_char, c_byte, c_ubyte, 8 | c_void_p, c_char_p, 9 | c_int32, c_uint32, c_int64, c_uint64, 10 | c_longlong, c_ulonglong, c_double, 11 | sizeof, c_size_t, c_ssize_t) 12 | 13 | 14 | # 'win32', 'darwin', 'linux' 15 | SCITER_OS = sys.platform 16 | SCITER_WIN = SCITER_OS == 'win32' 17 | SCITER_OSX = SCITER_OS == 'darwin' 18 | SCITER_LNX = SCITER_OS == 'linux' 19 | 20 | 21 | def utf16tostr(addr, size=-1): 22 | """Read UTF-16 string from memory and encode as python string.""" 23 | if addr is None: 24 | return None 25 | 26 | cb = size if size > 0 else 32 27 | bstr = ctypes.string_at(addr, cb) 28 | if size >= 0: 29 | return bstr.decode('utf-16le') 30 | 31 | # lookup zero char 32 | chunks = [] 33 | while True: 34 | found = cb 35 | for i in range(0, cb, 2): 36 | c = bstr[i] 37 | if c == 0x00: 38 | found = i 39 | break 40 | pass 41 | assert found % 2 == 0, "truncated string with len " + str(found) 42 | chunks.append(bstr[0:found].decode('utf-16le')) 43 | if found != cb: 44 | break 45 | addr = addr + cb 46 | bstr = ctypes.string_at(addr, cb) 47 | continue 48 | return "".join(chunks) 49 | 50 | 51 | class c_utf16_p(ctypes.c_char_p): 52 | """A ctypes wrapper for UTF-16 string pointer.""" 53 | # Taken from https://stackoverflow.com/a/35507014/736762, thanks to @eryksun. 54 | def __init__(self, value=None): 55 | super(c_utf16_p, self).__init__() 56 | if value is not None: 57 | self.value = value 58 | 59 | @property 60 | def value(self, 61 | c_void_p=ctypes.c_void_p): 62 | addr = c_void_p.from_buffer(self).value 63 | return utf16tostr(addr) 64 | 65 | @value.setter 66 | def value(self, value, 67 | c_char_p=ctypes.c_char_p): 68 | value = value.encode('utf-16le') + b'\x00' 69 | c_char_p.value.__set__(self, value) 70 | 71 | @classmethod 72 | def from_param(cls, obj): 73 | if isinstance(obj, str): 74 | obj = obj.encode('utf-16le') + b'\x00' 75 | return super(c_utf16_p, cls).from_param(obj) 76 | 77 | @classmethod 78 | def _check_retval_(cls, result): 79 | return result.value 80 | pass 81 | 82 | 83 | class UTF16LEField(object): 84 | """Structure member wrapper for UTF-16 string pointers.""" 85 | # Taken from https://stackoverflow.com/a/35507014/736762, thanks to @eryksun. 86 | def __init__(self, name): 87 | self.name = name 88 | 89 | def __get__(self, obj, cls, 90 | c_void_p=ctypes.c_void_p, 91 | addressof=ctypes.addressof): 92 | field_addr = addressof(obj) + getattr(cls, self.name).offset 93 | addr = c_void_p.from_address(field_addr).value 94 | return utf16tostr(addr) 95 | 96 | def __set__(self, obj, value): 97 | value = value.encode('utf-16le') + b'\x00' 98 | setattr(obj, self.name, value) 99 | pass 100 | 101 | 102 | if SCITER_WIN: 103 | # sciter.dll since 4.0.0.0 104 | SCITER_DLL_NAME = "sciter" 105 | SCITER_DLL_EXT = ".dll" 106 | 107 | SCFN = ctypes.WINFUNCTYPE 108 | SC_CALLBACK = ctypes.WINFUNCTYPE 109 | 110 | HWINDOW = c_void_p # HWND 111 | HDC = c_void_p # HDC 112 | 113 | BOOL = c_int32 114 | LPCWSTR = LPWSTR = ctypes.c_wchar_p 115 | 116 | ID2D1RenderTarget = c_void_p 117 | ID2D1Factory = c_void_p 118 | IDWriteFactory = c_void_p 119 | 120 | IDXGISwapChain = c_void_p 121 | IDXGISurface = c_void_p 122 | 123 | elif SCITER_OSX: 124 | # sciter-osx-32 since 3.3.1.8 125 | # libsciter since 4.4.6.3 126 | SCITER_DLL_NAME = "libsciter" 127 | SCITER_DLL_EXT = ".dylib" 128 | 129 | SCFN = ctypes.CFUNCTYPE 130 | SC_CALLBACK = ctypes.CFUNCTYPE 131 | 132 | HWINDOW = c_void_p # NSView* 133 | HDC = c_void_p # CGContextRef 134 | 135 | BOOL = c_byte 136 | LPCWSTR = LPWSTR = c_utf16_p 137 | 138 | elif SCITER_LNX: 139 | # libsciter since 3.3.1.7 140 | # libsciter-gtk.so instead of libsciter-gtk-64.so since 4.1.4 141 | SCITER_DLL_NAME = "libsciter-gtk" 142 | SCITER_DLL_EXT = ".so" 143 | 144 | SCFN = ctypes.CFUNCTYPE 145 | SC_CALLBACK = ctypes.CFUNCTYPE 146 | 147 | HWINDOW = c_void_p # GtkWidget* 148 | HDC = c_void_p # cairo_t 149 | 150 | BOOL = c_byte 151 | LPCWSTR = LPWSTR = c_utf16_p 152 | 153 | 154 | # Common types 155 | 156 | VOID = None 157 | nullptr = POINTER(c_int32)() 158 | 159 | BYTE = c_byte 160 | INT = c_int32 161 | UINT = c_uint32 162 | INT64 = c_int64 163 | tiscript_value = c_uint64 164 | 165 | # must be pointer-wide 166 | # WPARAM is defined as UINT_PTR (unsigned type) 167 | # LPARAM is defined as LONG_PTR (signed type) 168 | WPARAM = c_size_t 169 | LPARAM = c_ssize_t 170 | 171 | UINT_PTR = c_size_t 172 | LRESULT = c_ssize_t 173 | 174 | PBOOL = LPBOOL = POINTER(BOOL) 175 | LPCBYTE = c_char_p 176 | LPCSTR = LPSTR = c_char_p 177 | LPCVOID = LPVOID = c_void_p 178 | LPUINT = POINTER(UINT) 179 | 180 | 181 | class RECT(ctypes.Structure): 182 | """Rectangle coordinates structure.""" 183 | _fields_ = [("left", c_int32), 184 | ("top", c_int32), 185 | ("right", c_int32), 186 | ("bottom", c_int32)] 187 | tagRECT = _RECTL = RECTL = RECT 188 | PRECT = LPRECT = POINTER(RECT) 189 | 190 | 191 | class POINT(ctypes.Structure): 192 | """Point coordinates structure.""" 193 | _fields_ = [("x", c_int32), 194 | ("y", c_int32)] 195 | tagPOINT = _POINTL = POINTL = POINT 196 | PPOINT = LPPOINT = POINTER(POINT) 197 | 198 | 199 | class SIZE(ctypes.Structure): 200 | """SIZE structure for width and height.""" 201 | _fields_ = [("cx", c_int32), 202 | ("cy", c_int32)] 203 | tagSIZE = SIZEL = SIZE 204 | PSIZE = LPSIZE = POINTER(SIZE) 205 | 206 | 207 | class MSG(ctypes.Structure): 208 | """MSG structure for windows message queue.""" 209 | _fields_ = [("hWnd", HWINDOW), 210 | ("message", c_uint32), 211 | ("wParam", WPARAM), 212 | ("lParam", LPARAM), 213 | ("time", c_uint32), 214 | ("pt", POINT)] 215 | 216 | PMSG = LPMSG = POINTER(MSG) 217 | -------------------------------------------------------------------------------- /sciter/capi/scdom.py: -------------------------------------------------------------------------------- 1 | """DOM access methods, C interface.""" 2 | 3 | import enum 4 | import ctypes 5 | 6 | from sciter.capi.sctypes import INT, UINT, LPCWSTR, UTF16LEField 7 | 8 | HELEMENT = ctypes.c_void_p 9 | HNODE = ctypes.c_void_p 10 | HRANGE = ctypes.c_void_p 11 | HSARCHIVE = ctypes.c_void_p 12 | 13 | 14 | class SCDOM_RESULT(enum.IntEnum): 15 | """Result value for Sciter DOM functions.""" 16 | 17 | # function completed successfully 18 | SCDOM_OK = 0 19 | 20 | # invalid HWINDOW 21 | SCDOM_INVALID_HWND = 1 22 | 23 | # invalid HELEMENT 24 | SCDOM_INVALID_HANDLE = 2 25 | 26 | # attempt to use HELEMENT which is not marked by Sciter_UseElement() 27 | SCDOM_PASSIVE_HANDLE = 3 28 | 29 | # parameter is invalid, e.g. pointer is null 30 | SCDOM_INVALID_PARAMETER = 4 31 | 32 | # operation failed, e.g. invalid html in SciterSetElementHtml() 33 | SCDOM_OPERATION_FAILED = 5 34 | 35 | SCDOM_OK_NOT_HANDLED = (-1) 36 | # end 37 | 38 | 39 | class HPOSITION(ctypes.Structure): 40 | """.""" 41 | _fields_ = [ 42 | ("hn", HNODE), 43 | ("pos", INT), 44 | ] 45 | 46 | 47 | class METHOD_PARAMS(ctypes.Structure): 48 | """.""" 49 | _fields_ = [("methodID", UINT), ] 50 | 51 | 52 | class REQUEST_PARAM(ctypes.Structure): 53 | """.""" 54 | _fields_ = [ 55 | ("_name", LPCWSTR), 56 | ("_value", LPCWSTR), 57 | ] 58 | name = UTF16LEField('_name') 59 | value = UTF16LEField('_value') 60 | 61 | 62 | class NODE_TYPE(enum.IntEnum): 63 | """.""" 64 | NT_ELEMENT = 0 65 | NT_TEXT = 1 66 | NT_COMMENT = 2 67 | 68 | 69 | class NODE_INS_TARGET(enum.IntEnum): 70 | """.""" 71 | NIT_BEFORE = 0 72 | NIT_AFTER = 1 73 | NIT_APPEND = 2 74 | NIT_PREPEND = 3 75 | 76 | 77 | class ELEMENT_AREAS(enum.IntEnum): 78 | """Bounding rectangle of the element.""" 79 | 80 | ROOT_RELATIVE = 0x01 # - or this flag if you want to get HTMLayout window relative coordinates, 81 | SELF_RELATIVE = 0x02 # - "or" this flag if you want to get coordinates relative to the origin 82 | CONTAINER_RELATIVE = 0x03 # - position inside immediate container. 83 | VIEW_RELATIVE = 0x04 # - position relative to view - HTMLayout window 84 | 85 | CONTENT_BOX = 0x00 # content (inner) box 86 | PADDING_BOX = 0x10 # content + paddings 87 | BORDER_BOX = 0x20 # content + paddings + border 88 | MARGIN_BOX = 0x30 # content + paddings + border + margins 89 | 90 | BACK_IMAGE_AREA = 0x40 # relative to content origin - location of background image (if it set no-repeat) 91 | FORE_IMAGE_AREA = 0x50 # relative to content origin - location of foreground image (if it set no-repeat) 92 | 93 | SCROLLABLE_AREA = 0x60 # scroll_area - scrollable area in content box 94 | 95 | 96 | class SCITER_SCROLL_FLAGS(enum.IntEnum): 97 | """.""" 98 | SCROLL_TO_TOP = 0x01 99 | SCROLL_SMOOTH = 0x10 100 | 101 | 102 | class SET_ELEMENT_HTML(enum.IntEnum): 103 | """.""" 104 | SIH_REPLACE_CONTENT = 0 # replace content of the element 105 | SIH_INSERT_AT_START = 1 # insert html before first child of the element 106 | SIH_APPEND_AFTER_LAST = 2 # insert html after last child of the element 107 | SOH_REPLACE = 3 # replace element by html, a.k.a. element.outerHtml = "something" 108 | SOH_INSERT_BEFORE = 4 # insert html before the element 109 | SOH_INSERT_AFTER = 5 # insert html after the element 110 | 111 | 112 | class ELEMENT_STATE_BITS(enum.IntEnum): 113 | """Runtime DOM element state.""" 114 | STATE_LINK = 0x00000001 115 | STATE_HOVER = 0x00000002 116 | STATE_ACTIVE = 0x00000004 117 | STATE_FOCUS = 0x00000008 118 | STATE_VISITED = 0x00000010 119 | STATE_CURRENT = 0x00000020 # current (hot) item 120 | STATE_CHECKED = 0x00000040 # element is checked (or selected) 121 | STATE_DISABLED = 0x00000080 # element is disabled 122 | STATE_READONLY = 0x00000100 # readonly input element 123 | STATE_EXPANDED = 0x00000200 # expanded state - nodes in tree view 124 | STATE_COLLAPSED = 0x00000400 # collapsed state - nodes in tree view - mutually exclusive with 125 | STATE_INCOMPLETE = 0x00000800 # one of fore/back images requested but not delivered 126 | STATE_ANIMATING = 0x00001000 # is animating currently 127 | STATE_FOCUSABLE = 0x00002000 # will accept focus 128 | STATE_ANCHOR = 0x00004000 # anchor in selection (used with current in selects) 129 | STATE_SYNTHETIC = 0x00008000 # this is a synthetic element - don't emit it's head/tail 130 | STATE_OWNS_POPUP = 0x00010000 # this is a synthetic element - don't emit it's head/tail 131 | STATE_TABFOCUS = 0x00020000 # focus gained by tab traversal 132 | STATE_EMPTY = 0x00040000 # empty - element is empty (text.size() == 0 && subs.size() == 0) 133 | # if element has behavior attached then the behavior is responsible for the value of this flag. 134 | STATE_BUSY = 0x00080000 # busy; loading 135 | 136 | STATE_DRAG_OVER = 0x00100000 # drag over the block that can accept it (so is current drop target). Flag is set for the drop target block 137 | STATE_DROP_TARGET = 0x00200000 # active drop target. 138 | STATE_MOVING = 0x00400000 # dragging/moving - the flag is set for the moving block. 139 | STATE_COPYING = 0x00800000 # dragging/copying - the flag is set for the copying block. 140 | STATE_DRAG_SOURCE = 0x01000000 # element that is a drag source. 141 | STATE_DROP_MARKER = 0x02000000 # element is drop marker 142 | 143 | STATE_PRESSED = 0x04000000 # pressed - close to active but has wider life span - e.g. in MOUSE_UP it 144 | # is still on; so behavior can check it in MOUSE_UP to discover CLICK condition. 145 | STATE_POPUP = 0x08000000 # this element is out of flow - popup 146 | 147 | STATE_IS_LTR = 0x10000000 # the element or one of its containers has dir=ltr declared 148 | STATE_IS_RTL = 0x20000000 # the element or one of its containers has dir=rtl declared 149 | 150 | 151 | class REQUEST_TYPE(enum.IntEnum): 152 | """.""" 153 | GET_ASYNC = 0 154 | POST_ASYNC = 1 155 | GET_SYNC = 2 156 | POST_SYNC = 3 157 | 158 | 159 | class CTL_TYPE(enum.IntEnum): 160 | """DOM control type. Note: it was changed in 4.0.3.""" 161 | CTL_NO = 0 # This dom element has no behavior at all. 162 | CTL_UNKNOWN = 1 # This dom element has behavior but its type is unknown. 163 | CTL_EDIT = 2 # Single line edit box. 164 | CTL_NUMERIC = 3 # Numeric input with optional spin buttons. 165 | CTL_CLICKABLE = 4 # toolbar button, behavior:clickable. 166 | CTL_BUTTON = 5 # Command button. 167 | CTL_CHECKBOX = 6 # CheckBox (button). 168 | CTL_RADIO = 7 # OptionBox (button). 169 | CTL_SELECT_SINGLE = 8 # Single select, ListBox or TreeView. 170 | CTL_SELECT_MULTIPLE = 9 # Multiselectable select, ListBox or TreeView. 171 | CTL_DD_SELECT = 10 # Dropdown single select. 172 | CTL_TEXTAREA = 11 # Multiline TextBox. 173 | CTL_HTMLAREA = 12 # HTML selection behavior. 174 | CTL_PASSWORD = 13 # Password input element. 175 | CTL_PROGRESS = 14 # Progress element. 176 | CTL_SLIDER = 15 # Slider input element. 177 | CTL_DECIMAL = 16 # Decimal number input element. 178 | CTL_CURRENCY = 17 # Currency input element. 179 | CTL_SCROLLBAR = 18 180 | CTL_LIST = 19 181 | CTL_RICHTEXT = 20 182 | CTL_CALENDAR = 21 183 | CTL_DATE = 22 184 | CTL_TIME = 23 185 | CTL_FILE = 24 # file input element. 186 | CTL_PATH = 25 # path input element. 187 | 188 | CTL_LAST_INPUT = 26 189 | 190 | CTL_HYPERLINK = CTL_LAST_INPUT 191 | CTL_FORM = 27 192 | 193 | CTL_MENUBAR = 28 194 | CTL_MENU = 29 195 | CTL_MENUBUTTON = 30 196 | 197 | CTL_FRAME = 31 198 | CTL_FRAMESET = 32 199 | 200 | CTL_TOOLTIP = 33 201 | 202 | CTL_HIDDEN = 34 203 | CTL_URL = 35 # URL input element. 204 | CTL_TOOLBAR = 36 205 | 206 | CTL_WINDOW = 37 # has HWND attached to it 207 | 208 | CTL_LABEL = 38 209 | CTL_IMAGE = 39 # image/video object. 210 | CTL_PLAINTEXT = 40 # Multiline TextBox + colorizer. 211 | -------------------------------------------------------------------------------- /sciter/capi/scdef.py: -------------------------------------------------------------------------------- 1 | """Common Sciter declarations.""" 2 | 3 | import enum 4 | 5 | from ctypes import * 6 | 7 | from sciter.capi.sctypes import * 8 | from sciter.capi.scdom import HELEMENT 9 | from sciter.capi.screquest import HREQUEST 10 | from sciter.capi.scvalue import PSCITER_VALUE 11 | 12 | 13 | class LOAD_RESULT(enum.IntEnum): 14 | """.""" 15 | LOAD_OK = 0 # do default loading if data not set 16 | LOAD_DISCARD = 1 # discard request completely 17 | LOAD_DELAYED = 2 # data will be delivered later by the host application. 18 | 19 | LOAD_MYSELF = 3 # Use sciter-x-request.h[pp] API functions with SCN_LOAD_DATA::requestId handle. 20 | 21 | 22 | class SciterNotification(enum.IntEnum): 23 | """.""" 24 | SC_LOAD_DATA = 0x01 25 | SC_DATA_LOADED = 0x02 26 | SC_ATTACH_BEHAVIOR = 0x04 27 | SC_ENGINE_DESTROYED = 0x05 28 | SC_POSTED_NOTIFICATION = 0x06 29 | SC_GRAPHICS_CRITICAL_FAILURE = 0x07 30 | SC_KEYBOARD_REQUEST = 0x08 31 | SC_INVALIDATE_RECT = 0x09 32 | 33 | 34 | class SCITER_RT_OPTIONS(enum.IntEnum): 35 | """Sciter engine options (global or per-window).""" 36 | SCITER_SMOOTH_SCROLL = 1 # value: TRUE - enable, value: FALSE - disable, enabled by default 37 | SCITER_CONNECTION_TIMEOUT = 2 # global; value: milliseconds, connection timeout of http client 38 | SCITER_HTTPS_ERROR = 3 # global; value: 0 - drop connection, 1 - use builtin dialog, 2 - accept connection silently 39 | SCITER_FONT_SMOOTHING = 4 # value: 0 - system default, 1 - no smoothing, 2 - std smoothing, 3 - clear type 40 | 41 | SCITER_TRANSPARENT_WINDOW = 6 # Windows Aero support, value: 42 | # 0 - normal drawing, 43 | # 1 - window has transparent background after calls DwmExtendFrameIntoClientArea() or DwmEnableBlurBehindWindow(). 44 | SCITER_SET_GPU_BLACKLIST = 7 # global; 45 | # value = LPCBYTE, json - GPU black list, see: gpu-blacklist.json resource. 46 | SCITER_SET_SCRIPT_RUNTIME_FEATURES = 8, # global or window; value - combination of SCRIPT_RUNTIME_FEATURES flags. 47 | SCITER_SET_GFX_LAYER = 9 # global; value - GFX_LAYER 48 | SCITER_SET_DEBUG_MODE = 10 # global or window; value - TRUE/FALSE 49 | SCITER_SET_UX_THEMING = 11 # global; value - BOOL, TRUE - the engine will use "unisex" theme that is common for all platforms. 50 | # That UX theme is not using OS primitives for rendering input elements. Use it if you want exactly 51 | # the same (modulo fonts) look-n-feel on all platforms. 52 | SCITER_ALPHA_WINDOW = 12 # hWnd, value - TRUE/FALSE - window uses per pixel alpha (e.g. WS_EX_LAYERED/UpdateLayeredWindow() window) 53 | SCITER_SET_INIT_SCRIPT = 13 # hWnd - N/A , value LPCSTR - UTF-8 encoded script source to be loaded into each view before any other script execution. 54 | 55 | 56 | class SCRIPT_RUNTIME_FEATURES(enum.IntEnum): 57 | ALLOW_FILE_IO = 0x00000001 58 | ALLOW_SOCKET_IO = 0x00000002 59 | ALLOW_EVAL = 0x00000004 60 | ALLOW_SYSINFO = 0x00000008 61 | 62 | 63 | class GFX_LAYER(enum.IntEnum): 64 | AUTO = 0xFFFF 65 | CPU = 1 66 | 67 | if SCITER_WIN: 68 | GDI = 1 69 | elif SCITER_LNX: 70 | CG = 1 71 | elif SCITER_OSX: 72 | CAIRO = 1 73 | 74 | if SCITER_WIN: 75 | WARP = 2 76 | D2D = 3 77 | 78 | SKIA_CPU = 4 79 | SKIA_OPENGL = 5 80 | 81 | 82 | class OUTPUT_SUBSYTEMS(enum.IntEnum): 83 | DOM = 0 # html parser & runtime 84 | CSSS = 1 # csss! parser & runtime 85 | CSS = 2 # css parser 86 | TIS = 3 # TIS parser & runtime 87 | 88 | 89 | class OUTPUT_SEVERITY(enum.IntEnum): 90 | INFO = 0 91 | WARNING = 1 92 | ERROR = 2 93 | 94 | 95 | class SCITER_CREATE_WINDOW_FLAGS(enum.IntEnum): 96 | SW_CHILD = (1 << 0) # child window only, if this flag is set all other flags ignored 97 | SW_TITLEBAR = (1 << 1) # toplevel window, has titlebar 98 | SW_RESIZEABLE = (1 << 2) # has resizeable frame 99 | SW_TOOL = (1 << 3) # is tool window 100 | SW_CONTROLS = (1 << 4) # has minimize / maximize buttons 101 | SW_GLASSY = (1 << 5) # glassy window - supports "Acrylic" on Windows and "Vibrant" on MacOS. 102 | SW_ALPHA = (1 << 6) # transparent window ( e.g. WS_EX_LAYERED on Windows ) 103 | SW_MAIN = (1 << 7) # main window of the app, will terminate the app on close 104 | SW_POPUP = (1 << 8) # the window is created as topmost window. 105 | SW_ENABLE_DEBUG = (1 << 9) # make this window inspector ready 106 | SW_OWNS_VM = (1 << 10) # it has its own script VM 107 | 108 | 109 | class SCITER_CALLBACK_NOTIFICATION(Structure): 110 | """.""" 111 | _fields_ = [ 112 | ("code", c_uint), 113 | ("hwnd", HWINDOW), 114 | ] 115 | 116 | 117 | class SCN_LOAD_DATA(Structure): 118 | """.""" 119 | _fields_ = [ 120 | ("code", c_uint), 121 | ("hwnd", HWINDOW), 122 | ("_uri", LPCWSTR), 123 | ("outData", LPCBYTE), 124 | ("outDataSize", UINT), 125 | ("dataType", UINT), 126 | ("requestId", HREQUEST), 127 | ("principal", HELEMENT), 128 | ("initiator", HELEMENT), 129 | ] 130 | uri = UTF16LEField('_uri') 131 | 132 | 133 | class SCN_DATA_LOADED(Structure): 134 | """.""" 135 | _fields_ = [ 136 | ("code", c_uint), 137 | ("hwnd", HWINDOW), 138 | ("_uri", LPCWSTR), 139 | ("data", LPCBYTE), 140 | ("dataSize", UINT), 141 | ("dataType", UINT), 142 | ("status", UINT), 143 | ] 144 | uri = UTF16LEField('_uri') 145 | 146 | 147 | class SCN_ATTACH_BEHAVIOR(Structure): 148 | """.""" 149 | _fields_ = [ 150 | ("code", c_uint), 151 | ("hwnd", HWINDOW), 152 | ("element", HELEMENT), 153 | ("behaviorName", LPCSTR), 154 | ("elementProc", c_void_p), 155 | ("elementTag", LPVOID), 156 | ] 157 | 158 | class SCN_KEYBOARD_REQUEST(Structure): 159 | """.""" 160 | _fields_ = [ 161 | ("code", c_uint), 162 | ("hwnd", HWINDOW), 163 | ("keyboardMode", c_uint) 164 | ] 165 | 166 | class SCN_INVALIDATE_RECT(Structure): 167 | """.""" 168 | _fields_ = [ 169 | ("code", c_uint), 170 | ("hwnd", HWINDOW), 171 | ("invalidRect", RECT) 172 | ] 173 | 174 | 175 | LPSCITER_CALLBACK_NOTIFICATION = POINTER(SCITER_CALLBACK_NOTIFICATION) 176 | SciterHostCallback = SC_CALLBACK(UINT, LPSCITER_CALLBACK_NOTIFICATION, LPVOID) 177 | 178 | if SCITER_WIN: 179 | SciterWindowDelegate = SC_CALLBACK(LRESULT, HWINDOW, UINT, WPARAM, LPARAM, LPVOID, PBOOL) 180 | else: 181 | SciterWindowDelegate = c_void_p 182 | 183 | DEBUG_OUTPUT_PROC = SC_CALLBACK(VOID, LPVOID, UINT, UINT, LPCWSTR, UINT) 184 | 185 | LPCSTR_RECEIVER = SC_CALLBACK(VOID, LPCSTR, UINT, LPVOID) 186 | LPCWSTR_RECEIVER = SC_CALLBACK(VOID, LPCWSTR, UINT, LPVOID) 187 | LPCBYTE_RECEIVER = SC_CALLBACK(VOID, LPCBYTE, UINT, LPVOID) 188 | 189 | SciterElementCallback = SC_CALLBACK(BOOL, HELEMENT, LPVOID) 190 | 191 | ElementEventProc = SC_CALLBACK(BOOL, LPVOID, HELEMENT, UINT, LPVOID) 192 | 193 | ELEMENT_COMPARATOR = SC_CALLBACK(INT, HELEMENT, HELEMENT, LPVOID) 194 | 195 | KeyValueCallback = SC_CALLBACK(BOOL, LPVOID, PSCITER_VALUE, PSCITER_VALUE) 196 | 197 | NATIVE_FUNCTOR_INVOKE = CFUNCTYPE(VOID, LPVOID, UINT, PSCITER_VALUE, PSCITER_VALUE) 198 | NATIVE_FUNCTOR_RELEASE = CFUNCTYPE(VOID, LPVOID) 199 | 200 | ELEMENT_BITMAP_RECEIVER = SC_CALLBACK(VOID, LPCBYTE, INT, INT, UINT, UINT, LPVOID) 201 | 202 | 203 | class StringReceiver(): 204 | """LPCWSTR_RECEIVER wrapper.""" 205 | 206 | def __init__(self, string_type: str): 207 | """Construct callback by one of 'char', 'wchar' or 'byte' string type.""" 208 | self.text = None 209 | if string_type == 'char': 210 | self.cb = LPCSTR_RECEIVER(self._a2s) 211 | elif string_type == 'byte': 212 | self.cb = LPCBYTE_RECEIVER(self._b2s) 213 | elif string_type == 'wchar': 214 | self.cb = LPCWSTR_RECEIVER(self._w2s) 215 | else: 216 | raise ValueError("Unknown callback type. Use one of 'char', 'byte' or 'wchar'.") 217 | self._as_parameter_ = self.cb 218 | pass 219 | 220 | def _w2s(self, sz, n, ctx): 221 | # wchar_t 222 | self.text = sz if SCITER_WIN else sz.value 223 | pass 224 | 225 | def _a2s(self, sz, n, ctx): 226 | # char 227 | self.text = sz.decode('utf-8') 228 | pass 229 | 230 | def _b2s(self, sz, n, ctx): 231 | # byte 232 | self.text = sz.decode('utf-8') 233 | pass 234 | pass 235 | -------------------------------------------------------------------------------- /sciter/host.py: -------------------------------------------------------------------------------- 1 | """Sciter host application helpers.""" 2 | 3 | import ctypes 4 | import os.path 5 | 6 | from sciter.capi.scdef import * 7 | from sciter.capi.sctypes import HWINDOW 8 | 9 | import sciter 10 | import sciter.dom 11 | 12 | import sys 13 | 14 | _api = sciter.SciterAPI() 15 | 16 | 17 | class Host(): 18 | """Standard implementation of SCITER_CALLBACK_NOTIFY handler.""" 19 | 20 | def __init__(self): 21 | """.""" 22 | super().__init__() 23 | self.hwnd = None 24 | self.root = None 25 | pass 26 | 27 | def __call__(self, name, *args): 28 | """Alias for self.call_function().""" 29 | return self.call_function(name, *args) 30 | 31 | def setup_callback(self, hwnd): 32 | """Set callback for sciter engine events.""" 33 | if not hwnd: 34 | raise ValueError("Invalid window handle provided.") 35 | self.hwnd = hwnd 36 | self.root = self.get_root() # if called on existing document 37 | self._sciter_handler_proc = SciterHostCallback(self.handle_notification) 38 | _api.SciterSetCallback(hwnd, self._sciter_handler_proc, ctypes.c_void_p(0)) 39 | pass 40 | 41 | def setup_debug(self, hwnd=None, debug_windows=True, debug_output=True): 42 | """Setup debug output function for specific window or globally.""" 43 | ok = _api.SciterSetOption(hwnd, SCITER_RT_OPTIONS.SCITER_SET_DEBUG_MODE, debug_windows) 44 | if not ok: 45 | raise sciter.SciterError("Could not set debug mode") 46 | self._sciter_debug_proc = DEBUG_OUTPUT_PROC(self.on_debug_output) 47 | if debug_output: 48 | _api.SciterSetupDebugOutput(hwnd, None, self._sciter_debug_proc) 49 | else: 50 | _api.SciterSetupDebugOutput(hwnd, None, DEBUG_OUTPUT_PROC(0)) 51 | pass 52 | 53 | def set_option(self, option, value): 54 | """Set various sciter engine options, see the SCITER_RT_OPTIONS.""" 55 | hwnd = self.hwnd 56 | if option in (SCITER_RT_OPTIONS.SCITER_SET_GPU_BLACKLIST, SCITER_RT_OPTIONS.SCITER_SET_GFX_LAYER, SCITER_RT_OPTIONS.SCITER_SET_UX_THEMING): 57 | hwnd = None 58 | ok = _api.SciterSetOption(hwnd, option, value) 59 | if not ok: 60 | raise sciter.SciterError("Could not set option " + str(option) + "=" + str(value)) 61 | return self 62 | 63 | def set_home_url(self, url: str): 64 | """Set sciter window home url.""" 65 | ok = _api.SciterSetHomeURL(self.hwnd, url) 66 | if not ok: 67 | raise sciter.SciterError("Could not set home url " + str(url)) 68 | return self 69 | 70 | def set_media_type(self, media_type: str): 71 | """Set media type of this sciter instance.""" 72 | ok = _api.SciterSetMediaType(self.hwnd, media_type) 73 | if not ok: 74 | raise sciter.SciterError("Could not set media type " + str(media_type)) 75 | return self 76 | 77 | def set_media_vars(self, media: dict): 78 | """Set media variables of this sciter instance.""" 79 | v = sciter.Value(media) 80 | ok = _api.SciterSetMediaVars(self.hwnd, v) 81 | if not ok: 82 | raise sciter.SciterError("Could not set media vars " + str(media)) 83 | return self 84 | 85 | def set_master_css(self, css_str: str, append: bool): 86 | """Set Master style sheet.""" 87 | utf = css_str.encode('utf-8') 88 | if append: 89 | ok = _api.SciterAppendMasterCSS(utf, len(utf)) 90 | else: 91 | ok = _api.SciterSetMasterCSS(utf, len(utf)) 92 | if not ok: 93 | raise sciter.SciterError("Could not set master CSS") 94 | return self 95 | 96 | def set_css(self, css_str: str, base_url: str, media_type: str): 97 | """Set (reset) style sheet of current document.""" 98 | utf = css_str.encode('utf-8') 99 | ok = _api.SciterSetCSS(self.hwnd, utf, len(utf), base_url, media_type) 100 | if not ok: 101 | raise sciter.SciterError("Could not set CSS") 102 | return self 103 | 104 | def get_hwnd(self) -> HWINDOW: 105 | """Get window handle.""" 106 | return self.hwnd 107 | 108 | def load_file(self, uri: str, normalize=True): 109 | """Load HTML document from file.""" 110 | if normalize and "://" not in uri: 111 | uri = "file://" + os.path.abspath(uri).replace("\\", "/") 112 | ok = _api.SciterLoadFile(self.hwnd, uri) 113 | if not ok: 114 | raise sciter.SciterError("Unable to load file " + uri) 115 | self.root = self.get_root() 116 | return self 117 | 118 | def load_html(self, html: bytes, uri=None): 119 | """Load HTML document from memory.""" 120 | if not isinstance(html, bytes): 121 | raise TypeError("html must be a bytes type") 122 | cb = len(html) 123 | pb = ctypes.c_char_p(html) 124 | ok = _api.SciterLoadHtml(self.hwnd, pb, cb, uri) 125 | if not ok: 126 | raise sciter.SciterError("Unable to load html " + str(uri)) 127 | self.root = self.get_root() 128 | return self 129 | 130 | def get_root(self): 131 | """Get window root DOM element.""" 132 | he = sciter.dom.HELEMENT() 133 | ok = _api.SciterGetRootElement(self.hwnd, ctypes.byref(he)) 134 | sciter.dom.Element._throw_if(ok) 135 | return sciter.dom.Element(he) if he else None 136 | 137 | def eval_script(self, script: str, name=None): 138 | """Evaluate script in context of current document.""" 139 | rv = sciter.Value() 140 | ok = _api.SciterEval(self.hwnd, script, len(script), rv) 141 | sciter.Value.raise_from(rv, ok != False, name if name else 'Host.eval') 142 | return rv 143 | 144 | def call_function(self, name: str, *args): 145 | """Call scripting function defined in the global namespace.""" 146 | rv = sciter.Value() 147 | argc, argv, _ = sciter.Value.pack_args(*args) 148 | ok = _api.SciterCall(self.hwnd, name.encode('utf-8'), argc, argv, rv) 149 | sciter.Value.raise_from(rv, ok != False, name) 150 | return rv 151 | 152 | def data_ready(self, uri: str, data: bytes, request_id=None, hwnd=None): 153 | """This function is used as response to SCN_LOAD_DATA request.""" 154 | if not hwnd: 155 | hwnd = self.hwnd 156 | if request_id is not None: 157 | ok = _api.SciterDataReadyAsync(hwnd, uri, data, len(data), request_id) 158 | else: 159 | ok = _api.SciterDataReady(hwnd, uri, data, len(data)) 160 | if not ok: 161 | raise sciter.SciterError("Unable to pass data for " + uri) 162 | pass 163 | 164 | 165 | ## @name following functions can be overloaded 166 | def on_load_data(self, nm: SCN_LOAD_DATA): 167 | """Notifies that Sciter is about to download a referred resource.""" 168 | pass 169 | 170 | def on_data_loaded(self, nm: SCN_DATA_LOADED): 171 | """This notification indicates that external data (for example image) download process completed.""" 172 | pass 173 | 174 | def on_attach_behavior(self, nm: SCN_ATTACH_BEHAVIOR): 175 | """This notification is sent on parsing the document and while processing elements having non empty `style.behavior` attribute value.""" 176 | pass 177 | 178 | def on_debug_output(self, tag, subsystem, severity, text, text_len): 179 | """This output function will be used for reprting problems found while loading html and css documents.""" 180 | sysname = OUTPUT_SUBSYTEMS(subsystem).name.lower() 181 | sevname = OUTPUT_SEVERITY(severity).name.lower() 182 | if not sciter.SCITER_WIN: 183 | text = text.value 184 | message = text.replace("\r", "\n").rstrip() 185 | if message: 186 | destination = sys.stdout if sevname == 'info' else sys.stderr 187 | print("{}:{}: {}".format(sevname, sysname, message), file=destination) 188 | pass 189 | 190 | def handle_notification(self, pnm, param): 191 | """Sciter notification handler.""" 192 | # pylint: disable=assignment-from-none,assignment-from-no-return 193 | # because the `self.on_` methods can be overloaded 194 | rv = 0 195 | nm = pnm.contents 196 | if nm.code == SciterNotification.SC_LOAD_DATA: 197 | rv = self.on_load_data(ctypes.cast(pnm, ctypes.POINTER(SCN_LOAD_DATA)).contents) 198 | elif nm.code == SciterNotification.SC_DATA_LOADED: 199 | rv = self.on_data_loaded(ctypes.cast(pnm, ctypes.POINTER(SCN_DATA_LOADED)).contents) 200 | elif nm.code == SciterNotification.SC_ATTACH_BEHAVIOR: 201 | rv = self.on_attach_behavior(ctypes.cast(pnm, ctypes.POINTER(SCN_ATTACH_BEHAVIOR)).contents) 202 | assert(rv is None or isinstance(rv, int)) 203 | return 0 if rv is None else rv 204 | pass 205 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python bindings for Sciter 2 | 3 | [](https://ci.appveyor.com/project/pravic/pysciter) 4 | [](https://www.travis-ci.com/sciter-sdk/pysciter) 5 | [](https://pypi.python.org/pypi/PySciter) 6 | [](https://pypi.python.org/pypi/PySciter) 7 | [](https://sciter.com/forums) 8 | 9 | Check [this page](https://sciter.com/developers/sciter-sdk-bindings/) for other language bindings (Delphi / D / Go / .NET / Python / Rust). 10 | 11 | ---- 12 | 13 | 14 | ## Introduction 15 | 16 | Sciter is an embeddable [multiplatform](https://sciter.com/sciter/crossplatform/) HTML/CSS/script engine with GPU accelerated rendering designed to render modern desktop application UI. It's a compact, single dll/dylib/so file (4-8 mb) engine without any additional dependencies. 17 | 18 | 19 | ## Screenshots 20 | 21 | Check the [screenshot gallery](https://github.com/oskca/sciter#sciter-desktop-ui-examples) of the desktop UI examples. 22 | 23 | 24 | ## Description 25 | 26 | Physically Sciter is a mono library which contains: 27 | 28 | * [HTML and CSS](https://sciter.com/developers/for-web-programmers/) rendering engine based on the H-SMILE core used in [HTMLayout](https://terrainformatica.com/a-homepage-section/htmlayout/), 29 | * JavaScript in [Sciter.JS](https://sciter.com/sciter-js-is-the-mainstream-primary-version-of-sciter/), 30 | * JavaScript alike [Scripting engine](https://sciter.com/developers/sciter-docs/) – core of [TIScript](https://sciter.com/developers/for-web-programmers/tiscript-vs-javascript/) which by itself is based on [c-smile](https://c-smile.sourceforge.net/) engine, 31 | * Persistent [Database](https://sciter.com/docs/content/script/Storage.htm) (a.k.a. [JSON DB](https://terrainformatica.com/2006/10/what-the-hell-is-that-json-db/)) based on excellent DB products of [Konstantin Knizhnik](http://garret.ru/databases.html). 32 | * [Graphics](https://sciter.com/docs/content/sciter/Graphics.htm) module that uses native graphics primitives provided by supported platforms: Direct2D on Windows 7 and above, GDI+ on Windows XP, CoreGraphics on MacOS, Cairo on Linux/GTK. Yet there is an option to use built-in [Skia/OpenGL](https://skia.org/) backend on each platform. 33 | * Network communication module, it relies on platform HTTP client primitives and/or [Libcurl](https://curl.haxx.se/). 34 | 35 | 36 | Internally it contains the following modules: 37 | 38 | * **CSS** – CSS parser and the collection of parsed CSS rules, etc. 39 | * **HTML DOM** – HTML parser and DOM tree implementation. 40 | * **layout managers** – collection of various layout managers – text layout, default block layout, flex layouts. Support of positioned floating elements is also here. This module does the layout calculations heavy lifting. This module is also responsible for the rendering of layouts. 41 | * **input behaviors** – a collection of built-in behaviors – code behind "active" DOM elements: ``, `