├── .gitignore ├── MaterialUI-QML.pro ├── README.md ├── main.cpp ├── main.py ├── qml.qrc ├── readme_image ├── image1.jpg └── image2.jpg ├── src └── utils │ ├── application_event_filter.cpp │ ├── application_event_filter.h │ └── application_event_filter.py └── src_qml ├── common_component ├── MaterialUI │ ├── Font │ │ ├── FontAwesomeFont.qml │ │ ├── IconsName.js │ │ ├── fa-solid-900.ttf │ │ ├── fontawesome.css │ │ └── qmldir │ ├── MAnimation.qml │ ├── MButton.qml │ ├── MButtonBase.qml │ ├── MButtonGroup.qml │ ├── MCheckbox.qml │ ├── MChip.qml │ ├── MCircularProgress.qml │ ├── MCollapse.qml │ ├── MColorPicker.qml │ ├── MComplexSelect.qml │ ├── MCopyText.qml │ ├── MDatePicker.qml │ ├── MDateSelector.qml │ ├── MDialog.qml │ ├── MDirectoryButton.qml │ ├── MDivider.qml │ ├── MFade.qml │ ├── MFileButton.qml │ ├── MFileMenuItem.qml │ ├── MFilledInput.qml │ ├── MFormControlLabel.qml │ ├── MFramelessWindow.qml │ ├── MGrow.qml │ ├── MIcon.qml │ ├── MIconButton.qml │ ├── MInput.qml │ ├── MInputBase.qml │ ├── MLinearProgress.qml │ ├── MList.qml │ ├── MListItem.qml │ ├── MMenu.qml │ ├── MMenuItem.qml │ ├── MMenuList.qml │ ├── MOutlinedInput.qml │ ├── MOverflowYBox.qml │ ├── MPaper.qml │ ├── MPopover.qml │ ├── MRadio.qml │ ├── MRadioGroup.qml │ ├── MRipple.qml │ ├── MScaleX.qml │ ├── MScaleY.qml │ ├── MSelect.qml │ ├── MSelectBase.qml │ ├── MSlide.qml │ ├── MSlider.qml │ ├── MSvgIcon.qml │ ├── MSwitch.qml │ ├── MTextField.qml │ ├── MTimePicker.qml │ ├── MToast.qml │ ├── MToolTip.qml │ ├── MTouchRipple.qml │ ├── MTypography.qml │ ├── MZoom.qml │ ├── StyleComponent │ │ ├── MFilledInputStyle.qml │ │ ├── MFramelessWindowButtonsMac.qml │ │ ├── MFramelessWindowButtonsWin.qml │ │ ├── MInputStyle.qml │ │ ├── MOutlinedInputStyle.qml │ │ └── MWindowResizeHandler.qml │ ├── SvgIcon │ │ ├── FilledMap.js │ │ ├── OutlinedMap.js │ │ ├── RoundedMap.js │ │ ├── SharpMap.js │ │ └── TwoToneMap.js │ ├── colors │ │ ├── Grey.qml │ │ ├── Indigo.qml │ │ ├── Pink.qml │ │ ├── Red.qml │ │ └── qmldir │ ├── qmldir │ └── styles │ │ ├── Colors.qml │ │ ├── MShadow.qml │ │ ├── Palette.qml │ │ ├── TypographyStyle.qml │ │ └── qmldir ├── Route │ ├── Route.qml │ └── qmldir ├── SQL │ ├── QSQL │ │ ├── QSQL.qml │ │ ├── persistence.js │ │ ├── persistence.store.sql.js │ │ └── qmldir │ ├── SQLHelper │ │ ├── SQLTools.qml │ │ └── qmldir │ └── sqml │ │ ├── CrudDao.qml │ │ ├── CrudService.qml │ │ ├── DatabaseConnection.qml │ │ ├── SqlMapping.qml │ │ ├── SqlQueryBuilder.qml │ │ └── qmldir └── Timer │ ├── ExeOnceTimer │ └── ExeOnceTimer.qml │ └── OnceTimer │ └── OnceTimer.qml ├── common_image └── Icon │ └── logo.png ├── common_js ├── Color.js ├── ComponentConfig.js ├── StringUtil.js └── Tools.js ├── common_qml ├── Aria2Util.qml ├── GlobalTaskList.qml ├── QHttp.qml └── qmldir ├── instance_component ├── AboutDialog │ └── AboutDialog.qml ├── Navbar │ └── Navbar.qml ├── SQLTable │ ├── SettingData │ │ ├── SettingData.qml │ │ └── qmldir │ ├── TableBase │ │ └── TableBase.qml │ └── TableFactory │ │ ├── TableFactory.qml │ │ └── qmldir └── SystemTray │ └── SystemTray.qml ├── main.qml └── pages ├── Api ├── BaseApi.qml ├── ButtonApi.qml ├── ButtonBaseApi.qml ├── ButtonGroupApi.qml ├── CheckboxApi.qml ├── CircularProgressApi.qml ├── ColorPickerApi.qml ├── ComplexSelectApi.qml ├── DatePickerApi.qml ├── FormControlLabelApi.qml ├── FramelessWindowApi.qml ├── IconApi.qml ├── LinearProgressApi.qml ├── PaperApi.qml ├── PropsTable.qml ├── RadioApi.qml ├── RadioGroupApi.qml ├── SelectApi.qml ├── SliderApi.qml ├── SvgIconApi.qml ├── SwitchApi.qml ├── TextFieldApi.qml └── TimePicker.qml ├── Display ├── ButtonGroupPage.qml ├── ButtonPage.qml ├── CheckboxPage.qml ├── ColoPickerPage.qml ├── DateTimePickerPage.qml ├── FontAwesomeIconPage.qml ├── FramelessWindowPage.qml ├── IconPage.qml ├── PaperPage.qml ├── ProgressPage.qml ├── RadioPage.qml ├── SelectPage.qml ├── SliderPage.qml ├── SvgIconPage.qml ├── SwitchPage.qml ├── TextFieldPage.qml └── TransitionsPage.qml └── HomePage └── HomePage.qml /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/* 2 | 3 | MaterialUI-QML.pro.* 4 | build/* 5 | dist/* 6 | 7 | # Windows image file caches 8 | Thumbs.db 9 | ehthumbs.db 10 | 11 | # Folder config file 12 | Desktop.ini 13 | 14 | # Recycle Bin used on file shares 15 | $RECYCLE.BIN/ 16 | 17 | # Windows Installer files 18 | *.cab 19 | *.msi 20 | *.msm 21 | *.msp 22 | 23 | # Windows shortcuts 24 | *.lnk 25 | 26 | # ========================= 27 | # Operating System Files 28 | # ========================= 29 | 30 | # OSX 31 | # ========================= 32 | 33 | .DS_Store 34 | .AppleDouble 35 | .LSOverride 36 | 37 | *.pyc 38 | 39 | # Thumbnails 40 | ._* 41 | 42 | # Files that might appear in the root of a volume 43 | .DocumentRevisions-V100 44 | .fseventsd 45 | .Spotlight-V100 46 | .TemporaryItems 47 | .Trashes 48 | .VolumeIcon.icns 49 | 50 | # Directories potentially created on remote AFP share 51 | .AppleDB 52 | .AppleDesktop 53 | Network Trash Folder 54 | Temporary Items 55 | .apdisk 56 | -------------------------------------------------------------------------------- /MaterialUI-QML.pro: -------------------------------------------------------------------------------- 1 | QT += quick 2 | QT += quickcontrols2 3 | QT += gui 4 | QT += core 5 | QT += multimedia 6 | QT += network 7 | QT += sql 8 | 9 | CONFIG += c++11 10 | QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.15 11 | 12 | # You can make your code fail to compile if it uses deprecated APIs. 13 | # In order to do so, uncomment the following line. 14 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 15 | 16 | HEADERS += \ 17 | src/utils/application_event_filter.h 18 | 19 | SOURCES += main.cpp \ 20 | src/utils/application_event_filter.cpp 21 | 22 | RESOURCES += qml.qrc 23 | 24 | # Additional import path used to resolve QML modules in Qt Creator's code model 25 | QML_IMPORT_PATH = 26 | 27 | # Additional import path used to resolve QML modules just for Qt Quick Designer 28 | QML_DESIGNER_IMPORT_PATH = 29 | 30 | # Default rules for deployment. 31 | qnx: target.path = /tmp/$${TARGET}/bin 32 | else: unix:!android: target.path = /opt/$${TARGET}/bin 33 | !isEmpty(target.path): INSTALLS += target 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MaterialUI-QML 2 | This is a material ui written by Qt QML 3 | 4 | [Material Design](https://m1.material.io/) is a specification for a unified system of visual, motion, and interaction design that adapts across different devices. 5 | 6 | I try to deliver a set of QML UI components that implement the material design specification for use in Qt QML applications. 7 | 8 | # Qt version 9 | This branch is written for Qt5(PySide2). You can use the branch for [Qt6(PySide6)](https://github.com/AndyQsmart/MaterialUI-QML/tree/Qt6). 10 | 11 | # Usage 12 | Import package in your project 13 | ``` 14 | import "./common_component/MaterialUI" 15 | ``` 16 | In this case,I place "Material UI" in folder "common_component".You can move the "Material UI" to anywhere you want. 17 | 18 | # Example 19 | You can run the example project.It is an example that show some usage of components. 20 | 21 | 1. run in C++ 22 | - Qt 5.15.2 23 | - Set `QQuickWindow::setDefaultAlphaBuffer(true);` if use `MFramelessWindow` in mac. 24 | 25 | 2. run in Python 26 | - Python 3.9 27 | - pip install PySide2==5.15.2.1 28 | - Set `QQuickWindow.setDefaultAlphaBuffer(True)` if use `MFramelessWindow` in mac. 29 | - `python main.py` 30 | 31 | ![image](https://github.com/AndyQsmart/MaterialUI-QML/blob/main/readme_image/image1.jpg) 32 | ![image](https://github.com/AndyQsmart/MaterialUI-QML/blob/main/readme_image/image2.jpg) 33 | 34 | # Components (until now) 35 | ``` 36 | MAnimation.qml 37 | MButton.qml 38 | MButtonBase.qml 39 | MButtonGroup.qml 40 | MCheckbox.qml 41 | MChip.qml 42 | MCircularProgress.qml 43 | MCollapse.qml 44 | MColorPicker.qml 45 | MComplexSelect.qml 46 | MCopyText.qml 47 | MDatePicker.qml 48 | MDateSelector.qml 49 | MDialog.qml 50 | MDirectoryButton.qml 51 | MDivider.qml 52 | MFade.qml 53 | MFileButton.qml 54 | MFormControlLabel.qml 55 | MGrow.qml 56 | MIcon.qml 57 | MIconButton.qml 58 | MLinearProgress.qml 59 | MList.qml 60 | MListItem.qml 61 | MMenu.qml 62 | MMenuItem.qml 63 | MMenuList.qml 64 | MOverflowYBox.qml 65 | MPaper.qml 66 | MPopover.qml 67 | MRadio.qml 68 | MRadioGroup.qml 69 | MSelect.qml 70 | MSelectBase.qml 71 | MSlide.qml 72 | MSlider.qml 73 | MSvgIcon.qml 74 | MSwitch.qml 75 | MTextField.qml 76 | MTimePicker.qml 77 | MToast.qml 78 | MToolTip.qml 79 | MTypography.qml 80 | MZoom.qml 81 | ``` 82 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "src/utils/application_event_filter.h" 8 | 9 | int main(int argc, char *argv[]) { 10 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 11 | // 高分辨率适配 12 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 13 | QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); 14 | #endif 15 | 16 | QGuiApplication app(argc, argv); 17 | QFont default_font; 18 | default_font.setFamily("Arial"); 19 | app.setFont(default_font); 20 | app.setOrganizationName("AndyQsmart"); 21 | app.setOrganizationDomain("https://github.com/AndyQsmart/MaterialUI-QML"); 22 | 23 | QQmlApplicationEngine engine; 24 | 25 | // mac端无边框窗口,需要启用默认 Alpha 缓冲区 26 | #ifdef Q_OS_MAC 27 | QQuickWindow::setDefaultAlphaBuffer(true); 28 | #endif 29 | 30 | // 全局特殊事件处理 31 | ApplicationEventFilter *app_event_filter = new ApplicationEventFilter(); 32 | app.installEventFilter(app_event_filter); 33 | engine.rootContext()->setContextProperty("AppEventFilter", app_event_filter); 34 | 35 | const QUrl url(QStringLiteral("qrc:/src_qml/main.qml")); 36 | QObject::connect( 37 | &engine, &QQmlApplicationEngine::objectCreated, 38 | &app, [url](QObject *obj, const QUrl &objUrl) { 39 | if (!obj && url == objUrl) 40 | QCoreApplication::exit(-1); 41 | }, 42 | Qt::QueuedConnection 43 | ); 44 | 45 | engine.load(url); 46 | 47 | return app.exec(); 48 | } 49 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # This Python file uses the following encoding: utf-8 2 | import sys 3 | import os 4 | import platform 5 | 6 | from PySide2.QtCore import QCoreApplication, Qt 7 | from PySide2.QtGui import QGuiApplication, QFont 8 | from PySide2.QtQuick import QQuickWindow 9 | from PySide2.QtQml import QQmlApplicationEngine 10 | 11 | from src.utils.application_event_filter import ApplicationEventFilter 12 | 13 | if __name__ == "__main__": 14 | # 高分辨率适配 15 | QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling) 16 | QGuiApplication.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough) 17 | 18 | app = QGuiApplication(sys.argv) 19 | # QQuickStyle.setStyle('Material') 20 | defualt_font = QFont() 21 | defualt_font.setFamily("Arial") 22 | app.setFont(defualt_font) 23 | app.setOrganizationName('AndyQsmart') 24 | app.setOrganizationDomain('https://github.com/AndyQsmart/MaterialUI-QML') 25 | 26 | engine = QQmlApplicationEngine() 27 | 28 | # mac端无边框窗口,需要启用默认的 Alpha 缓冲区 29 | if platform.system() == 'Darwin': 30 | QQuickWindow.setDefaultAlphaBuffer(True) 31 | 32 | # 全局特殊事件处理 33 | app_event_filter = ApplicationEventFilter() 34 | app.installEventFilter(app_event_filter) 35 | engine.rootContext().setContextProperty("AppEventFilter", app_event_filter) 36 | 37 | engine.load(os.path.join(os.path.dirname(__file__), "src_qml/main.qml")) 38 | 39 | if not engine.rootObjects(): 40 | sys.exit(-1) 41 | 42 | sys.exit(app.exec_()) 43 | -------------------------------------------------------------------------------- /readme_image/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyQsmart/MaterialUI-QML/f423357a1293878bc481d2ad496211742e29cbd7/readme_image/image1.jpg -------------------------------------------------------------------------------- /readme_image/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyQsmart/MaterialUI-QML/f423357a1293878bc481d2ad496211742e29cbd7/readme_image/image2.jpg -------------------------------------------------------------------------------- /src/utils/application_event_filter.cpp: -------------------------------------------------------------------------------- 1 | #include "application_event_filter.h" 2 | #include 3 | #include 4 | #include 5 | 6 | bool ApplicationEventFilter::eventFilter(QObject *obj, QEvent *event) { 7 | // qDebug() << event->type(); 8 | auto event_type = event->type(); 9 | 10 | #ifdef Q_OS_MAC 11 | if (event_type == QEvent::ApplicationStateChange) { 12 | Qt::ApplicationState state = static_cast(event)->applicationState(); 13 | if (state == Qt::ApplicationActive) { 14 | emit appEvent("MAC_ApplicationActive", QVariant()); 15 | } 16 | } 17 | else if (event_type == QEvent::Quit) { 18 | emit appEvent("MAC_Quit", QVariant()); 19 | } 20 | #endif 21 | 22 | return QObject::eventFilter(obj, event); 23 | } 24 | -------------------------------------------------------------------------------- /src/utils/application_event_filter.h: -------------------------------------------------------------------------------- 1 | #ifndef APPLICATIONEVENTFILTER_H 2 | #define APPLICATIONEVENTFILTER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class ApplicationEventFilter : public QObject { 9 | Q_OBJECT 10 | 11 | protected: 12 | bool eventFilter(QObject *obj, QEvent *event) override; 13 | 14 | signals: 15 | void appEvent(QString type, QVariant data); 16 | }; 17 | 18 | #endif // APPLICATIONEVENTFILTER_H 19 | -------------------------------------------------------------------------------- /src/utils/application_event_filter.py: -------------------------------------------------------------------------------- 1 | import platform 2 | from PySide2.QtCore import Qt, QObject, Signal, QEvent 3 | from PySide2.QtWidgets import QApplication 4 | 5 | class ApplicationEventFilter(QObject): 6 | appEvent = Signal(str, 'QVariant') 7 | 8 | def eventFilter(self, obj: QObject, event: QEvent): 9 | event_type = event.type() 10 | 11 | if platform.system() == 'Darwin': 12 | if event_type == QEvent.ApplicationStateChange: 13 | state = QApplication.instance().applicationState() 14 | if state == Qt.ApplicationActive: 15 | self.appEvent.emit("MAC_ApplicationActive", {}) 16 | elif event_type == QEvent.Quit: 17 | state = QApplication.instance().applicationState() 18 | self.appEvent.emit("MAC_Quit", {}) 19 | 20 | return super().eventFilter(obj, event) 21 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/Font/FontAwesomeFont.qml: -------------------------------------------------------------------------------- 1 | // Fonts.qml 2 | //加载fontawesome5 otf 3 | pragma Singleton 4 | 5 | import QtQuick 2.15 6 | 7 | Item { 8 | id: fonts 9 | 10 | // readonly property FontLoader fontAwesomeRegular: FontLoader { 11 | // source: "./Font Awesome 5 Free-Regular-400.otf" 12 | // } 13 | readonly property FontLoader fontAwesomeSolid: FontLoader { 14 | source: "./fa-solid-900.ttf" 15 | } 16 | // readonly property FontLoader fontAwesomeBrands: FontLoader { 17 | // source: "./Font Awesome 5 Brands-Regular-400.otf" 18 | // } 19 | //导出字体名,供外部使用 20 | // readonly property string icons: fonts.fontAwesomeRegular.name 21 | readonly property string solid: fonts.fontAwesomeSolid.name 22 | // readonly property string brands: fonts.fontAwesomeBrands.name 23 | } 24 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/Font/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyQsmart/MaterialUI-QML/f423357a1293878bc481d2ad496211742e29cbd7/src_qml/common_component/MaterialUI/Font/fa-solid-900.ttf -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/Font/qmldir: -------------------------------------------------------------------------------- 1 | // qmldir 2 | singleton FontAwesomeFont 1.0 FontAwesomeFont.qml -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MAnimation.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | Item { 4 | id: control 5 | property bool open: false 6 | property int timeout: 242 7 | property var target: Item { } 8 | property Transition enter: null 9 | property Transition exit: null 10 | property State enterState: null 11 | property State exitState: null 12 | property real originX: 0 // 和x相关的动画,设置起始值 13 | property real originY: 0 // 和y相关的动画,设置起始值 14 | 15 | signal aboutToEnter() 16 | signal aboutToExit() 17 | 18 | onOpenChanged: { 19 | if (open) { 20 | aboutToEnter() 21 | control.state = "enter" 22 | } 23 | else { 24 | aboutToExit() 25 | control.state = "exit" 26 | } 27 | } 28 | 29 | Component.onCompleted: { 30 | if (enter) { 31 | enter.enabled = false 32 | } 33 | if (exit) { 34 | exit.enabled = false 35 | } 36 | 37 | if (open) { 38 | control.state = "enter" 39 | } 40 | else { 41 | control.state = "exit" 42 | } 43 | 44 | if (enter) { 45 | enter.enabled = true 46 | } 47 | if (exit) { 48 | exit.enabled = true 49 | } 50 | } 51 | 52 | states: [enterState, exitState] 53 | transitions: [enter, exit] 54 | } 55 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MButtonBase.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | import "./styles" 4 | import "./colors" 5 | 6 | // 原版 7 | Button { 8 | id: button 9 | property bool disabled: false 10 | // text: '' 11 | // property bool centerRipple: false 12 | property bool disableRipple: false 13 | property string textColor: '' 14 | property int fontSize: 14 // 新增字体大小 15 | property bool disableCursor: false // 新增鼠标属性 16 | 17 | enabled: !button.disabled 18 | 19 | contentItem: MTypography { 20 | variant: 'button' 21 | text: button.text 22 | align: 'center' 23 | // 字体不居中特殊处理 24 | lineHeight: 1 25 | font.pointSize: TypographyStyle.convertFontSize(button.fontSize) 26 | topPadding: (TypographyStyle.fontStyleList.button.line_height-1)*TypographyStyle.fontStyleList.button.size/2 27 | bottomPadding: (TypographyStyle.fontStyleList.button.line_height-1)*TypographyStyle.fontStyleList.button.size/2 28 | // 字体不居中特殊处理 29 | color: button.textColor 30 | } 31 | 32 | // ToolTip.contentItem: MTypography { 33 | // text: ToolTip.text 34 | // } 35 | 36 | ToolTip.toolTip.contentItem: MTypography { 37 | variant: 'caption' 38 | lineHeight: 1 39 | text: ToolTip.toolTip.text 40 | color: Colors.commonWhite 41 | } 42 | 43 | ToolTip.toolTip.background: Rectangle { 44 | color: Colors.alpha('#616161', 0.9) 45 | radius: 4 46 | } 47 | 48 | onPressedChanged: { 49 | if (!button.disabled) { 50 | if (button.pressed) { 51 | ripple.start(mouse_area.mouseX, mouse_area.mouseY) 52 | } 53 | else { 54 | ripple.stop() 55 | 56 | } 57 | } 58 | } 59 | 60 | MTouchRipple { 61 | id: ripple 62 | anchors.fill: parent 63 | currentColor: button.textColor && button.textColor != '' ? button.textColor : Colors.commonBlack 64 | } 65 | 66 | MouseArea { 67 | id: mouse_area 68 | cursorShape: disableCursor ? Qt.ArrowCursor : Qt.PointingHandCursor 69 | anchors.fill: parent 70 | 71 | onPressed: function(mouse) { 72 | mouse.accepted = false 73 | } 74 | 75 | onReleased: function(mouse) { 76 | mouse.accepted = false 77 | } 78 | 79 | onClicked: function(mouse) { 80 | mouse.accepted = false 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MButtonGroup.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Layouts 1.15 3 | import QtGraphicalEffects 1.15 4 | import "./styles" 5 | import "./colors" 6 | 7 | Rectangle { 8 | id: container 9 | default property alias children: childrenContainer.children 10 | property string orientation: 'horizontal' // 'horizontal' | 'vertical' 11 | property string size: 'medium' // 'large' | 'medium' | 'small' 12 | property string variant: 'outlined' // 'contained' | 'outlined' | 'text' 13 | property var disabled: null 14 | property var disableElevation: null 15 | property var disableRipple: null 16 | property string buttonColor: 'default' // 'default' | 'inherit' | 'primary' | 'secondary' 17 | 18 | width: childrenRect.width 19 | height: childrenRect.height 20 | radius: Palette.borderRadius 21 | border.width: variant == 'outlined' ? 1 : 0 22 | border.color: { 23 | let ans_color = Palette.string2Color(buttonColor, null) 24 | if (ans_color) { 25 | return Colors.alpha(ans_color, 0.5) 26 | } 27 | else { 28 | return Colors.alpha('#000000', 0.23) 29 | } 30 | } 31 | 32 | layer.enabled: variant === 'contained' && !disabled && !disableElevation 33 | layer.effect: MShadow { 34 | elevation: 2 35 | } 36 | 37 | Rectangle { 38 | width: childrenRect.width-2 39 | height: childrenRect.height-2 40 | color: "#00ffffff" 41 | layer.enabled: true 42 | layer.effect: OpacityMask { 43 | maskSource: Rectangle { 44 | width: container.width 45 | height: container.height 46 | radius: container.radius 47 | } 48 | } 49 | 50 | GridLayout { 51 | id: childrenContainer 52 | x: -1 53 | y: -1 54 | rowSpacing: 0 55 | columnSpacing: 0 56 | flow: orientation === 'vertical' ? GridLayout.TopToBottom : GridLayout.LeftToRight 57 | } 58 | 59 | Repeater { 60 | model: childrenContainer.children.length 61 | delegate: Item { 62 | Binding { 63 | target: childrenContainer.children[index] 64 | property: "variant" 65 | value: container.variant 66 | } 67 | Binding { 68 | target: childrenContainer.children[index] 69 | property: "size" 70 | value: container.size 71 | } 72 | Binding { 73 | target: childrenContainer.children[index] 74 | property: "background.radius" 75 | value: 0 76 | } 77 | Binding { 78 | target: childrenContainer.children[index] 79 | property: "disableElevation" 80 | value: true 81 | } 82 | Binding { 83 | when: disabled !== null 84 | target: childrenContainer.children[index] 85 | property: "disabled" 86 | value: disabled 87 | } 88 | Binding { 89 | when: disableRipple !== null 90 | target: childrenContainer.children[index] 91 | property: "disableRipple" 92 | value: disableRipple 93 | } 94 | Binding { 95 | target: childrenContainer.children[index] 96 | property: "color" 97 | value: buttonColor 98 | } 99 | Binding { 100 | target: childrenContainer.children[index] 101 | property: "background.border.width" 102 | value: index%2 ? 0 : 1 103 | } 104 | Binding { 105 | when: variant === 'contained' 106 | target: childrenContainer.children[index] 107 | property: "background.border.color" 108 | value: { 109 | if (childrenContainer.children[index].disabled) { 110 | return Palette.lightActionDisabled 111 | } 112 | else { 113 | if (buttonColor === 'primary') { 114 | return Palette.primaryDark 115 | } 116 | else if (buttonColor === 'secondary') { 117 | return Palette.secondaryDark 118 | } 119 | else { 120 | return Grey._400 121 | } 122 | } 123 | } 124 | } 125 | Binding { 126 | when: orientation === 'vertical' 127 | target: childrenContainer.children[index] 128 | property: "Layout.fillWidth" 129 | value: true 130 | } 131 | Binding { 132 | when: orientation !== 'vertical' 133 | target: childrenContainer.children[index] 134 | property: "Layout.fillHeight" 135 | value: true 136 | } 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MCheckbox.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | import QtGraphicalEffects 1.15 4 | import "./styles" 5 | import "./colors" 6 | 7 | CheckBox { 8 | id: checkbox 9 | property string color: 'secondary' // 'default' 'primary' 'secondary' color 10 | property bool disabled: false 11 | property bool disableRipple: false 12 | property string size: 'medium' // 'medium' 'small' 暂未实现 13 | property string value: "" 14 | 15 | 16 | checked: false 17 | checkable: !disabled 18 | implicitWidth: 42 19 | implicitHeight: 42 20 | width: 42 21 | height: 42 22 | topPadding: 9 23 | rightPadding: 9 24 | bottomPadding: 9 25 | leftPadding: 9 26 | 27 | Rectangle { 28 | visible: checkbox.hovered && !checkbox.disabled 29 | anchors.fill: parent 30 | radius: width/2 31 | color: { 32 | if (checkbox.checked) { 33 | return Colors.alpha(Palette.string2Color(checkbox.color, Grey._600), 0.04) 34 | } 35 | else { 36 | return Colors.alpha(Grey._600, 0.04) 37 | } 38 | } 39 | } 40 | 41 | indicator: Image { 42 | x: parent.width/2 - width/2 43 | y: parent.height/2 - height/2 44 | width: 24 45 | height: 24 46 | sourceSize.width: width*2 47 | sourceSize.height: height*2 48 | 49 | property string svgColor: { 50 | if (checkbox.disabled) { 51 | return Grey._400 52 | } 53 | 54 | if (checkbox.checked) { 55 | return Palette.string2Color(checkbox.color, Grey._600) 56 | } 57 | else { 58 | return Grey._600 59 | } 60 | } 61 | 62 | source: { 63 | let unchecked_src = `data:image/svg+xml;utf8,` 64 | let checked_src = `data:image/svg+xml;utf8,` 65 | 66 | return checkbox.checked ? checked_src : unchecked_src 67 | } 68 | } 69 | 70 | onPressedChanged: { 71 | if (!checkbox.disabled) { 72 | if (checkbox.pressed) { 73 | touch_ripple.start() 74 | } 75 | else { 76 | touch_ripple.stop() 77 | } 78 | } 79 | } 80 | 81 | Rectangle { 82 | id: ripple 83 | clip: true 84 | anchors.fill: parent 85 | radius: width/2 86 | color: Colors.commonTransparent 87 | 88 | layer.enabled: true 89 | layer.effect: OpacityMask { 90 | maskSource: Rectangle { 91 | width: ripple.width 92 | height: ripple.height 93 | radius: ripple.radius 94 | } 95 | } 96 | 97 | MTouchRipple { 98 | id: touch_ripple 99 | visible: !disableRipple && !checkbox.disabled 100 | width: checkbox.width 101 | height: checkbox.height 102 | center: true 103 | currentColor: { 104 | if (checkbox.checked) { 105 | return Palette.string2Color(checkbox.color, Grey._600) 106 | } 107 | else { 108 | return Grey._600 109 | } 110 | } 111 | } 112 | } 113 | 114 | MouseArea { 115 | id: mouse_area 116 | cursorShape: checkbox.disabled ? Qt.ArrowCursor : Qt.PointingHandCursor 117 | anchors.fill: parent 118 | enabled: false 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MCircularProgress.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./colors" 4 | 5 | Canvas { 6 | id: canvas 7 | property string color: 'primary' // 'inherit' 'primary' 'secondary' 8 | property string variant: 'indeterminate' // 'determinate' 'indeterminate' 'static' 9 | property bool disableShrink: false // 暂时未实现 10 | property int size: 40 11 | property real thickness: 3.6 12 | property real value: 0 // 0~100 13 | 14 | 15 | 16 | 17 | 18 | onValueChanged: { 19 | if (variant !== 'indeterminate') { 20 | canvas.requestPaint() 21 | } 22 | } 23 | 24 | width: canvas.size 25 | height: canvas.size 26 | 27 | property real animationangle: 0 28 | property int animation_duration: 1400 // 1400 29 | 30 | onAnimationangleChanged: { 31 | canvas.requestPaint() 32 | } 33 | 34 | onPaint: { 35 | var ctx = getContext("2d") 36 | ctx.reset() 37 | ctx.clearRect(0, 0, canvas.width, canvas.height) 38 | ctx.strokeStyle = canvas.color == 'secondary' ? Palette.secondaryMain : Palette.primaryMain 39 | ctx.lineWidth = canvas.thickness 40 | var start_angle = 0 41 | var end_angle = value*Math.PI*2/100 42 | if (variant == 'indeterminate') { 43 | if (canvas.animationangle < Math.PI) { 44 | start_angle = canvas.animationangle 45 | end_angle = start_angle + Math.PI*2 * (canvas.animationangle/Math.PI) 46 | } 47 | else { 48 | end_angle = canvas.animationangle 49 | start_angle = end_angle-Math.PI*2 * ((Math.PI*2-canvas.animationangle)/Math.PI) 50 | } 51 | } 52 | ctx.arc(canvas.size/2, canvas.size/2, (canvas.size-canvas.thickness)/2, start_angle-Math.PI/2, end_angle-Math.PI/2) 53 | ctx.stroke() 54 | } 55 | 56 | ParallelAnimation { 57 | running: canvas.variant == 'indeterminate' 58 | loops: Animation.Infinite 59 | 60 | NumberAnimation { 61 | target: canvas 62 | properties: 'animationangle' 63 | from: 0 64 | to: Math.PI*2 65 | duration: canvas.animation_duration 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MCollapse.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./colors" 4 | 5 | MAnimation { 6 | id: control 7 | timeout: 300 8 | property int collapsedSize: 0 9 | 10 | enter: Transition { 11 | to: "enter" 12 | NumberAnimation { 13 | duration: timeout*0.666 14 | property: "height" 15 | easing.type: Easing.InOutQuad 16 | from: collapsedSize 17 | } 18 | PropertyAnimation { 19 | duration: 0 20 | property: "clip" 21 | to: true 22 | } 23 | } 24 | enterState: State { 25 | name: "enter" 26 | PropertyChanges { 27 | target: control.target 28 | restoreEntryValues: true 29 | clip: true 30 | } 31 | } 32 | 33 | exit: Transition { 34 | to: "exit" 35 | NumberAnimation { 36 | duration: timeout*0.666 37 | property: "height" 38 | easing.type: Easing.InOutQuad 39 | to: collapsedSize 40 | } 41 | PropertyAnimation { 42 | duration: 0 43 | property: "clip" 44 | to: true 45 | } 46 | } 47 | exitState: State { 48 | name: "exit" 49 | PropertyChanges { 50 | target: control.target 51 | restoreEntryValues: true 52 | height: collapsedSize 53 | clip: true 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MComplexSelect.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./colors" 4 | 5 | MSelectBase { 6 | id: control 7 | default property alias children: menu_dialog.children 8 | property string label: "" 9 | 10 | property var registerClickList: [] 11 | 12 | function beforeOpenSelect() { 13 | let newRegisterClickList = [] 14 | for (let i = 0; i < children.length; i++) { 15 | let the_child = children[i] 16 | if (the_child.clicked && registerClickList.indexOf(the_child) === -1) { 17 | the_child.clicked.connect(function(){ 18 | if (the_child.value) { 19 | control.value = the_child.value 20 | control.label = the_child.label ? the_child.label : "" 21 | control.index = i 22 | change(the_child.value, i) 23 | menu_dialog.close() 24 | } 25 | }) 26 | } 27 | newRegisterClickList.push(the_child) 28 | } 29 | registerClickList = newRegisterClickList 30 | } 31 | 32 | displayItem: MTypography { 33 | id: text_item 34 | variant: "body1" 35 | text: label ? label : value 36 | noWrap: true 37 | lineHeight: TypographyStyle.convertLineHeight(1.1876) 38 | } 39 | 40 | Binding { 41 | target: text_item 42 | property: 'color' 43 | when: disabled 44 | value: Palette.lightTextDisabled 45 | } 46 | 47 | onSelectOpen: { 48 | menu_dialog.open() 49 | } 50 | 51 | MMenu { 52 | id: menu_dialog 53 | anchorEl: control 54 | anchorOrigin: Item.Bottom 55 | transformOrigin: Item.Top 56 | 57 | onAboutToShow: { 58 | control.menuOpened = true 59 | beforeOpenSelect() 60 | } 61 | 62 | onClosed: { 63 | control.menuOpened = false 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MDateSelector.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 1.4 3 | import QtQuick.Controls.Styles 1.4 4 | import QtQuick.Layouts 1.15 5 | import QtGraphicalEffects 1.15 6 | import "./styles" 7 | import "./colors" 8 | 9 | Calendar { 10 | id: root 11 | frameVisible: false 12 | 13 | style: CalendarStyle { 14 | gridVisible: false 15 | 16 | background: Rectangle { 17 | implicitWidth: 310 18 | implicitHeight: 305 19 | color: '#00ffffff' 20 | 21 | Rectangle { 22 | anchors.top: parent.top 23 | anchors.horizontalCenter: parent.horizontalCenter 24 | width: parent.width+20 25 | height: parent.height+10 26 | radius: Palette.borderRadius 27 | color: Colors.commonWhite 28 | 29 | layer.enabled: true 30 | layer.effect: MShadow { 31 | elevation: 1 32 | } 33 | } 34 | } 35 | 36 | navigationBar: RowLayout { 37 | width: parent.width 38 | spacing: 10 39 | 40 | MIconButton { 41 | id: left_year_button 42 | Layout.topMargin: 5 43 | 44 | Item { 45 | width: 20 46 | height: 20 47 | 48 | MIcon { 49 | anchors.centerIn: parent 50 | name: "angle-left" 51 | size: 20 52 | color: left_year_button.iconColor 53 | } 54 | } 55 | 56 | onClicked: { 57 | root.showPreviousMonth() 58 | } 59 | } 60 | 61 | MTypography{ 62 | Layout.fillWidth: true 63 | align: "center" 64 | text: styleData.title 65 | } 66 | 67 | MIconButton { 68 | id: right_year_button 69 | 70 | Item { 71 | width: 20 72 | height: 20 73 | 74 | MIcon { 75 | anchors.centerIn: parent 76 | name: "angle-right" 77 | size: 20 78 | color: right_year_button.iconColor 79 | } 80 | } 81 | 82 | onClicked: { 83 | root.showNextMonth() 84 | } 85 | } 86 | } 87 | 88 | dayOfWeekDelegate: MTypography { 89 | align: 'center' 90 | variant: "caption" 91 | textColor: "textSecondary" 92 | gutterBottom: true 93 | text: { 94 | switch (styleData.dayOfWeek) { 95 | case Locale.Sunday: return "周日" 96 | case Locale.Monday: return "周一" 97 | case Locale.Tuesday: return "周二" 98 | case Locale.Wednesday: return "周三" 99 | case Locale.Thursday: return "周四" 100 | case Locale.Friday: return "周五" 101 | case Locale.Saturday: return "周六" 102 | } 103 | } 104 | } 105 | 106 | dayDelegate: Item { 107 | Rectangle { 108 | id: day_item 109 | 110 | anchors.centerIn: parent 111 | width: 36 112 | height: 36 113 | radius: width/2 114 | color: styleData.selected ? Palette.primaryMain : (styleData.hovered ? Colors.alpha("#000000", 0.04) : "#00ffffff") 115 | 116 | MTypography { 117 | anchors.centerIn: parent 118 | textColor: styleData.selected ? "#ffffff" : (!styleData.valid || !styleData.visibleMonth ? "textSecondary" : "textPrimary") 119 | 120 | text: styleData.date.getDate() 121 | } 122 | 123 | MouseArea { 124 | anchors.fill: parent 125 | cursorShape: !styleData.valid ? Qt.ArrowCursor : Qt.PointingHandCursor 126 | enabled: false 127 | } 128 | 129 | layer.enabled: true 130 | layer.effect: OpacityMask { 131 | maskSource: Rectangle { 132 | width: day_item.width 133 | height: day_item.height 134 | radius: day_item.radius 135 | } 136 | } 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | import "./styles" 4 | import "./colors" 5 | 6 | Popup { 7 | id: dialog 8 | property bool fullScreen: false 9 | property bool fullWidth: false 10 | property bool disableBackdropClick: false 11 | property bool backdropInvisible: false // new 12 | property string maxWidth: 'sm' //'lg' 'md' 'sm' 'xl' 'xs' false 13 | property MAnimation transitionComponent: MFade { } 14 | parent: Overlay.overlay 15 | // anchors.centerIn: parent // 为了使用通用动画,故不使用该属性进行居中 16 | 17 | Binding { 18 | target: transitionComponent 19 | property: "originX" 20 | value: ((parent ? parent.width : 0) - dialog.width)/2 21 | } 22 | 23 | Binding { 24 | target: transitionComponent 25 | property: "originY" 26 | value: ((parent ? parent.height : 0) - dialog.height)/2 27 | } 28 | 29 | x: ((parent ? parent.width : 0) - dialog.width)/2 30 | y: ((parent ? parent.height : 0) - dialog.height)/2 31 | 32 | 33 | padding: 0 34 | visible: false 35 | modal: true 36 | focus: true 37 | closePolicy: disableBackdropClick ? Popup.CloseOnEscape : (Popup.CloseOnEscape | Popup.CloseOnPressOutside) 38 | 39 | Overlay.modal: Rectangle { 40 | color: backdropInvisible ? "#00ffffff" : "#80000000" 41 | } 42 | 43 | background: MPaper { 44 | elevation: 24 45 | } 46 | 47 | enter: transitionComponent ? transitionComponent.enter : null 48 | exit: transitionComponent ? transitionComponent.exit : null 49 | } 50 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MDirectoryButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Dialogs 1.3 3 | 4 | MButton { 5 | id: button 6 | property string title: qsTr('请选择路径') // 窗口标题 7 | signal change(string url) 8 | 9 | onClicked: { 10 | file_dialog.open() 11 | } 12 | 13 | FileDialog { 14 | id: file_dialog 15 | title: button.title 16 | selectFolder: true 17 | onAccepted: { 18 | let path_text = folder.toString() 19 | if (path_text.indexOf('file:///') === 0) { 20 | console.log(Qt.platform.os) 21 | if (Qt.platform.os === 'windows' || Qt.platform.os==="winrt") { 22 | path_text = path_text.substring(8, path_text.length) 23 | } 24 | else if (Qt.platform.os === 'osx') { 25 | path_text = path_text.substring(7, path_text.length) 26 | } 27 | } 28 | 29 | change(path_text) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MDivider.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | 4 | // 需要优化 5 | 6 | Rectangle { 7 | property bool light: false 8 | 9 | height: 1 10 | color: light ? Palette.lightTextDivider : Palette.lightTextDivider 11 | } 12 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MFade.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./colors" 4 | 5 | MAnimation { 6 | id: control 7 | timeout: 225 8 | 9 | enter: Transition { 10 | to: "enter" 11 | NumberAnimation { 12 | duration: timeout 13 | property: "opacity" 14 | easing.type: Easing.InOutQuad 15 | from: 0.0 16 | to: 1.0 17 | } 18 | } 19 | enterState: State { 20 | name: "enter" 21 | PropertyChanges { 22 | target: control.target 23 | opacity: 1 24 | } 25 | } 26 | 27 | exit: Transition { 28 | to: "exit" 29 | NumberAnimation { 30 | duration: timeout 31 | property: "opacity" 32 | easing.type: Easing.InOutQuad 33 | from: 1.0 34 | to: 0.0 35 | } 36 | } 37 | exitState: State { 38 | name: "exit" 39 | PropertyChanges { 40 | target: control.target 41 | opacity: 0 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MFileButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.13 2 | import QtQuick.Dialogs 1.3 3 | 4 | MButton { 5 | id: button 6 | property string title: qsTr('请选择文件') // 窗口标题 7 | property bool saveMode: false 8 | property bool multiple: false 9 | property string accept: '' 10 | property string acceptName: "" 11 | property string acceptExt: "" 12 | property bool acceptAll: true 13 | 14 | signal change(var fileUrls) 15 | 16 | onClicked: { 17 | file_dialog.open() 18 | } 19 | 20 | FileDialog { 21 | id: file_dialog 22 | title: button.title 23 | selectExisting: !button.saveMode 24 | selectMultiple: multiple 25 | nameFilters: { 26 | let ans = [] 27 | switch (button.accept) { 28 | case "srt": 29 | ans.push("字幕文件 (*.srt)") 30 | break 31 | case "image": 32 | ans.push("图片文件 (*.jpg *.jp2 *.jpeg *.png *.gif *.tiff)") 33 | break 34 | case "audio": 35 | ans.push("音频文件 (*.mp3 *.3gpp *.ac3 *.au *.mp2 *.mp4)") 36 | break 37 | case "video": 38 | ans.push("视频文件 (*.mp4 *.3gpp *.mpeg *.mpg *.rmvb *.mkv)") 39 | break 40 | } 41 | if ((acceptName && acceptName !== "") || (acceptExt && acceptExt !== "")) { 42 | ans.push(`${acceptName} (${acceptExt})`) 43 | } 44 | if (acceptAll) { 45 | ans.push("所有文件 (*)") 46 | } 47 | return ans 48 | } 49 | onAccepted: { 50 | let ans = [] 51 | for (let i = 0; i < fileUrls.length; i++) { 52 | let path_text = fileUrls[i] 53 | if (path_text.indexOf('file:///') === 0) { 54 | console.log(Qt.platform.os) 55 | if (Qt.platform.os === 'windows' || Qt.platform.os==="winrt") { 56 | path_text = path_text.substring(8, path_text.length) 57 | } 58 | else if (Qt.platform.os === 'osx') { 59 | path_text = path_text.substring(7, path_text.length) 60 | } 61 | ans.push(path_text) 62 | } 63 | } 64 | change(ans) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MFileMenuItem.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | 4 | MFileButton { 5 | id: list_item 6 | property bool dense: false 7 | property bool disableGutters: false 8 | property bool divider: false 9 | property bool selected: false 10 | 11 | property var m_padding: { 12 | let ans = [6, Palette.unit*2, 6, Palette.unit*2] 13 | 14 | if (dense) { 15 | ans[0] = ans[2] = 4 16 | } 17 | if (disableGutters) { 18 | ans[1] = ans[3] = 0 19 | } 20 | return ans 21 | } 22 | topPadding: m_padding[0] 23 | rightPadding: m_padding[1] 24 | bottomPadding: m_padding[2] 25 | leftPadding: m_padding[3] 26 | 27 | contentItem: MTypography { 28 | variant: 'body1' 29 | text: list_item.text 30 | color: list_item.textColor 31 | } 32 | 33 | background: Rectangle { 34 | color: { 35 | if (list_item.selected) { 36 | return Palette.lightActionSelected 37 | } 38 | 39 | if (list_item.hovered) { 40 | return Palette.lightActionHover 41 | } 42 | 43 | return Colors.commonTransparent 44 | } 45 | 46 | Rectangle { 47 | visible: divider 48 | anchors.bottom: parent.bottom 49 | anchors.left: parent.left 50 | anchors.right: parent.right 51 | height: 1 52 | color: Palette.lightTextDivider 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MFilledInput.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./StyleComponent" 3 | import "./styles" 4 | 5 | MInputBase { 6 | id: textInput 7 | color: 'primary' 8 | size: 'medium' // 'medium' | 'small' 9 | disabled: false 10 | _padding: styles.padding 11 | 12 | MFilledInputStyle { 13 | id: styles 14 | size: textInput.size 15 | disabled: textInput.disabled 16 | active: textInput.activeFocus 17 | color: textInput.color 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MFramelessWindow.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Window 2.15 3 | import QtQuick.Controls 2.15 4 | import QtGraphicalEffects 1.15 5 | import QtQuick.Shapes 1.15 6 | import "./StyleComponent" 7 | 8 | Window { 9 | id: root 10 | property bool enableBorderShadow: true 11 | property bool darkMode: false // system_palette.window.hslLightness < 0.5 12 | property string backgroundColor: "#ffffff" 13 | property alias dragBar: drag_bar 14 | property alias winSystemButtonBar: win_system_button_bar 15 | property alias macSystemButtonBar: mac_system_button_bar 16 | // 除了mac,其他都按照win的方式渲染 // Qt.platform.os === 'windows' || Qt.platform.os==="winrt" 17 | property string systemType: Qt.platform.os === 'osx' ? "mac" : "win" 18 | property bool disableMinimizeButton: false 19 | property bool disableMaximizeButton: false 20 | property bool disableCloseButton: false 21 | property int windowFlags: 0 22 | 23 | // property int safeAreaOrigin: Item.TopLeft // Item.TopLeft | Item.TopRight 24 | // property Item safeAreaRect: Item { 25 | // x: 0 26 | // y: 0 27 | // width: 0 28 | // height: 0 29 | // } 30 | 31 | 32 | 33 | 34 | default property alias data: bg_container.data 35 | property int winFlags: windowFlags | Qt.Window | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.FramelessWindowHint | (enableBorderShadow ? 0 : Qt.NoDropShadowWindowHint) 36 | property int macFlags: windowFlags | Qt.WindowMinimizeButtonHint | Qt.FramelessWindowHint | (enableBorderShadow ? 0 : Qt.NoDropShadowWindowHint) 37 | flags: Qt.platform.os === 'osx' ? macFlags : winFlags 38 | color: "transparent" 39 | // title: "窗口" 40 | 41 | // SystemPalette { 42 | // id: system_palette 43 | // } 44 | 45 | property int lastVisibility: -1 46 | 47 | onVisibilityChanged: { 48 | if (Qt.platform.os === 'osx') { 49 | // mac全屏后,退出全屏背景色有问题,重置窗口背景色 50 | if (root.lastVisibility === Window.FullScreen && root.visibility !== Window.FullScreen) { 51 | root.flags = 0 52 | root.flags = macFlags 53 | } 54 | 55 | // mac最小化需要flags取消无边框,退出最小化后,重置flags 56 | if (root.lastVisibility === Window.Minimized && root.visibility !== Window.Minimized) { 57 | root.flags = macFlags 58 | } 59 | 60 | lastVisibility = root.visibility 61 | } 62 | } 63 | 64 | MPaper { 65 | id: bg_container 66 | anchors.fill: parent 67 | radius: systemType == "mac" ? (root.visibility !== Window.FullScreen ? 10 : 0) : (root.visibility !== Window.Maximized ? 6 : 0) 68 | elevation: 0 69 | 70 | layer.enabled: true 71 | layer.effect: OpacityMask { 72 | maskSource: Rectangle { 73 | width: bg_container.width 74 | height: bg_container.height 75 | radius: bg_container.radius 76 | } 77 | } 78 | 79 | color: root.backgroundColor 80 | 81 | // 窗口拖动区域 82 | MouseArea { 83 | id: drag_bar 84 | anchors.top: parent.top 85 | anchors.left: parent.left 86 | anchors.right: parent.right 87 | height: systemType == "mac" ? 28 : 28 88 | 89 | onPressed: { 90 | startSystemMove() 91 | } 92 | } 93 | 94 | // win下的系统按钮 95 | MFramelessWindowButtonsWin { 96 | id: win_system_button_bar 97 | visible: systemType !== "mac" 98 | disableMinimizeButton: root.disableMinimizeButton 99 | disableMaximizeButton: root.disableMaximizeButton 100 | disableCloseButton: root.disableCloseButton 101 | darkMode: root.darkMode 102 | target: root 103 | z: 900 104 | } 105 | 106 | // mac下的系统按钮 107 | MFramelessWindowButtonsMac { 108 | id: mac_system_button_bar 109 | visible: systemType === "mac" && root.visibility !== Window.FullScreen 110 | disableMinimizeButton: root.disableMinimizeButton 111 | disableMaximizeButton: root.disableMaximizeButton 112 | disableCloseButton: root.disableCloseButton 113 | darkMode: root.darkMode 114 | target: root 115 | z: 900 116 | } 117 | 118 | // 窗口调整大小区域 119 | MWindowResizeHandler { 120 | anchors.fill: parent 121 | target: root 122 | z: 1000 123 | } 124 | } 125 | } 126 | 127 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MGrow.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./colors" 4 | 5 | MAnimation { 6 | id: control 7 | timeout: 242 8 | property int transformOrigin: Item.Center // Item.Center Item.BottomRight Item.TopLeft ... 9 | 10 | enter: Transition { 11 | to: "enter" 12 | NumberAnimation { 13 | duration: timeout 14 | property: "opacity" 15 | easing.type: Easing.InOutQuad 16 | from: 0.0 17 | to: 1.0 18 | } 19 | NumberAnimation { 20 | duration: timeout*0.666 21 | property: "scale" 22 | easing.type: Easing.InOutQuad 23 | from: 0 24 | to: 1 25 | } 26 | PropertyAnimation { 27 | duration: 0 28 | property: "transformOrigin" 29 | to: transformOrigin 30 | } 31 | } 32 | enterState: State { 33 | name: "enter" 34 | PropertyChanges { 35 | target: control.target 36 | opacity: 1 37 | scale: 1 38 | transformOrigin: transformOrigin 39 | } 40 | } 41 | 42 | exit: Transition { 43 | to: "exit" 44 | NumberAnimation { 45 | duration: timeout 46 | property: "opacity" 47 | easing.type: Easing.InOutQuad 48 | from: 1.0 49 | to: 0.0 50 | } 51 | NumberAnimation { 52 | duration: timeout*0.666 53 | property: "scale" 54 | easing.type: Easing.InOutQuad 55 | from: 1 56 | to: 0 57 | } 58 | PropertyAnimation { 59 | duration: 0 60 | property: "transformOrigin" 61 | to: transformOrigin 62 | } 63 | } 64 | exitState: State { 65 | name: "exit" 66 | PropertyChanges { 67 | target: control.target 68 | opacity: 0 69 | scale: 0 70 | transformOrigin: transformOrigin 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MIcon.qml: -------------------------------------------------------------------------------- 1 | // FontAwesomeToolButton.qml 2 | 3 | import QtQuick 2.15 4 | import "./styles" 5 | import "./Font" 6 | import "./Font/IconsName.js" as IconsName 7 | 8 | Text { 9 | id: button 10 | property string name 11 | // property alias color: text.color 12 | property real size: 14 13 | // 有Bold和Light两种设置 14 | font.weight: Font.Bold 15 | // font.family在Regular、Solid、Brands三种模式下选择,其中Regular、Solid是一样的 16 | font.family: FontAwesomeFont.solid 17 | text: IconsName.name[name] ? IconsName.name[name] : "" 18 | 19 | font.pointSize: { 20 | return TypographyStyle.convertFontSize(size) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MIconButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Layouts 1.15 3 | import QtGraphicalEffects 1.15 4 | import "./styles" 5 | import "./colors" 6 | 7 | MButtonBase { 8 | id: root 9 | default property alias children: childContainer.children 10 | property string size: 'medium' // 'small' 'medium' 11 | property string color: 'default' // 'default' 'primary' 'secondary' color 12 | property string iconColor: disabled ? Palette.lightActionDisabled : Palette.string2Color(color, Palette.lightActionActive) 13 | padding: size === "small" ? 3 : 12 14 | topPadding: padding 15 | bottomPadding: padding 16 | leftPadding: padding 17 | rightPadding: padding 18 | 19 | background: Rectangle { 20 | id: button_bg 21 | width: childContainer.width+root.leftPadding+root.rightPadding 22 | height: childContainer.height+root.topPadding+root.bottomPadding 23 | color: hovered ? Colors.alpha("#000000", 0.04) : "#00ffffff" 24 | radius: Math.max(width, height)/2 25 | } 26 | 27 | contentItem: RowLayout { 28 | id: childContainer 29 | width: childrenRect.width 30 | height: childrenRect.height 31 | } 32 | 33 | layer.enabled: true 34 | layer.effect: OpacityMask { 35 | maskSource: Rectangle { 36 | width: button_bg.width 37 | height: button_bg.height 38 | radius: button_bg.radius 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MInput.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./StyleComponent" 3 | import "./styles" 4 | 5 | MInputBase { 6 | id: textInput 7 | color: 'primary' 8 | size: 'medium' // 'medium' | 'small' 9 | disabled: false 10 | _padding: styles.padding 11 | 12 | MInputStyle { 13 | id: styles 14 | size: textInput.size 15 | disabled: textInput.disabled 16 | active: textInput.activeFocus 17 | color: textInput.color 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MInputBase.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | 4 | TextInput { 5 | id: textInput 6 | property string color: 'primary' 7 | property string placeholder: '' 8 | property string size: 'medium' // 'medium' | 'small' 9 | property bool disabled: false 10 | property bool hover: false 11 | 12 | 13 | 14 | property string _main_color: Palette.string2Color(textInput.color, Palette.primaryMain) 15 | property var _padding: [6, 0, 7, 0] 16 | enabled: !disabled 17 | verticalAlignment: Text.AlignVCenter 18 | clip: true 19 | selectByMouse: true 20 | selectionColor: textInput._main_color 21 | topPadding: _padding[0] 22 | rightPadding: _padding[1] 23 | bottomPadding: _padding[2] 24 | leftPadding: _padding[3] 25 | 26 | font.pointSize: TypographyStyle.fontStyleList.body1.size 27 | 28 | // placeholder 29 | MTypography { 30 | visible: textInput.text || textInput.inputMethodComposing ? false : true 31 | anchors.fill: parent 32 | noWrap: true 33 | verticalAlignment: Text.AlignVCenter 34 | leftPadding: textInput.leftPadding 35 | rightPadding: textInput.rightPadding 36 | text: placeholder 37 | color: textInput.disabled ? Palette.lightTextDisabled : Palette.lightTextSecondary 38 | font.pointSize: TypographyStyle.fontStyleList.body1.size 39 | lineHeight: 1 40 | } 41 | 42 | MouseArea { 43 | anchors.fill: parent 44 | cursorShape: Qt.IBeamCursor 45 | acceptedButtons: Qt.NoButton 46 | hoverEnabled: true 47 | 48 | onEntered: { 49 | textInput.hover = true 50 | } 51 | 52 | onExited: { 53 | textInput.hover = false 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MLinearProgress.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | import QtQuick.Shapes 1.15 4 | import "./styles" 5 | import "./colors" 6 | 7 | Item { 8 | id: root 9 | property string variant: 'indeterminate' // 'determinate' 'indeterminate' 'query' 'buffer' 10 | property string color: 'primary' // 'primary' 'secondary' 11 | property real value: 0 // 区间0~100 12 | property real valueBuffer: 100 // 区间0~100 13 | 14 | 15 | width: 120 16 | height: 4 17 | implicitWidth: width 18 | implicitHeight: height 19 | 20 | ProgressBar { 21 | id: control 22 | value: root.value/100 // 区间0~1 23 | property real valueBuffer: root.valueBuffer/100 24 | 25 | 26 | 27 | 28 | 29 | width: root.width 30 | height: root.height 31 | 32 | background: Item { 33 | id: bg 34 | width: control.width 35 | height: control.height 36 | 37 | Rectangle { 38 | width: root.variant == 'buffer' ? parent.width*control.valueBuffer : parent.width 39 | height: parent.height 40 | color: Colors.alpha(root.color == 'secondary' ? Palette.secondaryMain : Palette.primaryMain, 0.38) 41 | } 42 | 43 | Shape { 44 | id: buffer_line 45 | visible: root.variant == 'buffer' && control.valueBuffer < 1 46 | height: parent.height 47 | width: parent.width*(1-control.valueBuffer) 48 | x: parent.width*control.valueBuffer 49 | 50 | ShapePath { 51 | strokeWidth: buffer_line.height 52 | strokeColor: Colors.alpha(root.color == 'secondary' ? Palette.secondaryMain : Palette.primaryMain, 0.18) 53 | strokeStyle: ShapePath.DashLine 54 | dashPattern: [1, 3] 55 | 56 | startX: strokeWidth/2 57 | startY: buffer_line.height/2 58 | 59 | PathLine { 60 | x: buffer_line.width-buffer_line.height/2 61 | y: buffer_line.height/2 62 | } 63 | } 64 | } 65 | } 66 | 67 | contentItem: Item { 68 | width: control.width 69 | height: control.height 70 | 71 | Rectangle { 72 | id: progress 73 | property real animation_x: 0 74 | x: { 75 | if (root.variant === 'indeterminate') { 76 | if (animation_x < 0) { 77 | return 0 78 | } 79 | else { 80 | return animation_x 81 | } 82 | } 83 | else { 84 | return 0 85 | } 86 | } 87 | width: { 88 | if (root.variant === 'indeterminate') { 89 | if (animation_x < 0) { 90 | return parent.width/2+animation_x 91 | } 92 | else if (animation_x < parent.width/2) { 93 | return parent.width/2 94 | } 95 | else { 96 | return parent.width-animation_x 97 | } 98 | } 99 | else { 100 | return control.visualPosition * parent.width 101 | } 102 | } 103 | height: parent.height 104 | color: root.color == 'secondary' ? Palette.secondaryMain : Palette.primaryMain 105 | 106 | NumberAnimation { 107 | target: progress 108 | properties: 'animation_x' 109 | from: -bg.width/2 110 | to: bg.width/2+bg.width 111 | duration: 2100/3 112 | running: variant == 'indeterminate' 113 | loops: Animation.Infinite 114 | } 115 | } 116 | } 117 | } 118 | } 119 | 120 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MList.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Layouts 1.15 3 | import "./styles" 4 | 5 | Item { 6 | id: root 7 | property bool disablePadding: false 8 | property bool dense: false 9 | // property var subheader: null 10 | default property alias children: column_layout.children 11 | property int topPadding: { 12 | if (disablePadding) { 13 | return 0 14 | } 15 | let ans = Palette.unit 16 | if (dense) { 17 | ans = Palette.unit 18 | } 19 | return ans 20 | } 21 | property int bottomPadding: root.topPadding 22 | 23 | width: column_layout.width 24 | implicitWidth: width 25 | height: column_layout.height+topPadding+bottomPadding 26 | implicitHeight: height 27 | 28 | ColumnLayout { 29 | id: column_layout 30 | y: topPadding 31 | spacing: 0 32 | 33 | onChildrenChanged: { 34 | for (let i = 0; i < children.length; i++) { 35 | let the_child = children[i] 36 | the_child.Layout.fillWidth = true 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MListItem.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | 4 | // 原版 5 | MButton { 6 | id: list_item 7 | // button模式下,传给button 8 | // property string color: Palette.lightTextPrimary 9 | 10 | property string alignItems: 'center' // 'flex-start' 'center' 11 | property bool dense: false 12 | // disabled: false 13 | property bool disableGutters: false 14 | property bool divider: false 15 | property bool selected: false 16 | property bool button: false 17 | disableCursor: !button 18 | disableRipple: !button 19 | 20 | property var m_padding: { 21 | let ans = [Palette.unit, 0, Palette.unit, 0] 22 | 23 | if (dense) { 24 | ans = [Palette.unit/2, 0, Palette.unit/2, 0] 25 | } 26 | if (!disableGutters) { 27 | ans[1] = ans[3] = Palette.unit*2 28 | } 29 | return ans 30 | } 31 | topPadding: m_padding[0] 32 | rightPadding: m_padding[1] 33 | bottomPadding: m_padding[2] 34 | leftPadding: m_padding[3] 35 | 36 | background: Rectangle { 37 | color: { 38 | if (list_item.selected) { 39 | return Palette.lightActionSelected 40 | } 41 | 42 | if (button && list_item.hovered) { 43 | return Colors.alpha('#000000', 0.04) 44 | } 45 | 46 | return '#00000000' 47 | } 48 | 49 | Rectangle { 50 | visible: divider 51 | anchors.bottom: parent.bottom 52 | anchors.left: parent.left 53 | anchors.right: parent.right 54 | height: 1 55 | color: Palette.lightTextDivider 56 | } 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MMenu.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | 4 | MPopover { 5 | default property alias children: menu_list.children 6 | 7 | MMenuList { 8 | id: menu_list 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MMenuItem.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | 4 | MButton { 5 | id: list_item 6 | property bool dense: false 7 | property bool disableGutters: false 8 | property bool divider: false 9 | property bool selected: false 10 | 11 | property var m_padding: { 12 | let ans = [6, Palette.unit*2, 6, Palette.unit*2] 13 | 14 | if (dense) { 15 | ans[0] = ans[2] = 4 16 | } 17 | if (disableGutters) { 18 | ans[1] = ans[3] = 0 19 | } 20 | return ans 21 | } 22 | topPadding: m_padding[0] 23 | rightPadding: m_padding[1] 24 | bottomPadding: m_padding[2] 25 | leftPadding: m_padding[3] 26 | 27 | contentItem: MTypography { 28 | variant: 'body1' 29 | text: list_item.text 30 | color: list_item.textColor 31 | } 32 | 33 | background: Rectangle { 34 | color: { 35 | if (list_item.selected) { 36 | return Palette.lightActionSelected 37 | } 38 | 39 | if (list_item.hovered) { 40 | return Palette.lightActionHover 41 | } 42 | 43 | return Colors.commonTransparent 44 | } 45 | 46 | Rectangle { 47 | visible: divider 48 | anchors.bottom: parent.bottom 49 | anchors.left: parent.left 50 | anchors.right: parent.right 51 | height: 1 52 | color: Palette.lightTextDivider 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MMenuList.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | 4 | // 网页版原版 5 | MList { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MOutlinedInput.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./StyleComponent" 3 | import "./styles" 4 | 5 | MInputBase { 6 | id: textInput 7 | color: 'primary' 8 | size: 'medium' // 'medium' | 'small' 9 | disabled: false 10 | _padding: styles.padding 11 | 12 | MOutlinedInputStyle { 13 | id: styles 14 | size: textInput.size 15 | disabled: textInput.disabled 16 | active: textInput.activeFocus 17 | color: textInput.color 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MOverflowYBox.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | import "./styles" 4 | 5 | ScrollView { 6 | clip: true 7 | ScrollBar.horizontal.policy: ScrollBar.AlwaysOff 8 | // contentWidth: availableWidth 9 | } 10 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MPaper.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./colors" 4 | 5 | Rectangle { 6 | id: paper 7 | property int elevation: 1 // 0~24 8 | property bool square: false 9 | property string variant: 'elevation' // 'elevation' 'outlined' 10 | 11 | 12 | 13 | radius: paper.square ? 0 : Palette.borderRadius 14 | color: Colors.commonWhite 15 | 16 | border.width: paper.variant === 'outlined' ? 1 : 0 17 | border.color: Colors.alpha('#000000', 0.12) 18 | 19 | layer.enabled: paper.variant === 'elevation' && paper.elevation > 0 20 | layer.effect: MShadow { 21 | elevation: paper.elevation 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MRadio.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | import QtGraphicalEffects 1.15 4 | import "./styles" 5 | import "./colors" 6 | 7 | RadioButton { 8 | id: checkbox 9 | property string color: 'secondary' // 'default' 'primary' 'secondary' 10 | property bool disabled: false 11 | property bool disableRipple: false 12 | property string size: 'medium' // 'medium' 'small' 暂未实现 13 | property string value: "" 14 | 15 | 16 | checkable: !disabled 17 | checked: false 18 | implicitWidth: 42 19 | implicitHeight: 42 20 | width: 42 21 | height: 42 22 | topPadding: 9 23 | rightPadding: 9 24 | bottomPadding: 9 25 | leftPadding: 9 26 | 27 | Rectangle { 28 | visible: checkbox.hovered && !checkbox.disabled 29 | anchors.fill: parent 30 | radius: width/2 31 | color: { 32 | if (checkbox.checked) { 33 | return Colors.alpha(Palette.string2Color(checkbox.color, Grey._600), 0.04) 34 | } 35 | else { 36 | return Colors.alpha(Grey._600, 0.04) 37 | } 38 | } 39 | } 40 | 41 | background: Rectangle { 42 | id: bg 43 | x: parent.width/2 - width/2 44 | y: parent.height/2 - height/2 45 | width: 24 46 | height: 24 47 | } 48 | 49 | indicator: Rectangle { 50 | id: ind 51 | width: 18 52 | height: 18 53 | x: bg.x+3 54 | y: bg.y+3 55 | border.width: 2 56 | border.color: { 57 | if (checkbox.disabled) { 58 | return Grey._400 59 | } 60 | 61 | if (checkbox.checked) { 62 | return Palette.string2Color(checkbox.color, Grey._600) 63 | } 64 | else { 65 | return Grey._600 66 | } 67 | } 68 | radius: width/2 69 | color: Colors.commonTransparent 70 | 71 | Rectangle { 72 | property int size: checkbox.checked ? 10 : 0 73 | width: size 74 | height: size 75 | radius: size/2 76 | x: parent.width/2 - width/2 77 | y: parent.height/2 - height/2 78 | color: parent.border.color 79 | 80 | Behavior on size { 81 | NumberAnimation { 82 | duration: 150 83 | easing.type: Easing.InOutQuad 84 | } 85 | } 86 | } 87 | } 88 | 89 | onPressedChanged: { 90 | if (!checkbox.disabled) { 91 | if (checkbox.pressed) { 92 | touch_ripple.start() 93 | } 94 | else { 95 | touch_ripple.stop() 96 | } 97 | } 98 | } 99 | 100 | Rectangle { 101 | id: ripple 102 | clip: true 103 | anchors.fill: parent 104 | radius: width/2 105 | color: Colors.commonTransparent 106 | 107 | layer.enabled: true 108 | layer.effect: OpacityMask { 109 | maskSource: Rectangle { 110 | width: ripple.width 111 | height: ripple.height 112 | radius: ripple.radius 113 | } 114 | } 115 | 116 | MTouchRipple { 117 | id: touch_ripple 118 | visible: !disableRipple && !checkbox.disabled 119 | width: checkbox.width 120 | height: checkbox.height 121 | center: true 122 | currentColor: { 123 | if (checkbox.checked) { 124 | return Palette.string2Color(checkbox.color, Grey._600) 125 | } 126 | else { 127 | return Grey._600 128 | } 129 | } 130 | } 131 | } 132 | 133 | MouseArea { 134 | cursorShape: checkbox.disabled ? Qt.ArrowCursor : Qt.PointingHandCursor 135 | anchors.fill: parent 136 | enabled: false 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MRadioGroup.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | import QtQuick.Layouts 1.15 4 | import "./styles" 5 | import "./colors" 6 | 7 | Rectangle { 8 | id: container 9 | default property alias children: childrenContainer.children 10 | property bool row: false 11 | property var value: null 12 | 13 | 14 | 15 | width: childrenRect.width 16 | implicitWidth: width 17 | height: childrenRect.height 18 | implicitHeight: height 19 | color: "#00ffffff" 20 | 21 | signal change(string value) 22 | 23 | onValueChanged: { 24 | for (let i = 0; i < radioGroup.buttons.length; i++) { 25 | let the_button = radioGroup.buttons[i] 26 | if (the_button.value === value && !the_button.checked) { 27 | the_button.checked = true 28 | } 29 | } 30 | } 31 | 32 | ButtonGroup { 33 | id: radioGroup 34 | 35 | buttons: { 36 | let ans = [] 37 | for (let i = 0; i < childrenContainer.children.length; i++) { 38 | let the_child = childrenContainer.children[i] 39 | if (the_child instanceof MFormControlLabel) { 40 | if (the_child.control && the_child.control.length > 0 && the_child.control[0] instanceof MRadio) { 41 | if (!the_child.control[0].disabled) { 42 | ans.push(the_child.control[0]) 43 | } 44 | } 45 | } 46 | else if (the_child instanceof MRadio) { 47 | if (!the_child.disabled) { 48 | ans.push(the_child) 49 | } 50 | } 51 | } 52 | return ans 53 | } 54 | 55 | onClicked: { 56 | value = button.value 57 | change(value) 58 | } 59 | } 60 | 61 | GridLayout { 62 | id: childrenContainer 63 | x: -1 64 | y: -1 65 | rowSpacing: 0 66 | columnSpacing: 0 67 | flow: row ? GridLayout.LeftToRight : GridLayout.TopToBottom 68 | 69 | Component.onCompleted: { 70 | for (let i = 0; i < childrenContainer.children.length; i++) { 71 | let the_child = childrenContainer.children[i] 72 | if (the_child.value === value && !the_child.checked) { 73 | the_child.checked = true 74 | } 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MRipple.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | Item { 4 | id: root 5 | property bool open: false 6 | property real rippleX: 0 7 | property real rippleY: 0 8 | property real rippleSize: 0 9 | property bool pulsate: false 10 | property int timeout: 0 11 | property string currentColor: "#000000" 12 | 13 | signal exited() 14 | 15 | width: rippleSize 16 | height: rippleSize 17 | x: rippleX-width/2 18 | y: rippleY-height/2 19 | scale: 0 20 | opacity: 0.1 21 | 22 | property int fatherTimeout: pulsate ? 200 : 550 23 | property int childTimeout: 550 24 | 25 | Component.onCompleted: { 26 | father_enter.start() 27 | } 28 | 29 | Rectangle { 30 | id: child_root 31 | width: parent.width 32 | height: parent.height 33 | radius: width/2 34 | color: root.currentColor 35 | scale: 1 36 | opacity: 1 37 | property bool open: root.open 38 | 39 | onOpenChanged: { 40 | if (!child_root.open) { 41 | child_exit.start() 42 | } 43 | } 44 | 45 | NumberAnimation { 46 | id: child_exit 47 | 48 | target: child_root 49 | duration: childTimeout 50 | property: "opacity" 51 | easing.type: Easing.Bezier 52 | easing.bezierCurve: [0.4, 0, 0.2, 1] 53 | from: 1 54 | to: 0 55 | 56 | onFinished: { 57 | root.exited() 58 | } 59 | } 60 | 61 | SequentialAnimation { 62 | id: child_pulsate_exit 63 | loops: Animation.Infinite 64 | running: root.pulsate 65 | 66 | NumberAnimation { 67 | target: child_root 68 | duration: childTimeout/2 69 | property: "scale" 70 | easing.type: Easing.Bezier 71 | easing.bezierCurve: [0.4, 0, 0.2, 1] 72 | from: 1 73 | to: 0.92 74 | } 75 | NumberAnimation { 76 | target: child_root 77 | duration: childTimeout/2 78 | property: "scale" 79 | easing.type: Easing.Bezier 80 | easing.bezierCurve: [0.4, 0, 0.2, 1] 81 | from: 0.92 82 | to: 1 83 | } 84 | } 85 | } 86 | 87 | ParallelAnimation { 88 | id: father_enter 89 | 90 | NumberAnimation { 91 | target: root 92 | duration: fatherTimeout 93 | property: "scale" 94 | easing.type: Easing.Bezier 95 | easing.bezierCurve: [0.4, 0, 0.2, 1] 96 | from: 0 97 | to: 1 98 | } 99 | NumberAnimation { 100 | target: root 101 | duration: fatherTimeout 102 | property: "opacity" 103 | easing.type: Easing.Bezier 104 | easing.bezierCurve: [0.4, 0, 0.2, 1] 105 | from: 0.1 106 | to: 0.3 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MScaleX.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./colors" 4 | 5 | MAnimation { 6 | id: control 7 | timeout: 200 8 | property int transformOrigin: Item.Center // Item.Center Item.BottomRight Item.TopLeft ... 9 | property real origin: { 10 | if (transformOrigin == Item.TopLeft || transformOrigin == Item.Left || transformOrigin == Item.BottomLeft) { 11 | return 0 12 | } 13 | else if (transformOrigin == Item.TopRight || transformOrigin == Item.Right || transformOrigin == Item.BottomRight) { 14 | return control.target ? control.target.width : 0 15 | 16 | } 17 | else { 18 | return control.target ? control.target.width / 2 : 0 19 | } 20 | } 21 | 22 | Binding { 23 | target: control.target 24 | property: "transform" 25 | value: Scale { 26 | id: scaleTransform 27 | xScale: 0 28 | origin.x: control.origin 29 | origin.y: control.target ? control.target.height / 2 : 0 30 | } 31 | } 32 | 33 | enter: Transition { 34 | to: "enter" 35 | NumberAnimation { 36 | duration: timeout 37 | property: "xScale" 38 | easing.type: Easing.InOutQuad 39 | from: 0.0 40 | to: 1.0 41 | } 42 | } 43 | enterState: State { 44 | name: "enter" 45 | PropertyChanges { 46 | target: scaleTransform 47 | xScale: 1 48 | } 49 | } 50 | 51 | exit: Transition { 52 | to: "exit" 53 | NumberAnimation { 54 | duration: timeout 55 | property: "xScale" 56 | easing.type: Easing.InOutQuad 57 | from: 1.0 58 | to: 0.0 59 | } 60 | } 61 | exitState: State { 62 | name: "exit" 63 | PropertyChanges { 64 | target: scaleTransform 65 | xScale: 0 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MScaleY.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./colors" 4 | 5 | MAnimation { 6 | id: control 7 | timeout: 200 8 | property int transformOrigin: Item.Center // Item.Center Item.BottomRight Item.TopLeft ... 9 | property real origin: { 10 | if (transformOrigin == Item.TopLeft || transformOrigin == Item.Top || transformOrigin == Item.TopRight) { 11 | return 0 12 | } 13 | else if (transformOrigin == Item.BottomLeft || transformOrigin == Item.Bottom || transformOrigin == Item.BottomRight) { 14 | return control.target ? control.target.height : 0 15 | 16 | } 17 | else { 18 | return control.target ? control.target.height / 2 : 0 19 | } 20 | } 21 | 22 | Binding { 23 | target: control.target 24 | property: "transform" 25 | value: Scale { 26 | id: scaleTransform 27 | yScale: 0 28 | origin.x: control.target ? control.target.width / 2 : 0 29 | origin.y: control.origin 30 | } 31 | } 32 | 33 | enter: Transition { 34 | to: "enter" 35 | NumberAnimation { 36 | duration: timeout 37 | property: "yScale" 38 | easing.type: Easing.InOutQuad 39 | from: 0.0 40 | to: 1.0 41 | } 42 | } 43 | enterState: State { 44 | name: "enter" 45 | PropertyChanges { 46 | target: scaleTransform 47 | yScale: 1 48 | } 49 | } 50 | 51 | exit: Transition { 52 | to: "exit" 53 | NumberAnimation { 54 | duration: timeout 55 | property: "yScale" 56 | easing.type: Easing.InOutQuad 57 | from: 1.0 58 | to: 0.0 59 | } 60 | } 61 | exitState: State { 62 | name: "exit" 63 | PropertyChanges { 64 | target: scaleTransform 65 | yScale: 0 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MSelect.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./colors" 4 | 5 | MSelectBase { 6 | id: control 7 | property alias model: menu_repeater.model // list 8 | displayItem: MTypography { 9 | id: text_item 10 | variant: "body1" 11 | text: control.value 12 | noWrap: true 13 | lineHeight: TypographyStyle.convertLineHeight(1.1876) 14 | } 15 | 16 | Binding { 17 | target: text_item 18 | property: 'color' 19 | when: disabled 20 | value: Palette.lightTextDisabled 21 | } 22 | 23 | onSelectOpen: { 24 | menu_dialog.open() 25 | } 26 | 27 | MMenu { 28 | id: menu_dialog 29 | anchorEl: control 30 | anchorOrigin: Item.Bottom 31 | transformOrigin: Item.Top 32 | 33 | Repeater { 34 | id: menu_repeater 35 | 36 | delegate: MMenuItem { 37 | text: modelData 38 | 39 | onClicked: { 40 | control.value = modelData 41 | control.index = index 42 | change(control.value, control.index) 43 | menu_dialog.close() 44 | } 45 | } 46 | } 47 | 48 | onAboutToShow: { 49 | control.menuOpened = true 50 | } 51 | 52 | onClosed: { 53 | control.menuOpened = false 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MSelectBase.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Shapes 1.15 3 | import "./StyleComponent" 4 | import "./styles" 5 | import "./colors" 6 | 7 | Rectangle { 8 | id: control 9 | property string variant: 'standard' // 'filled' 'outlined' 'standard' 10 | property alias displayItem: display_container.children // list 11 | property int index: -1 12 | property string value: "" 13 | property string selectColor: "primary" 14 | property string size: 'medium' // 'medium' | 'small' 15 | property bool disabled: false 16 | property bool hover: false 17 | property string placeholder: "" 18 | property real minWidth: 0 19 | property real maxWidth: -1 20 | property var padding: { 21 | if (size === 'small') { 22 | variant === 'outlined' ? [10.5, 32, 10.5, 14] : (variant === 'filled' ? [14, 32, 15, 12] : [5, 24, 5, 0]) 23 | } 24 | else { 25 | variant === 'outlined' ? [18.5, 32, 18.5, 14] : (variant === 'filled' ? [18, 32, 19, 12] : [6, 24, 7, 0]) 26 | } 27 | } 28 | property var topPadding: padding && padding[0] ? padding[0] : 0 29 | property var rightPadding: padding && padding[1] ? padding[1] : 0 30 | property var bottomPadding: padding && padding[2] ? padding[2] : 0 31 | property var leftPadding: padding && padding[3] ? padding[3] : 0 32 | 33 | 34 | 35 | 36 | signal change(string value, int index) 37 | signal selectOpen() 38 | 39 | width: text_container.width 40 | height: text_container.height 41 | 42 | color: menuOpened ? Colors.alpha('#000000', 0.05) : "#00ffffff" 43 | property bool menuOpened: false 44 | 45 | Loader { 46 | id: loader 47 | sourceComponent: variant === 'outlined' ? outlined_style : (variant === 'filled' ? filled_style : standard_style) 48 | anchors.fill: parent 49 | z: -1 50 | } 51 | 52 | Component { 53 | id: standard_style 54 | MInputStyle { 55 | size: control.size 56 | disabled: control.disabled 57 | hover: control.hover 58 | active: control.menuOpened 59 | color: control.selectColor 60 | } 61 | } 62 | 63 | Component { 64 | id: outlined_style 65 | MOutlinedInputStyle { 66 | size: control.size 67 | disabled: control.disabled 68 | hover: control.hover 69 | active: control.menuOpened 70 | color: control.selectColor 71 | } 72 | } 73 | 74 | Component { 75 | id: filled_style 76 | MFilledInputStyle { 77 | size: control.size 78 | disabled: control.disabled 79 | hover: control.hover 80 | active: control.menuOpened 81 | color: control.selectColor 82 | } 83 | } 84 | 85 | Row { 86 | id: text_container 87 | topPadding: control.topPadding 88 | bottomPadding: control.bottomPadding 89 | leftPadding: control.leftPadding 90 | spacing: control.rightPadding-24 91 | rightPadding: variant === 'standard' ? 0 : 7 92 | 93 | Item { 94 | id: display_container 95 | width: { 96 | let text_width = Math.max(childrenRect.width, control.minWidth-control.leftPadding-control.rightPadding, 16) 97 | if (control.maxWidth >= 0) { 98 | text_width = Math.min(text_width, control.maxWidth) 99 | } 100 | return text_width 101 | } 102 | height: childrenRect.height 103 | anchors.verticalCenter: parent.verticalCenter 104 | } 105 | 106 | Item { 107 | width: 24 108 | height: 10 109 | anchors.verticalCenter: parent.verticalCenter 110 | 111 | Image { 112 | anchors.centerIn: parent 113 | 114 | width: 24 115 | height: 24 116 | sourceSize.width: width*2 117 | sourceSize.height: height*2 118 | source: `data:image/svg+xml;utf8,` 119 | } 120 | } 121 | } 122 | 123 | MTypography { 124 | visible: !control.value 125 | variant: "body1" 126 | textColor: 'textSecondary' 127 | text: placeholder 128 | noWrap: true 129 | lineHeight: TypographyStyle.convertLineHeight(1.2) 130 | anchors.verticalCenter: parent.verticalCenter 131 | leftPadding: control.leftPadding 132 | } 133 | 134 | MouseArea { 135 | visible: !control.disabled 136 | anchors.fill: parent 137 | cursorShape: Qt.PointingHandCursor 138 | hoverEnabled: true 139 | 140 | onEntered: { 141 | control.hover = true 142 | } 143 | 144 | onExited: { 145 | control.hover = false 146 | } 147 | 148 | onClicked: { 149 | selectOpen() 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MSlide.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./colors" 4 | 5 | MAnimation { 6 | id: control 7 | timeout: 225 8 | property string direction: 'down' // 'down' 'left' 'right' 'up' 9 | 10 | 11 | property real enterPosX: originX 12 | property real enterPosY: originY 13 | 14 | property real exitPosX: { 15 | switch (direction) { 16 | case 'left': 17 | return originX+500 18 | case 'right': 19 | return originX+-500-control.target.width 20 | case 'up': 21 | return originX 22 | default: 23 | return originX 24 | } 25 | } 26 | 27 | property real exitPosY: { 28 | switch (direction) { 29 | case 'left': 30 | return originY 31 | case 'right': 32 | return originY 33 | case 'up': 34 | return originY+250 35 | default: 36 | return originY-250-control.target.height 37 | } 38 | } 39 | 40 | enter: Transition { 41 | to: "enter" 42 | NumberAnimation { 43 | duration: timeout 44 | property: "opacity" 45 | easing.type: Easing.InOutQuad 46 | from: 0.0 47 | to: 1.0 48 | } 49 | NumberAnimation { 50 | duration: timeout 51 | property: "x" 52 | easing.type: Easing.InOutQuad 53 | from: control.exitPosX 54 | to: enterPosX 55 | } 56 | NumberAnimation { 57 | duration: timeout 58 | property: "y" 59 | easing.type: Easing.InOutQuad 60 | from: control.exitPosY 61 | to: enterPosY 62 | } 63 | } 64 | enterState: State { 65 | name: "enter" 66 | PropertyChanges { 67 | target: control.target 68 | opacity: 1 69 | x: enterPosX 70 | y: enterPosY 71 | } 72 | } 73 | 74 | exit: Transition { 75 | to: "exit" 76 | NumberAnimation { 77 | duration: timeout 78 | property: "opacity" 79 | easing.type: Easing.InOutQuad 80 | from: 1.0 81 | to: 0.0 82 | } 83 | NumberAnimation { 84 | duration: timeout 85 | property: "x" 86 | easing.type: Easing.InOutQuad 87 | from: enterPosX 88 | to: control.exitPosX 89 | } 90 | NumberAnimation { 91 | duration: timeout 92 | property: "y" 93 | easing.type: Easing.InOutQuad 94 | from: enterPosY 95 | to: control.exitPosY 96 | } 97 | } 98 | exitState: State { 99 | name: "exit" 100 | PropertyChanges { 101 | target: control.target 102 | opacity: 0 103 | x: control.exitPosX 104 | y: control.exitPosY 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MSvgIcon.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./SvgIcon/FilledMap.js" as FilledMap 4 | import "./SvgIcon/OutlinedMap.js" as OutlinedMap 5 | import "./SvgIcon/RoundedMap.js" as RoundedMap 6 | import "./SvgIcon/TwoToneMap.js" as TwoToneMap 7 | import "./SvgIcon/SharpMap.js" as SharpMap 8 | 9 | Item { 10 | id: root 11 | property string variant: "filled" // 'filled' | 'outliend' | 'rounded' | 'two tone' | 'sharp' 12 | property string color: "default" //'default' | 'primary' | 'secondary' | 'textSecondary' | 'error' | color 13 | property string fontSize: "medium" // 'small' | 'medium' | 'large' 14 | property string name: "" 15 | property real size: { 16 | switch (fontSize) { 17 | case "small": 18 | return 20 19 | case "medium": 20 | return 24 21 | case "large": 22 | return 35 23 | } 24 | return 24 25 | } 26 | 27 | 28 | 29 | 30 | 31 | property var nameMap: { 32 | switch (variant) { 33 | case "filled": 34 | return FilledMap.name 35 | case "outlined": 36 | return OutlinedMap.name 37 | case "rounded": 38 | return RoundedMap.name 39 | case "two tone": 40 | return TwoToneMap.name 41 | case "sharp": 42 | return SharpMap.name 43 | } 44 | return FilledMap.name 45 | } 46 | property string svgName: { 47 | switch (variant) { 48 | case "filled": 49 | return name 50 | case "outlined": 51 | return `${name}Outlined` 52 | case "rounded": 53 | return `${name}Rounded` 54 | case "two tone": 55 | return `${name}TwoTone` 56 | case "sharp": 57 | return `${name}Sharp` 58 | } 59 | return name 60 | } 61 | property var rgbaColor: Palette.colorStrToRgb(Palette.string2Color(root.color, "#000000")) 62 | 63 | width: size 64 | height: size 65 | 66 | Image { 67 | width: root.size 68 | height: root.size 69 | sourceSize.width: width*2 70 | sourceSize.height: height*2 71 | opacity: rgbaColor && (rgbaColor.a || rgbaColor.a === 0) ? rgbaColor.a/100 : 1 72 | source: { 73 | let color_str = '' 74 | if (rgbaColor) { 75 | color_str = `rgb(${rgbaColor.r},${rgbaColor.g},${rgbaColor.b})` 76 | } 77 | 78 | if (!nameMap[svgName]) { 79 | return '' 80 | } 81 | 82 | let svg_str = nameMap[svgName].replace(" 0) { 73 | return TypographyStyle.convertFontSize(fontSize) 74 | } 75 | 76 | let fontStyleList = TypographyStyle.fontStyleList 77 | if (!variant) { 78 | return fontStyleList.body2.size 79 | } 80 | 81 | return fontStyleList[variant].size ? fontStyleList[variant].size : fontStyleList.body2.size 82 | } 83 | 84 | font.weight: { 85 | let fontStyleList = TypographyStyle.fontStyleList 86 | if (!variant) { 87 | return fontStyleList.body2.weight 88 | } 89 | 90 | return fontStyleList[variant].weight ? fontStyleList[variant].weight : fontStyleList.body2.weight 91 | } 92 | 93 | lineHeight: { 94 | let fontStyleList = TypographyStyle.fontStyleList 95 | if (!variant) { 96 | return fontStyleList.body2.line_height 97 | } 98 | 99 | return fontStyleList[variant].line_height ? fontStyleList[variant].line_height : fontStyleList.body2.line_height 100 | } 101 | 102 | font.letterSpacing: { 103 | let fontStyleList = TypographyStyle.fontStyleList 104 | if (!variant) { 105 | return fontStyleList.body2.letter_spacing 106 | } 107 | 108 | return fontStyleList[variant].letter_spacing ? fontStyleList[variant].letter_spacing : fontStyleList.body2.letter_spacing 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/MZoom.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "./styles" 3 | import "./colors" 4 | 5 | MAnimation { 6 | id: control 7 | timeout: 225 8 | 9 | enter: Transition { 10 | to: "enter" 11 | NumberAnimation { 12 | duration: timeout*0.666 13 | property: "scale" 14 | easing.type: Easing.InOutQuad 15 | from: 0 16 | to: 1 17 | } 18 | // PropertyAnimation { 19 | // duration: 0 20 | // property: "transformOrigin" 21 | // to: transformOrigin 22 | // } 23 | } 24 | enterState: State { 25 | name: "enter" 26 | PropertyChanges { 27 | target: control.target 28 | // scale: 1 29 | // transformOrigin: transformOrigin 30 | } 31 | } 32 | 33 | exit: Transition { 34 | to: "exit" 35 | NumberAnimation { 36 | duration: timeout 37 | property: "scale" 38 | easing.type: Easing.InOutQuad 39 | from: 1.0 40 | to: 0.0 41 | } 42 | // PropertyAnimation { 43 | // duration: 0 44 | // property: "transformOrigin" 45 | // to: transformOrigin 46 | // } 47 | } 48 | exitState: State { 49 | name: "exit" 50 | PropertyChanges { 51 | target: control.target 52 | scale: 0 53 | // transformOrigin: transformOrigin 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/StyleComponent/MFilledInputStyle.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Shapes 1.15 3 | import "../styles" 4 | import "../" 5 | 6 | Item { 7 | id: root 8 | property string color: 'primary' 9 | property string size: 'medium' // 'medium' | 'small' 10 | property var padding: size === 'small' ? [14, 12, 15, 12] : [18, 12, 19, 12] 11 | property bool disabled: false 12 | property bool hover: false 13 | property bool active: false 14 | property string _main_color: Palette.string2Color(root.color, Palette.primaryMain) 15 | 16 | z: -1 17 | anchors.fill: parent 18 | 19 | 20 | Shape { 21 | id: filledComponent 22 | anchors.fill: parent 23 | property real shapeWidth: parent.width 24 | property real shapeHeight: parent.height 25 | 26 | ShapePath { 27 | strokeWidth: 0.1 28 | strokeColor: "#e8e8e8" 29 | fillColor: "#e8e8e8" 30 | 31 | startX: 0 32 | startY: Palette.borderRadius 33 | 34 | PathLine { 35 | x: 0 36 | y: filledComponent.shapeHeight 37 | } 38 | 39 | PathLine { 40 | x: filledComponent.shapeWidth 41 | y: filledComponent.shapeHeight 42 | } 43 | 44 | PathLine { 45 | x: filledComponent.shapeWidth 46 | y: Palette.borderRadius 47 | } 48 | 49 | PathArc { 50 | x: filledComponent.shapeWidth-Palette.borderRadius 51 | y: 0 52 | radiusX: Palette.borderRadius 53 | radiusY: Palette.borderRadius 54 | direction: PathArc.Counterclockwise 55 | } 56 | 57 | PathLine { 58 | x: Palette.borderRadius 59 | y: 0 60 | } 61 | 62 | PathArc { 63 | x: 0 64 | y: Palette.borderRadius 65 | radiusX: Palette.borderRadius 66 | radiusY: Palette.borderRadius 67 | direction: PathArc.Counterclockwise 68 | } 69 | } 70 | } 71 | 72 | property int strokeStyle: disabled ? ShapePath.DashLine : ShapePath.SolidLine 73 | property int strokeWidth: 1 74 | property string strokeColor: hover && !disabled ? Palette.lightTextPrimary : '#3B000000' 75 | 76 | // 下划线 77 | Shape { 78 | anchors.left: parent.left 79 | anchors.right: parent.right 80 | anchors.bottom: parent.bottom 81 | 82 | ShapePath { 83 | strokeWidth: { 84 | return root.strokeWidth 85 | } 86 | strokeColor: root.strokeColor 87 | strokeStyle: root.strokeStyle 88 | dashPattern: [2, 2] 89 | 90 | startX: root.strokeWidth/2 91 | startY: -root.strokeWidth/2 92 | 93 | PathLine { 94 | x: root.width-root.strokeWidth/2; 95 | y: -root.strokeWidth/2 96 | } 97 | } 98 | } 99 | 100 | MScaleX { 101 | target: underline 102 | open: active 103 | } 104 | 105 | Rectangle { 106 | id: underline 107 | width: parent.width 108 | anchors.bottom: parent.bottom 109 | height: 2 110 | color: root._main_color 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/StyleComponent/MFramelessWindowButtonsMac.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Window 2.15 3 | 4 | // mac下的系统按钮 5 | Item { 6 | id: mac_system_button 7 | property Window target: null 8 | property bool darkMode: false 9 | property bool disableMinimizeButton: false 10 | property bool disableMaximizeButton: false 11 | property bool disableCloseButton: false 12 | 13 | 14 | anchors.top: parent.top 15 | anchors.left: parent.left 16 | anchors.topMargin: 8 17 | anchors.leftMargin: 8 18 | width: childrenRect.width 19 | height: childrenRect.height 20 | property bool activeSystemButton: mac_system_button_area.containsMouse || root.activeFocusItem 21 | property string deactiveColor: darkMode ? "#5a5959" : "#d2d2d1" 22 | property string deactiveBorderColor: "#b5b3b3" // 仅浅色模式按钮有边框 23 | 24 | Row { 25 | spacing: 8 26 | 27 | // mac关闭按钮 28 | Rectangle { 29 | visible: !disableCloseButton 30 | width: 12 31 | height: 12 32 | radius: 6 33 | color: mac_system_button.activeSystemButton ? "#fc605c" : mac_system_button.deactiveColor 34 | border.width: darkMode ? 0 : 1 35 | border.color: mac_system_button.activeSystemButton ? "#f34042" : mac_system_button.deactiveBorderColor 36 | 37 | Image { 38 | visible: mac_system_button_area.containsMouse 39 | x: (parent.width-width)/2 40 | y: (parent.height-height)/2 41 | width: 6 42 | height: 6 43 | sourceSize.width: width*2 44 | sourceSize.height: height*2 45 | source: `data:image/svg+xml;utf8, 46 | 47 | 48 | ` 49 | } 50 | 51 | MouseArea { 52 | anchors.fill: parent 53 | onClicked: { 54 | target.close() 55 | } 56 | } 57 | } 58 | 59 | // mac最小化按钮 60 | Rectangle { 61 | visible: !disableMinimizeButton 62 | width: 12 63 | height: 12 64 | radius: 6 65 | color: mac_system_button.activeSystemButton ? "#fcbb40" : mac_system_button.deactiveColor 66 | border.width: darkMode ? 0 : 1 67 | border.color: mac_system_button.activeSystemButton ? "#eb9d29" : mac_system_button.deactiveBorderColor 68 | 69 | Image { 70 | visible: mac_system_button_area.containsMouse 71 | x: (parent.width-width)/2 72 | y: (parent.height-height)/2 73 | width: 8.5 74 | height: 1.5 75 | sourceSize.width: width*2 76 | sourceSize.height: height*2 77 | source: `data:image/svg+xml;utf8, 78 | 79 | ` 80 | } 81 | 82 | MouseArea { 83 | anchors.fill: parent 84 | onClicked: { 85 | if (Qt.platform.os === 'osx') { 86 | target.flags = 0 // mac无边框导致不能最小化,先重置成有边框,再最小化 87 | target.showMinimized() 88 | } 89 | else { 90 | target.hide() 91 | } 92 | } 93 | } 94 | } 95 | 96 | // mac全屏按钮 97 | Rectangle { 98 | visible: !disableMaximizeButton 99 | width: 12 100 | height: 12 101 | radius: 6 102 | color: mac_system_button.activeSystemButton ? "#34c648" : mac_system_button.deactiveColor 103 | border.width: darkMode ? 0 : 1 104 | border.color: mac_system_button.activeSystemButton ? "#20a932" : mac_system_button.deactiveBorderColor 105 | 106 | Image { 107 | visible: mac_system_button_area.containsMouse 108 | x: (parent.width-width)/2 109 | y: (parent.height-height)/2 110 | width: 6 111 | height: 6 112 | sourceSize.width: width*2 113 | sourceSize.height: height*2 114 | source: `data:image/svg+xml;utf8, 115 | 116 | 117 | ` 118 | } 119 | 120 | MouseArea { 121 | anchors.fill: parent 122 | onClicked: { 123 | if (Qt.platform.os === 'osx') { 124 | target.showFullScreen() 125 | } 126 | else { 127 | target.showMaximized() 128 | } 129 | } 130 | } 131 | } 132 | } 133 | 134 | MouseArea { 135 | id: mac_system_button_area 136 | anchors.fill: parent 137 | acceptedButtons: Qt.NoButton 138 | hoverEnabled: true 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/StyleComponent/MFramelessWindowButtonsWin.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Window 2.15 3 | 4 | // win下的系统按钮 5 | Item { 6 | id: win_system_button 7 | property Window target: null 8 | property bool darkMode: false 9 | property bool disableMinimizeButton: false 10 | property bool disableMaximizeButton: false 11 | property bool disableCloseButton: false 12 | 13 | 14 | anchors.right: parent.right 15 | anchors.top: parent.top 16 | width: childrenRect.width 17 | height: childrenRect.height 18 | property string minMaxHoverColor: "#33888888" 19 | property string closeHoverColor: "#ccff0000" 20 | 21 | 22 | Row { 23 | spacing: 0 24 | 25 | // win最小化按钮 26 | Rectangle { 27 | visible: !disableMinimizeButton 28 | width: 48 29 | height: 28 30 | 31 | color: win_min_button.containsMouse ? minMaxHoverColor : "#00ffffff" 32 | 33 | Image { 34 | scale: win_min_button.pressed ? 0.7 : 1 // 0.1秒动画 35 | x: (parent.width-width)/2 36 | y: (parent.height-height)/2 37 | width: 9 38 | height: 0.75 39 | sourceSize.width: width*2 40 | sourceSize.height: height*2 41 | source: `data:image/svg+xml;utf8, 42 | 43 | ` 44 | } 45 | 46 | MouseArea { 47 | id: win_min_button 48 | anchors.fill: parent 49 | hoverEnabled: true 50 | 51 | onClicked: { 52 | if (Qt.platform.os === 'osx') { 53 | target.flags = 0 // mac无边框导致不能最小化,先重置成有边框,再最小化 54 | target.showMinimized() 55 | } 56 | else { 57 | // target.hide() 58 | target.showMinimized() 59 | 60 | } 61 | } 62 | } 63 | } 64 | 65 | // win最大化按钮 66 | Rectangle { 67 | visible: !disableMaximizeButton 68 | width: 48 69 | height: 28 70 | 71 | color: win_max_button.containsMouse ? minMaxHoverColor : "#00ffffff" 72 | 73 | Image { 74 | scale: win_max_button.pressed ? 0.7 : 1 75 | x: (parent.width-width)/2 76 | y: (parent.height-height)/2 77 | width: root.visibility === Window.Maximized ? 10 : 9 78 | height: width 79 | sourceSize.width: width*2 80 | sourceSize.height: height*2 81 | source: root.visibility === Window.Maximized ? 82 | `data:image/svg+xml;utf8, 83 | 84 | 85 | ` 86 | : 87 | `data:image/svg+xml;utf8, 88 | 89 | ` 90 | } 91 | 92 | MouseArea { 93 | id: win_max_button 94 | anchors.fill: parent 95 | hoverEnabled: true 96 | 97 | onClicked: { 98 | if (target.visibility === Window.Maximized) { 99 | target.showNormal() 100 | } 101 | else { 102 | target.showMaximized() 103 | } 104 | } 105 | } 106 | } 107 | 108 | // win关闭按钮 109 | Rectangle { 110 | visible: !disableCloseButton 111 | width: 50 112 | height: 28 113 | 114 | color: win_close_button.containsMouse ? closeHoverColor : "#00ffffff" 115 | 116 | Image { 117 | scale: win_close_button.pressed ? 0.7 : 1 118 | x: (parent.width-width)/2 119 | y: (parent.height-height)/2 120 | width: 10 121 | height: 10 122 | sourceSize.width: width*2 123 | sourceSize.height: height*2 124 | source: `data:image/svg+xml;utf8, 125 | 126 | 127 | ` 128 | } 129 | 130 | MouseArea { 131 | id: win_close_button 132 | anchors.fill: parent 133 | hoverEnabled: true 134 | 135 | onClicked: { 136 | target.close() 137 | } 138 | } 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/StyleComponent/MInputStyle.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Shapes 1.15 3 | import "../styles" 4 | import "../" 5 | 6 | Item { 7 | id: root 8 | property string color: 'primary' 9 | property string size: 'medium' // 'medium' | 'small' 10 | property var padding: size === 'small' ? [5, 0, 5, 0] : [6, 0, 7, 0] 11 | property bool disabled: false 12 | property bool hover: false 13 | property bool active: false 14 | property string _main_color: Palette.string2Color(root.color, Palette.primaryMain) 15 | 16 | z: -1 17 | anchors.fill: parent 18 | 19 | property int strokeStyle: disabled ? ShapePath.DashLine : ShapePath.SolidLine 20 | property int strokeWidth: hover && !disabled ? 2 : 1 21 | property string strokeColor: hover && !disabled ? Palette.lightTextPrimary : '#3B000000' 22 | 23 | // 下划线 24 | Shape { 25 | anchors.left: parent.left 26 | anchors.right: parent.right 27 | anchors.bottom: parent.bottom 28 | 29 | ShapePath { 30 | strokeWidth: { 31 | return root.strokeWidth 32 | } 33 | strokeColor: root.strokeColor 34 | strokeStyle: root.strokeStyle 35 | dashPattern: [2, 2] 36 | 37 | startX: root.strokeWidth/2 38 | startY: -root.strokeWidth/2 39 | 40 | PathLine { 41 | x: root.width-root.strokeWidth/2; 42 | y: -root.strokeWidth/2 43 | } 44 | } 45 | } 46 | 47 | MScaleX { 48 | target: underline 49 | open: active 50 | } 51 | 52 | Rectangle { 53 | id: underline 54 | width: parent.width 55 | anchors.bottom: parent.bottom 56 | height: 2 57 | color: root._main_color 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/StyleComponent/MOutlinedInputStyle.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "../styles" 3 | 4 | Item { 5 | id: root 6 | property string color: 'primary' 7 | property string size: 'medium' // 'medium' | 'small' 8 | property var padding: size === 'small' ? [10.5, 14, 10.5, 14] : [18.5, 14, 18.5, 14] 9 | property bool disabled: false 10 | property bool hover: false 11 | property bool active: false 12 | property string _main_color: Palette.string2Color(root.color, Palette.primaryMain) 13 | 14 | z: -1 15 | anchors.fill: parent 16 | 17 | // outlined外边框 18 | Rectangle { 19 | enabled: false 20 | color: Colors.commonTransparent 21 | border.width: active ? 2 : 1 22 | border.color: active ? root._main_color : (hover && !disabled ? Palette.lightTextPrimary : '#3B000000') 23 | anchors.fill: parent 24 | radius: Palette.borderRadius 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/colors/Grey.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | 5 | QtObject { 6 | readonly property string _50: '#fafafa' 7 | readonly property string _100: '#f5f5f5' 8 | readonly property string _200: '#eeeeee' 9 | readonly property string _300: '#e0e0e0' 10 | readonly property string _400: '#bdbdbd' 11 | readonly property string _500: '#9e9e9e' 12 | readonly property string _600: '#757575' 13 | readonly property string _700: '#616161' 14 | readonly property string _800: '#424242' 15 | readonly property string _900: '#212121' 16 | readonly property string a100: '#d5d5d5' 17 | readonly property string a200: '#aaaaaa' 18 | readonly property string a400: '#303030' 19 | readonly property string a700: '#616161' 20 | } 21 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/colors/Indigo.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | 5 | QtObject { 6 | readonly property string _50: '#e8eaf6' 7 | readonly property string _100: '#c5cae9' 8 | readonly property string _200: '#9fa8da' 9 | readonly property string _300: '#7986cb' 10 | readonly property string _400: '#5c6bc0' 11 | readonly property string _500: '#3f51b5' 12 | readonly property string _600: '#3949ab' 13 | readonly property string _700: '#303f9f' 14 | readonly property string _800: '#283593' 15 | readonly property string _900: '#1a237e' 16 | readonly property string a100: '#8c9eff' 17 | readonly property string a200: '#536dfe' 18 | readonly property string a400: '#3d5afe' 19 | readonly property string a700: '#304ffe' 20 | } 21 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/colors/Pink.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | 5 | QtObject { 6 | readonly property string _50: '#fce4ec' 7 | readonly property string _100: '#f8bbd0' 8 | readonly property string _200: '#f48fb1' 9 | readonly property string _300: '#f06292' 10 | readonly property string _400: '#ec407a' 11 | readonly property string _500: '#e91e63' 12 | readonly property string _600: '#d81b60' 13 | readonly property string _700: '#c2185b' 14 | readonly property string _800: '#ad1457' 15 | readonly property string _900: '#880e4f' 16 | readonly property string a100: '#ff80ab' 17 | readonly property string a200: '#ff4081' 18 | readonly property string a400: '#f50057' 19 | readonly property string a700: '#c51162' 20 | } 21 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/colors/Red.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | 5 | QtObject { 6 | readonly property string _50: '#ffebee' 7 | readonly property string _100: '#ffcdd2' 8 | readonly property string _200: '#ef9a9a' 9 | readonly property string _300: '#e57373' 10 | readonly property string _400: '#ef5350' 11 | readonly property string _500: '#f44336' 12 | readonly property string _600: '#e53935' 13 | readonly property string _700: '#d32f2f' 14 | readonly property string _800: '#c62828' 15 | readonly property string _900: '#b71c1c' 16 | readonly property string a100: '#ff8a80' 17 | readonly property string a200: '#ff5252' 18 | readonly property string a400: '#ff1744' 19 | readonly property string a700: '#d50000' 20 | } 21 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/colors/qmldir: -------------------------------------------------------------------------------- 1 | singleton Indigo 1.0 Indigo.qml 2 | singleton Pink 1.0 Pink.qml 3 | singleton Red 1.0 Red.qml 4 | singleton Grey 1.0 Grey.qml 5 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/qmldir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyQsmart/MaterialUI-QML/f423357a1293878bc481d2ad496211742e29cbd7/src_qml/common_component/MaterialUI/qmldir -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/styles/Colors.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | 5 | QtObject { 6 | readonly property string commonBlack: '#000000' 7 | readonly property string commonWhite: '#ffffff' 8 | readonly property string commonTransparent: '#00ffffff' 9 | 10 | function alpha(color, value) { 11 | let simple_color = '' 12 | if (color.length === 9) { 13 | simple_color = color.substring(3, 9) 14 | } 15 | else { 16 | simple_color = color.substring(1, 7) 17 | } 18 | 19 | let alpha_str = parseInt(255*value).toString(16) 20 | if (alpha_str.length < 2) { 21 | alpha_str = '0'+alpha_str 22 | } 23 | 24 | return `#${alpha_str}${simple_color}` 25 | } 26 | 27 | function addAlpha(color, value) { 28 | let simple_color = '' 29 | let old_alpha = 1 30 | if (color.length === 9) { 31 | simple_color = color.substring(3, 9) 32 | old_alpha = parseInt(color.substring(1, 3), 16)/255 33 | } 34 | else { 35 | simple_color = color.substring(1, 7) 36 | } 37 | 38 | let alpha_str = parseInt(255*value*old_alpha).toString(16) 39 | if (alpha_str.length < 2) { 40 | alpha_str = '0'+alpha_str 41 | } 42 | 43 | return `#${alpha_str}${simple_color}` 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/styles/TypographyStyle.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | 5 | // 原版 6 | QtObject { 7 | // readonly property int fontSize: 14 // The default font size of the Material Specification. 8 | readonly property int fontWeightLight: Font.Thin 9 | readonly property int fontWeightRegular: Font.Normal 10 | readonly property int fontWeightMedium: Font.DemiBold // or Medium 11 | readonly property real scale: Qt.platform.os === "windows" ? 0.8 : 1 // Mac 1; Win 0.8; need to test 12 | 13 | readonly property var fontStyleList: ({ 14 | "h1": { 15 | size: convertFontSize(96), 16 | weight: fontWeightLight, 17 | line_height: 1.05/scale, // 1.167 18 | letter_spacing: -1.5, 19 | }, 20 | "h2": { 21 | size: convertFontSize(60), 22 | weight: fontWeightLight, 23 | line_height: 1.05/scale, // 1.2 24 | letter_spacing: -0.5, 25 | }, 26 | "h3": { 27 | size: convertFontSize(48), 28 | weight: Font.Normal, 29 | line_height: 1.05/scale, // 1.167 30 | letter_spacing: 0, 31 | }, 32 | "h4": { 33 | size: convertFontSize(34), 34 | weight: fontWeightRegular, 35 | line_height: 1.12/scale, // 1.235 36 | letter_spacing: 0.25, 37 | }, 38 | "h5": { 39 | size: convertFontSize(24), 40 | weight: fontWeightRegular, 41 | line_height: 1.22/scale, // 1.334 42 | letter_spacing: 0, 43 | }, 44 | "h6": { 45 | size: convertFontSize(20), 46 | weight: fontWeightMedium, 47 | line_height: 1.4/scale, // 1.6 48 | letter_spacing: 0.15, 49 | }, 50 | "subtitle1": { 51 | size: convertFontSize(16), 52 | weight: fontWeightRegular, 53 | line_height: 1.6/scale, // 1.75 54 | letter_spacing: 0.15, 55 | }, 56 | "subtitle2": { 57 | size: convertFontSize(14), 58 | weight: fontWeightMedium, 59 | line_height: 1.4/scale, // 1.57 60 | letter_spacing: 0.1, 61 | }, 62 | "body1": { 63 | size: convertFontSize(16), 64 | weight: fontWeightRegular, 65 | line_height: 1.35/scale, // 1.5 66 | letter_spacing: 0.15, 67 | }, 68 | "body2": { 69 | size: convertFontSize(14), 70 | weight: fontWeightRegular, 71 | line_height: 1.3/scale, // 1.43 72 | letter_spacing: 0.15, 73 | }, 74 | "button": { 75 | size: convertFontSize(14), 76 | weight: fontWeightMedium, 77 | line_height: 1.6/scale, // line_height: 1.75, 78 | letter_spacing: 0.4, 79 | // text-transform: uppercase; 80 | }, 81 | "caption": { 82 | size: convertFontSize(12), 83 | weight: fontWeightRegular, 84 | line_height: 1.5/scale, // 1.66 85 | letter_spacing: 0.4, 86 | }, 87 | "overline": { 88 | size: convertFontSize(12), 89 | weight: fontWeightRegular, 90 | line_height: 2.5/scale, // 2.66 91 | letter_spacing: 1, 92 | // text-transform: uppercase; 93 | } 94 | // "little": 10 95 | }) 96 | 97 | function convertFontSize(size) { 98 | return parseInt(size*scale) 99 | } 100 | 101 | function convertLineHeight(line_height) { 102 | return line_height/scale 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src_qml/common_component/MaterialUI/styles/qmldir: -------------------------------------------------------------------------------- 1 | singleton Colors 1.0 Colors.qml 2 | singleton Palette 1.0 Palette.qml 3 | singleton TypographyStyle 1.0 TypographyStyle.qml 4 | -------------------------------------------------------------------------------- /src_qml/common_component/Route/Route.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | 5 | Item { 6 | id: global_route 7 | signal switchToCallback(string url) 8 | signal navigateToCallback(string url) 9 | signal redirectToCallback(string url) 10 | signal navigateBackCallback(int count) 11 | 12 | property var routeStack: [{ url: "/" }] 13 | 14 | function getStack() { 15 | return routeStack 16 | } 17 | 18 | function setStack(value) { 19 | routeStack = value 20 | } 21 | 22 | function getUrlArg() { 23 | let current_route = routeStack[routeStack.length-1] 24 | return current_route.arg 25 | } 26 | 27 | function switchTo(url, arg=null) { 28 | let current_route = routeStack[routeStack.length-1] 29 | if (current_route.url === url) { 30 | return 31 | } 32 | 33 | console.log('(Route.qml)Route.switchTo url:', url, 'arg:', JSON.stringify(arg)) 34 | routeStack.push({ 35 | url, 36 | arg 37 | }) 38 | switchToCallback(url) 39 | } 40 | 41 | function navigateTo(url, arg=null) { 42 | let current_route = routeStack[routeStack.length-1] 43 | if (current_route.url === url) { 44 | return 45 | } 46 | 47 | console.log('(Route.qml)Route.navigateTo url:', url, 'arg:', JSON.stringify(arg)) 48 | routeStack.push({ 49 | url, 50 | arg 51 | }) 52 | navigateToCallback(url) 53 | } 54 | 55 | function redirectTo(url, arg=null) { 56 | let current_route = routeStack[routeStack.length-1] 57 | if (current_route.url === url) { 58 | return 59 | } 60 | 61 | console.log('(Route.qml)Route.redirectTo url:', url, 'arg:', JSON.stringify(arg)) 62 | routeStack[routeStack.length-1] = { 63 | url, 64 | arg 65 | } 66 | redirectToCallback(url) 67 | } 68 | 69 | function navigateBack(fail_url="/", count=1) { 70 | if (routeStack.length > 1) { 71 | routeStack.splice(routeStack.length-count, count) 72 | navigateBackCallback(count) 73 | } 74 | else { 75 | routeStack = [{ 76 | url: fail_url, 77 | arg: null, 78 | }] 79 | redirectToCallback(fail_url) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src_qml/common_component/Route/qmldir: -------------------------------------------------------------------------------- 1 | // qmldir 2 | singleton Route 1.0 Route.qml -------------------------------------------------------------------------------- /src_qml/common_component/SQL/QSQL/QSQL.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | import QtQuick.LocalStorage 2.15 5 | import "./persistence.js" as Persistence 6 | import "./persistence.store.sql.js" as PersistenceStoreSql 7 | 8 | QtObject { 9 | id: qsql 10 | property var connection: null 11 | property var db: { 12 | var the_db = Persistence.createPersistence() 13 | 14 | the_db.transaction = function (callback) { 15 | if (!connection) { 16 | throw new Error("No ongoing database connection, please connect first.") 17 | } else { 18 | connection.transaction(callback) 19 | } 20 | } 21 | 22 | the_db.store = the_db.store || {} 23 | the_db.store.sql = { 24 | defaultTypeMapper: PersistenceStoreSql.defaultTypeMapper, 25 | config: PersistenceStoreSql.config, 26 | }; 27 | 28 | var sqliteDialect = { 29 | // columns is an array of arrays, e.g. 30 | // [["id", "VARCHAR(32)", "PRIMARY KEY"], ["name", "TEXT"]] 31 | createTable: function (tableName, columns) { 32 | var tm = the_db.typeMapper; 33 | var sql = "CREATE TABLE IF NOT EXISTS `" + tableName + "` ("; 34 | var defs = []; 35 | for (var i = 0; i < columns.length; i++) { 36 | var column = columns[i]; 37 | defs.push("`" + column[0] + "` " + tm.columnType(column[1]) + (column[2] ? " " + column[2] : "")); 38 | } 39 | sql += defs.join(", "); 40 | sql += ')'; 41 | return sql; 42 | }, 43 | 44 | // columns is array of column names, e.g. 45 | // ["id"] 46 | createIndex: function (tableName, columns, options) { 47 | options = options || {}; 48 | return "CREATE " + (options.unique ? "UNIQUE " : "") + "INDEX IF NOT EXISTS `" + tableName + "__" + columns.join("_") + 49 | "` ON `" + tableName + "` (" + 50 | columns.map(function (col) { return "`" + col + "`"; }).join(", ") + ")"; 51 | } 52 | } 53 | 54 | the_db.store.sql.config(the_db, sqliteDialect) 55 | the_db.save = the_db.flush 56 | 57 | return the_db 58 | } 59 | 60 | function connect(arg) { 61 | const { identifier, version, description, estimatedSize } = arg 62 | console.log('(QSQL.qml)Connect datebase', JSON.stringify(arg)) 63 | qsql.connection = LocalStorage.openDatabaseSync( 64 | identifier, 65 | version, 66 | description, 67 | estimatedSize, 68 | function (db) { 69 | 70 | } 71 | ) 72 | if (qsql.connection.version === '') { 73 | // FIX: Error: SQL: database version mismatch 74 | qsql.connection.changeVersion('', version); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src_qml/common_component/SQL/QSQL/qmldir: -------------------------------------------------------------------------------- 1 | // qmldir 2 | singleton QSQL 1.0 QSQL.qml 3 | -------------------------------------------------------------------------------- /src_qml/common_component/SQL/SQLHelper/SQLTools.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | import "../QSQL" 5 | import "../../../common_js/Tools.js" as Tools 6 | 7 | Item { 8 | function getRangeQueryByField(field_name, kwarg) { 9 | let persistence = QSQL.db 10 | let min_field_value = kwarg['min_' + field_name] 11 | let max_field_value = kwarg['max_' + field_name] 12 | let field_value = kwarg[field_name] 13 | if (!Tools.isNone(field_value)) { 14 | return new persistence.PropertyFilter(field_name, '=', field_value) 15 | } 16 | if (Tools.isNone(min_field_value) && Tools.isNone(max_field_value)) { 17 | return null 18 | } 19 | let query = null 20 | if (!Tools.isNone(min_field_value)) { 21 | query = new persistence.PropertyFilter(field_name, '>=', min_field_value) 22 | } 23 | if (!Tools.isNone(max_field_value)) { 24 | if (query) { 25 | query = new persistence.AndFilter( 26 | query, 27 | new persistence.PropertyFilter(field_name, '<=', max_field_value) 28 | ) 29 | } 30 | else { 31 | query = new persistence.PropertyFilter(field_name, '<=', max_field_value) 32 | } 33 | } 34 | return query 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src_qml/common_component/SQL/SQLHelper/qmldir: -------------------------------------------------------------------------------- 1 | // qmldir 2 | singleton SQLTools 1.0 SQLTools.qml 3 | -------------------------------------------------------------------------------- /src_qml/common_component/SQL/sqml/CrudService.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | QtObject { 4 | id: service 5 | 6 | property DatabaseConnection connection 7 | readonly property alias dao: service.__dao 8 | property bool debug: connection != null ? connection.debug : false 9 | 10 | //protected: 11 | property CrudDao __dao 12 | 13 | function get(entity, callback, error) { 14 | error = error || __errorImpl; 15 | dao.get(entity, callback, error); 16 | } 17 | 18 | function getByEntity(entity, callback, error) { 19 | error = error || __errorImpl; 20 | dao.getByEntity(entity, callback, error); 21 | } 22 | 23 | function findList(entity, callback, error) { 24 | error = error || __errorImpl; 25 | dao.findList(entity, callback, error); 26 | } 27 | 28 | function insert(entity, callback, error) { 29 | error = error || __errorImpl; 30 | dao.insert(entity, callback, error); 31 | } 32 | 33 | function insertList(list, callback, error) { 34 | error = error || __errorImpl; 35 | dao.insertList(list, callback, error); 36 | } 37 | 38 | function update(entity, callback, error) { 39 | error = error || __errorImpl; 40 | dao.update(entity, callback, error); 41 | } 42 | 43 | function deleteById(entity, callback, error) { 44 | error = error || __errorImpl; 45 | dao.deleteById(entity, callback, error); 46 | } 47 | 48 | function deleteRecord(entity, callback, error) { 49 | error = error || __errorImpl; 50 | dao.deleteById(entity, callback, error); 51 | } 52 | 53 | function __errorImpl(error) { 54 | console.trace(); 55 | console.log(error); 56 | if(error instanceof Error) { 57 | throw error; 58 | } else { 59 | throw new Error(error); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src_qml/common_component/SQL/sqml/DatabaseConnection.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.LocalStorage 2.15 3 | 4 | // DatabaseConnection 5 | QtObject { 6 | id: databaseConnection 7 | 8 | property string identifier: "" 9 | property string version: "" 10 | property string description: "" 11 | property int estimatedSize: 0 12 | readonly property alias isOpen: databaseConnection.__isOpen 13 | property bool debug: false 14 | 15 | readonly property var database: databaseConnection.__database 16 | 17 | property var __database 18 | property bool __isOpen: false 19 | 20 | // onIdentifierChanged: { 21 | // __reOpen(); 22 | // } 23 | 24 | //@abstract 25 | function initDatabase(db) { 26 | } 27 | 28 | function __reOpen() { 29 | __isOpen = false; 30 | __tryOpen(); 31 | } 32 | 33 | function __tryOpen() { 34 | if(!__isOpen) { 35 | __openDatabase(); 36 | } 37 | } 38 | 39 | function __openDatabase() { 40 | if(__isOpen) { 41 | return; 42 | } 43 | 44 | __isOpen = true; 45 | 46 | console.debug("identifier", identifier, 47 | "version:", version, 48 | "description:", description, 49 | "estimatedSize:", estimatedSize); 50 | 51 | if(identifier !== '' && version !== '' && description !== '' && estimatedSize != 0) { 52 | try { 53 | __database = LocalStorage.openDatabaseSync(identifier, 54 | version, 55 | description, 56 | estimatedSize, 57 | initDatabase); 58 | 59 | if (__database.version === '') { 60 | // FIX: Error: SQL: database version mismatch 61 | __database.changeVersion('', version); 62 | } 63 | 64 | } catch(e) { 65 | __isOpen = false; 66 | console.trace() 67 | 68 | throw e; 69 | } 70 | } else { 71 | __isOpen = false; 72 | console.debug("identifier", identifier, 73 | "version:", version, 74 | "description:", description, 75 | "estimatedSize:", estimatedSize); 76 | throw "arguments lost!"; 77 | } 78 | } 79 | 80 | function changeVersion(from, to, callback) { 81 | __tryOpen(); 82 | 83 | if(typeof from === 'undefined' || from === '') { 84 | return; 85 | } 86 | 87 | if(typeof to === 'undefined' || to === '') { 88 | return; 89 | } 90 | 91 | if(from === to) { 92 | return; 93 | } 94 | 95 | database.changeVersion(from, to, callback); 96 | version = to; 97 | } 98 | 99 | function transaction(callback) { 100 | __tryOpen(); 101 | 102 | database.transaction(callback); 103 | } 104 | 105 | function readTransaction(callback) { 106 | __tryOpen(); 107 | 108 | database.readTransaction(callback); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src_qml/common_component/SQL/sqml/SqlMapping.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | // SqlMapping 4 | QtObject { 5 | id: sqlMapping 6 | 7 | property bool debug: false 8 | 9 | readonly property alias sqlQueryBuilder: sqlMapping.__sqlQueryBuilder 10 | 11 | readonly property SqlQueryBuilder __sqlQueryBuilder: SqlQueryBuilder { 12 | } 13 | 14 | //@abstract 15 | function get(entity) { 16 | return sqlQueryBuilder.dump(); 17 | } 18 | 19 | //@abstract 20 | function getByEntity(entity) { 21 | return sqlQueryBuilder.dump(); 22 | } 23 | 24 | //@abstract 25 | function findList(entity) { 26 | return sqlQueryBuilder.dump(); 27 | } 28 | 29 | //@abstract 30 | function insert(entity) { 31 | return sqlQueryBuilder.dump(); 32 | } 33 | 34 | //@abstract 35 | function insertList(list) { 36 | return sqlQueryBuilder.dump(); 37 | } 38 | 39 | //@abstract 40 | function update(entity) { 41 | return sqlQueryBuilder.dump(); 42 | } 43 | 44 | //@abstract 45 | function deleteById(entity) { 46 | return sqlQueryBuilder.dump(); 47 | } 48 | 49 | //@abstract 50 | function deleteRecord(entity) { 51 | return sqlQueryBuilder.dump(); 52 | } 53 | 54 | function stringNotEmpty(str) { 55 | return typeof str !== 'undefined' && str !== ''; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src_qml/common_component/SQL/sqml/qmldir: -------------------------------------------------------------------------------- 1 | module sqml 2 | 3 | # Simple layering CRUD for qml 4 | # The module identifier directive must be the first line of the file. Exactly one module identifier directive may exist in the qmldir file. 5 | 6 | CrudDao 1.0 CrudDao.qml 7 | CrudService 1.0 CrudService.qml 8 | DatabaseConnection 1.0 DatabaseConnection.qml 9 | SqlMapping 1.0 SqlMapping.qml 10 | SqlQueryBuilder 1.0 SqlQueryBuilder.qml 11 | -------------------------------------------------------------------------------- /src_qml/common_component/Timer/ExeOnceTimer/ExeOnceTimer.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "../../../common_js/Tools.js" as Tools 3 | 4 | Timer { 5 | id: timer 6 | interval: 0 7 | repeat: false 8 | running: false 9 | triggeredOnStart: false 10 | 11 | property var current_task_id: 0 12 | property var task_map: ({}) 13 | property var task_list: ([]) 14 | property var next_trigger_time: -1 15 | 16 | function exeOnceAtTime(func, mtimes) { 17 | task_map[current_task_id] = { 18 | func, 19 | mtimes, 20 | } 21 | current_task_id++ 22 | return current_task_id-1 23 | } 24 | 25 | function exe(task_id) { 26 | let task_info = task_map[task_id] 27 | 28 | if (!task_info) { 29 | return 30 | } 31 | 32 | let current_time = Date.parse(new Date()) 33 | let trigger_time = current_time+task_info.mtimes 34 | 35 | let in_list = false 36 | for (let i = 0; i < task_list.length; i++) { 37 | let task_in = task_list[i] 38 | if (task_in.task_id === task_id) { 39 | task_in.trigger_time = trigger_time 40 | in_list = true 41 | break 42 | } 43 | } 44 | if (!in_list) { 45 | task_list.push({ 46 | task_id, 47 | trigger_time, 48 | }) 49 | } 50 | if (timer.running) { 51 | if (trigger_time < next_trigger_time) { 52 | next_trigger_time = trigger_time 53 | timer.interval = task_info.mtimes 54 | timer.restart() 55 | } 56 | } 57 | else { 58 | next_trigger_time = trigger_time 59 | timer.interval = task_info.mtimes 60 | timer.start() 61 | } 62 | } 63 | 64 | onTriggered: { 65 | let current_time = Date.parse(new Date()) 66 | let new_task_list = [] 67 | let new_trigger_time = -1 68 | for (let i = 0; i < task_list.length; i++) { 69 | let the_task = task_list[i] 70 | if (the_task.trigger_time <= current_time) { 71 | let task_info = task_map[the_task.task_id] 72 | task_info.func() 73 | } 74 | else { 75 | new_task_list.push(the_task) 76 | if (new_trigger_time === -1 || new_trigger_time > the_task.trigger_time) { 77 | new_trigger_time = the_task.trigger_time 78 | } 79 | } 80 | } 81 | if (new_task_list.length > 0) { 82 | timer.task_list = new_task_list 83 | timer.next_trigger_time = new_trigger_time 84 | timer.interval = parseInt(new_trigger_time-current_time) 85 | timer.restart() 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src_qml/common_component/Timer/OnceTimer/OnceTimer.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "../../../common_js/Tools.js" as Tools 3 | 4 | Timer { 5 | id: timer 6 | interval: 0 7 | repeat: false 8 | running: false 9 | triggeredOnStart: false 10 | 11 | property var task_list: ([]) 12 | property var next_trigger_time: -1 13 | 14 | function setTimeout(func, mtimes) { 15 | let current_time = Date.parse(new Date()) 16 | let trigger_time = current_time+mtimes 17 | task_list.push({ 18 | func, 19 | trigger_time, 20 | }) 21 | if (timer.running) { 22 | if (trigger_time < next_trigger_time) { 23 | next_trigger_time = trigger_time 24 | timer.interval = mtimes 25 | timer.restart() 26 | } 27 | } 28 | else { 29 | next_trigger_time = trigger_time 30 | timer.interval = mtimes 31 | timer.start() 32 | } 33 | } 34 | 35 | onTriggered: { 36 | let current_time = Date.parse(new Date()) 37 | let new_task_list = [] 38 | let new_trigger_time = -1 39 | for (let i = 0; i < task_list.length; i++) { 40 | let the_task = task_list[i] 41 | if (the_task.trigger_time <= current_time) { 42 | the_task.func() 43 | } 44 | else { 45 | new_task_list.push(the_task) 46 | if (new_trigger_time === -1 || new_trigger_time > the_task.trigger_time) { 47 | new_trigger_time = the_task.trigger_time 48 | } 49 | } 50 | } 51 | if (new_task_list.length > 0) { 52 | timer.task_list = new_task_list 53 | timer.next_trigger_time = new_trigger_time 54 | timer.interval = parseInt(new_trigger_time-current_time) 55 | timer.restart() 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src_qml/common_image/Icon/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyQsmart/MaterialUI-QML/f423357a1293878bc481d2ad496211742e29cbd7/src_qml/common_image/Icon/logo.png -------------------------------------------------------------------------------- /src_qml/common_js/Color.js: -------------------------------------------------------------------------------- 1 | var none = '#00ffffff' 2 | var primary = '#2196f3' 3 | var background_primary = '#f9f9fc' 4 | // // background_primary: '#ecf0f5', 5 | var secondary = '#f50057' 6 | var text_primary = '#dd000000' // #1A1A1A 7 | var text_secondary = '#8590a5' // 原:rgba(0, 0, 0, 0.54) 8 | // transparent7_primary: 'rgba(33, 150, 243, 0.7)', 9 | // dark_primary: '#1c76d2', 10 | var gray = 'gray' 11 | var dark_gray = '#646464' 12 | // light_gray: '#f7f7f7', 13 | var white = '#ffffff' 14 | // transparent_white: 'rgba(255, 255, 255, 0.5)', 15 | // transparent95_white: 'rgba(255, 255, 255, 0.95)', 16 | var ddd = '#dddddd' 17 | var green = 'green' 18 | var greenyellow = 'greenyellow' 19 | // dark_green: 'rgb(1, 140, 117)', 20 | var black = 'black' 21 | // transparent_black: 'rgba(0, 0, 0, 0.5)', 22 | // transparent2_black: 'rgba(0, 0, 0, 0.2)', 23 | // blue: 'rgb(0, 123, 255)', 24 | // dark_blue: 'rgb(0, 119, 230)', 25 | // light_blue: '#81d4fa', 26 | // weak_blue: '#E3F2FD', 27 | // red: 'red', 28 | var orange_red = '#fc4a37' 29 | var orange = '#FF9800' 30 | var dark_yellow = '#FFC107' 31 | var gray_yellow = '#FDD835' 32 | -------------------------------------------------------------------------------- /src_qml/common_js/ComponentConfig.js: -------------------------------------------------------------------------------- 1 | var space_unit = 5 2 | -------------------------------------------------------------------------------- /src_qml/common_js/StringUtil.js: -------------------------------------------------------------------------------- 1 | var VERSION = '2023.06.12.11.53' 2 | -------------------------------------------------------------------------------- /src_qml/common_js/Tools.js: -------------------------------------------------------------------------------- 1 | var IMAGE_PROVIDER_NAME = 'image_provider' 2 | 3 | function pathJoin(path1, path2) { 4 | if (path1[path1.length-1] == '/') { 5 | path1 = path1.substring(0, path1.length-1) 6 | } 7 | return `${path1}/${path2}` 8 | } 9 | 10 | function getImagePathById(image_id) { 11 | if (isNone(image_id)) { 12 | return '' 13 | } 14 | 15 | return `image://${IMAGE_PROVIDER_NAME}/${image_id}` 16 | } 17 | 18 | function isNone(value) { 19 | if (value === undefined) 20 | return true 21 | if (value === null) 22 | return true 23 | if (typeof(value) == "number" && isNaN(value)) 24 | return true 25 | return false 26 | } 27 | 28 | function prefixZero(num, length) { 29 | return ('' + num).length < length ? ((new Array(length + 1)).join('0') + num).slice(-length) : '' + num; 30 | } 31 | 32 | function getTimeStamp() { 33 | let timestamp = Date.parse(new Date()) 34 | return parseInt(timestamp/1000) 35 | } 36 | 37 | function getTimeStampByDate(date) { 38 | return parseInt(new Date(date).getTime()/1000) 39 | } 40 | 41 | function getTimeByDate(date, format="%y.%M.%d %h:%mm.%s") { 42 | // console.log(date) 43 | format = format.replace("%MM", Tools.prefixZero(date.getMonth()+1, 2)) 44 | format = format.replace("%dd", Tools.prefixZero(date.getDate(), 2)) 45 | format = format.replace("%hh", Tools.prefixZero(date.getHours(), 2)) 46 | format = format.replace("%mm", Tools.prefixZero(date.getMinutes(), 2)) 47 | format = format.replace("%ss", Tools.prefixZero(date.getSeconds(), 2)) 48 | 49 | format = format.replace("%y", date.getFullYear()) 50 | format = format.replace("%M", date.getMonth()+1) 51 | format = format.replace("%d", date.getDate()) 52 | format = format.replace("%h", date.getHours()) 53 | format = format.replace("%m", date.getMinutes()) 54 | format = format.replace("%s", date.getSeconds()) 55 | return format 56 | } 57 | 58 | function getDateByStamp(time_stamp) { 59 | return new Date(time_stamp*1000) 60 | } 61 | 62 | function getTimeByStamp(timestamp, format="%y.%M.%d %h:%mm.%s") { 63 | let date = new Date(timestamp * 1000);//时间戳为10位需*1000,时间戳为13位的话不需乘1000 64 | format = format.replace("%MM", Tools.prefixZero(date.getMonth()+1, 2)) 65 | format = format.replace("%dd", Tools.prefixZero(date.getDate(), 2)) 66 | format = format.replace("%hh", Tools.prefixZero(date.getHours(), 2)) 67 | format = format.replace("%mm", Tools.prefixZero(date.getMinutes(), 2)) 68 | format = format.replace("%ss", Tools.prefixZero(date.getSeconds(), 2)) 69 | 70 | format = format.replace("%y", date.getFullYear()) 71 | format = format.replace("%M", date.getMonth()+1) 72 | format = format.replace("%d", date.getDate()) 73 | format = format.replace("%h", date.getHours()) 74 | format = format.replace("%m", date.getMinutes()) 75 | format = format.replace("%s", date.getSeconds()) 76 | return format 77 | } 78 | 79 | function getSecondTimeByStamp(timestamp, format="%hh:%mm:%ss") { 80 | let seconds = timestamp%60 81 | let minutes = (timestamp-seconds)/60 82 | let hours = (minutes-minutes%60)/60 83 | minutes = minutes%60 84 | format = format.replace("%hh", Tools.prefixZero(hours, 2)) 85 | format = format.replace("%mm", Tools.prefixZero(minutes, 2)) 86 | format = format.replace("%ss", Tools.prefixZero(seconds, 2)) 87 | 88 | format = format.replace("%h", hours) 89 | format = format.replace("%m", minutes) 90 | format = format.replace("%s", seconds) 91 | return format 92 | } 93 | -------------------------------------------------------------------------------- /src_qml/common_qml/GlobalTaskList.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | import QtQuick.Controls 2.15 5 | 6 | Item { 7 | property var download_list: ListModel { 8 | // const { download_link, file_name, file_path, m3u8, file_urls, pause, downloadFile } = item 9 | // const { url } = file_path[index] 10 | // const { gid, uri, out, status } = downloadFile[index] 11 | // const { base_uri, base_path, files } = m3u8 12 | // const { file } = files 13 | dynamicRoles: true 14 | } 15 | property var history_list: ListModel { 16 | dynamicRoles: true 17 | } 18 | property var trash_list: ListModel { 19 | dynamicRoles: true 20 | } 21 | 22 | Timer { 23 | id: set_timeout 24 | interval: 1000 25 | running: false 26 | repeat: false 27 | } 28 | 29 | function recoverFromDisk() { 30 | 31 | } 32 | 33 | function flushListToDisk() { 34 | 35 | } 36 | 37 | function deleteDownload(index, delete_file, callback) { 38 | pauseDownload(index, function() { 39 | let item = download_list.get(index) 40 | let save_path = Aria2Util.getTempSaveFolder(item.file_path, item.file_name) 41 | download_list.remove(index, 1) 42 | if (delete_file) { 43 | set_timeout.interval = 1000 44 | set_timeout.triggered.connect(function() { 45 | DownloadM3u8.deleteTempFolder(save_path) 46 | console.log("GlobalTaskList.DownloadM3u8.deleteTempFolder:", save_path) 47 | }) 48 | set_timeout.start() 49 | } 50 | else { 51 | console.log("GlobalTaskList.deleteDownload:need move to trash") 52 | } 53 | flushListToDisk() 54 | }) 55 | } 56 | 57 | function unpauseDownload(index, callback) { 58 | let download_item = download_list.get(index) 59 | let downloadFile = download_item.downloadFile 60 | let gid_list = [] 61 | for (let i = 0; i < downloadFile.count; i++) { 62 | let item = downloadFile.get(i) 63 | if (item.status !== "complete") { 64 | gid_list.push(item.gid) 65 | } 66 | } 67 | Aria2Util.multiUnpause(gid_list, function(res) { 68 | download_list.set(index, { 69 | pause: false, 70 | }) 71 | if (callback) { 72 | callback() 73 | } 74 | flushListToDisk() 75 | }) 76 | } 77 | 78 | function pauseDownload(index, callback) { 79 | let download_item = download_list.get(index) 80 | let downloadFile = download_item.downloadFile 81 | let gid_list = [] 82 | for (let i = 0; i < downloadFile.count; i++) { 83 | let item = downloadFile.get(i) 84 | if (item.status !== "complete") { 85 | gid_list.push(item.gid) 86 | } 87 | } 88 | Aria2Util.multiPause(gid_list, function(res) { 89 | download_list.set(index, { 90 | pause: true, 91 | }) 92 | if (callback) { 93 | callback() 94 | } 95 | flushListToDisk() 96 | }) 97 | } 98 | 99 | function refreshDownloadStatus(index) { 100 | var downloadSpeed = 0 101 | var uploadSpeed = 0 102 | var numActive = 0 103 | var numWaiting = 0 104 | var numStopped = 0 105 | 106 | let download_item = download_list.get(index) 107 | let downloadFile = download_item.downloadFile 108 | let gid_list = [] 109 | let gid_map = {} 110 | for (let i = 0; i < downloadFile.count; i++) { 111 | let item = downloadFile.get(i) 112 | if (item.status !== "complete") { 113 | gid_list.push(item.gid) 114 | gid_map[item.gid] = i 115 | } 116 | else { 117 | numStopped += 1 118 | } 119 | } 120 | 121 | Aria2Util.multicallTellStatus(gid_list, function(res) { 122 | for (let j = 0; j < res.length; j++) { 123 | let item = res[j][0] 124 | let ts_index = gid_map[item.gid] 125 | download_item.downloadFile.set(ts_index, { 126 | status: item.status, 127 | totalLength: item.totalLength, 128 | completedLength: item.completedLength, 129 | uploadLength: item.uploadLength, 130 | downloadSpeed: item.downloadSpeed, 131 | uploadSpeed: item.uploadSpeed, 132 | }) 133 | if (item.status === "active") { 134 | downloadSpeed += parseInt(item.downloadSpeed) 135 | } 136 | } 137 | download_list.set(index, { 138 | downloadSpeed, 139 | uploadSpeed, 140 | numActive, 141 | numWaiting, 142 | numStopped, 143 | numTotal: downloadFile.count, 144 | }) 145 | flushListToDisk() 146 | }) 147 | } 148 | 149 | function addDownloadItem(item) { 150 | download_list.append(item) 151 | flushListToDisk() 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src_qml/common_qml/QHttp.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | 5 | Item { 6 | function postJSON(url, arg, callback) { 7 | let xhr = new XMLHttpRequest() 8 | xhr.open("POST", url) 9 | xhr.setRequestHeader("Content-Type", "application/json") 10 | xhr.onreadystatechange = function() { 11 | // console.log("xhr.onreadystatechange") 12 | if (xhr.readyState == 4) { 13 | if (callback) { 14 | callback(xhr.responseText) 15 | } 16 | } 17 | } 18 | xhr.send(JSON.stringify(arg)) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src_qml/common_qml/qmldir: -------------------------------------------------------------------------------- 1 | // qmldir 2 | singleton QHttp 1.0 QHttp.qml 3 | singleton Aria2Util 1.0 Aria2Util.qml 4 | singleton GlobalTaskList 1.0 GlobalTaskList.qml 5 | -------------------------------------------------------------------------------- /src_qml/instance_component/AboutDialog/AboutDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls.Material 2.15 3 | import QtQuick.Controls 2.15 4 | import QtQuick.Layouts 1.15 5 | import QtQuick.Window 2.15 6 | import "../../common_component/MaterialUI" 7 | import "../../common_js/StringUtil.js" as Strings 8 | import "../../common_js/Color.js" as Color 9 | 10 | MDialog { 11 | id: aboutPopup 12 | width: 600 13 | height: 200 14 | padding: 20 15 | transitionComponent: MFade {} 16 | 17 | ColumnLayout { 18 | anchors.fill: parent 19 | spacing: 0 20 | 21 | RowLayout { 22 | ColumnLayout.fillWidth: true 23 | Layout.alignment: Qt.AlignLeft | Qt.AlignTop 24 | spacing: 0 25 | 26 | MTypography { 27 | variant: 'h6' 28 | text: qsTr("关于") 29 | RowLayout.fillWidth: true 30 | } 31 | 32 | MouseArea { 33 | width: 32 34 | height: 32 35 | cursorShape: Qt.PointingHandCursor 36 | 37 | MIcon { 38 | name: 'close' 39 | size: 20 40 | anchors.verticalCenter: parent.verticalCenter 41 | anchors.horizontalCenter: parent.horizontalCenter 42 | } 43 | 44 | onClicked: { 45 | aboutDialog.close() 46 | } 47 | } 48 | } 49 | 50 | RowLayout { 51 | Layout.topMargin: 20 52 | ColumnLayout.fillWidth: true 53 | ColumnLayout.fillHeight: true 54 | 55 | MTypography { 56 | wrapMode: Text.WrapAnywhere 57 | text: qsTr('MaterialUI库') 58 | } 59 | } 60 | 61 | MTypography { 62 | topPadding: 10 63 | ColumnLayout.fillWidth: true 64 | horizontalAlignment: Text.AlignRight 65 | text: qsTr('版本号:ver'+Strings.VERSION) 66 | textColor: 'textSecondary' 67 | variant: 'caption' 68 | } 69 | 70 | MTypography { 71 | topPadding: 10 72 | ColumnLayout.fillWidth: true 73 | horizontalAlignment: Text.AlignRight 74 | text: qsTr('Copyright © 2023') 75 | textColor: 'textSecondary' 76 | variant: 'caption' 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src_qml/instance_component/SQLTable/SettingData/SettingData.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.15 4 | import "../TableBase" 5 | import "../../../common_js/Tools.js" as Tools 6 | 7 | TableBase { 8 | table_name: 'SettingData' 9 | table_field: ({ 10 | name: 'TEXT', 11 | value: 'TEXT', 12 | }) 13 | 14 | function getValue(name, callback) { 15 | let query = getTable().all().filter('name', '=', name) 16 | query.list(null, (data)=>{ 17 | if (data.length === 0) { 18 | callback(null) 19 | } 20 | else { 21 | try { 22 | callback(JSON.parse(data[0].value)) 23 | } 24 | catch (e) { 25 | callback(null) 26 | } 27 | } 28 | }) 29 | } 30 | 31 | function setValue(name, value) { 32 | let query = getTable().all().filter('name', '=', name) 33 | query.list(null, (data)=>{ 34 | if (data.length === 0) { 35 | create({ 36 | name, 37 | value: JSON.stringify(value), 38 | }) 39 | } 40 | else { 41 | let the_data = data[0] 42 | the_data.value = JSON.stringify(value) 43 | save() 44 | } 45 | }) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src_qml/instance_component/SQLTable/SettingData/qmldir: -------------------------------------------------------------------------------- 1 | // qmldir 2 | singleton SettingData 1.0 SettingData.qml 3 | -------------------------------------------------------------------------------- /src_qml/instance_component/SQLTable/TableBase/TableBase.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import "../../../common_component/SQL/QSQL" 3 | import "../TableFactory" 4 | 5 | Item { 6 | id: table 7 | property string table_name: '' 8 | property var table_field: ({}) 9 | property var table_meta: null 10 | 11 | function getTable() { 12 | TableFactory.connect() 13 | TableFactory.migrateTable(table_name, table_field, function() { 14 | console.log(`(TableBase.qml)migrateTable success: ${table_name}`) 15 | }) 16 | if (!table_meta) { 17 | table_meta = QSQL.db.define(table_name, table_field) 18 | QSQL.db.schemaSync() 19 | } 20 | return table_meta 21 | } 22 | 23 | function create(arg) { 24 | console.log(JSON.stringify(arg)) 25 | let Table = table.getTable() 26 | let new_item = new Table(arg) 27 | QSQL.db.add(new_item) 28 | save() 29 | return new_item 30 | } 31 | 32 | function remove(item) { 33 | QSQL.db.remove(item) 34 | } 35 | 36 | function save(callback) { 37 | QSQL.db.save(null, callback) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src_qml/instance_component/SQLTable/TableFactory/qmldir: -------------------------------------------------------------------------------- 1 | // qmldir 2 | singleton TableFactory 1.0 TableFactory.qml 3 | -------------------------------------------------------------------------------- /src_qml/instance_component/SystemTray/SystemTray.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Window 2.15 3 | import QtQuick.Controls.Material 2.15 4 | import QtQuick.Controls 2.15 5 | import Qt.labs.platform 1.1 6 | 7 | SystemTrayIcon { 8 | signal showWindow() 9 | signal quitApp() 10 | 11 | visible: true 12 | icon.source: "../../common_image/Icon/logo.png" 13 | 14 | onActivated: { 15 | if (reason === SystemTrayIcon.Trigger) { 16 | showWindow() 17 | } 18 | } 19 | 20 | menu: Menu { 21 | MenuItem { 22 | text: qsTr("显示窗口") 23 | onTriggered: showWindow() 24 | } 25 | 26 | MenuItem { 27 | text: qsTr("退出") 28 | onTriggered: quitApp() 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src_qml/pages/Api/ButtonApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "Button" 5 | props_description: "Any other props supplied will be provided to the root Item (MButtonBase)." 6 | inheritance_description: "The props of the ButtonBase component are also available. You can take advantage of this behavior to target nested components." 7 | props_list: [ 8 | { 9 | name: "children", 10 | type: "Item", 11 | default_value: "", 12 | description: "The content of the button.", 13 | }, 14 | { 15 | name: "color", 16 | type: "'default'\n| 'primary'\n| 'secondary'\n| color", 17 | default_value: "'default'", 18 | description: "The color of the component. It supports those theme colors that make sense for this component.", 19 | }, 20 | { 21 | name: "disabled", 22 | type: "bool", 23 | default_value: "false", 24 | description: "If true, the button will be disabled.", 25 | }, 26 | { 27 | name: "disableCursor", 28 | type: "bool", 29 | default_value: "false", 30 | description: "[new] If true, the cursor style effect will be disabled.", 31 | }, 32 | { 33 | name: "disableElevation", 34 | type: "bool", 35 | default_value: "false", 36 | description: "If true, no elevation is used.", 37 | }, 38 | { 39 | name: "disableRipple", 40 | type: "bool", 41 | default_value: "false", 42 | description: "If true, the ripple effect will be disabled.", 43 | }, 44 | { 45 | name: "fontSize", 46 | type: "int", 47 | default_value: "", 48 | description: "[new] The text font size of the component. Usually, you do not need to change this prop.", 49 | }, 50 | { 51 | name: "size", 52 | type: "'large'\n| 'medium'\n| 'small'", 53 | default_value: "'medium'", 54 | description: "The size of the button. small is equivalent to the dense button styling.", 55 | }, 56 | { 57 | name: "text", 58 | type: "string", 59 | default_value: "", 60 | description: "The text content of the button.", 61 | }, 62 | { 63 | name: "textColor", 64 | type: "color", 65 | default_value: "", 66 | description: "[new] The text color of the component. If use this prop, ripple will be changed too.", 67 | }, 68 | { 69 | name: "variant", 70 | type: "'contained'\n| 'outlined'\n| 'text'", 71 | default_value: "'text'", 72 | description: "The variant to use.", 73 | }, 74 | ] 75 | demos_list: [ 76 | { 77 | name: "Button Group", 78 | url: "/buttongrouppage", 79 | }, 80 | { 81 | name: "Buttons", 82 | url: "/buttonpage", 83 | }, 84 | ] 85 | } 86 | -------------------------------------------------------------------------------- /src_qml/pages/Api/ButtonBaseApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "ButtonBase" 5 | props_description: "Any other props supplied will be provided to the root Item (native Button Item)." 6 | inheritance_description: "" 7 | props_list: [ 8 | { 9 | name: "children", 10 | type: "Item", 11 | default_value: "", 12 | description: "The content of the Item.", 13 | }, 14 | { 15 | name: "disabled", 16 | type: "bool", 17 | default_value: "false", 18 | description: "If true, the button will be disabled.", 19 | }, 20 | { 21 | name: "disableCursor", 22 | type: "bool", 23 | default_value: "false", 24 | description: "[new] If true, the cursor style effect will be disabled.", 25 | }, 26 | { 27 | name: "disableRipple", 28 | type: "bool", 29 | default_value: "false", 30 | description: "If true, the ripple effect will be disabled.", 31 | }, 32 | { 33 | name: "fontSize", 34 | type: "int", 35 | default_value: "", 36 | description: "[new] The text font size of the component. Usually, you do not need to change this prop.", 37 | }, 38 | { 39 | name: "text", 40 | type: "string", 41 | default_value: "", 42 | description: "The text content of the Item.", 43 | }, 44 | { 45 | name: "textColor", 46 | type: "color", 47 | default_value: "", 48 | description: "[new] The text color of the component. If use this prop, ripple will be changed too.", 49 | }, 50 | ] 51 | demos_list: [ 52 | { 53 | name: "Buttons", 54 | url: "/buttonpage", 55 | }, 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /src_qml/pages/Api/ButtonGroupApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "ButtonGroup" 5 | // props_description: "Any other props supplied will be provided to the root Item (MButtonBase)." 6 | // inheritance_description: "The props of the ButtonBase component are also available. You can take advantage of this behavior to target nested components." 7 | props_list: [ 8 | { 9 | name: "buttonColor", 10 | type: "'default'\n| 'inherit'\n| 'primary'\n| 'secondary'", 11 | default_value: "'default'", 12 | description: "The color of the component. It supports those theme colors that make sense for this component.", 13 | }, 14 | { 15 | name: "children", 16 | type: "MButton", 17 | default_value: "", 18 | description: "The content of the button group.", 19 | }, 20 | { 21 | name: "disabled", 22 | type: "bool", 23 | default_value: "false", 24 | description: "If true, the buttons will be disabled.", 25 | }, 26 | { 27 | name: "disableElevation", 28 | type: "bool", 29 | default_value: "false", 30 | description: "If true, no elevation is used.", 31 | }, 32 | { 33 | name: "disableRipple", 34 | type: "bool", 35 | default_value: "false", 36 | description: "If true, the ripple effect will be disabled.", 37 | }, 38 | { 39 | name: "orientation", 40 | type: "'horizontal'\n| 'vertical'", 41 | default_value: "'horizontal'", 42 | description: "The group orientation (layout flow direction).", 43 | }, 44 | { 45 | name: "size", 46 | type: "'large'\n| 'medium'\n| 'small'", 47 | default_value: "'medium'", 48 | description: "The size of the button. small is equivalent to the dense button styling.", 49 | }, 50 | { 51 | name: "variant", 52 | type: "'contained'\n| 'outlined'\n| 'text'", 53 | default_value: "'text'", 54 | description: "The variant to use.", 55 | }, 56 | ] 57 | demos_list: [ 58 | { 59 | name: "Button Group", 60 | url: "/buttongrouppage", 61 | }, 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /src_qml/pages/Api/CheckboxApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "Checkbox" 5 | props_list: [ 6 | { 7 | name: "checked", 8 | type: "bool", 9 | default_value: "", 10 | description: "If true, the component is checked.", 11 | }, 12 | { 13 | name: "color", 14 | type: "'default'\n| 'primary'\n| 'secondary'\n| color", 15 | default_value: "'secondary'", 16 | description: "The color of the component. It supports those theme colors that make sense for this component.", 17 | }, 18 | { 19 | name: "disabled", 20 | type: "bool", 21 | default_value: "false", 22 | description: "If true, the button will be disabled.", 23 | }, 24 | { 25 | name: "disableRipple", 26 | type: "bool", 27 | default_value: "false", 28 | description: "If true, the ripple effect will be disabled.", 29 | }, 30 | ] 31 | demos_list: [ 32 | { 33 | name: "Checkboxes", 34 | url: "/checkboxpage", 35 | }, 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /src_qml/pages/Api/CircularProgressApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "CircularProgress" 5 | props_list: [ 6 | { 7 | name: "color", 8 | type: "'primary'\n| 'secondary'\n| color", 9 | default_value: "'primary'", 10 | description: "The color of the component. It supports those theme colors that make sense for this component.", 11 | }, 12 | { 13 | name: "disableShrink", 14 | type: "bool", 15 | default_value: "false", 16 | description: "If true, the shrink animation is disabled. This only works if variant is indeterminate.", 17 | }, 18 | { 19 | name: "size", 20 | type: "number", 21 | default_value: "40", 22 | description: "The size of the circle.", 23 | }, 24 | { 25 | name: "thickness", 26 | type: "number", 27 | default_value: "3.6", 28 | description: "The thickness of the circle.", 29 | }, 30 | { 31 | name: "value", 32 | type: "number", 33 | default_value: "0", 34 | description: "The value of the progress indicator for the determinate variant. Value between 0 and 100.", 35 | }, 36 | { 37 | name: "variant", 38 | type: "'determinate'\n| 'indeterminate'\n| 'static'", 39 | default_value: "'indeterminate'", 40 | description: "The variant to use. Use indeterminate when there is no progress value.", 41 | }, 42 | ] 43 | demos_list: [ 44 | { 45 | name: "Progress", 46 | url: "/progresspage", 47 | }, 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /src_qml/pages/Api/ColorPickerApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "ColorPicker" 5 | props_description: "Any other props supplied will be provided to the root Item (MPopover)." 6 | inheritance_description: "The props of the Popover component are also available. You can take advantage of this behavior to target nested components." 7 | props_list: [ 8 | { 9 | name: "initColor", 10 | type: "color", 11 | default_value: "#000000", 12 | description: "The init color of the component.", 13 | }, 14 | { 15 | name: "onChange", 16 | type: "func", 17 | default_value: "", 18 | description: "Callback when select done, callback with a color param", 19 | }, 20 | ] 21 | demos_list: [ 22 | { 23 | name: "Color Picker", 24 | url: "/colorpickerpage", 25 | }, 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /src_qml/pages/Api/ComplexSelectApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "Complex Select" 5 | props_list: [ 6 | { 7 | name: "children", 8 | type: "Item", 9 | default_value: "", 10 | description: "The option elements to populate the select with. Can be some MenuItem.The MenuItem elements must define value (and label) property.", 11 | }, 12 | { 13 | name: "disabled", 14 | type: "bool", 15 | default_value: "false", 16 | description: "If true, the select will be disabled.", 17 | }, 18 | { 19 | name: "index", 20 | type: "int", 21 | default_value: "", 22 | description: "The select index.", 23 | }, 24 | { 25 | name: "maxWidth", 26 | type: "double", 27 | default_value: "", 28 | description: "[new] Max width of the select", 29 | }, 30 | { 31 | name: "minWidth", 32 | type: "double", 33 | default_value: "0", 34 | description: "[new] Min width of the select", 35 | }, 36 | { 37 | name: "padding", 38 | type: "list", 39 | default_value: "", 40 | description: "[new] Padding ofr the select", 41 | }, 42 | { 43 | name: "placeholder", 44 | type: "string", 45 | default_value: "", 46 | description: "The short hint displayed in the select before the user selects a value.", 47 | }, 48 | { 49 | name: "selectColor", 50 | type: "'primary'\n| 'secondary'\n| color", 51 | default_value: "'primary'", 52 | description: "[new] The select color of the component.", 53 | }, 54 | { 55 | name: "value", 56 | type: "string", 57 | default_value: "", 58 | description: "The select value. Providing an empty string will select no options. Set to an empty string '' if you don't want any of the available options to be selected. The string representation must match with the string representation of the model in order to be selected.", 59 | }, 60 | { 61 | name: "variant", 62 | type: "'filled'\n| 'outlined'\n| 'standard'", 63 | default_value: "'standard'", 64 | description: "The variant to use.", 65 | }, 66 | ] 67 | demos_list: [ 68 | { 69 | name: "Selects", 70 | url: "/selectpage", 71 | }, 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /src_qml/pages/Api/DatePickerApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "DatePicker" 5 | props_list: [ 6 | { 7 | name: "color", 8 | type: "'primary'\n| 'secondary'\n| color", 9 | default_value: "'primary'", 10 | description: "The color of the component. It supports those theme colors that make sense for this component.", 11 | }, 12 | { 13 | name: "disabled", 14 | type: "bool", 15 | default_value: "false", 16 | description: "If true, the picker will be disabled.", 17 | }, 18 | { 19 | name: "size", 20 | type: "'medium'\n| 'small'", 21 | default_value: "'medium'", 22 | description: "The size of the picker. small is equivalent to the dense picker styling.", 23 | }, 24 | { 25 | name: "value", 26 | type: "Date", 27 | default_value: "new Date()", 28 | description: "The date value.", 29 | }, 30 | { 31 | name: "variant", 32 | type: "'standard'\n| 'outlined'\n| 'filled'", 33 | default_value: "'standard'", 34 | description: "The variant to use.", 35 | }, 36 | ] 37 | demos_list: [ 38 | { 39 | name: "Date/Time Pickers", 40 | url: "/datetimepickerpage", 41 | }, 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /src_qml/pages/Api/FormControlLabelApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "FormControlLabel" 5 | props_list: [ 6 | { 7 | name: "checked", 8 | type: "bool", 9 | default_value: "", 10 | description: "If true, the component appears selected.", 11 | }, 12 | { 13 | name: "control", 14 | type: "'Item", 15 | default_value: "", 16 | description: "A control element. For instance, it can be be a Radio, a Switch or a Checkbox.", 17 | }, 18 | { 19 | name: "disabled", 20 | type: "bool", 21 | default_value: "false", 22 | description: "If true, the button will be disabled.", 23 | }, 24 | { 25 | name: "label", 26 | type: "string", 27 | default_value: "", 28 | description: "The text to be used in an enclosing label element.", 29 | }, 30 | { 31 | name: "labelPlacement", 32 | type: "'bottom'\n| 'end'\n| 'start'\n| 'top'", 33 | default_value: "false", 34 | description: "The position of the label.", 35 | }, 36 | { 37 | name: "value", 38 | type: "string", 39 | default_value: "", 40 | description: "The value of the component.", 41 | }, 42 | ] 43 | demos_list: [ 44 | { 45 | name: "Checkboxes", 46 | url: "/checkboxpage", 47 | }, 48 | { 49 | name: "Radio Buttons", 50 | url: "/radiopage", 51 | }, 52 | { 53 | name: "Switches", 54 | url: "/switchpage", 55 | }, 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /src_qml/pages/Api/FramelessWindowApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "Button" 5 | props_description: "Any other props supplied will be provided to the root Item (Window)." 6 | inheritance_description: "The props of the Window component are also available. You can take advantage of this behavior to target nested components." 7 | props_list: [ 8 | { 9 | name: "backgroundColor", 10 | type: "color", 11 | default_value: "'#ffffff'", 12 | description: "The background color of the component.", 13 | }, 14 | { 15 | name: "darkMode", 16 | type: "bool", 17 | default_value: "false", 18 | description: "If true, the window will render in dark mode.", 19 | }, 20 | { 21 | name: "disableCloseButton", 22 | type: "bool", 23 | default_value: "false", 24 | description: "If true, the close button will be disabled.", 25 | }, 26 | { 27 | name: "disableMaximizeButton", 28 | type: "bool", 29 | default_value: "false", 30 | description: "If true, the close maximize will be disabled.", 31 | }, 32 | { 33 | name: "disableMinimizeButton", 34 | type: "bool", 35 | default_value: "false", 36 | description: "If true, the close minimize will be disabled.", 37 | }, 38 | { 39 | name: "dragBar", 40 | type: "Item", 41 | default_value: "", 42 | description: "[realonly] You can access to the dragBar, and change dragBar's property.", 43 | }, 44 | { 45 | name: "enableBorderShadow", 46 | type: "bool", 47 | default_value: "true", 48 | description: "If false, the system border shadow will be disabled.", 49 | }, 50 | { 51 | name: "macSystemButtonBar", 52 | type: "Item", 53 | default_value: "", 54 | description: "[realonly] You can access to the macSystemButtonBar, and change macSystemButtonBar's property.", 55 | }, 56 | { 57 | name: "macSystemButtonBar", 58 | type: "string", 59 | default_value: "Qt.platform.os === 'osx' ? 'mac' : 'win'", 60 | description: "The system type of the window.", 61 | }, 62 | { 63 | name: "winSystemButtonBar", 64 | type: "Item", 65 | default_value: "", 66 | description: "[realonly] You can access to the winSystemButtonBar, and change winSystemButtonBar's property.", 67 | }, 68 | ] 69 | demos_list: [ 70 | { 71 | name: "Frameless Window", 72 | url: "/framelesswindowpage", 73 | }, 74 | ] 75 | } 76 | -------------------------------------------------------------------------------- /src_qml/pages/Api/IconApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "Icon" 5 | props_description: "Any other props supplied will be provided to the root Item (native Text Item)." 6 | inheritance_description: "The props of the Text component are also available. You can take advantage of this behavior to target nested components." 7 | props_list: [ 8 | { 9 | name: "children", 10 | type: "Item", 11 | default_value: "", 12 | description: "The content of the Item.", 13 | }, 14 | { 15 | name: "name", 16 | type: "string", 17 | default_value: "", 18 | description: "The name of the icon.", 19 | }, 20 | { 21 | name: "size", 22 | type: "int", 23 | default_value: "", 24 | description: "The fontSize applied to the icon.", 25 | }, 26 | { 27 | name: "text", 28 | type: "string", 29 | default_value: "", 30 | description: "The text content of the Item.This will override name.", 31 | }, 32 | ] 33 | demos_list: [ 34 | { 35 | name: "Icons", 36 | url: "/iconpage", 37 | }, 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /src_qml/pages/Api/LinearProgressApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "LinearProgress" 5 | props_list: [ 6 | { 7 | name: "color", 8 | type: "'primary'\n| 'secondary'\n| color", 9 | default_value: "'primary'", 10 | description: "The color of the component. It supports those theme colors that make sense for this component.", 11 | }, 12 | { 13 | name: "value", 14 | type: "number", 15 | default_value: "0", 16 | description: "The value of the progress indicator for the determinate and buffer variants. Value between 0 and 100.", 17 | }, 18 | { 19 | name: "valueBuffer", 20 | type: "number", 21 | default_value: "100", 22 | description: "The value for the buffer variant. Value between 0 and 100.", 23 | }, 24 | { 25 | name: "variant", 26 | type: "'buffer'\n| 'determinate'\n| 'indeterminate'\n| 'query'", 27 | default_value: "'indeterminate'", 28 | description: "The variant to use. Use indeterminate or query when there is no progress value.", 29 | }, 30 | ] 31 | demos_list: [ 32 | { 33 | name: "Progress", 34 | url: "/progresspage", 35 | }, 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /src_qml/pages/Api/PaperApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "Paper" 5 | props_description: "Any other props supplied will be provided to the root Item (native Rectangle Item)." 6 | inheritance_description: "The props of the Rectangle component are also available. You can take advantage of this behavior to target nested components." 7 | props_list: [ 8 | { 9 | name: "children", 10 | type: "Item", 11 | default_value: "", 12 | description: "The content of the Item.", 13 | }, 14 | { 15 | name: "elevation", 16 | type: "int", 17 | default_value: "1", 18 | description: "Shadow depth, corresponds to dp in the spec. It accepts values between 0 and 24 inclusive.", 19 | }, 20 | { 21 | name: "square", 22 | type: "bool", 23 | default_value: "false", 24 | description: "If true, rounded corners are disabled.", 25 | }, 26 | { 27 | name: "variant", 28 | type: "'elevation'\n| 'outlined'", 29 | default_value: "'elevation'", 30 | description: "The variant to use.", 31 | }, 32 | ] 33 | demos_list: [ 34 | { 35 | name: "Cards", 36 | // url: "/iconpage", 37 | }, 38 | { 39 | name: "Paper", 40 | url: "/paperpage", 41 | }, 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /src_qml/pages/Api/PropsTable.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Layouts 1.15 3 | import "../../common_component/MaterialUI" 4 | import "../../common_component/MaterialUI/styles" 5 | import "../../common_qml" 6 | 7 | ColumnLayout { 8 | property var propsList: [] 9 | 10 | Row { 11 | Layout.leftMargin: 20 12 | Layout.rightMargin: 20 13 | Layout.topMargin: 20 14 | Layout.fillWidth: true 15 | 16 | Column { 17 | width: parent.width/5 18 | leftPadding: 10 19 | bottomPadding: 10 20 | 21 | MTypography { 22 | text: "Name" 23 | font.weight: Font.DemiBold 24 | } 25 | } 26 | Column { 27 | width: parent.width/5 28 | bottomPadding: 10 29 | 30 | MTypography { 31 | text: "Type" 32 | font.weight: Font.DemiBold 33 | } 34 | } 35 | Column { 36 | width: parent.width/5 37 | bottomPadding: 10 38 | 39 | MTypography { 40 | text: "Default" 41 | font.weight: Font.DemiBold 42 | } 43 | 44 | } 45 | Column { 46 | width: parent.width*2/5 47 | bottomPadding: 10 48 | 49 | MTypography { 50 | text: "Description" 51 | font.weight: Font.DemiBold 52 | } 53 | } 54 | } 55 | 56 | MDivider { 57 | Layout.fillWidth: true 58 | Layout.leftMargin: 20 59 | Layout.rightMargin: 20 60 | } 61 | 62 | Repeater { 63 | model: propsList 64 | 65 | Column { 66 | Layout.fillWidth: true 67 | Layout.leftMargin: 20 68 | Layout.rightMargin: 20 69 | 70 | Row { 71 | id: row 72 | topPadding: 20 73 | bottomPadding: 20 74 | width: parent.width 75 | 76 | Column { 77 | width: parent.width/5 78 | anchors.verticalCenter: parent.verticalCenter 79 | leftPadding: 10 80 | 81 | MTypography { 82 | width: parent.width 83 | text: modelData.name 84 | } 85 | } 86 | Column { 87 | width: parent.width/5 88 | anchors.verticalCenter: parent.verticalCenter 89 | 90 | MTypography { 91 | width: parent.width 92 | color: Palette.secondaryDark 93 | text: modelData.type 94 | } 95 | } 96 | Column { 97 | width: parent.width/5 98 | anchors.verticalCenter: parent.verticalCenter 99 | 100 | MTypography { 101 | width: parent.width 102 | text: modelData.default_value ? modelData.default_value : " " 103 | } 104 | 105 | } 106 | Column { 107 | width: parent.width*2/5 108 | anchors.verticalCenter: parent.verticalCenter 109 | 110 | MTypography { 111 | width: parent.width 112 | text: modelData.description 113 | } 114 | } 115 | } 116 | MDivider { 117 | width: parent.width 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src_qml/pages/Api/RadioApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "Radio" 5 | props_list: [ 6 | { 7 | name: "checked", 8 | type: "bool", 9 | default_value: "", 10 | description: "If true, the component is checked.", 11 | }, 12 | { 13 | name: "color", 14 | type: "'default'\n| 'primary'\n| 'secondary'\n| color", 15 | default_value: "'secondary'", 16 | description: "The color of the component. It supports those theme colors that make sense for this component.", 17 | }, 18 | { 19 | name: "disabled", 20 | type: "bool", 21 | default_value: "false", 22 | description: "If true, the button will be disabled.", 23 | }, 24 | { 25 | name: "disableRipple", 26 | type: "bool", 27 | default_value: "false", 28 | description: "If true, the ripple effect will be disabled.", 29 | }, 30 | { 31 | name: "value", 32 | type: "string", 33 | default_value: "", 34 | description: "The value of the component. The DOM API casts this to a string.", 35 | }, 36 | ] 37 | demos_list: [ 38 | { 39 | name: "Radio Buttons", 40 | url: "/radiopage", 41 | }, 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /src_qml/pages/Api/RadioGroupApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "RadioGroup" 5 | props_list: [ 6 | { 7 | name: "children", 8 | type: "MRadio\n| MFormControlLabel", 9 | default_value: "", 10 | description: "The content of the component.", 11 | }, 12 | { 13 | name: "value", 14 | type: "string", 15 | default_value: "", 16 | description: "The value of the component. The DOM API casts this to a string.", 17 | }, 18 | ] 19 | demos_list: [ 20 | { 21 | name: "Radio Buttons", 22 | url: "/radiopage", 23 | }, 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /src_qml/pages/Api/SelectApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "Select" 5 | props_list: [ 6 | { 7 | name: "disabled", 8 | type: "bool", 9 | default_value: "false", 10 | description: "If true, the select will be disabled.", 11 | }, 12 | { 13 | name: "index", 14 | type: "int", 15 | default_value: "", 16 | description: "The select index.", 17 | }, 18 | { 19 | name: "maxWidth", 20 | type: "double", 21 | default_value: "", 22 | description: "[new] Max width of the select", 23 | }, 24 | { 25 | name: "minWidth", 26 | type: "double", 27 | default_value: "0", 28 | description: "[new] Min width of the select", 29 | }, 30 | { 31 | name: "model", 32 | type: "list", 33 | default_value: "", 34 | description: "The elements of the select.", 35 | }, 36 | { 37 | name: "padding", 38 | type: "list", 39 | default_value: "", 40 | description: "[new] Padding ofr the select", 41 | }, 42 | { 43 | name: "placeholder", 44 | type: "string", 45 | default_value: "", 46 | description: "The short hint displayed in the select before the user selects a value.", 47 | }, 48 | { 49 | name: "selectColor", 50 | type: "'primary'\n| 'secondary'\n| color", 51 | default_value: "'primary'", 52 | description: "[new] The select color of the component.", 53 | }, 54 | { 55 | name: "value", 56 | type: "string", 57 | default_value: "", 58 | description: "The select value. Providing an empty string will select no options. Set to an empty string '' if you don't want any of the available options to be selected. The string representation must match with the string representation of the model in order to be selected.", 59 | }, 60 | { 61 | name: "variant", 62 | type: "'filled'\n| 'outlined'\n| 'standard'", 63 | default_value: "'standard'", 64 | description: "The variant to use.", 65 | }, 66 | ] 67 | demos_list: [ 68 | { 69 | name: "Selects", 70 | url: "/selectpage", 71 | }, 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /src_qml/pages/Api/SliderApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "Slider" 5 | props_list: [ 6 | { 7 | name: "color", 8 | type: "'primary'\n| 'secondary'\n| color", 9 | default_value: "'primary'", 10 | description: "The color of the component. It supports those theme colors that make sense for this component.", 11 | }, 12 | { 13 | name: "disabled", 14 | type: "bool", 15 | default_value: "false", 16 | description: "If true, the slider will be disabled.", 17 | }, 18 | { 19 | name: "marks", 20 | type: "bool", 21 | default_value: "false", 22 | description: "Marks indicate predetermined values to which the user can move the slider. If true the marks will be spaced according the value of the step prop. ", 23 | }, 24 | 25 | { 26 | name: "max", 27 | type: "number", 28 | default_value: "100", 29 | description: "The maximum allowed value of the slider. Should not be equal to min.", 30 | }, 31 | { 32 | name: "min", 33 | type: "number", 34 | default_value: "0", 35 | description: "The minimum allowed value of the slider. Should not be equal to max.", 36 | }, 37 | { 38 | name: "orientation", 39 | type: "'horizontal'\n| 'vertical'", 40 | default_value: "'horizontal'", 41 | description: "The slider orientation.", 42 | }, 43 | { 44 | name: "step", 45 | type: "number", 46 | default_value: "1", 47 | description: "The granularity with which the slider can step through values. (A \"discrete\" slider.) The min prop serves as the origin for the valid values. We recommend (max - min) to be evenly divisible by the step.When step is null, the thumb can only be slid onto marks provided with the marks prop.", 48 | }, 49 | { 50 | name: "value", 51 | type: "number", 52 | default_value: "0", 53 | description: "The element value.", 54 | }, 55 | { 56 | name: "valueLabelDisplay", 57 | type: "'on'\n| 'auto'\m| 'off'", 58 | default_value: "'off'", 59 | description: "Controls when the value label is displayed: - auto the value label will display when the thumb is hovered or focused. - on will display persistently. - off will never display.", 60 | }, 61 | { 62 | name: "valueLabelFormat", 63 | type: "func", 64 | default_value: "(x) => x", 65 | description: "The format function the value label's value.When a function is provided, it should have the following signature: - {number} value The value label's value to format", 66 | }, 67 | ] 68 | demos_list: [ 69 | { 70 | name: "Slider", 71 | url: "/sliderpage", 72 | }, 73 | ] 74 | } 75 | -------------------------------------------------------------------------------- /src_qml/pages/Api/SvgIconApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "SvgIcon" 5 | props_list: [ 6 | { 7 | name: "color", 8 | type: "'default'\n| 'primary'\n| 'secondary'\n| 'textSecondary'\n| 'error'\n| color", 9 | default_value: "", 10 | description: "The color of the icon.", 11 | }, 12 | { 13 | name: "fontSize", 14 | type: "'small'\n| 'medium'\n| 'large'", 15 | default_value: "'medium'", 16 | description: "The fontSize applied to the icon.", 17 | }, 18 | { 19 | name: "name", 20 | type: "string", 21 | default_value: "", 22 | description: "The name of the icon.", 23 | }, 24 | { 25 | name: "size", 26 | type: "real", 27 | default_value: "", 28 | description: "The size applied to the icon.This will override fontSize.", 29 | }, 30 | { 31 | name: "variant", 32 | type: "'filled'\n| 'outliend'\n| 'rounded'\n| 'two tone'\n| 'sharp'", 33 | default_value: "'filled'", 34 | description: "The variant of the Icon.", 35 | }, 36 | ] 37 | demos_list: [ 38 | { 39 | name: "Icons", 40 | url: "/iconpage", 41 | }, 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /src_qml/pages/Api/SwitchApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "Switch" 5 | props_list: [ 6 | { 7 | name: "checked", 8 | type: "bool", 9 | default_value: "", 10 | description: "If true, the component is checked.", 11 | }, 12 | { 13 | name: "color", 14 | type: "'default'\n| 'primary'\n| 'secondary'\n| color", 15 | default_value: "'secondary'", 16 | description: "The color of the component. It supports those theme colors that make sense for this component.", 17 | }, 18 | { 19 | name: "disabled", 20 | type: "bool", 21 | default_value: "false", 22 | description: "If true, the button will be disabled.", 23 | }, 24 | { 25 | name: "disableRipple", 26 | type: "bool", 27 | default_value: "false", 28 | description: "If true, the ripple effect will be disabled.", 29 | }, 30 | { 31 | name: "value", 32 | type: "string", 33 | default_value: "", 34 | description: "The value of the component. ", 35 | }, 36 | ] 37 | demos_list: [ 38 | { 39 | name: "Switches", 40 | url: "/switchpage", 41 | }, 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /src_qml/pages/Api/TextFieldApi.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "TextField" 5 | props_list: [ 6 | { 7 | name: "color", 8 | type: "'primary'\n| 'secondary'", 9 | default_value: "'primary'", 10 | description: "The color of the component. It supports those theme colors that make sense for this component.", 11 | }, 12 | { 13 | name: "disabled", 14 | type: "bool", 15 | default_value: "false", 16 | description: "If true, the input will be disabled.", 17 | }, 18 | { 19 | name: "placeholder", 20 | type: "string", 21 | default_value: "", 22 | description: "The short hint displayed in the input before the user enters a value.", 23 | }, 24 | { 25 | name: "size", 26 | type: "'medium'\n| 'small'", 27 | default_value: "'medium'", 28 | description: "The size of the text field.", 29 | }, 30 | { 31 | name: "variant", 32 | type: "'filled'\n| 'outlined'\n| 'standard'", 33 | default_value: "'standard'", 34 | description: "The variant to use.", 35 | }, 36 | ] 37 | demos_list: [ 38 | { 39 | name: "Text Fields", 40 | url: "/textfieldpage", 41 | }, 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /src_qml/pages/Api/TimePicker.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | 3 | BaseApi { 4 | name: "TimePicker" 5 | props_list: [ 6 | { 7 | name: "color", 8 | type: "'primary'\n| 'secondary'\n| color", 9 | default_value: "'primary'", 10 | description: "The color of the component. It supports those theme colors that make sense for this component.", 11 | }, 12 | { 13 | name: "disabled", 14 | type: "bool", 15 | default_value: "false", 16 | description: "If true, the picker will be disabled.", 17 | }, 18 | { 19 | name: "size", 20 | type: "'medium'\n| 'small'", 21 | default_value: "'medium'", 22 | description: "The size of the picker. small is equivalent to the dense picker styling.", 23 | }, 24 | { 25 | name: "value", 26 | type: "Date", 27 | default_value: "new Date()", 28 | description: "The date value.", 29 | }, 30 | { 31 | name: "variant", 32 | type: "'standard'\n| 'outlined'\n| 'filled'", 33 | default_value: "'standard'", 34 | description: "The variant to use.", 35 | }, 36 | ] 37 | demos_list: [ 38 | { 39 | name: "Date/Time Pickers", 40 | url: "/datetimepickerpage", 41 | }, 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /src_qml/pages/Display/FontAwesomeIconPage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | import QtQuick.Layouts 1.15 4 | import "../../common_component/MaterialUI" 5 | import "../../common_component/MaterialUI/styles" 6 | import "../../common_component/Route" 7 | import "../../common_qml" 8 | import "../../common_js/Color.js" as Color 9 | import "../../common_js/Tools.js" as Tools 10 | import "../../common_component/MaterialUI/Font/IconsName.js" as IconsName 11 | 12 | Pane { 13 | id: container 14 | x: 0 15 | y: 0 16 | padding: 0 17 | 18 | RowLayout { 19 | id: main_area 20 | anchors.fill: parent 21 | spacing: 0 22 | 23 | MOverflowYBox { 24 | RowLayout.fillHeight: true 25 | RowLayout.fillWidth: true 26 | 27 | ColumnLayout { 28 | width: main_area.width 29 | spacing: 0 30 | 31 | Column { 32 | Layout.fillWidth: true 33 | leftPadding: 20 34 | rightPadding: 20 35 | topPadding: 20 36 | 37 | MTypography { 38 | width: parent.width-40 39 | variant: "h4" 40 | text: "FontAwesome Icons 图标" 41 | } 42 | 43 | MTypography { 44 | width: parent.width-40 45 | variant: "h5" 46 | text: "你可以在使用 1400 多个 FontAwesome icons。" 47 | gutterBottom: true 48 | } 49 | } 50 | 51 | Rectangle { 52 | Layout.fillWidth: true 53 | Layout.leftMargin: 20 54 | Layout.rightMargin: 20 55 | height: childrenRect.height 56 | implicitHeight: height 57 | border.width: 1 58 | border.color: Color.ddd 59 | radius: 4 60 | 61 | Flow { 62 | width: parent.width-40 63 | spacing: 20 64 | padding: 20 65 | anchors.horizontalCenter: parent.horizontalCenter 66 | 67 | Repeater { 68 | property var keys: Object.keys(IconsName.name).sort() 69 | model: keys 70 | delegate: Column { 71 | width: 160 72 | 73 | MIcon { 74 | size: 20 75 | name: modelData 76 | anchors.horizontalCenter: parent.horizontalCenter 77 | } 78 | 79 | MTypography { 80 | variant: 'caption' 81 | text: modelData 82 | anchors.horizontalCenter: parent.horizontalCenter 83 | } 84 | } 85 | } 86 | } 87 | } 88 | 89 | 90 | 91 | // API 92 | 93 | Column { 94 | Layout.fillWidth: true 95 | leftPadding: 20 96 | rightPadding: 20 97 | topPadding: 40 98 | 99 | MTypography { 100 | variant: "h5" 101 | text: "API" 102 | gutterBottom: true 103 | } 104 | 105 | RowLayout { 106 | MTypography { 107 | variant: "body1" 108 | text: "○" 109 | } 110 | MButton { 111 | color: "secondary" 112 | text: "MIcon { }" 113 | onClicked: { 114 | Route.redirectTo("/api/icon") 115 | } 116 | } 117 | } 118 | } 119 | 120 | 121 | Rectangle { 122 | Layout.fillWidth: true 123 | height: 20 124 | } 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src_qml/pages/HomePage/HomePage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | import QtQuick.Layouts 1.15 4 | import "../../common_component/MaterialUI" 5 | import "../../common_component/Route" 6 | import "../../common_qml" 7 | import "../../common_js/Color.js" as Color 8 | import "../../common_js/Tools.js" as Tools 9 | 10 | Pane { 11 | id: container 12 | x: 0 13 | y: 0 14 | padding: 0 15 | 16 | RowLayout { 17 | id: main_area 18 | anchors.fill: parent 19 | spacing: 0 20 | 21 | Rectangle { 22 | id: right_area 23 | RowLayout.fillHeight: true 24 | RowLayout.fillWidth: true 25 | 26 | ColumnLayout { 27 | anchors.fill: parent 28 | spacing: 0 29 | 30 | Rectangle { 31 | RowLayout.fillHeight: true 32 | } 33 | 34 | MTypography { 35 | Layout.alignment: Qt.AlignHCenter 36 | text: "MaterialUI-QML" 37 | textColor: "primary" 38 | fontSize: 48 39 | } 40 | 41 | MTypography { 42 | Layout.alignment: Qt.AlignHCenter 43 | text: "QML组件用于更快速、更简便的QML开发。" 44 | textColor: "primary" 45 | fontSize: 24 46 | } 47 | 48 | Rectangle { 49 | RowLayout.fillHeight: true 50 | } 51 | } 52 | } 53 | } 54 | } 55 | --------------------------------------------------------------------------------