diff --git a/GUI/Electron/.gitignore b/GUI/Electron/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/GUI/Electron/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/GUI/Electron/index.html b/GUI/Electron/index.html new file mode 100644 index 0000000..682a2da --- /dev/null +++ b/GUI/Electron/index.html @@ -0,0 +1,14 @@ + + + + + + + Hello World! + + + Title: + + + + \ No newline at end of file diff --git a/GUI/Electron/main.js b/GUI/Electron/main.js new file mode 100644 index 0000000..8ebefed --- /dev/null +++ b/GUI/Electron/main.js @@ -0,0 +1,62 @@ +const { app, BrowserWindow, ipcMain } = require('electron') +const path = require('node:path') + +function createWindow () { + const mainWindow = new BrowserWindow({ + webPreferences: { + preload: path.join(__dirname, 'preload.js') + } + }) + + ipcMain.on('set-title', (event, title) => { + const webContents = event.sender + const win = BrowserWindow.fromWebContents(webContents) + win.setTitle(title) + }) + + mainWindow.loadFile('index.html') +} + +app.whenReady().then(() => { + createWindow() + + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) + + +// const { app, BrowserWindow, ipcMain, dialog } = require('electron') +// const path = require('node:path') + +// async function handleFileOpen() { +// const { canceled, filePaths } = await dialog.showOpenDialog() +// if (!canceled) { +// return filePaths[0] +// } +// } + +// function createWindow() { +// const mainWindow = new BrowserWindow({ +// webPreferences: { +// preload: path.join(__dirname, 'preload.js') +// } +// }) +// mainWindow.loadFile('index.html') +// } + +// app.whenReady().then(() => { +// ipcMain.handle('dialog:openFile', handleFileOpen) +// createWindow() +// app.on('activate', function () { +// if (BrowserWindow.getAllWindows().length === 0) createWindow() +// }) +// }) + +// app.on('window-all-closed', function () { +// if (process.platform !== 'darwin') app.quit() +// }) \ No newline at end of file diff --git a/GUI/Electron/package-lock.json b/GUI/Electron/package-lock.json new file mode 100644 index 0000000..6e934a2 --- /dev/null +++ b/GUI/Electron/package-lock.json @@ -0,0 +1,904 @@ +{ + "name": "gui", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gui", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "fs": "^0.0.1-security", + "path": "^0.12.7" + }, + "devDependencies": { + "electron": "^27.0.4" + } + }, + "node_modules/@electron/get": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", + "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "18.18.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.9.tgz", + "integrity": "sha512-0f5klcuImLnG4Qreu9hPj/rEfFq6YRc5n2mAjSsH+ec/mJL+3voBH0+8T7o8RpFjH7ovc+TRsL/c7OYIQsPTfQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "dev": true, + "optional": true + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "optional": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "optional": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "optional": true + }, + "node_modules/electron": { + "version": "27.0.4", + "resolved": "https://registry.npmjs.org/electron/-/electron-27.0.4.tgz", + "integrity": "sha512-ob29rN1mtiyAXzF8HsHd5jh8bYKd9OQDakfdOExi0F7epU97gXPHaj6JPjbBJ/vpki5d32SyKVePW4vxeNZk1A==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@electron/get": "^2.0.0", + "@types/node": "^18.11.18", + "extract-zip": "^2.0.1" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 12.20.55" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "optional": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "optional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "optional": true, + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "dev": true, + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-agent/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "optional": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "optional": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "optional": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "optional": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "optional": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "dev": true, + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "dev": true, + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true, + "optional": true + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "optional": true + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "optional": true + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } +} diff --git a/GUI/Electron/package.json b/GUI/Electron/package.json new file mode 100644 index 0000000..6da0e9b --- /dev/null +++ b/GUI/Electron/package.json @@ -0,0 +1,19 @@ +{ + "name": "gui", + "version": "1.0.0", + "description": "", + "main": "main.js", + "scripts": { + "start": "electron .", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "electron": "^27.0.4" + }, + "dependencies": { + "fs": "^0.0.1-security", + "path": "^0.12.7" + } +} diff --git a/GUI/Electron/preload.js b/GUI/Electron/preload.js new file mode 100644 index 0000000..e957e40 --- /dev/null +++ b/GUI/Electron/preload.js @@ -0,0 +1,12 @@ +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInMainWorld('electronAPI', { + setTitle: (title) => ipcRenderer.send('set-title', title) +}) + + +// const { contextBridge, ipcRenderer } = require('electron') + +// contextBridge.exposeInMainWorld('electronAPI', { +// openFile: () => ipcRenderer.invoke('dialog:openFile') +// }) \ No newline at end of file diff --git a/GUI/Electron/renderer.js b/GUI/Electron/renderer.js new file mode 100644 index 0000000..94b99c0 --- /dev/null +++ b/GUI/Electron/renderer.js @@ -0,0 +1,14 @@ +const setButton = document.getElementById('btn') +const titleInput = document.getElementById('title') +setButton.addEventListener('click', () => { + const title = titleInput.value + window.electronAPI.setTitle(title) +}) + +// const btn = document.getElementById('btn') +// const filePathElement = document.getElementById('filePath') + +// btn.addEventListener('click', async () => { +// const filePath = await window.electronAPI.openFile() +// filePathElement.innerText = filePath +// }) \ No newline at end of file diff --git a/GUI/nana.cpp b/GUI/nana.cpp new file mode 100644 index 0000000..2443601 --- /dev/null +++ b/GUI/nana.cpp @@ -0,0 +1,14 @@ +#include +#include + +int main() +{ + using namespace nana; + form fm; + fm.caption(L"Hello, World!"); + button btn(fm, rectangle{20, 20, 150, 30}); + btn.caption(L"Quit"); + btn.events().click(API::exit); + fm.show(); + exec(); +} \ No newline at end of file diff --git a/GUI/nana/any.hpp b/GUI/nana/any.hpp new file mode 100644 index 0000000..a6e28ce --- /dev/null +++ b/GUI/nana/any.hpp @@ -0,0 +1,160 @@ +/** + * Any + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/any.hpp + * + * @brief An implementation of experimental library any of C++ standard(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html#any) + */ + +#ifndef NANA_ANY_HPP +#define NANA_ANY_HPP +#include +#include +#include + +#include "c++defines.hpp" + +namespace nana +{ + + class bad_any_cast + : public std::bad_cast + { + }; + + class any + { + class content_interface + { + public: + virtual ~content_interface() = default; + + virtual const std::type_info& type() const noexcept = 0; + virtual content_interface* clone() const = 0; + }; + + template + class holder : public content_interface + { + holder& operator=(const holder&) = delete; + public: + holder(const Value& other) + : value(other) + {} + + holder(Value&& other) + : value(static_cast(other)) + {} + public: + const std::type_info& type() const noexcept override + { + return typeid(Value); + } + + content_interface* clone() const override + { + return new holder(value); + } + public: + Value value; //representation accessible for friend of any + }; + public: + //constructors and destructor + any() noexcept; + + any(const any& other); + any(any&& other) noexcept; + + template + any(Value && value, + typename std::enable_if::value>::type * = nullptr, + typename std::enable_if::value>::type* = nullptr) + : content_(new holder::type>(std::forward(value))) + { + } + + ~any(); + + //assignments + any& operator=(const any& other); + any& operator=(any&& other) noexcept; + + template + any& operator=(Value&& other) + { + any(std::forward(other)).swap(*this); + return *this; + } + + //modifiers + void clear() noexcept; + void swap(any& other) noexcept; + + //observers + bool empty() const noexcept; + const std::type_info& type() const noexcept; + private: + template + friend Value* any_cast(any*) noexcept; + private: + content_interface * content_; + }; + + // Non-member functions + inline void swap(any& x, any& y) noexcept + { + x.swap(y); + } + + template + Value any_cast(const any& operand) + { + using value_type = typename std::remove_reference::type; + return any_cast(const_cast(operand)); + } + + template + Value any_cast(any& operand) + { + using value_type = typename std::remove_reference::type; + + auto value_ptr = any_cast(&operand); + if (!value_ptr) + throw bad_any_cast(); + + using ref_type = typename std::conditional::value, Value, typename std::add_lvalue_reference::type>::type; + return static_cast(*value_ptr); + } + + template + Value any_cast(any && operand) + { + static_assert(std::is_rvalue_reference::value || std::is_const::type>::value, "nana::any_cast shall not be used for getting non-const reference to temporary objects"); + return any_cast(operand); + } + + template + const Value* any_cast(const any* operand) noexcept + { + return any_cast(const_cast(operand)); + } + + template + Value* any_cast(any* operand) noexcept + { + if (!operand) + return nullptr; + + auto holder = dynamic_cast::type>*>(operand->content_); + return (holder ? &holder->value : nullptr); + } + +}//end namespace nana + +#endif diff --git a/GUI/nana/audio/detail/audio_device.hpp b/GUI/nana/audio/detail/audio_device.hpp new file mode 100644 index 0000000..768a957 --- /dev/null +++ b/GUI/nana/audio/detail/audio_device.hpp @@ -0,0 +1,64 @@ +#ifndef NANA_AUDIO_DETAIL_AUDIO_DEVICE_HPP +#define NANA_AUDIO_DETAIL_AUDIO_DEVICE_HPP + +#include + +#ifdef NANA_ENABLE_AUDIO + +#include +#include +#if defined(NANA_WINDOWS) + #include +#elif defined(NANA_LINUX) + #include +#elif defined(NANA_POSIX) + #include +#endif + +namespace nana{ namespace audio +{ + namespace detail + { + class audio_device + { + public: + audio_device(); + ~audio_device(); + + bool empty() const; + bool open(std::size_t channels, std::size_t rate, std::size_t bits_per_sample); + void close(); + void prepare(buffer_preparation & buf_prep); + void write(buffer_preparation::meta * m); + void wait_for_drain() const; + private: +#if defined(NANA_WINDOWS) + static void __stdcall _m_dev_callback(HWAVEOUT handle, UINT msg, audio_device * self, DWORD_PTR, DWORD_PTR); +#endif + +#if defined(NANA_WINDOWS) + HWAVEOUT handle_; + std::recursive_mutex queue_lock_; + std::vector done_queue_; +#elif defined(NANA_LINUX) + snd_pcm_t * handle_; + std::size_t rate_; + std::size_t channels_; + std::size_t bytes_per_sample_; + std::size_t bytes_per_frame_; +#elif defined(NANA_POSIX) + int handle_; + int rate_; + int channels_; + int bytes_per_sample_; + int bytes_per_frame_; +#endif + buffer_preparation * buf_prep_; + }; + + }//end namespace detail +}//end namespace audio +}//end namespace nana + +#endif //NANA_ENABLE_AUDIO +#endif diff --git a/GUI/nana/audio/detail/audio_stream.hpp b/GUI/nana/audio/detail/audio_stream.hpp new file mode 100644 index 0000000..6b0a56a --- /dev/null +++ b/GUI/nana/audio/detail/audio_stream.hpp @@ -0,0 +1,86 @@ +#ifndef NANA_AUDIO_DETAIL_AUDIO_STREAM_HPP +#define NANA_AUDIO_DETAIL_AUDIO_STREAM_HPP + +#include + +#ifdef NANA_ENABLE_AUDIO + +#include + +namespace nana{ namespace audio{ + namespace detail + { + namespace wave_spec + { + #if defined(NANA_WINDOWS) + #pragma pack(1) + struct master_riff_chunk + { + unsigned ckID; //"RIFF" + unsigned cksize; + unsigned waveID; //"WAVE" + }; + + struct format_chunck + { + unsigned ckID; //"fmt " + unsigned cksize; + unsigned short wFormatTag; + unsigned short nChannels; + unsigned nSamplePerSec; + unsigned nAvgBytesPerSec; + unsigned short nBlockAlign; + unsigned short wBitsPerSample; + }; + #pragma pack() + #elif defined(NANA_POSIX) + struct master_riff_chunk + { + unsigned ckID; //"RIFF" + unsigned cksize; + unsigned waveID; //"WAVE" + }__attribute__((packed)); + + struct format_chunck + { + unsigned ckID; //"fmt " + unsigned cksize; + unsigned short wFormatTag; + unsigned short nChannels; + unsigned nSamplePerSec; + unsigned nAvgBytesPerSec; + unsigned short nBlockAlign; + unsigned short wBitsPerSample; + }__attribute__((packed)); + #endif + } + + class audio_stream + { + struct chunck + { + unsigned ckID; + unsigned cksize; + }; + public: + bool open(const std::string& file); + void close(); + bool empty() const; + const wave_spec::format_chunck & format() const; + std::size_t data_length() const; + void locate(); + std::size_t read(void * buf, std::size_t len); + private: + std::size_t _m_locate_chunck(unsigned ckID); + private: + std::ifstream fs_; + wave_spec::format_chunck ck_format_; + std::size_t pcm_data_pos_; + std::size_t pcm_data_size_; + std::size_t data_size_; + }; //end class audio_stream + } +}//end namespace audio +}//end namespace nana +#endif //NANA_ENABLE_AUDIO +#endif diff --git a/GUI/nana/audio/detail/buffer_preparation.hpp b/GUI/nana/audio/detail/buffer_preparation.hpp new file mode 100644 index 0000000..7272d9b --- /dev/null +++ b/GUI/nana/audio/detail/buffer_preparation.hpp @@ -0,0 +1,71 @@ +#ifndef NANA_AUDIO_DETAIL_BUFFER_PREPARATION_HPP +#define NANA_AUDIO_DETAIL_BUFFER_PREPARATION_HPP +#include + +#ifdef NANA_ENABLE_AUDIO + +#include + +#if defined(STD_THREAD_NOT_SUPPORTED) + #include + #include + #include +#else + #include + #include + #include +#endif + +#include +#include + +#if defined(NANA_WINDOWS) + #include +#endif + +#include + +namespace nana{ namespace audio +{ + namespace detail + { + class buffer_preparation + { + public: +#if defined(NANA_WINDOWS) + typedef WAVEHDR meta; +#elif defined(NANA_POSIX) + struct meta + { + char * buf; + std::size_t bufsize; + }; +#endif + + public: + buffer_preparation(audio_stream& as, std::size_t seconds); + + ~buffer_preparation(); + + meta * read(); + //Revert the meta that returned by read() + void revert(meta * m); + bool data_finished() const; + private: + void _m_prepare_routine(); + private: + std::atomic running_; + std::atomic wait_for_buffer_; + std::thread thr_; + mutable std::mutex token_buffer_, token_prepared_; + mutable std::condition_variable cond_buffer_, cond_prepared_; + + std::vector buffer_, prepared_; + std::size_t block_size_; + audio_stream & as_; + }; + }//end namespace detail +}//end namespace audio +}//end namespace nana +#endif //NANA_ENABLE_AUDIO +#endif diff --git a/GUI/nana/audio/player.hpp b/GUI/nana/audio/player.hpp new file mode 100644 index 0000000..0dad445 --- /dev/null +++ b/GUI/nana/audio/player.hpp @@ -0,0 +1,37 @@ +#ifndef NANA_AUDIO_PLAYER_HPP +#define NANA_AUDIO_PLAYER_HPP +#include +#include + +#ifdef NANA_ENABLE_AUDIO + +#include + +namespace nana{ namespace audio +{ /// class player + /// \brief play an audio file in PCM Windows WAV format + /// + /// \include audio_player.cpp + class player + : private nana::noncopyable + { + struct implementation; + public: + player(); + player(const std::string& file); + ~player(); + + bool open(const std::string& file); + void play(); + void close(); + private: + implementation* impl_; + }; +}//end namespace audio +}//end namespace nana + +#endif //NANA_ENABLE_AUDIO + +#include + +#endif diff --git a/GUI/nana/basic_types.hpp b/GUI/nana/basic_types.hpp new file mode 100644 index 0000000..895f476 --- /dev/null +++ b/GUI/nana/basic_types.hpp @@ -0,0 +1,528 @@ +/** + * Basic Types definition + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/basic_types.hpp + */ + +#ifndef NANA_BASIC_TYPES_HPP +#define NANA_BASIC_TYPES_HPP + +#include +#include +#include + +namespace nana +{ + /// A constant value for the invalid position. + const std::size_t npos = static_cast(-1); + + + template + struct casei_char_traits + : public std::char_traits + { + typedef CharT char_type; + + + //static constexpr bool eq(char_type c1, char_type c2) noexcept + //VC2012 does not support constexpr and noexcept keywords + static bool eq(char_type c1, char_type c2) + { + return std::toupper(c1) == std::toupper(c2); + } + + //static constexpr bool lt(char_type c1, char_type c2) noexcept + //VC2012 does not support constexpr and noexcept keywords + static bool lt(char_type c1, char_type c2) + { + return std::toupper(c1) < std::toupper(c2); + } + + static int compare(const char_type* s1, const char_type* s2, std::size_t n) + { + while(n--) + { + char_type c1 = std::toupper(*s1); + char_type c2 = std::toupper(*s2); + if(c1 < c2) return -1; + if(c1 > c2) return 1; + ++s1; + ++s2; + } + return 0; + } + + static const char_type* find(const char_type* s, std::size_t n, const char_type& a) + { + char_type ua = std::toupper(a); + const char_type * end = s + n; + while((s != end) && (std::toupper(*s) != ua)) + ++s; + return (s == end ? nullptr : s); + } + }; + + using cistring = std::basic_string>; + using ciwstring = std::basic_string>; + + + namespace detail + { + struct drawable_impl_type; //declaration, defined in platform_spec.hpp + } + + namespace paint + { + typedef nana::detail::drawable_impl_type* drawable_type; + } + + enum class mouse_action + { + begin, normal = begin, normal_captured, hovered, pressed, end + }; + + enum class element_state + { + normal, + hovered, + focus_normal, + focus_hovered, + pressed, + disabled + }; + + union pixel_argb_t + { + struct element_tag + { + unsigned char blue; + unsigned char green; + unsigned char red; + unsigned char alpha_channel; + }element; + unsigned value; + }; + + union pixel_rgba_t + { + struct element_tag + { + unsigned char alpha_channel; + unsigned char blue; + unsigned char green; + unsigned char red; + }element; + unsigned value; + }; + + using pixel_color_t = pixel_argb_t; + + /// See extended CSS color keywords (4.3) in http://www.w3.org/TR/2011/REC-css3-color-20110607/ + enum class colors + { + alice_blue = 0xf0f8ff, + antique_white = 0xfaebd7, + aqua = 0xFFFF, + aquamarine = 0x7fffd4, + azure = 0xf0ffff, + beige = 0xf5f5dc, + bisque = 0xffe4ce, + black = 0x0, + blanched_almond = 0xffebcd, + blue = 0x0000FF, + blue_violet = 0x8a2be2, + brown = 0xa52a2a, + burly_wood = 0xdeb887, + cadet_blue = 0x5f9ea0, + chartreuse = 0x7fff00, + chocolate = 0xd2691e, + coral = 0xff7f50, + cornflower_blue = 0x6495ed, + cornsilk = 0xfff8dc, + crimson = 0xdc143c, + cyan = 0xffff, + dark_blue = 0x8b, + dark_cyan = 0x8b8b, + dark_goldenrod = 0xb8860b, + dark_gray = 0xa9a9a9, + dark_green = 0x6400, + dark_grey = dark_gray, + dark_khaki = 0xbdb76b, + dark_magenta = 0x8b008b, + dark_olive_green = 0x556b2f, + dark_orange = 0xff8c00, + dark_orchid = 0x9932cc, + dark_red = 0x8b0000, + dark_salmon = 0xe9976a, + dark_sea_green = 0x8fbc8f, + dark_slate_blue = 0x483d8b, + dark_slate_gray = 0x2f4f4f, + dark_slate_grey = 0x2f4f4f, + dark_turquoise = 0xced1, + dark_violet = 0x9400d3, + deep_pink = 0xff1493, + deep_sky_blue = 0xbfff, + dim_gray = 0x696969, + dim_grey = dim_gray, + dodger_blue = 0x1e90ff, + firebrick = 0xb22222, + floral_white = 0xfffaf0, + forest_green = 0x228b22, + fuchsia = 0xFF00FF, + gainsboro = 0xdcdcdc, + ghost_white = 0xf8f8ff, + gold = 0xffd700, + goldenrod = 0xdaa520, + gray = 0x808080, + green = 0x008000, + green_yellow = 0xadff2f, + grey = gray, + honeydew = 0xf0fff0, + hot_pink = 0xff69b4, + indian_red = 0xcd5c5c, + indigo = 0x4b0082, + ivory = 0xfffff0, + khaki = 0xf0e68c, + lavendar = 0xe6e6fa, + lavender_blush = 0xfff0f5, + lawn_green = 0x7cfc00, + lemon_chiffon = 0xfffacd, + light_blue = 0xadd8e6, + light_coral = 0xf08080, + light_cyan = 0xe0ffff, + light_goldenrod_yellow = 0xfafad2, + light_gray = 0xd3d3d3, + light_green = 0x90ee90, + light_grey = light_gray, + light_pink = 0xffb6c1, + light_salmon = 0xffa07a, + light_sea_green = 0x20b2aa, + light_sky_blue = 0x87cefa, + light_slate_gray = 0x778899, + light_slate_grey = light_slate_gray, + light_steel_blue = 0xb0c4de, + light_yellow = 0xffffe0, + lime = 0x00FF00, + lime_green = 0x32cd32, + linen = 0xfaf0e6, + magenta = 0xff00ff, + maroon = 0x800000, + medium_aquamarine = 0x66cdaa, + medium_blue = 0xcd, + medium_orchid = 0xba55d3, + medium_purple = 0x9370db, + medium_sea_green = 0x3cb371, + medium_slate_blue = 0x7b68ee, + medium_spring_green = 0xfa9a, + medium_turquoise = 0x48d1cc, + medium_violet_red = 0xc71585, + midnight_blue = 0x191970, + mint_cream = 0xf5fffa, + + misty_rose = 0xffe4e1, + moccasin = 0xffe4b5, + navajo_white = 0xffdead, + navy = 0x000080, + old_lace = 0xfdf5e6, + olive = 0x808000, + olive_drab = 0x6b8e23, + orange = 0xffa500, + orange_red = 0xff4500, + orchid = 0xda70d6, + pale_goldenrod = 0xeee8aa, + pale_green = 0x98fb98, + pale_turquoise = 0xafeeee, + pale_violet_red = 0xdb7093, + papaya_whip = 0xffefd5, + peach_puff = 0xffdab9, + peru = 0xcd853f, + pink = 0xffc0cb, + plum = 0xdda0dd, + powder_blue = 0xb0e0e6, + purple = 0x800080, + red = 0xFF0000, + rosy_brown = 0xbc8f8f, + royal_blue = 0x4169e1, + saddle_brown = 0x8b4513, + salmon = 0xfa8072, + sandy_brown = 0xf4a460, + sea_green = 0x2e8b57, + sea_shell = 0xfff5ee, + sienna = 0xa0522d, + silver = 0xc0c0c0, + sky_blue = 0x87ceeb, + slate_blue = 0x6a5acd, + slate_gray = 0x708090, + slate_grey = 0x708090, + snow = 0xfffafa, + spring_green = 0xff7f, + steel_blue = 0x4682b4, + tan = 0xd2b48c, + teal = 0x008080, + thistle = 0xd8bfd8, + tomato = 0xff6347, + turquoise = 0x40e0d0, + violet = 0xee82ee, + wheat = 0xf5deb3, + white = 0xFFFFFF, + white_smoke = 0xf5f5f5, + yellow = 0xFFFF00, + yellow_green = 0x9acd32, + + //temporary definitions, these will be replaced by color schema + button_face_shadow_start = 0xF5F4F2, + button_face_shadow_end = 0xD5D2CA, + button_face = 0xD4D0C8 , //,light_cyan + dark_border = 0x404040, + gray_border = 0x808080, + highlight = 0x1CC4F7 + }; + + //Some helper types to identify an integer as color. + enum class color_rgb : unsigned{}; + enum class color_argb: unsigned{}; + enum class color_rgba : unsigned{}; + + class color + { + public: + color() = default; + color(colors); + color(colors, double alpha); + color(color_rgb); + color(color_argb); + color(color_rgba); + color(unsigned red, unsigned green, unsigned blue, double alpha = 1.0); + + /// Initializes the color with a CSS-like rgb string. + explicit color(std::string css_rgb); + + color& alpha(double); ///< Sets alpha channel + color& from_rgb(unsigned red, unsigned green, unsigned blue); ///< immutable alpha channel + + /// Sets color with a HSL value. + /// @param hue in range of [0, 360] + /// @param saturation in range of [0, 1] + /// @param lightness in range of [0, 1] + color& from_hsl(double hue, double saturation, double lightness); ///< immutable alpha channel + + /// Blends color + /** + * Returns a color which is blended as this * (1 - fade_rate) + blending_color * fade_rate + * @param blending_color Color to blend + * @param fade_rate Blending rate for blending_color + * @return a blended color + */ + color blend(const color& blending_color, double fade_rate) const; + + /// Determines whether the color is completely transparent. + bool invisible() const; + pixel_color_t px_color() const; + pixel_argb_t argb() const; + pixel_rgba_t rgba() const; + + const double& r() const; + const double& g() const; + const double& b() const; + const double& a() const; + + bool operator==(const color& other) const; + bool operator!=(const color& other) const; + + friend color operator+(const color&, const color&); + private: + double r_{ 0.0 }; + double g_{ 0.0 }; + double b_{ 0.0 }; + double a_{ 0.0 }; //invisible + }; + + template + struct basic_point + { + //typedef-names + using value_type = T; + + //data member + value_type x{}; + value_type y{}; + + //member functions + basic_point() = default; + + basic_point(value_type x, value_type y) + : x{ x }, y{y} + {} + + bool operator==(const basic_point& other) const noexcept + { + return (x == other.x && y == other.y); + } + + bool operator!=(const basic_point& other) const noexcept + { + return (x != other.x || y != other.y); + } + + bool operator<(const basic_point& other) const noexcept + { + return ((y < other.y) || (y == other.y && x < other.x)); + } + + bool operator<=(const basic_point& other) const noexcept + { + return ((y < other.y) || (y == other.y && x <= other.x)); + } + + bool operator>(const basic_point& other) const noexcept + { + return ((y > other.y) || (y == other.y && x > other.x)); + } + + bool operator>=(const basic_point& other) const noexcept + { + return ((y > other.y) || (y == other.y && x >= other.x)); + } + + basic_point operator-(const basic_point& other) const noexcept + { + return{ x - other.x, y - other.y }; + } + + basic_point operator+(const basic_point& other) const noexcept + { + return{ x + other.x, y + other.y }; + } + + basic_point& operator-=(const basic_point& other) noexcept + { + x -= other.x; + y -= other.y; + return *this; + } + + basic_point& operator+=(const basic_point& other) noexcept + { + x += other.x; + y += other.y; + return *this; + } + }; + + using point = basic_point; + using upoint = basic_point; + + struct size + { + using value_type = unsigned; + size(); + size(value_type width, value_type height); + + bool empty() const; ///< true if width * height == 0 + bool is_hit(const point&) const; ///< Assume it is a rectangle at (0,0), and check whether a specified position is in the rectangle. + size& shift(); + + bool operator==(const size& rhs) const; + bool operator!=(const size& rhs) const; + size operator+(const size&) const; + + value_type width; + value_type height; + }; + + struct rectangle + { + rectangle(); ///< a zero-size rectangle at (0, 0). + rectangle(int x, int y, unsigned width, unsigned height); + explicit rectangle(const size &); ///< a rectangle with specified size at coordinate (0, 0). + explicit rectangle(const point&, const size& = size()); + + bool operator==(const rectangle& rhs) const; + bool operator!=(const rectangle& rhs) const; + + point position() const noexcept; + rectangle& position(const point&) noexcept; + + size dimension() const noexcept; + rectangle& dimension(const size&) noexcept; + + /// Pares the specified pixels off the rectangle. + /** + * It's equal to x += pixels; y + pixels; width -= (pixels << 1); height -= (pixels << 1); + * @param pixels The number of pixels to be pared. If the number that multiples pixels twice is larger than width/height, the width/height will be zero. If the pixels is a negative number, the width/height is add the number that multiple pixels twice. + * @return The reference of *this. + */ + rectangle& pare_off(int pixels); + + int right() const noexcept; + int bottom() const noexcept; + bool is_hit(int x, int y) const; + bool is_hit(const point& pos) const; + bool empty() const; ///< true if width * height == 0. + rectangle& shift(); ///< Swap position x and y, size width and height. + + int x; + int y; + unsigned width; + unsigned height; + }; + + class rectangle_rotator + { + public: + rectangle_rotator(bool rotated, const ::nana::rectangle& area); + + int x() const; + int & x_ref(); + int y() const; + int & y_ref(); + unsigned w() const; + unsigned & w_ref(); + unsigned h() const; + unsigned & h_ref(); + + int right() const; + int bottom() const; + const ::nana::rectangle& result() const; + private: + bool rotated_; + ::nana::rectangle area_; + };//end class rectangle_rotator + + enum class arrange + { + unknown, horizontal, vertical, horizontal_vertical + }; + + ///The definition of horizontal alignment + enum class align + { + left, center, right + }; + + ///The definition of vertical alignment + enum class align_v + { + top, center, bottom + }; + + ///The definition of the four corners of the world + enum class direction + { + north, + south, + east, + west, + southeast + }; +}//end namespace nana +#include +#endif + + diff --git a/GUI/nana/c++defines.hpp b/GUI/nana/c++defines.hpp new file mode 100644 index 0000000..c7d5383 --- /dev/null +++ b/GUI/nana/c++defines.hpp @@ -0,0 +1,264 @@ +/** + * Predefined Symbols for C++ + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2016-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/c++defines.hpp + * + * @brief Provide switches to adapt to the target OS, use of external libraries or workarounds compiler errors or lack of std C++ support. + * + * To control target OS/compiler: + * - NANA_WINDOWS + * - NANA_MINGW + * - NANA_POSIX + * - NANA_LINUX + * - NANA_MACOS + * - NANA_X11 + * + * External libraries: + * - NANA_LIBPNG, USE_LIBPNG_FROM_OS + * - NANA_LIBJPEG, USE_LIBJPEG_FROM_OS + * + * (see: Feature-testing recommendations for C++ + * in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0096r0.html + * for example: __cpp_lib_experimental_filesystem = 201406 in is a known issue on libstdc++, it works on libc++) + * - STD_THREAD_NOT_SUPPORTED (GCC < 4.8.1) + * - STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED (MinGW with GCC < 4.8.1) + * - STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED (MinGW with GCC < 4.8.1) + * - STD_TO_STRING_NOT_SUPPORTED (MinGW with GCC < 4.8) + * - STD_FILESYSTEM_NOT_SUPPORTED (GCC < 5.3) .... + * - CXX_NO_INLINE_NAMESPACE (Visual C++ < 2015) + * + * There are two kinds of flags: + * * _nana_std_xxx indicates that nana provides a standard-like class for workaround of lack of C++ support. + * * _nana_std_has_xxx indicates that nana detects whether a C++ feature is supported. Nana doesn't provide a standard-like class for this missing feature. + * + * - _nana_std_make_unique (__cpluscplus < 201402) + * - _nana_std_put_time (GCC < 5) + * - _nana_std_clamp (Visual C++ < 2017) + */ + +#ifndef NANA_CXX_DEFINES_INCLUDED +#define NANA_CXX_DEFINES_INCLUDED +// #define STD_FILESYSTEM_NOT_SUPPORTED + +//C++ language +#if defined(_MSC_VER) +# if (_MSC_VER < 1900) // VC2013 +# //About std.experimental.filesystem. +# //Through VC2013 has provided , but all the names are given in namespace std. It's hard to alias these names into std::experimental, +# //So Nana use nana.filesystem implement instead for VC2013 +# define STD_FILESYSTEM_NOT_SUPPORTED +# +# //Nana defines some macros for lack of support of keywords +# define _ALLOW_KEYWORD_MACROS +# +# define CXX_NO_INLINE_NAMESPACE //no support of C++11 inline namespace until Visual C++ 2015 +# define noexcept //no support of noexcept until Visual C++ 2015 + +# define constexpr //no support of constexpr until Visual C++ 2015 ? const ?? +# endif +#elif defined(__GNUC__) && not defined(__clang__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ < 6) +# define noexcept //no support of noexcept until GCC 4.6 +# endif +#endif + +// Set this to "UTF-32" at the command-line for big endian. +#ifndef NANA_UNICODE + // much of the world runs intel compatible processors so default to LE. + #define NANA_UNICODE "UTF-32LE" +#endif + +// Select platform ...... +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) //Microsoft Windows + #define NANA_WINDOWS + typedef unsigned long thread_t; + + // MINGW ... + #if defined(__MINGW32__) || defined(__MINGW64__) || defined(MINGW) + #define NANA_MINGW + #endif // MINGW + +#elif defined(__APPLE__) || defined(APPLE) //Mac OS X + //Symbols for MACOS + #define NANA_MACOS + #define NANA_POSIX + #define NANA_X11 + typedef unsigned long thread_t; +#elif defined(__FreeBSD__) + #define NANA_POSIX + #define NANA_X11 + typedef unsigned long thread_t; +#elif (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC) //Linux + #define NANA_LINUX + #define NANA_POSIX + #define NANA_X11 + typedef unsigned long thread_t; +#else + static_assert(false, "Only Windows and Linux are supported now (Mac OS and BSD are experimental)"); +#endif + +// Select compiler ... +#if defined(_MSC_VER) //Microsoft Visual C++ + #define _SCL_SECURE_NO_WARNNGS + #define _CRT_SECURE_NO_DEPRECATE + #pragma warning(disable : 4996) + +# if (_MSC_VER >= 1900) + // google: break any code that tries to use codecvt or codecvt. + // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support. + // google: Those definitions are for codecvt::id, codecvt::id and codecvt::id respectively. + // However, the codecvt::id and codecvt::id definitions aren't there, and indeed, if you look at locale0.cpp in the CRT source code you'll see they're not defined at all. + // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. +# define STD_CODECVT_NOT_SUPPORTED +# endif // _MSC_VER == 1900 + +#elif defined(__clang__) //Clang + + #include // Introduces some implement-specific flags of ISO C++ Library + #if defined(__GLIBCPP__) || defined(__GLIBCXX__) + // is a known issue on libstdc++, it works on libc++ + #define STD_CODECVT_NOT_SUPPORTED + #endif +#elif defined(__GNUC__) // GCC + + #include // Introduces some implementation-specific flags of ISO C++ Library + #if defined(__GLIBCPP__) || defined(__GLIBCXX__) + // is a known issue on libstdc++, it works on libc++ todo review ! + #define STD_CODECVT_NOT_SUPPORTED + + //It's a known issue of libstdc++ on MinGW + //introduce to_string/to_wstring workarounds for disabled capacity of stdlib + #ifdef _GLIBCXX_HAVE_BROKEN_VSWPRINTF + #if (__GNUC__ < 5) + # define STD_TO_STRING_NOT_SUPPORTED + #endif + + #define STD_TO_WSTRING_NOT_SUPPORTED + #endif + #endif + + +# if ((__GNUC__ < 5) ) +# define _nana_std_put_time +# endif + +# if ((__GNUC__ > 5) || ((__GNUC__ == 5) && (__GNUC_MINOR__ >= 3 ) ) ) +# undef STD_FILESYSTEM_NOT_SUPPORTED +# else +# define STD_FILESYSTEM_NOT_SUPPORTED +# endif + + #if (__GNUC__ == 4) + #if ((__GNUC_MINOR__ < 8) || (__GNUC_MINOR__ == 8 && __GNUC_PATCHLEVEL__ < 1)) + #define STD_THREAD_NOT_SUPPORTED + #endif + + #if defined(NANA_MINGW) + #ifndef __MINGW64_VERSION_MAJOR + //It's a known issue under MinGW(except MinGW-W64) + #define STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED + #endif + #endif + + #if (__GNUC_MINOR__ < 8) + //introduce to_string/to_wstring workaround for lack of stdlib definitions + #ifndef STD_TO_STRING_NOT_SUPPORTED + # define STD_TO_STRING_NOT_SUPPORTED + #endif + + #ifndef STD_TO_WSTRING_NOT_SUPPORTED + # define STD_TO_WSTRING_NOT_SUPPORTED + #endif + #endif + #endif +#endif + +//Assume the std::thread is not implemented on MinGW, +//unless it was compiled with POSIX threading support. +//But some toolchains may implement std::thread. +#ifdef NANA_MINGW +# ifndef STD_THREAD_NOT_SUPPORTED +# define STD_THREAD_NOT_SUPPORTED +# endif +#endif + + +//Detects the feature std::make_unique +//std::make_unique has been provided by Visual C++ 2013 and later +#undef _nana_std_make_unique +#if (defined(__clang__) && (__cplusplus < 201305L || (__cplusplus == 201305L && (__clang_major__ * 100 + __clang_minor__ < 304 )))) \ + || ((!defined(__clang__)) && defined(__GNUC__) && __cplusplus < 201300L) +# define _nana_std_make_unique +#endif + +//Detects the feature std::clamp +//Visual C++ 2017 with /std:c++latest provides the std::clamp +#undef _nana_std_clamp +#if (defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || _MSVC_LANG < 201403L)) \ + || (defined(__clang__) && (__cplusplus < 201406L)) \ + || (defined(__GNUC__) && (!defined(__clang__)) && (__cplusplus < 201703)) +# define _nana_std_clamp +#endif + + +#undef _nana_std_optional +#if ((defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || _MSVC_LANG < 201703))) || \ + ((!defined(_MSC_VER)) && ((__cplusplus < 201703L) || \ + (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__ < 400)) || \ + (!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 701))) \ + ) +# define _nana_std_optional +#endif + +#undef _nana_std_has_string_view +#undef _nana_std_has_emplace_return_type +#if ((defined(_MSC_VER) && (_MSC_VER >= 1912) && defined(_MSVC_LANG) && _MSVC_LANG >= 201703)) || \ + ((__cplusplus >= 201703L) && \ + (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__ >= 400) || \ + (!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 701))) \ + ) +# define _nana_std_has_string_view +# define _nana_std_has_emplace_return_type +#endif + + +#if defined(NANA_WINDOWS) + #ifndef _UNICODE + #define _UNICODE + #endif + + #ifndef UNICODE + #define UNICODE + #endif +#endif + +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0061r0.html + +#if defined(__cpp_lib_experimental_filesystem) && (__cpp_lib_experimental_filesystem == 201406) +# undef STD_FILESYSTEM_NOT_SUPPORTED +#endif + + +#ifdef __has_include +# if __has_include() +# undef STD_FILESYSTEM_NOT_SUPPORTED +# endif +# if __has_include() +# if !(defined(NANA_MINGW) && !defined(_GLIBCXX_HAS_GTHREADS)) +//See the comment above regarding MinGW's threading support +# undef STD_THREAD_NOT_SUPPORTED +# endif +# endif +#endif + +#endif // NANA_CXX_DEFINES_INCLUDED diff --git a/GUI/nana/charset.hpp b/GUI/nana/charset.hpp new file mode 100644 index 0000000..b26dbb6 --- /dev/null +++ b/GUI/nana/charset.hpp @@ -0,0 +1,98 @@ +/** + * The charset Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/charset.hpp + */ + +#ifndef NANA_CHARSET_HPP +#define NANA_CHARSET_HPP +#include + +namespace nana +{ + namespace utf + { + /// Attempt to get a pointer to a character of UTF-8 string by a specified character index. + /// @param text_utf8 A string encoded as UTF-8. + /// @param pos The unicode character index. + /// @returns A pointer to the unicode character. It returns a null if pos is out of range. + const char* char_ptr(const char* text_utf8, unsigned pos); + const char* char_ptr(const ::std::string& text_utf8, unsigned pos); + + /// Get the unicode character by a specified character index. + /// @param text_utf8 A string encoded as UTF-8. + /// @param pos The unicode character index. + /// @param len A unsigned pointer to receive the number of bytes it takes in UTF-8 encoded. If len is a nullptr, it is ignored. + /// @returns A unicode character. '\0' if pos is out of range. + wchar_t char_at(const char* text_utf8, unsigned pos, unsigned * len); + wchar_t char_at(const ::std::string& text_utf8, unsigned pos, unsigned * len); + } + + enum class unicode + { + utf8, utf16, utf32 + }; + + namespace detail + { + class charset_encoding_interface; + } + + /*!\class charset + \brief An intelligent charset class for character code conversion. + Example: + 1. A UTF-8 string from the socket. + + int len = ::recv(sd, buf, buflen, 0); + textbox.caption(nana::charset(std::string(buf, len), nana::unicode::utf8)); + + 2. Send the string in text to the socket as UTF-8. + + std::string utf8str = nana::charset(textbox.caption()).to_bytes(nana::unicode::utf8); + ::send(sd, utf8str.c_str(), utf8str.size(), 0); + + 3, Convert a string to the specified multi-byte character code. + + // Convert to a multibytes string through default system language. + std::string mbstr = nana::charset(a_wstring); + + // If the default system language is English and convert + // a Chinese unicode string to multibytes string through GB2312 + std::setlocale(LC_CTYPE, "zh_CN.GB2312"); + //set::setlocale(LC_CTYPE, ".936"); call it in Windows + std::string mbstr = nana::charset(a_wstring_with_chinese); + + */ + class charset + { + public: + charset(const charset&); + charset & operator=(const charset&); + charset(charset&&); + charset & operator=(charset&&); + + charset(const std::string&); /// + +namespace nana +{ + namespace concepts + { + /// The Any Objective is an object that may attach to some other object. + template // no dep. on IndexType ?? + class any_objective + { + public: + virtual ~any_objective() = default; + + template + void anyobj(const Target& t) + { + nana::any * p = _m_anyobj(true); + if(nullptr == p) + throw std::runtime_error("Nana.any_objective: Object does not exist"); + *p = t; + } + + template + void anyobj(Target&& t) + { + nana::any * p = _m_anyobj(true); + if(nullptr == p) + throw std::runtime_error("Nana.any_objective: Object does not exist"); + + *p = std::move(t); + } + + template + Target * anyobj() const ///< Retrieves the attached object. Returns a nullptr if empty or if the type not match. + { + return any_cast(_m_anyobj(false)); + } + private: + virtual nana::any* _m_anyobj(bool allocate_if_empty) const = 0; + }; + + /// The Any Objective is an object that may attach to some other object. + template + class any_objective + { + public: + typedef IndexType anyobj_index_t; ///< The type of index. It is available if Dimension is greater than 0. + + virtual ~any_objective() = default; + + template + void anyobj(anyobj_index_t i, const Target& t) + { + nana::any * p = _m_anyobj(i, true); + if(nullptr == p) + throw std::runtime_error("Nana.any_objective: Object does not exist."); + *p = t; + } + + template + void anyobj(anyobj_index_t i, Target&& t) + { + nana::any * p = _m_anyobj(i, true); + if(nullptr == p) + throw std::runtime_error("Nana.any_objective: Object does not exist"); + *p = std::move(t); + } + + template + Target * anyobj(anyobj_index_t i) const ///< Retrieves the attached object. Returns a nullptr if empty or if the type not match. + { + return any_cast(_m_anyobj(i, false)); + } + private: + virtual nana::any* _m_anyobj(anyobj_index_t i, bool allocate_if_empty) const = 0; + }; + + /// The Any Objective is an object that may attach to some other object. + template + class any_objective + { + public: + typedef IndexType anyobj_index_t; + + virtual ~any_objective(){} + + template + void anyobj(anyobj_index_t i0, anyobj_index_t i1, const Target& t) + { + nana::any * p = _m_anyobj(i0, i1, true); + if(nullptr == p) + throw std::runtime_error("Nana.any_objective: Object does not exist"); + + *p = t; + } + + template + void anyobj(anyobj_index_t i0, anyobj_index_t i1, Target&& t) + { + nana::any * p = _m_anyobj(i0, i1, true); + if(nullptr == p) + throw std::runtime_error("Nana.any_objective: Object does not exist"); + *p = std::move(t); + } + + template + Target * anyobj(anyobj_index_t i0, anyobj_index_t i1) const ///< Retrieves the attached object. Returns a nullptr if empty or if the type not match. + { + return any_cast(_m_anyobj(i0, i1, false)); + } + private: + virtual nana::any* _m_anyobj(anyobj_index_t i0, anyobj_index_t i1, bool allocate_if_empty) const = 0; + }; + }//end namespace concepts +}//end namespace nana +#endif diff --git a/GUI/nana/config.hpp b/GUI/nana/config.hpp new file mode 100644 index 0000000..aeabf1d --- /dev/null +++ b/GUI/nana/config.hpp @@ -0,0 +1,115 @@ +/** + * Nana Configuration + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/config.hpp + * + * @brief Provide switches to enable 3rd-party libraries for a certain feature. + * + * External libraries: + * - NANA_LIBPNG, USE_LIBPNG_FROM_OS + * - NANA_LIBJPEG, USE_LIBJPEG_FROM_OS + * - NANA_ENABLE_AUDIO + * + * messages: + * - VERBOSE_PREPROCESSOR, STOP_VERBOSE_PREPROCESSOR + */ + +#ifndef NANA_CONFIG_HPP +#define NANA_CONFIG_HPP + +#include "c++defines.hpp" + +//The following basic configurations are ignored when NANA_IGNORE_CONF is defined. +//The NANA_IGNORE_CONF may be specified by CMake generated makefile. +#ifndef NANA_IGNORE_CONF + +// Here defines some flags that tell Nana what features will be supported. + +/////////////////////////// +// Support of std::thread +// Boost.Thread is preferred. +// NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ is only available on MinGW when STD_THREAD_NOT_SUPPORTED is defined. +// if NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ is enabled, Boost.Thread will be replaced with meganz's mingw-std-threads. +// https://github.com/meganz/mingw-std-threads +//#define NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ + +//# The ISO C++ File System Technical Specification(ISO - TS, or STD) is optional. +//# http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf +//# This is not a workaround, but an user option. +//# The library maybe available in the std library in use or from Boost(almost compatible) +//# http://www.boost.org/doc/libs/1_60_0/libs/filesystem/doc/index.htm +//# or you can choose to use the(partial, but functional) implementation provided by nana. +//# If you include the file +//# the selected option will be set by nana into std::experimental::filesystem +//# By default Nana will try to use the STD.If not available will try +//# to use boost if available.Nana own implementation will be use only none of them are available. +//# You can change that default if you change one of the following +//# (please don't define more than one of the _XX_FORCE options): +// +//#define BOOST_FILESYSTEM_AVAILABLE // "Is Boost filesystem available?" +//#define BOOST_FILESYSTEM_FORCE // "Force use of Boost filesystem if available (over ISO and nana) +//#define STD_FILESYSTEM_FORCE // "Use of STD filesystem?(a compilation error will occur if not available)" OFF) +//#define NANA_FILESYSTEM_FORCE // "Force nana filesystem over ISO and boost?" OFF) +// +// Make sure you (cmake?) provide the following where correspond (please find the correct values): +// set CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT "Where to find ?" "../") +// set CMAKE_BOOST_FILESYSTEM_LIB "Flag for the compiler to link: " "-lboost/fs") +// include_directories CMAKE_BOOST_FILESYSTEM_INCLUDE_ROOT +// APPEND flag LINKS CMAKE_BOOST_FILESYSTEM_LIB + + +/////////////////// +// Support of PCM playback +// +//#define NANA_ENABLE_AUDIO + +/////////////////// +// Support for PNG +// Define the NANA_ENABLE_PNG to enable the support of PNG. +// +//#define NANA_ENABLE_PNG //! +//#define USE_LIBPNG_FROM_OS // Un-Comment it to use libpng from operating system. +#if defined(NANA_ENABLE_PNG) + #if !defined(USE_LIBPNG_FROM_OS) + #define NANA_LIBPNG + #endif +#endif + +/////////////////// +// Support for JPEG +// Define the NANA_ENABLE_JPEG to enable the support of JPEG. +// +//#define NANA_ENABLE_JPEG //! +//#define USE_LIBJPEG_FROM_OS // Un-Comment it to use libjpeg from operating system. +#if defined(NANA_ENABLE_JPEG) + #if !defined(USE_LIBJPEG_FROM_OS) + #define NANA_LIBJPEG + #endif +#endif + +/////////////////// +// Support for NANA_AUTOMATIC_GUI_TESTING +// Will cause the program to self-test the GUI. A default automatic GUI test +// will be added to all programs which don't have yet one defined. This default test will simple +// wait 10 sec. (time to construct, show and execute the GUI) and then exit normally. +// +//#define NANA_AUTOMATIC_GUI_TESTING + + + +#if !defined(VERBOSE_PREPROCESSOR) +//#define VERBOSE_PREPROCESSOR +#endif + +#if !defined(STOP_VERBOSE_PREPROCESSOR) +//#define STOP_VERBOSE_PREPROCESSOR +#endif + +#endif // NANA_IGNORE_CONFIG +#endif // NANA_CONFIG_HPP diff --git a/GUI/nana/datetime.hpp b/GUI/nana/datetime.hpp new file mode 100644 index 0000000..c87d58a --- /dev/null +++ b/GUI/nana/datetime.hpp @@ -0,0 +1,77 @@ +/* + * A Date Time Implementation + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/datetime.hpp + */ + +#ifndef NANA_DATETIME_HPP +#define NANA_DATETIME_HPP +#include + +namespace nana +{ + /// A date operation class. \see nana::date_chooser + class date + { + public: + struct value + { + unsigned year; ///< 1601 - 30827 + unsigned month; ///< 1-12 + unsigned day; ///< 1-31 + }; + + date(); ///< the initialized date is today. + explicit date(const std::tm&); + date(int year, int month, int day); + + date operator - (int off) const; + date operator + (int off) const; + bool operator==(const date&) const; + bool operator!=(const date&) const; + bool operator<(const date&) const; + bool operator>(const date&) const; + bool operator<=(const date&) const; + bool operator>=(const date&) const; + + int day_of_week() const; + const value & read() const; + void set(const std::tm&); + + static int day_of_week(int year, int month, int day); + static unsigned year_days(const unsigned year); ///< the number of days in the specified year. + static unsigned month_days(const unsigned year, const unsigned month); ///< the number of days in the specified month. + static unsigned day_in_year(unsigned y, unsigned m, unsigned d); ///< Returns the index of the specified day in this year, at range[1, 365] or [1, 366] + private: + date _m_add(unsigned x) const; + date _m_sub(unsigned x) const; + private: + value value_; + }; //end class date + + class time + { + public: + struct value + { + unsigned hour; ///<[0-23] + unsigned minute; ///<[0-59] + unsigned second; ///<[0-61], the range of [60, 61] is used for leap seconds + }; + + time(); + time(const std::tm&); + time(unsigned hour, unsigned minute, unsigned second); + const value& read() const; + void set(const std::tm&); + private: + value value_; + };//end class time +}//end namespace nana + +#endif diff --git a/GUI/nana/deploy.hpp b/GUI/nana/deploy.hpp new file mode 100644 index 0000000..9550e9f --- /dev/null +++ b/GUI/nana/deploy.hpp @@ -0,0 +1,122 @@ +/* + * The Deploy Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/deploy.hpp + * + * What follows is dependent on what defined in nana/config.hpp + */ + +#ifndef NANA_DEPLOY_HPP +#define NANA_DEPLOY_HPP +#include + +#include +#include + +#include + +#include + +#ifdef _nana_std_has_string_view +#include +#endif + +namespace nana +{ + /// move to *.h ?? + struct utf8_Error : std::runtime_error + { + static bool use_throw; ///< def { true }; use carefully - it is a global variable !! \todo initialize from a #define ? + + using std::runtime_error::runtime_error; + +#if defined(_MSC_VER) +# if (_MSC_VER < 1900) + //A workaround for lack support of C++11 inheriting constructors for VC2013 + explicit utf8_Error(const std::string& msg); +# endif +#endif + + void emit(); + }; + + + /// Checks whether a specified text is utf8 encoding +#ifdef _nana_std_has_string_view + bool is_utf8(std::string_view str); + void throw_not_utf8(std::string_view str); +#else + bool is_utf8(const char* str, std::size_t len); + void throw_not_utf8(const std::string& text); + void throw_not_utf8(const char*, std::size_t len); + void throw_not_utf8(const char*); +#endif + + /// this text needed change, it needed review ?? + bool review_utf8(const std::string& text); + + /// this text needed change, it needed review ?? + bool review_utf8(std::string& text); + + const std::string& to_utf8(const std::string&); + +#ifdef _nana_std_has_string_view + std::string to_utf8(std::wstring_view sv); + std::wstring to_wstring(std::string_view utf8_str); +#else + std::string to_utf8(const std::wstring&); + std::wstring to_wstring(const std::string& utf8_str); +#endif + + const std::wstring& to_wstring(const std::wstring& wstr); + std::wstring&& to_wstring(std::wstring&& wstr); + +#if defined(NANA_WINDOWS) + std::string to_osmbstr(const std::string& text_utf8); +#else + std::string to_osmbstr(std::string text_utf8); +#endif + + + namespace detail + { +#if defined(NANA_WINDOWS) + using native_string_type = std::wstring; +#else //POSIX + using native_string_type = std::string; +#endif + } + +#if defined(NANA_WINDOWS) + const detail::native_string_type to_nstring(const std::string&); + const detail::native_string_type& to_nstring(const std::wstring&); + detail::native_string_type to_nstring(std::string&&); + detail::native_string_type&& to_nstring(std::wstring&&); +#else //POSIX + const detail::native_string_type& to_nstring(const std::string&); + const detail::native_string_type to_nstring(const std::wstring&); + detail::native_string_type&& to_nstring(std::string&&); + detail::native_string_type to_nstring(std::wstring&&); +#endif + detail::native_string_type to_nstring(int); + detail::native_string_type to_nstring(double); + detail::native_string_type to_nstring(std::size_t); +} + + +namespace nana +{ + inline unsigned make_rgb(unsigned char red, unsigned char green, unsigned char blue) + { + return ((unsigned(red) << 16)|((unsigned(green)<<8))|blue); + } +} + +#include +#endif //NANA_DEPLOY_HPP diff --git a/GUI/nana/filesystem/filesystem.hpp b/GUI/nana/filesystem/filesystem.hpp new file mode 100644 index 0000000..79bfdce --- /dev/null +++ b/GUI/nana/filesystem/filesystem.hpp @@ -0,0 +1,627 @@ +/** + * A ISO C++ filesystem Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/filesystem/filesystem.hpp + * @author Ariel Vina-Rodriguez, Jinhao + * @brief Mimic std::filesystem + * and need VC2015 or a C++11 compiler. With a few correction can be compiler by VC2013 + */ + +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf --- pdf of std draft N4100 2014-07-04 +// http://en.cppreference.com/w/cpp/experimental/fs +// http://cpprocks.com/introduction-to-tr2-filesystem-library-in-vs2012/ --- TR2 filesystem in VS2012 +// https://msdn.microsoft.com/en-us/library/hh874694%28v=vs.140%29.aspx --- C++ 14, the header VS2015 +// https://msdn.microsoft.com/en-us/library/hh874694%28v=vs.120%29.aspx --- header VS2013 +// http://cplusplus.github.io/filesystem-ts/working-draft.html --- in html format +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4099.html --- in html format +// http://article.gmane.org/gmane.comp.lib.boost.devel/256220 --- The filesystem TS unanimously approved by ISO. +// http://theboostcpplibraries.com/boost.filesystem --- Boost docs +// http://www.boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm --- +// http://www.boost.org/doc/libs/1_34_0/libs/filesystem/doc/index.htm +// http://www.boost.org/doc/libs/1_58_0/boost/filesystem.hpp +// https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.200x --- Table 1.4. g++ C++ Technical Specifications Implementation Status + +#ifndef NANA_FILESYSTEM_HPP +#define NANA_FILESYSTEM_HPP +#include + +//Filesystem Selection +#include + +#define NANA_USING_NANA_FILESYSTEM 0 +#define NANA_USING_STD_FILESYSTEM 0 +#define NANA_USING_BOOST_FILESYSTEM 0 + +//#define NANA_FILESYSTEM_FORCE 1 + +#if (defined(NANA_FILESYSTEM_FORCE) || ( (defined(STD_FILESYSTEM_NOT_SUPPORTED) && !defined(BOOST_FILESYSTEM_AVAILABLE)) && !(defined(BOOST_FILESYSTEM_FORCE) || defined(STD_FILESYSTEM_FORCE)) ) ) +#undef NANA_USING_NANA_FILESYSTEM +#define NANA_USING_NANA_FILESYSTEM 1 + +#elif (defined(BOOST_FILESYSTEM_AVAILABLE) && ( defined(BOOST_FILESYSTEM_FORCE) || ( defined(STD_FILESYSTEM_NOT_SUPPORTED) && !defined(STD_FILESYSTEM_FORCE) ) )) +#undef NANA_USING_BOOST_FILESYSTEM +#define NANA_USING_BOOST_FILESYSTEM 1 +# include +# include + +// inline boost::filesystem into std::filesystem +namespace std { + namespace filesystem { + inline namespace boost_filesystem { + using namespace boost::filesystem; + using file_time_type = std::chrono::time_point; + + enum class file_type { + none = boost::filesystem::file_type::status_unknown, + not_found = boost::filesystem::file_type::file_not_found, + regular = boost::filesystem::file_type::regular_file, + directory = boost::filesystem::file_type::directory_file, + symlink = boost::filesystem::file_type::symlink_file, + block = boost::filesystem::file_type::block_file, + character = boost::filesystem::file_type::character_file, + fifo = boost::filesystem::file_type::fifo_file, + socket = boost::filesystem::file_type::socket_file, + unknown = boost::filesystem::file_type::type_unknown, + }; + // Boost dont include generic_u8string + // http://www.boost.org/doc/libs/1_66_0/boost/filesystem/path.hpp + // + // Boost versions: 1.67.0, 1.66.0, ... 1.56.0 enable directory_iterator C++11 range-base for + // http://www.boost.org/doc/libs/1_66_0/boost/filesystem/operations.hpp + // but travis come with an oooold version of boost + // 1.55.0 NOT enable directory_iterator C++11 range-base for + // http://www.boost.org/doc/libs/1_54_0/boost/filesystem/operations.hpp + #if BOOST_VERSION < 105600 + namespace boost { // todo ?? + // enable directory_iterator C++11 range-base for statement use --------------------// + + // begin() and end() are only used by a range-based for statement in the context of + // auto - thus the top-level const is stripped - so returning const is harmless and + // emphasizes begin() is just a pass through. + inline const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT + { + return iter; + } + + inline directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT + { + return directory_iterator(); + } + } + #endif + } // boost_filesystem + } // filesystem +} // std + +#else +# undef NANA_USING_STD_FILESYSTEM +# define NANA_USING_STD_FILESYSTEM 1 + //Detects whether the compiler supports std::filesystem under current options +# if ((defined(_MSC_VER) && (_MSC_VER >= 1912) && defined(_MSVC_LANG) && _MSVC_LANG >= 201703)) || \ + ((__cplusplus >= 201703L) && \ + (defined(__clang__) && (__clang_major__ >= 7) || \ + (!defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 8))) ) +# include +# else +# include + namespace std{ + namespace filesystem{ + using namespace std::experimental::filesystem; + } + } +# undef NANA_USING_STD_EXPERIMENTAL_FILESYSTEM +# define NANA_USING_STD_EXPERIMENTAL_FILESYSTEM +# endif +#endif // BOOST_FILESYSTEM and NANA_FILESYSTEM + +#if NANA_USING_NANA_FILESYSTEM + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace nana { + namespace filesystem { + + enum class file_type + { + none = 0, ///< has not been determined or an error occurred while trying to determine + not_found = -1, ///< Pseudo-type: file was not found. Is not considered an error + regular = 1, + directory = 2, + symlink = 3, ///< Symbolic link file + block = 4, ///< Block special file + character = 5, ///< Character special file + fifo = 6, ///< FIFO or pipe file + socket = 7, + unknown = 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other + }; + + enum class perms + { + none = 0, ///< There are no permissions set for the file. + all = 0x1FF, ///< owner_all | group_all | others_all + mask = 0xFFF, ///< all | set_uid | set_gid | sticky_bit. + unknown = 0xFFFF ///< not known, such as when a file_status object is created without specifying the permissions + }; + //enum class copy_options; + + enum class directory_options + { + none, + follow_directory_symlink, + skip_permission_denied + }; + + struct space_info + { + uintmax_t capacity; + uintmax_t free; + uintmax_t available; + }; + + using file_time_type = std::chrono::time_point; ///< trivial-clock> ; + + class file_status + { + file_type m_ft = file_type::none; + perms m_prms = perms::unknown; + + public: + explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown); + + // observers + file_type type() const; + + perms permissions() const; + + // modifiers + void type(file_type ft); + + void permissions(perms prms); + + private: + file_type value_; + perms perms_; + }; + + /// concerned only with lexical and syntactic aspects and does not necessarily exist in + /// external storage, and the pathname is not necessarily valid for the current operating system + /// or for a particular file system + /// A sequence of elements that identify the location of a file within a filesystem. + /// The elements are the: + /// rootname (opt), root-directory (opt), and an optional sequence of filenames. + /// The maximum number of elements in the sequence is operating system dependent. + class path + { + public: +#if defined(NANA_WINDOWS) + using value_type = wchar_t; + const static value_type preferred_separator = L'\\'; +#else + using value_type = char; + const static value_type preferred_separator = '/'; +#endif + using string_type = std::basic_string; + + path() = default; + + template + path(const Source &source) + { + _m_assign(source); + } + + // modifiers + void clear() noexcept; + + path &make_preferred(); + + path &remove_filename(); + //path& replace_filename(const path& replacement); + //path& replace_extension(const path& replacement = path()); + //void swap(path& rhs) noexcept; + + // decomposition + path root_name() const; + + path root_directory() const; + + path root_path() const; + + path relative_path() const; + + path parent_path() const; + + path filename() const; + + path stem() const; + + path extension() const; + + // query + bool empty() const noexcept; + + bool has_root_name() const + { return !root_name().empty(); } + + bool has_root_directory() const + { return !root_directory().empty(); } + + bool has_root_path() const + { return !root_path().empty(); } + + bool has_relative_path() const + { return !relative_path().empty(); } + + bool has_parent_path() const + { return !parent_path().empty(); }; // temp;; + bool has_filename() const + { return !filename().empty(); }; // temp; + //bool has_stem() const; + bool has_extension() const + { return !extension().empty(); }; // temp + bool is_absolute() const; + + bool is_relative() const; + + int compare(const path &other) const; + + file_type what() const; + + const value_type *c_str() const; + + const string_type &native() const; + + operator string_type() const; + + std::string string() const; + + std::wstring wstring() const; + + // std::string u8string() const; + // std::u16string u16string() const; + // std::u32string u32string() const; + + std::string generic_string() const; + + std::wstring generic_wstring() const; + + // std::string generic_u8string() const; + // std::u16string generic_u16string() const; + // std::u32string generic_u32string() const; + + path lexically_normal() const; + + //appends + path &operator/=(const path &other); + + template + path &operator/=(const Source &source) + { + path other(source); + return this->operator/=(other); + } + + template + path &append(const Source &source) + { + path other(source); + return this->operator/=(other); + } + + private: + void _m_assign(const std::string &source_utf8); + + void _m_assign(const std::wstring &source); + + private: + string_type pathstr_; + }; + + bool operator==(const path &lhs, const path &rhs); + + bool operator!=(const path &lhs, const path &rhs); + + bool operator<(const path &lhs, const path &rhs); + + bool operator>(const path &lhs, const path &rhs); + + path operator/(const path &lhs, const path &rhs); + + + class filesystem_error + : public std::system_error + { + public: + explicit filesystem_error(const std::string &msg, std::error_code); + + filesystem_error(const std::string &msg, const path &path1, std::error_code err); + + filesystem_error(const std::string &msg, const path &path1, const path &path2, std::error_code err); + + const path &path1() const noexcept; + + const path &path2() const noexcept; + // const char* what() const noexcept; + private: + path path1_; + path path2_; + }; + + + class directory_entry + { + public: + directory_entry() = default; + + explicit directory_entry(const filesystem::path &); + + //modifiers + void assign(const filesystem::path &); + + void replace_filename(const filesystem::path &); + + //observers + file_status status() const; + + operator const filesystem::path &() const + { return path_; }; + + const filesystem::path &path() const; + + private: + filesystem::path path_; + }; + + /// InputIterator that iterate over the sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator + class directory_iterator : public std::iterator + { + using find_handle = void *; + public: + + directory_iterator() noexcept; + + explicit directory_iterator(const path &p); + + directory_iterator(const path &p, directory_options opt); + + const value_type &operator*() const; + + const value_type *operator->() const; + + directory_iterator &operator++(); + + directory_iterator operator++(int); ///< extention + + bool equal(const directory_iterator &x) const; + + private: + template + static bool _m_ignore(const Char *p) + { + while (*p == '.') + ++p; + return (*p == 0); + } + + void _m_prepare(const path &file_path); + + void _m_read(); + + private: + bool end_{false}; + path::string_type path_; + directory_options option_{directory_options::none}; + + std::shared_ptr find_ptr_; + find_handle handle_{nullptr}; + value_type value_; + }; + + /// enable directory_iterator range-based for statements + inline directory_iterator begin(directory_iterator iter) noexcept + { + return iter; + } + + inline directory_iterator end(const directory_iterator &) noexcept + { + return {}; + } + + + //class recursive_directory_iterator; + //// enable recursive_directory_iterator range-based for statements + //recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; + //recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; + + //template + inline bool operator==(const directory_iterator/**/ &x, const directory_iterator/**/ &y) + { + return x.equal(y); + } + + //template + inline bool operator!=(const directory_iterator/**/ &x, const directory_iterator/**/ &y) + { + return !x.equal(y); + } + + + file_status status(const path &p); + + file_status status(const path &p, std::error_code &); + + std::uintmax_t file_size(const path &p); + + std::uintmax_t file_size(const path &p, std::error_code &ec) noexcept; + + inline bool is_directory(file_status s) noexcept + { return s.type() == file_type::directory; } + + bool is_directory(const path &p); + + bool is_directory(const path &p, std::error_code &ec) noexcept; + + inline bool is_regular_file(file_status s) noexcept + { + return s.type() == file_type::regular; + } + + inline bool is_regular_file(const path &p) + { + return is_regular_file(status(p)); + } + // bool is_regular_file(const path& p, error_code& ec) noexcept; // todo: + // Returns: is_regular_file(status(p, ec)).Returns false if an error occurs. // todo: + + inline bool is_empty(const path &p) + { + auto fs = status(p); + + if (is_directory(fs)) + return (directory_iterator() == directory_iterator(p)); + + return (file_size(p) == 0); + } + // bool is_empty(const path& p, error_code& ec) noexcept; + + + bool create_directories(const path &p); + + //bool create_directories(const path& p, error_code& ec) noexcept; + bool create_directory(const path &p); + + //bool create_directory(const path& p, error_code& ec) noexcept; + bool create_directory(const path &p, const path &attributes); + //bool create_directory(const path& p, const path& attributes, error_code& ec) noexcept; + + + /// The time of last data modification of p, determined as if by the value of the POSIX + /// stat structure member st_mtime obtained as if by POSIX stat(). + file_time_type last_write_time(const path &p); + /// returns file_time_type::min() if an error occurs + //file_time_type last_write_time(const path& p, error_code& ec) noexcept; + + + path current_path(); + + //path current_path(error_code& ec); + void current_path(const path &p); ///< chdir + //void current_path(const path& p, error_code& ec) noexcept; + + bool remove(const path &p); + + bool remove(const path &p, std::error_code &ec); // noexcept; + + //uintmax_t remove_all(const path& p); + //uintmax_t remove_all(const path& p, error_code& ec) noexcept; + + template + std::basic_string parent_path(const std::basic_string &path) + { + auto index = path.size(); + + if (index) + { + auto str = path.c_str(); + + for (--index; index > 0; --index) + { + auto c = str[index]; + if (c != '\\' && c != '/') + break; + } + + for (--index; index > 0; --index) + { + auto c = str[index]; + if (c == '\\' || c == '/') + break; + } + } + + return index ? path.substr(0, index + 1) : std::basic_string(); + } + + path absolute(const path& p); + path absolute(const path& p, std::error_code& err); + + path canonical(const path& p); + path canonical(const path& p, std::error_code& err); + + path weakly_canonical(const path& p); + path weakly_canonical(const path& p, std::error_code& err); + + bool exists( file_status s ) noexcept; + bool exists( const path& p ); + bool exists( const path& p, std::error_code& ec ) noexcept; + } //end namespace filesystem +} //end namespace nana + +namespace std +{ + namespace filesystem + { +#if defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || _MSVC_LANG < 201703) + using namespace ::nana::filesystem; +#else + inline namespace nana_filesystem + { + using namespace ::nana::filesystem; + } +#endif + } +} + + +#else // not #if NANA_USING_NANA_FILESYSTEM and not BOOST_FILESYSTEM, also incomplete STD_FILESYSTEM +//Implements the missing functions for various version of experimental/filesystem + namespace std + { + namespace filesystem + { +#if defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703)) + path absolute(const path& p); + path absolute(const path& p, std::error_code& err); + + path canonical(const path& p); + path canonical(const path& p, std::error_code& err); + + path weakly_canonical(const path& p); + path weakly_canonical(const path& p, std::error_code& err); +#endif +/* +#if defined(NANA_MINGW) // todo ?? + bool exists( std::filesystem::file_status s ) noexcept; + bool exists( const std::filesystem::path& p ); + bool exists( const std::filesystem::path& p, std::error_code& ec ) noexcept; +#endif +*/ + //Visual Studio 2017 +#if (defined(NANA_USING_STD_EXPERIMENTAL_FILESYSTEM) && defined(_MSC_VER) && (_MSC_VER > 1912)) || \ + (!defined(__clang__) && defined(__GNUC__) && (__cplusplus < 201603 || (__GNUC__* 100 + __GNUC_MINOR__ < 801))) + path weakly_canonical(const path& p); + path weakly_canonical(const path& p, std::error_code& err); +#endif + } // namespace filesystem + } // namespace std + +#endif // incomplete STD_FILESYSTEM + +#include +#endif //NANA_FILESYSTEM_HPP diff --git a/GUI/nana/filesystem/filesystem_ext.hpp b/GUI/nana/filesystem/filesystem_ext.hpp new file mode 100644 index 0000000..3eca8f9 --- /dev/null +++ b/GUI/nana/filesystem/filesystem_ext.hpp @@ -0,0 +1,130 @@ +/** +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file nana\filesystem\filesystem_ext.hpp +* @autor Ariel Vina-Rodriguez: +* @brief Some convenient extensions to the filesystem library. +* +*/ + +#ifndef NANA_FILESYSTEM_EXT_HPP +#define NANA_FILESYSTEM_EXT_HPP + +#include +#include + +namespace nana +{ +namespace filesystem_ext +{ + +#if defined(NANA_WINDOWS) + constexpr auto const def_root = "C:"; + constexpr auto const def_rootstr = "C:\\"; + constexpr auto const def_rootname = "Local Drive(C:)"; +#elif defined(NANA_POSIX) + constexpr auto const def_root = "/"; + constexpr auto const def_rootstr = "/"; + constexpr auto const def_rootname = "Root/"; +#endif + +std::filesystem::path path_user(); ///< extention ? + +inline bool is_directory(const std::filesystem::directory_entry& dir) noexcept +{ + return is_directory(dir.status()); +} + +//template // DI = directory_iterator from std, boost, or nana : return directory_entry +class directory_only_iterator : public std::filesystem::directory_iterator +{ + using directory_iterator = std::filesystem::directory_iterator; + + directory_only_iterator& find_first() + { + directory_only_iterator end{}; + while (*this != end) + { + if (is_directory((*(*this)).status())) + return *this; + this->directory_iterator::operator++(); + } + return *this; + } +public: + directory_only_iterator() = default; + + template + directory_only_iterator(Arg&& arg, Args&&... args) : directory_iterator(arg, std::forward(args)...) + { + find_first(); + } + + directory_only_iterator& operator++() + { + this->directory_iterator::operator++(); + return find_first(); + } +}; + +inline directory_only_iterator begin(directory_only_iterator iter) noexcept +{ + return iter; +} + +inline directory_only_iterator end(const directory_only_iterator&) noexcept +{ + return{}; +} + +//template // DI = directory_iterator from std, boost, or nana : value_type directory_entry +class regular_file_only_iterator : public std::filesystem::directory_iterator +{ + using directory_iterator = std::filesystem::directory_iterator; + regular_file_only_iterator& find_first() + { + while (((*this) != directory_iterator{}) && !is_regular_file((**this).status())) + this->directory_iterator::operator++(); + return (*this); + } +public: + regular_file_only_iterator() = default; + + template + regular_file_only_iterator(Arg&& arg, Args&&... args) : directory_iterator(std::forward(arg), std::forward(args)...) + { + find_first(); + } + + regular_file_only_iterator& operator++() + { + this->directory_iterator::operator++(); + return find_first(); + } +}; + +inline regular_file_only_iterator begin(regular_file_only_iterator iter) noexcept +{ + return iter; +} + +inline regular_file_only_iterator end(const regular_file_only_iterator&) noexcept +{ + return{}; +} + +std::string pretty_file_size(const std::filesystem::path& path); + +std::string pretty_file_date(const std::filesystem::path& path); + +bool modified_file_time(const std::filesystem::path& p, struct tm&); ///< extention ? + +} // filesystem_ext +} // nana + +#endif //NANA_FILESYSTEM_EXT_HPP diff --git a/GUI/nana/fwd.hpp b/GUI/nana/fwd.hpp new file mode 100644 index 0000000..c3795e3 --- /dev/null +++ b/GUI/nana/fwd.hpp @@ -0,0 +1,22 @@ +/* + * Forward Declarations + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/fwd.hpp + * + */ + +#ifndef NANA_FWD_HPP +#define NANA_FWD_HPP + +namespace nana +{ + class filebox; + class msgbox; +}//end namespace nana +#endif //NANA_FWD_HPP diff --git a/GUI/nana/gui.hpp b/GUI/nana/gui.hpp new file mode 100644 index 0000000..09c2f7b --- /dev/null +++ b/GUI/nana/gui.hpp @@ -0,0 +1,54 @@ +/** + * Nana GUI Header + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/gui.hpp + * @description + * the header file contains the files required for running of Nana.GUI + */ + +#ifndef NANA_GUI_HPP +#define NANA_GUI_HPP + +#include "gui/compact.hpp" +#include "gui/screen.hpp" +#include "gui/widgets/form.hpp" +#include "gui/drawing.hpp" +#include "gui/msgbox.hpp" +#include "gui/place.hpp" + + +namespace nana +{ +#ifdef NANA_AUTOMATIC_GUI_TESTING + + /// @brief Take control of the GUI and optionally automatically tests it. + /// + /// @detail It transfers to nana the program flow control, which begin pumping messages + /// from the underlying OS, interpreting and sending it with suitable arguments + /// to the nana widgets that registered a response in the corresponding event. + /// It also accept arguments to be used in case of automatic GUI testing. + /// Other Way the arguments are ignored. + void exec( + unsigned wait = 1, ///< for the GUI to be constructed, in seconds + unsigned wait_end = 1, ///< for the GUI to be destructed, in seconds + std::function = {} ///< emit events to mimics user actions and may assert results + ); + + /// send a click message to this widget - useful in GUI testing + void click(widget& w); + + /// in seconds + void Wait(unsigned wait = 0); +#else + void exec(); +#endif + + +}//end namespace nana +#endif diff --git a/GUI/nana/gui/animation.hpp b/GUI/nana/gui/animation.hpp new file mode 100644 index 0000000..f908344 --- /dev/null +++ b/GUI/nana/gui/animation.hpp @@ -0,0 +1,88 @@ +/* + * An Animation Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/animation.hpp + */ + +#ifndef NANA_GUI_ANIMATION_HPP +#define NANA_GUI_ANIMATION_HPP +#include +#include + +#include +#include + + +namespace nana +{ + class animation; + /// Holds the frames and frame builders. Have reference semantics for efficiency. + class frameset + { + friend class animation; + public: + /// function which builds frames. + using framebuilder = std::function; + public: + frameset(); + void push_back(paint::image); ///< Inserts frames at the end. + void push_back(framebuilder fb, std::size_t length); ///< Inserts a framebuilder and the number of frames that it generates. + private: + struct impl; + std::shared_ptr impl_; + }; + /// Easy way to display an animation or create an animated GUI + class animation + { + struct branch_t + { + frameset frames; + std::function condition; + }; + + struct impl; + class performance_manager; + + /// Non-copyable + animation(const animation&) = delete; + animation& operator=(const animation&) = delete; + public: + animation(std::size_t fps = 23); + ~animation(); + + animation(animation&&); + animation& operator=(animation&&); + + void push_back(frameset frms); + + void looped(bool enable); ///< Enables or disables the animation repeating playback. + + void play(); + + void pause(); + + /// Renders the animation at a fixed position + void output(window wd, const nana::point& pos); + + /// Renders the animation at a rectangle + /** + * If the size of rectangle is not equal to the size of frame, it stretches the frame for the size of rectangle. + * @param wd Output window. + * @param r Generator of the rectangle. The generator gets called every time rendering occurs. + */ + void output(window wd, std::function r); + + void fps(std::size_t n); + std::size_t fps() const; + private: + std::unique_ptr impl_; + }; +} //end namespace nana +#include +#endif //NANA_GUI_ANIMATION_HPP diff --git a/GUI/nana/gui/basis.hpp b/GUI/nana/gui/basis.hpp new file mode 100644 index 0000000..d9b94de --- /dev/null +++ b/GUI/nana/gui/basis.hpp @@ -0,0 +1,337 @@ +/** + * \file basis.hpp + * \brief This file provides basis class and data structures required by the GUI + * + * Basis Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#ifndef NANA_GUI_BASIS_HPP +#define NANA_GUI_BASIS_HPP + +#include + +#include "../basic_types.hpp" +#include "../traits.hpp" //metacomp::fixed_type_set + +namespace nana +{ + namespace detail + { + struct basic_window; + + struct native_window_handle_impl; + struct native_drawable_impl; + struct event_handle_impl; + } + + struct accel_key + { + char key{ '\0' }; + bool case_sensitive{ false }; + bool alt{ false }; + bool ctrl{ false }; + bool shift{ false }; + }; + + enum class checkstate + { + unchecked, checked, partial + }; + + enum class window_border + { + none, + left, right, top, bottom, + top_left, top_right, bottom_left, bottom_right + }; + + enum class window_relationship + { + owner, ///< Owner window. + parent, ///< Parent window. + either_po ///< One between owner and parent. + }; + + enum class bground_mode + { + none, + basic, + blend + }; + + enum class dragdrop_status + { + not_ready, + ready, + in_progress + }; + + namespace category + { + enum class flags + { + super, + widget = 0x1, + lite_widget = 0x3, + root = 0x5 + }; + //wait for constexpr + struct widget_tag{ static const flags value = flags::widget; }; + struct lite_widget_tag : public widget_tag{ static const flags value = flags::lite_widget; }; + struct root_tag : public widget_tag{ static const flags value = flags::root; }; + }// end namespace category + + using window = detail::basic_window*; ///< The window handle type representing nana window objects + using native_window_type = detail::native_window_handle_impl*; ///< The native window handle type representing system native windows. E.g, HWND in windows, Window in X11 + + using event_handle = detail::event_handle_impl*; ///< The event handle type representing nana window events + using native_drawable_type = detail::native_drawable_impl*; ///< The drawable handle type representing system native drawable objects. E.g. HDC in windows, Drawable in X11 + + + struct keyboard + { + enum{ + //Control Code for ASCII + start_of_headline = 0x1, //Ctrl+A + end_of_text = 0x3, //Ctrl+C + backspace = 0x8, tab = 0x9, + alt = 0x12, + enter_n = 0xA, enter = 0xD, enter_r = 0xD, + sync_idel = 0x16, //Ctrl+V + cancel = 0x18, //Ctrl+X + end_of_medium = 0x19, //Ctrl+Y + substitute = 0x1A, //Ctrl+Z + escape = 0x1B, + space = 0x20, //Space + del = 0x7F, //Delete + os_del = del, //Deprecated + + //The following names are intuitive name of ASCII control codes + select_all = start_of_headline, + copy = end_of_text, + paste = sync_idel, + cut = cancel, + redo = end_of_medium, + undo = substitute, + + //System Code for OS + os_tab = 0x09, + os_shift = 0x10, + os_ctrl = 0x11, + os_pageup = 0x21, os_pagedown, + os_arrow_left = 0x25, os_arrow_up, os_arrow_right, os_arrow_down, + os_insert = 0x2D, + os_end = 0x23, os_home //Pos 1 + }; + }; + + enum class cursor + { + hand = 60, ///< displays a hand to indicate a text or an element is clickable + arrow = 68, ///< the default shape + wait = 150, ///< indicates the system is currently busy + iterm = 152, ///< A text caret. Displays a caret to indicate the UI is input able + size_we = 108, + size_ns = 116, + size_top_left = 134, + size_top_right = 136, + size_bottom_left = 12, + size_bottom_right = 14 + }; + + enum class mouse + { + any_button, + left_button, + middle_button, + right_button + }; + + enum class z_order_action + { + none, + bottom, ///< brings a window at the bottom of z-order. + top, ///< brings a widget at the top of the z-order. + topmost, ///< brings a window at the top of the z-order and stays here. + foreground ///< brings a window to the foreground. + }; + + /// Window appearance structure defined to specify the appearance of a form + struct appearance + { + bool taskbar; + bool floating; + bool no_activate; + + bool minimize; + bool maximize; + bool sizable; + + bool decoration; + + appearance(); + appearance(bool has_decoration, bool taskbar, bool floating, bool no_activate, bool min, bool max, bool sizable); + }; + + +/** @brief Provided to generate an appearance object with better readability and understandability + +A window has an appearance. This appearance can be specified when a window is being created. +To determine the appearance of a window there is a structure named nana::appearance with +a bool member for each feature with can be included or excluded in the "appearance" of the windows form. +But in practical development is hard to describe the style of the appearance using the struct nana::appearance. +If a form would to be defined without min/max button and sizable border, then + +\code{.CPP} + nana::form form(x, y, width, height, nana::appearance(false, false, false, true, false)); +\endcode + +This piece of code may be confusing because of the 5 parameters of the constructor of `nana::form`. So the library provides a helper class for making it easy. +For better readability and understandability Nana provides three templates classes to generate an appearance object: +nana::appear::decorate, nana::appear::bald and nana::appear::optional. Each provide an operator +that return a corresponding nana::appearance with predefined values. +*/ + struct appear + { + struct minimize{}; + struct maximize{}; + struct sizable{}; + struct taskbar{}; + struct floating{}; + struct no_activate{}; + + /** @brief Create an appearance of a window with "decoration" in non-client area, such as title bar + * + * We can create a form without min/max button and sizable border like this: + * \code{.CPP} + * using nana::appear; + * nana::form form(x, y, width, height, appear::decorate()); + * \endcode + * The appearance created by appear::decorate<>() has a titlebar and borders that are draw by the + * platform- window manager. If a window needs a minimize button, it should be: + * \code{.CPP} + * appear::decorate() + * \endcode + */ + template< typename Minimize = null_type, + typename Maximize = null_type, + typename Sizable = null_type, + typename Floating = null_type, + typename NoActive = null_type> + struct decorate + { + typedef meta::fixed_type_set set_type; + + operator appearance() const + { + return appearance( true, true, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value + ); + } + }; + + /// Create an appearance of a window without "decoration" with no titlebar and no 3D-look borders. + template < typename Taskbar = null_type, + typename Floating = null_type, + typename NoActive = null_type, + typename Minimize = null_type, + typename Maximize = null_type, + typename Sizable = null_type> + struct bald + { + typedef meta::fixed_type_set set_type; + + operator appearance() const + { + return appearance( false, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value + ); + } + }; + /// Create a window with decoration depending on the first non-type template parameter + template < bool HasDecoration = true, + typename Sizable = null_type, + typename Taskbar = null_type, + typename Floating = null_type, + typename NoActive = null_type> + struct optional + { + typedef meta::fixed_type_set set_type; + + operator appearance() const + { + return appearance(HasDecoration, + set_type::template count::value, + set_type::template count::value, + set_type::template count::value, + true, true, + set_type::template count::value); + } + }; + };//end namespace appear + + /// Interface for caret operations + class caret_interface + { + public: + virtual ~caret_interface() = default; + + virtual bool activated() const = 0; + virtual void disable_throw() noexcept = 0; + + virtual void effective_range(const rectangle& range) = 0; + + virtual void position(const point& pos) = 0; + virtual point position() const = 0; + + virtual void dimension(const size& size) = 0; + virtual size dimension() const = 0; + + virtual void visible(bool visibility) = 0; + virtual bool visible() const = 0; + };//end class caret_interface + + /// Interface for scroll operations + /** + * This interface provides methods to operate the scrollbars that are contained + * in a specific widget, such as listbox and treebox + */ + class scroll_operation_interface + { + public: + virtual ~scroll_operation_interface() = default; + + virtual bool visible(bool vert) const = 0; + }; + + namespace parameters + { + /// The system-wide parameters for mouse wheel + struct mouse_wheel + { + unsigned lines; ///< The number of lines to scroll when the vertical mouse wheel is moved. + unsigned characters; ///< The number of characters to scroll when the horizontal mouse wheel is moved. + + mouse_wheel(); + }; + } +}//end namespace nana + +#include +#endif diff --git a/GUI/nana/gui/compact.hpp b/GUI/nana/gui/compact.hpp new file mode 100644 index 0000000..c4a9789 --- /dev/null +++ b/GUI/nana/gui/compact.hpp @@ -0,0 +1,57 @@ +/** + * Nana GUI Library Definition + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/gui/compact.hpp + * @description + * the header file contains the files required for running of Nana.GUI + */ + +#ifndef NANA_GUI_WVL_HPP +#define NANA_GUI_WVL_HPP + +#include "programming_interface.hpp" + +namespace nana +{ + namespace detail + { + struct form_loader_private + { + template friend class form_loader; + private: + static void insert_form(::nana::widget*); + }; + + template + class form_loader + { + public: + template + Form & operator()(Args &&... args) const + { + auto p = new Form(std::forward(args)...); + + if (p->empty()) + throw std::runtime_error("form_loader failed to create the form"); + + + detail::form_loader_private::insert_form(p); + if (IsVisible) + p->show(); + + return *p; + } + + }; + } + + template + using form_loader = detail::form_loader; +}//end namespace nana +#endif diff --git a/GUI/nana/gui/detail/bedrock.hpp b/GUI/nana/gui/detail/bedrock.hpp new file mode 100644 index 0000000..834431a --- /dev/null +++ b/GUI/nana/gui/detail/bedrock.hpp @@ -0,0 +1,129 @@ +/** + * A Bedrock Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/gui/detail/bedrock.hpp + * + * @brief A Bedrock Implementation + */ + +#ifndef NANA_GUI_DETAIL_BEDROCK_HPP +#define NANA_GUI_DETAIL_BEDROCK_HPP +#include "general_events.hpp" +#include "color_schemes.hpp" + +namespace nana +{ +namespace detail +{ + class element_store; + + class events_operation; + struct basic_window; + class window_manager; + + struct window_platform_assoc; + + /// @brief fundamental core component, it provides an abstraction to the OS platform and some basic functions. + class bedrock + { + bedrock(); + + bedrock(const bedrock&) = delete; + bedrock& operator=(const bedrock&) = delete; + public: + struct thread_context; + + class flag_guard; + + /// RAII class for window message processing + class root_guard + { + public: + /// Enables lazy_update + root_guard(bedrock& brock, basic_window* root_wd); + + /// Disables lazy-update and clears update requesters queue. + ~root_guard(); + private: + bedrock& brock_; + basic_window* const root_wd_; + }; + + ~bedrock(); + void pump_event(window, bool is_modal); + void flush_surface(basic_window*, bool forced, const rectangle* update_area = nullptr); + static int inc_window(thread_t tid = 0); + thread_context* open_thread_context(thread_t tid = 0); + thread_context* get_thread_context(thread_t tid = 0); + void remove_thread_context(thread_t tid = 0); + static bedrock& instance(); + + basic_window* focus(); + + void set_menubar_taken(basic_window*); + + //Delay Restores focus when a menu which attached to menubar is closed + void delay_restore(int); + bool close_menu_if_focus_other_window(native_window_type focus); + void set_menu(native_window_type menu_window, bool is_keyboard_condition); + native_window_type get_menu(native_window_type owner, bool is_keyboard_condition); + native_window_type get_menu(); + void erase_menu(bool try_destroy); + + void get_key_state(arg_keyboard&); + + bool shortkey_occurred(bool status); + bool shortkey_occurred() const; + + element_store& get_element_store() const; + void map_through_widgets(basic_window*, native_drawable_type); + + //Closes the windows which are associated with the specified thread. If the given thread_id is 0, it closes all windows + void close_thread_window(thread_t thread_id); + + public: + //Platform-dependent functions + static void delete_platform_assoc(window_platform_assoc*); + void keyboard_accelerator(native_window_type, const accel_key&, const std::function&); + public: + void event_expose(basic_window *, bool exposed); + void event_move(basic_window*, int x, int y); + bool event_msleave(basic_window*); + void event_focus_changed(basic_window* root_wd, native_window_type receiver, bool getting); + void thread_context_destroy(basic_window*); + void thread_context_lazy_refresh(); + void update_cursor(basic_window*); + void set_cursor(basic_window*, nana::cursor, thread_context*); + void define_state_cursor(basic_window*, nana::cursor, thread_context*); + void undefine_state_cursor(basic_window*, thread_context*); + + color_schemes& scheme(); + events_operation& evt_operation(); + window_manager& wd_manager(); + + void manage_form_loader(basic_window*, bool insert_or_remove); + public: + // if 'bForce__EmitInternal', then ONLY internal (widget's) events are processed (even through explicit filtering) + bool emit(event_code, basic_window*, const event_arg&, bool ask_update, thread_context*, const bool bForce__EmitInternal = false); + private: + void _m_emit_core(event_code, basic_window*, bool draw_only, const event_arg&, const bool bForce__EmitInternal); + void _m_event_filter(event_code, basic_window*, thread_context*); + private: + static bedrock bedrock_object; + + struct pi_data; + pi_data* pi_data_; + struct private_impl; + private_impl *impl_; + };//end class bedrock +}//end namespace detail +}//end namespace nana + +#endif + diff --git a/GUI/nana/gui/detail/color_schemes.hpp b/GUI/nana/gui/detail/color_schemes.hpp new file mode 100644 index 0000000..79e0977 --- /dev/null +++ b/GUI/nana/gui/detail/color_schemes.hpp @@ -0,0 +1,80 @@ +/* +* Color Schemes +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/color_schemes.hpp +* @description: +*/ +#ifndef NANA_DETAIL_COLOR_SCHEMES_HPP +#define NANA_DETAIL_COLOR_SCHEMES_HPP + +#include "widget_geometrics.hpp" + +namespace nana +{ + namespace detail + { + class scheme_factory_interface + { + public: + struct factory_identifier{}; + virtual ~scheme_factory_interface() = default; + + virtual factory_identifier* get_id() const = 0; + virtual widget_geometrics* create() = 0; + virtual widget_geometrics* create(widget_geometrics&) = 0; + }; + + + template + class scheme_factory + : public scheme_factory_interface + { + private: + factory_identifier* get_id() const override + { + return &fid_; + } + + widget_geometrics* create() override + { + return (new Scheme); + } + + widget_geometrics* create(widget_geometrics& other) override + { + return (new Scheme(static_cast(other))); + } + private: + static factory_identifier fid_; + }; + + template + scheme_factory_interface::factory_identifier scheme_factory::fid_; + + class color_schemes + { + struct implement; + color_schemes(const color_schemes&) = delete; + color_schemes(color_schemes&&) = delete; + color_schemes& operator=(const color_schemes&) = delete; + color_schemes& operator=(color_schemes&&) = delete; + public: + using scheme = widget_geometrics; + + color_schemes(); + ~color_schemes(); + + scheme& scheme_template(scheme_factory_interface&&); + scheme* create(scheme_factory_interface&&); + private: + implement * impl_; + }; + }//end namespace detail; +}//end namespace nana +#endif \ No newline at end of file diff --git a/GUI/nana/gui/detail/drawer.hpp b/GUI/nana/gui/detail/drawer.hpp new file mode 100644 index 0000000..ce7ade4 --- /dev/null +++ b/GUI/nana/gui/detail/drawer.hpp @@ -0,0 +1,204 @@ +/* + * A Drawer Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/detail/drawer.hpp + */ + +#ifndef NANA_GUI_DETAIL_DRAWER_HPP +#define NANA_GUI_DETAIL_DRAWER_HPP + +#include +#include "general_events.hpp" +#include +#include +#include + +namespace nana +{ + class widget; + + namespace detail + { + class drawer; + } + + class drawer_trigger; + class event_filter_status + { + public: + event_filter_status(); + event_filter_status(const event_filter_status& rOther); + event_filter_status(const unsigned evt_disabled_); + const event_filter_status& operator=(const event_filter_status& rOther); + const event_filter_status& operator=(const unsigned evt_disabled_); + + bool operator[](const nana::event_code evt_code) const; + bool operator==(const event_filter_status& rOther) const; + bool operator!=(const event_filter_status& rOther) const; + + private: + unsigned evt_disabled_; + friend class drawer_trigger; + }; + + class drawer_trigger + { + friend class detail::drawer; + + //Noncopyable + drawer_trigger(const drawer_trigger&) = delete; + drawer_trigger& operator=(const drawer_trigger&) = delete; + + //Nonmovable + drawer_trigger(drawer_trigger&&) = delete; + drawer_trigger& operator=(drawer_trigger&&) = delete; + + public: + using widget_reference = widget&; + using graph_reference = paint::graphics&; + + drawer_trigger() = default; + virtual ~drawer_trigger() = default; + virtual void attached(widget_reference, graph_reference); //none-const + virtual void detached(); //none-const + + virtual void typeface_changed(graph_reference); + virtual void refresh(graph_reference); + + virtual void resizing(graph_reference, const arg_resizing&); + virtual void resized(graph_reference, const arg_resized&); + virtual void move(graph_reference, const arg_move&); + virtual void click(graph_reference, const arg_click&); + virtual void dbl_click(graph_reference, const arg_mouse&); + virtual void mouse_enter(graph_reference, const arg_mouse&); + virtual void mouse_move(graph_reference, const arg_mouse&); + virtual void mouse_leave(graph_reference, const arg_mouse&); + virtual void mouse_down(graph_reference, const arg_mouse&); + virtual void mouse_up(graph_reference, const arg_mouse&); + virtual void mouse_wheel(graph_reference, const arg_wheel&); + virtual void mouse_dropfiles(graph_reference, const arg_dropfiles&); + + virtual void focus(graph_reference, const arg_focus&); + virtual void key_ime(graph_reference, const arg_ime&); + virtual void key_press(graph_reference, const arg_keyboard&); + virtual void key_char(graph_reference, const arg_keyboard&); + virtual void key_release(graph_reference, const arg_keyboard&); + virtual void shortkey(graph_reference, const arg_keyboard&); + + void filter_event(const event_code evt_code, const bool bDisabled); + void filter_event(const std::vector& evt_codes, const bool bDisabled); + void filter_event(const event_filter_status& evt_all_states); + bool filter_event(const event_code evt_code); + event_filter_status filter_event(); + void clear_filter(); + + private: + void _m_reset_overridden(); + bool _m_overridden(event_code) const; + private: + unsigned overridden_{ 0xFFFFFFFF }; + unsigned evt_disabled_{ 0 }; // bit set if event is filtered + }; + + namespace detail + { + struct basic_window; + + //@brief: Every window has a drawer, the drawer holds a drawer_trigger for + // a widget. + class drawer + : nana::noncopyable, nana::nonmovable + { + enum class method_state + { + pending, + overridden, + not_overridden + }; + public: + drawer(); + ~drawer(); + + void bind(basic_window*); + + void typeface_changed(); + void click(const arg_click&, const bool); + void dbl_click(const arg_mouse&, const bool); + void mouse_enter(const arg_mouse&, const bool); + void mouse_move(const arg_mouse&, const bool); + void mouse_leave(const arg_mouse&, const bool); + void mouse_down(const arg_mouse&, const bool); + void mouse_up(const arg_mouse&, const bool); + void mouse_wheel(const arg_wheel&, const bool); + void mouse_dropfiles(const arg_dropfiles&, const bool); + void resizing(const arg_resizing&, const bool); + void resized(const arg_resized&, const bool); + void move(const arg_move&, const bool); + void focus(const arg_focus&, const bool); + void key_ime(const arg_ime& arg, const bool bForce__EmitInternal); + void key_press(const arg_keyboard&, const bool); + void key_char(const arg_keyboard&, const bool); + void key_release(const arg_keyboard&, const bool); + void shortkey(const arg_keyboard&, const bool); + void map(window, bool forced, const rectangle* update_area = nullptr); //Copy the root buffer to screen + void refresh(); + drawer_trigger* realizer() const; + void attached(widget&, drawer_trigger&); + drawer_trigger* detached(); + public: + void clear(); + void* draw(std::function &&, bool diehard); + void erase(void* diehard); + private: + void _m_effect_bground_subsequent(); + method_state& _m_mth_state(int pos); + + template + void _m_emit(event_code evt_code, const Arg& arg, Mfptr mfptr, const bool bForce__EmitInternal) + { + const int pos = static_cast(evt_code); + + auto realizer = this->realizer(); + auto & mth_state = _m_mth_state(pos); + + if (realizer && (method_state::not_overridden != mth_state)) + { + const bool bFiltered = !bForce__EmitInternal && realizer->filter_event(evt_code); + if (method_state::pending == mth_state) + { + if (!bFiltered) + (realizer->*mfptr)(graphics, arg); + + //Check realizer, when the window is closed in that event handler, the drawer will be + //detached and realizer will be a nullptr + if (realizer) + mth_state = (realizer->_m_overridden(evt_code) ? method_state::overridden : method_state::not_overridden); + } + else + { + if (!bFiltered) + (realizer->*mfptr)(graphics, arg); + } + + _m_effect_bground_subsequent(); + } + } + public: + nana::paint::graphics graphics; + private: + struct data_implement; + + data_implement * const data_impl_; + }; + }//end namespace detail +}//end namespace nana + +#include + +#endif diff --git a/GUI/nana/gui/detail/element_store.hpp b/GUI/nana/gui/detail/element_store.hpp new file mode 100644 index 0000000..72df9fb --- /dev/null +++ b/GUI/nana/gui/detail/element_store.hpp @@ -0,0 +1,48 @@ +/* +* The Store for the Storage Of Elements +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/detail/element_store.hpp +*/ + +#ifndef NANA_GUI_DETAIL_ELEMENT_STORE_HPP +#define NANA_GUI_DETAIL_ELEMENT_STORE_HPP + +#include +#include + +#include +#include + + +namespace nana +{ +namespace detail +{ + class element_store + { + using element_interface = ::nana::element::element_interface; + using cloneable_element = pat::cloneable< ::nana::element::element_interface>; + + struct data; + public: + element_store(); + ~element_store(); + + element_interface * const * bground(const std::string&); + void bground(const std::string&, const pat::cloneable&); + void bground(const std::string&, pat::cloneable&&); + private: + struct implementation; + std::unique_ptr impl_; + }; +}//end namespace detail +} +#include + +#endif diff --git a/GUI/nana/gui/detail/event_code.hpp b/GUI/nana/gui/detail/event_code.hpp new file mode 100644 index 0000000..a9802e4 --- /dev/null +++ b/GUI/nana/gui/detail/event_code.hpp @@ -0,0 +1,49 @@ +/* +* Definitions of General Events Code +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/detail/event_code.hpp +* +*/ + +#ifndef NANA_DETAIL_EVENT_CODE_HPP +#define NANA_DETAIL_EVENT_CODE_HPP + +namespace nana +{ + enum class event_code + { + click, ///< A mouse click event. + dbl_click, ///< A mouse double click event. + mouse_enter, ///< A mouse enters a widget. + mouse_move, ///< A mouse moves over a widget. + mouse_leave, ///< A mouse leaves a widget. + mouse_down, ///< A mouse button is pressed on a widget. + mouse_up, ///< A mouse button is released on a widget. + mouse_wheel, ///< A mouse scrolls the wheel on a widget. + mouse_drop, ///< A mouse release over a window that is registered as recipient of drag and drop. + expose, ///< + resizing, ///< A widget's size is sizing. In this event, A widget's size can be overridden with a new size. + resized, ///< A widget's size is changing. + move, ///< + unload, ///< A form is closed by clicking the X button, only works for root widget. + destroy, ///< A widget is about to be destroyed. + focus, ///< A widget's focus is changed. + key_ime, + key_press, ///< A keyboard is pressed on a focus widget. + key_char, ///< The focus widget received a character. + key_release, ///< A keyboard is released on a focus widget. + shortkey, ///< The widgets received a shortkey message. + + elapse, ///< Unoperational events? . A widget received a tick that is sended by timer. + + end ///< End indicator, it's not an event. + }; +}//end namespace nana + +#endif \ No newline at end of file diff --git a/GUI/nana/gui/detail/events_holder.hpp b/GUI/nana/gui/detail/events_holder.hpp new file mode 100644 index 0000000..23b5aae --- /dev/null +++ b/GUI/nana/gui/detail/events_holder.hpp @@ -0,0 +1,20 @@ +#ifndef NANA_DETAIL_EVENTS_HOLDER_HPP +#define NANA_DETAIL_EVENTS_HOLDER_HPP +#include + +namespace nana +{ + struct general_events; + + namespace detail + { + class events_holder + { + public: + virtual ~events_holder(){} + virtual bool set_events(const std::shared_ptr&) = 0; + virtual general_events* get_events() const = 0; + }; + }//end namespace detail +}//end namespace nana +#endif diff --git a/GUI/nana/gui/detail/events_operation.hpp b/GUI/nana/gui/detail/events_operation.hpp new file mode 100644 index 0000000..e28b9af --- /dev/null +++ b/GUI/nana/gui/detail/events_operation.hpp @@ -0,0 +1,30 @@ +#ifndef NANA_DETAIL_EVENTS_OPERATION_HPP +#define NANA_DETAIL_EVENTS_OPERATION_HPP + +#include +#include + +#if defined(STD_THREAD_NOT_SUPPORTED) +#include +#else +#include +#endif + +namespace nana +{ + namespace detail + { + class events_operation + { + public: + void register_evt(event_handle); + void cancel(event_handle); + void erase(event_handle); + private: + std::recursive_mutex mutex_; + std::unordered_set handles_; + }; + }//end namespace detail +}//end namespace nana + +#endif diff --git a/GUI/nana/gui/detail/general_events.hpp b/GUI/nana/gui/detail/general_events.hpp new file mode 100644 index 0000000..d8b81c7 --- /dev/null +++ b/GUI/nana/gui/detail/general_events.hpp @@ -0,0 +1,571 @@ +/** +* Definition of General Events +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/detail/general_events.hpp +*/ +#ifndef NANA_DETAIL_GENERAL_EVENTS_HPP +#define NANA_DETAIL_GENERAL_EVENTS_HPP + +#include + +#include +#include "event_code.hpp" +#include "internal_scope_guard.hpp" +#include "../../filesystem/filesystem.hpp" +#include +#include +#include + +namespace nana +{ + namespace API + { + bool is_window(window); ///< Determines whether a window is existing, equal to !empty_window. + } + + namespace detail + { + void events_operation_register(event_handle); + + class event_interface + { + public: + virtual ~event_interface() = default; + virtual void remove(event_handle) = 0; + }; + + class event_docker_interface + { + public: + virtual ~event_docker_interface() = default; + virtual event_interface* get_event() const = 0; + }; + + + struct docker_base + : public event_docker_interface + { + event_interface * const event_ptr; + bool flag_deleted; + const bool unignorable; + + docker_base(event_interface*, bool unignorable_flag); + detail::event_interface * get_event() const override; + }; + + class event_base + : public detail::event_interface + { + public: + ~event_base(); + + std::size_t length() const; + void clear() noexcept; + + void remove(event_handle evt) override; + protected: + //class emit_counter is a RAII helper for emitting count + //It is used for avoiding a try{}catch block which is required for some finial works when + //event handlers throw exceptions. Precondition event_base.dockers_ != nullptr. + class emit_counter + { + public: + emit_counter(event_base*); + ~emit_counter(); + private: + event_base * const evt_; + }; + + event_handle _m_emplace(detail::event_docker_interface*, bool in_front); + protected: + unsigned emitting_count_{ 0 }; + bool deleted_flags_{ false }; + std::vector * dockers_{ nullptr }; + }; + }//end namespace detail + + /// base class for all event argument types + class event_arg + { + public: + virtual ~event_arg() = default; + + /// ignorable handlers behind the current one in a chain of event handlers will not get called. + void stop_propagation() const; + bool propagation_stopped() const; + private: + mutable bool stop_propagation_{ false }; + }; + + struct general_events; + + /** @brief the type of the members of general_events. + * + * It connect the functions to be called as response to the event and manages that chain of responses + * It is a functor, that get called to connect a "normal" response function, with normal "priority". + * If a response function need another priority (unignorable or called first) it will need to be connected with + * the specific connect function not with the operator() + * It also permit to "emit" that event, calling all the active responders. + */ + template + class basic_event : public detail::event_base + { + public: + using arg_reference = const typename std::remove_reference::type &; + private: + struct docker + : public detail::docker_base + { + /// the callback/response function taking the typed argument + std::function invoke; + + docker(basic_event * evt, std::function && ivk, bool unignorable_flag) + : docker_base(evt, unignorable_flag), invoke(std::move(ivk)) + {} + + docker(basic_event * evt, const std::function & ivk, bool unignorable_flag) + : docker_base(evt, unignorable_flag), invoke(ivk) + {} + }; + public: + /// Creates an event handler at the beginning of event chain + template + event_handle connect_front(Function && fn) + { +#ifdef __cpp_if_constexpr + if constexpr(std::is_invocable_v) + { + return _m_emplace(new docker{ this, fn, false }, true); + } + else if constexpr(std::is_invocable_v) + { + return _m_emplace(new docker{ this, [fn](arg_reference) { + fn(); + }, false }, true); + } +#else + using prototype = typename std::remove_reference::type; + return _m_emplace(new docker(this, factory::value>::build(std::forward(fn)), false), true); +#endif + } + +#ifndef __cpp_if_constexpr + /// It will not get called if stop_propagation() was called. + event_handle connect(void (*fn)(arg_reference)) + { + return connect([fn](arg_reference arg){ + fn(arg); + }); + } +#endif + + /// It will not get called if stop_propagation() was called, because it is set at the end of the chain.. + template + event_handle connect(Function && fn) + { +#ifdef __cpp_if_constexpr + if constexpr(std::is_invocable_v) + { + return _m_emplace(new docker{ this, fn, false }, false); + } + else if constexpr(std::is_invocable_v) + { + return _m_emplace(new docker{ this, [fn](arg_reference) mutable{ + fn(); + }, false }, false); + } +#else + using prototype = typename std::remove_reference::type; + return _m_emplace(new docker(this, factory::value>::build(std::forward(fn)), false), false); +#endif + } + + /// It will not get called if stop_propagation() was called. + template + event_handle operator()(Function&& fn) + { + return connect(std::forward(fn)); + } + + /// It will get called because it is unignorable. + template + event_handle connect_unignorable(Function && fn, bool in_front = false) + { +#ifdef __cpp_if_constexpr + if constexpr(std::is_invocable_v) + { + return _m_emplace(new docker{ this, fn, true }, in_front); + } + else if constexpr(std::is_invocable_v) + { + return _m_emplace(new docker{ this, [fn](arg_reference) mutable{ + fn(); + }, true }, in_front); + } +#else + using prototype = typename std::remove_reference::type; + return _m_emplace(new docker(this, factory::value>::build(std::forward(fn)), true), in_front); +#endif + } + + void emit(arg_reference& arg, window window_handle) + { + internal_scope_guard lock; + if (nullptr == dockers_) + return; + + emit_counter ec(this); + + //The dockers may resize when a new event handler is created by a calling handler. + //Traverses with position can avaid crash error which caused by a iterator which becomes invalid. + for (std::size_t i = 0; i < dockers_->size(); ++i) + { + auto d = static_cast(dockers_->data()[i]); + if (d->flag_deleted || (arg.propagation_stopped() && !d->unignorable)) + continue; + + d->invoke(arg); + + if (window_handle && (!::nana::API::is_window(window_handle))) + break; + } + } + private: + +#ifndef __cpp_if_constexpr + template + struct factory + { + static std::function build(Fn && fn) + { + return std::move(fn); + } + + static std::function build(const Fn & fn) + { + return fn; + } + }; + + template + struct factory + { + typedef typename std::remove_reference::type arg_type; + typedef typename std::remove_reference::type fn_type; + + template + static std::function build(Tfn && fn) + { + typedef typename std::remove_reference::type type; + return build_second(std::forward(fn), &type::operator()); + } + + template + static std::function build_second(Tfn&& fn, Ret(fn_type::*)()) + { + return [fn](arg_reference) mutable + { + fn(); + }; + } + + template + static std::function build_second(Tfn&& fn, Ret(fn_type::*)()const) + { + return [fn](arg_reference) mutable + { + fn(); + }; + } + + template + static std::function build_second(Tfn&& fn, Ret(fn_type::*)(arg_reference)) + { + return std::forward(fn); + } + + template + static std::function build_second(Tfn&& fn, Ret(fn_type::*)(arg_reference)const) + { + return std::forward(fn); + } + + template + static std::function build_second(Tfn&& fn, Ret(fn_type::*)(Arg2)) + { + static_assert(std::is_convertible::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function."); + return[fn](arg_reference arg) mutable + { + fn(arg); + }; + } + + template + static std::function build_second(Tfn&& fn, Ret(fn_type::*)(Arg2)const) + { + static_assert(std::is_convertible::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function."); + return [fn](arg_reference arg) mutable + { + fn(arg); + }; + } + }; + + template + struct factory < std::function, false> + { + typedef typename std::remove_reference::type arg_type; + static_assert(std::is_convertible::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function."); + + static std::function build(const std::function& fn) + { + return [fn](arg_reference arg) mutable{ + fn(arg); + }; + } + + static std::function build_second(std::function && fn) + { + return std::move(fn); + } + }; + + template + struct factory < std::function, false> + { + static std::function build(const std::function& fn) + { + return[fn](arg_reference) mutable{ + fn(); + }; + } + }; + + template + struct factory < Ret(*)(), false> + { + static std::function build(Ret(*fn)()) + { + return[fn](arg_reference) mutable{ + fn(); + }; + } + }; + + template + struct factory < Ret(*)(Arg2), false> + { + typedef typename std::remove_reference::type arg_type; + static_assert(std::is_convertible::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function."); + + static std::function build(Ret(*fn)(Arg2)) + { + return[fn](arg_reference arg) mutable { + fn(arg); + }; + } + }; + + template + struct factory < Ret(), false> + { + static std::function build(Ret(*fn)()) + { + return[fn](arg_reference){ + fn(); + }; + } + }; + + template + struct factory < Ret(Arg2), false> + { + typedef typename std::remove_reference::type arg_type; + static_assert(std::is_convertible::value, "The parameter type is not allowed, please check the function parameter type where you connected the event function."); + + static std::function build(Ret(*fn)(Arg2)) + { + return[fn](arg_reference arg){ + fn(arg); + }; + } + }; +#endif + }; + + struct arg_mouse + : public event_arg + { + event_code evt_code; ///< what kind of mouse event? + ::nana::window window_handle; ///< A handle to the event window + ::nana::point pos; ///< cursor position in the event window + ::nana::mouse button; ///< indicates a button which triggers the event + + bool left_button; ///< true if mouse left button is pressed + bool mid_button; ///< true if mouse middle button is pressed + bool right_button; ///< true if mouse right button is pressed + bool alt; ///< true if keyboard alt is pressed + bool shift; ///< true if keyboard Shift is pressed + bool ctrl; ///< true if keyboard Ctrl is pressed + + /// Checks if left button is operated, + bool is_left_button() const + { + return (event_code::mouse_move == evt_code ? left_button : (mouse::left_button == button)); + } + }; + + /// \brief in arg_wheel event_code is event_code::mouse_wheel + + /// The type arg_wheel is derived from arg_mouse, a handler + /// with prototype void(const arg_mouse&) can be set for mouse_wheel. + struct arg_wheel : public arg_mouse + { + enum class wheel{ + vertical, + horizontal + }; + + wheel which; ///< which wheel is rotated + bool upwards; ///< true if the wheel is rotated to the top/left, depends on which and false otherwise + unsigned distance; ///< expressed in multiples or divisions of 120 + }; + + struct arg_dropfiles : public event_arg + { + ::nana::window window_handle; ///< A handle to the event window + ::nana::point pos; ///< cursor position in the event window + std::vector files; ///< external filenames + }; + + struct arg_expose : public event_arg + { + ::nana::window window_handle; ///< A handle to the event window + bool exposed; ///< the window is visible? + }; + + struct arg_focus : public event_arg + { + /// A constant to indicate how keyboard focus emitted. + enum class reason + { + general, ///< the focus is received by OS native window manager. + tabstop, ///< the focus is received by pressing tab. + mouse_press ///< the focus is received by pressing a mouse button. + }; + + ::nana::window window_handle; ///< A handle to the event window + ::nana::native_window_type receiver; ///< it is a native window handle, and specified which window receives focus + bool getting; ///< the window received focus? + reason focus_reason; ///< determines how the widget receives keyboard focus, it is ignored when 'getting' is equal to false + }; + + struct arg_ime: public event_arg + { + enum class reason + { + composition, + result + }; + + ::nana::window window_handle; ///< A handle to the event window + reason ime_reason; + std::wstring composition_string; + }; + + struct arg_keyboard : public event_arg + { + event_code evt_code; ///< it is event_code::key_press in current event + ::nana::window window_handle; ///< A handle to the event window + mutable wchar_t key; ///< the key corresponding to the key pressed + mutable bool ignore; ///< this member is only available for key_char event, set 'true' to ignore the input. + bool alt; ///< it is set to indicate the modifier key Alt just prior to the event. + bool ctrl; ///< it is set to indicate the modifier key Ctrl just prior to the event. + bool shift; ///< it is set to indicate the modifier key Shift just prior to the event. + }; + + struct arg_move : public event_arg + { + ::nana::window window_handle; ///< A handle to the event window + int x; ///< + int y; ///< + }; + + struct arg_resized : public event_arg + { + ::nana::window window_handle; ///< A handle to the event window + unsigned width; ///< new width in pixels. + unsigned height; ///< new height in pixels. + }; + + struct arg_resizing : public event_arg + { + ::nana::window window_handle; ///< A handle to the event window + window_border border; ///< the window is being resized by moving border + mutable unsigned width; ///< new width in pixels. If it is modified, the window's width will be the modified value + mutable unsigned height; ///< new height in pixels. If it is modified, the window's height will be the modified value + }; + + struct arg_unload : public event_arg + { + ::nana::window window_handle; ///< A handle to the event window + mutable bool cancel; ///< + }; + + struct arg_destroy : public event_arg + { + ::nana::window window_handle; ///< A handle to the event window + }; + /// a higher level event argument than just mouse down + struct arg_click : public event_arg + { + ::nana::window window_handle; ///< A handle to the event window + const arg_mouse* mouse_args{}; ///< If it is not null, it refers to the mouse arguments for click event emitted by mouse, nullptr otherwise. + }; + + /// provides some fundamental events that every widget owns. + struct general_events + { + virtual ~general_events() = default; + basic_event mouse_enter; ///< the cursor enters the window + basic_event mouse_move; ///< the cursor moves on the window + basic_event mouse_leave; ///< the cursor leaves the window + basic_event mouse_down; ///< the user presses the mouse button + basic_event mouse_up; ///< the user presses the mouse button + basic_event click; ///< the window is clicked, but occurs after mouse_down and before mouse_up + basic_event dbl_click; ///< the window is double clicked + basic_event mouse_wheel; ///< the mouse wheel rotates while the window has focus + basic_event mouse_dropfiles; ///< the mouse drops some external data while the window enable accepting files + basic_event expose; ///< the visibility changes + basic_event focus; ///< the window receives or loses keyboard focus + basic_event key_press; ///< a key is pressed while the window has focus. event code is event_code::key_press + basic_event key_release; ///< a key is released while the window has focus. event code is event_code::key_release + basic_event key_char; ///< a character, whitespace or backspace is pressed. event code is event_code::key_char + basic_event shortkey; ///< a defined short key is pressed. event code is event_code::shortkey + + basic_event move; ///< the window changes position + basic_event resizing; ///< the window is changing its size + basic_event resized; ///< the window is changing its size + + basic_event destroy; ///< the window is destroyed, but occurs when all children have been destroyed + }; + + namespace detail + { + struct events_root_extension + : public general_events + { + basic_event unload; + }; + }//end namespace detail +}//end namespace nana + +#include + +#endif diff --git a/GUI/nana/gui/detail/inner_fwd.hpp b/GUI/nana/gui/detail/inner_fwd.hpp new file mode 100644 index 0000000..ffe18a5 --- /dev/null +++ b/GUI/nana/gui/detail/inner_fwd.hpp @@ -0,0 +1,24 @@ +/* +* Inner Forward Declaration +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/detail/inner_fwd.hpp +* +*/ + +#ifndef NANA_GUI_INNER_FWD_HPP +#define NANA_GUI_INNER_FWD_HPP + +#include + +namespace nana{ + namespace detail + { + } +} +#endif //NANA_GUI_INNER_FWD_HPP diff --git a/GUI/nana/gui/detail/internal_scope_guard.hpp b/GUI/nana/gui/detail/internal_scope_guard.hpp new file mode 100644 index 0000000..6ad8ae8 --- /dev/null +++ b/GUI/nana/gui/detail/internal_scope_guard.hpp @@ -0,0 +1,43 @@ +/* +* Forward Declaration of Internal Scope Guard +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/detail/internal_scope_guard.hpp +*/ +#ifndef NANA_GUI_DETAIL_INTERNAL_SCOPE_GUARD_HPP +#define NANA_GUI_DETAIL_INTERNAL_SCOPE_GUARD_HPP + +namespace nana +{ + //Implemented in bedrock + class internal_scope_guard + { + internal_scope_guard(const internal_scope_guard&) = delete; + internal_scope_guard(internal_scope_guard&&) = delete; + + internal_scope_guard& operator=(const internal_scope_guard&) = delete; + internal_scope_guard& operator=(internal_scope_guard&&) = delete; + public: + internal_scope_guard(); + ~internal_scope_guard(); + }; + + class internal_revert_guard + { + internal_revert_guard(const internal_revert_guard&) = delete; + internal_revert_guard(internal_revert_guard&&) = delete; + + internal_revert_guard& operator=(const internal_revert_guard&) = delete; + internal_revert_guard& operator=(internal_revert_guard&&) = delete; + public: + internal_revert_guard(); + ~internal_revert_guard(); + }; +} + +#endif \ No newline at end of file diff --git a/GUI/nana/gui/detail/native_window_interface.hpp b/GUI/nana/gui/detail/native_window_interface.hpp new file mode 100644 index 0000000..dac3fa9 --- /dev/null +++ b/GUI/nana/gui/detail/native_window_interface.hpp @@ -0,0 +1,109 @@ +/* + * Platform Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/detail/native_window_interface.hpp + */ + +#ifndef NANA_GUI_DETAIL_NATIVE_WINDOW_INTERFACE_HPP +#define NANA_GUI_DETAIL_NATIVE_WINDOW_INTERFACE_HPP + +#include "../basis.hpp" +#include + +#include + +namespace nana +{ +namespace detail +{ + + struct native_interface + { + struct window_result + { + native_window_type native_handle; + + unsigned width; //client size + unsigned height; //client size + + unsigned extra_width; //extra border size, it is useful in Windows, ignore in X11 always 0 + unsigned extra_height; //extra border size, it is useful in Windows, ignore in X11 always 0 + }; + + struct frame_extents + { + int left; + int right; + int top; + int bottom; + }; + + using native_string_type = ::nana::detail::native_string_type; + + //Execute a function in a thread which is associated with the specified native window. + static void affinity_execute(native_window_type, const std::function&); + + static nana::size primary_monitor_size(); + static rectangle screen_area_from_point(const point&); + static window_result create_window(native_window_type, bool nested, const rectangle&, const appearance&); + static native_window_type create_child_window(native_window_type, const rectangle&); + +#if defined(NANA_X11) + static void set_modal(native_window_type); +#endif + static void enable_dropfiles(native_window_type, bool); + static void enable_window(native_window_type, bool); + // (On Windows) The system displays the large icon in the ALT+TAB dialog box, and the small icon in the window caption. + static bool window_icon(native_window_type, const paint::image& big_icon, const paint::image& small_icon); + static void activate_owner(native_window_type); + static void activate_window(native_window_type); + static void close_window(native_window_type); + static void show_window(native_window_type, bool show, bool active); + static void restore_window(native_window_type); + static void zoom_window(native_window_type, bool ask_for_max); + static void refresh_window(native_window_type); + static bool is_window(native_window_type); + static bool is_window_visible(native_window_type); + static bool is_window_zoomed(native_window_type, bool ask_for_max); + + static nana::point window_position(native_window_type); + static void move_window(native_window_type, int x, int y); + static bool move_window(native_window_type, const rectangle&); + static void bring_top(native_window_type, bool activated); + static void set_window_z_order(native_window_type, native_window_type wd_after, z_order_action action_if_no_wd_after); + + static frame_extents window_frame_extents(native_window_type); + static bool window_size(native_window_type, const size&); + static void get_window_rect(native_window_type, rectangle&); + static void window_caption(native_window_type, const native_string_type&); + static native_string_type window_caption(native_window_type); + static void capture_window(native_window_type, bool); + static nana::point cursor_position(); + + static native_window_type get_window(native_window_type wd, window_relationship); + static native_window_type parent_window(native_window_type child, native_window_type new_parent, bool returns_previous); + //For Caret + static void caret_create(native_window_type, const ::nana::size&); + static void caret_destroy(native_window_type); + static void caret_pos(native_window_type, const ::nana::point&); + static void caret_visible(native_window_type, bool); + + static void set_focus(native_window_type); + static native_window_type get_focus_window(); + static bool calc_screen_point(native_window_type, nana::point&); + static bool calc_window_point(native_window_type, nana::point&); + + static native_window_type find_window(int x, int y); + static nana::size check_track_size(nana::size sz, unsigned extra_width, unsigned extra_height, bool true_for_max); + }; + + +}//end namespace detail +}//end namespace nana +#endif diff --git a/GUI/nana/gui/detail/widget_content_measurer_interface.hpp b/GUI/nana/gui/detail/widget_content_measurer_interface.hpp new file mode 100644 index 0000000..39e39e5 --- /dev/null +++ b/GUI/nana/gui/detail/widget_content_measurer_interface.hpp @@ -0,0 +1,48 @@ +/* +* Widget Content Measurer Interface +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/detail/widget_content_measurer_interface.hpp +*/ + +#ifndef NANA_WIDGET_CONTENT_MEASURER_INTERFACE_HEADER_INCLUDED +#define NANA_WIDGET_CONTENT_MEASURER_INTERFACE_HEADER_INCLUDED + +#include +#include +#include + +namespace nana +{ + namespace dev + { + /// An interface for measuring content of the widget + class widget_content_measurer_interface + { + public: + using graph_reference = paint::graphics&; + virtual ~widget_content_measurer_interface() = default; + + /// Measures content + /** + * @param graph The graphics for the operation. + * @param limit_pixels The number of pixels of the limited edge. If this parameter is zero, it is ignored. + * @param limit_width True if limits the width, false if limits the height. + * @return the size of content. + */ + virtual ::std::optional measure(graph_reference graph, unsigned limit_pixels, bool limit_width) const = 0; + + /// Returns the extension to the size of widget from content extent + /** + * @return the width and height of extension to the widget size. + */ + virtual size extension() const = 0; + }; + } +} +#endif diff --git a/GUI/nana/gui/detail/widget_geometrics.hpp b/GUI/nana/gui/detail/widget_geometrics.hpp new file mode 100644 index 0000000..91cdff6 --- /dev/null +++ b/GUI/nana/gui/detail/widget_geometrics.hpp @@ -0,0 +1,53 @@ +/* +* Widget Geometrics +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/widget_geometrics.hpp +* @description: +*/ +#ifndef NANA_DETAIL_WIDGET_GEOMETRICS_HPP +#define NANA_DETAIL_WIDGET_GEOMETRICS_HPP + +#include +#include +namespace nana +{ + /// a tool to share and set a color common to many uses + class color_proxy + { + public: + color_proxy(const color_proxy&); + color_proxy(color_rgb); + color_proxy(color_argb); + color_proxy(color_rgba); + color_proxy(colors); + color_proxy& operator=(const color_proxy&); + color_proxy& operator=(const ::nana::color&); + color_proxy& operator=(color_rgb); + color_proxy& operator=(color_argb); + color_proxy& operator=(color_rgba); + color_proxy& operator=(colors); + color get_color() const; + color get(const color& default_color) const; + operator color() const; + private: + std::shared_ptr color_; + };//end namespace color_proxy + + /// define common color and geometrical properties + struct widget_geometrics + { + virtual ~widget_geometrics() = default; + + color_proxy activated{ static_cast(0x60C8FD) }; + color_proxy background{colors::button_face}; + color_proxy foreground{colors::black}; + }; +} + +#endif \ No newline at end of file diff --git a/GUI/nana/gui/detail/widget_notifier_interface.hpp b/GUI/nana/gui/detail/widget_notifier_interface.hpp new file mode 100644 index 0000000..81a0a28 --- /dev/null +++ b/GUI/nana/gui/detail/widget_notifier_interface.hpp @@ -0,0 +1,39 @@ +/* + * Widget Notifier Interface + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/detail/widget_notifier_interface.hpp + */ + +#ifndef NANA_GUI_DETAIL_WIDGET_NOTIFIER_INTERFACE_HEADER +#define NANA_GUI_DETAIL_WIDGET_NOTIFIER_INTERFACE_HEADER +#include +#include + +namespace nana +{ + class widget; //forward declaration + + namespace detail + { + class widget_notifier_interface + { + public: + virtual ~widget_notifier_interface() = default; + + static std::unique_ptr get_notifier(widget*); //defined in nana/gui/widgets/widget.cpp + + virtual widget* widget_ptr() const = 0; + virtual void destroy() = 0; + virtual ::nana::detail::native_string_type caption() = 0; + virtual void caption(::nana::detail::native_string_type) = 0; + }; + } +} + +#endif \ No newline at end of file diff --git a/GUI/nana/gui/detail/window_layout.hpp b/GUI/nana/gui/detail/window_layout.hpp new file mode 100644 index 0000000..01256ce --- /dev/null +++ b/GUI/nana/gui/detail/window_layout.hpp @@ -0,0 +1,102 @@ +/* + * Window Layout Implementation + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/detail/window_layout.hpp + * + */ + +#ifndef NANA_GUI_DETAIL_WINDOW_LAYOUT_HPP +#define NANA_GUI_DETAIL_WINDOW_LAYOUT_HPP +#include + +#include +#include + +namespace nana +{ + namespace paint + { + class image; + class graphics; + } +} + +namespace nana{ +namespace detail +{ + struct basic_window; + + //class window_layout + class window_layout + { + public: + struct wd_rectangle + { + basic_window * window; + rectangle r; + }; + + enum class paint_operation { + none, + have_refreshed, + try_refresh + }; + public: + static void paint(basic_window*, paint_operation, bool request_refresh_children); + + static bool maproot(basic_window*, bool have_refreshed, bool request_refresh_children); + + static void paste_children_to_graphics(basic_window*, nana::paint::graphics& graph); + + //read_visual_rectangle + //@brief: Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget, + // the visual rectangle is a rectangular block that a window should be displayed on screen. + // The result is a rectangle that is a visible area for its ancesters. + static bool read_visual_rectangle(basic_window*, nana::rectangle& visual); + + //read_overlaps + // reads the overlaps that are overlapped a rectangular block + static bool read_overlaps(basic_window*, const nana::rectangle& vis_rect, std::vector& blocks); + + static bool enable_effects_bground(basic_window *, bool enabled); + + //make_bground + // update the glass buffer of a glass window. + static void make_bground(basic_window* const); + private: + + /// _m_paste_children + /** + * Pastes children window to the root graphics directly. just paste the visual rectangle + * @param window A handle to the window whose child windows will be pasted to the graph. + * @param has_refreshed Indicates whethere the window has been refreshed. + * @param request_refresh_children A flag indicates whether to refresh its child windows. + * @param parent_rect The child windows which are overlapped with the rectangle will be pasted + * @param graph A graphics object to which the child windows are pasted. + * @param graph_rpos The reference point to the graph. + */ + static void _m_paste_children(basic_window* window, bool has_refreshed, bool request_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos); + + static void _m_paint_glass_window(basic_window*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other); + + //Notify the windows which have brground to update their background buffer. + static void _m_notify_glasses(basic_window* const sigwd); + private: + struct data_section + { + std::vector effects_bground_windows; + }; + static data_section data_sect; + };//end class window_layout +}//end namespace detail +}//end namespace nana + +#include + +#endif //NANA_GUI_DETAIL_WINDOW_LAYOUT_HPP + diff --git a/GUI/nana/gui/detail/window_manager.hpp b/GUI/nana/gui/detail/window_manager.hpp new file mode 100644 index 0000000..8c4390d --- /dev/null +++ b/GUI/nana/gui/detail/window_manager.hpp @@ -0,0 +1,186 @@ +/** + * Window Manager Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/detail/window_manager.hpp + * + * + * destroy method destroys a window handle and the handles of its children, but it doesn't delete the handle which type is a root window + * destroy_handle method just destroys the handle which type is a root window + * + */ + +#ifndef NANA_GUI_DETAIL_WINDOW_MANAGER_HPP +#define NANA_GUI_DETAIL_WINDOW_MANAGER_HPP + +#include + +#include "event_code.hpp" +#include "inner_fwd.hpp" +#include + +namespace nana +{ + class widget; //forward declaration + namespace paint + { + class image; + class graphics; + } +} + +namespace nana{ +namespace detail +{ + class widget_notifier_interface; //forward declaration + + struct root_misc; + + class window_manager + { + class revertible_mutex + { + revertible_mutex(const revertible_mutex&) = delete; + revertible_mutex& operator=(const revertible_mutex&) = delete; + revertible_mutex(revertible_mutex&&) = delete; + revertible_mutex& operator=(revertible_mutex&&) = delete; + public: + revertible_mutex(); + ~revertible_mutex(); + + void lock(); + bool try_lock(); + void unlock(); + + void revert(); + void forward(); + private: + struct implementation; + implementation * const impl_; + }; + public: + using native_window = native_window_type; + using mutex_type = revertible_mutex; + + window_manager(); + ~window_manager(); + + std::size_t window_count() const; + mutex_type & internal_lock() const; + void all_handles(std::vector&) const; + + void event_filter(basic_window*, bool is_make, event_code); + + bool available(basic_window*); + bool available(basic_window *, basic_window*); + + basic_window* create_root(basic_window*, bool nested, rectangle, const appearance&, widget*); + basic_window* create_widget(basic_window*, const rectangle&, bool is_lite, widget*); + void close(basic_window*); + + //destroy + //@brief: Delete the window handle + void destroy(basic_window*); + + //destroy_handle + //@brief: Delete window handle, the handle type must be a root and a frame. + + // Deletes a window whose category type is a root type or a frame type. + void destroy_handle(basic_window*); + + void icon(basic_window*, const paint::image& small_icon, const paint::image& big_icon); + + bool show(basic_window* wd, bool visible); + + //find a widget window at specified position + //@param root A root window + //@param pos Position + //@param ignore_captured A flag indicates whether to ignore redirecting the result to its captured window. If this paramter is true, it returns the window at the position, if the parameter is false, it returns the captured window if the captured window don't ignore children. + basic_window* find_window(native_window_type root, const point& pos, bool ignore_captured = false); + + //move the wnd and its all children window, x and y is a relatively coordinate for wnd's parent window + bool move(basic_window*, int x, int y, bool passive); + bool move(basic_window*, const rectangle&); + + bool size(basic_window*, nana::size, bool passive, bool ask_update); + + basic_window* root(native_window_type) const; + + //Copy the root buffer that wnd specified into DeviceContext + void map(basic_window*, bool forced, const rectangle* update_area = nullptr); + + bool update(basic_window*, bool redraw, bool force, const rectangle* update_area = nullptr); + void update_requesters(basic_window* root_wd); + void refresh_tree(basic_window*); + + void do_lazy_refresh(basic_window*, bool force_copy_to_screen, bool refresh_tree = false); + + bool set_parent(basic_window* wd, basic_window* new_parent); + basic_window* set_focus(basic_window*, bool root_has_been_focused, arg_focus::reason); + + basic_window* capture_redirect(basic_window*); + + bool capture_window_entered(int root_x, int root_y, bool& prev); + basic_window * capture_window() const; + void capture_window(basic_window*, bool capture, bool ignore_children_if_captured); + + void enable_tabstop(basic_window*); + basic_window* tabstop(basic_window*, bool forward) const; //forward means move to next in logic. + + void remove_trash_handle(thread_t tid); + + bool enable_effects_bground(basic_window*, bool); + + bool calc_window_point(basic_window*, nana::point&); + + root_misc* root_runtime(native_window) const; + + bool register_shortkey(basic_window*, unsigned long key); + void unregister_shortkey(basic_window*, bool with_children); + + basic_window* find_shortkey(native_window_type, unsigned long key); + + void set_safe_place(basic_window* wd, std::function&& fn); + void call_safe_place(thread_t thread_id); + private: + void _m_disengage(basic_window*, basic_window* for_new); + void _m_destroy(basic_window*); + void _m_move_core(basic_window*, const point& delta); + void _m_shortkeys(basic_window*, bool with_chlidren, std::vector>& keys) const; + basic_window* _m_find(basic_window*, const point&); + static bool _m_effective(basic_window*, const point& root_pos); + private: + mutable mutex_type mutex_; + + struct wdm_private_impl; + wdm_private_impl * const impl_; + + struct attribute + { + struct captured + { + basic_window *window; + bool inside; + bool ignore_children; + std::vector > history; + }capture; + }attr_; + + struct menu_tag + { + native_window_type window; + native_window_type owner; + bool has_keyboard; + }menu_; + };//end class window_manager +}//end namespace detail +}//end namespace nana + +#include + +#endif diff --git a/GUI/nana/gui/dragdrop.hpp b/GUI/nana/gui/dragdrop.hpp new file mode 100644 index 0000000..16da397 --- /dev/null +++ b/GUI/nana/gui/dragdrop.hpp @@ -0,0 +1,138 @@ +/** +* Drag and Drop Implementation +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2018-2019 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/dragdrop.hpp +* @author: Jinhao(cnjinhao@hotmail.com) +*/ +#ifndef NANA_GUI_DRAGDROP_INCLUDED +#define NANA_GUI_DRAGDROP_INCLUDED + +#include +#include +#include "basis.hpp" + +#include +#include + +namespace nana +{ + /// Drag and drop actions + enum class dnd_action + { + copy, ///< Copy the data to target. + move, ///< Move the data to target. + link ///< Create a link from source data to target. + }; + + class simple_dragdrop + { + struct implementation; + + simple_dragdrop(const simple_dragdrop&) = delete; + simple_dragdrop& operator=(const simple_dragdrop&) = delete; + + simple_dragdrop(simple_dragdrop&&) = delete; + simple_dragdrop& operator=(simple_dragdrop&&) = delete; + public: + explicit simple_dragdrop(window source); + simple_dragdrop(window drag_origin, + std::function when, + window drop_target, + std::function how) + : simple_dragdrop{drag_origin} + { + condition(when); + make_drop(drop_target, how); + } + ~simple_dragdrop(); + + /// Condition checker + /** + * Sets a condition checker that determines whether the drag-and-drop operation can start. If a condition checker is not set, it always start drag-and-drop operation. + * @param predicate_fn Unary predicate which returns #true# for starting drag-and-drop operation. + */ + void condition(std::function predicate_fn); + void make_drop(window target, std::function drop_fn); + private: + implementation* const impl_; + }; + + namespace detail + { + struct dragdrop_data; + } + + class dragdrop + { + struct implementation; + + /// Non-copyable + dragdrop(const dragdrop&) = delete; + dragdrop& operator=(const dragdrop&) = delete; + + /// Non-movable + dragdrop(dragdrop&&) = delete; + dragdrop& operator=(dragdrop&&) = delete; + public: + class data + { + friend struct dragdrop::implementation; + + /// Non-copyable + data(const data&) = delete; + data& operator=(const data&) = delete; + public: + /// Constructor + /** + * Constructs a data object used for drag and drop + * @param requested_action Indicates how the data to be transferred. + */ + data(dnd_action requested_action = dnd_action::copy); + data(data&&); + ~data(); + + data& operator=(data&& rhs); + + void insert(std::filesystem::path); + private: + detail::dragdrop_data* real_data_; + }; + + dragdrop(window source); + ~dragdrop(); + + /// Condition checker + /*** + * Sets a condition checker that determines whether the drag-and-drop operation can start. If a condition checker is not set, it always start drag-and-drop operation. + * @param predicate_fn A predicate function to be set. + */ + void condition(std::function predicate_fn); + + /// Transferred data + /** + * Set a data generator. When drag begins, it is called to generate a data object for transferring. + * @param generator It returns the data for transferring. + */ + void prepare_data(std::function generator); + + /// Drop handler + /** + * The drop handler is called when the drop operation is completed. There are 3 parameters for the handler + * dropped Indicates whether the data is accepted by a target window. + * executed_action Indicates the action returned by target window. Ignore if dropped is false. + * data_transferred The data object which is generated by the generator. + * @param finish_fn The drop handling function. + */ + void drop_finished(std::function finish_fn); + private: + implementation* const impl_; + }; +} + +#endif \ No newline at end of file diff --git a/GUI/nana/gui/dragger.hpp b/GUI/nana/gui/dragger.hpp new file mode 100644 index 0000000..9e6bbbf --- /dev/null +++ b/GUI/nana/gui/dragger.hpp @@ -0,0 +1,49 @@ +/* +* A Dragger Implementation +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/dragger.hpp +*/ + +#ifndef NANA_GUI_DRAGGER_HPP +#define NANA_GUI_DRAGGER_HPP +#include +#include "basis.hpp" +#include "../basic_types.hpp" +#include "../traits.hpp" + +namespace nana +{ + /// \brief Helper class that allows the user to drag windows. + /// + /// If a user presses the mouse on the specified window and moves the mouse, the specified window is dragged. + /// The drag target window and trigger window can be set more than once. + /// See [Is it possible to make event inside event handler?](https://nanapro.codeplex.com/discussions/444121) + /// and [How to make widget movable by mouse the best way](https://nanapro.codeplex.com/discussions/444058) + + class dragger + : nana::noncopyable + { + class dragger_impl_t; + public: + dragger(); + ~dragger(); + + dragger(dragger&&); + dragger& operator=(dragger&&); + + void target(window); + void target(window, const rectangle& restrict_area, nana::arrange); + void remove_target(window); + void trigger(window); + private: + dragger_impl_t * impl_; + }; +}//end namespace nana +#include +#endif diff --git a/GUI/nana/gui/drawing.hpp b/GUI/nana/gui/drawing.hpp new file mode 100644 index 0000000..693af74 --- /dev/null +++ b/GUI/nana/gui/drawing.hpp @@ -0,0 +1,54 @@ +/* + * A Drawing Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/drawing.hpp + */ +#ifndef NANA_GUI_DRAWING_HPP +#define NANA_GUI_DRAWING_HPP + +#include +#include "widgets/widget.hpp" +#include "../traits.hpp" +namespace nana +{ + /// \brief Draw pictures on a widget by specifying a drawing method that will be employed every time the widget refreshes. + /// By the end of drawing, the picture may not be displayed immediately. + /// If a picture need to be displayed immediately call nana::gui::API::refresh_window() . + class drawing + :private nana::noncopyable + { + struct draw_fn_handle; + public: + using diehard_t = draw_fn_handle * ; ///< A handle to a drawing method + using draw_fn_t = std::function; ///< A function to draw + + drawing(window w); ///< Create a drawing object for a widget w + + virtual ~drawing(); ///< Just for polymorphism + + bool empty() const; ///< Returns true if the drawing object is invalid. + void update() const; + + void draw(const draw_fn_t&); ///< Draws things that are defined by draw_fn_t. + void draw(draw_fn_t&&); ///< Draws things that are defined by draw_fn_t. + + /// Draws things that are defined by draw_fn_t but will not be deleted when clear() is called. + diehard_t draw_diehard(const draw_fn_t&); + /// Draws things that are defined by draw_fn_t but will not be deleted when clear() is called. + diehard_t draw_diehard(draw_fn_t&&); + void erase(diehard_t); ///< Erases a diehard drawing method. + + void clear(); ///< Erases all. + private: + window handle_; + };//end class drawing +}//end namespace nana + +#include +#endif diff --git a/GUI/nana/gui/effects.hpp b/GUI/nana/gui/effects.hpp new file mode 100644 index 0000000..c405f8e --- /dev/null +++ b/GUI/nana/gui/effects.hpp @@ -0,0 +1,67 @@ +/* + * Background Effects Implementation + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/effects.hpp + * + */ +#ifndef NANA_GUI_EFFECTS_HPP +#define NANA_GUI_EFFECTS_HPP +#include +#include + +namespace nana +{ + namespace effects + { + enum class edge_nimbus + { + none, active = 0x1, over = 0x2 + }; + + class bground_interface + { + public: + typedef paint::graphics & graph_reference; + + virtual ~bground_interface() = 0; + virtual void take_effect(window, graph_reference) const = 0; + }; + + class bground_factory_interface + { + friend class effects_accessor; + public: + virtual ~bground_factory_interface() = 0; + private: + virtual bground_interface * create() const = 0; + }; + + class bground_transparent + : public bground_factory_interface + { + public: + explicit bground_transparent(std::size_t percent); + private: + bground_interface* create() const override; + private: + std::size_t percent_; + }; + + class bground_blur + : public bground_factory_interface + { + public: + bground_blur(std::size_t radius); + private: + bground_interface * create() const override; + private: + std::size_t radius_; + }; + } +}//end namespace nana +#endif diff --git a/GUI/nana/gui/element.hpp b/GUI/nana/gui/element.hpp new file mode 100644 index 0000000..bb76656 --- /dev/null +++ b/GUI/nana/gui/element.hpp @@ -0,0 +1,347 @@ +/* + * Elements of GUI Gadgets + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/element.hpp + */ +#ifndef NANA_GUI_ELEMENT_HPP +#define NANA_GUI_ELEMENT_HPP + +#include +#include +#include +#include + +namespace nana +{ + namespace paint + { + //forward declaration + class image; + } + + namespace element + { + namespace detail + { + class element_abstract + { + public: + using graph_reference = ::nana::paint::graphics&; + virtual ~element_abstract() = default; + }; + + class factory_abstract + { + public: + virtual ~factory_abstract() = default; + + virtual void destroy(element_abstract *); + }; + } + + class element_interface + : public detail::element_abstract + { + public: + virtual bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state) = 0; + }; + + class crook_interface + : public detail::element_abstract + { + public: + using state = checkstate; + + struct data + { + state check_state; + bool radio; + }; + + virtual bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state, const data&) = 0; + }; + + class border_interface + : public detail::element_abstract + { + public: + virtual bool draw(graph_reference, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle&, element_state, unsigned weight) = 0; + }; + + class arrow_interface + : public detail::element_abstract + { + public: + virtual bool draw(graph_reference, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle&, element_state, direction) = 0; + }; + + class provider + { + public: + template + struct factory_interface + : public detail::factory_abstract + { + virtual ElementInterface* create() const = 0; + }; + + template + class factory + : public factory_interface + { + public: + using interface_type = factory_interface; + + ElementInterface * create() const override + { + return (new Element); + } + }; + + void add_arrow(const std::string&, const pat::cloneable>&); + arrow_interface* const * cite_arrow(const std::string&); + + void add_border(const std::string&, const pat::cloneable>&); + border_interface* const * cite_border(const std::string&); + + void add_button(const std::string&, const pat::cloneable>&); + element_interface* const* cite_button(const std::string&); + + void add_x_icon(const std::string& name, const pat::cloneable>&); + element_interface* const* cite_x_icon(const std::string&); + + void add_crook(const std::string& name, const pat::cloneable>&); + crook_interface* const * cite_crook(const std::string& name); + + void add_cross(const std::string& name, const pat::cloneable>&); + element_interface* const* cite_cross(const std::string&); + }; + + class arrow; + template + void add_arrow(const std::string& name) + { + using factory_t = provider::factory; + provider().add_arrow(name, pat::cloneable(factory_t())); + } + + class border; + template + void add_border(const std::string& name) + { + using factory_t = provider::factory; + provider().add_border(name, pat::cloneable(factory_t())); + } + + class button; + template + void add_button(const std::string& name) + { + using factory_t = provider::factory; + provider().add_button(name, pat::cloneable(factory_t())); + } + + class x_icon; + template + void add_x_icon(const std::string& name) + { + using factory_t = provider::factory; + provider().add_x_icon(name, pat::cloneable(factory_t())); + } + + class crook; + template + void add_crook(const std::string& name) + { + using factory_t = provider::factory; + provider().add_crook(name, pat::cloneable(factory_t())); + } + + class cross; + template + void add_cross(const std::string& name) + { + using factory_t = provider::factory; + provider().add_cross(name, pat::cloneable(factory_t())); + } + }//end namespace element + + template class facade; + + template<> + class facade + : public element::element_interface + { + public: + using graph_reference = ::nana::paint::graphics &; + using state = element::crook_interface::state; + + facade(const char* name = nullptr); + + facade & reverse(); + facade & check(state); + state checked() const; + + facade& radio(bool); + bool radio() const; + + void switch_to(const char*); + public: + //Implement element_interface + bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle& r, element_state) override; + private: + element::crook_interface::data data_; + element::crook_interface* const * cite_; + }; //end class facade + + template<> class facade + : public element::element_interface + { + public: + facade(const char* name = nullptr); + void switch_to(const char*); + + void thickness(unsigned thk); + void size(unsigned size_pixels); + public: + //Implement element_interface + bool draw(graph_reference, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle&, element_state) override; + private: + unsigned thickness_{6}; + unsigned size_{ 14 }; + element::element_interface* const * cite_; + }; + + template<> + class facade + : public element::element_interface + { + using graph_reference = ::nana::paint::graphics &; + public: + facade(const char* name = nullptr); + + void switch_to(const char*); + public: + //Implement element_interface + bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state) override; + private: + element::border_interface* const * cite_; + };//end class facade + + template<> + class facade + : public element::element_interface + { + using graph_reference = ::nana::paint::graphics &; + public: + enum class style + { + solid + }; + + facade(const char* name = nullptr); + + void switch_to(const char*); + void direction(::nana::direction); + public: + //Implement element_interface + bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state) override; + private: + element::arrow_interface* const * cite_; + ::nana::direction dir_{::nana::direction::north}; + };//end class facade + + template<> + class facade + : public element::element_interface + { + public: + facade(const char* name = nullptr); + void switch_to(const char*); + public: + //Implement element_interface + bool draw(graph_reference, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle&, element_state) override; + private: + element::element_interface* const * cite_; + };//end class facade + + template<> + class facade + : public element::element_interface + { + public: + facade(const char* name = nullptr); + void switch_to(const char*); + public: + //Implement element_interface + bool draw(graph_reference, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle&, element_state) override; + private: + element::element_interface* const * cite_; + };//end class facade + + namespace element + { + void set_bground(const char* name, const pat::cloneable&); + void set_bground(const char* name, pat::cloneable &&); + + class cite_bground + { + public: + typedef paint::graphics& graph_reference; + typedef pat::cloneable cloneable_element; + + cite_bground(const char*); + + void set(const cloneable_element&); + void set(const char*); + + bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state); + private: + cloneable_element holder_; + element_interface * place_ptr_; + element_interface * const * ref_ptr_; + }; + + class bground + : public element_interface + { + public: + typedef paint::graphics& graph_reference; + + bground(); + bground(const bground&); + ~bground(); + bground& operator=(const bground&); + + bground& image(const paint::image&, bool vertical, const nana::rectangle& valid_area); ///< Set a picture for the background + bground& image(const paint::graphics&, bool vertical, const nana::rectangle& valid_area); ///< Set a picture for the background + + void states(const std::vector &); ///< Set the state sequence of the background picture. + void states(std::vector &&); ///< Set the state sequence of the background picture. + void reset_states(); + + void join(element_state target, element_state joiner); + + void stretch_parts(unsigned left, unsigned top, unsigned right, unsigned bottom); + + //Implement the methods of element_interface. + virtual bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state); + private: + struct draw_method; + struct draw_image; + struct draw_graph; + + struct implementation; + std::unique_ptr impl_; + }; //end class bground + }//end namespace element +}//end namespace nana + +#include +#endif //NANA_GUI_ELEMENT_HPP diff --git a/GUI/nana/gui/filebox.hpp b/GUI/nana/gui/filebox.hpp new file mode 100644 index 0000000..3a3e7e0 --- /dev/null +++ b/GUI/nana/gui/filebox.hpp @@ -0,0 +1,128 @@ +/** + * Filebox + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/gui/filebox.hpp + * @author Jinhao + * @brief dialogs to chose file(s) or a directory, implemented "native" in windows but using nana for X11 + */ + +#ifndef NANA_GUI_FILEBOX_HPP +#define NANA_GUI_FILEBOX_HPP +#include +#include +#include +#include + +namespace nana +{ /// Create an Open or Save dialog box to let user select the name of a file. + class filebox + { + struct implement; + + filebox(filebox&&) = delete; + filebox& operator=(filebox&&) = delete; + public: + using path_type = std::filesystem::path; + + filebox(window owner, bool is_open_mode); + filebox(const filebox&); + ~filebox(); + + filebox& operator=(const filebox&); + + /// Change owner window + /** + * Changes the owner window for the filebox. When #show()/operator()# are invoked, the dialog of filebox will be created with the specified owner. + * @param handle A handle to a window which will be used for the owner of filebox + */ + void owner(window handle); + + /// Changes new title + /** + * Changes the title. When #show()/operator()# are invoked, the dialog of filebox will be created with the specified title. + * @param text Text of title + * @return the reference of *this. + */ + filebox& title( ::std::string text); + + /// Sets a initial path + /** + * Suggest initial path used to locate a directory when the filebox starts. + * @note the behavior of init_path is different between Win7 and Win2K/XP/Vista, but its behavior under Linux is conformed with Win7. + * @param path a path of initial directory + * @return reference of *this. + */ + filebox& init_path(const path_type& path); + + /// Sets a initial filename + /** + * Suggest a filename when filebox starts. If the filename contains a path, the initial path will be replaced with the path presents in initial filename. + * @param filename a filename used for a initial filename when filebox starts. + * @return reference of *this. + */ + filebox& init_file(const ::std::string& filename); ///< Init file, if it contains a path, the init path is replaced by the path of init file. + + /// \brief Add a filetype filter. + /// To specify multiple filter in a single description, use a semicolon to separate the patterns(for example,"*.TXT;*.DOC;*.BAK"). + filebox& add_filter(const ::std::string& description, ///< for example: "Text File" + const ::std::string& filetype ///< filter pattern(for example: "*.TXT") + ); + + filebox& add_filter(const std::vector> &filters); + + const path_type& path() const; + + filebox& allow_multi_select(bool allow); + + /// Display the filebox dialog + std::vector show() const; + + /// a function object method alternative to show() to display the filebox dialog, + std::vector operator()() const + { + return show(); + } + private: + implement * impl_; + }; + + class folderbox + { + struct implement; + + folderbox(const folderbox&) = delete; + folderbox& operator=(const folderbox&) = delete; + folderbox(folderbox&&) = delete; + folderbox& operator=(folderbox&&) = delete; + public: + using path_type = std::filesystem::path; + + explicit folderbox(window owner = nullptr, const path_type& init_path = {}, std::string title={}); + ~folderbox(); + + /// Enables/disables multi select + folderbox& allow_multi_select(bool allow); + + std::vector show() const; + + std::vector operator()() const + { + return show(); + } + + /// Changes title + /** + * @param text Text of title + */ + folderbox& title(std::string text); + private: + implement* impl_; + }; +}//end namespace nana +#endif diff --git a/GUI/nana/gui/layout_utility.hpp b/GUI/nana/gui/layout_utility.hpp new file mode 100644 index 0000000..fdadf03 --- /dev/null +++ b/GUI/nana/gui/layout_utility.hpp @@ -0,0 +1,43 @@ +/* + * Utility Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/layout_utility.hpp + */ + +#ifndef NANA_GUI_LAYOUT_UTILITY_HPP +#define NANA_GUI_LAYOUT_UTILITY_HPP + +#include "basis.hpp" + +namespace nana +{ + //overlap test if overlapped between r1 and r2 + bool overlapped(const rectangle& r1, const rectangle& r2); + + // overlap, compute the overlapping area between r1 and r2. the r is for root + bool overlap(const rectangle& r1, const rectangle& r2, rectangle& r); + + bool overlap(const rectangle& ir, const size& valid_input_area, const rectangle & dr, const size& valid_dst_area, rectangle& output_src_r, rectangle& output_dst_r); + + bool intersection(const rectangle & r, point pos_beg, point pos_end, point& good_pos_beg, point& good_pos_end); + + /// Zoom the input_s to fit for ref_s + void fit_zoom(const size& input_s, const size& ref_s, size& result_s); + size fit_zoom(const size& input_s, size ref_s); + + //zoom + //@brief: Calculate the scaled rectangle by refer dst rectangle, that scale factor is same as that between scaled and refer. + void zoom(const rectangle& refer, const rectangle& scaled, const rectangle& refer_dst, rectangle& r); + + //covered + //@brief: Tests a rectangle whether it is wholly covered by another. + bool covered(const rectangle& underlying, // 1st rectangle must be placed under 2nd rectangle + const rectangle& cover); +}//end namespace nana +#endif diff --git a/GUI/nana/gui/msgbox.hpp b/GUI/nana/gui/msgbox.hpp new file mode 100644 index 0000000..5b82219 --- /dev/null +++ b/GUI/nana/gui/msgbox.hpp @@ -0,0 +1,337 @@ +/** +* A Message Box Class +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file nana/gui/msgbox.hpp +*/ + +#ifndef NANA_GUI_MSGBOX_HPP +#define NANA_GUI_MSGBOX_HPP +#include + +#include + +namespace nana +{ + //Forward declaration of filebox for msgbox + class filebox; + + /// Prefabricated modal dialog box (with text, icon and actions buttons) that informs and instructs the user. + class msgbox + { + public: + /// Identifiers of icons. + enum icon_t{icon_none, icon_information, icon_warning, icon_error, icon_question}; + + /// Identifiers of buttons. + enum button_t{ok, yes_no, yes_no_cancel}; + + /// Identifiers of buttons that a user clicked. + enum pick_t{pick_ok, pick_yes, pick_no, pick_cancel}; + + /// Default constructor that creates a message box with default title and default button, the default button is OK. + msgbox(); + + /// Copy constructor from an existing msgbox object. + msgbox(const msgbox&); + + /// Assign from an existing msgbox object. + msgbox& operator=(const msgbox&); + + /// Constructor that creates a message box with a specified title and default button. + msgbox(const ::std::string&); + + /// Constructor that creates a message box with an owner window, a specified title and buttons. + msgbox(window, const ::std::string&, button_t = ok); + + /// Sets an icon for informing user. + msgbox& icon(icon_t); + + /// Clears the text message buffer. + void clear(); + + /// Writes a string to the buffer. + msgbox & operator<<(const std::wstring&); + + /// Writes a string to the buffer. + msgbox & operator<<(const wchar_t*); + + /// Writes a UTF-8 string to the buffer. + msgbox & operator<<(const std::string&); + + /// Writes a UTF-8 string to the buffer. + msgbox & operator<<(const char*); + + /// Writes a string to the buffer. + msgbox & operator<<(const nana::charset&); + + // Calls a manipulator to the stream. + msgbox & operator<<(std::ostream& (*)(std::ostream&)); + + /// Write a streamable object to the buffer. + template + msgbox & operator<<(const T& t) + { + sstream_< impl_; + }; + + /// Integer input + class integer + : public abstract_content + { + struct implement; + public: + integer(::std::string label, int init_value, int begin, int last, int step); + ~integer(); + + int value() const; + private: + //Implementation of abstract_content + const ::std::string& label() const override; + window create(window, unsigned label_px) override; + unsigned fixed_pixels() const override; + private: + std::unique_ptr impl_; + }; + + /// Floating-point number input. + class real + : public abstract_content + { + struct implement; + public: + real(::std::string label, double init_value, double begin, double last, double step); + ~real(); + + double value() const; + private: + //Implementation of abstract_content + const ::std::string& label() const override; + window create(window, unsigned label_px) override; + unsigned fixed_pixels() const override; + private: + std::unique_ptr impl_; + }; + + /// String input or an option from a dropdown list. + class text + : public abstract_content + { + struct implement; + + text(const text&) = delete; + text& operator=(const text&) = delete; + public: + text(::std::string label, ::std::string init_text = ::std::string()); + text(::std::string label, std::vector<::std::string>); + + ~text(); + + void tip_string(std::wstring tip); + void tip_string(std::string tip_utf8); + + void mask_character(wchar_t ch); + + ::std::string value() const; + private: + //Implementation of abstract_content + const ::std::string& label() const override; + window create(window, unsigned label_px) override; + unsigned fixed_pixels() const override; + private: + std::unique_ptr impl_; + }; + + /// Date input + class date + : public abstract_content + { + struct implement; + public: + date(::std::string label); + + ~date(); + + ::std::string value() const; + int year() const; + int month() const; //[1, 12] + int day() const; //[1, 31] + private: + //Implementation of abstract_content + const ::std::string& label() const override; + window create(window, unsigned label_px) override; + unsigned fixed_pixels() const override; + private: + std::unique_ptr impl_; + }; + + /// Path of a file. + /// + /// The path requires an object of filebox. When the user clicks the `Browse` button, + /// it invokes the filebox with proper configurations to query a filename. + class path + : public abstract_content + { + struct implement; + public: + path(::std::string label, const ::nana::filebox&); + ~path(); + + ::std::string value() const; + private: + //Implementation of abstract_content + const ::std::string& label() const override; + window create(window, unsigned label_px) override; + private: + std::unique_ptr impl_; + }; + + inputbox(window owner, ///< A handle to an owner window (just a parent form or widget works) + ::std::string description, ///< tells users what the purpose for the input. It can be a formatted-text. + ::std::string title = ::std::string() ///< The title for the inputbox. + ); + + /// shows images at left/right side of inputbox + void image(::nana::paint::image image, ///< The image + bool is_left, ///< true to place the image at left side, false to the right side + const rectangle& valid_area = {} ///< The area of the image to be displayed + ); + + /// shows images at top/bottom side of inputbox + void image_v(::nana::paint::image, ///< The image + bool is_top, ///< `true` to place the image at top side, `false` at bottom side + const rectangle& valid_area = {} ///< The area of the image to be displayed + ); + + /// Shows the inputbox and wait for the user input. + /// + /// This method shows the inputbox without preventing the user interacts with other windows. + template + bool show(Args&& ... args) + { + std::vector contents; +#ifdef __cpp_fold_expressions + (contents.emplace_back(&args), ...); +#else + _m_fetch_args(contents, std::forward(args)...); +#endif + if (contents.empty()) + return false; + + return _m_open(contents, false); + } + + /// Shows the inputbox and wait for the user input blocking other windows. + /// + /// This method blocks the execution and prevents user interaction with other + /// windows until the inputbox is closed. + template + bool show_modal(Args&& ... args) + { + std::vector contents; +#ifdef __cpp_fold_expressions + (contents.emplace_back(&args), ...); +#else + _m_fetch_args(contents, std::forward(args)...); +#endif + + if (contents.empty()) + return false; + + return _m_open(contents, true); + } + + /// Sets a verifier to verify the user input, taking a handle to the inputbox. + void verify(std::function verifier); + + /** Sets the minimum width for the entry fields + @param[in] pixels new minimum width + + If not called, the default is 100 pixels + */ + void min_width_entry_field( unsigned pixels ); + + private: +#ifndef __cpp_fold_expressions + void _m_fetch_args(std::vector&); + + template + void _m_fetch_args(std::vector& contents, abstract_content& content, Args&&... args) + { + contents.push_back(&content); + _m_fetch_args(contents, std::forward(args)...); + } +#endif + + bool _m_open(std::vector&, bool modal); + private: + window owner_; + ::std::string description_; + ::std::string title_; + std::function verifier_; + ::nana::paint::image images_[4]; + ::nana::rectangle valid_areas_[4]; + unsigned min_width_entry_field_pixels_; + }; +}//end namespace nana +#include + +#endif diff --git a/GUI/nana/gui/notifier.hpp b/GUI/nana/gui/notifier.hpp new file mode 100644 index 0000000..d0d87ef --- /dev/null +++ b/GUI/nana/gui/notifier.hpp @@ -0,0 +1,70 @@ +/* + * Definition of Notifier + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/notifier.hpp + */ + +#ifndef NANA_GUI_NOTIFIER_HPP +#define NANA_GUI_NOTIFIER_HPP +#include +#include +#include + +namespace nana +{ + class notifier; + + struct arg_notifier + : public event_arg + { + event_code evt_code; + notifier* notifier_ptr; + nana::point pos; + bool left_button; + bool mid_button; + bool right_button; + + operator arg_mouse() const; + }; + + namespace detail + { + struct notifier_events + { + basic_event mouse_move; + basic_event mouse_down; + basic_event mouse_up; + basic_event mouse_leave; + basic_event dbl_click; + }; + } + + class notifier + { + struct implement; + notifier(const notifier&) = delete; + notifier(notifier&&) = delete; + notifier& operator=(const notifier&) = delete; + notifier& operator=(notifier&&) = delete; + public: + notifier(window); + ~notifier(); + void close(); + void text(const ::std::string&); + void icon(const ::std::string& icon_file); + void insert_icon(const ::std::string& icon_file); + void period(std::chrono::milliseconds time); + detail::notifier_events& events(); + window handle() const; + private: + implement * impl_; + }; +}//end namespace nana +#include +#endif diff --git a/GUI/nana/gui/place.hpp b/GUI/nana/gui/place.hpp new file mode 100644 index 0000000..a7a56f1 --- /dev/null +++ b/GUI/nana/gui/place.hpp @@ -0,0 +1,178 @@ +/** + * An Implementation of Place for Layout + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/gui/place.cpp + * + * @contributions + * error, width/height, min/max and splitter bar initial weight by Ariel Vina-Rodriguez. + */ + +#ifndef NANA_GUI_PLACE_HPP +#define NANA_GUI_PLACE_HPP +#include +#include +#include +#include + +namespace nana +{ + namespace paint + { + class graphics; + } + + class widget; + namespace detail + { + class place_agent + { + public: + virtual ~place_agent() = default; + virtual std::unique_ptr create(nana::window) const = 0; + }; + } + + template + class agent + : public detail::place_agent + { + public: + agent(std::function initializer) + : init_(std::move(initializer)) + {} + + agent(const char* text) + : text_(text) + { + throw_not_utf8(text); + } + + agent(std::string text, std::function initializer = {}) + : text_(std::move(text)), init_(std::move(initializer)) + { + throw_not_utf8(text_); + } + + private: + std::unique_ptr create(nana::window handle) const override + { + std::unique_ptr ptr(new Widget(handle)); + ptr->caption(text_); + if (init_) + init_(*ptr); + return std::move(ptr); + } + private: + std::string text_; + std::function init_; + }; + + /// Layout management - an object of class place is attached to a widget, and it automatically positions and resizes the children widgets. + class place + : ::nana::noncopyable + { + struct implement; + + + class field_interface + { + field_interface(const field_interface&) = delete; + field_interface& operator=(const field_interface&) = delete; + field_interface(field_interface&&) = delete; + field_interface& operator=(field_interface&&) = delete; + public: + field_interface() = default; + virtual ~field_interface() = default; + virtual field_interface& operator<<(const char* label) = 0; + virtual field_interface& operator<<(std::string label) = 0; + virtual field_interface& operator<<(window) = 0; + virtual field_interface& fasten(window) = 0; + + template + field_interface& operator<<(const agent& ag) + { + _m_add_agent(ag); + return *this; + } + private: + virtual void _m_add_agent(const detail::place_agent&) = 0; + }; + public: + class error :public std::invalid_argument + { + public: + error( const std::string& what, + const place& plc, + std::string field = "unknown", + std::string::size_type pos = std::string::npos); + std::string base_what; + std::string owner_caption; ///< truncate caption (title) of the "placed" widget + std::string div_text; ///< involved div_text + std::string field; ///< posible field where the error ocurred. + std::string::size_type pos; ///< posible position in the div_text where the error ocurred. npos if unknown + }; + /// reference to a field manipulator which refers to a field object created by place + using field_reference = field_interface &; + + place(); + place(window);///< Attaches to a specified widget. + ~place(); + + /** @brief Bind to a window + * @param handle A handle to a window which the place wants to attach. + * @remark It will throw an exception if the place has already binded to a window. + */ + void bind(window handle); + window window_handle() const; + + void splitter_renderer(std::function fn); + + void div(std::string div_text); ///< Divides the attached widget into fields. May throw placa::error + const std::string& div() const noexcept; ///< Returns div-text that depends on fields status. + static bool valid_field_name(const char* name) ///< must begin with _a-zA-Z + { + return name && (*name == '_' || (('a' <= *name && *name <= 'z') || ('A' <= *name && *name <= 'Z'))); + } + void modify(const char* field_name, const char* div_text); ///< Modifies a specified field. May throw placa::error + + field_reference field(const char* name);///< Returns a field with the specified name. + + void field_visible(const char* field_name, bool visible); ///< + place& dock(const std::string& dockname, const std::string& factory_name, Args&& ... args) + { + return dock(dockname, factory_name, std::bind([](window parent, Args & ... args) + { + return std::unique_ptr(new Panel(parent, std::forward(args)...)); + }, std::placeholders::_1, args...)); + } + + place& dock(const std::string& dockname, std::string factory_name, std::function(window)> factory); + widget* dock_create(const std::string& factory); + private: + implement * impl_; + }; + + +}//end namespace nana +#include + +#endif //#ifndef NANA_GUI_PLACE_HPP diff --git a/GUI/nana/gui/programming_interface.hpp b/GUI/nana/gui/programming_interface.hpp new file mode 100644 index 0000000..8107f0a --- /dev/null +++ b/GUI/nana/gui/programming_interface.hpp @@ -0,0 +1,490 @@ +/* + * Nana GUI Programming Interface Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/programming_interface.hpp + */ + +#ifndef NANA_GUI_PROGRAMMING_INTERFACE_HPP +#define NANA_GUI_PROGRAMMING_INTERFACE_HPP +#include +#include "effects.hpp" +#include "detail/general_events.hpp" +#include "detail/color_schemes.hpp" +#include "detail/widget_content_measurer_interface.hpp" +#include +#include + +namespace nana +{ + class drawer_trigger; + class widget; + + namespace dev + { + /// Traits for widget classes + template + struct widget_traits + { + using event_type = typename Widget::event_type; + using scheme_type = typename Widget::scheme_type; + }; + + template<> + struct widget_traits + { + using event_type = ::nana::general_events; + using scheme_type = ::nana::widget_geometrics; + }; + } + +namespace API +{ +#ifdef NANA_X11 + //Some platform specific functions for X11 + namespace x11 + { + /// Returns the connection to the X server + const void* get_display(); + } +#endif + + namespace detail + { + ::nana::widget_geometrics* make_scheme(::nana::detail::scheme_factory_interface&&); + } + + void effects_edge_nimbus(window, effects::edge_nimbus); + effects::edge_nimbus effects_edge_nimbus(window); + + void effects_bground(window, const effects::bground_factory_interface&, double fade_rate); + void effects_bground(std::initializer_list wdgs, const effects::bground_factory_interface&, double fade_rate); + + bground_mode effects_bground_mode(window); + void effects_bground_remove(window); + + //namespace dev + //@brief: The interfaces defined in namespace dev are used for developing the nana.gui + namespace dev + { + void affinity_execute(window window_handle, const std::function&); + + bool set_events(window, const std::shared_ptr&); + + template + std::unique_ptr make_scheme() + { + return std::unique_ptr{static_cast(API::detail::make_scheme(::nana::detail::scheme_factory()))}; + } + + void set_scheme(window, widget_geometrics*); + widget_geometrics* get_scheme(window); + + /// Sets a content measurer + void set_measurer(window, ::nana::dev::widget_content_measurer_interface*); + + void attach_drawer(widget&, drawer_trigger&); + ::nana::detail::native_string_type window_caption(window) noexcept; + void window_caption(window, ::nana::detail::native_string_type); + + window create_window(window, bool nested, const rectangle&, const appearance&, widget* attached); + window create_widget(window, const rectangle&, widget* attached); + window create_lite_widget(window, const rectangle&, widget* attached); + + paint::graphics* window_graphics(window); + + void delay_restore(bool); + + void register_menu_window(window, bool has_keyboard); + void set_menubar(window wd, bool attach); + + void enable_space_click(window, bool enable); + + bool copy_transparent_background(window, paint::graphics&); + bool copy_transparent_background(window, const rectangle& src_r, paint::graphics&, const point& dst_pt); + + /// Refreshes a widget surface + /* + * This function will copy the drawer surface into system window after the event process finished. + */ + void lazy_refresh(); + + void draw_shortkey_underline(paint::graphics&, const std::string& text, wchar_t shortkey, std::size_t shortkey_position, const point& text_pos, const color&); + + void window_draggable(window, bool enabled); + bool window_draggable(window); + }//end namespace dev + + + /// Returns the widget pointer of the specified window. + /* + * @param window_handle A handle to a window owning the widget. + * @return A widget pointer. + */ + widget* get_widget(window window_handle); + + namespace detail + { + general_events* get_general_events(window); + + // emits both internal and external event (internal event can be filtered) + bool emit_event(event_code, window, const ::nana::event_arg&); + + // explicitly emits internal event (internal event not to be filtered) + bool emit_internal_event(event_code, window, const ::nana::event_arg&); + + class enum_widgets_function_base + { + public: + virtual ~enum_widgets_function_base() = default; + void enum_widgets(window, bool recursive); + private: + virtual bool _m_enum_fn(::nana::widget*) = 0; + }; + + template + class enum_widgets_function + : public enum_widgets_function_base + { + public: + enum_widgets_function(EnumFunction && enum_fn) + : enum_fn_(static_cast(enum_fn)) + {} + private: + bool _m_enum_fn(::nana::widget* wd) override + { + return _m_enum_call(wd); + } + + template::value>::type* = nullptr> + bool _m_enum_call(::nana::widget* wd) + { + enum_fn_(*wd); + return true; + } + + template::value>::type* = nullptr> + bool _m_enum_call(::nana::widget* wd) + { + auto ptr = dynamic_cast(wd); + if (nullptr == ptr) + return false; + + enum_fn_(*ptr); + return true; + } + private: + EnumFunction && enum_fn_; + }; + }//end namespace detail + + ///Sets languages + /** + * Specifies the languages in order to make the program display multi-languages correctly + * Under Windows, the pragram can display multi-languages correctly, so this function is useless for Windows. + */ + void font_languages(const std::string& langs); + + void exit(); ///< close all windows in current thread + void exit_all(); ///< close all windows + + /// @brief Searches whether the text contains a '&' and removes the character for transforming. + /// If the text contains more than one '&' characters, the others are ignored. e.g + /// text = "&&a&bcd&ef", the result should be "&abcdef", shortkey = 'b', and pos = 2. + std::string transform_shortkey_text + ( std::string text, ///< the text is transformed + wchar_t &shortkey, ///< the character which indicates a short key. + std::string::size_type *skpos ///< retrieves the shortkey position if it is not a null_ptr; + ); + bool register_shortkey(window, unsigned long); + void unregister_shortkey(window); + + nana::point cursor_position(); + rectangle make_center(unsigned width, unsigned height); ///< Retrieves a rectangle which is in the center of the screen. + rectangle make_center(window, unsigned width, unsigned height); ///< Retrieves a rectangle which is in the center of the window + + template + void enum_widgets(window wd, bool recursive, EnumFunction && fn) + { + static_assert(std::is_convertible::type*, ::nana::widget*>::value, "enum_widgets: The specified Widget is not a widget type."); + + detail::enum_widgets_function enum_fn(static_cast(fn)); + enum_fn.enum_widgets(wd, recursive); + } + + void window_icon_default(const paint::image& small_icon, const paint::image& big_icon = {}); + void window_icon(window, const paint::image& small_icon, const paint::image& big_icon = {}); + + bool empty_window(window); ///< Determines whether a window is existing. + bool is_window(window); ///< Determines whether a window is existing, equal to !empty_window. + bool is_destroying(window); ///< Determines whether a window is destroying + void enable_dropfiles(window, bool); + + bool is_transparent_background(window); + + /// \brief Retrieves the native window of a Nana.GUI window. + /// + /// The native window type is platform-dependent. Under Microsoft Windows, a conversion can be employed between + /// nana::native_window_type and HWND through reinterpret_cast operator. Under X System, a conversion can + /// be employed between nana::native_window_type and Window through reinterpret_cast operator. + /// \return If the function succeeds, the return value is the native window handle to the Nana.GUI window. If fails return zero. + native_window_type root(window); + window root(native_window_type); ///< Retrieves the native window of a Nana.GUI window. + + void fullscreen(window, bool); + + void close_window(window); + void show_window(window, bool show); ///< Sets a window visible state. + void restore_window(window); + void zoom_window(window, bool ask_for_max); + bool visible(window); + window get_parent_window(window); + window get_owner_window(window); + + bool set_parent_window(window, window new_parent); + + template + typename ::nana::dev::widget_traits::event_type & events(window wd) + { + using event_type = typename ::nana::dev::widget_traits::event_type; + + internal_scope_guard lock; + auto * general_evt = detail::get_general_events(wd); + if (nullptr == general_evt) + throw std::invalid_argument("API::events(): bad parameter window handle, no events object or invalid window handle."); + +#ifdef __cpp_if_constexpr + if constexpr(std::is_same_v) + { + return *general_evt; + } + else + { + auto * widget_evt = dynamic_cast(general_evt); + if (nullptr == widget_evt) + throw std::invalid_argument("API::events(): bad template parameter Widget, the widget type and window handle do not match."); + return *widget_evt; + } +#else + if (std::is_same<::nana::general_events, event_type>::value) + return *static_cast(general_evt); + + auto * widget_evt = dynamic_cast(general_evt); + if (nullptr == widget_evt) + throw std::invalid_argument("API::events(): bad template parameter Widget, the widget type and window handle do not match."); + return *widget_evt; +#endif + } + + template::value>::type* = nullptr> + bool emit_event(event_code evt_code, window wd, const EventArg& arg) + { + return detail::emit_event(evt_code, wd, arg); + } + + template::value>::type* = nullptr> + bool emit_internal_event(event_code evt_code, window wd, const EventArg& arg) + { + return detail::emit_internal_event(evt_code, wd, arg); + } + + void umake_event(event_handle); + + template + typename ::nana::dev::widget_traits::scheme_type & scheme(window wd) + { + using scheme_type = typename ::nana::dev::widget_traits::scheme_type; + + internal_scope_guard lock; + auto * wdg_colors = dev::get_scheme(wd); + if (nullptr == wdg_colors) + throw std::invalid_argument("API::scheme(): bad parameter window handle, no events object or invalid window handle."); + +#ifdef __cpp_if_constexpr + if constexpr(std::is_same<::nana::widget_geometrics, scheme_type>::value) + { + return *static_cast(wdg_colors); + } + else + { + auto * comp_wdg_colors = dynamic_cast(wdg_colors); + if (nullptr == comp_wdg_colors) + throw std::invalid_argument("API::scheme(): bad template parameter Widget, the widget type and window handle do not match."); + return *comp_wdg_colors; + } +#else + if (std::is_same<::nana::widget_geometrics, scheme_type>::value) + return *static_cast(wdg_colors); + + auto * comp_wdg_colors = dynamic_cast(wdg_colors); + if (nullptr == comp_wdg_colors) + throw std::invalid_argument("API::scheme(): bad template parameter Widget, the widget type and window handle do not match."); + return *comp_wdg_colors; +#endif + } + + point window_position(window); + void move_window(window, const point&); + void move_window(window wd, const rectangle&); + + void bring_top(window, bool activated); + bool set_window_z_order(window wd, window wd_after, z_order_action action_if_no_wd_after); + + void draw_through(window, std::function); + void map_through_widgets(window, native_drawable_type); + + size window_size(window); + void window_size(window, const size&); + size window_outline_size(window); + void window_outline_size(window, const size&); + + ::std::optional window_rectangle(window); + bool get_window_rectangle(window, rectangle&); + bool track_window_size(window, const size&, bool true_for_max); ///< Sets the minimum or maximum tracking size of a window. + void window_enabled(window, bool); + bool window_enabled(window); + + /// Refresh the window and display it immediately calling the refresh function of its drawer_trigger. + /* + * The drawer::refresh() will be called. If the current state is lazy_refrsh, the window is delayed to update the graphics until an event is finished. + * @param window_handle A handle to the window to be refreshed. + */ + void refresh_window(window window_handle); + void refresh_window_tree(window); ///< Refreshes the specified window and all its children windows, then displays it immediately + void update_window(window); ///< Copies the off-screen buffer to the screen for immediate display. + + void window_caption(window, const std::string& title_utf8); + void window_caption(window, const std::wstring& title); + ::std::string window_caption(window); + + void window_cursor(window, cursor); + cursor window_cursor(window); + + void activate_window(window); + + /// Determines whether the specified window will get the keyboard focus when its root window gets native system focus. + bool is_focus_ready(window); + + /// Returns the current keyboard focus window. + window focus_window(); + + /// Sets the keyboard focus for a specified window. + void focus_window(window); + + /// Returns a window which has grabbed the mouse input. + window capture_window(); + + /// Enables a window to grab the mouse input. + /** + * @param window_handle A handle to a window to grab the mouse input. + * @param ignore_children Indicates whether to redirect the mouse input to its children if the mouse pointer is over its children. + */ + void set_capture(window window_handle, bool ignore_children); + + /// Disable a window to grab the mouse input. + /** + * @param window handle A handle to a window to release grab of mouse input. + */ + void release_capture(window window_handle); + + /// Blocks the execution and other windows' messages until the specified window is closed. + void modal_window(window); + + /// Blocks the execution until the specified window is closed. + void wait_for(window); + + color fgcolor(window); + color fgcolor(window, const color&); + color bgcolor(window); + color bgcolor(window, const color&); + color activated_color(window); + color activated_color(window, const color&); + + void create_caret(window, const size&); + void destroy_caret(window); + + /// Opens an existing caret of a window. + /** + * This function returns an object to operate caret. The object doesn't create or destroy the caret. + * When you are finished with the caret, be sure to reset the pointer. + * + * @param window_handle A handle to a window whose caret is to be retrieved + * @return a pointer to the caret proxy. + * @except throws std::runtime if the window doesn't have a caret when disable_throw is false + */ + ::std::unique_ptr open_caret(window window_handle, bool disable_throw = false); + + /// Enables that the user can give input focus to the specified window using TAB key. + void tabstop(window); + + /// Enables or disables a window to receive a key_char event for pressing TAB key. + /* + * @param window_handle A handle to the window to catch TAB key through key_char event. + * @param enable Indicates whether to enable or disable catch of TAB key. If this parameter is *true*, the window + * receives a key_char event when pressing TAB key, and the input focus is not changed. If this parameter is *false*, the + * input focus is changed to the next tabstop window. + */ + void eat_tabstop(window window_handle, bool enable); + + /// Sets the input focus to the window which the tabstop is near to the specified window. + /* + * @param window_handle A handle to the window. + * @param forward Indicates whether forward or backward window to be given the input focus. + * @return A handle to the window which to be given the input focus. + */ + window move_tabstop(window window_handle, bool forward); + + /// Sets the window active state. If a window active state is false, the window will not obtain the focus when a mouse clicks on it which will be obtained by take_if_has_active_false. + void take_active(window, bool has_active, window take_if_has_active_false); + + /// Copies the graphics of a specified to a new graphics object. + bool window_graphics(window, nana::paint::graphics&); + bool root_graphics(window, nana::paint::graphics&); + bool get_visual_rectangle(window, nana::rectangle&); + + void typeface(window, const nana::paint::font&); + paint::font typeface(window); + + bool calc_screen_point(window, point&); ///); + + /// Returns a widget content extent size + /** + * @param wd A handle to a window that returns its content extent size. + * @param limited_px Specifies the max pixels of width or height. If this parameter is zero, this parameter will be ignored. + * @param limit_width Indicates whether the it limits the width or height. If this parameter is *true*, the width is limited. + * If the parameter is *false*, the height is limited. This parameter is ignored if limited_px = 0. + * @return if optional has a value, the first size indicates the content extent, the second size indicates the size of + * widget by the content extent. + */ + ::std::optional> content_extent(window wd, unsigned limited_px, bool limit_width); + + unsigned screen_dpi(bool x_requested); + + dragdrop_status window_dragdrop_status(::nana::window); +}//end namespace API + +}//end namespace nana + +#endif + diff --git a/GUI/nana/gui/screen.hpp b/GUI/nana/gui/screen.hpp new file mode 100644 index 0000000..06c344e --- /dev/null +++ b/GUI/nana/gui/screen.hpp @@ -0,0 +1,75 @@ +/* +* Screen Informations +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/screen.hpp +*/ + +#ifndef NANA_GUI_SCREEN_HPP +#define NANA_GUI_SCREEN_HPP +#include "basis.hpp" +#include +#include + +namespace nana +{ + /// The monitor display metrics + class display + { + public: + virtual ~display() = default; + + /// The index of monitor. + virtual std::size_t get_index() const = 0; + + virtual bool is_primary_monitor() const = 0; + + /// Returns the positional coordinates and size of the display device in reference to the desktop area + virtual const ::nana::rectangle& area() const = 0; + virtual const ::nana::rectangle& workarea() const = 0; + }; + + /// Provides some functions to get the metrics of the monitors \include screen.cpp + class screen + { + struct implement; + public: + /// gets the size in pixel of the whole virtual desktop + static ::nana::size desktop_size(); + + /// gets the resolution in pixel of the primary monitor, + /// if there is only one monitor installed in the system, + /// the return value of primary_monitor_size is equal to desktop_size's. + static ::nana::size primary_monitor_size(); + + + screen(); + + /// Reload has no preconditions, it's safe to call on moved-from + void reload(); + + /// Returns the number of display monitors installed in the system + std::size_t count() const; + + /// gets the display monitor that contains the specified point + display& from_point(const point&); + + /// gets the display monitor that contains the specified window + display& from_window(window); + + display& get_display(std::size_t index) const; + display& get_primary() const; + + /// applies a given function to all display monitors + void for_each(std::function) const; + private: + std::shared_ptr impl_; + }; +}//end namespace nana + +#endif diff --git a/GUI/nana/gui/state_cursor.hpp b/GUI/nana/gui/state_cursor.hpp new file mode 100644 index 0000000..139b621 --- /dev/null +++ b/GUI/nana/gui/state_cursor.hpp @@ -0,0 +1,28 @@ +/* + * State Cursor + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/state_cursor.hpp + */ + +#include +namespace nana +{ + class state_cursor + { + state_cursor(const state_cursor&) = delete; + state_cursor& operator=(const state_cursor&) = delete; + public: + state_cursor(window, cursor); + state_cursor(state_cursor&&); + state_cursor& operator=(state_cursor&&); + ~state_cursor(); + private: + window handle_; + }; +} \ No newline at end of file diff --git a/GUI/nana/gui/timer.hpp b/GUI/nana/gui/timer.hpp new file mode 100644 index 0000000..5973511 --- /dev/null +++ b/GUI/nana/gui/timer.hpp @@ -0,0 +1,74 @@ +/* + * A Timer Implementation + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/timer.hpp + * @description: + * A timer can repeatedly call a piece of code. The duration between + * calls is specified in milliseconds. Timer is different from other graphics + * controls, it has no graphics interface. + * + * @contributors: rbrugo(#417) + */ + +#ifndef NANA_GUI_TIMER_HPP +#define NANA_GUI_TIMER_HPP +#include +#include + +namespace nana +{ + + class timer; + + struct arg_elapse + : public event_arg + { + timer* sender; //indicates which timer emitted this notification + }; + + /// Can repeatedly call a piece of code. + class timer + { + struct implement; + + timer(const timer&) = delete; + timer& operator=(const timer&) = delete; + timer(timer&&) = delete; + timer& operator=(timer&&) = delete; + public: + timer(); + explicit timer(std::chrono::milliseconds ms); + ~timer(); + + template + void elapse(Function && fn) + { + elapse_->connect(std::forward(fn)); + } + + void reset(); + void start(); + bool started() const; + void stop(); + + void interval(std::chrono::milliseconds ms); + + template + inline Duration interval() const + { + return std::chrono::duration_cast(std::chrono::milliseconds{ _m_interval() }); + } + private: + unsigned _m_interval() const; + private: + std::shared_ptr> elapse_; + implement * const impl_; + }; +}//end namespace nana +#include +#endif diff --git a/GUI/nana/gui/tooltip.hpp b/GUI/nana/gui/tooltip.hpp new file mode 100644 index 0000000..89ec2c1 --- /dev/null +++ b/GUI/nana/gui/tooltip.hpp @@ -0,0 +1,76 @@ +/* + * A Tooltip Implementation + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/tooltip.hpp + */ + +#ifndef NANA_GUI_WIDGETS_TOOLTIP_HPP +#define NANA_GUI_WIDGETS_TOOLTIP_HPP +#include "widgets/widget.hpp" + +namespace nana +{ + ///tooltip_interface + ///An interface for user-defined tooltip window. + class tooltip_interface + { + public: + virtual ~tooltip_interface(){} + + virtual bool tooltip_empty() const = 0; + virtual nana::size tooltip_size() const = 0; + virtual void tooltip_text(const ::std::string&) = 0; + virtual void tooltip_move(const nana::point& screen_pos, bool ignore_pos) = 0; + virtual void duration(std::size_t) = 0; + }; + + class tooltip + { + class factory_interface + { + public: + virtual ~factory_interface(){} + virtual tooltip_interface* create() = 0; + virtual void destroy(tooltip_interface*) = 0; + }; + + template + class factory + : public factory_interface + { + tooltip_interface * create() override + { + return new TooltipWindow; + } + + void destroy(tooltip_interface* p) override + { + delete p; + } + }; + public: + typedef factory_interface factory_if_type; + + template + static void make_factory() + { + _m_hold_factory(new factory); + } + + tooltip() = default; + tooltip(window w, const ::std::string &tip){set(w,tip);} + + + static void set(window, const ::std::string&); + static void show(window, point pos, const ::std::string&, std::size_t duration); + static void close(); + private: + static void _m_hold_factory(factory_interface*); + };//class tooltip +}//namespace nana +#endif diff --git a/GUI/nana/gui/widgets/button.hpp b/GUI/nana/gui/widgets/button.hpp new file mode 100644 index 0000000..b2982ef --- /dev/null +++ b/GUI/nana/gui/widgets/button.hpp @@ -0,0 +1,123 @@ +/** + * A Button Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/button.hpp + * @contributor + * besh81(pr#361) + */ + +#ifndef NANA_GUI_WIDGET_BUTTON_HPP +#define NANA_GUI_WIDGET_BUTTON_HPP +#include "widget.hpp" +#include +#include + + +namespace nana{ + namespace drawerbase + { + namespace button + { + /// Draw the button + class trigger: public drawer_trigger + { + class measurer; + public: + trigger(); + ~trigger(); + + void emit_click(); + void icon(const nana::paint::image&); + bool enable_pushed(bool); + bool pushed(bool); + bool pushed() const; + void omitted(bool); + bool focus_color(bool); + + element::cite_bground & cite(); + private: + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void mouse_enter(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void key_press(graph_reference, const arg_keyboard&) override; + void focus(graph_reference, const arg_focus&) override; + private: + void _m_draw_title(graph_reference, bool enabled); + void _m_draw_background(graph_reference); + void _m_draw_border(graph_reference); + void _m_press(graph_reference, bool); + private: + widget* wdg_{nullptr}; + paint::graphics* graph_{nullptr}; + + element::cite_bground cite_{"button"}; + + std::unique_ptr measurer_; + + struct attr_tag + { + element_state e_state; + bool omitted; + bool focused; + bool pushed; + bool keep_pressed; + bool enable_pushed; + bool focus_color; + paint::image * icon; + ::nana::color bgcolor; + ::nana::color fgcolor; + }attr_; + }; + }//end namespace button + }//end namespace drawerbase + + /// Define a button widget and provides the interfaces to be operational + class button + : public widget_object + { + typedef widget_object base_type; + public: + button(); + button(window parent, bool visible); + button(window parent, const ::std::string& caption, bool visible = true); + button(window parent, const char* caption, bool visible = true); + button(window parent, const nana::rectangle& = rectangle(), bool visible = true); + + /// Shows an icon in front of caption + /** + * @param image Icon to be shown. If image is empty, the current icon is erased from the button. + * @return the reference of *this. + */ + button& icon(const nana::paint::image& image); + button& enable_pushed(bool); + bool pushed() const; + button& pushed(bool); + button& omitted(bool); ///< Enables/Disables omitting displaying the caption if the text is too long. + button& enable_focus_color(bool); ///< Enables/Disables showing the caption with a special color to indicate the button is focused. + + button& set_bground(const pat::cloneable&); ///< Sets a user-defined background element. + button& set_bground(const std::string&); ///< Sets a pre-defined background element by a name. + + button& transparent(bool enable); + bool transparent() const; + + button& edge_effects(bool enable); + private: + //Overrides widget virtual functions + void _m_complete_creation() override; + void _m_caption(native_string_type&&) override; + }; +}//end namespace nana +#include + +#endif + diff --git a/GUI/nana/gui/widgets/categorize.hpp b/GUI/nana/gui/widgets/categorize.hpp new file mode 100644 index 0000000..131f2a8 --- /dev/null +++ b/GUI/nana/gui/widgets/categorize.hpp @@ -0,0 +1,263 @@ +/** + * A Categorize Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/categorize.hpp + */ + +#ifndef NANA_GUI_WIDGET_CATEGORIZE_HPP +#define NANA_GUI_WIDGET_CATEGORIZE_HPP + +#include +#include +#include +#include + +namespace nana +{ + template class categorize; + + template + struct arg_categorize + : public event_arg + { + categorize & widget; + ValueType & value; + + arg_categorize(categorize & wdg, ValueType& v) + : widget(wdg), value(v) + {} + }; + + namespace drawerbase + { + namespace categorize + { + template + struct categorize_events + : public general_events + { + basic_event> selected; + }; + + class event_agent_interface + { + public: + virtual ~event_agent_interface(){} + virtual void selected(::nana::any&) = 0; + }; + + template + class event_agent + : public event_agent_interface + { + public: + event_agent(::nana::categorize& wdg) + : widget_(wdg) + {} + + void selected(::nana::any & var) + { + auto vp = any_cast(&var); + + T null_val; + arg_categorize arg(widget_, vp ? *vp : null_val); + widget_.events().selected.emit(arg, widget_.handle()); + } + private: + ::nana::categorize & widget_; + }; + + class renderer + { + public: + typedef nana::paint::graphics & graph_reference; + + struct ui_element + { + enum t + { + none, //Out of the widget + somewhere, item_root, item_name, item_arrow + }; + + t what; + std::size_t index; + + ui_element(); + }; + + virtual ~renderer() = 0; + virtual void background(graph_reference, window wd, const nana::rectangle&, const ui_element&) = 0; + virtual void root_arrow(graph_reference, const nana::rectangle&, mouse_action) = 0; + virtual void item(graph_reference, const nana::rectangle&, std::size_t index, const ::std::string& name, unsigned textheight, bool has_child, mouse_action) = 0; + virtual void border(graph_reference) = 0; + }; + + class trigger + : public drawer_trigger + { + class scheme; + public: + typedef renderer::ui_element ui_element; + + trigger(); + ~trigger(); + + void insert(const ::std::string&, nana::any); + bool childset(const ::std::string&, nana::any); + bool childset_erase(const ::std::string&); + bool clear(); + + //splitstr + //@brief: Sets the splitstr. If the parameter will be ignored if it is an empty string. + void splitstr(const ::std::string&); + const ::std::string& splitstr() const; + + void path(const ::std::string&); + ::std::string path() const; + + template + void create_event_agent(::nana::categorize& wdg) + { + event_agent_.reset(new event_agent(wdg)); + _m_event_agent_ready(); + } + + nana::any & value() const; + private: + void _m_event_agent_ready() const; + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + private: + std::unique_ptr event_agent_; + scheme * scheme_{nullptr}; + }; + }//end namespace categorize + }//end namespace drawerbase + + + + /// \brief Represent an architecture of categories and what category is chosen. + /// The categorize widget can be used for representing a path of a directory or the order of a hierarchy. + template + class categorize + : public widget_object> + { + public: + using native_string_type = widget::native_string_type; + using value_type = T; ///< The type of objects stored + using renderer = drawerbase::categorize::renderer; ///< The interface for user-defined renderer. + + categorize() + { + this->get_drawer_trigger().create_event_agent(*this); + } + + categorize(window wd, const rectangle& r = rectangle(), bool visible = true) + { + this->get_drawer_trigger().create_event_agent(*this); + this->create(wd, r, visible); + } + + categorize(window wd, bool visible) + : categorize(wd, ::nana::rectangle(), visible) + { + } + + categorize(window wd, const std::string& text_utf8, bool visible = true) + : categorize(wd, ::nana::rectangle(), visible) + { + this->caption(text_utf8); + } + + categorize(window wd, const char* text_utf8, bool visible = true) + : categorize(wd, ::nana::rectangle(), visible) + { + this->caption(text_utf8); + } + + categorize(window wd, const std::wstring& text, bool visible = true) + : categorize(wd, ::nana::rectangle(), visible) + { + this->caption(text); + } + + categorize(window wd, const wchar_t* text, bool visible = true) + : categorize(wd, ::nana::rectangle(), visible) + { + this->caption(text); + } + + /// Insert a new category with a specified name and the object of value type. + /// The new category would be inserted as a child in current category, + /// and after inserting, the new category is replaced of the current category as a new current one. + categorize& insert(const std::string& name, const value_type& value) + { + this->get_drawer_trigger().insert(name, value); + API::update_window(*this); + return *this; + } + + /// Inserts a child category into current category. + categorize& childset(const std::string& name, const value_type& value) + { + throw_not_utf8(name); + if(this->get_drawer_trigger().childset(name, value)) + API::update_window(*this); + return *this; + } + + /// Erases a child category with a specified name from current category. + categorize& childset_erase(const std::string& name) + { + if(this->get_drawer_trigger().childset_erase(name)) + API::update_window(*this); + return *this; + } + + void clear() + { + if(this->get_drawer_trigger().clear()) + API::update_window(*this); + } + + /// Sets the splitter string + categorize& splitstr(const std::string& sstr) + { + this->get_drawer_trigger().splitstr(sstr); + return *this; + } + + std::string splitstr() const + { + return this->get_drawer_trigger().splitstr(); + } + + /// Retrieves a reference of the current category's value type object. If current category is empty, it throws a exception of std::runtime_error. + value_type& value() const + { + return nana::any_cast(this->get_drawer_trigger().value()); + } + private: + //Overrides widget's virtual functions + void _m_caption(native_string_type&& str) override + { + this->get_drawer_trigger().path(to_utf8(str)); + API::dev::window_caption(*this, to_nstring(this->get_drawer_trigger().path()) ); + } + }; +}//end namespace nana +#include +#endif diff --git a/GUI/nana/gui/widgets/checkbox.hpp b/GUI/nana/gui/widgets/checkbox.hpp new file mode 100644 index 0000000..d5b6d25 --- /dev/null +++ b/GUI/nana/gui/widgets/checkbox.hpp @@ -0,0 +1,145 @@ +/** + * A CheckBox Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/checkbox.hpp + */ + +#ifndef NANA_GUI_WIDGET_CHECKBOX_HPP +#define NANA_GUI_WIDGET_CHECKBOX_HPP +#include + +#include "widget.hpp" +#include +#include + +namespace nana { + + //forward-declaration + class checkbox; + + struct arg_checkbox + : public event_arg + { + checkbox * const widget; + + arg_checkbox(checkbox* wdg) + : widget(wdg) + {} + }; + +namespace drawerbase +{ + namespace checkbox + { + struct scheme + : public widget_geometrics + { + color_proxy square_bgcolor{ static_cast(0x0) }; + color_proxy square_border_color{ colors::black }; + }; + + struct events_type + : public general_events + { + basic_event checked; + }; + + class drawer + : public drawer_trigger + { + struct implement; + public: + drawer(); + ~drawer(); //To instance imptr_; + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void mouse_enter(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + public: + implement * impl() const; + private: + static const int interval = 4; + implement * impl_; + }; + }//end namespace checkbox +}//end namespace drawerbase + + + class checkbox + : public widget_object + { + public: + checkbox(); + checkbox(window, bool visible); + checkbox(window, const std::string& text, bool visible = true); + checkbox(window, const char* text, bool visible = true); + checkbox(window, const rectangle& = rectangle(), bool visible = true); + + void element_set(const char* name); + void react(bool want); ///< Enables the reverse check while clicking on the checkbox. + bool checked() const; + + /// Checks/unchecks the checkbox + void check(bool state); + + /// \brief With the radio mode, users make a choice among a set of mutually exclusive, + /// related options. Users can choose one and only one option. + /// There is a helper class manages checkboxs for radio mode, + /// \see radio_group. + void radio(bool); + void transparent(bool value); + bool transparent() const; + };//end class checkbox + + /// for managing checkboxs in radio mode + class radio_group + { + struct element_tag + { + checkbox * uiobj; + event_handle eh_clicked; + event_handle eh_checked; + event_handle eh_destroy; + event_handle eh_keyboard; + }; + public: + constexpr static const std::size_t npos = static_cast(-1); + ~radio_group(); + void add(checkbox&); + + ///< Retrieves the index of checked option. It returns radio_group::npos if no checkbox is checked. + std::size_t checked() const; + std::size_t size() const; + + template + void on_clicked(Function&& click_fn) + { + for (auto & e : ui_container_) + { + e.uiobj->events().click(std::move(click_fn)); + } + } + + template + void on_checked(Function&& check_fn) + { + for (auto & e : ui_container_) + { + e.uiobj->events().checked(std::move(check_fn)); + } + } + private: + std::vector ui_container_; + }; +}//end namespace nana +#include + +#endif diff --git a/GUI/nana/gui/widgets/combox.hpp b/GUI/nana/gui/widgets/combox.hpp new file mode 100644 index 0000000..cf4d609 --- /dev/null +++ b/GUI/nana/gui/widgets/combox.hpp @@ -0,0 +1,223 @@ +/** + * A Combox Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/combox.hpp + */ + +#ifndef NANA_GUI_WIDGETS_COMBOX_HPP +#define NANA_GUI_WIDGETS_COMBOX_HPP +#include +#include "widget.hpp" +#include "float_listbox.hpp" +#include "skeletons/text_editor_part.hpp" +#include +#include +#include + +namespace nana +{ + /// A list box combined with a textbox - the list box should drop down when the user selects the arrow next to the control + class combox; + + struct arg_combox + : public event_arg + { + combox & widget; + arg_combox(combox&); + }; + + namespace drawerbase + { + namespace combox + { + struct combox_events + : public general_events + { + basic_event selected; + basic_event text_changed; + }; + + class drawer_impl; + + class trigger + : public drawer_trigger + { + public: + trigger(); + ~trigger(); + + drawer_impl& get_drawer_impl(); + const drawer_impl& get_drawer_impl() const; + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void focus(graph_reference, const arg_focus&) override; + void mouse_enter(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_wheel(graph_reference, const arg_wheel&) override; + void key_ime(graph_reference, const arg_ime&) override; + void key_press(graph_reference, const arg_keyboard&) override; + void key_char(graph_reference, const arg_keyboard&) override; + private: + drawer_impl * const drawer_; + }; + + class item_proxy + : public std::iterator + { + public: + item_proxy(drawer_impl*, std::size_t pos); + item_proxy& text(const ::std::string&); + + ::std::string text() const; + item_proxy& select(); + bool selected() const; + item_proxy& icon(const nana::paint::image&); + nana::paint::image icon() const; + + template + T * value_ptr() const + { + return any_cast(_m_anyobj(false)); + } + + template + T & value() const + { + auto * pany = _m_anyobj(false); + if (nullptr == pany) + throw std::runtime_error("combox::item_proxy.value() is empty"); + + T * p = any_cast(pany); + if (nullptr == p) + throw std::runtime_error("combox::item_proxy.value() invalid type of value"); + return *p; + } + + template + item_proxy& value(T&& val) + { + *_m_anyobj(true) = ::std::forward(val); + return *this; + } + public: + /// Behavior of Iterator's value_type +#ifdef _nana_std_has_string_view + bool operator==(::std::string_view) const; +#else + bool operator==(const ::std::string&) const; + bool operator==(const char*) const; +#endif + + /// Behavior of Iterator + item_proxy & operator=(const item_proxy&); + + /// Behavior of Iterator + item_proxy & operator++(); + + /// Behavior of Iterator + item_proxy operator++(int); + + /// Behavior of Iterator + item_proxy& operator*(); + + /// Behavior of Iterator + const item_proxy& operator*() const; + + /// Behavior of Iterator + item_proxy* operator->(); + + /// Behavior of Iterator + const item_proxy* operator->() const; + + /// Behavior of Iterator + bool operator==(const item_proxy&) const; + + /// Behavior of Iterator + bool operator!=(const item_proxy&) const; + private: + nana::any * _m_anyobj(bool alloc_if_empty) const; + private: + drawer_impl * impl_; + std::size_t pos_; + }; + }//end namespace combox + }//end namespace drawerbase + + class combox + : public widget_object, + public nana::concepts::any_objective + { + public: + typedef float_listbox::item_renderer item_renderer; + typedef drawerbase::combox::item_proxy item_proxy; + + combox(); + combox(window, bool visible); + combox(window, ::std::string, bool visible = true); + combox(window, const char*, bool visible = true); + combox(window, const rectangle& r = rectangle(), bool visible = true); + + void clear(); + void editable(bool); + bool editable() const; + void set_accept(std::function); + combox& push_back(std::string); + std::size_t the_number_of_options() const; + std::size_t option() const; ///< Index of the last selected, from drop-down list, item. + void option(std::size_t); ///< Select the text specified by index + ::std::string text(std::size_t) const; + void erase(std::size_t pos); + + template + item_proxy operator[](const Key& kv) + { + typedef typename nana::detail::type_escape::type key_t; + std::shared_ptr p(new nana::key >(kv), [](nana::detail::key_interface*p) + { + delete p; + }); + + return _m_at_key(std::move(p)); + } + + template + void erase_key(Key&& kv) + { + typedef typename nana::detail::type_escape::type key_t; + std::unique_ptr p(new nana::key >(std::forward(kv))); + _m_erase(p.get()); + } + + /// \brief Set user-defined item renderer object. + /// It is an address therefore the user should not destroy the renderer object + /// after it is set to the combox. Passing null_ptr cancels the user-defined renderer object. + void renderer(item_renderer*); + + void image(std::size_t, const nana::paint::image&); + nana::paint::image image(std::size_t) const; + void image_pixels(unsigned); ///&&); + void _m_erase(nana::detail::key_interface*); + drawerbase::combox::drawer_impl & _m_impl(); + const drawerbase::combox::drawer_impl& _m_impl() const; + private: + //Overrides widget's virtual functions + native_string_type _m_caption() const noexcept override; + void _m_caption(native_string_type&&) override; + nana::any * _m_anyobj(std::size_t pos, bool alloc_if_empty) const override; + }; +} +#include +#endif diff --git a/GUI/nana/gui/widgets/date_chooser.hpp b/GUI/nana/gui/widgets/date_chooser.hpp new file mode 100644 index 0000000..3d138fa --- /dev/null +++ b/GUI/nana/gui/widgets/date_chooser.hpp @@ -0,0 +1,84 @@ +/** + * A date chooser Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/date_chooser.hpp + */ + +#ifndef NANA_GUI_WIDGETS_DATE_CHOOSER_HPP +#define NANA_GUI_WIDGETS_DATE_CHOOSER_HPP +#include +#include "widget.hpp" +#include + +namespace nana +{ + class date_chooser; + + struct arg_datechooser + : public event_arg + { + date_chooser * const widget; + + arg_datechooser(date_chooser* wdg) + : widget(wdg) + {} + }; + + namespace drawerbase + { + namespace date_chooser + { + struct date_chooser_events + : public general_events + { + + basic_event date_changed; + }; + + class trigger : public drawer_trigger + { + class model; + public: + static const int topbar_height = 34; + static const int border_size = 3; + + trigger(); + ~trigger(); + model* get_model() const; + private: + void refresh(graph_reference) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void key_press(graph_reference, const arg_keyboard&) override; + private: + model * model_; + }; + + }//end namespace date_chooser + + }//end namespace drawerbase + + /// \see nana::date + class date_chooser + : public widget_object + { + public: + date_chooser(); + date_chooser(window, bool visible); + date_chooser(window, const nana::rectangle& r = rectangle(), bool visible = true); + + bool chose() const; + nana::date read() const; + void weekstr(unsigned index, ::std::string);/// + +#endif diff --git a/GUI/nana/gui/widgets/detail/compset.hpp b/GUI/nana/gui/widgets/detail/compset.hpp new file mode 100644 index 0000000..363bb6a --- /dev/null +++ b/GUI/nana/gui/widgets/detail/compset.hpp @@ -0,0 +1,87 @@ +/* + * Concept of Component Set + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/detail/compset.hpp + */ + +#ifndef NANA_GUI_WIDGETS_DETAIL_COMPSET_HPP +#define NANA_GUI_WIDGETS_DETAIL_COMPSET_HPP + +#include + +namespace nana{ namespace widgets{ namespace detail +{ + /// A component set used for accessing the components of items of a widget. + template + class compset + { + public: + /// A type of widget-defined components. + typedef Component component_t; + + /// A type of widget-defined item attribute. + typedef ItemAttribute item_attribute_t; + + /// A type of a componenet state for rendering. + struct comp_attribute_t + { + nana::rectangle area; + bool mouse_pointed; + }; + + public: + /// The destrcutor + virtual ~compset(){} + + /// Access the widget-defined item attribute. + virtual const item_attribute_t& item_attribute() const = 0; + + /// Access a specified component of the item. + virtual bool comp_attribute(component_t, comp_attribute_t &) const = 0; + }; + + /// A component set placer used for specifying component position and size. + template + class compset_placer + { + public: + typedef ::nana::paint::graphics & graph_reference; + /// A type of widget-defined components. + typedef Component component_t; + + /// A type of widget-defined item attribute. + typedef ItemAttribute item_attribute_t; + + /// Widget scheme. + typedef WidgetScheme widget_scheme_t; + public: + /// The destructor. + virtual ~compset_placer(){} + + /// Enable/Disable the specified component. + virtual void enable(component_t, bool) = 0; + virtual bool enabled(component_t) const = 0; + + /// Height of an item, in pixels. + // this method is content-indepented, this feature is easy for implementation. + virtual unsigned item_height(graph_reference) const = 0; + + /// Width of an item, in pixels + virtual unsigned item_width(graph_reference, const item_attribute_t&) const = 0; + + /// Locate a component through the specified coordinate. + /// @param comp the component of the item. + /// @param attr the attribute of the item. + /// @param r the pointer refers to a rectangle for receiving the position and size of the component. + /// @returns the true when the component is located by the locator. + virtual bool locate(component_t comp, const item_attribute_t& attr, rectangle * r) const = 0; + }; +}//end namespace detail +}//end namespace widgets +}//end namespace nana +#endif diff --git a/GUI/nana/gui/widgets/detail/inline_widget.hpp b/GUI/nana/gui/widgets/detail/inline_widget.hpp new file mode 100644 index 0000000..875c294 --- /dev/null +++ b/GUI/nana/gui/widgets/detail/inline_widget.hpp @@ -0,0 +1,94 @@ +/** + * A Inline Widget Interface Definition + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/detail/inline_widget.hpp + * + */ + +#ifndef NANA_GUI_INLINE_WIDGETS_HPP +#define NANA_GUI_INLINE_WIDGETS_HPP +#include "../../basis.hpp" + +namespace nana +{ + namespace detail + { + template + class inline_widget_indicator + { + public: + /// A type to index a item + using index_type = Index; + + /// A type to the value of the item + using value_type = Value; + + /// The destructor + virtual ~inline_widget_indicator() = default; + + /// Returns the host widget of the indicator + virtual ::nana::widget& host() const = 0; + + /// Returns the position of column + virtual std::size_t column() const = 0; + + /// Modifies the value of a item specified by pos + virtual void modify(index_type pos, const value_type&) const = 0; + + /// Sends a signal that a specified item is selected + virtual void selected(index_type) = 0; + + /// Sends a signal that a specified item is hovered + virtual void hovered(index_type) = 0; + }; + + template + class inline_widget_notifier_interface + { + public: + /// A type to index a item + using index_type = Index; + + /// A type to the value of the item + using value_type = Value; + + /// A type to the status + using status_type = Status; + + /// A typedef name of a inline widget indicator + using inline_indicator = inline_widget_indicator; + + /// A type to the notifier interface that will be refered by the abstract factory pattern + using factory_interface = inline_widget_notifier_interface; + + /// The destructor + virtual ~inline_widget_notifier_interface() = default; + + /// A message to create the inline widget + virtual void create(window) = 0; + + /// A message to activate the inline widget to attach a specified item + virtual void activate(inline_indicator&, index_type) = 0; + + /// A message to change the status + virtual void notify_status(status_type, bool) = 0; + + /// A message to resize the inline widget + virtual void resize(const size&) = 0; + + /// A message to set the value from the item + virtual void set(const value_type&) = 0; + + /// Determines whether to draw the background of the widget + virtual bool whether_to_draw() const = 0; + }; //end class inline_widget_notifier_interface + } +} + +#endif \ No newline at end of file diff --git a/GUI/nana/gui/widgets/detail/inline_widget_manager.hpp b/GUI/nana/gui/widgets/detail/inline_widget_manager.hpp new file mode 100644 index 0000000..ef5ec65 --- /dev/null +++ b/GUI/nana/gui/widgets/detail/inline_widget_manager.hpp @@ -0,0 +1,89 @@ +/** + * A Inline Widget Manager Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/detail/inline_widget_manager.hpp + * + */ + +#ifndef NANA_GUI_INLINE_WIDGET_MANAGER_HPP +#define NANA_GUI_INLINE_WIDGET_MANAGER_HPP +#include "inline_widget.hpp" +#include +#include "../panel.hpp" + +#include + +namespace nana +{ + namespace detail + { + + template + class inline_widget_manager + { + using index_type = Index; + using value_type = Value; + using indicator_type = inline_widget_indicator; + using inline_widget = inline_widget_interface; + using factory = pat::abstract_factory; + + struct widget_holder + { + panel docker; + std::unique_ptr widget_ptr; + }; + public: + void set_window(window wd) + { + window_handle_ = wd; + } + + void set_factory(std::unique_ptr fac) + { + factory_.swap(fac); + } + + void place(point pos, const size& dimension, const size & visible_size, const indicator_type& indicator, index_type index) + { + auto holder = _m_append(); + holder->docker.move({ pos, visible_size }); + holder->widget_ptr->move({ point(), dimension }); + + holder->widget_ptr->activate(indicator, index); + } + private: + widget_holder* _m_append() + { + if (swap_widgets_.empty()) + { + widgets_.emplace_back(); + widgets_.back().swap(swap_widgets_.back()); + swap_widgets_.pop_back(); + } + else + { + + widgets_.emplace_back(new widget_holder); + auto & holder = widgets_.back(); + holder->docker.create(window_handle_, false); + holder->widget_ptr.swap(factory_->create()); + holder->widget_ptr->create(holder->docker->handle()); + } + return widgets_.back().get(); + } + private: + window window_handle_{nullptr}; + std::unique_ptr factory_; + std::vector> widgets_; + std::vector> swap_widgets_; + }; + } +} + +#endif diff --git a/GUI/nana/gui/widgets/detail/tree_cont.hpp b/GUI/nana/gui/widgets/detail/tree_cont.hpp new file mode 100644 index 0000000..fad5d66 --- /dev/null +++ b/GUI/nana/gui/widgets/detail/tree_cont.hpp @@ -0,0 +1,532 @@ +/* + * A Tree Container class implementation + * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/detail/tree_cont.hpp + */ + +#ifndef NANA_GUI_WIDGETS_DETAIL_TREE_CONT_HPP +#define NANA_GUI_WIDGETS_DETAIL_TREE_CONT_HPP +#include +#include + +namespace nana +{ +namespace widgets +{ +namespace detail +{ + template + struct tree_node + { + typedef std::pair value_type; + + value_type value; + + tree_node *owner; + tree_node *next; + tree_node *child; + + tree_node(tree_node* owner) + :owner(owner), next(nullptr), child(nullptr) + {} + + ~tree_node() + { + if(owner) + { + tree_node * t = owner->child; + if(t != this) + { + while(t->next != this) + t = t->next; + t->next = next; + } + else + owner->child = next; + } + + tree_node * t = child; + while(t) + { + tree_node * t_next = t->next; + delete t; + t = t_next; + } + } + + bool is_ancestor_of(const tree_node* child) const + { + while (child) + { + if (child == this) + return true; + + child = child->owner; + } + return false; + } + + tree_node * front() const + { + if (this->owner && (this != this->owner->child)) + { + auto i = this->owner->child; + while (i->next != this) + i = i->next; + + return i; + } + return nullptr; + } + }; + + template + class tree_cont + { + typedef tree_cont self_type; + + public: + typedef UserData element_type; + typedef tree_node node_type; + typedef typename node_type::value_type value_type; + + enum class enum_order + { + stop, //Stop enumeration + proceed_with_children, + proceed + }; + + tree_cont() + :root_(nullptr) + {} + + ~tree_cont() + { + clear(&root_); + } + + void clear(node_type* node) + { + while (node->child) + { + //If there is a sibling of child, the root_.child + //will be assigned with the sibling. + remove(node->child); + } + } + + bool verify(const node_type* node) const + { + if(node) + { + while(node->owner) + { + if(node->owner == &root_) + return true; + + node = node->owner; + } + } + return false; + } + + node_type* get_root() const + { + return &root_; + } + + node_type* get_owner(const node_type* node) const + { + return (verify(node) && (node->owner != &root_) ? node->owner : nullptr); + } + + node_type * node(node_type* node, const std::string& key) + { + if(node) + { + for(node_type * child = node->child; child; child = child->next) + { + if(child->value.first == key) + return child; + } + } + return nullptr; + } + + node_type* insert(node_type* node, const std::string& key, const element_type& elem) + { + if(nullptr == node) + return insert(key, elem); + + if(verify(node)) + { + node_type **new_node_ptr; + if(node->child) + { + node_type* child = node->child; + for(; child; child = child->next) + { + if(child->value.first == key) + { + child->value.second = elem; + return child; + } + } + + child = node->child; + while(child->next) + child = child->next; + + new_node_ptr = &(child->next); + } + else + new_node_ptr = &(node->child); + + *new_node_ptr = new node_type(node); + + (*new_node_ptr)->value.first = key; + (*new_node_ptr)->value.second = elem; + return (*new_node_ptr); + } + return nullptr; + } + + node_type* insert(const std::string& key, const element_type& elem) + { + auto node = _m_locate(key); + + //Doesn't return the root node + if (node == &root_) + return nullptr; + + if(node) + node->value.second = elem; + return node; + } + + void remove(node_type* node) + { + if(verify(node)) + delete node; + } + + node_type* find(const std::string& path) const + { + auto p = _m_locate(path); + return (&root_ == p ? nullptr : p); + } + + node_type* ref(const std::string& path) + { + auto p = _m_locate(path); + return (&root_ == p ? nullptr : p); + } + + unsigned indent_size(const node_type* node) const + { + if(node) + { + unsigned indent = 0; + for(;(node = node->owner); ++indent) + { + if(node == &root_) return indent; + } + } + return 0; + } + + template + void for_each(node_type* node, Functor f) const + { + if(nullptr == node) node = root_.child; + int state = 0; //0: Sibling, the last is a sibling of node + //1: Owner, the last is the owner of node + //>= 2: Children, the last is is a child of the node that before this node. + while(node) + { + enum_order order = f(*node, state); + + if (enum_order::stop == order) + { + return; + } + else if (node->child && (enum_order::proceed_with_children == order)) + { + node = node->child; + state = 1; + } + else if(node->next) + { + node = node->next; + state = 0; + } + else + { + state = 1; + if(node == &root_) return; + + while(true) + { + ++state; + if(node->owner->next) + { + node = node->owner->next; + break; + } + else + node = node->owner; + + if(node == &root_) return; + } + } + } + } + + template + unsigned child_size_if(const ::std::string& key, PredAllowChild pac, PredAllowNode pan) const + { + auto node = _m_locate(key); + return (node ? child_size_if(*node, pac, pan) : 0); + } + + template + unsigned child_size_if(const node_type& node, PredAllowChild pac, PredAllowNode pan) const + { + unsigned size = 0; + const node_type* pnode = node.child; + while(pnode) + { + if (!pan(*pnode)) + { + pnode = pnode->next; + continue; + } + + ++size; + if(pnode->child && pac(*pnode)) + size += child_size_if(*pnode, pac, pan); + + pnode = pnode->next; + } + return size; + } + + template + std::size_t distance_if(const node_type * node, PredAllowChild pac, PredAllowNode pan) const + { + if(nullptr == node) return 0; + const node_type * iterator = root_.child; + + std::size_t off = 0; + std::stack stack; + + while(iterator && iterator != node) + { + if (!pan(*iterator)) + { + iterator = iterator->next; + continue; + } + + ++off; + + if(iterator->child && pac(*iterator)) + { + stack.push(iterator); + iterator = iterator->child; + } + else + iterator = iterator->next; + + while((nullptr == iterator) && stack.size()) + { + iterator = stack.top()->next; + stack.pop(); + } + } + return off; + } + + template + node_type* advance_if(node_type* node, std::size_t off, PredAllowChild pac, PredAllowNode pan) + { + if(nullptr == node) node = root_.child; + + std::stack stack; + + while(node && off) + { + if (!pan(*node)) + { + node = node->next; + continue; + } + + --off; + if(node->child && pac(*node)) + { + stack.push(node); + node = node->child; + } + else + node = node->next; + + while(nullptr == node && stack.size()) + { + node = stack.top(); + stack.pop(); + node = node->next; + } + } + + return node; + } + private: + //Functor defintions + + struct each_make_node + { + each_make_node(self_type& self) + :node(&(self.root_)) + {} + + bool operator()(const ::std::string& key_node) + { + node_type *child = node->child; + node_type *tail = nullptr; + while(child) + { + if(key_node == child->value.first) + { + node = child; + return true; + } + tail = child; + child = child->next; + } + + child = new node_type(node); + if(tail) + tail->next = child; + else + node->child = child; + + child->value.first = key_node; + node = child; + return true; + } + + node_type * node; + }; + + + struct find_key_node + { + find_key_node(const self_type& self) + :node(&self.root_) + {} + + bool operator()(const ::std::string& key_node) + { + return ((node = _m_find(node->child, key_node)) != nullptr); + } + + node_type *node; + }; + private: + static node_type* _m_find(node_type* node, const ::std::string& key_node) + { + while(node) + { + if(key_node == node->value.first) + return node; + + node = node->next; + } + return nullptr; + } + + template + void _m_for_each(const ::std::string& key, Function function) const + { + //Ignores separaters at the begin of key. + auto beg = key.find_first_not_of("\\/"); + if (key.npos == beg) + return; + + auto end = key.find_first_of("\\/", beg); + + + while(end != ::std::string::npos) + { + if(beg != end) + { + if(!function(key.substr(beg, end - beg))) + return; + } + + auto next = key.find_first_not_of("\\/", end); + + if ((next == ::std::string::npos) && end) + return; + + if (0 == end) + { + if ((!function(key.substr(0, 1))) || (next == ::std::string::npos)) + return; + } + + beg = next; + end = key.find_first_of("\\/", beg); + + } + + function(key.substr(beg, key.size() - beg)); + } + + template + node_type* _m_locate(const ::std::string& key) + { + if(key.size()) + { + if(CreateIfNotExists) + { + each_make_node emn(*this); + _m_for_each(key, emn); + return emn.node; + } + else + { + find_key_node fkn(*this); + _m_for_each(key, fkn); + return const_cast(fkn.node); + } + } + return &root_; + } + + node_type* _m_locate(const std::string& key) const + { + if(key.size()) + { + find_key_node fkn(*this); + _m_for_each(key, fkn); + return fkn.node; + } + return &root_; + } + private: + mutable node_type root_; + };//end class tree_cont +}//end namespace detail +}//end namespace widgets +}//end namesace nana + +#include +#endif diff --git a/GUI/nana/gui/widgets/detail/widget_iterator.hpp b/GUI/nana/gui/widgets/detail/widget_iterator.hpp new file mode 100644 index 0000000..6f8945e --- /dev/null +++ b/GUI/nana/gui/widgets/detail/widget_iterator.hpp @@ -0,0 +1,37 @@ +/* + * A Widget Iterator Template + * Copyright(C) 2017-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/detail/widget_iterator.hpp + * @description: widget_iterator is the base class provided to simplify definitions of the required types for widget iterators. + * It is provided because of deprecation of std::iterator in C++17 + */ +#ifndef NANA_GUI_WIDGET_ITERATOR_INCLUDED +#define NANA_GUI_WIDGET_ITERATOR_INCLUDED + +#include //provides std::ptrdiff_t + + +namespace nana { + namespace widgets { + namespace detail + { + template + class widget_iterator + { + public: + using iterator_category = Category; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T * ; + using reference = T & ; + }; + } + } +} + +#endif diff --git a/GUI/nana/gui/widgets/float_listbox.hpp b/GUI/nana/gui/widgets/float_listbox.hpp new file mode 100644 index 0000000..ac84284 --- /dev/null +++ b/GUI/nana/gui/widgets/float_listbox.hpp @@ -0,0 +1,109 @@ +/** + * A float_listbox Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/float_listbox.hpp + */ + +#ifndef NANA_GUI_WIDGETS_FLOAT_LISTBOX_HPP +#define NANA_GUI_WIDGETS_FLOAT_LISTBOX_HPP +#include + +#include "widget.hpp" +#include +#include + +namespace nana +{ + namespace drawerbase{ + namespace float_listbox + { + class item_interface + { + public: + virtual ~item_interface(){} + + virtual const nana::paint::image & image() const = 0; + virtual const char* text() const = 0; + }; + + //struct module_def + //@brief: This defines a data structure used for float_listbox + struct module_def + { + std::vector> items; + + std::size_t max_items{ 10 }; // the number of items display. + mutable std::size_t index{ ::nana::npos }; // the result of the selection. + mutable bool have_selected{ false }; + }; + + class item_renderer + { + public: + using widget_reference = widget&; + using graph_reference = paint::graphics&; + using item_interface = float_listbox::item_interface; + + enum state_t{StateNone, StateHighlighted}; + + virtual ~item_renderer() = default; + virtual void image(bool enabled, unsigned pixels) = 0; + virtual void render(widget_reference, graph_reference, const nana::rectangle&, const item_interface*, state_t) = 0; + virtual unsigned item_pixels(graph_reference) const = 0; + }; + + class drawer_impl; + + class trigger + : public drawer_trigger + { + public: + trigger(); + ~trigger(); + drawer_impl& get_drawer_impl(); + const drawer_impl& get_drawer_impl() const; + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + private: + class drawer_impl *drawer_; + }; + } + }//end namespace drawerbase + + class float_listbox + : public widget_object + { + typedef widget_object base_type; + public: + typedef drawerbase::float_listbox::item_renderer item_renderer; + typedef drawerbase::float_listbox::module_def module_type; + typedef drawerbase::float_listbox::item_interface item_interface; + + /** @brief Constructor + * @param window A handle to a window which is a owner of float_listbox + * @param rectangle A position and a size of float_listbox + * @param is_ignore_first_mouse_up The flost_listbox will be closed when a mouse_up is emitted, this parameter is specified for ignoring the first mouse_up emitting. + * @remark The float_listbox can be pop-upped in a mouse_down event, the next mouse_up may be ignored, otherwise the float_listbox will be closed when user releases the button. + */ + float_listbox(window, const rectangle&, bool is_ignore_first_mouse_up); + + void set_module(const module_type&, unsigned image_pixels); + void scroll_items(bool upwards); + void move_items(bool upwards, bool circle); + void renderer(item_renderer*); + std::size_t index() const; + }; +} +#include + +#endif diff --git a/GUI/nana/gui/widgets/form.hpp b/GUI/nana/gui/widgets/form.hpp new file mode 100644 index 0000000..f17f107 --- /dev/null +++ b/GUI/nana/gui/widgets/form.hpp @@ -0,0 +1,95 @@ +/** + * A Form Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/gui/widgets/form.hpp + */ + +#ifndef NANA_GUI_WIDGET_FORM_HPP +#define NANA_GUI_WIDGET_FORM_HPP + +#include "widget.hpp" +#include + +namespace nana +{ + class place; + + namespace drawerbase + { + namespace form + { + class trigger: public drawer_trigger + { + public: + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + private: + widget* wd_{nullptr}; + }; + + class form_base + : public widget_object + { + public: + form_base(window owner, bool nested, const rectangle&, const appearance&); + + //place methods + + place & get_place(); + void div(std::string div_text); + place::field_reference operator[](const char* field_name); + void collocate() noexcept; + private: + std::unique_ptr place_; + }; + }//end namespace form + }//end namespace drawerbase + + /// The form widget represents a popup window. + /// + /// Overall it is a root widget (\see: Overview of widgets) which attaches the OS/Windowing system's native window. + /// It is different from other window widgets in that its default constructor creates the window. + /// \see nana::appearance + class form + : public drawerbase::form::form_base + { + public: + /// helper template class for creating the appearance of the form. + using appear = ::nana::appear; + + /// Creates a window form owned by the desktop, at the point and size specified by rect, and with the specified appearance. + explicit form(const rectangle& = API::make_center(300, 200), const appearance& = {}); //Default constructor + /// Creates a window always floating above its owner at the point and size specified by rect, with the specified appearance. This window is always floating above its owner. + explicit form(window owner, const ::nana::size& = { 300, 200 }, const appearance& = {}); + explicit form(window owner, const rectangle&, const appearance& = {}); + form(const form&, const ::nana::size& = { 300, 200 }, const appearance& = {}); //Copy constructor + + /// Blocks the execution and other windows' messages until this window is closed. + void modality() const; + + /// Blocks the execution until this window is closed. + void wait_for_this(); + + void keyboard_accelerator(const accel_key&, const std::function& fn); + }; + + class nested_form + : public drawerbase::form::form_base + { + public: + using appear = ::nana::appear; + + nested_form(const form&, const rectangle& = {}, const appearance& = {}); + nested_form(const nested_form&, const rectangle& = {}, const appearance& = {}); + + nested_form(window, const appearance&); + nested_form(window, const rectangle& = {}, const appearance& = {}); + }; +}//end namespace nana +#endif diff --git a/GUI/nana/gui/widgets/group.hpp b/GUI/nana/gui/widgets/group.hpp new file mode 100644 index 0000000..139f7f1 --- /dev/null +++ b/GUI/nana/gui/widgets/group.hpp @@ -0,0 +1,132 @@ +/** + * A group widget implementation + * Nana C++ Library(http://www.nanaro.org) + * Copyright(C) 2015-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/group.hpp + * + * @Author: Stefan Pfeifer(st-321), Ariel Vina-Rodriguez (qPCR4vir) + * + * @brief group is a widget used to visually group and layout other widgets. + */ + +#ifndef NANA_GUI_WIDGETS_GROUP_HPP +#define NANA_GUI_WIDGETS_GROUP_HPP + +#include +#include +#include + +namespace nana{ + + namespace drawerbase + { + namespace group + { + struct scheme : public nana::widget_geometrics + { + color_proxy border{ colors::gray_border }; + }; + }// end namespace panel + }//end namespace drawerbase + + class group + : public widget_object + { + struct implement; + public: + using field_reference = place::field_reference; + constexpr static const std::size_t npos = static_cast(-1); + + enum class background_mode + { + none, + transparent, + blending + }; + + /// The default construction + group(); + + /// The construction that creates the widget + group(window parent, const rectangle& = {}, bool visible = true); + + /// The construction that creates the widget and set the title or caption + group(window parent, ///< a handle to the parent + ::std::string title, ///< caption of the group + bool formatted = false, ///< Enable/disable the formatted text for the title + unsigned gap = 2, ///< between the content and the external limit + const rectangle& r = {} , + bool visible = true + ); + + + /// The destruction + ~group(); + + /// Adds an option for user selection + checkbox& add_option(::std::string); + + /// Modifies the alignment of the title + group& caption_align(align position); + group& caption_background_mode(background_mode mode); + + /// Enables/disables the radio mode which is single selection + group& radio_mode(bool); + + /// Returns the index of selected option in radio_mode, it throws a logic_error if radio_mode is false. + std::size_t option() const; + + /** Set check/unchecked status of specified option + @param[in] pos zero-based index of option to set + @param[in] check status required, defaults to checked + throws an out_of_range if !(pos < number of options) + */ + void option_check( std::size_t pos, bool check = true ); + + /// Determines whether a specified option is checked, it throws an out_of_range if !(pos < number of options) + bool option_checked(std::size_t pos) const; + + /// Change typeface of caption label ( does not effect child widgets ) + void typeface( const nana::paint::font& font ); + + group& enable_format_caption(bool format); + + group& collocate() noexcept; + + /// this will set the `usr_div_str` for an internal field, called the "user field". + /// The "full" `place` of a `group` widget is internally divided into a field for the title, + /// a field for the added "options" and a field for "user" widgets. + group& div(const char* div_str) noexcept; + field_reference operator[](const char* field); + + void field_display(const char* field_name, bool display); /// + Widget* create_child(const char* field, Args && ... args) + { + auto wdg = new Widget(handle(), std::forward(args)...); + _m_add_child(field, wdg); + return wdg; + } + private: + void _m_add_child(const char* field, widget*); + void _m_init(); + void _m_complete_creation() override; + native_string_type _m_caption() const noexcept override; + void _m_caption(native_string_type&&) override; + private: + std::unique_ptr impl_; + }; + +}//end namespace nana +#endif diff --git a/GUI/nana/gui/widgets/label.hpp b/GUI/nana/gui/widgets/label.hpp new file mode 100644 index 0000000..09d990e --- /dev/null +++ b/GUI/nana/gui/widgets/label.hpp @@ -0,0 +1,86 @@ +/** + * A Label Control Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/label.hpp + */ + +#ifndef NANA_GUI_WIDGET_LABEL_HPP +#define NANA_GUI_WIDGET_LABEL_HPP + +#include "widget.hpp" +#include + +namespace nana +{ + namespace drawerbase + { + namespace label + { + enum class command /// Defines the event type for format listener. + { + enter, leave, click + }; + + /// draw the label + class trigger: public drawer_trigger + { + public: + struct implement; + + trigger(); + ~trigger(); + implement * impl() const; + private: + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void click(graph_reference, const arg_click&) override; + private: + implement * impl_; + }; + + }//end namespace label + }//end namespace drawerbase + + class label + : public widget_object + { + label(const label&) = delete; + label(label&&) = delete; + public: + typedef drawerbase::label::command command; + label(); + label(window, bool visible); + label(window, const std::string& text, bool visible = true); + label(window parent, const char* text, bool visible = true) :label(parent, std::string(text),visible) {}; + label(window, const rectangle& = {}, bool visible = true); + label& transparent(bool); ///< Switchs the label widget to the transparent background mode. + bool transparent() const noexcept; + label& format(bool); ///< Switches the format mode of the widget. + label& add_format_listener(std::function); + + /// as same as the HTML "for" attribute of a label + label& click_for(window associated_window) noexcept; + + /// Returns the size of the text. If *allowed_width_in_pixel* is not zero, returns a + /// "corrected" size that changes lines to fit the text into the specified width + nana::size measure(unsigned allowed_width_in_pixel) const; + + static ::nana::size measure(::nana::paint::graphics&, const ::std::string&, unsigned allowed_width_in_pixel, bool format_enabled, align h_align, align_v v_align); + + label& text_align(align horizontal_align, align_v vertical_align= align_v::top); + private: + //Overrides widget's virtual function + void _m_caption(native_string_type&&) override; + }; +}//end namespace nana +#include + +#endif diff --git a/GUI/nana/gui/widgets/listbox.hpp b/GUI/nana/gui/widgets/listbox.hpp new file mode 100644 index 0000000..d7a1a70 --- /dev/null +++ b/GUI/nana/gui/widgets/listbox.hpp @@ -0,0 +1,1640 @@ +/** + * A List Box Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/listbox.hpp + * @contributors: + * Hiroshi Seki + * Ariel Vina-Rodriguez + * leobackes(pr#86,pr#97) + * Benjamin Navarro(pr#81) + * besh81(pr#130) + * dankan1890(pr#158) + */ + +#ifndef NANA_GUI_WIDGETS_LISTBOX_HPP +#define NANA_GUI_WIDGETS_LISTBOX_HPP +#include + +#include "widget.hpp" +#include "detail/inline_widget.hpp" +#include "detail/widget_iterator.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace nana +{ + class listbox; + + namespace drawerbase + { + namespace listbox + { + using size_type = std::size_t; + using native_string_type = ::nana::detail::native_string_type; + + /// An interface of column operations + class column_interface + { + public: + // Destructor + virtual ~column_interface() = default; + + /// Returns the width of the column, in pixel + virtual unsigned width() const noexcept = 0; + + /// Sets width + /** + * @param pixels The pixels of width + */ + virtual void width(unsigned pixels) noexcept = 0; + + /// Automatically adjusted width + /** + * @param minimum The minimal width of column, in pixel + * @param maximum The maximal width of column, in pixel + */ + virtual void width(unsigned minimum, unsigned maximum) = 0; + + /// Returns the position of the column + /** + * @param disp_order Indicates whether the display position or absolute position to be returned + * @return the position of the column. + */ + virtual size_type position(bool disp_order) const noexcept = 0; + + /// Returns the caption of column + virtual std::string text() const noexcept = 0; + + /// Sets the caption of column + /** + * @param text_utf8 A UTF-8 string for the caption. + */ + virtual void text(std::string text_utf8) = 0; + + /// Sets alignment of column text + /** + * @param align Alignment + */ + virtual void text_align(::nana::align align) noexcept = 0; + + /// Adjusts the width to fit the content + /** + * The priority of max: maximum, ranged width, scheme's max_fit_content. + * @param maximum Sets the width of column to the maximum if the width of content is larger than maximum + */ + virtual void fit_content(unsigned maximum = 0) noexcept = 0; + + /// Sets an exclusive font for the column + virtual void typeface(const paint::font& column_font) = 0; + + /// Returns a font + virtual paint::font typeface() const noexcept = 0; + + /// Determines the visibility state of the column + /** + * @return true if the column is visible, false otherwise + */ + virtual bool visible() const noexcept = 0; + + /// Sets the visibility state of the column + /** + * @param is_visible Indicates whether to show or hide the column + */ + virtual void visible(bool is_visible) noexcept = 0; + }; + + class const_virtual_pointer + { + struct intern + { + public: + virtual ~intern() noexcept = default; + }; + + template + struct real_pointer + : public intern + { + const T * ptr; + + real_pointer(const T* p) noexcept + : ptr(p) + {} + }; + + const_virtual_pointer(const const_virtual_pointer&) = delete; + const_virtual_pointer& operator=(const const_virtual_pointer&) = delete; + + const_virtual_pointer(const_virtual_pointer&&) = delete; + const_virtual_pointer& operator=(const_virtual_pointer&&) = delete; + public: + template + explicit const_virtual_pointer(const Type* p) + : intern_(new real_pointer{p}) + { + } + + ~const_virtual_pointer() noexcept + { + delete intern_; + } + + template + const typename std::remove_const::type *get() const noexcept + { + using value_type = typename std::remove_const::type; + auto target = dynamic_cast*>(intern_); + return (target ? target->ptr : nullptr); + } + private: + intern * intern_; + }; + + struct cell + { + struct format + { + ::nana::color bgcolor; + ::nana::color fgcolor; + + format() noexcept = default; + format(const ::nana::color& bgcolor, const ::nana::color& fgcolor) noexcept; + }; + + using format_ptr = ::std::unique_ptr; + + ::std::string text; + format_ptr custom_format; + + cell() = default; + cell(const cell&); + cell(cell&&) noexcept; + cell(::std::string) noexcept; + cell(::std::string, const format&); + + cell& operator=(const cell&); + cell& operator=(cell&&) noexcept; + }; + + class container_interface + { + friend class model_guard; + public: + virtual ~container_interface() = default; + + virtual void clear() = 0; + virtual void erase(std::size_t pos) = 0; + + virtual std::size_t size() const = 0; + virtual bool immutable() const = 0; + + virtual void emplace(std::size_t pos) = 0; + virtual void emplace_back() = 0; + + virtual void assign(std::size_t pos, const std::vector& cells) = 0; + virtual std::vector to_cells(std::size_t pos) const = 0; + + virtual bool push_back(const const_virtual_pointer&) = 0; + + virtual void * pointer() = 0; + virtual const void* pointer() const = 0; + }; + + template + struct container_translator + { + using value_translator = std::function& cells)>; + using cell_translator = std::function(const Value&)>; + + value_translator to_value; + cell_translator to_cell; + }; + + template + class basic_container + : public container_interface + { + }; + + template + class standalone_container + : public basic_container + { + using value_type = typename STLContainer::value_type; + using value_translator = typename container_translator::value_translator; + using cell_translator = typename container_translator::cell_translator; + public: + standalone_container(STLContainer&& cont, value_translator vtrans, cell_translator ctrans) + : container_(std::move(cont)), + translator_({ vtrans, ctrans }) + {} + + standalone_container(const STLContainer& cont, value_translator vtrans, cell_translator ctrans) + : container_(cont), + translator_({ vtrans, ctrans }) + {} + private: + void clear() override + { + container_.clear(); + } + + void erase(std::size_t pos) override + { + auto i = container_.begin(); + std::advance(i, pos); + container_.erase(i); + } + + std::size_t size() const override + { + return container_.size(); + } + + bool immutable() const override + { + return false; + } + + void emplace(std::size_t pos) override + { + auto i = container_.begin(); + std::advance(i, pos); + + container_.emplace(i); + } + + void emplace_back() override + { + container_.emplace_back(); + } + + void assign(std::size_t pos, const std::vector& cells) override + { + container_.at(pos) = translator_.to_value(cells); + } + + std::vector to_cells(std::size_t pos) const override + { + return translator_.to_cell(container_.at(pos)); + } + + bool push_back(const const_virtual_pointer& dptr) override + { + auto value = dptr.get(); + if (value) + { + container_.push_back(*value); + return true; + } + return false; + } + + void* pointer() override + { + return &container_; + } + + const void* pointer() const override + { + return &container_; + } + private: + STLContainer container_; + container_translator translator_; + }; + + + template + class shared_container + : public basic_container + { + using value_type = typename STLContainer::value_type; + using value_translator = typename container_translator::value_translator; + using cell_translator = typename container_translator::cell_translator; + + public: + using container_reference = STLContainer&; + + + shared_container(container_reference cont, value_translator vtrans, cell_translator ctrans) + : container_(cont), translator_({ vtrans, ctrans }) + { + + } + private: + void clear() override + { + container_.clear(); + } + + void erase(std::size_t pos) override + { + auto i = container_.begin(); + std::advance(i, pos); + container_.erase(i); + } + + std::size_t size() const override + { + return container_.size(); + } + + bool immutable() const override + { + return false; + } + + void emplace(std::size_t pos) override + { + auto i = container_.begin(); + std::advance(i, pos); + + container_.emplace(i); + } + + void emplace_back() override + { + container_.emplace_back(); + } + + void assign(std::size_t pos, const std::vector& cells) override + { + container_.at(pos) = translator_.to_value(cells); + } + + std::vector to_cells(std::size_t pos) const override + { + return translator_.to_cell(container_.at(pos)); + } + + bool push_back(const const_virtual_pointer& dptr) override + { + auto value = dptr.get(); + if (value) + { + container_.push_back(*value); + return true; + } + return false; + } + + void* pointer() override + { + return &container_; + } + + const void* pointer() const override + { + return &container_; + } + private: + container_reference container_; + container_translator translator_; + }; + + template + class shared_immutable_container + : public basic_container + { + using value_type = typename STLContainer::value_type; + using cell_translator = typename container_translator::cell_translator; + + + public: + using container_reference = const STLContainer&; + + + shared_immutable_container(container_reference cont, cell_translator ctrans) + : container_(cont), ctrans_(ctrans) + { + } + private: + void clear() override + { + throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); + } + + void erase(std::size_t /*pos*/) override + { + throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); + } + + std::size_t size() const override + { + return container_.size(); + } + + bool immutable() const override + { + return true; + } + + void emplace(std::size_t /*pos*/) override + { + throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); + } + + void emplace_back() override + { + throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); + } + + void assign(std::size_t /*pos*/, const std::vector& /*cells*/) override + { + throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); + } + + std::vector to_cells(std::size_t pos) const override + { + return ctrans_(container_.at(pos)); + } + + bool push_back(const const_virtual_pointer& /*dptr*/) override + { + throw std::runtime_error("nana::listbox disallow to remove items because of immutable model"); + } + + void* pointer() override + { + return nullptr; + } + + const void* pointer() const override + { + return &container_; + } + private: + container_reference container_; + cell_translator ctrans_; + }; + + class model_interface + { + public: + virtual ~model_interface() = default; + + virtual void lock() = 0; + virtual void unlock() = 0; + + virtual container_interface* container() noexcept = 0; + virtual const container_interface* container() const noexcept = 0; + }; + + class model_guard + { + model_guard(const model_guard&) = delete; + model_guard& operator=(const model_guard&) = delete; + public: + model_guard(model_interface* model) + : model_(model) + { + model->lock(); + } + + model_guard(model_guard&& other) + : model_(other.model_) + { + other.model_ = nullptr; + } + + ~model_guard() noexcept + { + if (model_) + model_->unlock(); + } + + model_guard& operator=(model_guard&& other) + { + if (this != &other) + { + if (model_) + model_->unlock(); + + model_ = other.model_; + other.model_ = nullptr; + } + return *this; + } + + template + STLContainer& container() + { + using stlcontainer = typename std::decay::type; + + if (!model_) + throw std::runtime_error("nana::listbox empty model_guard"); + + using type = basic_container; + auto p = dynamic_cast(model_->container()); + if (nullptr == p) + throw std::invalid_argument("invalid listbox model container type"); + + if (nullptr == p->pointer()) + throw std::runtime_error("the modal is immutable, please declare model_guard with const"); + + return *static_cast(p->pointer()); + } + + template + const STLContainer& container() const + { + using stlcontainer = typename std::decay::type; + + if (!model_) + throw std::runtime_error("nana::listbox empty model_guard"); + + using type = basic_container; + auto p = dynamic_cast(model_->container()); + if (nullptr == p) + throw std::invalid_argument("invalid listbox model container type"); + + return *static_cast(p->pointer()); + } + private: + model_interface* model_; + }; + + template + class standalone_model_container + : public model_interface + { + public: + using value_translator = typename container_translator::value_translator; + using cell_translator = typename container_translator::cell_translator; + + standalone_model_container(STLContainer&& container, value_translator vtrans, cell_translator ctrans) + : container_(std::move(container), std::move(vtrans), std::move(ctrans)) + { + } + + standalone_model_container(const STLContainer& container, value_translator vtrans, cell_translator ctrans) + : container_(container, std::move(vtrans), std::move(ctrans)) + { + } + + void lock() override + { + mutex_.lock(); + } + + void unlock() override + { + mutex_.unlock(); + } + + container_interface* container() noexcept override + { + return &container_; + } + + const container_interface* container() const noexcept override + { + return &container_; + } + private: + Mutex mutex_; + standalone_container container_; + }; + + template + class shared_model_container + : public model_interface + { + public: + using value_translator = typename container_translator::value_translator; + using cell_translator = typename container_translator::cell_translator; + + shared_model_container(STLContainer& container, value_translator vtrans, cell_translator ctrans) + : container_ptr_(new shared_container(container, std::move(vtrans), std::move(ctrans))) + { + } + + shared_model_container(const STLContainer& container, cell_translator ctrans) + : container_ptr_(new shared_immutable_container(container, std::move(ctrans))) + { + } + + void lock() override + { + mutex_.lock(); + } + + void unlock() override + { + mutex_.unlock(); + } + + container_interface* container() noexcept override + { + return container_ptr_.get(); + } + + const container_interface* container() const noexcept override + { + return container_ptr_.get(); + } + private: + Mutex mutex_; + std::unique_ptr container_ptr_; + }; + + + /// useful for both absolute and display (sorted) positions + struct index_pair + { + constexpr static const size_type npos = ::nana::npos; + + size_type cat; //The pos of category + size_type item; //the pos of item in a category. + + explicit index_pair(size_type cat_pos = 0, size_type item_pos = 0) noexcept + : cat(cat_pos), item(item_pos) + {} + + bool empty() const noexcept + { + return (npos == cat); + } + + void set_both(size_type n) noexcept + { + cat = item = n; + } + + bool is_category() const noexcept + { + return (npos != cat && npos == item); + } + + bool operator==(const index_pair& r) const noexcept + { + return (r.cat == cat && r.item == item); + } + + bool operator!=(const index_pair& r) const noexcept + { + return !this->operator==(r); + } + + bool operator<(const index_pair& r) const noexcept + { + return (cat < r.cat) || ((cat == r.cat) && (r.item != npos) && ((item == npos) || (item < r.item))); + } + + bool operator>(const index_pair& r) const noexcept + { + return (cat > r.cat) || ((cat == r.cat) && (item != npos) && ((r.item == npos) || (item > r.item))); + } + }; + + using index_pairs = ::std::vector; + + enum class inline_widget_status{ + checked, + checking, + selected, + selecting + }; + + using inline_notifier_interface = detail::inline_widget_notifier_interface; + + // struct essence + //@brief: this struct gives many data for listbox, + // the state of the struct does not effect on member functions, therefore all data members are public. + struct essence; + + class oresolver + { + public: + oresolver(essence*) noexcept; + oresolver& operator<<(bool); + oresolver& operator<<(short); + oresolver& operator<<(unsigned short); + oresolver& operator<<(int); + oresolver& operator<<(unsigned int); + oresolver& operator<<(long); + oresolver& operator<<(unsigned long); + oresolver& operator<<(long long); + oresolver& operator<<(unsigned long long); + oresolver& operator<<(float); + oresolver& operator<<(double); + oresolver& operator<<(long double); + + oresolver& operator<<(const char* text_utf8); + oresolver& operator<<(const wchar_t*); + oresolver& operator<<(const std::string& text_utf8); + oresolver& operator<<(const std::wstring&); + oresolver& operator<<(std::wstring&&); + oresolver& operator<<(cell); + oresolver& operator<<(std::nullptr_t); + + std::vector && move_cells() noexcept; + + ::nana::listbox& listbox() noexcept; + private: + essence* const ess_; + std::vector cells_; + }; + + class iresolver + { + public: + iresolver(std::vector) noexcept; + + iresolver& operator>>(bool&); + iresolver& operator>>(short&); + iresolver& operator>>(unsigned short&); + iresolver& operator>>(int&); + iresolver& operator>>(unsigned int&); + iresolver& operator>>(long&); + iresolver& operator>>(unsigned long&); + iresolver& operator>>(long long&); + iresolver& operator>>(unsigned long long&); + iresolver& operator>>(float&); + iresolver& operator>>(double&); + iresolver& operator>>(long double&); + + iresolver& operator>>(std::string& text_utf8); + iresolver& operator>>(std::wstring&); + iresolver& operator>>(cell&); + iresolver& operator>>(std::nullptr_t) noexcept; + private: + std::vector cells_; + std::size_t pos_{0}; + }; + + + struct category_t; + class drawer_header_impl; + class drawer_lister_impl; + + /// mostly works on display positions + class trigger: public drawer_trigger + { + public: + trigger(); + ~trigger(); + essence& ess() const noexcept; + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void typeface_changed(graph_reference) override; + void refresh(graph_reference) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void dbl_click(graph_reference, const arg_mouse&) override; + void resized(graph_reference, const arg_resized&) override; + void key_press(graph_reference, const arg_keyboard&) override; + void key_char(graph_reference, const arg_keyboard&) override; + private: + essence * essence_; + drawer_header_impl *drawer_header_; + drawer_lister_impl *drawer_lister_; + };//end class trigger + + /// operate with absolute positions and contain only the position but maintain pointers to parts of the real items + /// item_proxy self, it references and iterators are not invalidated by sort() + class item_proxy + : public ::nana::widgets::detail::widget_iterator + { + public: + item_proxy(essence*, const index_pair& = index_pair{npos, npos}); + + /// the main purpose of this it to make obvious that item_proxy operate with absolute positions, and don't get moved during sort() + static item_proxy from_display(essence *, const index_pair &relative) ; + item_proxy from_display(const index_pair &relative) const; + + /// possible use: last_selected_display = last_selected.to_display().item; use with caution, it get invalidated after a sort() + index_pair to_display() const; + + /// Determines whether the item is displayed on the screen + bool displayed() const; + + /// Determines whether the item_proxy refers to invalid item. + /** + * @return true if the item_proxy refers to an invalid item, false otherwise. + */ + bool empty() const noexcept; + + /// Checks/unchecks the item + /** + * @param chk Indicates whether to check or uncheck the item + * @param scroll_view Indicates whether to scroll the view to the item. It is ignored if the item is displayed. + * @return the reference of *this. + */ + item_proxy & check(bool chk, bool scroll_view = false); + + /// Determines whether the item is checked + bool checked() const; + + /// Selects/deselects the item + /** + * @param sel Indicates whether to select or deselect the item + * @param scroll_view Indicates whether to scroll the view to the item. It is ignored if the item is displayed. + * @return the reference of *this. + */ + item_proxy & select(bool sel, bool scroll_view = false); + + /// Determines whether he item is selected + bool selected() const; + + item_proxy & bgcolor(const nana::color&); + nana::color bgcolor() const; + + item_proxy& fgcolor(const nana::color&); + nana::color fgcolor() const; + + index_pair pos() const noexcept; + + size_type columns() const noexcept; + + /// Converts a position of column between display position and absolute position + /** + * @param col The display position or absolute position. + * @param disp_order Indicates whether the col is a display position or absolute position. If this parameter is true, the col is display position + * @return absolute position if disp_order is false, display position otherwise. + */ + size_type column_cast(size_type col, bool disp_order) const; + + item_proxy& text(size_type abs_col, cell); + item_proxy& text(size_type abs_col, std::string); + item_proxy& text(size_type abs_col, const std::wstring&); + std::string text(size_type abs_col) const; + + void icon(const nana::paint::image&); + + template + item_proxy & resolve_from(const T& t) + { + oresolver ores(_m_ess()); + ores << t; + auto && cells = ores.move_cells(); + auto cols = columns(); + cells.resize(cols); + for (auto pos = 0u; pos < cols; ++pos) + { + auto & el = cells[pos]; + if (el.text.size() == 1 && el.text[0] == '\0') + continue; + text(pos, std::move(el)); + } + + return *this; + } + + template + void resolve_to(T& t) const + { + iresolver ires(_m_cells()); + ires >> t; + } + + template + T const * value_ptr() const + { + return any_cast(_m_value()); + } + + template + T & value() const + { + auto * pany = _m_value(); + if(nullptr == pany) + throw std::runtime_error("listbox::item_proxy.value() is empty"); + + T * p = any_cast(_m_value()); + if(nullptr == p) + throw std::runtime_error("listbox::item_proxy.value() invalid type of value"); + return *p; + } + template + T & value() + { + auto * pany = _m_value(); + if (nullptr == pany) + throw std::runtime_error("listbox::item_proxy.value() is empty"); + + T * p = any_cast(_m_value(false)); + if (nullptr == p) + throw std::runtime_error("listbox::item_proxy.value() invalid type of value"); + return *p; + } + template + item_proxy & value(T&& t) + { + *_m_value(true) = ::std::forward(t); + return *this; + } + + /// Behavior of Iterator's value_type +#ifdef _nana_std_has_string_view + bool operator==(::std::string_view sv) const; + bool operator==(::std::wstring_view sv) const; +#else + bool operator==(const char * s) const; + bool operator==(const wchar_t * s) const; + bool operator==(const ::std::string& s) const; + bool operator==(const ::std::wstring& s) const; +#endif + + /// Behavior of Iterator + item_proxy & operator=(const item_proxy&); + + /// Behavior of Iterator + item_proxy & operator++(); + + /// Behavior of Iterator + item_proxy operator++(int); + + /// Behavior of Iterator + item_proxy& operator*(); + + /// Behavior of Iterator + const item_proxy& operator*() const; + + /// Behavior of Iterator + item_proxy* operator->(); + + /// Behavior of Iterator + const item_proxy* operator->() const; + + /// Behavior of Iterator + bool operator==(const item_proxy&) const; + + /// Behavior of Iterator + bool operator!=(const item_proxy&) const; + + //Undocumented method + essence * _m_ess() const noexcept; + private: + std::vector _m_cells() const; + nana::any * _m_value(bool alloc_if_empty); + const nana::any * _m_value() const; + private: + essence * ess_; + category_t* cat_{nullptr}; + + index_pair pos_; //Position of an item, it never represents a category when item proxy is available. + }; + + class cat_proxy + : public ::nana::widgets::detail::widget_iterator + { + public: + using inline_notifier_interface = drawerbase::listbox::inline_notifier_interface; + template using value_translator = typename container_translator::value_translator; + template using cell_translator = typename container_translator::cell_translator; + + cat_proxy() noexcept = default; + cat_proxy(essence*, size_type pos) noexcept; + cat_proxy(essence*, category_t*) noexcept; + + /// Append an item at the end of this category using the oresolver to generate the texts to be put in each column. + /// + /// First you have to make sure there is an overload of the operator<<() of the oresolver for the type of the object used here + /// If a listbox have a model set, try call append_model instead. + template + item_proxy append( T&& t, ///< Value used by the resolver to generate the texts to be put in each column of the item + bool set_value = false) ///< determines whether to set the object as the value of this item. + { + oresolver ores(ess_); + + //Troubleshoot: + //If a compiler error that no operator<< overload found for type T occurs, please define a overload operator<<(oresolver&, const T&). + //If a listbox have a model set, try call append_model instead. + if (set_value) + ores << t; //copy it if it is rvalue and set_value is true. + else + ores << std::forward(t); + + _m_append(ores.move_cells()); + + item_proxy iter{ ess_, index_pair(pos_, size() - 1) }; + if (set_value) + iter.value(std::forward(t)); + + _m_update(); + + return iter; + } + + template + void append_model(const T& t) + { + nana::internal_scope_guard lock; + _m_try_append_model(const_virtual_pointer{ &t }); + _m_update(); + } + + template + void model(STLContainer&& container, ValueTranslator vtrans, CellTranslator ctrans) + { + _m_reset_model(new standalone_model_container::type, Mutex>(std::forward(container), std::move(vtrans), std::move(ctrans))); + } + + template + void shared_model(STLContainer& container, ValueTranslator vtrans, CellTranslator ctrans) + { + _m_reset_model(new shared_model_container::type, Mutex>(container, std::move(vtrans), std::move(ctrans))); + } + + template + void shared_model(const STLContainer& container, CellTranslator ctrans) + { + _m_reset_model(new shared_model_container::type, Mutex>(container, std::move(ctrans))); + } + + model_guard model(); + + /// Appends one item at the end of this category with the specifies texts in the column fields + void append(std::initializer_list texts_utf8); + void append(std::initializer_list texts); + + size_type columns() const; + + cat_proxy& text(std::string); + cat_proxy& text(std::wstring); + std::string text() const; + + cat_proxy & select(bool); + bool selected() const; + + /// Enables/disables the number of items in the category to be displayed behind the category title + cat_proxy& display_number(bool display); + + /// Determines whether the category is expanded. + bool expanded() const; + + /// Expands/collapses the category + /** + * @param expand Indicates whether to expand or collapse the category. If this parameter is true, it expands the category. If the parameter is false, it collapses the category. + * @return the reference of *this. + */ + cat_proxy& expanded(bool expand); + + /// Behavior of a container + void push_back(std::string text_utf8); + + item_proxy begin() const; + item_proxy end() const; + item_proxy cbegin() const; + item_proxy cend() const; + + item_proxy at(size_type pos_abs) const; + item_proxy back() const; + + /// Converts the index between absolute position and display position + /** + * @param from The index to be converted + * @param from_display_order If this parameter is true, the method converts a display position to an absolute position. + * If the parameter is false, the method converts an absolute position to a display position. + * @return a display position or an absolute position that are depending on from_display_order. + */ + size_type index_cast(size_type from, bool from_display_order) const; + + /// this cat position + size_type position() const; + + /// Returns the number of items + size_type size() const; + + /// Behavior of Iterator + cat_proxy& operator=(const cat_proxy&); + + /// Behavior of Iterator + cat_proxy & operator++(); + + /// Behavior of Iterator + cat_proxy operator++(int); + + /// Behavior of Iterator + cat_proxy& operator*(); + + /// Behavior of Iterator + const cat_proxy& operator*() const; + + /// Behavior of Iterator + cat_proxy* operator->(); + + /// Behavior of Iterator + const cat_proxy* operator->() const; + + /// Behavior of Iterator + bool operator==(const cat_proxy&) const; + + /// Behavior of Iterator + bool operator!=(const cat_proxy&) const; + + void inline_factory(size_type column, pat::cloneable> factory); + private: + void _m_append(std::vector && cells); + void _m_try_append_model(const const_virtual_pointer&); + void _m_cat_by_pos() noexcept; + void _m_update() noexcept; + void _m_reset_model(model_interface*); + private: + essence* ess_{nullptr}; + category_t* cat_{nullptr}; + size_type pos_{0}; ///< Absolute position, not relative to display, and dont change during sort() + }; + + struct export_options + { + std::string sep = ::std::string {"\t"}, + endl= ::std::string {"\n"}; + bool only_selected_items{true}, + only_checked_items {false}, + only_visible_columns{true}; + + using columns_indexs = std::vector; + columns_indexs columns_order; + }; + } + }//end namespace drawerbase + + struct arg_listbox + : public event_arg + { + mutable drawerbase::listbox::item_proxy item; + + arg_listbox(const drawerbase::listbox::item_proxy&) noexcept; + }; + + /// The event parameter type for listbox's category_dbl_click + struct arg_listbox_category + : public event_arg + { + drawerbase::listbox::cat_proxy category; + + /// A flag that indicates whether or not to block expansion/shrink of category when it is double clicked. + mutable bool block_operation{ false }; + + arg_listbox_category(const drawerbase::listbox::cat_proxy&) noexcept; + }; + + namespace drawerbase + { + namespace listbox + { + struct listbox_events + : public general_events + { + /// An event occurs when the toggle of a listbox item is checked. + basic_event checked; + + /// An event occurs when a listbox item is clicked. + basic_event selected; + + /// An event occurs when a listbox category is double clicking. + basic_event category_dbl_click; + }; + + struct scheme + : public widget_geometrics + { + color_proxy header_bgcolor{static_cast(0xf1f2f4)}; + color_proxy header_fgcolor{ colors::black }; + color_proxy header_grabbed{ static_cast(0x8BD6F6)}; + color_proxy header_floated{ static_cast(0xBABBBC)}; + color_proxy item_selected{ static_cast(0xCCE8FF) }; + color_proxy item_highlighted{ static_cast(0xE5F3FF) }; + + color_proxy selection_box{ static_cast(0x3399FF) }; ///< Color of selection box border. + + + std::shared_ptr column_font; ///< Renderer draws column texts with the font if it is not a nullptr. + + /// The max column width which is generated by fit_content is allowed. It is ignored when it is 0, or a max value is passed to fit_content. + unsigned max_fit_content{ 0 }; + + unsigned min_column_width{ 20 }; ///< def=20 . non counting suspension_width + + unsigned text_margin{ 5 }; ///< def= 5. Additional or extended with added (before) to the text width to determine the cell width. cell_w = text_w + ext_w +1 + + unsigned item_height_ex{ 6 }; ///< Set !=0 !!!! def=6. item_height = text_height + item_height_ex + unsigned header_splitter_area_before{ 2 }; ///< def=2. But 4 is better... IMO + unsigned header_splitter_area_after{ 3 }; ///< def=3. But 4 is better... + unsigned header_padding_top{ 3 }; + unsigned header_padding_bottom{ 3 }; + + ::nana::parameters::mouse_wheel mouse_wheel{}; ///< The number of lines/characters to scroll when vertical/horizontal mouse wheel is moved. + }; + } + }//end namespace drawerbase + +/*! \class listbox +\brief A rectangle containing a list of strings from which the user can select. +This widget contain a list of \a categories, with in turn contain a list of \a items. +A \a category is a text with can be \a selected, \a checked and \a expanded to show the \a items. +An \a item is formed by \a column-fields, each corresponding to one of the \a headers. +An \a item can be \a selected and \a checked. +The user can \a drag the header to \a resize it or to \a reorganize it. +By \a clicking on one header the list get \a reordered, first up, and then down alternatively. + +1. The resolver is used to resolute an object of the specified type into (or back from) a listbox item. +3. nana::listbox creates the category 0 by default. + This is an special category, because it is invisible, while the associated items are visible. + The optional, user-created categories begin at index 1 and are visible. + The member functions without the categ parameter operate the items that belong to category 0. +4. A sort compare is used for sorting the items. It is a strict weak ordering comparer that must meet the requirement: + Irreflexivity (comp(x, x) returns false) + and + Antisymmetry(comp(a, b) != comp(b, a) returns true) + A simple example. + bool sort_compare( const std::string& s1, nana::any*, + const std::string& s2, nana::any*, bool reverse) + { + return (reverse ? s1 > s2 : s1 < s2); + } + listbox.set_sort_compare(0, sort_compare); + The listbox supports attaching a customer's object for each item, therefore the items can be + sorted by comparing these customer's object. + bool sort_compare( const std::string&, nana::any* o1, + const std::string&, nana::any* o2, bool reverse) + { + if(o1 && o2) //some items may not attach a customer object. + { + int * i1 = any_cast(*o1); + int * i2 = any_cast(*o2); + return (i1 && i2 && (reverse ? *i1 > *i2 : *i1 < *i2)); + // ^ some types may not be int. + } + return false; + } + auto cat = listbox.at(0); + cat.at(0).value(10); //10 is custom data. + cat.at(1).value(20); //20 is custom data. +5. listbox is a widget_object, with template parameters drawerbase::listbox::trigger and drawerbase::listbox::scheme +among others. +That means that listbox have a member trigger_ constructed first and accessible with get_drawer_trigger() and +a member (unique pointer to) scheme_ accessible with scheme_type& scheme() created in the constructor +with API::dev::make_scheme() which call API::detail::make_scheme(::nana::detail::scheme_factory()) +which call restrict::bedrock.make_scheme(static_cast<::nana::detail::scheme_factory_base&&>(factory)); +which call pi_data_->scheme.create(std::move(factory)); +which call factory.create(scheme_template(std::move(factory))); +which call (new Scheme(static_cast(other))); +and which in create is set with: API::dev::set_scheme(handle_, scheme_.get()); which save the scheme pointer in +the nana::detail::basic_window member pointer scheme +\todo doc: actualize this example listbox.at(0)... +\see nana::drawerbase::listbox::cat_proxy +\see nana::drawerbase::listbox::item_proxy +\example listbox_Resolver.cpp +*/ + class listbox + : public widget_object, + public concepts::any_objective + { + public: + /// An unsigned integral type + using size_type = drawerbase::listbox::size_type; + + /// The representation of a category/item + using index_pair = drawerbase::listbox::index_pair; + + /// A index_pair package + using index_pairs = drawerbase::listbox::index_pairs; + + /// Iterator to access category + using cat_proxy = drawerbase::listbox::cat_proxy; + + /// Iterator to access item + using item_proxy = drawerbase::listbox::item_proxy; + + /// The input resolver that converts an object to an item + using iresolver = drawerbase::listbox::iresolver; + + /// The output resolver that converts an item to an object + using oresolver = drawerbase::listbox::oresolver; + + /// The representation of an item cell + using cell = drawerbase::listbox::cell; + + /// The options for exporting items into a string variable + using export_options = drawerbase::listbox::export_options; + + /// The interface for user-defined inline widgets + using inline_notifier_interface = drawerbase::listbox::inline_notifier_interface; + + /// Column operations + using column_interface = drawerbase::listbox::column_interface; + public: + + // Constructors + listbox() = default; + listbox(window, bool visible); + listbox(window, const rectangle& = {}, bool visible = true); + + // Element access + + /// Returns the category at specified location pos, with bounds checking. + cat_proxy at(size_type pos); + const cat_proxy at(size_type pos) const; + + /// Returns the item at specified absolute position + item_proxy at(const index_pair& abs_pos); + const item_proxy at(const index_pair &abs_pos) const; + + + /// Returns the category at specified location pos, no bounds checking is performed. + cat_proxy operator[](size_type pos); + const cat_proxy operator[](size_type pos) const; + + /// Returns the item at specified absolute position, no bounds checking is performed. + item_proxy operator[](const index_pair& abs_pos); + const item_proxy operator[](const index_pair &abs_pos) const; + + // Associative category access + + /// Returns a proxy to the category of the key or create a new one in the right order + /** + * @param key The key of category to find + * @return A category proxy + */ + template + cat_proxy assoc(Key&& key) + { + using key_type = typename ::nana::detail::type_escape::type>::type; + + auto p = std::make_shared>>(std::forward(key)); + return cat_proxy(&_m_ess(), _m_assoc(p, true)); + } + + /// Returns a proxy to the category of the key or create a new one in the right order + /** + * @param key The key of category to find + * @return A category proxy + */ + template + cat_proxy assoc_at(Key&& key) + { + using key_type = typename ::nana::detail::type_escape::type>::type; + + auto p = std::make_shared>>(std::forward(key)); + + auto categ = _m_assoc(p, false); + if (nullptr == categ) + throw std::out_of_range("listbox: invalid key."); + + return cat_proxy(&_m_ess(), categ); + } + + /// Removes the category associated with the specified key + /** + * @param key The key of category to remove + */ + template + void assoc_erase(Key&& key) + { + using key_type = typename ::nana::detail::type_escape::type>::type; + + ::nana::key> wrap(key); + _m_erase_key(&wrap); + } + + bool assoc_ordered(bool); + + void auto_draw(bool) noexcept; ///< Set state: Redraw automatically after an operation + + template + void avoid_drawing(Function fn) + { + this->auto_draw(false); + try + { + fn(); + } + catch (...) + { + this->auto_draw(true); + throw; + } + this->auto_draw(true); + } + + /// Scrolls the view to the first or last item of a specified category + void scroll(bool to_bottom, size_type cat_pos = ::nana::npos); + + /// Scrolls the view to show an item specified by absolute position at top/bottom of the listbox. + void scroll(bool to_bottom, const index_pair& abs_pos); + + /// Appends a new column with a header text and the specified width at the end, and return it position + /// + /// If a width of 0 is passed the width will be set to fit the header text. + size_type append_header(std::string text_utf8, unsigned width = 120); + size_type append_header(std::wstring text, unsigned width = 120); + + void clear_headers(); ///< Removes all the columns. + + cat_proxy append(std::string category); ///< Appends a new category to the end + cat_proxy append(std::wstring category); ///< Appends a new category to the end + void append(std::initializer_list categories); ///< Appends categories to the end + void append(std::initializer_list categories); ///< Appends categories to the end + + /// Access a column at specified position + /** + * @param pos Position of column + * @param disp_order Indicates whether the pos is display position or absolute position. + * @return Reference to the requested column + * @except std::out_of_range if !(pos < columns()) + */ + column_interface & column_at(size_type pos, bool disp_order = false); + + /// Access a column at specified position + /** + * @param pos Position of column + * @param disp_order Indicates whether the pos is display position or absolute position. + * @return Constant reference to the requested column + * @except std::out_of_range if !(pos < columns()) + */ + const column_interface & column_at(size_type pos, bool disp_order = false) const; + + /// Returns the number of columns + size_type column_size() const; + + /// Move column to view_position + void move_column(size_type abs_pos, size_type view_pos); + + /// Sort columns in range first_col to last_col inclusive using the values from a row + void reorder_columns(size_type first_col, + size_type last_col, + index_pair row, bool reverse, + std::function comp); + + void column_resizable(bool resizable); + bool column_resizable() const; + void column_movable(bool); + bool column_movable() const; + + /// Returns the rectangle where the content is drawn. + rectangle content_area() const; + + cat_proxy insert(cat_proxy, ::std::string); + cat_proxy insert(cat_proxy, ::std::wstring); + + /// Inserts an item before a specified position + /** + * @param abs_pos The absolute position before which an item will be inserted. + * @param text Text of the first column, UTF-8 encoded. + */ + void insert_item(const index_pair& abs_pos, ::std::string text); + + /// Inserts an item before a specified position + /** + * @param abs_pos The absolute position before which an item will be inserted. + * @param text Text of the first column. + */ + void insert_item(const index_pair& abs_pos, const ::std::wstring& text); + + + void insert_item(index_pair abs_pos, const listbox& rhs, const index_pairs& indexes); + + /// Returns the index pair of the item which contains the specified "screen" point. + index_pair cast(const point & screen_pos) const; + + /// Converts the index between absolute position and display position + /** + * @param idx The index to be converted + * @param from_display_order If this parameter is true, the method converts a display position to an absolute position. + * If the parameter is false, the method converts an absolute position to a display position. + * @return a display position or an absolute position that are depending on from_display_order. + */ + index_pair index_cast(index_pair idx, bool from_display_order) const; + + /// Returns the item which is hovered + /** + * The item position is an absolute position. + * @param return_end Indicates whether to return an end position instead of an empty position if no item is hovered. + * @return The position of the hovered item. If return_end is true and no item is hovered it returns the position next to the last item of last category. + */ + index_pair hovered(bool return_end) const; + + /// Returns the absolute position of the column which contains the specified "screen" point. + size_type column_from_pos(const point & screen_pos) const; + + void checkable(bool make_checkeable); ///< Display a checkbox at te links of each item if make_checkeable=true + index_pairs checked() const; ///< Returns all the items which are checked. + + void clear(size_type cat); ///< Removes all the items from the specified category + void clear(); ///< Removes all the items from all categories + void erase(size_type cat); ///< Erases a category + void erase(); ///< Erases all categories. + void erase(index_pairs indexes); ///< Erases specified items. + item_proxy erase(item_proxy indx); ///< Erases specified item. + + bool sortable() const; ///< return whether the listbox is set to be sortable + void sortable(bool enable); ///< set the listbox to be or not to be sortable + + ///Sets a strict weak ordering comparer for a column + void set_sort_compare( size_type col, + std::function strick_ordering); + + /// Sort the items using the specified column. + /// + /// Invalidates any existing reference from display position to absolute item, + /// that is: after sort() display offset point to different items + void sort_col(size_type col, bool reverse = false); + size_type sort_col() const; ///< return the column currently used to sort items + + /// Eliminate any "column sorting", effectively setting the items in the order of creation. + /// + /// Potentially invalidates any existing reference from display position to absolute item, + /// that is: after unsort() display offset may point to different items + void unsort(); + + ///< Prevent sorting until `freeze` is set to false. + bool freeze_sort(bool freeze); + + index_pairs selected() const; /// icon_renderer); + + /// Sets category icons + /** + * @param img_expanded An icon displayed in front of category title when the category is expanded. + * @param img_collapsed An icon displayed in front of category title when the category is collapsed. + * @return the reference of *this. + */ + listbox& category_icon(const paint::image& img_expanded, const paint::image& img_collapsed); + + /// Returns first visible element + /** + * It may return an item or a category item. + * @return the index of first visible element. + */ + index_pair first_visible() const; + + /// Returns last visible element + /** + * It may return an item or a category item. + * @return the index of last visible element. + */ + index_pair last_visible() const; + + /// Returns all visible items + /** + * It returns all visible items that are displayed in listbox window. + * @return index_pairs containing all visible items. + */ + index_pairs visibles() const; + + /// Sets a predicate that indicates whether to deselect items when mouse_up is triggered. + /** + * The predicate is called before the listbox attempts to deselect the selected items in the mouse_up event. Other situations, + * the predicates isn't called, for example, releasing mouse button after user performed a box selection, because listbox doesn't deselect the items during this operation. + * @param predicate Decides to deselect the items. + * The paramater of predicate indicates the mouse button which is releasing. + * It returns true to deselect the selected items. It returns false to cancel to deselect the selected items. + */ + void set_deselect(std::function predicate); + + unsigned suspension_width() const; + private: + drawerbase::listbox::essence & _m_ess() const; + nana::any* _m_anyobj(size_type cat, size_type index, bool allocate_if_empty) const override; + drawerbase::listbox::category_t* _m_assoc(std::shared_ptr, bool create_if_not_exists); + void _m_erase_key(nana::detail::key_interface*) noexcept; + std::shared_ptr _m_scroll_operation() override; + }; +}//end namespace nana + +#include +#endif diff --git a/GUI/nana/gui/widgets/menu.hpp b/GUI/nana/gui/widgets/menu.hpp new file mode 100644 index 0000000..b2315ac --- /dev/null +++ b/GUI/nana/gui/widgets/menu.hpp @@ -0,0 +1,217 @@ +/** + * A Menu implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2009-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/menu.hpp + * + */ + +#ifndef NANA_GUI_WIDGETS_MENU_HPP +#define NANA_GUI_WIDGETS_MENU_HPP +#include "widget.hpp" +#include +#include + +namespace nana +{ + class menu; + + namespace drawerbase + { + namespace menu + { + struct menu_type; //declaration + + using native_string_type = ::nana::detail::native_string_type; + + enum class checks + { + none, + option, + highlight + }; + + struct menu_item_type + { + /// This class is used as parameter of menu event function. + class item_proxy + { + public: + item_proxy(std::size_t pos, ::nana::menu*); + item_proxy& enabled(bool); + bool enabled() const; + + item_proxy& check_style(checks); + item_proxy& checked(bool); + bool checked() const; + + item_proxy& text(std::string title_utf8); + std::string text() const; + + std::size_t index() const; + private: + std::size_t const pos_; + ::nana::menu* const menu_; + }; + /// A callback functor type. + typedef std::function event_fn_t; + + //Default constructor initializes the item as a splitter + menu_item_type(); + menu_item_type(std::string, const event_fn_t&); + + struct + { + bool enabled:1; + bool splitter:1; + bool checked:1; + }flags; + + struct + { + bool own_creation; //Indicates the menu_ptr is created by create_sub_menu + menu_type* menu_ptr; + }linked; + + std::string text; + event_fn_t event_handler; + checks style{checks::none}; + paint::image image; + mutable wchar_t hotkey{0}; + }; + + class renderer_interface + { + public: + using graph_reference = nana::paint::graphics &; + + enum class state + { + normal, active + }; + + struct attr + { + state item_state; + bool enabled; + bool checked; + checks check_style; + }; + + virtual ~renderer_interface() = default; + + virtual void background(graph_reference, window) = 0; + virtual void item(graph_reference, const nana::rectangle&, const attr&) = 0; + virtual void item_image(graph_reference, const nana::point&, unsigned image_px, const paint::image&) = 0; + virtual void item_text(graph_reference, const nana::point&, const std::string&, unsigned text_pixels, const attr&) = 0; + virtual void sub_arrow(graph_reference, const nana::point&, unsigned item_pixels, const attr&) = 0; + }; + }//end namespace menu + }//end namespace drawerbase + + class menu + : private noncopyable + { + struct implement; + + //let menubar access the private _m_popup() method. + friend class menu_accessor; + public: + typedef drawerbase::menu::checks checks; + + typedef drawerbase::menu::renderer_interface renderer_interface; + typedef drawerbase::menu::menu_item_type::item_proxy item_proxy; + typedef drawerbase::menu::menu_item_type::event_fn_t event_fn_t; ///< A callback functor type. Prototype: `void(item_proxy&)` + + menu(); ///< The default constructor. NO OTHER CONSTRUCTOR. + ~menu(); + + /// Appends an item to the menu. + item_proxy append(std::string text_utf8, const event_fn_t& handler = {}); + void append_splitter(); + + /// Inserts new item at specified position + /** + * It will invalidate the existing item proxies from the specified position. + * @param pos The position where new item to be inserted + * @param text_utf8 The title of item + * @param handler The event handler for the item. + * @return the item proxy to the new inserted item. + */ + item_proxy insert(std::size_t pos, std::string text_utf8, const event_fn_t& handler = {}); + + void clear(); ///< Erases all of the items. + /// Closes the menu. It does not destroy the menu; just close the window for the menu. + void close(); + void image(std::size_t pos, const paint::image& icon); + void text(std::size_t pos, std::string text_utf8); + std::string text(std::size_t pos) const; + void check_style(std::size_t pos, checks); + void checked(std::size_t pos, bool); + bool checked(std::size_t pos) const; + void enabled(std::size_t pos, bool);///< Enables or disables the mouse or keyboard input for the item. + bool enabled(std::size_t pos) const; + void erase(std::size_t pos); ///< Removes the item + bool link(std::size_t pos, menu& menu_obj);///< Link a menu to the item as a sub menu. + menu * link(std::size_t pos) const; ///< Retrieves a linked sub menu of the item. + menu *create_sub_menu(std::size_t pos); + void popup(window owner, int x, int y); ///< Popup the menu at the owner window. + void popup_await(window owner, int x, int y); + void answerer(std::size_t index, const event_fn_t&); ///< Modify answerer of the specified item. + void destroy_answer(std::function); ///< Sets an answerer for the callback while the menu window is closing. + void gaps(const nana::point&); ///< Sets the gap between a menu and its sub menus.(\See Note4) + void goto_next(bool forward); ///< Moves the focus to the next or previous item. + bool goto_submen();///< Popup the submenu of the current item if it has a sub menu. Returns true if succeeds. + bool exit_submenu(); ///< Closes the current window of the sub menu. + std::size_t size() const; ///< Return the number of items. + int send_shortkey(wchar_t key); + void pick(); + + menu& max_pixels(unsigned); ///< Sets the max width in pixels of the item. + unsigned max_pixels() const; + + menu& item_pixels(unsigned); ///< Sets the height in pixel for the items. + unsigned item_pixels() const; + + void renderer(const pat::cloneable&); ///< Sets a user-defined renderer. + const pat::cloneable& renderer() const; + + /// Returns the handle of menu window + /** + * @return handle of menu window, nullptr if the menu hasn't been popped up. + */ + window handle() const; + private: + void _m_popup(window, const point& position, bool called_by_menubar); + private: + implement * impl_; + }; + + namespace detail + { + class popuper + { + public: + popuper(menu&, mouse); + popuper(menu&, window owner, const point&, mouse); + void operator()(const arg_mouse&); + private: + menu & mobj_; + window owner_; + bool take_mouse_pos_; + nana::point pos_; + mouse mouse_; + }; + } + + detail::popuper menu_popuper(menu&, mouse = mouse::right_button); + detail::popuper menu_popuper(menu&, window owner, const point&, mouse = mouse::right_button); +}//end namespace nana +#include + +#endif diff --git a/GUI/nana/gui/widgets/menubar.hpp b/GUI/nana/gui/widgets/menubar.hpp new file mode 100644 index 0000000..b159a77 --- /dev/null +++ b/GUI/nana/gui/widgets/menubar.hpp @@ -0,0 +1,95 @@ +/* + * A Menubar implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2009-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/menubar.hpp + */ + +#ifndef NANA_GUI_WIDGETS_MENUBAR_HPP +#define NANA_GUI_WIDGETS_MENUBAR_HPP +#include "widget.hpp" +#include "menu.hpp" +#include + +namespace nana +{ + namespace drawerbase + { + namespace menubar + { + using native_string_type = ::nana::detail::native_string_type; + + struct scheme + : public widget_geometrics + { + color_proxy text_fgcolor{ colors::black }; + color_proxy body_highlight{ static_cast(0xc0ddfc) }; + color_proxy body_selected{ colors::white }; + color_proxy border_selected{ colors::dark_border }; + color_proxy border_highlight{ colors::highlight }; + }; + + class trigger + : public drawer_trigger + { + struct essence; + public: + trigger(); + ~trigger(); + essence& ess() const; + private: + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void focus(graph_reference, const arg_focus&) override; + void key_press(graph_reference, const arg_keyboard&) override; + void key_release(graph_reference, const arg_keyboard&) override; + void shortkey(graph_reference, const arg_keyboard&) override; + private: + void _m_move(graph_reference, bool to_left); + private: + essence * const ess_; + }; + }//end namespace menubar + }//end namespace drawerbase + + /// \brief A toolbar at the top of window for pop-upping menus. + /// + /// The widget sets as shortkey the character behind the first of & in the text, for the item. e.g. "File(&F)" or "&File". + class menubar + : public widget_object + { + public: + menubar() = default; ///< The default constructor delay creation. + menubar(window); ///< Create a menubar at the top of the specified window. + ~menubar(); + void create(window); ///< Create a menubar at the top of the specified window. + menu& push_back(const std::string&); ///< Appends a new (empty) menu. + menu& at(size_t index) const; ///< Gets the menu specified by index. + std::size_t length() const; ///< Number of menus. + void clear(); ///< Removes all the menus. + + /// Deselects the menu + /** + * If a menu is popped up, the menu deselects the item and close the pop-upped menu. + * @return true if an item is deselected, false otherwise. + */ + bool cancel(); + + /// Determines the mouse is hovered on the menubar or its popped menu. + bool hovered() const; + private: + ::nana::event_handle evt_resized_{nullptr}; + };//end class menubar +}//end namespace nana +#include + +#endif diff --git a/GUI/nana/gui/widgets/panel.hpp b/GUI/nana/gui/widgets/panel.hpp new file mode 100644 index 0000000..2b6683d --- /dev/null +++ b/GUI/nana/gui/widgets/panel.hpp @@ -0,0 +1,72 @@ +/** + * A Panel Implementation + * Nana C++ Library(http://www.nanaro.org) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/panel.hpp + * @author: Jinhao + * @contributors: Ariel Vina-Rodriguez + * + * @brief panel is a widget used for placing some widgets. + */ + +#ifndef NANA_GUI_WIDGETS_PANEL_HPP +#define NANA_GUI_WIDGETS_PANEL_HPP +#include "widget.hpp" +#include + +namespace nana +{ + namespace drawerbase + { + namespace panel + { + class drawer: public drawer_trigger + { + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + private: + window window_{nullptr}; + }; + }// end namespace panel + }//end namespace drawerbase + /// For placing other widgets, where the bool template parameter determines if it is widget or lite_widget, which in actual use makes no difference. + template + class panel + : public widget_object::type, + drawerbase::panel::drawer> + { + public: + panel(){} + + panel(window wd, bool visible) + { + this->create(wd, rectangle(), visible); + this->bgcolor(API::bgcolor(wd)); + } + + panel(window wd, const nana::rectangle& r = rectangle(), bool visible = true) + { + this->create(wd, r, visible); + this->bgcolor(API::bgcolor(wd)); + } + + bool transparent() const + { + return API::is_transparent_background(*this); + } + + void transparent(bool tr) + { + if(tr) + API::effects_bground(*this, effects::bground_transparent(0), 0); + else + API::effects_bground_remove(*this); + } + }; +}//end namespace nana +#endif diff --git a/GUI/nana/gui/widgets/picture.hpp b/GUI/nana/gui/widgets/picture.hpp new file mode 100644 index 0000000..83068b7 --- /dev/null +++ b/GUI/nana/gui/widgets/picture.hpp @@ -0,0 +1,73 @@ +/** + * A Picture Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/picture.hpp + * + * @brief Used for showing a picture + */ +#ifndef NANA_GUI_WIDGET_PICTURE_HPP +#define NANA_GUI_WIDGET_PICTURE_HPP +#include + +#include "widget.hpp" + +namespace nana +{ + class picture; + + namespace drawerbase + { + namespace picture + { + struct implement; + + class drawer : public drawer_trigger + { + friend class ::nana::picture; + public: + drawer(); + ~drawer(); + void attached(widget_reference, graph_reference) override; + private: + void refresh(graph_reference) override; + private: + implement * const impl_; + }; + }//end namespace picture + }//end namespace drawerbase + + /// Rectangle area for displaying a bitmap file + class picture + : public widget_object + { + public: + picture() = default; + picture(window, bool visible); + picture(window, const rectangle& ={}, bool visible = true); + + void load(::nana::paint::image, const rectangle& valid_area = {}); + + /// Sets the align of image. + void align(align, align_v); + + /// Enables the image to be stretched to the widget size. + void stretchable(unsigned left, unsigned top, unsigned right, unsigned bottom); + + /// Enables/disables the image to be stretched without changing aspect ratio. + void stretchable(bool); + + /// Fills a gradual-change color in background. If one of colors is invisible or clr_from is equal to clr_to, it draws background in bgcolor. + void set_gradual_background(const color& clr_from, const color& clr_to, bool horizontal); + void transparent(bool); + bool transparent() const; + }; +}//end namespace nana +#include + +#endif diff --git a/GUI/nana/gui/widgets/progress.hpp b/GUI/nana/gui/widgets/progress.hpp new file mode 100644 index 0000000..37a5c89 --- /dev/null +++ b/GUI/nana/gui/widgets/progress.hpp @@ -0,0 +1,69 @@ +/** + * A Progress Indicator Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/progress.hpp + */ + +#ifndef NANA_GUI_WIDGET_PROGRESS_HPP +#define NANA_GUI_WIDGET_PROGRESS_HPP +#include "widget.hpp" + +namespace nana +{ + namespace drawerbase + { + namespace progress + { + struct scheme + : public widget_geometrics + { + scheme(); + + color_proxy gradient_bgcolor{ colors::button_face_shadow_start }; + color_proxy gradient_fgcolor{ static_cast(0x6FFFA8) }; + }; + + class substance; + + class trigger + : public drawer_trigger + { + public: + trigger(); + ~trigger(); + + substance* progress() const; + private: + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + private: + substance* const progress_; + }; + } + }//end namespace drawerbase + /// \brief A progressbar widget with two styles: know, and unknown amount value (goal). + /// In unknown style the amount is ignored and the bar is scrolled when value change. + class progress + : public widget_object + { + public: + progress(); + progress(window, bool visible); + progress(window, const rectangle & = rectangle(), bool visible = true); + + unsigned value() const; + unsigned value(unsigned val); + unsigned inc(); + unsigned amount() const; + unsigned amount(unsigned value); + void unknown(bool); + bool unknown() const; + }; +}//end namespace nana +#endif diff --git a/GUI/nana/gui/widgets/scroll.hpp b/GUI/nana/gui/widgets/scroll.hpp new file mode 100644 index 0000000..9bee580 --- /dev/null +++ b/GUI/nana/gui/widgets/scroll.hpp @@ -0,0 +1,506 @@ +/** + * A Scroll Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/scroll.hpp + * @contributors: Ariel Vina-Rodriguez + */ +#ifndef NANA_GUI_WIDGET_SCROLL_HPP +#define NANA_GUI_WIDGET_SCROLL_HPP + +#include "widget.hpp" +#include +#include + +namespace nana +{ + template class scroll; //forward declaration + + struct arg_scroll + : public event_arg + { + window window_handle; + + arg_scroll(window wd) + : window_handle{ wd } + {} + }; + + namespace drawerbase + { + namespace scroll + { + struct scroll_events + : public general_events + { + basic_event value_changed; + }; + + enum class buttons + { + none, forward, backward, scroll, first, second + }; + + struct metrics_type + { + using size_type = std::size_t; + + size_type peak; ///< the whole total + size_type range; ///< how many is shown on a page, that is, How many to scroll after click on first or second + size_type step; ///< how many to scroll by click in forward or backward + size_type value; ///< current offset calculated from the very beginning + + buttons what; + bool pressed; + size_type scroll_length; ///< the length in pixels of the central button show how many of the total (peak) is shown (range) + int scroll_pos; ///< in pixels, and correspond to the offset from the very beginning (value) + int scroll_mouse_offset; + + metrics_type(); + }; + + class drawer + { + public: + enum class states + { + none, highlight, actived, selected + }; + + using graph_reference = paint::graphics&; + const static unsigned fixedsize = 16; // make it part of a new "metric" in the widget_scheme + + drawer(bool vert); + buttons what(graph_reference, const point&); + void scroll_delta_pos(graph_reference, int); + void auto_scroll(); + void draw(graph_reference); + + private: + bool _m_check() const; + void _m_adjust_scroll(graph_reference); + void _m_background(graph_reference); + void _m_button_frame(graph_reference, ::nana::rectangle, states state); + void _m_draw_scroll(graph_reference, states state); + void _m_draw_button(graph_reference, ::nana::rectangle, buttons what, states state); + public: + metrics_type metrics; + bool const vert; + }; + + template + class trigger + : public drawer_trigger + { + public: + typedef metrics_type::size_type size_type; + + trigger() + : graph_(nullptr), drawer_(Vertical) + { + } + + const metrics_type& metrics() const + { + return drawer_.metrics; + } + + void peak(size_type s) + { + if (graph_ && (drawer_.metrics.peak != s)) + { + drawer_.metrics.peak = s; + API::refresh_window(widget_->handle()); + } + } + + void value(size_type s) + { + if (drawer_.metrics.range > drawer_.metrics.peak) + s = 0; + else if (s + drawer_.metrics.range > drawer_.metrics.peak) + s = drawer_.metrics.peak - drawer_.metrics.range; + + if (graph_ && (drawer_.metrics.value != s)) + { + drawer_.metrics.value = s; + _m_emit_value_changed(); + + API::refresh_window(*widget_); + } + } + + void range(size_type s) + { + if (graph_ && (drawer_.metrics.range != s)) + { + drawer_.metrics.range = s; + API::refresh_window(widget_->handle()); + } + } + + void step(size_type s) + { + drawer_.metrics.step = (s ? s : 1); + } + + bool make_step(bool forward, unsigned multiple) + { + if (!graph_) + return false; + + size_type step = (multiple > 1 ? drawer_.metrics.step * multiple : drawer_.metrics.step); + size_type value = drawer_.metrics.value; + if (forward) + { + size_type maxv = drawer_.metrics.peak - drawer_.metrics.range; + if (drawer_.metrics.peak > drawer_.metrics.range && value < maxv) + { + if (maxv - value >= step) + value += step; + else + value = maxv; + } + } + else if (value) + { + if (value > step) + value -= step; + else + value = 0; + } + size_type cmpvalue = drawer_.metrics.value; + drawer_.metrics.value = value; + if (value != cmpvalue) + { + _m_emit_value_changed(); + return true; + } + return false; + } + private: + void attached(widget_reference widget, graph_reference graph) override + { + graph_ = &graph; + widget_ = static_cast< ::nana::scroll*>(&widget); + widget.caption("nana scroll"); + + //scroll doesn't want the keyboard focus. + API::take_active(widget, false, widget.parent()); + + timer_.stop(); + timer_.elapse(std::bind(&trigger::_m_tick, this)); + } + + void detached() override + { + graph_ = nullptr; + } + + void refresh(graph_reference graph) override + { + drawer_.draw(graph); + } + + void resized(graph_reference graph, const ::nana::arg_resized&) override + { + drawer_.draw(graph); + API::dev::lazy_refresh(); + } + + void mouse_enter(graph_reference graph, const ::nana::arg_mouse& arg) override + { + drawer_.metrics.what = drawer_.what(graph, arg.pos); + drawer_.draw(graph); + API::dev::lazy_refresh(); + } + + void mouse_move(graph_reference graph, const ::nana::arg_mouse& arg) override + { + if (drawer_.metrics.pressed && (drawer_.metrics.what == buttons::scroll)) + { + size_type cmpvalue = drawer_.metrics.value; + drawer_.scroll_delta_pos(graph, (Vertical ? arg.pos.y : arg.pos.x)); + if (cmpvalue != drawer_.metrics.value) + _m_emit_value_changed(); + } + else + { + buttons what = drawer_.what(graph, arg.pos); + if (drawer_.metrics.what == what) + return; //no change, don't redraw + + drawer_.metrics.what = what; + } + + drawer_.draw(graph); + API::dev::lazy_refresh(); + } + + void dbl_click(graph_reference graph, const arg_mouse& arg) override + { + mouse_down(graph, arg); + } + + void mouse_down(graph_reference graph, const arg_mouse& arg) override + { + if (arg.left_button) + { + drawer_.metrics.pressed = true; + drawer_.metrics.what = drawer_.what(graph, arg.pos); + switch (drawer_.metrics.what) + { + case buttons::first: + case buttons::second: + make_step(drawer_.metrics.what == buttons::second, 1); + timer_.interval(std::chrono::seconds{1}); + timer_.start(); + break; + case buttons::scroll: + widget_->set_capture(true); + drawer_.metrics.scroll_mouse_offset = (Vertical ? arg.pos.y : arg.pos.x) - drawer_.metrics.scroll_pos; + break; + case buttons::forward: + case buttons::backward: + { + size_type cmpvalue = drawer_.metrics.value; + drawer_.auto_scroll(); + if (cmpvalue != drawer_.metrics.value) + _m_emit_value_changed(); + } + break; + default: //Ignore buttons::none + break; + } + drawer_.draw(graph); + API::dev::lazy_refresh(); + } + } + + void mouse_up(graph_reference graph, const arg_mouse& arg) override + { + timer_.stop(); + + widget_->release_capture(); + + drawer_.metrics.pressed = false; + drawer_.metrics.what = drawer_.what(graph, arg.pos); + drawer_.draw(graph); + API::dev::lazy_refresh(); + } + + void mouse_leave(graph_reference graph, const arg_mouse&) override + { + if (drawer_.metrics.pressed) return; + + drawer_.metrics.what = buttons::none; + drawer_.draw(graph); + API::dev::lazy_refresh(); + } + + void mouse_wheel(graph_reference graph, const arg_wheel& arg) override + { + if (make_step(arg.upwards == false, 3)) + { + drawer_.draw(graph); + API::dev::lazy_refresh(); + } + } + private: + void _m_emit_value_changed() + { + widget_->events().value_changed.emit({ widget_->handle() }, widget_->handle()); + } + + void _m_tick() + { + make_step(drawer_.metrics.what == buttons::second, 1); + API::refresh_window(widget_->handle()); + timer_.interval(std::chrono::milliseconds{ 100 }); + } + private: + ::nana::scroll * widget_; + nana::paint::graphics * graph_; + drawer drawer_; + timer timer_; + }; + }//end namespace scroll + }//end namespace drawerbase + + class scroll_interface + { + public: + using size_type = std::size_t; + + virtual ~scroll_interface() = default; + + /// \brief Determines whether it is scrollable. + /// @param for_less whether it can be scrolled for a less value (backward or "up" if true, forward or "down" if false). + virtual bool scrollable(bool for_less) const = 0; + + /// the whole total (peak) + virtual size_type amount() const = 0; + + virtual void amount(size_type peak) = 0; + + /// Get the range of the widget (how many is shown on a page, that is, How many to scroll after click on first or second) + virtual size_type range() const = 0; + + /// Set the range of the widget. + virtual void range(size_type r) = 0; + + /// \brief Get the value (current offset calculated from the very beginning) + /// @return the value. + virtual size_type value() const = 0; + + /// \brief Set the value. + /// @param s a new value. + virtual void value(size_type s) = 0; + + + /// \brief Get the step of the sroll widget. The step indicates a variation of the value. + /// @return the step. + virtual size_type step() const = 0; + + /// \brief Set the step. + /// @param s a value for step. + virtual void step(size_type s) = 0; + + /// \brief Increase/decrease values by a step (alternatively by some number of steps). + /// @param forward it determines whether increase or decrease. + /// @return true if the value is changed. + virtual bool make_step(bool forward, unsigned steps = 1) = 0; + + virtual window window_handle() const = 0; + }; + + /// Provides a way to display an object which is larger than the window's client area. + template + class scroll // add a widget scheme? + : public widget_object, drawerbase::scroll::scroll_events>, + public scroll_interface + { + typedef widget_object > base_type; + public: + + /// \brief The default constructor without creating the widget. + scroll(){} + + /// \brief The construct that creates a widget. + /// @param wd A handle to the parent window of the widget being created. + /// @param visible specify the visibility after creation. + scroll(window wd, bool visible = true) + { + this->create(wd, rectangle(), visible); // add a widget scheme? and take some colors from these wd? + } + + /// \brief The construct that creates a widget. + /// @param wd A handle to the parent window of the widget being created. + /// @param r the size and position of the widget in its parent window coordinate. + /// @param visible specify the visibility after creation. + scroll(window wd, const rectangle& r, bool visible = true) + { + this->create(wd, r, visible); + } + + /// \brief Determines whether it is scrollable. + /// @param for_less whether it can be scrolled for a less value (backward or "up" if true, forward or "down" if false). + bool scrollable(bool for_less) const override + { + auto & m = this->get_drawer_trigger().metrics(); + return (for_less ? (0 != m.value) : (m.value < m.peak - m.range)); + } + /// the whole total (peak) + size_type amount() const override + { + return this->get_drawer_trigger().metrics().peak; + } + + void amount(size_type peak) override + { + return this->get_drawer_trigger().peak(peak); + } + + /// Get the range of the widget (how many is shown on a page, that is, How many to scroll after click on first or second) + size_type range() const override + { + return this->get_drawer_trigger().metrics().range; + } + + /// Set the range of the widget. + void range(size_type r) override + { + return this->get_drawer_trigger().range(r); + } + + /// \brief Get the value (current offset calculated from the very beginning) + /// @return the value. + size_type value() const override + { + return this->get_drawer_trigger().metrics().value; + } + + /// \brief Set the value. + /// @param s a new value. + void value(size_type s) override + { + return this->get_drawer_trigger().value(s); + } + + /// \brief Get the step of the sroll widget. The step indicates a variation of the value. + /// @return the step. + size_type step() const override + { + return this->get_drawer_trigger().metrics().step; + } + + /// \brief Set the step. + /// @param s a value for step. + void step(size_type s) override + { + return this->get_drawer_trigger().step(s); + } + + /// \brief Increase/decrease values by a step (alternatively by some number of steps). + /// @param forward it determines whether increase or decrease. + /// @return true if the value is changed. + bool make_step(bool forward, unsigned steps = 1) override + { + if (this->get_drawer_trigger().make_step(forward, steps)) + { + API::refresh_window(this->handle()); + return true; + } + return false; + } + + window window_handle() const override + { + return this->handle(); + } + + /// \brief Increase/decrease values by steps as if it is scrolled through mouse wheel. + /// @param forward it determines whether increase or decrease. + /// @return true if the value is changed. + bool make_scroll(bool forward) + { + return this->make_step(forward, 3); // set this 3 in the metrics of the widget scheme ? + } + + /// \brief Increase/decrease values by a page as if it is scrolled page up. + /// @param forward it determines whether increase or decrease. + /// @return true if the value is changed. + bool make_page_scroll(bool forward) + { + auto const count = range() / step(); + return this->make_step(forward, static_cast(count > 2 ? count - 1 : 1)); + } + };//end class scroll +}//end namespace nana +#include +#endif diff --git a/GUI/nana/gui/widgets/skeletons/text_editor.hpp b/GUI/nana/gui/widgets/skeletons/text_editor.hpp new file mode 100644 index 0000000..5657af7 --- /dev/null +++ b/GUI/nana/gui/widgets/skeletons/text_editor.hpp @@ -0,0 +1,342 @@ +/* + * A text editor implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/skeletons/text_editor.hpp + * @description: + */ + +#ifndef NANA_GUI_SKELETONS_TEXT_EDITOR_HPP +#define NANA_GUI_SKELETONS_TEXT_EDITOR_HPP +#include + +#include "textbase.hpp" +#include "text_editor_part.hpp" +#include + +#include + +#include + +namespace nana +{ + namespace paint + { + // Forward declaration + class graphics; + } +} + +namespace nana{ namespace widgets +{ + namespace skeletons + { + class text_editor + { + struct attributes; + class editor_behavior_interface; + class behavior_normal; + class behavior_linewrapped; + + enum class command{ + backspace, input_text, move_text, + }; + //Commands for undoable + template class basic_undoable; + class undo_backspace; + class undo_input_text; + class undo_move_text; + + class keyword_parser; + class helper_pencil; + + struct text_section; + + text_editor(const text_editor&) = delete; + text_editor& operator=(const text_editor&) = delete; + + text_editor(text_editor&&) = delete; + text_editor& operator=(text_editor&&) = delete; + public: + using char_type = wchar_t; + using size_type = textbase::size_type; + using string_type = textbase::string_type; + using path_type = std::filesystem::path; + + using event_interface = text_editor_event_interface; + + using graph_reference = ::nana::paint::graphics&; + + struct renderers + { + std::function background; ///< a customized background renderer + std::function border; ///< a customized border renderer + }; + + enum class accepts + { + no_restrict, integer, real + }; + + text_editor(window, graph_reference, const text_editor_scheme*); + ~text_editor(); + + size caret_size() const; + const point& content_origin() const; + + void set_highlight(const ::std::string& name, const ::nana::color&, const ::nana::color&); + void erase_highlight(const ::std::string& name); + void set_keyword(const ::std::wstring& kw, const std::string& name, bool case_sensitive, bool whole_word_matched); + void erase_keyword(const ::std::wstring& kw); + + colored_area_access_interface& colored_area(); + + void set_accept(std::function); + void set_accept(accepts); + bool respond_ime(const arg_ime& arg); + bool respond_char(const arg_keyboard& arg); + bool respond_key(const arg_keyboard& arg); + + void typeface_changed(); + + void indent(bool, std::function generator); + void set_event(event_interface*); + + bool load(const path_type& file); + + void text_align(::nana::align alignment); + + /// Sets the text area. + /// @return true if the area is changed with the new value. + bool text_area(const nana::rectangle&); + + /// Returns the text area + rectangle text_area(bool including_scroll) const; + + bool tip_string(::std::string&&); + + /// Returns the reference of listbox attributes + const attributes & attr() const noexcept; + + /// Set the text_editor whether it is line wrapped, it returns false if the state is not changed. + bool line_wrapped(bool); + + bool multi_lines(bool); + + /// Enables/disables the editability of text_editor + /** + * @param enable Indicates whether to enable or disable the editability + * @param enable_cart Indicates whether to show or hide the caret when the text_editor is not editable. It is ignored if enable is false. + */ + void editable(bool enable, bool enable_caret); + void enable_background(bool); + void enable_background_counterpart(bool); + + void undo_clear(); + void undo_max_steps(std::size_t); + std::size_t undo_max_steps() const; + + renderers& customized_renderers(); + + unsigned line_height() const; + unsigned screen_lines(bool completed_line = false) const; + + bool getline(std::size_t pos, ::std::wstring&) const; + void text(std::wstring, bool end_caret); + std::wstring text() const; + + /// Moves the caret at specified position + /** + * @param pos the text position + * @param stay_in_view Indicates whether to adjust the view to make the caret in view. This parameter is ignored if the caret is already in view. + * @return true indicates a refresh is required. + */ + bool move_caret(upoint pos, bool stay_in_view = false); + void move_caret_end(bool update); + void reset_caret_pixels() const; + void reset_caret(bool stay_in_view = false); + void show_caret(bool isshow); + + bool selected() const; + bool get_selected_points(nana::upoint&, nana::upoint&) const; + + bool select(bool); + + bool select_points(nana::upoint arg_a, nana::upoint arg_b); + + /// Sets the end position of a selected string. + void set_end_caret(bool stay_in_view); + + bool hit_text_area(const point&) const; + bool hit_select_area(nana::upoint pos, bool ignore_when_select_all) const; + + bool move_select(); + bool mask(wchar_t); + + /// Returns width of text area excluding the vscroll size. + unsigned width_pixels() const; + window window_handle() const; + + /// Returns text position of each line that currently displays on screen + const std::vector& text_position() const; + + void focus_behavior(text_focus_behavior); + void select_behavior(bool move_to_end); + + std::size_t line_count(bool text_lines) const; + public: + void draw_corner(); + void render(bool focused); + public: + void put(std::wstring, bool perform_event); + void put(wchar_t); + void copy() const; + void cut(); + void paste(); + void enter(bool record_undo, bool perform_event); + void del(); + void backspace(bool record_undo, bool perform_event); + void undo(bool reverse); + void move_ns(bool to_north); //Moves up and down + void move_left(); + void move_right(); + const upoint& mouse_caret(const point& screen_pos, bool stay_in_view); + const upoint& caret() const noexcept; + point caret_screen_pos() const; + bool scroll(bool upwards, bool vertical); + + bool focus_changed(const arg_focus&); + bool mouse_enter(bool entering); + bool mouse_move(bool left_button, const point& screen_pos); + void mouse_pressed(const arg_mouse& arg); + bool select_word(const arg_mouse& arg); + + skeletons::textbase& textbase() noexcept; + const skeletons::textbase& textbase() const noexcept; + + bool try_refresh(); + + std::shared_ptr scroll_operation() const; + private: + nana::color _m_draw_colored_area(paint::graphics& graph, const std::pair& row, bool whole_line); + std::vector _m_render_text(const ::nana::color& text_color); + void _m_pre_calc_lines(std::size_t line_off, std::size_t lines); + + //Caret to screen coordinate or context coordiate(in pixels) + ::nana::point _m_caret_to_coordinate(::nana::upoint pos, bool to_screen_coordinate = true) const; + //Screen coordinate or context coordinate(in pixels) to caret, + ::nana::upoint _m_coordinate_to_caret(::nana::point pos, bool from_screen_coordinate = true) const; + + bool _m_pos_from_secondary(std::size_t textline, const nana::upoint& secondary, unsigned & pos); + bool _m_pos_secondary(const nana::upoint& charpos, nana::upoint& secondary_pos) const; + bool _m_move_caret_ns(bool to_north); + void _m_update_line(std::size_t pos, std::size_t secondary_count_before); + + bool _m_accepts(char_type) const; + ::nana::color _m_bgcolor() const; + + void _m_reset_content_size(bool calc_lines = false); + void _m_reset(); + + //Inserts text at position where the caret is + ::nana::upoint _m_put(::std::wstring, bool perform_event); + + ::nana::upoint _m_erase_select(bool perform_event); + + ::std::wstring _m_make_select_string() const; + static bool _m_resolve_text(const ::std::wstring&, std::vector> & lines); + + bool _m_cancel_select(int align); + nana::size _m_text_extent_size(const char_type*, size_type n) const; + + /// Adjust position of view to make caret stay in screen + bool _m_adjust_view(); + + bool _m_move_select(bool record_undo); + + int _m_text_top_base() const; + int _m_text_topline() const; + + /// Returns the logical position that text starts of a specified line in x-axis + int _m_text_x(const text_section&) const; + + void _m_draw_parse_string(const keyword_parser&, bool rtl, ::nana::point pos, const ::nana::color& fgcolor, const wchar_t*, std::size_t len) const; + //_m_draw_string + //@brief: Draw a line of string + void _m_draw_string(int top, const ::nana::color&, const nana::upoint& str_pos, const text_section&, bool if_mask) const; + //_m_update_caret_line + //@brief: redraw whole line specified by caret pos. + //@return: true if caret overs the border + bool _m_update_caret_line(std::size_t secondary_before); + + unsigned _m_char_by_pixels(const unicode_bidi::entity&, unsigned pos) const; + unsigned _m_pixels_by_char(const ::std::wstring&, ::std::size_t pos) const; + void _m_handle_move_key(const arg_keyboard& arg); + + unsigned _m_width_px(bool exclude_vs) const; + void _m_draw_border(); + private: + struct implementation; + implementation * const impl_; + + nana::window window_; + graph_reference graph_; + const text_editor_scheme* scheme_; + event_interface * event_handler_{ nullptr }; + + wchar_t mask_char_{0}; + + struct attributes + { + ::std::string tip_string; + + ::nana::align alignment{ ::nana::align::left }; + + bool line_wrapped{false}; + bool multi_lines{true}; + bool editable{true}; + bool enable_caret{ true }; ///< Indicates whether to show or hide caret when text_editor is not editable + bool enable_background{true}; + }attributes_; + + struct text_area_type + { + nana::rectangle area; + + bool captured{ false }; + unsigned tab_space{ 4 }; + }text_area_; + + struct selection + { + enum class mode{ no_selected, mouse_selected, method_selected, move_selected, move_selected_take_effect }; + + bool ignore_press{ false }; + bool move_to_end{ false }; + mode mode_selection{ mode::no_selected }; + text_focus_behavior behavior{text_focus_behavior::none}; + + nana::upoint a, b; + }select_; + + struct coordinate + { + nana::upoint caret; //position of caret by text, it specifies the position of a new character + nana::upoint shift_begin_caret; + }points_; + + size_t composition_size_ { 0 }; + }; + }//end namespace skeletons +}//end namespace widgets +}//end namespace nana + +#include + +#endif + diff --git a/GUI/nana/gui/widgets/skeletons/text_editor_part.hpp b/GUI/nana/gui/widgets/skeletons/text_editor_part.hpp new file mode 100644 index 0000000..4e77a48 --- /dev/null +++ b/GUI/nana/gui/widgets/skeletons/text_editor_part.hpp @@ -0,0 +1,69 @@ + +#ifndef NANA_WIDGETS_SKELETONS_TEXT_EDITOR_SCHEME_HPP +#define NANA_WIDGETS_SKELETONS_TEXT_EDITOR_SCHEME_HPP + +#include "../../detail/widget_geometrics.hpp" +#include + +namespace nana +{ + namespace widgets + { + namespace skeletons + { + enum class text_focus_behavior + { + none, + select, + select_if_tabstop, + select_if_click, + select_if_tabstop_or_click + }; + + //forward declaration + class text_editor; + + struct text_editor_scheme + : public ::nana::widget_geometrics + { + color_proxy selection{ static_cast(0x3399FF) }; + color_proxy selection_unfocused{ static_cast(0xF0F0F0) }; + color_proxy selection_text{colors::white}; + + parameters::mouse_wheel mouse_wheel; ///< The number of lines/characters to scroll when the vertical/horizontal mouse wheel is moved. + }; + + class text_editor_event_interface + { + public: + virtual ~text_editor_event_interface() = default; + + virtual void text_exposed(const std::vector&) = 0; + }; + + struct colored_area_type + { + const ::std::size_t begin; ///< The begin line position + ::std::size_t count; ///< The number of lines + + ::nana::color bgcolor; + ::nana::color fgcolor; + }; + + class colored_area_access_interface + { + public: + using colored_area_type = skeletons::colored_area_type; + + virtual ~colored_area_access_interface(); + + virtual std::shared_ptr get(std::size_t line_pos) = 0; + virtual bool clear() = 0; + virtual bool remove(std::size_t line_pos) = 0; + virtual std::size_t size() const = 0; + virtual std::shared_ptr at(std::size_t index) = 0; + }; + } + } +} +#endif \ No newline at end of file diff --git a/GUI/nana/gui/widgets/skeletons/text_token_stream.hpp b/GUI/nana/gui/widgets/skeletons/text_token_stream.hpp new file mode 100644 index 0000000..438a053 --- /dev/null +++ b/GUI/nana/gui/widgets/skeletons/text_token_stream.hpp @@ -0,0 +1,994 @@ +/* + * Text Token Stream + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/skeletons/text_token_stream.hpp + */ + +#ifndef NANA_GUI_WIDGETS_SKELETONS_TEXT_TOKEN_STREAM +#define NANA_GUI_WIDGETS_SKELETONS_TEXT_TOKEN_STREAM + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace nana{ namespace widgets{ namespace skeletons +{ + //The tokens are defined for representing a text, the tokens are divided + //into two parts. + //Formatted tokens: The tokens present in a format block, they form the format-syntax. + //Data tokens: The tokens present a text displaying on the screen. + enum class token + { + tag_begin, tag_end, format_end, + font, bold, size, color, url, target, image, top, center, bottom, baseline, + number, string, _true, _false, red, green, blue, white, black, binary, min_limited, max_limited, + + equal, comma, backslash, + data, endl, + eof + }; + + + class tokenizer + { + public: + tokenizer(const std::wstring& s, bool format_enabled) : + iptr_(s.data()), + endptr_(s.data() + s.size()), + format_enabled_(format_enabled) + { + } + + void push(token tk) + { + revert_token_ = tk; + } + + //Read the token. + token read() + { + if (revert_token_ != token::eof) + { + token tk = revert_token_; + revert_token_ = token::eof; + return tk; + } + + if (iptr_ == endptr_) + return token::eof; + + //Check whether it is a format token. + if (format_enabled_ && format_state_) + return _m_format_token(); + + return _m_token(); + } + + const ::std::wstring& idstr() const + { + return idstr_; + } + + const std::pair& binary() const + { + return binary_; + } + + std::pair binary_number() const + { + return{ std::stoul(binary_.first), std::stoul(binary_.second) }; + } + + int number() const + { + return std::stoi(idstr_, nullptr, 0); + } + private: + static bool _m_unicode_word_breakable(const wchar_t* ch) noexcept + { + if (*ch) + return unicode_wordbreak(*ch, ch[1]); + return true; + } + + //Read the data token + token _m_token() + { + wchar_t ch = *iptr_; + if (ch > 0xFF) + { + //This is the Unicode. + + idstr_.clear(); + idstr_.append(1, ch); + + if (_m_unicode_word_breakable(iptr_)) + { + ++iptr_; + return token::data; + } + + ch = *++iptr_; + while ((iptr_ != endptr_) && (ch > 0xFF) && (false == _m_unicode_word_breakable(iptr_))) + { + idstr_.append(1, ch); + + ch = *++iptr_; + } + + //When the last _m_unicode_word_breakable returns true, it implies the ch(left character) + //is not the breakable character. So it belongs to the data. + idstr_.append(1, ch); + ++iptr_; + + return token::data; + } + + if ('\n' == ch) + { + ++iptr_; + return token::endl; + } + + if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) + { + auto idstr = iptr_; + do + { + ch = *(++iptr_); + } while (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')); + + idstr_.assign(idstr, iptr_); + + return token::data; + } + + if ('0' <= ch && ch <= '9') + { + _m_read_number(); + return token::data; + } + + if (('<' == ch) && format_enabled_) + { + //pos keeps the current position, and it used for restoring + //iptr_ when the search is failed. + + auto pos = ++iptr_; + _m_eat_whitespace(); + if (*iptr_ == '/') + { + ++iptr_; + _m_eat_whitespace(); + if (*iptr_ == '>') + { + ++iptr_; + return token::format_end; + } + } + + //Restore the iptr_; + iptr_ = pos; + + format_state_ = true; + return token::tag_begin; + } + + //Escape + if (this->format_enabled_ && (ch == '\\')) + { + if (iptr_ + 1 < endptr_) + { + ch = *(iptr_ + 1); + + if ('<' == ch || '>' == ch) //two characters need to be escaped. + { + iptr_ += 2; + } + else + { + //ignore escape + ch = '\\'; + iptr_++; + } + } + else + { + iptr_ = endptr_; + return token::eof; + } + } + else + ++iptr_; + + idstr_.clear(); + idstr_.append(1, ch); + return token::data; + } + + //Read the format token + token _m_format_token() + { + _m_eat_whitespace(); + + auto ch = *iptr_++; + switch (ch) + { + case ',': return token::comma; + case '/': return token::backslash; + case '=': return token::equal; + case '>': + format_state_ = false; + return token::tag_end; + case '"': + //Here is a string and all the meta characters will be ignored except " + { + auto str = iptr_; + + while ((iptr_ != endptr_) && (*iptr_ != '"')) + ++iptr_; + + idstr_.assign(str, iptr_++); + } + return token::string; + case '(': + _m_eat_whitespace(); + if ((iptr_ < endptr_) && _m_is_idstr_element(*iptr_)) + { + auto pbegin = iptr_; + while ((iptr_ < endptr_) && _m_is_idstr_element(*iptr_)) + ++iptr_; + + binary_.first.assign(pbegin, iptr_); + + _m_eat_whitespace(); + if ((iptr_ < endptr_) && (',' == *iptr_)) + { + ++iptr_; + _m_eat_whitespace(); + if ((iptr_ < endptr_) && _m_is_idstr_element(*iptr_)) + { + pbegin = iptr_; + while ((iptr_ < endptr_) && _m_is_idstr_element(*iptr_)) + ++iptr_; + + binary_.second.assign(pbegin, iptr_); + + _m_eat_whitespace(); + if ((iptr_ < endptr_) && (')' == *iptr_)) + { + ++iptr_; + return token::binary; + } + } + } + } + + return token::eof; + } + + + + if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || '_' == ch) + { + --iptr_; + + //Here is a identifier + _m_read_idstr(); + + if (L"font" == idstr_) + return token::font; + else if (L"bold" == idstr_) + return token::bold; + else if (L"size" == idstr_) + return token::size; + else if (L"baseline" == idstr_) + return token::baseline; + else if (L"top" == idstr_) + return token::top; + else if (L"center" == idstr_) + return token::center; + else if (L"bottom" == idstr_) + return token::bottom; + else if (L"color" == idstr_) + return token::color; + else if (L"image" == idstr_) + return token::image; + else if (L"true" == idstr_) + return token::_true; + else if (L"url" == idstr_) + return token::url; + else if (L"target" == idstr_) + return token::target; + else if (L"false" == idstr_) + return token::_false; + else if (L"red" == idstr_) + return token::red; + else if (L"green" == idstr_) + return token::green; + else if (L"blue" == idstr_) + return token::blue; + else if (L"white" == idstr_) + return token::white; + else if (L"black" == idstr_) + return token::black; + else if (L"min_limited" == idstr_) + return token::min_limited; + else if (L"max_limited" == idstr_) + return token::max_limited; + + return token::string; + } + + if ('0' <= ch && ch <= '9') + { + --iptr_; + _m_read_number(); + return token::number; + } + + return token::eof; + } + + static bool _m_is_idstr_element(wchar_t ch) + { + return (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('_' == ch) || ('0' <= ch && ch <= '9')); + } + + //Read the identifier. + void _m_read_idstr() + { + auto idstr = iptr_; + + wchar_t ch; + do + { + ch = *(++iptr_); + } while (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('_' == ch) || ('0' <= ch && ch <= '9')); + + idstr_.assign(idstr, iptr_); + } + + //Read the number + void _m_read_number() + { + idstr_.clear(); + + wchar_t ch = *iptr_; + + idstr_ += ch; + + //First check the number whether will be a hex number. + if ('0' == ch) + { + ch = *++iptr_; + if ((!('0' <= ch && ch <= '9')) && (ch != 'x' && ch != 'X')) + return; + + if (ch == 'x' || ch == 'X') + { + //Here is a hex number + idstr_ += 'x'; + ch = *++iptr_; + while (('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')) + { + idstr_ += ch; + ch = *++iptr_; + } + return; + } + + //Here is not a hex number + idstr_ += ch; + } + + ch = *++iptr_; + while ('0' <= ch && ch <= '9') + { + idstr_ += ch; + ch = *++iptr_; + } + } + + void _m_eat_whitespace() + { + while (true) + { + switch (*iptr_) + { + case ' ': + case '\t': + ++iptr_; + break; + default: + return; + } + } + } + private: + const wchar_t * iptr_; + const wchar_t * endptr_; + const bool format_enabled_; + bool format_state_{false}; + + std::wstring idstr_; + std::pair binary_; + token revert_token_{token::eof}; + }; + + //The fblock states a format, and a format from which it is inherted + struct fblock + { + struct aligns + { + enum t + { + top, center, bottom, + baseline + }; + }; + + ::std::string font; + double font_size; + bool bold; + bool bold_empty; //bold should be ignored if bold_empty is true + aligns::t text_align; + ::nana::color bgcolor; //If the color is not specified, it will be ignored, and the system will search for its parent. + ::nana::color fgcolor; //ditto + + ::std::wstring target; + ::std::wstring url; + + fblock * parent; + }; + + //The abstruct data class states a data. + class data + { + public: + typedef nana::paint::graphics& graph_reference; + + virtual ~data(){} + + virtual bool is_text() const = 0; + virtual bool is_whitespace() const = 0; + virtual const std::wstring& text() const = 0; + virtual void measure(graph_reference) = 0; + virtual void nontext_render(graph_reference, int x, int y) = 0; + virtual const nana::size & size() const = 0; + virtual std::size_t ascent() const = 0; + }; + + + class data_text + : public data + { + public: + data_text(const std::wstring& s) + : str_(s) + {} + private: + virtual bool is_text() const override + { + return true; + } + + virtual bool is_whitespace() const override + { + return false; + } + + virtual const std::wstring& text() const override + { + return str_; + } + + virtual void measure(graph_reference graph) override + { + size_ = graph.text_extent_size(str_); + unsigned ascent; + unsigned descent; + unsigned internal_leading; + graph.text_metrics(ascent, descent, internal_leading); + ascent_ = ascent; + } + + virtual void nontext_render(graph_reference, int, int) override + { + } + + virtual const nana::size & size() const override + { + return size_; + } + + virtual std::size_t ascent() const override + { + return ascent_; + } + private: + std::wstring str_; + nana::size size_; + std::size_t ascent_; + }; + + class data_image + : public data + { + public: + data_image(const std::wstring& imgpath, const nana::size & sz, std::size_t limited) + : image_(imgpath)//, limited_(limited) + { + size_ = image_.size(); + + if(sz.width != 0 && sz.height != 0) + { + bool make_fit = false; + switch(limited) + { + case 1: + make_fit = (size_.width < sz.width || size_.height < sz.height); + break; + case 2: + make_fit = (size_.width > sz.width || size_.height > sz.height); + break; + } + + if(make_fit) + { + nana::size res; + nana::fit_zoom(size_, sz, res); + size_ = res; + } + else + size_ = sz; + } + } + private: + //implement data interface + virtual bool is_text() const override + { + return false; + } + + virtual bool is_whitespace() const override + { + return false; + } + + virtual const std::wstring& text() const override + { + return str_; + } + + virtual void measure(graph_reference) override + { + } + + virtual void nontext_render(graph_reference graph, int x, int y) override + { + if(size_ != image_.size()) + image_.stretch(::nana::rectangle{ image_.size() }, graph, nana::rectangle(x, y, size_.width, size_.height)); + else + image_.paste(graph, point{ x, y }); + } + + virtual const nana::size & size() const override + { + return size_; + } + + virtual std::size_t ascent() const override + { + return size_.height; + } + private: + std::wstring str_; + nana::paint::image image_; + nana::size size_; + }; + + class dstream + { + struct value + { + fblock * fblock_ptr; + data * data_ptr; + }; + public: + typedef std::list >::iterator iterator; + typedef std::deque linecontainer; + + ~dstream() + { + close(); + } + + void close() + { + for(auto & values: lines_) + { + for(std::deque::iterator u = values.begin(); u != values.end(); ++u) + delete u->data_ptr; + } + + lines_.clear(); + + for(auto p : fblocks_) + delete p; + + fblocks_.clear(); + } + + void parse(const std::wstring& s, bool format_enabled) + { + close(); + + tokenizer tknizer(s, format_enabled); + std::stack fstack; + + fstack.push(_m_create_default_fblock()); + + while(true) + { + token tk = tknizer.read(); + if (token::eof == tk) + break; + + switch(tk) + { + case token::data: + _m_data_factory(tk, tknizer.idstr(), fstack.top(), lines_.back()); + break; + case token::endl: + lines_.emplace_back(); + break; + case token::tag_begin: + _m_parse_format(tknizer, fstack); + + if(attr_image_.path.size()) + { + _m_data_image(fstack.top(), lines_.back()); + //This fblock just serves the image. So we should restore the pervious fblock + fstack.pop(); + } + + break; + case token::format_end: + if(fstack.size() > 1) + fstack.pop(); + break; + default: + throw std::runtime_error("invalid token"); + } + } + + //Reorder the sequence of line blocks for RTL languages. + for (auto & ln : lines_) + { + std::wstring str; + //Position only holds the start positions of blocks in a line. + std::vector position; + for (auto & b : ln) + { + position.push_back(str.size()); + str += b.data_ptr->text(); + } + + std::remove_reference::type dump; + dump.swap(ln); + + auto entities = unicode_bidi{}.reorder(str.c_str(), str.size()); + for (auto & e : entities) + { + auto pos = e.begin - str.c_str(); + + auto i = std::find(position.cbegin(), position.cend(), pos); + + //If the pos is not a start position, it indicates the block of bidi entity has been inserted into + //the ln container. Because the content of a block may be divided into multiple bidi entities. + if (i == position.cend()) + continue; + + ln.push_back(dump[i - position.cbegin()]); + + auto const endpos = e.end - str.c_str(); + //Check whether the next position is belone to current entity. + while (++i != position.cend()) + { + if (*i < static_cast(endpos)) + { + ln.push_back(dump[i - position.cbegin()]); + } + else + break; + } + } + } + } + + iterator begin() + { + return lines_.begin(); + } + + iterator end() + { + return lines_.end(); + } + private: + void _m_parse_format(tokenizer & tknizer, std::stack & fbstack) + { + fblock * fp = _m_inhert_from(fbstack.top()); + + attr_image_.reset(); + + while(true) + { + switch(tknizer.read()) + { + case token::comma: //Eat the comma, now the comma can be omitted. + break; + case token::eof: + case token::tag_end: + fblocks_.push_back(fp); + fbstack.push(fp); + return; + case token::font: + if(token::equal != tknizer.read()) + throw std::runtime_error(""); + + if(token::string != tknizer.read()) + throw std::runtime_error(""); + + fp->font = to_utf8(tknizer.idstr()); + break; + case token::size: + if(token::equal != tknizer.read()) + throw std::runtime_error(""); + + switch(tknizer.read()) + { + case token::number: + fp->font_size = tknizer.number(); + break; + case token::binary: + { + auto value = tknizer.binary_number(); + attr_image_.size.width = value.first; + attr_image_.size.height = value.second; + } + break; + default: + throw std::runtime_error(""); + } + break; + case token::color: + if(token::equal != tknizer.read()) + throw std::runtime_error(""); + + switch(tknizer.read()) + { + case token::number: + { + pixel_color_t px; + px.value = static_cast(tknizer.number()); + fp->fgcolor = {px.element.red, px.element.green, px.element.blue}; + } + break; + case token::red: + fp->fgcolor = colors::red; + break; + case token::green: + fp->fgcolor = colors::green; + break; + case token::blue: + fp->fgcolor = colors::blue; + break; + case token::white: + fp->fgcolor = colors::white; + break; + case token::black: + fp->fgcolor = colors::black; + break; + default: + throw std::runtime_error(""); + } + break; + case token::red: //support the omitting of color. + fp->fgcolor = colors::red; + break; + case token::green: //support the omitting of color. + fp->fgcolor = colors::green; + break; + case token::blue: //support the omitting of color. + fp->fgcolor = colors::blue; + break; + case token::white: //support the omitting of color. + fp->fgcolor = colors::white; + break; + case token::black: //support the omitting of color. + fp->fgcolor = colors::black; + break; + case token::baseline: + fp->text_align = fblock::aligns::baseline; + break; + case token::top: + fp->text_align = fblock::aligns::top; + break; + case token::center: + fp->text_align = fblock::aligns::center; + break; + case token::bottom: + fp->text_align = fblock::aligns::bottom; + break; + case token::image: + if(token::equal != tknizer.read()) + throw std::runtime_error(""); + + if(token::string != tknizer.read()) + throw std::runtime_error(""); + + attr_image_.path = tknizer.idstr(); + break; + case token::min_limited: + attr_image_.limited = 1; + break; + case token::max_limited: + attr_image_.limited = 2; + break; + case token::target: + if(token::equal != tknizer.read()) + throw std::runtime_error("error: a '=' is required behind 'target'"); + + if(token::string != tknizer.read()) + throw std::runtime_error("error: the value of 'target' should be a string"); + + fp->target = tknizer.idstr(); + break; + case token::url: + if(token::equal != tknizer.read()) + throw std::runtime_error("error: a '=' is required behind 'url'"); + + if(token::string != tknizer.read()) + throw std::runtime_error("error: the value of 'url' should be a string"); + + fp->url = tknizer.idstr(); + break; + case token::bold: + { + token tk = tknizer.read(); + if(token::equal == tk) + { + switch(tknizer.read()) + { + case token::_true: + fp->bold = true; + break; + case token::_false: + fp->bold = false; + break; + default: + throw std::runtime_error(""); + } + } + else + { + tknizer.push(tk); + fp->bold = true; + } + fp->bold_empty = false; + } + break; + default: + throw std::runtime_error(""); + } + } + } + + fblock* _m_create_default_fblock() + { + //Make sure that there is not a fblock is created. + if(fblocks_.size()) + return fblocks_.front(); + + //Create a default fblock. + fblock * fbp = new fblock; + + fbp->font_size = -1; + fbp->bold = false; + fbp->bold_empty = true; + fbp->text_align = fblock::aligns::baseline; + + fbp->parent = nullptr; + + fblocks_.push_back(fbp); + lines_.emplace_back(); + + return fbp; + } + + fblock * _m_inhert_from(fblock* fp) + { + fblock * fbp = new fblock; + + fbp->font = fp->font; + fbp->font_size = fp->font_size; + fbp->bold = fp->bold; + fbp->bold_empty = fp->bold_empty; + fbp->text_align = fp->text_align; + + fbp->bgcolor = fp->bgcolor; + fbp->fgcolor = fp->fgcolor; + + fbp->target = fp->target; + + fbp->parent = fp; + + return fbp; + } + + void _m_data_factory(token tk, const std::wstring& idstr, fblock* fp, std::deque& line) + { + value v; + v.fblock_ptr = fp; + + switch(tk) + { + case token::data: + v.data_ptr = new data_text(idstr); + break; + default: + break; + } + + line.push_back(v); + } + + void _m_data_image(fblock* fp, std::deque& line) + { + value v; + v.fblock_ptr = fp; + + v.data_ptr = new data_image(attr_image_.path, attr_image_.size, attr_image_.limited); + + line.push_back(v); + } + + private: + std::vector fblocks_; + std::list > lines_; + + struct attr_image_tag + { + std::wstring path; + nana::size size; + std::size_t limited; + + void reset() + { + path.clear(); + size.width = size.height = 0; + limited = 0; + } + }attr_image_; + }; +}//end namespace skeletons +}//end namespace widgets +}//end namepsace nana +#include +#endif //NANA_GUI_WIDGETS_SKELETONS_TEXT_TOKEN_STREAM diff --git a/GUI/nana/gui/widgets/skeletons/textbase.hpp b/GUI/nana/gui/widgets/skeletons/textbase.hpp new file mode 100644 index 0000000..1800fc7 --- /dev/null +++ b/GUI/nana/gui/widgets/skeletons/textbase.hpp @@ -0,0 +1,541 @@ +/* + * A textbase class implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/skeletons/textbase.hpp + * @description: This class manages the multi-line text and provides some operation on text + */ + +#ifndef NANA_GUI_WIDGET_DETAIL_TEXTBASE_HPP +#define NANA_GUI_WIDGET_DETAIL_TEXTBASE_HPP +#include + +#include +#include +#include +#include + +#include "textbase_export_interface.hpp" + +#include +#include +#include + +namespace nana +{ +namespace widgets +{ +namespace skeletons +{ + template + class textbase + : public ::nana::noncopyable + { + public: + using char_type = CharT; + using string_type = std::basic_string; + using size_type = typename string_type::size_type; + using path_type = std::filesystem::path; + + textbase() + { + attr_max_.reset(); + //Insert an empty string for the first line of empty text. + text_cont_.emplace_back(); + } + + void set_event_agent(textbase_event_agent_interface * evt) + { + evt_agent_ = evt; + } + + bool empty() const + { + return (text_cont_.empty() || + ((text_cont_.size() == 1) && text_cont_.front().empty())); + } + + bool load(const path_type& file) + { + std::ifstream ifs{ file.string() }; + if (!ifs) + return false; + + std::error_code err; + auto const bytes = file_size(file, err); + if (err) + return false; + + if(bytes >= 2) + { + int ch = ifs.get(); + if(0xEF == ch && bytes >= 3) + { + //UTF8 + ch = ifs.get(); + if(0xBB == ch && 0xBF == ifs.get()) + { + ifs.close(); + return load(file, nana::unicode::utf8); + } + } + else if(0xFF == ch) + { + if(0xFE == ifs.get()) + { + //UTF16,UTF32 + if((bytes >= 4) && (ifs.get() == 0 && ifs.get() == 0)) + { + ifs.close(); + return load(file, nana::unicode::utf32); + } + ifs.close(); + return load(file, nana::unicode::utf16); + } + } + else if(0xFE == ch) + { + if(ifs.get() == 0xFF) + { + //UTF16(big-endian) + ifs.close(); + return load(file, nana::unicode::utf16); + } + } + else if(0 == ch) + { + if(bytes >= 4 && ifs.get() == 0) + { + ch = ifs.get(); + if(0xFE == ch && ifs.get() == 0xFF) + { + //UTF32(big_endian) + ifs.close(); + return load(file, nana::unicode::utf32); + } + } + } + } + + ifs.clear(); + ifs.seekg(0, std::ios::beg); + + text_cont_.clear(); //Clear only if the file can be opened. + attr_max_.reset(); + + std::string str_mbs; + while(ifs.good()) + { + std::getline(ifs, str_mbs); + text_cont_.emplace_back(static_cast(nana::charset{ str_mbs })); + if (text_cont_.back().size() > attr_max_.size) + { + attr_max_.size = text_cont_.back().size(); + attr_max_.line = text_cont_.size() - 1; + } + } + + _m_saved(file); + return true; + } + + static void byte_order_translate_2bytes(std::string& str) + { + char * s = const_cast(str.c_str()); + char * end = s + str.size(); + for(; s < end; s += 2) + { + char c = *s; + *s = *(s + 1); + *(s + 1) = c; + } + } + + static void byte_order_translate_4bytes(std::string& str) + { + char * s = const_cast(str.c_str()); + char * end = s + str.size(); + for(; s < end; s += 4) + { + char c = *s; + *s = *(s + 3); + *(s + 3) = c; + + c = *(s + 1); + *(s + 1) = *(s + 2); + *(s + 2) = c; + } + } + + bool load(const path_type& file, nana::unicode encoding) + { + std::ifstream ifs{ file.string() }; + + if (!ifs) + return false; + + std::string str; + bool big_endian = true; + + if(ifs.good()) + { + text_cont_.clear(); //Clear only if the file can be opened. + attr_max_.reset(); + + std::getline(ifs, str); + + std::size_t len_of_BOM = 0; + switch(encoding) + { + case nana::unicode::utf8: + len_of_BOM = 3; break; + case nana::unicode::utf16: + len_of_BOM = 2; break; + case nana::unicode::utf32: + len_of_BOM = 4; break; + default: + throw std::runtime_error("Specified a wrong UTF"); + } + + big_endian = (str[0] == 0x00 || str[0] == char(0xFE)); + str.erase(0, len_of_BOM); + if(big_endian) + { + if(nana::unicode::utf16 == encoding) + byte_order_translate_2bytes(str); + else + byte_order_translate_4bytes(str); + } + + text_cont_.emplace_back(static_cast(nana::charset{ str, encoding })); + attr_max_.size = text_cont_.back().size(); + attr_max_.line = 0; + } + + while(ifs.good()) + { + std::getline(ifs, str); + + if(big_endian) + { + if(nana::unicode::utf16 == encoding) + byte_order_translate_2bytes(str); + else + byte_order_translate_4bytes(str); + } + + text_cont_.emplace_back(static_cast(nana::charset{ str, encoding })); + if (text_cont_.back().size() > attr_max_.size) + { + attr_max_.size = text_cont_.back().size(); + attr_max_.line = text_cont_.size() - 1; + } + } + + _m_saved(file); + return true; + } + + void store(const path_type& filename, bool is_unicode, ::nana::unicode encoding) const + { + std::ofstream ofs(filename.string(), std::ios::binary); + if(ofs && text_cont_.size()) + { + auto i = text_cont_.cbegin(); + auto const count = text_cont_.size() - 1; + + std::string last_mbs; + + if (is_unicode) + { + const char * le_boms[] = { "\xEF\xBB\xBF", "\xFF\xFE", "\xFF\xFE\x0\x0" }; //BOM for little-endian + int bytes = 0; + switch (encoding) + { + case nana::unicode::utf8: + bytes = 3; break; + case nana::unicode::utf16: + bytes = 2; break; + case nana::unicode::utf32: + bytes = 4; break; + } + + if (bytes) + ofs.write(le_boms[static_cast(encoding)], bytes); + + for (std::size_t pos = 0; pos < count; ++pos) + { + auto mbs = nana::charset(*(i++)).to_bytes(encoding); + ofs.write(mbs.c_str(), static_cast(mbs.size())); + ofs.write("\r\n", 2); + } + + last_mbs = nana::charset(text_cont_.back()).to_bytes(encoding); + } + else + { + for (std::size_t pos = 0; pos < count; ++pos) + { + std::string mbs = nana::charset(*(i++)); + ofs.write(mbs.c_str(), mbs.size()); + ofs.write("\r\n", 2); + } + last_mbs = nana::charset(text_cont_.back()); + } + + ofs.write(last_mbs.c_str(), static_cast(last_mbs.size())); + _m_saved(filename); + } + } + + //Triggers the text_changed event. + //It is exposed for outter classes. For a outter class(eg. text_editor), a changing text content operation + //may contains multiple textbase operations, therefore, the outter class determines when an event should be triggered. + // + //Addtional, using text_changed() method, it is possible to allow a outter class performing some updating operations + //before triggering text_changed event. + void text_changed() + { + if (!changed_) + { + _m_emit_first_change(); + changed_ = true; + } + + if (edited_) + { + if (evt_agent_) + evt_agent_->text_changed(); + + edited_ = false; + } + } + + size_type lines() const + { + return text_cont_.size(); + } + + const string_type& getline(size_type pos) const + { + if (pos < text_cont_.size()) + return text_cont_[pos]; + return nullstr_; + } + + std::pair max_line() const + { + return std::make_pair(attr_max_.line, attr_max_.size); + } + public: + void replace(size_type pos, string_type && text) + { + if (text_cont_.size() <= pos) + { + text_cont_.emplace_back(std::move(text)); + pos = text_cont_.size() - 1; + } + else + _m_at(pos).swap(text); + + _m_make_max(pos); + edited_ = true; + } + + void insert(upoint pos, string_type && str) + { + if(pos.y < text_cont_.size()) + { + string_type& lnstr = _m_at(pos.y); + + if(pos.x < lnstr.size()) + lnstr.insert(pos.x, str); + else + lnstr += str; + } + else + { + text_cont_.emplace_back(std::move(str)); + pos.y = static_cast(text_cont_.size() - 1); + } + + _m_make_max(pos.y); + edited_ = true; + } + + void insertln(size_type pos, string_type&& str) + { + if (pos < text_cont_.size()) + text_cont_.emplace(_m_iat(pos), std::move(str)); + else + text_cont_.emplace_back(std::move(str)); + + _m_make_max(pos); + edited_ = true; + } + + void erase(size_type line, size_type pos, size_type count) + { + if (line < text_cont_.size()) + { + string_type& lnstr = _m_at(line); + if ((pos == 0) && (count >= lnstr.size())) + lnstr.clear(); + else + lnstr.erase(pos, count); + + if (attr_max_.line == line) + _m_scan_for_max(); + + edited_ = true; + } + } + + bool erase(size_type pos, std::size_t n) + { + //Bounds checking + if ((pos >= text_cont_.size()) || (0 == n)) + return false; + + if (pos + n > text_cont_.size()) + n = text_cont_.size() - pos; + + text_cont_.erase(_m_iat(pos), _m_iat(pos + n)); + + if (pos <= attr_max_.line && attr_max_.line < pos + n) + _m_scan_for_max(); + else if (pos < attr_max_.line) + attr_max_.line -= n; + + edited_ = true; + return true; + } + + void erase_all() + { + text_cont_.clear(); + attr_max_.reset(); + text_cont_.emplace_back(); //text_cont_ must not be empty + + _m_saved({}); + } + + void merge(size_type pos) + { + if(pos + 1 < text_cont_.size()) + { + auto i = _m_iat(pos + 1); + _m_at(pos) += *i; + + text_cont_.erase(i); + _m_make_max(pos); + + //If the maxline is behind the pos line, + //decrease the maxline. Because a line between maxline and pos line + //has been deleted. + if(pos < attr_max_.line) + --attr_max_.line; + + edited_ = true; + } + } + + const path_type& filename() const + { + return filename_; + } + + bool edited() const + { + return changed_; + } + + void reset_status(bool remain_saved_filename) + { + if(!remain_saved_filename) + filename_.clear(); + + changed_ = false; + } + + bool saved() const + { + return !(changed_ || filename_.empty()); + } + private: + string_type& _m_at(size_type pos) + { + return *_m_iat(pos); + } + + typename std::deque::iterator _m_iat(size_type pos) + { + return text_cont_.begin() + pos; + } + + void _m_make_max(std::size_t pos) + { + const string_type& str = _m_at(pos); + if(str.size() > attr_max_.size) + { + attr_max_.size = str.size(); + attr_max_.line = pos; + } + } + + void _m_scan_for_max() + { + attr_max_.reset(); + for (std::size_t i = 0; i < text_cont_.size(); ++i) + _m_make_max(i); + } + + void _m_emit_first_change() const + { + if (evt_agent_) + evt_agent_->first_change(); + } + + void _m_saved(const path_type& filename) const + { + if((filename_ != filename) || changed_) + { + filename_ = filename; + _m_emit_first_change(); + } + + changed_ = false; + } + private: + std::deque text_cont_; + textbase_event_agent_interface* evt_agent_{ nullptr }; + + mutable bool changed_{ false }; + mutable bool edited_{ false }; + mutable path_type filename_; ///< The saved filename + const string_type nullstr_; + + struct attr_max + { + std::size_t line; ///< The line number of max line + std::size_t size; ///< The number of characters in max line + + void reset() + { + line = 0; + size = 0; + } + }attr_max_; + }; + +}//end namespace detail +}//end namespace widgets +}//end namespace nana +#include + +#endif diff --git a/GUI/nana/gui/widgets/skeletons/textbase_export_interface.hpp b/GUI/nana/gui/widgets/skeletons/textbase_export_interface.hpp new file mode 100644 index 0000000..eeda5b4 --- /dev/null +++ b/GUI/nana/gui/widgets/skeletons/textbase_export_interface.hpp @@ -0,0 +1,33 @@ +/* + * Definitions of textbase export interfaces + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/skeletons/textbase_export_interface.hpp + * @description: It is defined outside, some headers like textbox should not include a whole textbase for its ext_evtbase + * + */ + +#ifndef NANA_GUI_WIDGET_TEXTBASE_EXPORT_INTERFACE_HPP +#define NANA_GUI_WIDGET_TEXTBASE_EXPORT_INTERFACE_HPP + +namespace nana{ namespace widgets +{ + namespace skeletons + { + class textbase_event_agent_interface + { + public: + virtual ~textbase_event_agent_interface() = default; + + virtual void first_change() = 0; ///< An event for the text first change after text has been opened or stored. + virtual void text_changed() = 0; ///< An event for the change of text. + }; + }//end namespace skeletons +}//end namespace widgets +}//end namespace nana +#endif //NANA_GUI_WIDGET_TEXTBASE_EXPORT_INTERFACE_HPP diff --git a/GUI/nana/gui/widgets/slider.hpp b/GUI/nana/gui/widgets/slider.hpp new file mode 100644 index 0000000..5cbffa9 --- /dev/null +++ b/GUI/nana/gui/widgets/slider.hpp @@ -0,0 +1,175 @@ +/** + * A Slider Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/slider.hpp + */ +#ifndef NANA_GUI_WIDGETS_SLIDER_HPP +#define NANA_GUI_WIDGETS_SLIDER_HPP + +#include + +#include "widget.hpp" +#include + +namespace nana +{ + class slider; + + struct arg_slider + : public event_arg + { + slider & widget; + + arg_slider(slider&); + }; + + namespace drawerbase + { + namespace slider + { + + struct scheme_impl + : public widget_geometrics + { + /// Colors + color_proxy color_adorn { static_cast(0x3da3ce) }; + color_proxy color_bar { static_cast(0x878787) }; + color_proxy color_slider { static_cast(0x606060) }; + color_proxy color_slider_highlighted{ static_cast(0x2d93be) }; + color_proxy color_vernier { colors::red }; + color_proxy color_vernier_text { colors::white }; + + /// Geometrical parameters + unsigned vernier_text_margin{ 8 }; + + }; + + struct slider_events + : public general_events + { + basic_event value_changed; + }; + + enum class seekdir + { + bilateral, forward, backward + }; + + + class renderer_interface + { + public: + using graph_reference = ::nana::paint::graphics&; + using scheme = scheme_impl; + + struct data_bar + { + bool vert; ///< Indicates whether the slider is vertical. + ::nana::rectangle area; ///< Position and size of bar. + unsigned border_weight; ///< The border weight in pixels. + }; + + struct data_slider + { + bool vert; ///< Indicates whether the slider is vertical. + double pos; + unsigned border_weight; + unsigned weight; + }; + + struct data_adorn + { + bool vert; ///< Indicates whether the slider is vertical. + ::nana::point bound; + int fixedpos; + unsigned block; + unsigned vcur_scale; + }; + + struct data_vernier + { + bool vert; ///< Indicates whether the slider is vertical. + int position; + int end_position; + unsigned knob_weight; + + std::string text; + }; + + virtual ~renderer_interface() = default; + + virtual void background(window, graph_reference, bool transparent, const scheme&) = 0; + virtual void adorn(window, graph_reference, const data_adorn&, const scheme&) = 0; + virtual void vernier(window, graph_reference, const data_vernier&, const scheme&) = 0; + virtual void bar(window, graph_reference, const data_bar&, const scheme&) = 0; + virtual void slider(window, graph_reference, mouse_action, const data_slider&, const scheme&) = 0; + }; + + class trigger + : public drawer_trigger + { + class model; + public: + trigger(); + ~trigger(); + model* get_model() const; + private: + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void resized(graph_reference, const arg_resized&) override; + private: + model * model_ptr_; + }; + }//end namespace slider + }//end namespace drawerbase + + + /// A slider widget which the user can drag for tracking + class slider + : public widget_object + { + public: + using renderer_interface = drawerbase::slider::renderer_interface; ///< The interface for customized renderer. + using seekdir = drawerbase::slider::seekdir; ///< Defines the slider seek direction. + + slider(); + slider(window, bool visible); + slider(window, const rectangle& = rectangle(), bool visible = true); + + void seek(seekdir); ///< Define the direction that user can seek by using mouse. + void vertical(bool); + bool vertical() const; + void maximum(unsigned); + unsigned maximum() const; + + /** Set slider value + @param[in] v new value for slider. + v will be clipped to the range 0 to maximum + */ + void value(int ); + + unsigned value() const; + unsigned move_step(bool forward); ///< Increase or decrease the value of slider. + unsigned adorn() const; + + const pat::cloneable& renderer(); ///< Refers to the current renderer that slider is using. + void renderer(const pat::cloneable&); ///< Set the current renderer. + + void vernier(std::function provider); + void transparent(bool); + bool transparent() const; + }; +}//end namespace nana +#include + +#endif diff --git a/GUI/nana/gui/widgets/spinbox.hpp b/GUI/nana/gui/widgets/spinbox.hpp new file mode 100644 index 0000000..ee99e14 --- /dev/null +++ b/GUI/nana/gui/widgets/spinbox.hpp @@ -0,0 +1,128 @@ +/** + * A Spin box widget + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/spinbox.hpp + */ + +#ifndef NANA_GUI_WIDGET_SPINBOX_HPP +#define NANA_GUI_WIDGET_SPINBOX_HPP + +#include +#include "widget.hpp" +#include "skeletons/text_editor_part.hpp" + +namespace nana +{ + class spinbox; + + struct arg_spinbox + : public event_arg + { + spinbox & widget; + arg_spinbox(spinbox&); + }; + + namespace drawerbase + { + namespace spinbox + { + struct spinbox_events + : public general_events + { + basic_event text_changed; + }; + + /// Declaration of internal spinbox implementation + class implementation; + + /// Drawer of spinbox + class drawer + : public ::nana::drawer_trigger + { + drawer(const drawer&) = delete; + drawer(drawer&&) = delete; + drawer& operator=(const drawer&) = delete; + drawer& operator=(drawer&&) = delete; + public: + drawer(); + ~drawer(); + implementation * impl() const; + private: + //Overrides drawer_trigger + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + + void focus(graph_reference, const arg_focus&) override; + void mouse_wheel(graph_reference, const arg_wheel&) override; + void dbl_click(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse& arg) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void key_ime(graph_reference, const arg_ime& arg) override; + void key_press(graph_reference, const arg_keyboard&) override; + void key_char(graph_reference, const arg_keyboard&) override; + void resized(graph_reference, const arg_resized&) override; + private: + implementation * const impl_; + }; + } + }//end namespace drawerbase + + /// Spinbox Widget + class spinbox + : public widget_object + { + public: + /// Constructs a spinbox. + spinbox(); + spinbox(window, bool visible); + spinbox(window, const nana::rectangle& = {}, bool visible = true); + + /// Sets the widget whether it accepts user keyboard input. + /// @param accept Set to indicate whether it accepts user keyboard input. + void editable(bool accept); + + /// Determines whether the widget accepts user keyboard input. + bool editable() const; + + /// Sets the numeric spin values and step. + void range(int begin, int last, int step); + void range(double begin, double last, double step); + + /// Sets the string spin values. + void range(std::vector values_utf8); + + std::vector range_string() const; + std::pair range_int() const; + std::pair range_double() const; + + /// Selects/Deselects the text + void select(bool); + + /// Gets the spun value + ::std::string value() const; + void value(const ::std::string&); + int to_int() const; + double to_double() const; + + /// Sets the modifiers + void modifier(std::string prefix_utf8, std::string suffix_utf8); + void modifier(const std::wstring & prefix, const std::wstring& suffix); + private: + native_string_type _m_caption() const noexcept; + void _m_caption(native_string_type&&); + }; //end class spinbox +}//end namespace nana +#include +#endif //NANA_GUI_WIDGET_SPINBOX_HPP diff --git a/GUI/nana/gui/widgets/tabbar.hpp b/GUI/nana/gui/widgets/tabbar.hpp new file mode 100644 index 0000000..7d3246a --- /dev/null +++ b/GUI/nana/gui/widgets/tabbar.hpp @@ -0,0 +1,480 @@ +/** + * A Tabbar implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/tabbar.hpp + * @brief A tabbar contains tab items and toolbox for scrolling, closing, selecting items. + * + */ +#ifndef NANA_GUI_WIDGET_TABBAR_HPP +#define NANA_GUI_WIDGET_TABBAR_HPP +#include + +#include "widget.hpp" +#include +#include + +namespace nana +{ + template class tabbar; + + template + struct arg_tabbar + : public event_arg + { + tabbar & widget; + T & value; + std::size_t item_pos; ///< position of the item + + arg_tabbar(tabbar& wdg, T& v, std::size_t p) + : widget(wdg), value{ v }, item_pos(p) + {} + }; + + template + struct arg_tabbar_click : public arg_tabbar + { + arg_tabbar_click(tabbar& wdg, T& v, std::size_t p) + : arg_tabbar({wdg, v, p}) + {} + + bool left_button = false; ///< true if mouse left button is pressed + bool mid_button = false; ///< true if mouse middle button is pressed + bool right_button = false; ///< true if mouse right button is pressed + }; + + template + struct arg_tabbar_mouse + : public arg_mouse + { + arg_tabbar_mouse(const arg_mouse& arg, tabbar& wdg, T& v, std::size_t p) + : arg_mouse{ arg }, widget(wdg), value{ v }, item_pos(p) + {} + + tabbar & widget; + T & value; + std::size_t item_pos; ///< position of the item + }; + + template + struct arg_tabbar_adding + : public event_arg + { + arg_tabbar_adding(tabbar& wdg, std::size_t p) + : widget(wdg), where(p) + {} + + tabbar & widget; + mutable bool add = true; ///< determines whether to add the item + std::size_t where; ///< position where to add the item + }; + + template + struct arg_tabbar_removed : public arg_tabbar + { + arg_tabbar_removed(tabbar& wdg, T& v, std::size_t p) + : arg_tabbar({wdg, v, p}) + {} + + mutable bool remove = true; ///< determines whether to remove the item + mutable bool close_attach_window = true; ///< determines whether to close the attached window. It is ignored if remove is false + }; + + namespace drawerbase + { + namespace tabbar + { + template + struct tabbar_events + : public general_events + { + using value_type = T; + + basic_event> adding; + basic_event> added; + basic_event> tab_click; + basic_event> activated; + basic_event> removed; + }; + + class event_agent_interface + { + public: + virtual ~event_agent_interface() = default; + virtual bool adding(std::size_t) = 0; + virtual void added(std::size_t) = 0; + virtual bool click(const arg_mouse&, std::size_t) = 0; + virtual void activated(std::size_t) = 0; + virtual bool removed(std::size_t, bool & close_attached) = 0; + }; + + class item_renderer + { + public: + typedef item_renderer item_renderer_type; + typedef ::nana::paint::graphics & graph_reference; + enum state_t{disable, normal, highlight, press}; + + struct item_t + { + ::nana::rectangle r; + ::nana::color bgcolor; + ::nana::color fgcolor; + }; + + virtual ~item_renderer() = default; + virtual void background(graph_reference, const nana::rectangle& r, const ::nana::color& bgcolor) = 0; + virtual void item(graph_reference, const item_t&, bool active, state_t) = 0; + virtual void close_fly(graph_reference, const nana::rectangle&, bool active, state_t) = 0; + + virtual void add(graph_reference, const nana::rectangle&, state_t) = 0; + virtual void close(graph_reference, const nana::rectangle&, state_t) = 0; + virtual void back(graph_reference, const nana::rectangle&, state_t) = 0; + virtual void next(graph_reference, const nana::rectangle&, state_t) = 0; + virtual void list(graph_reference, const nana::rectangle&, state_t) = 0; + }; + + template + class event_agent + : public event_agent_interface + { + public: + using arg_tabbar = ::nana::arg_tabbar; + + event_agent(::nana::tabbar& tb, DrawerTrigger & dtr) + : tabbar_(tb), drawer_trigger_(dtr) + {} + + bool adding(std::size_t pos) override + { + ::nana::arg_tabbar_adding arg_ta(tabbar_, pos); + tabbar_.events().adding.emit(arg_ta, tabbar_); + return arg_ta.add; + } + + void added(std::size_t pos) override + { + if(pos != npos) + { + drawer_trigger_.at_no_bound_check(pos) = T(); + tabbar_.events().added.emit(arg_tabbar({ tabbar_, tabbar_[pos], pos }), tabbar_); + } + } + + bool click(const arg_mouse& arg, std::size_t pos) override + { + ::nana::arg_tabbar_mouse arg_tm(arg, tabbar_, tabbar_[pos], pos); + tabbar_.events().tab_click.emit(arg_tm, tabbar_); + return arg_tm.propagation_stopped(); + } + + void activated(std::size_t pos) override + { + if(pos != npos) + tabbar_.events().activated.emit(arg_tabbar({ tabbar_, tabbar_[pos], pos}), tabbar_); + } + + bool removed(std::size_t pos, bool & close_attach) override + { + if(pos != npos) + { + ::nana::arg_tabbar_removed arg(tabbar_, tabbar_[pos], pos); + tabbar_.events().removed.emit(arg, tabbar_); + close_attach = arg.close_attach_window; + return arg.remove; + } + close_attach = true; + return true; + } + private: + ::nana::tabbar & tabbar_; + DrawerTrigger& drawer_trigger_; + }; + + class layouter; + + class trigger + : public drawer_trigger + { + public: + using native_string_type = ::nana::detail::native_string_type; + + enum class kits + { + add, ///< The type identifies the add button of the tabbar's toolbox. + scroll, ///< The type identifies the scroll button of the tabbar's toolbox + list, ///< The type identifies the list button of the tabbar's toolbox + close ///< The type identifies the close button of the tabbar's toolbox + }; + + trigger(); + ~trigger(); + void activate(std::size_t); + std::size_t activated() const; + nana::any& at(std::size_t) const; + nana::any& at_no_bound_check(std::size_t) const; + const pat::cloneable & ext_renderer() const; + void ext_renderer(const pat::cloneable&); + void set_event_agent(event_agent_interface*); + void insert(std::size_t, native_string_type&&, nana::any&&); + std::size_t length() const; + bool close_fly(bool); + window attach(std::size_t, window, bool drop_other); + void erase(std::size_t); + void tab_color(std::size_t, bool is_bgcolor, const ::nana::color&); + void tab_image(size_t, const nana::paint::image&); + void text(std::size_t, const native_string_type&); + native_string_type text(std::size_t) const; + bool toolbox(kits, bool); + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + private: + layouter * layouter_; + }; + } + }//end namespace drawerbase + /// Analogous to dividers in a notebook or the labels in a file cabinet + template + class tabbar + : public widget_object> + { + typedef drawerbase::tabbar::trigger drawer_trigger_t; + public: + using value_type = Type; ///< The type of element data which is stored in the tabbar. + using item_renderer = drawerbase::tabbar::item_renderer; ///< A user-defined item renderer should be derived from this interface. + using kits = drawer_trigger_t::kits; + + tabbar() + { + evt_agent_.reset(new drawerbase::tabbar::event_agent(*this, this->get_drawer_trigger())); + this->get_drawer_trigger().set_event_agent(evt_agent_.get()); + } + + tabbar(window wd, bool visible) + : tabbar() + { + this->create(wd, rectangle(), visible); + } + + tabbar(window wd, const rectangle& r = rectangle(), bool visible = true) + : tabbar() + { + this->create(wd, r, visible); + } + + ~tabbar() + { + this->get_drawer_trigger().set_event_agent(nullptr); + } + + value_type & operator[](std::size_t pos) const + { + return any_cast(this->get_drawer_trigger().at_no_bound_check(pos)); + } + + void activated(std::size_t pos) /// Activates a tab specified by pos. + { + this->get_drawer_trigger().activate(pos); + } + + std::size_t activated() const + { + return this->get_drawer_trigger().activated(); + } + + value_type const & at(std::size_t pos) const /// Returns pos'th element + { + return any_cast(this->get_drawer_trigger().at(pos)); + } + + void close_fly(bool fly) /// Draw or not a close button in each tab. + { + if (this->get_drawer_trigger().close_fly(fly)) + API::refresh_window(this->handle()); + } + + const pat::cloneable& renderer() const + { + return this->get_drawer_trigger().ext_renderer(); + } + + void renderer(const pat::cloneable& ir) + { + this->get_drawer_trigger().ext_renderer(ir); + } + + std::size_t length() const /// Returns the number of items. + { + return this->get_drawer_trigger().length(); + } + + /// Append a new tab + tabbar& append(std::string text, window attach_wd, value_type value = {}) // 2x text convertion. maybe better to duplicate code? + { + return this->append( static_cast(nana::charset(std::move(text), nana::unicode::utf8)), attach_wd, std::move(value)); + } + + tabbar& append(std::wstring text, window attach_wd, value_type value = {}) + { + if (attach_wd && API::empty_window(attach_wd)) + throw std::invalid_argument("Appending a tab to a tabbar - error: tabbar.attach: invalid window handle"); + + this->get_drawer_trigger().insert(::nana::npos, to_nstring(std::move(text)), std::move(value)); + if (attach_wd) + this->attach(this->get_drawer_trigger().length() - 1, attach_wd); + + API::update_window(*this); + return *this; + } + + void push_back(std::string text) /// Append a new item. + { + this->get_drawer_trigger().insert(::nana::npos, to_nstring(std::move(text)), value_type()); + API::update_window(*this); + } + + void insert(std::size_t pos, std::string text, value_type value = {}) + { + if (pos > length()) + throw std::out_of_range("tabbar::insert invalid position"); + + this->get_drawer_trigger().insert(pos, to_nstring(std::move(text)), std::move(value)); + API::update_window(*this); + } + + void insert(std::size_t pos, std::wstring text, value_type value = {}) + { + if (pos > length()) + throw std::out_of_range("tabbar::insert invalid position"); + + this->get_drawer_trigger().insert(pos, to_nstring(std::move(text)), std::move(value)); + API::update_window(*this); + } + + /// Attach a window to a specified tab. When the tab is activated, tabbar shows the attached window. + /** + * @param pos The position of tab to set the attached window. + * @param attach_wd A handle to the window to be set. + * @param drop_other Drop the attached windows of other tabs whose attach windows are equal to the parameter attach_wd. If drop_other is true, the other tabs attached windows equal to attach_wd will be dropped. + * @return A handle to the last attached window of specified tab. + */ + window attach(std::size_t pos, window attach_wd, bool drop_other = true) + { + if (attach_wd && API::empty_window(attach_wd)) + throw std::invalid_argument("tabbar.attach: invalid window handle"); + + return this->get_drawer_trigger().attach(pos, attach_wd, drop_other); + } + + void erase(std::size_t pos) + { + this->get_drawer_trigger().erase(pos); + } + + void tab_bgcolor(std::size_t pos, const ::nana::color& clr) + { + this->get_drawer_trigger().tab_color(pos, true, clr); + } + + void tab_fgcolor(std::size_t pos, const ::nana::color& clr) + { + this->get_drawer_trigger().tab_color(pos, false, clr); + } + + void tab_image(std::size_t pos, const nana::paint::image& img) + { + this->get_drawer_trigger().tab_image(pos, img); + } + + /// Sets buttons of the tabbar's toolbox, refer to notes for more details. + void toolbox(kits kit, bool enable) + { + if (this->get_drawer_trigger().toolbox(kit, enable)) + API::refresh_window(this->handle()); + } + + void text(std::size_t pos, const std::string& str) /// Sets the title of the specified item, If pos is invalid, the method throws an std::out_of_range object. + { + this->get_drawer_trigger().text(pos, to_nstring(str)); + } + + std::string text(std::size_t pos) const /// Returns a title of a specified item, If pos is invalid, the method throws a std::out_of_range object. + { + return to_utf8(this->get_drawer_trigger().text(pos)); + } + private: + std::unique_ptr > evt_agent_; + }; +}//end namespace nana + + +namespace nana +{ + namespace drawerbase + { + namespace tabbar_lite + { + class model; + + struct events + : public general_events + { + basic_event selected; + }; + + class driver + : public drawer_trigger + { + public: + driver(); + ~driver(); + + model* get_model() const noexcept; + private: + //Overrides drawer_trigger's method + void attached(widget_reference, graph_reference) override; + void refresh(graph_reference) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + private: + model* const model_; + }; + } + }//end namespace drawerbase + + class tabbar_lite + : public widget_object + { + public: + tabbar_lite() = default; + tabbar_lite(window, bool visible = true, const::nana::rectangle& = {}); + + public: //capacity + std::size_t length() const; + + public: //modifiers + void attach(std::size_t pos, window); + window attach(std::size_t pos) const; + + void push_back(std::string text, ::nana::any par = {}); + void push_front(std::string text, ::nana::any par = {}); + + std::size_t selected() const; + void erase(std::size_t pos, bool close_attached = true); + }; +} +#include + +#endif diff --git a/GUI/nana/gui/widgets/textbox.hpp b/GUI/nana/gui/widgets/textbox.hpp new file mode 100644 index 0000000..8c7d745 --- /dev/null +++ b/GUI/nana/gui/widgets/textbox.hpp @@ -0,0 +1,305 @@ +/** + * A Textbox Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/textbox.hpp + */ +#ifndef NANA_GUI_WIDGET_TEXTBOX_HPP +#define NANA_GUI_WIDGET_TEXTBOX_HPP +#include + +#include +#include "skeletons/textbase_export_interface.hpp" +#include "skeletons/text_editor_part.hpp" + +#include + +namespace nana +{ + class textbox; + + struct arg_textbox + : public event_arg + { + textbox& widget; + const std::vector& text_position; ///< position of characters that the first character of line which are displayed + + arg_textbox(textbox&, const std::vector&); + }; + + namespace drawerbase + { + namespace textbox + { + struct textbox_events + : public general_events + { + basic_event first_change; + basic_event text_changed; + basic_event text_exposed; + }; + + class event_agent + : public widgets::skeletons::textbase_event_agent_interface, + public widgets::skeletons::text_editor_event_interface + { + public: + event_agent(::nana::textbox&, const std::vector&); + private: + //Overrides textbase_event_agent_interface + void first_change() override; + void text_changed() override; + private: + //Overrides text_editor_event_interface + void text_exposed(const std::vector&) override; + private: + ::nana::textbox & widget_; + const std::vector& text_position_; + }; + + //class drawer + class drawer + : public drawer_trigger + { + public: + using text_editor = widgets::skeletons::text_editor; + + drawer(); + text_editor * editor(); + const text_editor * editor() const; + private: + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void focus(graph_reference, const arg_focus&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_enter(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void dbl_click(graph_reference, const arg_mouse&) override; + void key_ime(graph_reference, const arg_ime&) override; + void key_press(graph_reference, const arg_keyboard&)override; + void key_char(graph_reference, const arg_keyboard&) override; + void mouse_wheel(graph_reference, const arg_wheel&) override; + void resized(graph_reference, const arg_resized&) override; + void typeface_changed(graph_reference) override; + private: + void _m_text_area(unsigned width, unsigned height); + private: + widget* widget_; + widgets::skeletons::text_editor * editor_; + std::unique_ptr evt_agent_; + }; + }//end namespace textbox + }//end namespace drawerbase + + /// Allow users to enter and edit text by typing on the keyboard. + class textbox + :public widget_object + { + public: + using colored_area_type = widgets::skeletons::colored_area_type; + using colored_area_access_interface = widgets::skeletons::colored_area_access_interface; + + using text_focus_behavior = widgets::skeletons::text_focus_behavior; + using text_positions = std::vector; + + using path_type = std::filesystem::path; + + /// The default constructor without creating the widget. + textbox(); + + /// \brief The construct that creates a widget. + /// @param wd A handle to the parent window of the widget being created. + /// @param visible specifying the visible after creating. + textbox(window, bool visible); + + /// \brief The construct that creates a widget with a specified text. + /// @param window A handle to the parent window of the widget being created. + /// @param text the text that will be displayed. + /// @param visible specifying the visible after creating. + textbox(window, const std::string& text, bool visible = true); + + /// \brief The construct that creates a widget with a specified text. + /// @param window A handle to the parent window of the widget being created. + /// @param text the text that will be displayed. + /// @param visible specifying the visible after creating. + textbox(window, const char* text, bool visible = true); + + /// \brief The construct that creates a widget. + /// @param window A handle to the parent window of the widget being created. + /// @param rectangle the size and position of the widget in its parent window coordinate. + /// @param visible specifying the visible after creating. + textbox(window, const rectangle& = rectangle(), bool visible = true); + + /// \brief Loads a text file. When attempt to load a unicode encoded text file, be sure the file have a BOM header. + void load(const path_type& file); + void store(const path_type& file); + void store(const path_type& file, nana::unicode encoding); + + colored_area_access_interface* colored_area_access(); + + point content_origin() const; + + /// Enables/disables the textbox to indent a line. Idents a new line when it is created by pressing enter. + /// @param generator generates text for identing a line. If it is empty, textbox indents the line according to last line. + textbox& indention(bool, std::function generator = {}); + + /// Discards the old text and set a new text. It also clears the filename/edited flags and undo command. + /// A workaround for reset, explicit default constructor syntax, because VC2013 incorrectly treats {} as {0}. + /* + * @param text A new text replaces the old text. + * @param end_caret Indicates whether to position the caret to the end of text. + * @return a reference of *this. + */ + textbox& reset(const std::string& text = std::string(), bool end_caret = true); ///< discard the old text and set a new text + + /// The file of last store operation. + path_type filename() const; + + /// Determine whether the text was edited. + bool edited() const; + + /// Reset the edited flag to false manually + textbox& edited_reset(); + + /// Determine whether the changed text has been saved into the file. + bool saved() const; + + /// Read the text from a specified line. It returns true for success. + bool getline(std::size_t pos, std::string&) const; + + /// Read the text from a specified line with a set offset. It returns true for success. + bool getline(std::size_t line_index,std::size_t offset,std::string& text) const; + + // Get all text from textbox. + // It returns a empty string if failed or the textbox is empty. + std::string text() const { return caption(); } + + /// Read the text from a specified line; returns an empty optional on failure + std::optional getline(std::size_t pos) const; + + ///Read the text from a specified line with a set offset. Returns an empty optional for + /// failure. + std::optional getline(std::size_t line_index, std::size_t offset) const; + + /// Gets the caret position + /// Returns true if the caret is in the area of display, false otherwise. + bool caret_pos(point& pos, bool text_coordinate) const; + + /// Gets the caret position, in text coordinate + upoint caret_pos() const; + + /// Sets the caret position with a text position + textbox& caret_pos(const upoint&); + + /// Appends an string. If `at_caret` is `true`, the string is inserted at the position of caret, otherwise, it is appended at end of the textbox. + textbox& append(const std::string& text, bool at_caret); + textbox& append(const std::wstring& text, bool at_caret); + /// Determines whether the text is line wrapped. + bool line_wrapped() const; + textbox& line_wrapped(bool); + + /// Determines whether the text is multi-line enabled. + bool multi_lines() const; + textbox& multi_lines(bool); + + /// Determines whether the textbox accepts user input + bool editable() const; + textbox& editable(bool); + + /// Enables the caret if the textbox currently is not editable + textbox& enable_caret(); + + void set_accept(std::function); + + textbox& tip_string(::std::string); + + /// Set a mask character. Text is displayed as mask character if a mask character is set. This is used for hiding some special text, such as password. + textbox& mask(wchar_t); + + /// Returns true if some text is selected. + bool selected() const; + bool get_selected_points(nana::upoint &a, nana::upoint &b) const; + + /// Selects/Deselects all text. + void select(bool); + + void select_points(nana::upoint arg_a, nana::upoint arg_b); + + /// Returns the bounds of a text selection + /** + * @return no selection if pair.first == pair.second. + */ + std::pair selection() const; + + void copy() const; ///< Copies the selected text into shared memory, such as clipboard under Windows. + void paste(); ///< Pastes the text from shared memory. + void del(); + + int to_int() const; + double to_double() const; + textbox& from(int); + textbox& from(double); + + void clear_undo(); + + void set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor); + void erase_highlight(const std::string& name); + void set_keywords(const std::string& name, bool case_sensitive, bool whole_word_match, std::initializer_list kw_list); + void set_keywords(const std::string& name, bool case_sensitive, bool whole_word_match, std::initializer_list kw_list_utf8); + void erase_keyword(const std::string& kw); + + /// Sets the text alignment + textbox& text_align(::nana::align alignment); + + /// Returns the text position of each line that currently displays on screen. + text_positions text_position() const; + + /// Returns the rectangle of text area + rectangle text_area() const; + + /// Returns the height of line in pixels + unsigned line_pixels() const; + + /// Sets the behavior when textbox gets focus. + void focus_behavior(text_focus_behavior); + + /// Sets the caret move behavior when the content of textbox is selected. + /// E.g. Whether caret moves to left of selected content or moves to left of last position when left arrow key is pressed. + /// @param move_to_end determines whether to move caret to left of selected_content or to left of last position. + void select_behavior(bool move_to_end); + + /// Sets the undo/redo queue length + /** + * @param len The length of the queue. If this parameter is zero, the undo/redo is disabled. + */ + void set_undo_queue_length(std::size_t len); + + /// Returns the number of lines that text are displayed in the screen. + /** + * The number of display lines may be not equal to the number of text lines when the textbox + * is line wrapped mode. + * @return the number of lines that text are displayed in the screen. + */ + std::size_t display_line_count() const noexcept; + + /// Returns the number of text lines. + std::size_t text_line_count() const noexcept; + protected: + //Overrides widget's virtual functions + native_string_type _m_caption() const noexcept override; + void _m_caption(native_string_type&&) override; + void _m_typeface(const paint::font&) override; + std::shared_ptr _m_scroll_operation() override; + }; +}//end namespace nana +#include + +#endif diff --git a/GUI/nana/gui/widgets/toolbar.hpp b/GUI/nana/gui/widgets/toolbar.hpp new file mode 100644 index 0000000..ed3456e --- /dev/null +++ b/GUI/nana/gui/widgets/toolbar.hpp @@ -0,0 +1,170 @@ +/** + * A Toolbar Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/toolbar.hpp + */ + +#ifndef NANA_GUI_WIDGET_TOOLBAR_HPP +#define NANA_GUI_WIDGET_TOOLBAR_HPP +#include + +#include "widget.hpp" + +namespace nana +{ + class toolbar; + + struct arg_toolbar + : public event_arg + { + toolbar& widget; + std::size_t button; + + arg_toolbar(toolbar&, std::size_t); + }; + + namespace drawerbase + { + namespace toolbar + { + enum class tool_type + { + button, + toggle + }; + + class item_proxy + { + public: + item_proxy(::nana::toolbar*, std::size_t pos); + + bool enable() const; + item_proxy& enable(bool enable_state); + + item_proxy& tooltype(tool_type type); ///< Sets the tool style. + + bool istoggle() const; ///< Returns true if the tool style is toggle. + bool toggle() const; ///< Gets the tool toggle state (only if tool style is toggle). + item_proxy& toggle(bool toggle_state); ///< Sets the tool toggle state (only if tool style is toggle). + std::string toggle_group() const; ///< Returns the toggle group associated with the tool (only if tool style is toggle). + item_proxy& toggle_group(const ::std::string& group); ///< Adds the tool to a toggle group (only if tool style is toggle). + + item_proxy& textout(bool show); ///< Show/Hide the text inside the button + + private: + nana::toolbar* const tb_; + std::size_t const pos_; + }; + + struct item_type + { + std::string text; + nana::paint::image image; + unsigned pixels{ 0 }; + unsigned position{ 0 }; // last item position. + nana::size textsize; + bool enable{ true }; + + tool_type type{ tool_type::button }; + bool toggle{ false }; + std::string group; + + bool textout{ false }; + + item_type(const std::string& text, const nana::paint::image& img, tool_type type) + :text(text), image(img), type(type) + {} + }; + + struct toolbar_events + : public general_events + { + basic_event selected; ///< A mouse click on a control button. + basic_event enter; ///< The mouse enters a control button. + basic_event leave; ///< The mouse leaves a control button. + }; + + class item_container; + + class drawer + : public drawer_trigger + { + struct drawer_impl_type; + + public: + using size_type = std::size_t; + + drawer(); + ~drawer(); + + item_container& items() const; + void scale(unsigned); + private: + void refresh(graph_reference) override; + void attached(widget_reference, graph_reference) override; + void detached() override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + private: + size_type _m_which(point, bool want_if_disabled) const; + void _m_calc_pixels(item_type*, bool force); + private: + ::nana::toolbar* widget_; + drawer_impl_type* impl_; + }; + + }//end namespace toolbar + }//end namespace drawerbase + + /// Control bar that contains buttons for controlling + class toolbar + : public widget_object + { + public: + using size_type = std::size_t; ///< A type to count the number of elements. + using tool_type = drawerbase::toolbar::tool_type; + + toolbar() = default; + toolbar(window, bool visible, bool detached=false); + toolbar(window, const rectangle& = rectangle(), bool visible = true, bool detached = false); + + void separate(); ///< Adds a separator. + drawerbase::toolbar::item_proxy append(const ::std::string& text, const nana::paint::image& img); ///< Adds a control button. + drawerbase::toolbar::item_proxy append(const ::std::string& text); ///< Adds a control button. + void clear(); ///< Removes all control buttons and separators. + + bool enable(size_type index) const; + void enable(size_type index, bool enable_state); + + void tooltype(size_type index, tool_type type); ///< Sets the tool style. + + bool istoggle(size_type index) const; ///< Returns true if the tool style is toggle. + bool toggle(size_type index) const; ///< Gets the tool toggle state (only if tool style is toggle). + void toggle(size_type index, bool toggle_state); ///< Sets the tool toggle state (only if tool style is toggle). + std::string toggle_group(size_type index) const; ///< Returns the toggle group associated with the tool (only if tool style is toggle). + void toggle_group(size_type index, const ::std::string& group); ///< Adds the tool to a toggle group (only if tool style is toggle). + + void textout(size_type index, bool show); ///< Show/Hide the text inside the button + + void scale(unsigned s); ///< Sets the scale of control button. + + /// Enable to place buttons at right part. After calling it, every new button is right aligned. + void go_right(); + + bool detached() { return detached_; }; + + private: + bool detached_; + }; +}//end namespace nana +#include + +#endif diff --git a/GUI/nana/gui/widgets/treebox.hpp b/GUI/nana/gui/widgets/treebox.hpp new file mode 100644 index 0000000..f6a9c41 --- /dev/null +++ b/GUI/nana/gui/widgets/treebox.hpp @@ -0,0 +1,528 @@ +/** + * A Tree Box Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/gui/widgets/treebox.hpp + * @brief + * The treebox organizes the nodes by a key string. + * The treebox would have a vertical scrollbar if there are too many nodes + * to display. It does not have an horizontal scrollbar: + * the widget will adjust the node's displaying position for fitting. + */ + +#ifndef NANA_GUI_WIDGETS_TREEBOX_HPP +#define NANA_GUI_WIDGETS_TREEBOX_HPP + +#include +#include "widget.hpp" +#include "detail/compset.hpp" +#include "detail/tree_cont.hpp" +#include +#include +#include +#include + +namespace nana +{ + class treebox; + + namespace drawerbase + { + namespace treebox + { + enum class component + { + begin, expander = begin, crook, icon, text, bground, end + }; + + struct node_image_tag + { + nana::paint::image normal; + nana::paint::image hovered; + nana::paint::image expanded; + }; + + struct node_attribute + { + bool has_children; ///< Determines whether the node has visible children + bool expended; + checkstate checked; + bool selected; + bool mouse_pointed; + nana::paint::image icon_normal; + nana::paint::image icon_hover; + nana::paint::image icon_expanded; + ::std::string text; + }; + + struct scheme + : public widget_geometrics + { + color_proxy item_bg_selected{ static_cast(0xD5EFFC) }; ///< item selected: background color + color_proxy item_fg_selected{ static_cast(0x99DEFD) }; ///< item selected: foreground color + color_proxy item_bg_highlighted{ static_cast(0xE8F5FD) }; ///< item highlighted: background color + color_proxy item_fg_highlighted{ static_cast(0xD8F0FA) }; ///< item highlighted: foreground color + color_proxy item_bg_selected_and_highlighted{ static_cast(0xC4E8FA) }; ///< item selected and highlighted: background color + color_proxy item_fg_selected_and_highlighted{ static_cast(0xB6E6FB) }; ///< item selected and highlighted: foreground color + + unsigned item_offset{ 16 }; ///< item position displacement in pixels + unsigned text_offset{ 4 }; ///< text position displacement in pixels + unsigned icon_size{ 16 }; ///< icon size in pixels + unsigned crook_size{ 16 }; ///< crook size in pixels (TODO: the function that draw the crook doesn't scale the shape) + + unsigned indent_displacement{ 18 }; ///< children position displacement in pixels (def=18 (before was 10)) + }; + + typedef widgets::detail::compset compset_interface; + typedef widgets::detail::compset_placer compset_placer_interface; + + class renderer_interface + { + public: + typedef drawerbase::treebox::component component; + typedef ::nana::paint::graphics& graph_reference; + typedef drawerbase::treebox::compset_interface compset_interface; + typedef compset_interface::item_attribute_t item_attribute_t; + typedef compset_interface::comp_attribute_t comp_attribute_t; + + virtual ~renderer_interface() = default; + + virtual void begin_paint(::nana::widget&) = 0; + virtual void bground(graph_reference, const compset_interface *) const = 0; + virtual void expander(graph_reference, const compset_interface *) const = 0; + virtual void crook(graph_reference, const compset_interface *) const = 0; + virtual void icon(graph_reference, const compset_interface *) const = 0; + virtual void text(graph_reference, const compset_interface *) const = 0; + }; + + class item_proxy; + + class trigger + :public drawer_trigger + { + class implementation; + class item_locator; + public: + struct treebox_node_type + { + treebox_node_type(); + treebox_node_type(std::string); + treebox_node_type& operator=(const treebox_node_type&); + + ::std::string text; + nana::any value; + bool expanded; + bool hidden; + checkstate checked; + ::std::string img_idstr; + }; + + struct pseudo_node_type{}; + + using tree_cont_type = widgets::detail::tree_cont; + using node_type = tree_cont_type::node_type; + + trigger(); + ~trigger(); + + implementation * impl() const; + + void check(node_type*, checkstate); + + pat::cloneable& renderer() const; + + void placer(::nana::pat::cloneable&&); + const ::nana::pat::cloneable& placer() const; + + node_type* insert(node_type*, const std::string& key, std::string&&); + node_type* insert(const std::string& path, std::string&&); + + node_image_tag& icon(const ::std::string&); + void icon_erase(const ::std::string&); + void node_icon(node_type*, const ::std::string& id); + unsigned node_width(const node_type*) const; + + bool rename(node_type*, const char* key, const char* name); + + private: + //Overrides drawer_trigger methods + void attached(widget_reference, graph_reference) override; + void detached() override; + void refresh(graph_reference) override; + void dbl_click(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_wheel(graph_reference, const arg_wheel&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void resized(graph_reference, const arg_resized&) override; + void key_press(graph_reference, const arg_keyboard&) override; + void key_char(graph_reference, const arg_keyboard&) override; + private: + implementation * const impl_; + }; //end class trigger + + + /// \brief A proxy for accessing the node. The key string is case sensitive. + class item_proxy + : public std::iterator + { + public: + item_proxy() = default; ///< The default constructor creates an end iterator. + + //Undocumented constructor. + item_proxy(trigger*, trigger::node_type*); + + /// Append a child. + item_proxy append(const ::std::string& key, ::std::string name); + + /// Append a child with a specified value (user object.). + template + item_proxy append(const ::std::string& key, ::std::string name, T&& t) + { + item_proxy ip = append(key, std::move(name)); + if(false == ip.empty()) + ip.value(std::forward(t)); + return ip; + } + + /// Return true if the proxy does not refer to a node, as an end iterator. + bool empty() const; + + /// \brief Return the distance between the ROOT node and this node. + /// @return only available when empty() is false. + std::size_t level() const; + + /// Return the check state + bool checked() const; + + /// Set the check state, and it returns itself. + item_proxy& check(bool); + + /// Clears the child nodes + item_proxy& clear(); + + /// Return true when the node is expanded \todo change to expanded ?? + bool expanded() const; + + /// Expand/Shrink children of the node, and returns itself. \todo change to expand ?? + item_proxy& expand(bool); + + /// Return true when the node is selected. + bool selected() const; + + /// Select the node, and returns itself.. + item_proxy& select(bool); + + /// Return true when the node is hidden. + bool hidden() const; + + /// Hide the node, and returns itself. + item_proxy& hide(bool); + + /// Return the icon. + const ::std::string& icon() const; + + /// Set the icon, and returns itself.. + item_proxy& icon(const ::std::string& id); + + /// Return the text. + const ::std::string& text() const; + + /// Set the text, and returns itself. + item_proxy& text(const ::std::string&); + + /// Set a new key, and returns itself.. + item_proxy& key(const ::std::string& s); + + /// Return the key. + const ::std::string& key() const; + + std::size_t size() const; ///< Returns the number of child nodes. + + /// Return the first child of the node. + item_proxy child() const; + + /// Return the owner of the node. + item_proxy owner() const; + + /// Return the sibling of the node. + item_proxy sibling() const; + + /// Return the first child of the node + item_proxy begin() const; + + /// An end node. + item_proxy end() const; + + /// Makes an action for each sub item recursively, returns the item that stops the action where action returns false. + item_proxy visit_recursively(std::function action); + + bool operator==(const ::std::string& s) const; ///< Compare the text of node with s. + bool operator==(const char* s ) const; ///< Compare the text of node with s. + bool operator==(const wchar_t* s ) const; ///< Compare the text of node with s. + + /// Behavior of Iterator + item_proxy& operator=(const item_proxy&); + + /// Behavior of Iterator + item_proxy & operator++(); + + /// Behavior of Iterator + item_proxy operator++(int); + + /// Behavior of Iterator + item_proxy& operator*(); + + /// Behavior of Iterator + const item_proxy& operator*() const; + + /// Behavior of Iterator + item_proxy* operator->(); + + /// Behavior of Iterator + const item_proxy* operator->() const; + + /// Behavior of Iterator + bool operator==(const item_proxy&) const; + + /// Behavior of Iterator + bool operator!=(const item_proxy&) const; + + template + const T * value_ptr() const + { + return any_cast(&_m_value()); + } + + template + T * value_ptr() + { + return any_cast(&_m_value()); + } + + template + const T& value() const + { + auto p = any_cast(&_m_value()); + if(nullptr == p) + throw std::runtime_error("treebox::value() Invalid type of value."); + return *p; + } + + template + T& value() + { + auto p = any_cast(&_m_value()); + if (nullptr == p) + throw std::runtime_error("treebox::value() Invalid type of value."); + return *p; + } + + template + item_proxy & value(T&& t) + { + _m_value() = std::forward(t); + return *this; + } + + // Undocumented methods for internal use + trigger::node_type * _m_node() const; + private: + nana::any& _m_value(); + const nana::any& _m_value() const; + private: + trigger * trigger_{nullptr}; + trigger::node_type * node_{nullptr}; + };//end class item_proxy + }//end namespace treebox + }//end namespace drawerbase + + /// a type of treebox event parameter + struct arg_treebox + : public event_arg + { + treebox& widget; ///< where the event occurs + drawerbase::treebox::item_proxy & item; ///< the operated node + bool operated; ///< operation state of the event + + arg_treebox(treebox&, drawerbase::treebox::item_proxy&, bool operated); + }; + + namespace drawerbase + { + namespace treebox + { + struct treebox_events + : public general_events + { + basic_event expanded; ///< a user expands or shrinks a node + basic_event checked; ///< a user checks or unchecks a node + basic_event selected; ///< a user selects or unselects a node + basic_event hovered; ///< a user moves the cursor over a node + basic_event hidden; ///< a user hides or shows a node + }; + }//end namespace treebox + }//end namespace drawerbase + + /// \brief Displays a hierarchical list of items, such as the files and directories on a disk. + /// See also in [documentation](http://nanapro.org/en-us/documentation/widgets/treebox.htm) + class treebox + :public widget_object + { + public: + /// A type refers to the item and is also used to iterate through the nodes. + typedef drawerbase::treebox::item_proxy item_proxy; + + /// state images for the node + typedef drawerbase::treebox::node_image_tag node_image_type; + + /// The interface of treebox user-defined item renderer + typedef drawerbase::treebox::renderer_interface renderer_interface; + + /// The interface of treebox compset_placer to define the position of node components + typedef drawerbase::treebox::compset_placer_interface compset_placer_interface; + + /// The default constructor without creating the widget. + treebox(); + + /// \brief The construct that creates a widget. + /// @param wd A handle to the parent window of the widget being created. + /// @param visible specifying the visibility after creating. + treebox(window wd, bool visible); + + /// \brief The construct that creates a widget. + /// @param wd A handle to the parent window of the widget being created. + /// @param r the size and position of the widget in its parent window coordinate. + /// @param visible specifying if visible after creating. + treebox(window, const nana::rectangle& = rectangle(), bool visible = true); + + template + treebox & renderer(const ItemRenderer & rd) ///< set user-defined node renderer + { + get_drawer_trigger().renderer() = ::nana::pat::cloneable{rd}; + return *this; + } + + const nana::pat::cloneable & renderer() const; ///< get user-defined node renderer + + template + treebox & placer(const Placer & r) ///< location of a node components + { + get_drawer_trigger().placer(::nana::pat::cloneable(r)); + return *this; + } + + const nana::pat::cloneable & placer() const; + + /// \brief Enable the widget to be draws automatically when it is operated. + /// + /// The treebox automatically redraws after certain operations, but, + /// under some circumstances, it is good to disable the automatic drawing mode, + /// for example, before adding nodes in a loop, disable the mode avoiding + /// frequent and useless refresh for better performance, and then, after + /// the operations, enable the automatic redraw mode again. + /// @param enable bool whether to enable. + void auto_draw(bool enable); + + /// Prevents drawing during execution. + template + void avoid_drawing(Function fn) + { + this->auto_draw(false); + try + { + fn(); + } + catch (...) + { + this->auto_draw(true); + throw; + } + this->auto_draw(true); + } + + /// \brief Enable the checkboxs for each item of the widget. + /// @param enable bool indicates whether to show or hide the checkboxs. + treebox & checkable(bool enable); + + + bool checkable() const; ///< Are the checkboxs are enabled? + + /// Clears the contents + void clear(); + + /// \brief Creates an icon scheme with the specified name. + /// + /// The icon scheme includes 3 images for node states. + /// These states are 'normal', 'hovered' and 'expanded'. + /// If 'hovered' or 'expanded' are not set, it uses 'normal' state image for these 2 states. + /// See also in [documentation](http://nanapro.org/en-us/help/widgets/treebox.htm) + /// @param id The name of an icon scheme. If the name is not existing, it creates a new scheme for the name. + /// @return The reference of node image scheme corresponding with the specified id. + node_image_type& icon(const ::std::string& id); + + void icon_erase(const ::std::string& id); + + item_proxy find(const ::std::string& keypath); ///< Find an item through a specified keypath. + + /// Inserts a new node to treebox, but if the keypath exists change and returns the existing node. + item_proxy insert(const ::std::string& path_key, ///< specifies the node hierarchy + ::std::string title ///< used for displaying + ); + + /// Inserts a new node to treebox, but if the keypath exists change and returns the existing node. + item_proxy insert( item_proxy pos, ///< the parent item node + const ::std::string& key, ///< specifies the new node + ::std::string title ///< title used for displaying in the new node. + ); + + item_proxy erase(item_proxy i); ///< Removes the node at i and return the Item proxy following the removed node + + void erase(const ::std::string& keypath); ///< Removes the node by the key path. + + ::std::string make_key_path(item_proxy i, const ::std::string& splitter) const;/// _m_scroll_operation() override; + + };//end class treebox +}//end namespace nana + +#include + +#endif diff --git a/GUI/nana/gui/widgets/widget.hpp b/GUI/nana/gui/widgets/widget.hpp new file mode 100644 index 0000000..ce46843 --- /dev/null +++ b/GUI/nana/gui/widgets/widget.hpp @@ -0,0 +1,524 @@ +/** + * The fundamental widget class implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/gui/widgets/widget.hpp + */ + +#ifndef NANA_GUI_WIDGET_HPP +#define NANA_GUI_WIDGET_HPP + +#include +#include "../programming_interface.hpp" +#include +#include + +namespace nana +{ + namespace detail + { + //Forward declaration of widget_notifier_interface + class widget_notifier_interface; + } + + /// Abstract class for defining the capacity interface. + class widget + { + friend class detail::widget_notifier_interface; + class inner_widget_notifier; + typedef void(*dummy_bool_type)(widget* (*)(const widget&)); + + + //Noncopyable + widget(const widget&) = delete; + widget& operator=(const widget&) = delete; + + //Nonmovable + widget(widget&&) = delete; + widget& operator=(widget&&) = delete; + + public: + using native_string_type = detail::native_string_type; + + widget() = default; + + virtual ~widget() = default; + virtual window handle() const = 0; ///< Returns the handle of window, returns 0 if window is not created. + bool empty() const; ///< Determines whether the manipulator is handling a window. + void close(); + + window parent() const; + + ::std::string caption() const noexcept; + ::std::wstring caption_wstring() const noexcept; + native_string_type caption_native() const noexcept; + + widget& caption(std::string utf8); + widget& caption(std::wstring); + + template + void i18n(std::string msgid, Args&&... args) + { + _m_caption(::nana::to_nstring(::nana::internationalization().get(msgid, std::forward(args)...))); + } + + void i18n(i18n_eval); + + void cursor(nana::cursor); + nana::cursor cursor() const; ///< Retrieves the shape of cursor + + void typeface(const paint::font& font); + paint::font typeface() const; + + bool enabled() const; ///< Determines whether the window is enabled for mouse and keyboard input. + void enabled(bool); + + void enable_dropfiles(bool); ///< Enables/Disables a window to accept dropped files. + + void focus(); + bool focused() const; + + std::shared_ptr scroll_operation(); + + void show(); ///< Sets the window visible. + void hide(); ///< Sets the window invisible. + bool visible() const; + + nana::size size() const; + void size(const nana::size&); + + /// Enables the widget to grab the mouse input. + /* + * @param ignore_children Indicates whether to redirect the mouse input to its children if the mouse pointer is over its children. + */ + void set_capture(bool ignore_children); + + /// Disables the widget to grab the mouse input. + void release_capture(); + + point pos() const; + void move(int x, int y); + void move(const point&); + void move(const rectangle&); + + void fgcolor(const nana::color&); + nana::color fgcolor() const; + void bgcolor(const nana::color&); + nana::color bgcolor() const; + + general_events& events() const; + + void umake_event(event_handle eh) const; ///< Deletes an event callback by a handle. + + widget& register_shortkey(wchar_t); ///< Registers a shortkey. To remove a registered key, pass 0. + + widget& take_active(bool activated, window take_if_not_activated); + widget& tooltip(const ::std::string&); + + operator dummy_bool_type() const; + operator window() const; + protected: + std::unique_ptr<::nana::detail::widget_notifier_interface> _m_wdg_notifier(); + private: + virtual void _m_notify_destroy() = 0; + + protected: + //protected members, a derived class must call this implementation if it overrides an implementation + virtual void _m_complete_creation(); + + virtual general_events& _m_get_general_events() const = 0; + virtual native_string_type _m_caption() const noexcept; + virtual void _m_caption(native_string_type&&); + virtual nana::cursor _m_cursor() const; + virtual void _m_cursor(nana::cursor); + virtual void _m_close(); + virtual bool _m_enabled() const; + virtual void _m_enabled(bool); + virtual std::shared_ptr _m_scroll_operation(); + virtual bool _m_show(bool); + virtual bool _m_visible() const; + virtual void _m_size(const nana::size&); + virtual void _m_move(int x, int y); + virtual void _m_move(const rectangle&); + + virtual void _m_typeface(const nana::paint::font& font); + virtual nana::paint::font _m_typeface() const; + + virtual void _m_fgcolor(const nana::color&); + virtual nana::color _m_fgcolor() const; + virtual void _m_bgcolor(const nana::color&); + virtual nana::color _m_bgcolor() const; + }; + + namespace detail + { + class widget_base + : public widget + { + public: + window handle() const override; + protected: + void _m_notify_destroy() override; + protected: + window handle_{ nullptr }; + }; + } + + /// Base class of all the classes defined as a widget window. Defaultly a widget_tag + /// + /// \tparam Category + /// \tparam DrawerTrigger must be derived from nana::drawer_trigger + /// \tparam Events + /// \tparam Scheme + template::value>::type> + class widget_object: public detail::widget_base + { + protected: + typedef DrawerTrigger drawer_trigger_t; + public: + using scheme_type = Scheme; + using event_type = Events; + + widget_object() + : events_{ std::make_shared() }, + scheme_{ API::dev::make_scheme() } + { + static_assert(std::is_base_of<::nana::drawer_trigger, DrawerTrigger>::value, "The type DrawerTrigger must be derived from nana::drawer_trigger"); + } + + ~widget_object() + { + API::close_window(handle()); + } + + event_type& events() const + { + return *events_; + } + + bool create(window parent_wd, bool visible) ///< Creates a no-size (zero-size) widget. in a widget/root window specified by parent_wd. + { + return create(parent_wd, rectangle(), visible); + } + + bool create(window parent_wd, const rectangle & r = {}, bool visible = true) ///< in a widget/root window specified by parent_wd. + { + if(parent_wd && this->empty()) + { + handle_ = API::dev::create_widget(parent_wd, r, this); + API::dev::set_events(handle_, events_); + API::dev::set_scheme(handle_, scheme_.get()); + API::dev::attach_drawer(*this, trigger_); + if(visible) + API::show_window(handle_, true); + + this->_m_complete_creation(); + } + return (this->empty() == false); + } + + widget_object& borderless(bool enable) + { + API::widget_borderless(handle_, enable); + return *this; + } + + bool borderless() const + { + return API::widget_borderless(handle_); + } + + scheme_type& scheme() const + { + return *scheme_; + } + + // disables or re-enables internal handling of event within base-widget + void filter_event(const event_code evt_code, const bool bDisabled) + { + trigger_.filter_event(evt_code, bDisabled); + } + + void filter_event(const std::vector evt_codes, const bool bDisabled) + { + trigger_.filter_event(evt_codes, bDisabled); + } + + void filter_event(const event_filter_status& evt_all_states) + { + trigger_.filter_event(evt_all_states); + } + + void clear_filter() + { + trigger_.clear_filter(); + } + + // reads status of if event is filtered + bool filter_event(const event_code evt_code) + { + return trigger_.filter_event(evt_code); + } + + event_filter_status filter_event() + { + return trigger_.filter_event(); + } + + protected: + DrawerTrigger& get_drawer_trigger() + { + return trigger_; + } + + const DrawerTrigger& get_drawer_trigger() const + { + return trigger_; + } + private: + general_events& _m_get_general_events() const override + { + return *events_; + } + + void _m_notify_destroy() override final + { + widget_base::_m_notify_destroy(); + events_ = std::make_shared(); + } + private: + DrawerTrigger trigger_; + std::shared_ptr events_; + std::unique_ptr scheme_; + };//end class widget_object + + /// Base class of all the classes defined as a non-graphics-buffer widget window. + /// + /// The second template parameter DrawerTrigger is always ignored.\see nana::panel + /// type DrawerTrigger must be derived from nana::drawer_trigger + template + class widget_object: public detail::widget_base + { + protected: + typedef DrawerTrigger drawer_trigger_t; + public: + using scheme_type = Scheme; + using event_type = Events; + + widget_object() + : events_{ std::make_shared() }, scheme_{ API::dev::make_scheme() } + { + static_assert(std::is_base_of<::nana::drawer_trigger, DrawerTrigger>::value, "The type DrawerTrigger must be derived from nana::drawer_trigger"); + } + + ~widget_object() + { + API::close_window(handle()); + } + + event_type& events() const + { + return *events_; + } + + bool create(window parent_wd, bool visible) ///< Creates a no-size (zero-size) widget. in a widget/root window specified by parent_wd. + { + return create(parent_wd, rectangle(), visible); + } + + bool create(window parent_wd, const rectangle& r = rectangle(), bool visible = true) ///< in a widget/root window specified by parent_wd. + { + if(parent_wd && this->empty()) + { + handle_ = API::dev::create_lite_widget(parent_wd, r, this); + API::dev::set_events(handle_, events_); + API::dev::set_scheme(handle_, scheme_.get()); + if(visible) + API::show_window(handle_, true); + this->_m_complete_creation(); + } + return (this->empty() == false); + } + + scheme_type& scheme() const + { + return *scheme_; + } + private: + general_events& _m_get_general_events() const override + { + return *events_; + } + + void _m_notify_destroy() override final + { + widget_base::_m_notify_destroy(); + events_ = std::make_shared(); + } + private: + std::shared_ptr events_; + std::unique_ptr scheme_; + };//end class widget_object + + + /// Base class of all the classes defined as a root window. \see nana::form + /// + /// \tparam DrawerTrigger must be derived from nana::drawer_trigger + /// \tparam Events + /// \tparam Scheme + template + class widget_object: public detail::widget_base + { + protected: + typedef DrawerTrigger drawer_trigger_t; + public: + using scheme_type = Scheme; + using event_type = Events; + + widget_object() + : widget_object(nullptr, false, API::make_center(300, 150), appearance(), this) + { + static_assert(std::is_base_of<::nana::drawer_trigger, DrawerTrigger>::value, "The type DrawerTrigger must be derived from nana::drawer_trigger"); + } + + widget_object(window owner, bool nested, const rectangle& r = {}, const appearance& apr = {}) + { + static_assert(std::is_base_of<::nana::drawer_trigger, DrawerTrigger>::value, "The type DrawerTrigger must be derived from nana::drawer_trigger"); + handle_ = API::dev::create_window(owner, nested, r, apr, this); + _m_bind_and_attach(); + } + + ~widget_object() + { + API::close_window(handle()); + } + + event_type& events() const + { + return *events_; + } + + void activate() + { + API::activate_window(handle_); + } + + native_window_type native_handle() const + { + return API::root(handle_); + } + + void bring_top(bool activated) + { + API::bring_top(handle(), activated); + } + + window owner() const + { + return API::get_owner_window(handle_); + } + + void icon(const nana::paint::image& ico) + { + API::window_icon(handle_, ico); + } + + void restore() + { + API::restore_window(handle_); + } + + void zoom(bool ask_for_max) + { + API::zoom_window(handle_, ask_for_max); + } + + bool is_zoomed(bool check_maximized) const + { + return API::is_window_zoomed(handle_, check_maximized); + } + + widget_object& z_order(window wd_after, z_order_action action_if_no_wd_after) + { + API::set_window_z_order(handle_, wd_after, action_if_no_wd_after); + return *this; + } + + scheme_type& scheme() const + { + return *scheme_; + } + + void draw_through(std::function draw_fn) + { + API::draw_through(handle(), draw_fn); + } + + void map_through_widgets(native_drawable_type drawable) + { + API::map_through_widgets(handle(), drawable); + } + + void outline_size(const ::nana::size& sz) + { + API::window_outline_size(handle(), sz); + } + + ::nana::size outline_size() const + { + return API::window_outline_size(handle()); + } + protected: + DrawerTrigger& get_drawer_trigger() + { + return trigger_; + } + + const DrawerTrigger& get_drawer_trigger() const + { + return trigger_; + } + private: + void _m_bind_and_attach() + { + events_ = std::make_shared(); + API::dev::set_events(handle_, events_); + + scheme_ = API::dev::make_scheme(); + API::dev::set_scheme(handle_, scheme_.get()); + API::dev::attach_drawer(*this, trigger_); + } + + general_events& _m_get_general_events() const override + { + return *events_; + } + + void _m_notify_destroy() override final + { + widget_base::_m_notify_destroy(); + events_ = std::make_shared(); + } + private: + DrawerTrigger trigger_; + std::shared_ptr events_; + std::unique_ptr scheme_; + };//end class widget_object + +}//end namespace nana + +#include +#endif diff --git a/GUI/nana/internationalization.hpp b/GUI/nana/internationalization.hpp new file mode 100644 index 0000000..cba03bf --- /dev/null +++ b/GUI/nana/internationalization.hpp @@ -0,0 +1,249 @@ +/* + * An Implementation of i18n + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/internationalization.hpp + */ + +#ifndef NANA_INTERNATIONALIZATION_HPP +#define NANA_INTERNATIONALIZATION_HPP +#include +#include +#include +#include +#include + +namespace nana +{ + class internationalization + { + friend class i18n_eval; + public: + /// Sets a handler to handle a msgid which hasn't been translated. + static void set_missing(std::function handler); + + void load(const std::string& file); + void load_utf8(const std::string& file); + + template + ::std::string get(std::string msgid_utf8, Args&&... args) const + { + std::vector arg_strs; + +#ifdef __cpp_fold_expressions + (_m_fetch_args(arg_strs, std::forward(args)),...); +#else + _m_fetch_args(arg_strs, std::forward(args)...); +#endif + + auto msgstr = _m_get(std::move(msgid_utf8)); + _m_replace_args(msgstr, &arg_strs); + return msgstr; + } + + ::std::string get(std::string msgid_utf8) const; + void set(std::string msgid_utf8, ::std::string msgstr); + + template + ::std::string operator()(std::string msgid_utf8, Args&&... args) const + { + return get(msgid_utf8, std::forward(args)...); + } + private: + std::string _m_get(std::string&& msgid) const; + void _m_replace_args(::std::string& str, std::vector<::std::string> * arg_strs) const; + +#ifndef __cpp_fold_expressions + static void _m_fetch_args(std::vector&); //Termination of _m_fetch_args +#endif + + static void _m_fetch_args(std::vector& v, const char* arg); + static void _m_fetch_args(std::vector& v, const std::string& arg); + static void _m_fetch_args(std::vector& v, std::string& arg); + static void _m_fetch_args(std::vector& v, std::string&& arg); + static void _m_fetch_args(std::vector& v, const wchar_t* arg); + static void _m_fetch_args(std::vector& v, const std::wstring& arg); + static void _m_fetch_args(std::vector& v, std::wstring& arg); + static void _m_fetch_args(std::vector& v, std::wstring&& arg); + + template + static void _m_fetch_args(std::vector& v, Arg&& arg) + { + std::stringstream ss; + ss << arg; + v.emplace_back(ss.str()); + } + +#ifndef __cpp_fold_expressions + template + void _m_fetch_args(std::vector& v, const char* arg, Args&&... args) const + { + v.emplace_back(arg); + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, const std::string& arg, Args&&... args) const + { + v.emplace_back(arg); + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, std::string& arg, Args&&... args) const + { + v.emplace_back(arg); + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, std::string&& arg, Args&&... args) const + { + v.emplace_back(std::move(arg)); + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, const wchar_t* arg, Args&&... args) const + { + v.emplace_back(to_utf8(arg)); + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, const std::wstring& arg, Args&&... args) const + { + v.emplace_back(to_utf8(arg)); + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, std::wstring& arg, Args&&... args) const + { + v.emplace_back(to_utf8(arg)); + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, std::wstring&& arg, Args&&... args) const + { + v.emplace_back(to_utf8(arg)); + _m_fetch_args(v, std::forward(args)...); + } + + template + void _m_fetch_args(std::vector& v, Arg&& arg, Args&&... args) const + { + std::stringstream ss; + ss << arg; + v.emplace_back(ss.str()); + _m_fetch_args(v, std::forward(args)...); + } +#endif + };//end class internationalization + + class i18n_eval + { + class eval_arg + { + public: + virtual ~eval_arg() = default; + virtual std::string eval() const = 0; + virtual std::unique_ptr clone() const = 0; + }; + + class arg_string; + class arg_eval; + + template + class arg_function: public eval_arg + { + public: + arg_function(std::function fn) + : fn_(fn) + {} + + std::string eval() const override + { + std::stringstream ss; + ss << fn_(); + return ss.str(); + } + + std::unique_ptr clone() const override + { + return std::unique_ptr(new arg_function(*this)); + } + private: + std::function fn_; + }; + public: + i18n_eval() = default; + + template + i18n_eval(std::string msgid_utf8, Args&&... args) + : msgid_(std::move(msgid_utf8)) + { +#ifdef __cpp_fold_expressions + (_m_fetch_args(std::forward(args)), ...); +#else + _m_fetch_args(std::forward(args)...); +#endif + } + + i18n_eval(const i18n_eval&); + + //Workaround for VC2013, becuase it can't specified a default explicit move-constructor + i18n_eval(i18n_eval&&); //= default + + i18n_eval& operator=(const i18n_eval&); + i18n_eval& operator=(i18n_eval&& rhs); + + std::string operator()() const; + private: +#ifndef __cpp_fold_expressions + void _m_fetch_args(){} //Termination of _m_fetch_args + + template + void _m_fetch_args(Arg&& arg, Args&&... args) + { + _m_add_args(std::forward(arg)); + _m_fetch_args(std::forward(args)...); + } +#endif + + template + void _m_add_args(Arg&& arg) + { + std::stringstream ss; + ss << arg; + _m_add_args(ss.str()); + } + + template + void _m_add_args(std::function fn) + { + args_.emplace_back(new arg_function(fn)); + } + + void _m_add_args(i18n_eval&); + void _m_add_args(const i18n_eval&); + void _m_add_args(i18n_eval&&); + + void _m_add_args(std::string&); + void _m_add_args(const std::string&); + void _m_add_args(std::string&&); + + void _m_add_args(const std::wstring&); + private: + std::string msgid_; + std::vector> args_; + };//end class i18n_eval; +} + +#endif//NANA_I18N_HPP diff --git a/GUI/nana/key_type.hpp b/GUI/nana/key_type.hpp new file mode 100644 index 0000000..8d77edb --- /dev/null +++ b/GUI/nana/key_type.hpp @@ -0,0 +1,123 @@ +/* +* A Key Implementation +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/key_type.hpp +*/ +#ifndef NANA_KEY_TYPE_HPP +#define NANA_KEY_TYPE_HPP + +namespace nana +{ + namespace detail + { + class key_interface + { + public: + virtual ~key_interface(){} + + virtual bool same_type(const key_interface*) const noexcept = 0; + virtual bool compare(const key_interface*) const noexcept = 0; ///< is this key less than right key? [call it less(rk), less_than(rk) or compare_less(rk)?: if (lk.less_than(rk )) ] + }; //end class key_interface + + //Use less compare for equal compare [call it equal_by_less()?] + inline bool pred_equal(const key_interface * left, const key_interface* right) noexcept + { + return (left->same_type(right) && (left->compare(right) == false) && (right->compare(left) == false)); + } + + template + struct type_escape + { + using type = T; + }; + + template<> + struct type_escape + { + using type = ::std::string; + }; + + template<> + struct type_escape + { + using type = ::std::string; + }; + + template + struct type_escape + { + using type = ::std::string; + }; + + template + struct type_escape + { + using type = ::std::string; + }; + + template<> + struct type_escape + { + using type = ::std::wstring; + }; + + template<> + struct type_escape + { + using type = ::std::wstring; + }; + + template + struct type_escape + { + using type = ::std::wstring; + }; + + template + struct type_escape + { + using type = ::std::wstring; + }; + } + + template + class key + : public detail::key_interface + { + public: + typedef detail::key_interface key_interface; + typedef T key_type; + + key(const key_type& k) + : key_object_(k) + {} + + key(key_type&& k) + : key_object_(std::move(k)) + { + } + public: + //implement key_interface methods + bool same_type(const key_interface * p) const noexcept override + { + return (nullptr != dynamic_cast(p)); + } + + bool compare(const key_interface* p) const noexcept override + { + auto rhs = dynamic_cast(p); + return rhs && compare_(key_object_, rhs->key_object_); + } + private: + Compare compare_; + key_type key_object_; + }; +} + +#endif diff --git a/GUI/nana/optional.hpp b/GUI/nana/optional.hpp new file mode 100644 index 0000000..a84a4e1 --- /dev/null +++ b/GUI/nana/optional.hpp @@ -0,0 +1,375 @@ +/** + * Optional + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/optional.hpp + * + * @brief An implementation of experimental library optional of C++ standard(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3793.html) + */ + +#ifndef NANA_STD_OPTIONAL_HEADER_INCLUDED +#define NANA_STD_OPTIONAL_HEADER_INCLUDED + +#include + +#ifndef _nana_std_optional +#include +#else +#include + +namespace nana +{ + namespace detail + { + template + class storage + { + public: + using value_type = T; + + storage() = default; + + template + storage(U&& value) + : initialized_{ true } + { + ::new (data_) value_type(std::forward(value)); + } + + template + storage(const U& value) + : initialized_{ true } + { + ::new (data_) value_type(value); + } + + storage(const storage& other) + : initialized_{ other.initialized_ } + { + if (other.initialized_) + ::new (data_) value_type(*other.ptr()); + } + + storage(storage&& other) + : initialized_{ other.initialized_ } + { + if (other.initialized_) + ::new (data_) value_type(std::move(*other.ptr())); + } + + template + storage(const storage& other) + : initialized_{ other.initialized_ } + { + if (other.initialized_) + ::new (data_) value_type(*other.ptr()); + } + + ~storage() + { + destroy(); + } + + bool initialized() const noexcept + { + return initialized_; + } + + void set_initialized() + { + initialized_ = true; + } + + void destroy() + { + if (initialized_) + { + ptr()->~T(); + initialized_ = false; + } + } + + template + void assign(U&& value) + { + if (initialized_) + *ptr() = std::forward(value); + else + { + ::new (data_) value_type(std::forward(value)); + initialized_ = true; + } + } + + void assign(const storage& other) + { + if (!other.initialized_) + { + destroy(); + return; + } + + if (initialized_) + *ptr() = *other.ptr(); + else + { + ::new (data_) value_type(*other.ptr()); + initialized_ = true; + } + } + + void assign(storage&& other) + { + if (!other.initialized_) + { + destroy(); + return; + } + + if (initialized_) + *ptr() = std::move(*other.ptr()); + else + { + ::new (data_) value_type(std::move(*other.ptr())); + initialized_ = true; + } + } + + const T* ptr() const + { + return reinterpret_cast(data_); + } + + T* ptr() + { + return reinterpret_cast(data_); + } + private: + bool initialized_{ false }; + char data_[sizeof(value_type)]; + }; + }//end namespace detail + + class bad_optional_access + : public std::logic_error + { + public: + bad_optional_access() + : std::logic_error("Attempted to access the value of an uninitialized optional object.") + {} + }; + + template + class optional + { + public: + using value_type = T; + + constexpr optional() = default; + constexpr optional(std::nullptr_t) {} + + optional(const optional& other) + : storage_(other.storage_) + {} + + optional(optional&& other) + : storage_(std::move(other.storage_)) + {} + + constexpr optional(const value_type& value) + : storage_(value) + {} + + constexpr optional(value_type&& value) + : storage_(std::move(value)) + {} + + optional& operator=(std::nullptr_t) + { + storage_.destroy(); + return *this; + } + + optional& operator=(const optional& other) + { + if (this != &other) + { + storage_.assign(other.storage_); + } + return *this; + } + + optional& operator=(optional&& other) + { + if (this != &other) + { + storage_.assign(std::move(other.storage_)); + } + return *this; + } + + template + optional& operator=(U&& value) + { + storage_.assign(std::forward(value)); + + return *this; + } + + //Value access + //constexpr + value_type* operator->() + { + return storage_.ptr(); + } + constexpr const value_type* operator->() const + { + return storage_.ptr(); + } + + //constexpr + value_type& operator*() + { + return *storage_.ptr(); + } + + constexpr const value_type& operator*() const + { + return *storage_.ptr(); + } + + /* + //constexpr + value_type&& operator*() && + { + return std::move(*storage_.ptr()); + } + + //constexpr + const value_type&& operator*() const && + { + return std::move(*storage_.ptr()); + } + */ + + //Condition + constexpr explicit operator bool() const + { + return storage_.initialized(); + } + + constexpr bool has_value() const + { + return storage_.initialized(); + } + + //constexpr + value_type& value() + { + if (!storage_.initialized()) + throw bad_optional_access{}; + + return *storage_.ptr(); + } + + constexpr const value_type& value() const + { + if (!storage_.initialized()) + throw bad_optional_access{}; + + return *storage_.ptr(); + } + /* + //constexpr + value_type&& value() + { + if (!storage_.initialized()) + throw bad_optional_access{}; + + return std::move(*storage_.ptr()); + } + + constexpr const value_type&& value() const + { + if (!storage_.initialized()) + throw bad_optional_access{}; + + return std::move(*storage_.ptr()); + } + */ + + template + constexpr T value_or(U&& default_value) const + { + return (has_value() ? **this : static_cast(std::forward(default_value))); + } + + template + //constexpr + T value_or(U&& default_value) + { + return (has_value() ? std::move(**this) : static_cast(std::forward(default_value))); + } + + //Modifiers + void swap(optional& other) + { + if (has_value() && other.has_value()) + { + std::swap(**this, *other); + return; + } + else if (has_value()) + { + other.emplace(std::move(***this)); + storage_.destroy(); + } + else if (other.has_value()) + { + this->emplace(std::move(*other)); + other.storage_.destroy(); + } + } + + void reset() + { + storage_.destroy(); + } + + template + void emplace(Args&&... args) + { + storage_.destroy(); + ::new (storage_.ptr()) T(std::forward(args)...); + + storage_.set_initialized(); + } + + template + void emplace(std::initializer_list il, Args&& ... args) + { + storage_.destroy(); + ::new (storage_.ptr()) T(il, std::forward(args)...); + + storage_.set_initialized(); + } + + + private: + detail::storage storage_; + + }; +} + +namespace std +{ + using nana::optional; +} + +#endif //_nana_std_optional +#endif diff --git a/GUI/nana/paint/detail/image_impl_interface.hpp b/GUI/nana/paint/detail/image_impl_interface.hpp new file mode 100644 index 0000000..6a0e114 --- /dev/null +++ b/GUI/nana/paint/detail/image_impl_interface.hpp @@ -0,0 +1,31 @@ +#ifndef NANA_PAINT_DETAIL_IMAGE_IMPL_INTERFACE_HPP +#define NANA_PAINT_DETAIL_IMAGE_IMPL_INTERFACE_HPP + +#include "../image.hpp" +#include + +namespace nana{ namespace paint{ + + // class image::image_impl_interface + // the nana::image refers to an object of image::image_impl_interface by nana::refer. Employing nana::refer to refer the image::implement_t object indirectly is used + // for saving the memory that sharing the same image resource with many nana::image objects. + class image::image_impl_interface + : private nana::noncopyable + { + image_impl_interface& operator=(const image_impl_interface& rhs); + public: + using graph_reference = nana::paint::graphics&; + virtual ~image_impl_interface() = 0; //The destructor is defined in ../image.cpp + virtual bool open(const std::filesystem::path& file) = 0; + virtual bool open(const void* data, std::size_t bytes) = 0; // reads image from memory + virtual bool alpha_channel() const = 0; + virtual bool empty() const = 0; + virtual void close() = 0; + virtual nana::size size() const = 0; + virtual void paste(const nana::rectangle& src_r, graph_reference dst, const point& p_dst) const = 0; + virtual void stretch(const nana::rectangle& src_r, graph_reference dst, const nana::rectangle& r) const = 0; + };//end class image::image_impl_interface +}//end namespace paint +}//end namespace nana + +#endif diff --git a/GUI/nana/paint/detail/image_process_provider.hpp b/GUI/nana/paint/detail/image_process_provider.hpp new file mode 100644 index 0000000..761544a --- /dev/null +++ b/GUI/nana/paint/detail/image_process_provider.hpp @@ -0,0 +1,127 @@ +#ifndef NANA_PAINT_IMAGE_PROCESS_PROVIDER_HPP +#define NANA_PAINT_IMAGE_PROCESS_PROVIDER_HPP +#include +#include +#include +#include + +namespace nana +{ + namespace paint + { + namespace detail + { + class image_process_provider + : nana::noncopyable + { + image_process_provider(); + + struct stretch_tag + { + typedef paint::image_process::stretch_interface interface_t; + typedef pat::mutable_cloneable cloneable_t; + typedef std::map table_t; + + table_t table; + interface_t* employee; + }stretch_; + + struct alpha_blend_tag + { + typedef paint::image_process::alpha_blend_interface interface_t; + typedef pat::mutable_cloneable cloneable_t; + typedef std::map table_t; + + table_t table; + interface_t * employee; + }alpha_blend_; + + struct blend_tag + { + typedef paint::image_process::blend_interface interface_t; + typedef pat::mutable_cloneable cloneable_t; + typedef std::map table_t; + + table_t table; + interface_t * employee; + }blend_; + + struct line_tag + { + typedef paint::image_process::line_interface interface_t; + typedef pat::mutable_cloneable cloneable_t; + typedef std::map table_t; + + table_t table; + interface_t * employee; + }line_; + + struct blur_tag + { + typedef paint::image_process::blur_interface interface_t; + typedef pat::mutable_cloneable cloneable_t; + typedef std::map table_t; + + table_t table; + interface_t * employee; + }blur_; + public: + + static image_process_provider & instance(); + + stretch_tag & ref_stretch_tag(); + paint::image_process::stretch_interface * const * stretch() const; + paint::image_process::stretch_interface * ref_stretch(const std::string& name) const; + + alpha_blend_tag & ref_alpha_blend_tag(); + paint::image_process::alpha_blend_interface * const * alpha_blend() const; + paint::image_process::alpha_blend_interface * ref_alpha_blend(const std::string& name) const; + + blend_tag & ref_blend_tag(); + paint::image_process::blend_interface * const * blend() const; + paint::image_process::blend_interface * ref_blend(const std::string& name) const; + + line_tag & ref_line_tag(); + paint::image_process::line_interface * const * line() const; + paint::image_process::line_interface * ref_line(const std::string& name) const; + + blur_tag & ref_blur_tag(); + paint::image_process::blur_interface * const * blur() const; + paint::image_process::blur_interface * ref_blur(const std::string& name) const; + public: + template + void set(Tag & tag, const std::string& name) + { + auto i = tag.table.find(name); + if(i != tag.table.end()) + tag.employee = &(*(i->second)); + } + + //add + //@brief: The add operation is successful if the name does not exist. + // it does not replace the existing object by new object, because this + // feature is thread safe and efficiency. + template + void add(Tag & tag, const std::string& name) + { + if(tag.table.count(name) == 0) + { + typedef typename Tag::cloneable_t cloneable_t; + auto & obj = tag.table[name]; + obj = cloneable_t(ImageProcessor()); + if(nullptr == tag.employee) + tag.employee = &(*obj); + } + } + private: + template + typename Tag::interface_t* _m_read(const Tag& tag, const std::string& name) const + { + auto i = tag.table.find(name); + return (i != tag.table.end() ? &(*i->second) : tag.employee); + } + }; + } + } +}//end namespace nana +#endif diff --git a/GUI/nana/paint/detail/native_paint_interface.hpp b/GUI/nana/paint/detail/native_paint_interface.hpp new file mode 100644 index 0000000..a6cc453 --- /dev/null +++ b/GUI/nana/paint/detail/native_paint_interface.hpp @@ -0,0 +1,45 @@ +/* + * Platform Implementation + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/paint/detail/native_paint_interface.hpp + */ + +#ifndef NANA_PAINT_DETAIL_PLATFORM_HPP +#define NANA_PAINT_DETAIL_PLATFORM_HPP +#include + +namespace nana +{ +namespace paint +{ +namespace detail +{ + nana::size drawable_size(drawable_type); + + std::unique_ptr alloc_fade_table(double fade_rate); + void free_fade_table(const unsigned char*); + + //color = bgcolor * fade_rate + fgcolor * (1 - fade_rate); + nana::pixel_color_t fade_color(nana::pixel_color_t bgcolor, nana::pixel_color_t fgcolor, const unsigned char* const fade_table); + nana::pixel_color_t fade_color_intermedia(pixel_color_t fgcolor, const unsigned char* fade_table); + nana::pixel_color_t fade_color_by_intermedia(pixel_color_t bgcolor, nana::pixel_color_t fgcolor_intermedia, const unsigned char* const fade_table); + + //dw color = dw color * fade_rate + bdcolor * (1 - fade_rate) + void blend(drawable_type dw, const nana::rectangle& r, pixel_color_t bdcolor, double fade_rate); + + nana::size real_text_extent_size(drawable_type, const char*, std::size_t len); + nana::size real_text_extent_size(drawable_type, const wchar_t*, std::size_t len); + nana::size text_extent_size(drawable_type, const char*, std::size_t len); + nana::size text_extent_size(drawable_type, const wchar_t*, std::size_t len); + + void draw_string(drawable_type, const nana::point&, const wchar_t *, std::size_t len); +}//end namespace detail +}//end namespace paint +}//end namespace nana + +#endif diff --git a/GUI/nana/paint/detail/ptdefs.hpp b/GUI/nana/paint/detail/ptdefs.hpp new file mode 100644 index 0000000..ac5647e --- /dev/null +++ b/GUI/nana/paint/detail/ptdefs.hpp @@ -0,0 +1,29 @@ +#ifndef NANA_PAINT_PTDEFS_INCLUDED +#define NANA_PAINT_PTDEFS_INCLUDED + +namespace nana +{ + namespace detail + { + struct native_font_signature; + + + struct font_style + { + unsigned weight{ 400 }; //normal + bool italic{ false }; + bool underline{ false }; + bool strike_out{ false }; + + font_style() = default; + font_style(unsigned weight, bool italic = false, bool underline = false, bool strike_out = false); + }; + }//end namespace detail + + namespace paint + { + using native_font_type = ::nana::detail::native_font_signature*; + } +} + +#endif \ No newline at end of file diff --git a/GUI/nana/paint/graphics.hpp b/GUI/nana/paint/graphics.hpp new file mode 100644 index 0000000..6e93585 --- /dev/null +++ b/GUI/nana/paint/graphics.hpp @@ -0,0 +1,247 @@ +/* + * Paint Graphics Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/paint/graphics.hpp + */ + +#ifndef NANA_PAINT_GRAPHICS_HPP +#define NANA_PAINT_GRAPHICS_HPP + +#include + +#include "../basic_types.hpp" +#include "../gui/basis.hpp" +#include + +#include "detail/ptdefs.hpp" + +#ifdef _nana_std_has_string_view +#include +#endif + +namespace nana +{ + namespace paint + { + class font + { + friend class graphics; + public: + using path_type = ::std::filesystem::path; + + using font_style = ::nana::detail::font_style; + + font(); + font(drawable_type); + font(const font&); + + font(const ::std::string& name, double size_pt, const font_style& fs = {}); + font(double size_pt, const path_type& truetype, const font_style& fs = {}); + + ~font(); + bool empty() const; + + void set_default() const; + ::std::string name() const; + + /// Returns font size, in point. + /** + * @param fixed Indicates whether to return a fixed font size. If this parameter is false, the method may return zero for default system font size. If the parameter is true, the method returns a fixed size of default font size if the font size that assigned by constructor is zero. + * @return The font size, in point. + */ + double size(bool fixed = false) const; + + bool bold() const; + unsigned weight() const; + bool italic() const; + native_font_type handle() const; + void release(); + bool strikeout() const; + bool underline() const; + + font& operator=(const font&); + bool operator==(const font&) const; + bool operator!=(const font&) const; + private: + struct impl_type; + impl_type * impl_; + }; + + /// \brief off-screen resource defined as ref-counting, can refer one resource + /// + /// Load a bitmap into a graphics: + /// \code + /// nana::paint::graphics graph; + /// nana::paint::image img("C:\\ABitmap.bmp"); + /// img.paste(graph, 0, 0); //graph may create if it is empty + /// \endcode + class graphics + { + public: + graphics(); + graphics(const ::nana::size&); ///< size in pixel + graphics(const graphics&); ///< the resource is not copyed, the two graphics objects refer to the *SAME* resource + graphics& operator=(const graphics&); + + graphics(graphics&&); + graphics& operator=(graphics&&); + + ~graphics(); + + bool changed() const; ///< Returns true if the graphics object is operated + bool empty() const; ///< Returns true if the graphics object does not refer to any resource. + explicit operator bool() const noexcept; + + drawable_type handle() const; + const void* pixmap() const; + const void* context() const; + + void swap(graphics& other) noexcept; + + /// Creates a graphics/drawable resource + /** + * @param sz The dimension of the graphics to be requested. If sz is empty, it performs as release(). + */ + void make(const ::nana::size& sz); + void resize(const ::nana::size&); + void typeface(const font&); ///< Selects a specified font type into the graphics object. + font typeface() const; + +#ifdef _nana_std_has_string_view + ::nana::size text_extent_size(std::string_view text) const; + ::nana::size text_extent_size(std::wstring_view text) const; + + ///Only supports the wide string, because it is very hard to specify the begin and end position in a UTF-8 string. + ::nana::size glyph_extent_size(std::wstring_view text, std::size_t begin, std::size_t end) const; + + /// Returns a buffer which stores the pixel of each charater stored in text. + /** + * @param text The text to be requested. + * @return A buffer which stores the pixel of each character stored in text, its length is same with text's length. If text is empty, it returns a buffer with a senseless value. + */ + std::unique_ptr glyph_pixels(std::wstring_view text) const; + + ::nana::size bidi_extent_size(std::string_view utf8_text) const; + ::nana::size bidi_extent_size(std::wstring_view text) const; +#else + ::nana::size text_extent_size(const ::std::string&) const; + ::nana::size text_extent_size(const char*, std::size_t len) const; + + ::nana::size text_extent_size(const wchar_t*) const; ///< Computes the width and height of the specified string of text. + ::nana::size text_extent_size(const ::std::wstring&) const; ///< Computes the width and height of the specified string of text. + ::nana::size text_extent_size(const wchar_t*, std::size_t length) const; ///< Computes the width and height of the specified string of text with the specified length. + ::nana::size text_extent_size(const ::std::wstring&, std::size_t length) const; ///< Computes the width and height of the specified string of text with the specified length. + + ::nana::size glyph_extent_size(const wchar_t*, std::size_t length, std::size_t begin, std::size_t end) const; + ::nana::size glyph_extent_size(const ::std::wstring&, std::size_t length, std::size_t begin, std::size_t end) const; + + bool glyph_pixels(const wchar_t *, std::size_t length, unsigned* pxbuf) const; + + ::nana::size bidi_extent_size(const std::wstring&) const; + ::nana::size bidi_extent_size(const std::string&) const; +#endif + + bool text_metrics(unsigned & ascent, unsigned& descent, unsigned& internal_leading) const; + + void line_begin(int x, int y); + + void bitblt(int x, int y, const graphics& source); ///< Transfers the source to the specified point. + void bitblt(const ::nana::rectangle& r_dst, native_window_type src); ///< Transfers the color data corresponding to r_dst from the src window to this graphics. + void bitblt(const ::nana::rectangle& r_dst, native_window_type src, const point& p_src); ///< Transfers the color data corresponding to r_dst from the src window at point p_src to this graphics. + void bitblt(const ::nana::rectangle& r_dst, const graphics& src); ///< Transfers the color data corresponding to r_dst from the src graphics to this graphics. + void bitblt(const ::nana::rectangle& r_dst, const graphics& src, const point& p_src);///< Transfers the color data corresponding to r_dst from the src graphics at point p_src to this graphics. + + void blend(const ::nana::rectangle& r, const ::nana::color&, double fade_rate); + void blend(const ::nana::rectangle& blend_r, const graphics& blend_graph, const point& blend_graph_point, double fade_rate);///< blends with the blend_graph. + + void blur(const ::nana::rectangle& r, std::size_t radius); ///< Blur process. + + void paste(graphics& dst, int x, int y) const; ///< Paste the graphics object into the dest at (x, y) + void paste(native_window_type dst, const ::nana::rectangle&, int sx, int sy) const; ///< Paste the graphics object into a platform-dependent window at (x, y) + void paste(native_window_type dst, int dx, int dy, unsigned width, unsigned height, int sx, int sy) const; + void paste(drawable_type dst, int x, int y) const; + void paste(const ::nana::rectangle& r_src, graphics& dst, int x, int y) const; + void rgb_to_wb(); ///< Transform a color graphics into black&white. + + void stretch(const ::nana::rectangle& src_r, graphics& dst, const ::nana::rectangle& r) const; + void stretch(graphics& dst, const ::nana::rectangle&) const; + + void flush(); + + unsigned width() const; ///< Returns the width of the off-screen buffer. + unsigned height() const; ///< Returns the height of the off-screen buffer. + ::nana::size size() const; + void setsta(); ///< Clears the status if the graphics object had been changed + void set_changed(); + void release(); + + /// Saves images as a windows bitmap file + /// @param file_utf8 A UTF-8 string to a filename + void save_as_file(const char* file_utf8) const noexcept; + + ::nana::color palette(bool for_text) const; + graphics& palette(bool for_text, const ::nana::color&); + + void set_pixel(int x, int y, const ::nana::color&); + void set_pixel(int x, int y); + +#ifdef _nana_std_has_string_view + unsigned bidi_string(const point&, std::string_view utf8str); + unsigned bidi_string(const point& pos, std::wstring_view str); + + void string(const point&, std::string_view utf8str); + void string(const point&, std::string_view utf8str, const nana::color&); + + void string(const point&, std::wstring_view str); + void string(const point&, std::wstring_view str, const nana::color&); +#else + unsigned bidi_string(const nana::point&, const wchar_t *, std::size_t len); + unsigned bidi_string(const point& pos, const char*, std::size_t len); + + void string(const point&, const std::string& text_utf8); + void string(const point&, const std::string& text_utf8, const color&); + + void string(point, const wchar_t*, std::size_t len); + void string(const point&, const wchar_t*); + void string(const point&, const ::std::wstring&); + void string(const point&, const ::std::wstring&, const color&); +#endif + + void line(const point&, const point&); + void line(const point&, const point&, const color&); + void line_to(const point&, const color&); + void line_to(const point&); + + void rectangle(bool solid); + void rectangle(bool solid, const color&); + void rectangle(const ::nana::rectangle&, bool solid); + void rectangle(const ::nana::rectangle&, bool solid, const color&); + void frame_rectangle(const ::nana::rectangle&, const color& left, const color& top, const color& right, const color& bottom); + void frame_rectangle(const ::nana::rectangle&, const color&, unsigned gap); + + void gradual_rectangle(const ::nana::rectangle&, const color& from, const color& to, bool vertical); + void round_rectangle(const ::nana::rectangle&, unsigned radius_x, unsigned radius_y, const color&, bool solid, const color& color_if_solid); + private: + struct implementation; + std::unique_ptr impl_; + }; + + class draw + { + public: + draw(graphics& graph); + + void corner(const rectangle& r, unsigned pixels); + private: + graphics& graph_; + }; + }//end namespace paint +} //end namespace nana +#endif + diff --git a/GUI/nana/paint/image.hpp b/GUI/nana/paint/image.hpp new file mode 100644 index 0000000..5820ac3 --- /dev/null +++ b/GUI/nana/paint/image.hpp @@ -0,0 +1,62 @@ +/* + * Paint Image Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/paint/image.hpp + * @description: class image is used for load an image file into memory. + */ + +#ifndef NANA_PAINT_IMAGE_HPP +#define NANA_PAINT_IMAGE_HPP + +#include "graphics.hpp" + +namespace nana +{ +namespace paint +{ + /// load a picture file + class image + { + friend class image_accessor; + typedef bool (image::* unspecified_bool_t)() const; + public: + class image_impl_interface; + + image() noexcept; + image(const image&); + image(image&&); + explicit image(const ::std::string& file); + explicit image(const ::std::wstring& file); + + ~image(); + image& operator=(const image& rhs); + image& operator=(image&&); + bool open(const ::std::string& file); + bool open(const ::std::wstring& file); + + /// Opens an icon from a specified buffer + bool open(const void* data, std::size_t bytes); + bool empty() const noexcept; + operator unspecified_bool_t() const; + void close() noexcept; + + bool alpha() const noexcept; + nana::size size() const noexcept; + void paste(graphics& dst, const point& p_dst) const; + void paste(const nana::rectangle& r_src, graphics& dst, const point& p_dst) const;///< Paste the area of picture specified by r_src into the destination graphics specified by dst at position p_dst. + void stretch(const nana::rectangle& r_src, graphics& dst, const nana::rectangle& r_dst) const;/// image_ptr_; + };//end class image + +}//end namespace paint +}//end namespace nana + +#endif + diff --git a/GUI/nana/paint/image_process_interface.hpp b/GUI/nana/paint/image_process_interface.hpp new file mode 100644 index 0000000..75945f9 --- /dev/null +++ b/GUI/nana/paint/image_process_interface.hpp @@ -0,0 +1,85 @@ +/* + * Image Processing Interfaces + * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/paint/image_process_interface.hpp + */ + +#ifndef NANA_PAINT_IMAGE_PROCESS_INTERFACE_HPP +#define NANA_PAINT_IMAGE_PROCESS_INTERFACE_HPP + +#include +#include + +namespace nana +{ + namespace paint + { /// Image Processing Algorithm Interfaces + namespace image_process + { /// The interface of stretch algorithm. + class stretch_interface + { + public: + virtual ~stretch_interface() = default; + /// Copies the image from a source rectangle into a destination rectangle, stretching or compressing the image to fit the dimensions of the destination rectangle in destination(d_pixbuf). + virtual void process(const paint::pixel_buffer & s_pixbuf, + const nana::rectangle& source_rectangle, + paint::pixel_buffer & d_pixbuf, + const nana::rectangle& destination_rectangle + ) const = 0; + }; + + class alpha_blend_interface + { + public: + virtual ~alpha_blend_interface() = default; + virtual void process(const paint::pixel_buffer& s_pixbuf, const nana::rectangle& s_r, paint::pixel_buffer& d_pixbuf, const point& d_pos) const = 0; + }; + /// The interface of a blend algorithm. + class blend_interface + { + public: + virtual ~blend_interface() = default; + /// \brief Blends two images with specified area and blend rate. + /// + /// Semantics: \code dest_pixbuf = dest_pixbuf * fade_rate + scr_pixbuf * (1 - fade_rate); \endcode + /// The area is always valid, it is calculated by Nana before passing to the algorithm. So the area could be applied without a check. + virtual void process( const paint::pixel_buffer& src_pixbuf, + const nana::rectangle& src_area, + paint::pixel_buffer& dest_pixbuf, + const nana::point& dest_pos, + double fade_rate ///< blend rate in the range of [0, 1] + ) const = 0; + }; + /// The interface of line algorithm. + class line_interface + { + public: + virtual ~line_interface() = default; + + /// \brief Draws a line + /// + /// Semantics: \code pixbuf = pixbuf * (1 - fade_rate) + color * fade_rate \endcode + /// The two points are calculated by Nana, they are always valid, and pos_beg.x <= pos_end.x + virtual void process(paint::pixel_buffer & pixbuf, + const point& pos_beg, ///< left point + const point& pos_end, ///< right point + const ::nana::color&, + double fade_rate ///< blend rate in the range of [0, 1] If not 0, the line is blended to the pixbuf + ) const = 0; + }; + + class blur_interface + { + public: + virtual ~blur_interface() = default; + virtual void process(paint::pixel_buffer&, const nana::rectangle& r, std::size_t radius) const = 0; + }; + } + }//end namespace paint +}//end namespace nana +#endif diff --git a/GUI/nana/paint/image_process_selector.hpp b/GUI/nana/paint/image_process_selector.hpp new file mode 100644 index 0000000..46a53ae --- /dev/null +++ b/GUI/nana/paint/image_process_selector.hpp @@ -0,0 +1,71 @@ +#ifndef NANA_PAINT_IMAGE_PROCESS_SELECTOR_HPP +#define NANA_PAINT_IMAGE_PROCESS_SELECTOR_HPP +#include "detail/image_process_provider.hpp" + +namespace nana +{ + namespace paint + { + namespace image_process + { /// Configure the image processing algorithms. + class selector + { + public: + /// Selects an image processor through a specified name. + /*! if users give a non-existing name for choosing an image processor, + the call succeed, but no image processor would be replaced. + */ + void stretch(const std::string& name); + /// Inserts a new user-defined image processor for stretch. + template + void add_stretch(const std::string& name) + { + detail::image_process_provider & p = detail::image_process_provider::instance(); + p.add(p.ref_stretch_tag(), name); + } + + /// Selects an image process through a specified name. + void alpha_blend(const std::string& name); + /// Inserts a new user defined image process for alpha blend. + template + void add_alpha_blend(const std::string& name) + { + detail::image_process_provider& p = detail::image_process_provider::instance(); + p.add(p.ref_alpha_blend_tag(), name); + } + + /// Selects an image processor blend through a specified name. + void blend(const std::string& name); + /// Inserts a new user-defined image processor for blend. + template + void add_blend(const std::string& name) + { + detail::image_process_provider& p = detail::image_process_provider::instance(); + p.add(p.ref_blend_tag(), name); + } + + /// Selects an image processor through a specified name. + void line(const std::string& name); + /// Inserts a new user-defined image processor for line. + template + void add_line(const std::string& name) + { + detail::image_process_provider & p = detail::image_process_provider::instance(); + p.add(p.ref_line_tag(), name); + } + + /// blur - Selects an image procssor through a specified name. + void blur(const std::string& name); + /// Inserts a new user-defined image process for blur. + template + void add_blur(const std::string& name) + { + detail::image_process_provider & p = detail::image_process_provider::instance(); + p.add(p.ref_blur_tag(), name); + } + }; + } + } +} + +#endif diff --git a/GUI/nana/paint/pixel_buffer.hpp b/GUI/nana/paint/pixel_buffer.hpp new file mode 100644 index 0000000..9ca8609 --- /dev/null +++ b/GUI/nana/paint/pixel_buffer.hpp @@ -0,0 +1,85 @@ +/* + * Pixel Buffer Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/paint/pixel_buffer.hpp + */ + +#ifndef NANA_PAINT_PIXEL_BUFFER_HPP +#define NANA_PAINT_PIXEL_BUFFER_HPP + +#include +#include + +namespace nana{ namespace paint +{ + class pixel_buffer + { + struct pixel_buffer_storage; + typedef bool (pixel_buffer:: * unspecified_bool_t)() const; + public: + pixel_buffer() = default; + pixel_buffer(drawable_type, const nana::rectangle& want_rectangle); + pixel_buffer(drawable_type, std::size_t top, std::size_t lines); + pixel_buffer(std::size_t width, std::size_t height); + + ~pixel_buffer(); + + void attach(drawable_type, const nana::rectangle& want_rectangle); + + bool open(drawable_type); + bool open(drawable_type, const nana::rectangle& want_rectangle); + bool open(std::size_t width, std::size_t height); + + void alpha_channel(bool enabled); + bool alpha_channel() const; + + void close(); + + bool empty() const; + + operator unspecified_bool_t() const; + + std::size_t bytes() const; + std::size_t bytes_per_line() const; + nana::size size() const; + + pixel_color_t * at(const point& pos) const; + pixel_color_t * raw_ptr(std::size_t row) const; + pixel_color_t * operator[](std::size_t row) const; + + void fill_row(std::size_t row, const unsigned char* buffer, std::size_t bytes, unsigned bits_per_pixel); + + void put(const unsigned char* rawbits, std::size_t width, std::size_t height, std::size_t bits_per_pixel, std::size_t bytes_per_line, bool is_negative); + + void line(const std::string& name); + void line(const ::nana::point& pos_beg, const ::nana::point& pos_end, const ::nana::color&, double fade_rate); + + void rectangle(const nana::rectangle&, const ::nana::color&, double fade_rate, bool solid); + void gradual_rectangle(const ::nana::rectangle&, const ::nana::color& from, const ::nana::color& to, double fade_rate, bool vertical); + + pixel_color_t pixel(int x, int y) const; + void pixel(int x, int y, pixel_color_t); + + void paste(drawable_type, const point& p_dst) const; + void paste(const nana::rectangle& s_r, drawable_type, const point& p_dst) const; + void paste(native_window_type, const point& p_dst) const; + void stretch(const std::string& name); + void stretch(const nana::rectangle& s_r, drawable_type, const nana::rectangle& r) const; + void blend(const std::string& name); + void blend(const nana::rectangle& s_r, drawable_type dw_dst, const nana::point& d_pos, double fade_rate) const; + void blur(const nana::rectangle& r, std::size_t radius); + + pixel_buffer rotate(double angle, const color& extend_color); + private: + std::shared_ptr storage_; + }; +}//end namespace paint +}//end namespace nana + +#endif diff --git a/GUI/nana/paint/text_renderer.hpp b/GUI/nana/paint/text_renderer.hpp new file mode 100644 index 0000000..3510bb3 --- /dev/null +++ b/GUI/nana/paint/text_renderer.hpp @@ -0,0 +1,63 @@ +#ifndef NANA_PAINT_TEXT_RENDERER_HPP +#define NANA_PAINT_TEXT_RENDERER_HPP +#include + +namespace nana +{ + namespace paint + { + class text_renderer + { + public: + using graph_reference = graphics &; + + enum class mode + { + truncate_with_ellipsis, + truncate_letter_with_ellipsis, + word_wrap + }; + + text_renderer(graph_reference graph, align = align::left); + + nana::size extent_size(int x, int y, const wchar_t*, std::size_t len, unsigned space_pixels) const; + + void render(const point&, const wchar_t*, std::size_t len); + void render(const point&, const wchar_t*, std::size_t len, unsigned space_pixels, mode); + private: + graph_reference graph_; + align text_align_; + }; + + /// Draw aligned string + class aligner + { + public: + using graph_reference = graphics&; + + /// Constructor + /** + * @param graph Reference to a graphics object + * @param text_align Alignment of text + * @param text_align_if_too_long Alignment of text if the pixels of string is larger than text area + */ + aligner(graph_reference graph, align text_align = align::left); + aligner(graph_reference graph, align text_align, align text_align_if_too_long); + + /// Draws a text with specified text alignment. + /** + * @param text Text to draw + * @param pos Postion where the text to draw + * @param width The width of text area. If the pixels of text is larger than this parameter, it draws ellipsis + */ + void draw(const std::string& text, point pos, unsigned width); + void draw(const std::wstring& text, point pos, unsigned width); + private: + graph_reference graph_; + align text_align_; + align text_align_ex_; + }; + } +} + +#endif diff --git a/GUI/nana/pat/abstract_factory.hpp b/GUI/nana/pat/abstract_factory.hpp new file mode 100644 index 0000000..9f23642 --- /dev/null +++ b/GUI/nana/pat/abstract_factory.hpp @@ -0,0 +1,113 @@ +/* + * A Generic Abstract Factory Pattern Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/pat/abstract_factory.hpp + * @description: A generic easy-to-use abstract factory pattern implementation + */ + +#ifndef NANA_PAT_ABSFACTORY_HPP +#define NANA_PAT_ABSFACTORY_HPP +#include "cloneable.hpp" +#include +#include +#include + +namespace nana +{ + namespace pat + { + namespace detail + { + //A Base class for abstract factory, avoids decorated name length exceeding for a class template. + class abstract_factory_base + { + public: + virtual ~abstract_factory_base() = default; + }; + } + + template + class abstract_factory + : public detail::abstract_factory_base + { + public: + using interface_type = Interface; + + virtual ~abstract_factory() = default; + virtual std::unique_ptr create() = 0; + }; + + namespace detail + { + template + struct pack{ + using type = pack; + }; + + template + struct make_pack_helper + { // explodes gracefully below 0 + static_assert(!Negative, + "make_integer_sequence requires N to be non-negative."); + }; + + template + struct make_pack_helper, + pack > + : pack + { // ends recursion at 0 + }; + + template + struct make_pack_helper, + pack > + : make_pack_helper, + pack > + { // counts down to 0 + }; + + template + using make_pack = typename make_pack_helper, pack >::type; + + template + class abs_factory + : public abstract_factory + { + std::unique_ptr create() override + { + constexpr auto const Size = std::tuple_size::value; + return std::unique_ptr{ _m_new(make_pack{}) }; + } + + template + Interface* _m_new(const pack &) + { + return new T(std::get(args_)...); + } + public: + abs_factory(const Args&... args) + : args_(args...) + { + } + private: + std::tuple args_; + }; + }//end namespace detail + + template + pat::cloneable> make_factory(Args &&... args) + { + return detail::abs_factory::type...>(std::forward(args)...); + } + }//end namespace pat +}//end namespace nana +#endif diff --git a/GUI/nana/pat/cloneable.hpp b/GUI/nana/pat/cloneable.hpp new file mode 100644 index 0000000..60d691f --- /dev/null +++ b/GUI/nana/pat/cloneable.hpp @@ -0,0 +1,210 @@ +/* +* A Generic Cloneable Pattern Implementation +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/pat/cloneable.hpp +* @description: A generic easy-to-use cloneable pattern implementation +*/ +#ifndef NANA_PAT_CLONEABLE_HPP +#define NANA_PAT_CLONEABLE_HPP + +#include +#include +#include +#include +#include + + +namespace nana{ namespace pat{ + + namespace detail + { + class cloneable_interface + { + public: + virtual ~cloneable_interface() = default; + virtual void * get() = 0; + virtual cloneable_interface* clone() const = 0; + virtual void self_delete() const = 0; + }; + + struct cloneable_interface_deleter + { + void operator()(cloneable_interface * p) + { + if (p) + p->self_delete(); + } + }; + + template + class cloneable_wrapper + : public cloneable_interface + { + public: + using value_type = T; + + cloneable_wrapper() = default; + + cloneable_wrapper(const value_type& obj) + :value_obj_(obj) + {} + + cloneable_wrapper(value_type&& rv) + :value_obj_(std::move(rv)) + {} + private: + //Implement cloneable_interface + virtual void* get() override + { + return &value_obj_; + } + + virtual cloneable_interface* clone() const override + { + return (new cloneable_wrapper{ value_obj_ }); + } + + virtual void self_delete() const override + { + (delete this); + } + private: + value_type value_obj_; + }; + }//end namespace detail + + template + class cloneable + { + using base_t = Base; + using cloneable_interface = detail::cloneable_interface; + + using const_base_ptr = typename std::conditional::type; + using const_base_ref = typename std::conditional::type; + + template friend class cloneable; + + struct inner_bool + { + int true_stand; + }; + + typedef int inner_bool::* operator_bool_t; + + template + using member_enabled = std::enable_if<(!std::is_base_of::type>::value) && std::is_base_of::type>::value, int>; + public: + cloneable() noexcept = default; + + cloneable(std::nullptr_t) noexcept{} + + template::type* = nullptr> + cloneable(T&& t) + : cwrapper_(new detail::cloneable_wrapper::type>(std::forward(t)), detail::cloneable_interface_deleter()), + fast_ptr_(reinterpret_cast::type*>(cwrapper_->get())) + {} + + cloneable(const cloneable& r) + { + if(r.cwrapper_) + { + cwrapper_ = std::move(std::shared_ptr(r.cwrapper_->clone(), detail::cloneable_interface_deleter{})); + fast_ptr_ = reinterpret_cast(cwrapper_->get()); + } + } + + cloneable(cloneable && r) + : cwrapper_(std::move(r.cwrapper_)), + fast_ptr_(r.fast_ptr_) + { + r.fast_ptr_ = nullptr; + } + + template::value>::type* = nullptr> + cloneable(const cloneable& other) + { + if (other) + { + char* value_ptr = reinterpret_cast(other.cwrapper_->get()); + char* base_ptr = reinterpret_cast(other.fast_ptr_); + + auto ptr_diff = std::distance(base_ptr, value_ptr); + + cwrapper_.reset(other.cwrapper_->clone(), detail::cloneable_interface_deleter{}); + fast_ptr_ = reinterpret_cast(reinterpret_cast(cwrapper_->get()) - ptr_diff); + } + } + + cloneable & operator=(const cloneable& r) + { + if((this != &r) && r.cwrapper_) + { + cwrapper_ = std::shared_ptr(r.cwrapper_->clone(), detail::cloneable_interface_deleter()); + fast_ptr_ = reinterpret_cast(cwrapper_->get()); + } + return *this; + } + + cloneable & operator=(cloneable&& r) + { + if(this != &r) + { + cwrapper_ = std::move(r.cwrapper_); + fast_ptr_ = r.fast_ptr_; + r.fast_ptr_ = nullptr; + } + return *this; + } + + base_t& operator*() + { + return *fast_ptr_; + } + + const_base_ref operator*() const noexcept + { + return *fast_ptr_; + } + + base_t * operator->() noexcept + { + return fast_ptr_; + } + + const_base_ptr operator->() const noexcept + { + return fast_ptr_; + } + + base_t * get() const noexcept + { + return fast_ptr_; + } + + void reset() + { + fast_ptr_ = nullptr; + cwrapper_.reset(); + } + + operator operator_bool_t() const noexcept + { + return (fast_ptr_ ? &inner_bool::true_stand : nullptr); + } + private: + std::shared_ptr cwrapper_; + base_t * fast_ptr_{nullptr}; + }; + + template + using mutable_cloneable = cloneable; +}//end namespace pat +}//end namespace nana +#include +#endif diff --git a/GUI/nana/pop_ignore_diagnostic b/GUI/nana/pop_ignore_diagnostic new file mode 100644 index 0000000..ff56355 --- /dev/null +++ b/GUI/nana/pop_ignore_diagnostic @@ -0,0 +1,5 @@ + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +# pragma GCC diagnostic pop +#endif + diff --git a/GUI/nana/push_ignore_diagnostic b/GUI/nana/push_ignore_diagnostic new file mode 100644 index 0000000..4931e9d --- /dev/null +++ b/GUI/nana/push_ignore_diagnostic @@ -0,0 +1,4 @@ +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Weffc++" +#endif diff --git a/GUI/nana/std_condition_variable.hpp b/GUI/nana/std_condition_variable.hpp new file mode 100644 index 0000000..5e202d9 --- /dev/null +++ b/GUI/nana/std_condition_variable.hpp @@ -0,0 +1,16 @@ +#ifndef NANA_STD_CONDITION_VARIABLE_HPP +#define NANA_STD_CONDITION_VARIABLE_HPP +#include + +#if defined(STD_THREAD_NOT_SUPPORTED) +#if defined(NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ) + #include +#else +#include +namespace std +{ + typedef boost::condition_variable condition_variable; +} +#endif // (NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ) +#endif // (STD_THREAD_NOT_SUPPORTED) +#endif // NANA_STD_CONDITION_VARIABLE_HPP diff --git a/GUI/nana/std_mutex.hpp b/GUI/nana/std_mutex.hpp new file mode 100644 index 0000000..55f486e --- /dev/null +++ b/GUI/nana/std_mutex.hpp @@ -0,0 +1,41 @@ +#ifndef NANA_STD_MUTEX_HPP +#define NANA_STD_MUTEX_HPP +#include + +#if defined(STD_THREAD_NOT_SUPPORTED) + +#if defined(NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ) +#include +#include +#include +//#include +//#include +#include +#include +// http://lxr.free-electrons.com/source/include/uapi/asm-generic/errno.h#L53 +//#define EPROTO 71 /* Protocol error */ +#ifdef _GLIBCXX_HAS_GTHREADS +# include +#else +#include +#include +#endif +#else +#include +#include +#include + +namespace std +{ + template + using lock_guard = boost::lock_guard; + + template + using unique_lock = boost::unique_lock; + + typedef boost::mutex mutex; + typedef boost::recursive_mutex recursive_mutex; +} +#endif // (NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ) +#endif // (STD_THREAD_NOT_SUPPORTED) +#endif // NANA_STD_MUTEX_HPP diff --git a/GUI/nana/std_thread.hpp b/GUI/nana/std_thread.hpp new file mode 100644 index 0000000..87db1e5 --- /dev/null +++ b/GUI/nana/std_thread.hpp @@ -0,0 +1,28 @@ +#ifndef NANA_STD_THREAD_HPP +#define NANA_STD_THREAD_HPP +#include + +#if defined(STD_THREAD_NOT_SUPPORTED) + +#if defined(NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ) + +#ifdef _GLIBCXX_HAS_GTHREADS +# include +#else +# include +#endif +#else +#include +namespace std +{ + typedef boost::thread thread; +} +#endif // (NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ) + +#else + +#include + +#endif // (STD_THREAD_NOT_SUPPORTED) + +#endif // NANA_STD_THREAD_HPP diff --git a/GUI/nana/stdc++.hpp b/GUI/nana/stdc++.hpp new file mode 100644 index 0000000..381882b --- /dev/null +++ b/GUI/nana/stdc++.hpp @@ -0,0 +1,161 @@ +/** + * Standard Library for C++11/14/17 + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2017-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/stdc++.hpp + * + * @brief Implement the lack support of standard library. + */ + +#ifndef NANA_STDCXX_INCLUDED +#define NANA_STDCXX_INCLUDED + +#include "c++defines.hpp" + +//Implement workarounds for GCC/MinGW which version is below 4.8.2 +#if defined(STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED) +namespace std +{ + //Workaround for no implementation of std::stoi in MinGW. + int stoi(const std::string&, std::size_t * pos = nullptr, int base = 10); + int stoi(const std::wstring&, std::size_t* pos = nullptr, int base = 10); + + //Workaround for no implementation of std::stof in MinGW. + float stof(const std::string&, std::size_t * pos = nullptr); + float stof(const std::wstring&, std::size_t* pos = nullptr); + + //Workaround for no implementation of std::stod in MinGW. + double stod(const std::string&, std::size_t * pos = nullptr); + double stod(const std::wstring&, std::size_t* pos = nullptr); + + //Workaround for no implementation of std::stold in MinGW. + long double stold(const std::string&, std::size_t * pos = nullptr); + long double stold(const std::wstring&, std::size_t* pos = nullptr); + + //Workaround for no implementation of std::stol in MinGW. + long stol(const std::string&, std::size_t* pos = nullptr, int base = 10); + long stol(const std::wstring&, std::size_t* pos = nullptr, int base = 10); + + //Workaround for no implementation of std::stoll in MinGW. + long long stoll(const std::string&, std::size_t* pos = nullptr, int base = 10); + long long stoll(const std::wstring&, std::size_t* pos = nullptr, int base = 10); + + //Workaround for no implementation of std::stoul in MinGW. + unsigned long stoul(const std::string&, std::size_t* pos = nullptr, int base = 10); + unsigned long stoul(const std::wstring&, std::size_t* pos = nullptr, int base = 10); + + //Workaround for no implementation of std::stoull in MinGW. + unsigned long long stoull(const std::string&, std::size_t* pos = nullptr, int base = 10); + unsigned long long stoull(const std::wstring&, std::size_t* pos = nullptr, int base = 10); +} +#endif //STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED + +#ifdef STD_TO_STRING_NOT_SUPPORTED +namespace std +{ + //Workaround for no implementation of std::to_string/std::to_wstring in MinGW. + std::string to_string(long double); + std::string to_string(double); + std::string to_string(unsigned); + std::string to_string(int); + std::string to_string(long); + std::string to_string(unsigned long); + std::string to_string(long long); + std::string to_string(unsigned long long); + std::string to_string(float); +} +#endif + +#ifdef STD_TO_WSTRING_NOT_SUPPORTED +namespace std +{ + std::wstring to_wstring(long double); + std::wstring to_wstring(double); + std::wstring to_wstring(unsigned); + std::wstring to_wstring(int); + std::wstring to_wstring(long); + std::wstring to_wstring(unsigned long); + std::wstring to_wstring(long long); + std::wstring to_wstring(unsigned long long); + std::wstring to_wstring(float); +} +#endif + +#ifdef _nana_std_make_unique + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3656.htm + +#include +#include +#include +#include + +namespace std { + template struct _Unique_if { + typedef unique_ptr _Single_object; + }; + + template struct _Unique_if { + typedef unique_ptr _Unknown_bound; + }; + + template struct _Unique_if { + typedef void _Known_bound; + }; + + template + typename _Unique_if::_Single_object + make_unique(Args&&... args) { + return unique_ptr(new T(std::forward(args)...)); + } + + template + typename _Unique_if::_Unknown_bound + make_unique(size_t n) { + typedef typename remove_extent::type U; + return unique_ptr(new U[n]()); + } + + template + typename _Unique_if::_Known_bound + make_unique(Args&&...) = delete; +} +#endif //_nana_std_make_unique + +#ifdef _nana_std_put_time +#include +#include +namespace std +{ + //Workaround for no implementation of std::put_time in gcc < 5. + /* std unspecified return type */ + //template< class CharT, class RTSTR >// let fail for CharT != char / wchar_t + //RTSTR put_time(const std::tm* tmb, const CharT* fmt); + + //template< > + std::string put_time/**/(const std::tm* tmb, const char* fmt); + + //Defined in header + // std::size_t strftime(char* str, std::size_t count, const char* format, const std::tm* time); + //template<> + //std::wstring put_time(const std::tm* tmb, const wchar_t* fmt); +} +#endif // _nana_std_put_time + +#if defined(_nana_std_clamp) +namespace std +{ + // since C++17 + template + constexpr const T& clamp(const T& v, const T& lo, const T& hi) + { + return (v < lo ? lo : (hi < v ? hi : v)); + } +} +#endif + +#endif // NANA_STDCXX_INCLUDED diff --git a/GUI/nana/system/dataexch.hpp b/GUI/nana/system/dataexch.hpp new file mode 100644 index 0000000..7ce6be7 --- /dev/null +++ b/GUI/nana/system/dataexch.hpp @@ -0,0 +1,51 @@ +/* + * Data Exchanger Implementation + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/system/dataexch.hpp + * @description: An implementation of a data exchange mechanism through Windows Clipboard, X11 Selection. + */ + +#ifndef NANA_SYSTEM_DATAEXCH_HPP +#define NANA_SYSTEM_DATAEXCH_HPP +#include + +namespace nana{ + +namespace paint{ + class graphics; +} + +namespace system{ + + /// a data exchange mechanism through Windows Clipboard, X11 Selection. + class dataexch + { + public: + enum class format + { + text, pixmap + }; + + void set(const std::string & text_utf8, native_window_type owner = nullptr); + void set(const std::wstring& text, native_window_type owner = nullptr); + + bool set(const nana::paint::graphics& g, native_window_type owner = nullptr); + + void get(std::string& text_utf8); + void get(std::wstring& text); + + std::wstring wget(); + private: + bool _m_set(format, const void* buf, std::size_t size, native_window_type); + void* _m_get(format, size_t& size); + }; + +}//end namespace system +}//end namespace nana + +#endif diff --git a/GUI/nana/system/platform.hpp b/GUI/nana/system/platform.hpp new file mode 100644 index 0000000..399e149 --- /dev/null +++ b/GUI/nana/system/platform.hpp @@ -0,0 +1,46 @@ +/* + * A platform API implementation + * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/system/platform.hpp + * @description: + * this implements some API for platform-independent programming + */ + +#ifndef NANA_SYSTEM_PLATFORM_HPP +#define NANA_SYSTEM_PLATFORM_HPP +#include + +namespace nana +{ +namespace system +{ + //sleep + //@brief: suspend current thread for a specified milliseconds. + //its precision is depended on hardware. + void sleep(unsigned milliseconds); + + //this_thread_id + //@brief: get the identifier of calling thread. + thread_t this_thread_id(); + + //timestamp + //@brief: it retrieves the timestamp at the time the function is called. + // it is easy for get the number of milliseconds between calls. + unsigned long timestamp(); + + //get_async_mouse_state + //@brief: it determines whether a mouse button was pressed at the time the function is called. + bool get_async_mouse_state(int button); + + //open an url through a default browser + void open_url(const std::string& url); + +}//end namespace system +}//end namespace nana + +#endif diff --git a/GUI/nana/system/shared_wrapper.hpp b/GUI/nana/system/shared_wrapper.hpp new file mode 100644 index 0000000..ab14997 --- /dev/null +++ b/GUI/nana/system/shared_wrapper.hpp @@ -0,0 +1,101 @@ +/* + * Operation System Shared Linkage Library Wrapper Implementation + * Copyright(C) 2003-2016 Jinhao + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/system/shared_wrapper.hpp + * @description: + */ +#ifndef NANA_SYSTEM_SHARED_WRAPPER_HPP +#define NANA_SYSTEM_SHARED_WRAPPER_HPP + +#include +#include +#include + + +namespace nana +{ +namespace system +{ + + namespace detail + { + namespace shared_helper + { + + typedef void* module_t; + void* symbols(module_t handle, const char* symbol); + + } //end namespace shared_helper + }//end namespace detail + + class shared_wrapper + { + typedef detail::shared_helper::module_t module_t; + + + template + struct function_ptr + { + typedef typename std::conditional::value, + Function*, + typename std::conditional::value && std::is_pointer::value, Function, int>::type + >::type type; + }; + + struct impl_type + { + module_t handle; + std::string symbol; + void* proc_address; + + impl_type(); + }; + public: + shared_wrapper(); + shared_wrapper(const char* filename); + ~shared_wrapper(); + + bool open(const char* filename); + void close(); + bool empty() const; + + template + typename function_ptr::type symbols(const char* symbol) + { + typedef typename function_ptr::type fptr_type; + + //if(nana::traits::is_function_pointer::value == false) + if (::std::is_function::type>::value == false) + throw std::invalid_argument("shared_wrapper::symbols, template<_Function> is not a function type or a function pointer type"); + + if(symbol == 0) + throw std::invalid_argument("shared_wrapper::symbols, symbol is null string"); + + if(impl_.handle == 0) + throw std::logic_error("shared_wrapper::symbols, empty handle"); + + if(impl_.symbol != symbol) + { + void *result = detail::shared_helper::symbols(impl_.handle, symbol); + if(result == 0) + throw std::logic_error("shared_wrapper::symbols, empty proc address"); + + impl_.proc_address = result; + impl_.symbol = symbol; + } + return (fptr_type)(this->impl_.proc_address); + } + + private: + impl_type impl_; + }; +}//end namespace system +}//end namespace nana + +#endif + diff --git a/GUI/nana/system/timepiece.hpp b/GUI/nana/system/timepiece.hpp new file mode 100644 index 0000000..b1db9db --- /dev/null +++ b/GUI/nana/system/timepiece.hpp @@ -0,0 +1,40 @@ +/* + * Timepiece Implementation + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/system/timepiece.hpp + * @description: a time counter + */ + +#ifndef NANA_SYSTEM_TIMEPIECE_HPP +#define NANA_SYSTEM_TIMEPIECE_HPP + +#include "../c++defines.hpp" + +namespace nana +{ +namespace system +{ /// used for measuring and signaling the end of time intervals. + class timepiece + { + public: + timepiece(); + timepiece(const timepiece&); + ~timepiece(); + timepiece & operator=(const timepiece &); + void start() noexcept; ///< Set the begin time. + double calc() const noexcept; ///< Get the intervals from the begin time. + private: + struct impl_t; + impl_t * impl_; + }; + +}//end namespace system +}//end namespace nana + +#endif + diff --git a/GUI/nana/threads/pool.hpp b/GUI/nana/threads/pool.hpp new file mode 100644 index 0000000..1234bcb --- /dev/null +++ b/GUI/nana/threads/pool.hpp @@ -0,0 +1,136 @@ +/* + * A Thread Pool Implementation + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * + * @file: nana/threads/pool.hpp + */ + +#ifndef NANA_THREADS_POOL_HPP +#define NANA_THREADS_POOL_HPP + +#include +#include +#include +#include + +#ifndef STD_THREAD_NOT_SUPPORTED +# include +#endif + +namespace nana{ + /// Some mutex classes for synchronizing. +namespace threads +{ /// A thread pool manages a group threads for a large number of tasks processing. + class pool + { + struct task + { + enum t{general, signal}; + + const t kind; + + task(t); + virtual ~task() = 0; + virtual void run() = 0; + }; + + template + struct task_wrapper + : task + { + typedef Function function_type; + function_type taskobj; + + task_wrapper(const function_type& f) + : task(task::general), taskobj(f) + {} + + void run() + { + taskobj(); + } + }; + + struct task_signal; + class impl; + + pool(const pool&) = delete; + pool& operator=(const pool&) = delete; + public: +#ifndef STD_THREAD_NOT_SUPPORTED + pool(unsigned thread_number = std::thread::hardware_concurrency()); ///< Creates a group of threads. +#else + pool(unsigned thread_number = 0); +#endif + pool(pool&&); + ~pool(); ///< waits for the all running tasks till they are finished and skips all the queued tasks. + + pool& operator=(pool&&); + + template + void push(const Function& f) + { + task * taskptr = nullptr; + + try + { + taskptr = new task_wrapper::value, Function*, Function>::type>(f); + _m_push(taskptr); + } + catch(std::bad_alloc&) + { + delete taskptr; + } + } + + void signal(); ///< Make a signal that will be triggered when the tasks which are pushed before it are finished. + void wait_for_signal(); ///< Waits for a signal until the signal processed. + void wait_for_finished(); + private: + void _m_push(task* task_ptr); + private: + impl * impl_; + };//end class pool + + /// Manages a group threads for a large number of tasks processing. + template + class pool_pusher + { + public: + /// same as Function if Function is not a function prototype, otherwise value_type is a pointer type of function + typedef typename std::conditional::value, Function*, Function>::type value_type; + + pool_pusher(pool& pobj, value_type fn) + :pobj_(pobj), value_(fn) + {} + + void operator()() const + { + pobj_.push(value_); + } + private: + pool & pobj_; + value_type value_; + }; + + template + pool_pusher pool_push(pool& pobj, const Function& fn) + { + return pool_pusher(pobj, fn); + } + + template + pool_pusher > pool_push(pool& pobj, Class& obj, void(Concept::*mf)()) + { + return pool_pusher >(pobj, std::bind(mf, &obj)); + } + +}//end namespace threads +}//end namespace nana +#endif + diff --git a/GUI/nana/traits.hpp b/GUI/nana/traits.hpp new file mode 100644 index 0000000..ae27f9f --- /dev/null +++ b/GUI/nana/traits.hpp @@ -0,0 +1,61 @@ +/* + * Traits Implementation + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * + * @file: nana/traits.hpp + */ + +#ifndef NANA_TRAITS_HPP +#define NANA_TRAITS_HPP +#include + +namespace nana +{ + class null_type{}; + + /// Prevent a class to be copyable + class noncopyable + { + noncopyable(const noncopyable&) = delete; + noncopyable& operator=(const noncopyable&) = delete; + protected: + noncopyable() = default; + }; + + /// Prevent a class to be movable + class nonmovable + { + nonmovable(nonmovable&&) = delete; + nonmovable& operator=(nonmovable&&) = delete; + protected: + nonmovable() = default; + }; + + namespace meta + { + template< typename Param0 = null_type, typename Param1 = null_type, + typename Param2 = null_type, typename Param3 = null_type, + typename Param4 = null_type, typename Param5 = null_type, + typename Param6 = null_type, typename Param7 = null_type, + typename Param8 = null_type, typename Param9 = null_type> + struct fixed_type_set + { + template + struct count + { + enum{value = std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value + + std::is_same::value}; + }; + }; + }//end namespace meta +}//end namespace nana + +#endif diff --git a/GUI/nana/unicode_bidi.hpp b/GUI/nana/unicode_bidi.hpp new file mode 100644 index 0000000..2d74516 --- /dev/null +++ b/GUI/nana/unicode_bidi.hpp @@ -0,0 +1,79 @@ +#ifndef NANA_UNICODE_BIDI_HPP +#define NANA_UNICODE_BIDI_HPP +#include +#include + + +namespace nana +{ + class unicode_bidi + { + public: + typedef wchar_t char_type; + + enum class directional_override_status + { + neutral, right_to_left, left_to_right + }; + + enum class bidi_char + { + L, LRE, LRO, R, AL, RLE, RLO, + PDF = 0x1000, EN, ES, ET, AN, CS, NSM, BN, + B = 0x2000, S, WS, ON + }; + + enum class bidi_category + { + strong, weak = 0x1000, neutral = 0x2000 + }; + + const static char_type LRE = 0x202A; + const static char_type RLE = 0x202B; + const static char_type PDF = 0x202C; + const static char_type LRO = 0x202D; + const static char_type RLO = 0x202E; + const static char_type LRM = 0x200E; + const static char_type RLM = 0x200F; + + struct remember + { + unsigned level; + directional_override_status directional_override; + }; + + struct entity + { + const wchar_t * begin, * end; + bidi_char bidi_char_type; + unsigned level; + }; + + std::vector reorder(const char_type*, std::size_t len); + static bool is_text_right(const entity&); + private: + static unsigned _m_paragraph_level(const char_type * begin, const char_type * end); + + void _m_push_entity(const char_type * begin, const char_type *end, unsigned level, bidi_char); + + std::vector::iterator _m_search_first_character(); + + bidi_char _m_eor(std::vector::iterator); + + void _m_resolve_weak_types(); + void _m_resolve_neutral_types(); + void _m_resolve_implicit_levels(); + void _m_reordering_resolved_levels(std::vector & reordered); + static bidi_category _m_bidi_category(bidi_char); + static bidi_char _m_char_dir(char_type); + private: + std::vector levels_; + }; + + std::vector unicode_reorder(const wchar_t* text, std::size_t length); + + bool unicode_wordbreak(wchar_t left, wchar_t right); +} +#include + +#endif diff --git a/GUI/nana/verbose_preprocessor.hpp b/GUI/nana/verbose_preprocessor.hpp new file mode 100644 index 0000000..ee0089b --- /dev/null +++ b/GUI/nana/verbose_preprocessor.hpp @@ -0,0 +1,137 @@ +/** + * Nana Verbose preprocessor + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/verbose_preprocessor.hpp + * + * @brief show the values of configuration constants during compilation to facilitate build debugging. + * + * Define VERBOSE_PREPROCESSOR to show the messages or undefine for a normal build. + * Normally undefined. Define in case you want to debug the build system. + * + * @authors Ariel Vina-Rodriguez (qPCR4vir) + * + */ +// Created by ariel.rodriguez on 08.12.2015. +// + +#ifndef NANA_VERBOSE_PREPROCESSOR_H +#define NANA_VERBOSE_PREPROCESSOR_H + +#if defined(VERBOSE_PREPROCESSOR) + + #include + #include + + + + #define STRING2(...) #__VA_ARGS__ + #define STRING(x) STRING2(x) + #define SHOW_VALUE(x) " " #x " = " STRING2(x) + + #pragma message ( "\n -----> Verbose preprocessor" ) + #pragma message ( SHOW_VALUE(VERBOSE_PREPROCESSOR) ) + #pragma message ( SHOW_VALUE(STOP_VERBOSE_PREPROCESSOR) ) + + #pragma message ( "\n -----> OS: \n --Windows: " ) + #pragma message ( SHOW_VALUE(_WIN32) ) + #pragma message ( SHOW_VALUE(__WIN32__) ) + #pragma message ( SHOW_VALUE(WIN32) ) + #pragma message ( SHOW_VALUE(NANA_WINDOWS) ) + + #pragma message ( "\n ---NIX: " ) + #pragma message ( SHOW_VALUE(NANA_LINUX) ) + #pragma message ( SHOW_VALUE(NANA_POSIX) ) + #pragma message ( SHOW_VALUE(NANA_X11) ) + #pragma message ( SHOW_VALUE(APPLE) ) + #pragma message ( SHOW_VALUE(NANA_IGNORE_CONF) ) + + + #pragma message ( "\n -----> Compilers: \n MinGW: " ) + #pragma message ( SHOW_VALUE(__MINGW32__) ) + #pragma message ( SHOW_VALUE(__MINGW64__) ) + #pragma message ( SHOW_VALUE(MINGW) ) + + #pragma message ( "\n ---MSC: " ) + #pragma message ( SHOW_VALUE(_MSC_VER) ) + #pragma message ( SHOW_VALUE(_MSC_FULL_VER) ) + + #pragma message ( "\n ---GNU: " ) + #pragma message ( SHOW_VALUE(__GNUC__) ) + #pragma message ( SHOW_VALUE(__GNUC_MINOR__) ) + #pragma message ( SHOW_VALUE(__GNUC_PATCHLEVEL__) ) + + #pragma message ( "\n ---Clang compiler: " ) + #pragma message ( SHOW_VALUE(__clang__) ) + #pragma message ( SHOW_VALUE(__GLIBCPP__) ) + #pragma message ( SHOW_VALUE(__GLIBCXX__) ) + + #pragma message ( "\n -----> STD: " ) + #pragma message ( SHOW_VALUE(STD_CODECVT_NOT_SUPPORTED) ) + #pragma message ( SHOW_VALUE(STD_THREAD_NOT_SUPPORTED) ) + #pragma message ( SHOW_VALUE(STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED) ) + #pragma message ( SHOW_VALUE(STD_TO_STRING_NOT_SUPPORTED) ) + #pragma message ( SHOW_VALUE(STD_TO_WSTRING_NOT_SUPPORTED) ) + #pragma message ( SHOW_VALUE(USE_github_com_meganz_mingw_std_threads) ) + #pragma message ( SHOW_VALUE(NANA_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ) ) + #pragma message ( SHOW_VALUE(STD_THREAD_NOT_SUPPORTED) ) + #pragma message ( SHOW_VALUE(_nana_std_put_time) ) + #pragma message ( SHOW_VALUE(STD_MAKE_UNIQUE_NOT_SUPPORTED) ) + + #pragma message ( SHOW_VALUE(STD_FILESYSTEM_NOT_SUPPORTED) ) + #pragma message ( SHOW_VALUE(BOOST_FILESYSTEM_AVAILABLE) ) + #pragma message ( SHOW_VALUE(BOOST_FILESYSTEM_FORCE) ) + #pragma message ( SHOW_VALUE(STD_FILESYSTEM_FORCE) ) + #pragma message ( SHOW_VALUE(NANA_FILESYSTEM_FORCE) ) + #pragma message ( SHOW_VALUE(CXX_NO_INLINE_NAMESPACE) ) + //#pragma message ( SHOW_VALUE(__has_include) ) + #pragma message ( SHOW_VALUE(__cpp_lib_experimental_filesystem) ) + #pragma message ( SHOW_VALUE(NANA_USING_NANA_FILESYSTEM) ) + #pragma message ( SHOW_VALUE(NANA_USING_STD_FILESYSTEM) ) + #pragma message ( SHOW_VALUE(NANA_USING_BOOST_FILESYSTEM) ) + + #pragma message ( "\n#include " ) + #include + + #pragma message ( SHOW_VALUE(STD_MAKE_UNIQUE_NOT_SUPPORTED) ) + #pragma message ( SHOW_VALUE(STD_FILESYSTEM_NOT_SUPPORTED) ) + #pragma message ( SHOW_VALUE(BOOST_FILESYSTEM_AVAILABLE) ) + #pragma message ( SHOW_VALUE(BOOST_FILESYSTEM_FORCE) ) + #pragma message ( SHOW_VALUE(STD_FILESYSTEM_FORCE) ) + #pragma message ( SHOW_VALUE(NANA_FILESYSTEM_FORCE) ) + #pragma message ( SHOW_VALUE(CXX_NO_INLINE_NAMESPACE) ) + //#pragma message ( SHOW_VALUE(__has_include) ) + #pragma message ( SHOW_VALUE(__cpp_lib_experimental_filesystem) ) + #pragma message ( SHOW_VALUE(NANA_USING_NANA_FILESYSTEM) ) + #pragma message ( SHOW_VALUE(NANA_USING_STD_FILESYSTEM) ) + #pragma message ( SHOW_VALUE(NANA_USING_BOOST_FILESYSTEM) ) + + #pragma message ( SHOW_VALUE(NANA_UNICODE) ) + #pragma message ( SHOW_VALUE(_UNICODE) ) + #pragma message ( SHOW_VALUE(UNICODE) ) + + #pragma message ( "\n -----> Libraries: " ) + #pragma message ( SHOW_VALUE(NANA_ENABLE_AUDIO) ) + #pragma message ( SHOW_VALUE(NANA_ENABLE_PNG) ) + #pragma message ( SHOW_VALUE(USE_LIBPNG_FROM_OS) ) + #pragma message ( SHOW_VALUE(NANA_LIBPNG) ) + #pragma message ( SHOW_VALUE(NANA_ENABLE_JPEG) ) + #pragma message ( SHOW_VALUE(USE_LIBJPEG_FROM_OS) ) + #pragma message ( SHOW_VALUE(NANA_LIBJPEG) ) + + + // #pragma message ( "\n =" STRING() ", \n =" STRING()" , \n =" STRING() ) + + #if defined(STOP_VERBOSE_PREPROCESSOR) + #error ("\nCompilation stopped to avoid annoying messages") + #endif + +#endif // VERBOSE_PREPROCESSOR + + +#endif //NANA_VERBOSE_PREPROCESSOR_H