diff --git a/client/amnizia-client.pro b/client/amnizia-client.pro new file mode 100644 index 000000000..077b7c9b9 --- /dev/null +++ b/client/amnizia-client.pro @@ -0,0 +1,102 @@ +QT += widgets core gui network xml + +TARGET = amnezia-client +TEMPLATE = app + +DEFINES += QT_DEPRECATED_WARNINGS + + +win32 { + +#win32-g++ { +# QMAKE_CXXFLAGS += -Werror +#} +#win32-msvc*{ +# QMAKE_CXXFLAGS += /WX +#} + +FORMS += ui/mainwindow.ui + +RESOURCES += \ + res.qrc + +OTHER_FILES += platform_win/vpnclient.rc +RC_FILE = platform_win/vpnclient.rc + +HEADERS += publib/winhelp.h + +SOURCES += publib/winhelp.cpp + +CONFIG -= embed_manifest_exe +DEFINES += _CRT_SECURE_NO_WARNINGS VPNCLIENT_TAPSIGNED +#QMAKE_LFLAGS += /MANIFESTUAC:\"level=\'requireAdministrator\' uiAccess=\'false\'\" + +VERSION = 1.1.1.1 +QMAKE_TARGET_COMPANY = "AmneziaVPN" +QMAKE_TARGET_PRODUCT = "AmneziaVPN" + +CONFIG -= embed_manifest_exe + +LIBS += -luser32 \ + -lrasapi32 \ + -lshlwapi \ + -liphlpapi \ + -lws2_32 \ + -liphlpapi \ + -lgdi32 + + +MT_PATH = \"C:/Program Files (x86)/Microsoft SDKs/Windows/v7.1A/bin/x64/mt.exe\" +WIN_PWD = $$replace(PWD, /, \\) +OUT_PWD_WIN = $$replace(OUT_PWD, /, \\) + +!win32-g++: QMAKE_POST_LINK = "$$MT_PATH -manifest $$quote($$WIN_PWD\\platform_win\\$$basename(TARGET).exe.manifest) -outputresource:$$quote($$OUT_PWD_WIN\\$(DESTDIR_TARGET);1)" + else: QMAKE_POST_LINK = "$$MT_PATH -manifest $$PWD/platform_win/$$basename(TARGET).exe.manifest -outputresource:$$OUT_PWD/$(DESTDIR_TARGET)" +} + +macx { + +OBJECTIVE_HEADERS += +OBJECTIVE_SOURCES += publib/macos_functions.mm + +HEADERS += \ + +SOURCES += \ + +QMAKE_OBJECTIVE_CFLAGS += -F/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks + +FORMS += ui/mainwindow_mac.ui + +LIBS += -framework CoreServices -framework Foundation -framework AppKit + +RESOURCES += \ + res_mac.qrc + +ICON = images/main.icns +} + +SOURCES += main.cpp\ + publib/debug.cpp \ + publib/runguard.cpp \ + publib/winhelp.cpp \ + ui/Controls/SlidingStackedWidget.cpp \ + ui/mainwindow.cpp \ + ui/customshadoweffect.cpp + +HEADERS += ui/mainwindow.h \ + publib/debug.h \ + publib/runguard.h \ + publib/winhelp.h \ + ui/customshadoweffect.h \ + ui/Controls/SlidingStackedWidget.h + +FORMS += ui/mainwindow.ui + + +TRANSLATIONS = translations/amneziavpn.en.ts \ + translations/amneziavpn.ru.ts + + + +win32: LIBS += -L$$PWD/../../../../../../../OpenSSL-Win32/lib/ -llibcrypto + diff --git a/client/fonts/Lato-Black.ttf b/client/fonts/Lato-Black.ttf new file mode 100644 index 000000000..a87109f58 Binary files /dev/null and b/client/fonts/Lato-Black.ttf differ diff --git a/client/fonts/Lato-BlackItalic.ttf b/client/fonts/Lato-BlackItalic.ttf new file mode 100644 index 000000000..505e23faa Binary files /dev/null and b/client/fonts/Lato-BlackItalic.ttf differ diff --git a/client/fonts/Lato-Bold.ttf b/client/fonts/Lato-Bold.ttf new file mode 100644 index 000000000..59c48434c Binary files /dev/null and b/client/fonts/Lato-Bold.ttf differ diff --git a/client/fonts/Lato-BoldItalic.ttf b/client/fonts/Lato-BoldItalic.ttf new file mode 100644 index 000000000..3371a4bf0 Binary files /dev/null and b/client/fonts/Lato-BoldItalic.ttf differ diff --git a/client/fonts/Lato-Italic.ttf b/client/fonts/Lato-Italic.ttf new file mode 100644 index 000000000..9babe6a82 Binary files /dev/null and b/client/fonts/Lato-Italic.ttf differ diff --git a/client/fonts/Lato-Light.ttf b/client/fonts/Lato-Light.ttf new file mode 100644 index 000000000..ccba01a99 Binary files /dev/null and b/client/fonts/Lato-Light.ttf differ diff --git a/client/fonts/Lato-LightItalic.ttf b/client/fonts/Lato-LightItalic.ttf new file mode 100644 index 000000000..fd58065ec Binary files /dev/null and b/client/fonts/Lato-LightItalic.ttf differ diff --git a/client/fonts/Lato-Regular.ttf b/client/fonts/Lato-Regular.ttf new file mode 100644 index 000000000..f01f55892 Binary files /dev/null and b/client/fonts/Lato-Regular.ttf differ diff --git a/client/fonts/Lato-Thin.ttf b/client/fonts/Lato-Thin.ttf new file mode 100644 index 000000000..ca2cc0dea Binary files /dev/null and b/client/fonts/Lato-Thin.ttf differ diff --git a/client/fonts/Lato-ThinItalic.ttf b/client/fonts/Lato-ThinItalic.ttf new file mode 100644 index 000000000..1e319da5d Binary files /dev/null and b/client/fonts/Lato-ThinItalic.ttf differ diff --git a/client/images/AmneziaVPN.png b/client/images/AmneziaVPN.png new file mode 100644 index 000000000..81448fefa Binary files /dev/null and b/client/images/AmneziaVPN.png differ diff --git a/client/images/Line.png b/client/images/Line.png new file mode 100644 index 000000000..c5a3a4663 Binary files /dev/null and b/client/images/Line.png differ diff --git a/client/images/arrow_left.png b/client/images/arrow_left.png new file mode 100644 index 000000000..091b40977 Binary files /dev/null and b/client/images/arrow_left.png differ diff --git a/client/images/close.png b/client/images/close.png new file mode 100644 index 000000000..2fc5db3e1 Binary files /dev/null and b/client/images/close.png differ diff --git a/client/images/connect_button_connected.png b/client/images/connect_button_connected.png new file mode 100644 index 000000000..171eb79e1 Binary files /dev/null and b/client/images/connect_button_connected.png differ diff --git a/client/images/connect_button_disconnected.png b/client/images/connect_button_disconnected.png new file mode 100644 index 000000000..a88e26e44 Binary files /dev/null and b/client/images/connect_button_disconnected.png differ diff --git a/client/images/connected_line.png b/client/images/connected_line.png new file mode 100644 index 000000000..9ed7fd74d Binary files /dev/null and b/client/images/connected_line.png differ diff --git a/client/images/controls/check_off.png b/client/images/controls/check_off.png new file mode 100644 index 000000000..0a7fbf709 Binary files /dev/null and b/client/images/controls/check_off.png differ diff --git a/client/images/controls/check_on.png b/client/images/controls/check_on.png new file mode 100644 index 000000000..8b3b683b1 Binary files /dev/null and b/client/images/controls/check_on.png differ diff --git a/client/images/controls/checkbox_hover.png b/client/images/controls/checkbox_hover.png new file mode 100644 index 000000000..c6415422d Binary files /dev/null and b/client/images/controls/checkbox_hover.png differ diff --git a/client/images/controls/checkbox_unchecked.png b/client/images/controls/checkbox_unchecked.png new file mode 100644 index 000000000..657d15dd6 Binary files /dev/null and b/client/images/controls/checkbox_unchecked.png differ diff --git a/client/images/controls/radio_off.png b/client/images/controls/radio_off.png new file mode 100644 index 000000000..685980bdf Binary files /dev/null and b/client/images/controls/radio_off.png differ diff --git a/client/images/controls/radio_on.png b/client/images/controls/radio_on.png new file mode 100644 index 000000000..48560e537 Binary files /dev/null and b/client/images/controls/radio_on.png differ diff --git a/client/images/download.png b/client/images/download.png new file mode 100644 index 000000000..0e9491331 Binary files /dev/null and b/client/images/download.png differ diff --git a/client/images/favorites_disabled.png b/client/images/favorites_disabled.png new file mode 100644 index 000000000..12a821acf Binary files /dev/null and b/client/images/favorites_disabled.png differ diff --git a/client/images/favorites_enabled.png b/client/images/favorites_enabled.png new file mode 100644 index 000000000..61e28f422 Binary files /dev/null and b/client/images/favorites_enabled.png differ diff --git a/client/images/favorites_hover.png b/client/images/favorites_hover.png new file mode 100644 index 000000000..71e7a1b2b Binary files /dev/null and b/client/images/favorites_hover.png differ diff --git a/client/images/listitembg.png b/client/images/listitembg.png new file mode 100644 index 000000000..4107a7ea4 Binary files /dev/null and b/client/images/listitembg.png differ diff --git a/client/images/min.png b/client/images/min.png new file mode 100644 index 000000000..cacc4fec7 Binary files /dev/null and b/client/images/min.png differ diff --git a/client/images/settings.png b/client/images/settings.png new file mode 100644 index 000000000..60127b5cd Binary files /dev/null and b/client/images/settings.png differ diff --git a/client/images/tray/active.png b/client/images/tray/active.png new file mode 100644 index 000000000..632ee3a23 Binary files /dev/null and b/client/images/tray/active.png differ diff --git a/client/images/tray/default.png b/client/images/tray/default.png new file mode 100644 index 000000000..1e7dfd392 Binary files /dev/null and b/client/images/tray/default.png differ diff --git a/client/images/tray/error.png b/client/images/tray/error.png new file mode 100644 index 000000000..56efcce11 Binary files /dev/null and b/client/images/tray/error.png differ diff --git a/client/images/underline.png b/client/images/underline.png new file mode 100644 index 000000000..e38c37b64 Binary files /dev/null and b/client/images/underline.png differ diff --git a/client/images/upload.png b/client/images/upload.png new file mode 100644 index 000000000..185e7a7b1 Binary files /dev/null and b/client/images/upload.png differ diff --git a/client/main.cpp b/client/main.cpp new file mode 100644 index 000000000..2320b0b21 --- /dev/null +++ b/client/main.cpp @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "publib/runguard.h" +#include "publib/debug.h" + +#include "ui/mainwindow.h" + +#ifdef Q_OS_WIN +#include +#endif + +#define ApplicationName "AmneziaVPN" + + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(res); + + QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); + RunGuard::instance(ApplicationName).activate(); + + QApplication app(argc, argv); + + if (! RunGuard::instance().tryToRun()) { + qDebug() << "Tried to run second instance. Exiting..."; + QMessageBox::information(NULL, QObject::tr("Notify"), QObject::tr("AmneziaVPN is already running.")); + return 0; + } + + QFontDatabase::addApplicationFont(":/fonts/Lato-Black.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-BlackItalic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Bold.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-BoldItalic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Italic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Light.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-LightItalic.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Regular.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-Thin.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Lato-ThinItalic.ttf"); + + + { + QTranslator *translator = new QTranslator; + QLocale ru(QLocale("ru_RU")); + QLocale::setDefault(ru); + if (translator->load(QLocale(), "amnezia-client", ".", QLatin1String(":/translations"))) { + bool ok = qApp->installTranslator(translator); + qDebug().noquote() << "Main: Installing translator for locale" << ru.name() << ok; + } + else { + qDebug().noquote() << "Main: Failed to install translator for locale" << ru.name(); + } + } + + + app.setOrganizationName("AmneziaVPN"); + app.setOrganizationDomain("AmneziaVPN.ORG"); + app.setApplicationName(ApplicationName); + app.setApplicationDisplayName(ApplicationName); + app.setApplicationVersion("1.0.0.0"); + + //app.setQuitOnLastWindowClosed(false); + + QCommandLineParser parser; + parser.setApplicationDescription("AmneziaVPN"); + parser.addHelpOption(); + parser.addVersionOption(); + + QCommandLineOption debugToConsoleOption("d", QCoreApplication::translate("main", "Output to console instead log file")); + parser.addOption(debugToConsoleOption); + +#ifdef Q_OS_MAC + QCommandLineOption forceUseBrightIconsOption("b", QCoreApplication::translate("main", "Force use bright icons")); + parser.addOption(forceUseBrightIconsOption); +#endif + + // Process the actual command line arguments given by the user + parser.process(app); + + bool debugToConsole = parser.isSet(debugToConsoleOption); + bool forceUseBrightIcons = false; + +#ifdef Q_OS_MAC + forceUseBrightIcons = parser.isSet(forceUseBrightIconsOption); +#endif + + + qDebug() << "Set output to console: " << debugToConsole; + if (!debugToConsole) { + if (!Debug::init()) { + qCritical() << "Initialization of debug subsystem failed"; + } + } + + QFont f("Lato Regular", 10); + f.setStyleStrategy(QFont::PreferAntialias); + app.setFont(f); + + MainWindow mainWindow(forceUseBrightIcons); + mainWindow.show(); + + return app.exec(); +} diff --git a/client/platform_win/vpnclient.rc b/client/platform_win/vpnclient.rc new file mode 100644 index 000000000..8ac789dfd --- /dev/null +++ b/client/platform_win/vpnclient.rc @@ -0,0 +1,48 @@ +#include +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +IDI_ICON1 ICON "../images/main.ico" + +#define VER_FILEVERSION 1,1,1,1 +#define VER_FILEVERSION_STR "1.1.1.1\0" + +#define VER_PRODUCTVERSION 1,1,1,1 +#define VER_PRODUCTVERSION_STR "1.1.1.1\0" + +#define VER_COMPANYNAME_STR "AmneziaVPN" +#define VER_FILEDESCRIPTION_STR "AmneziaVPN" +#define VER_INTERNALNAME_STR "AmneziaVPN" +#define VER_LEGALCOPYRIGHT_STR "AmneziaVPN." +#define VER_LEGALTRADEMARKS1_STR "All Rights Reserved" +#define VER_LEGALTRADEMARKS2_STR VER_LEGALTRADEMARKS1_STR +#define VER_ORIGINALFILENAME_STR "amneziavpn.exe" +#define VER_PRODUCTNAME_STR "AmneziaVPN" + +#define VER_COMPANYDOMAIN_STR "http://amnezia.org/" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_PRODUCTVERSION +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", VER_COMPANYNAME_STR + VALUE "FileDescription", VER_FILEDESCRIPTION_STR + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "InternalName", VER_INTERNALNAME_STR + VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR + VALUE "LegalTrademarks1", VER_LEGALTRADEMARKS1_STR + VALUE "LegalTrademarks2", VER_LEGALTRADEMARKS2_STR + VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR + VALUE "ProductName", VER_PRODUCTNAME_STR + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/client/publib/debug.cpp b/client/publib/debug.cpp new file mode 100644 index 000000000..700191880 --- /dev/null +++ b/client/publib/debug.cpp @@ -0,0 +1,130 @@ +#include "debug.h" + +#include +#include +#include +#include +#include + +#define LOGS_DIR "logs" +#define CLIENT_LOG_SUFFIX "amneziavpn.log" +#define MAX_LOG_FILES 5 +#define FORMAT_STRING "yyyy-MM-dd--hh-mm-ss" + +QFile Debug::m_clientLog; +QTextStream Debug::m_clientLogTextStream; +QString Debug::m_clientLogName; + +void debugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + // Skip Qt warnings + if (msg.contains("known incorrect sRGB profile")) return; + if (msg.contains("libpng warning")) return; + if (msg.contains("Unknown property ffont")) return; + + Debug::m_clientLogTextStream << qFormatLogMessage(type, context, msg) << endl << flush; +} + +bool Debug::init() +{ + QString path = qApp->applicationDirPath(); + QDir appDir(path); + + // init function is called before exec application, so data location folder may not exist + if (!appDir.exists()) + { + qWarning() << "Debug: init: log directory doesn't exist or mkpath command error:" << path; + return false; + } + + if (!appDir.exists(LOGS_DIR) && !appDir.mkdir(LOGS_DIR)) + { + qWarning() << "Debug: init: log directory doesn't exist or mkdir command error:" << path << LOGS_DIR; + return false; + } + + if (!appDir.cd(LOGS_DIR)) + { + qWarning() << "Debug: init: cd command error:" << path << LOGS_DIR; + return false; + } + + //delete older log files + auto clientLogsCount = 0; + QFileInfoList logDirList = appDir.entryInfoList( + QDir::Files | QDir::NoDotAndDotDot, + QDir::Time); + for (auto fileInfo : logDirList) + { + if ((fileInfo.completeSuffix() == CLIENT_LOG_SUFFIX && + ++clientLogsCount > MAX_LOG_FILES)) + { + appDir.remove(fileInfo.filePath()); + } + } + + //prepare log file names + auto currentDateTime = QDateTime::currentDateTime().toString(FORMAT_STRING); + + m_clientLogName = QString("%1.%2").arg(currentDateTime).arg(CLIENT_LOG_SUFFIX); + return init(appDir); +} + +bool Debug::init(QDir& appDir) +{ + Q_UNUSED(appDir) + qSetMessagePattern("[%{time}|%{type}] %{message}"); + +#ifndef QT_DEBUG + m_clientLog.setFileName(appDir.filePath(m_clientLogName)); + if (!m_clientLog.open(QIODevice::WriteOnly | QIODevice::Append)) { + qWarning() << "Debug::init - failed to open m_clientLog file:" << m_clientLogName; + return false; + } + m_clientLog.setTextModeEnabled(true); + m_clientLogTextStream.setDevice(&m_clientLog); + qInstallMessageHandler(debugMessageHandler); +#else +#ifdef DEBUG_OUTPUT_TWO_DIRECTIONAL + m_clientLog.setFileName(appDir.filePath(m_clientLogName)); + if (!m_clientLog.open(QIODevice::WriteOnly | QIODevice::Append)) + return false; + m_clientLog.setTextModeEnabled(true); + m_clientLogTextStream.setDevice(&m_clientLog); + defaultMessageHandler = qInstallMessageHandler(debugMessageHandler); +#endif +#endif + +#ifndef Q_OS_WIN + if (!fixOvpnLogPermissions()) + qWarning() << "Debug: permissions for ovpn.log were not fixed"; +#endif + return true; +} + +QString Debug::getPathToClientLog() +{ + QString path = qApp->applicationDirPath(); + QDir appDir(path); + if (!appDir.exists(LOGS_DIR) || !appDir.cd(LOGS_DIR)) + { + qWarning() << "Debug: log directory doesn't exist or cd command error:" << path; + return ""; + } + + return appDir.filePath(m_clientLogName); +} + +QString Debug::getPathToLogsDir() +{ + QString path = qApp->applicationDirPath(); + QDir appDir(path); + if (!appDir.exists(LOGS_DIR) || !appDir.cd(LOGS_DIR)) + { + qWarning() << "Debug: log directory doesn't exist or cd command error" << path; + return ""; + } + return appDir.absolutePath(); +} + + diff --git a/client/publib/debug.h b/client/publib/debug.h new file mode 100644 index 000000000..b51aabc2b --- /dev/null +++ b/client/publib/debug.h @@ -0,0 +1,27 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#include +#include +#include +#include + +class Debug +{ +public: + static bool init(); + static QString getPathToClientLog(); + static QString getPathToLogsDir(); + +private: + static bool init(QDir& appDir); + +private: + static QFile m_clientLog; + static QTextStream m_clientLogTextStream; + static QString m_clientLogName; + + friend void debugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); +}; + +#endif // DEBUG_H diff --git a/client/publib/runguard.cpp b/client/publib/runguard.cpp new file mode 100644 index 000000000..729c7eced --- /dev/null +++ b/client/publib/runguard.cpp @@ -0,0 +1,88 @@ +#include "runguard.h" +#include + +namespace +{ + +QString generateKeyHash( const QString& key, const QString& salt ) +{ + QByteArray data; + + data.append( key.toUtf8() ); + data.append( salt.toUtf8() ); + data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex(); + + return data; +} + +} + +RunGuard::RunGuard(const QString& key) + : key( key ) + , memLockKey( generateKeyHash( key, "_memLockKey" ) ) + , sharedmemKey( generateKeyHash( key, "_sharedmemKey" ) ) + , sharedMem( sharedmemKey ) + , memLock( memLockKey, 1 ) +{ + qDebug() << "RunGuard::RunGuard key" << key; +} + +RunGuard &RunGuard::instance(const QString& key) +{ + static RunGuard s(key); + return s; +} + +void RunGuard::activate() +{ + memLock.acquire(); + { + QSharedMemory fix(sharedmemKey); // Fix for *nix: http://habrahabr.ru/post/173281/ + fix.attach(); + } + memLock.release(); +} + +RunGuard::~RunGuard() +{ + release(); +} + +bool RunGuard::isAnotherRunning() const +{ + if ( sharedMem.isAttached() ) + return false; + + memLock.acquire(); + const bool isRunning = sharedMem.attach(); + if ( isRunning ) + sharedMem.detach(); + memLock.release(); + + return isRunning; +} + +bool RunGuard::tryToRun() +{ + if ( isAnotherRunning() ) // Extra check + return false; + + memLock.acquire(); + const bool result = sharedMem.create( sizeof( quint64 ) ); + memLock.release(); + if ( !result ) + { + release(); + return false; + } + + return true; +} + +void RunGuard::release() +{ + memLock.acquire(); + if ( sharedMem.isAttached() ) + sharedMem.detach(); + memLock.release(); +} diff --git a/client/publib/runguard.h b/client/publib/runguard.h new file mode 100644 index 000000000..96df44a83 --- /dev/null +++ b/client/publib/runguard.h @@ -0,0 +1,37 @@ +#ifndef RUNGUARD_H +#define RUNGUARD_H + +#include +#include +#include +#include + +/** + * @brief The RunGuard class - The application single instance (via shared memory) + */ +class RunGuard +{ + +public: + static RunGuard &instance(const QString& key = QString()); + + ~RunGuard(); + + void activate(); + bool isAnotherRunning() const; + bool tryToRun(); + void release(); + +private: + RunGuard(const QString& key); + Q_DISABLE_COPY( RunGuard ) + + const QString key; + const QString memLockKey; + const QString sharedmemKey; + + mutable QSharedMemory sharedMem; + mutable QSystemSemaphore memLock; + +}; +#endif // RUNGUARD_H diff --git a/client/publib/winhelp.cpp b/client/publib/winhelp.cpp new file mode 100644 index 000000000..4e6f8d2b1 --- /dev/null +++ b/client/publib/winhelp.cpp @@ -0,0 +1,261 @@ +#include "winhelp.h" + +#include +#include +#include +#include +#include +#include + + +#define REG_AUTORUN_PATH "Software\\Microsoft\\Windows\\CurrentVersion\\Run" + +int winhelpGetRegistry(const char *name, const char *reg, char *value) +{ + unsigned long nType = REG_SZ, nData = MAX_PATH; + if(ERROR_SUCCESS != SHGetValueA(HKEY_CURRENT_USER, reg, + name, &nType, value, &nData)) + return -1; + return 1; +} + +int winhelpSetRegistry(const char *name, const char *reg, const char *value) +{ + if(ERROR_SUCCESS != SHSetValueA(HKEY_CURRENT_USER, reg, + name, REG_SZ, value, (DWORD)strlen(value))) + return -1; + return 1; +} + +int winhelpLaunchStartupRegister(const char *name, int enable, const char *p) +{ + char path[MAX_PATH] = {0}; + if(p && strlen(p) == 0) + p = NULL; + if(p) { + if(enable) + strcpy(path, "\""); + else + strcpy(path, ";\""); + GetModuleFileNameA(NULL, path + strlen(path), MAX_PATH); + strcat(path, "\" "); + strcat(path, p); + } else { + if(enable) + strcpy(path, ""); + else + strcpy(path, ";"); + GetModuleFileNameA(NULL, path + strlen(path), MAX_PATH); + } + if(winhelpSetRegistry(name, REG_AUTORUN_PATH, path) < 0) + return -1; + return 1; +} + +/* use the task scheduler, we do not need to care about UAC when start up */ +int winhelpLaunchStartupTaskScheduler(const char *name, int enable, const char *p) +{ + char cmd[MAX_PATH * 10] = {0}; + char path[MAX_PATH] = {0}; + UINT i = 0; + GetModuleFileNameA(NULL, path, MAX_PATH); + if (QString(path).contains("build-vpn-")) { + qDebug() << "winhelpLaunchStartupTaskScheduler : skipping auto launch for build dir"; + return 0; + } + + if(enable) { + if(p == NULL) + p = ""; + sprintf(cmd, "schtasks /create /sc onlogon /tr \"\\\"%s\\\" %s\" " + "/tn \"%s\" /f /rl highest", path, p, name); + + } else { + sprintf(cmd, "schtasks /delete /tn \"%s\" /f", name); + } + qDebug().noquote() << "winhelpLaunchStartupTaskScheduler cmd:" << cmd; + i = WinExec(cmd, SW_HIDE); + return 1; +} + +int winhelpLaunchStartup(const char *name, int enable, const char *p) +{ + OSVERSIONINFOA info = {0}; + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + if(GetVersionExA(&info) < 0) + return -2; + if(info.dwMajorVersion >= 6) + return winhelpLaunchStartupTaskScheduler(name, enable, p); + else + return winhelpLaunchStartupRegister(name, enable, p); +} + +int str2int(const char *s) +{ + int r = 0; + while(*s && *(s + 1) && *(s + 2) && *(s + 3)) { + r += ((const int *)s)[0]; + s += 4; + } + return r; +} + +int winhelpOneProcess() +{ + char path[MAX_PATH] = {0}; + int i = 0, size = 0, cur = 0; + GetModuleFileNameA(NULL, path, MAX_PATH); + size = strlen(path); + for(i = size; i >= 0 && path[i] != '\\' ; i--); + cur = i + 1; + while(path[i] != '.' && path[i])i++; + path[i] = '\0'; + sprintf(path, "ONE_%s", path + cur); + CreateEventA(NULL, FALSE, FALSE, path); + if(GetLastError()) + return 0; + return 1; +} + +int winhelpSystemBits() +{ + typedef BOOL (WINAPI *LPFN_ISWOW64)(HANDLE, PBOOL); + int b64 = FALSE; + LPFN_ISWOW64 fnIsWow64 = (LPFN_ISWOW64)GetProcAddress( + GetModuleHandleA("kernel32"), "IsWow64Process"); + if(NULL != fnIsWow64) { + if(!fnIsWow64(GetCurrentProcess(),&b64)) { + return -1; + } + } + return b64 ? 64 : 86; +} + +bool winhelpIsSystem_x64() +{ + typedef BOOL (WINAPI *LPFN_ISWOW64)(HANDLE, PBOOL); + int b64 = FALSE; + LPFN_ISWOW64 fnIsWow64 = (LPFN_ISWOW64)GetProcAddress( + GetModuleHandleA("kernel32"), "IsWow64Process"); + if(NULL != fnIsWow64) { + if(!fnIsWow64(GetCurrentProcess(),&b64)) { + return false; + } + } + return b64 ? true : false; +} + +typedef struct _PROCESS_QUERY +{ + HANDLE h; + PROCESSENTRY32 d; +}PROCESS_QUERY; + +int winhelpProcessQuery(void **p) +{ + PROCESS_QUERY *q = (PROCESS_QUERY *)malloc(sizeof(PROCESS_QUERY)); + if(q == NULL) + return -2; + q->h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if(q->h == INVALID_HANDLE_VALUE) { + free(q); + return -1; + } + if(FALSE == Process32First(q->h, &q->d)) { + CloseHandle(q->h); + free(q); + return -3; + } + *p = (void *)q; + return 1; +} + +int winhelpProcessNext(void *h, char *name) +{ + PROCESS_QUERY *q = (PROCESS_QUERY *)h; + int pid = 0; + if(q == NULL) + return 0; + if(q->h == NULL) { + free(q); + return 0; + } + if(name) + wsprintfA(name, "%ls", q->d.szExeFile); + pid = (int)q->d.th32ProcessID; + + if(FALSE == Process32Next(q->h, &q->d)) { + CloseHandle(q->h); + q->h = NULL; + } + return pid; +} + +int winhelpRecvEvent(const char *event) +{ + HANDLE hEvent = CreateEventA(NULL, FALSE, FALSE, event); + if(hEvent == NULL) + return 0; + WaitForSingleObject(hEvent, INFINITE); + CloseHandle(hEvent); + return 1; +} + +int winhelpSendEvent(const char *event) +{ + HANDLE hEvent = OpenEventA(EVENT_ALL_ACCESS, FALSE, event); + if(hEvent == NULL) + return 0; + SetEvent(hEvent); + CloseHandle(hEvent); + return 1; +} + +int winhelpSystemVersion() +{ + OSVERSIONINFOA ver = {0}; + int version = 0; + ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + GetVersionExA(&ver); + version = ver.dwMajorVersion * 0x100 + ver.dwMinorVersion; + return version; +} + +int winhelperSetMTUSize(const char *subname, int size) +{ + char cmd[MAX_PATH] = {0}; + sprintf(cmd, "netsh interface ipv4 set subinterface \"%s\" mtu=%d store=persistent", + subname, size); + return (int)WinExec(cmd, SW_HIDE); +} + +int winhelpRecvSendBytes(const char *dev, int *recv, int *send) +{ + MIB_IFTABLE *it = NULL; + DWORD size = sizeof(MIB_IFTABLE), ret = 0, i = 0; + DWORD tr = 0, ts = 0; + + if(it = (MIB_IFTABLE *)malloc(sizeof (MIB_IFTABLE)), it == NULL) + return -1; + if(GetIfTable(it, &size, FALSE) == ERROR_INSUFFICIENT_BUFFER) { + free(it); + if(it = (MIB_IFTABLE *)malloc(size), it == NULL) + return -2; + } + if(ret = GetIfTable(it, &size, FALSE), ret != NO_ERROR) { + free(it); + return -3; + } + for(i = 0; i < it->dwNumEntries; i++) { + MIB_IFROW *ir = &it->table[i]; + if(strstr((const char *)ir->bDescr, dev) == 0) + continue; + tr += (int)ir->dwInOctets; + ts += (int)ir->dwOutOctets; + } + *recv = tr; + *send = ts; + free(it); + return 1; +} + diff --git a/client/publib/winhelp.h b/client/publib/winhelp.h new file mode 100644 index 000000000..43e9367ab --- /dev/null +++ b/client/publib/winhelp.h @@ -0,0 +1,26 @@ +#ifndef WINHELP_H +#define WINHELP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int winhelpLaunchStartup(const char *, int, const char *); +extern int winhelpOneProcess(); +extern int winhelpSystemBits(); +extern bool winhelpIsSystem_x64(); +extern int winhelpProcessQuery(void **); +extern int winhelpProcessNext(void *, char *); +extern int winhelpRecvEvent(const char *); +extern int winhelpSendEvent(const char *); +extern int winhelpSystemVersion(); +extern int winhelperSetMTUSize(const char *, int); +extern int winhelpRecvSendBytes(const char *, int *, int *); + +#ifdef __cplusplus +} +#endif + +#endif /* WINHELP_H */ diff --git a/client/res.qrc b/client/res.qrc new file mode 100644 index 000000000..667df8cd0 --- /dev/null +++ b/client/res.qrc @@ -0,0 +1,39 @@ + + + images/close.png + images/listitembg.png + images/settings.png + images/underline.png + images/min.png + images/favorites_disabled.png + images/favorites_enabled.png + images/favorites_hover.png + images/controls/check_off.png + images/controls/check_on.png + images/controls/radio_off.png + images/controls/radio_on.png + images/connected_line.png + images/download.png + images/upload.png + images/controls/checkbox_hover.png + images/controls/checkbox_unchecked.png + images/tray/active.png + images/tray/default.png + images/tray/error.png + images/arrow_left.png + images/connect_button_connected.png + images/connect_button_disconnected.png + fonts/Lato-Black.ttf + fonts/Lato-BlackItalic.ttf + fonts/Lato-Bold.ttf + fonts/Lato-BoldItalic.ttf + fonts/Lato-Italic.ttf + fonts/Lato-Light.ttf + fonts/Lato-LightItalic.ttf + fonts/Lato-Regular.ttf + fonts/Lato-Thin.ttf + fonts/Lato-ThinItalic.ttf + images/Line.png + images/AmneziaVPN.png + + diff --git a/client/ui/Controls/SlidingStackedWidget.cpp b/client/ui/Controls/SlidingStackedWidget.cpp new file mode 100644 index 000000000..104de5228 --- /dev/null +++ b/client/ui/Controls/SlidingStackedWidget.cpp @@ -0,0 +1,193 @@ +#include "SlidingStackedWidget.h" + +SlidingStackedWidget::SlidingStackedWidget(QWidget *parent) + : QStackedWidget(parent) +{ + if (parent != 0) { + m_mainwindow = parent; + } + else { + m_mainwindow = this; + qDebug().noquote() << "ATTENTION: untested mainwindow case !"; + } + // parent should not be 0; not tested for any other case yet !! + +#ifdef Q_OS_SYMBIAN +#ifndef __S60_50__ + qDebug().noquote() << "WARNING: ONLY TESTED AND 5TH EDITION"; +#endif // __S60_50__ +#endif // Q_OS_SYMBIAN + + // Now, initialize some private variables with default values + m_vertical = false; + // setVerticalMode(true); + m_speed = 500; + m_animationtype = QEasingCurve::OutBack; // check out the QEasingCurve documentation for different styles + m_now = 0; + m_next = 0; + m_wrap = false; + m_pnow = QPoint(0,0); + m_active = false; +} + +SlidingStackedWidget::~SlidingStackedWidget() { +} + +void SlidingStackedWidget::setVerticalMode(bool vertical) { + m_vertical = vertical; +} + +void SlidingStackedWidget::setSpeed(int speed) { + m_speed = speed; +} + +void SlidingStackedWidget::setAnimation(enum QEasingCurve::Type animationtype) { + m_animationtype = animationtype; +} + +void SlidingStackedWidget::setWrap(bool wrap) { + m_wrap = wrap; +} + +void SlidingStackedWidget::slideInNext() { + int now = currentIndex(); + if (m_wrap || (now < count() - 1)) + // count is inherit from QStackedWidget + slideInIdx(now + 1); +} + +void SlidingStackedWidget::slideInPrev() { + int now = currentIndex(); + if (m_wrap || (now > 0)) + slideInIdx(now - 1); +} + +void SlidingStackedWidget::slideInIdx(int idx, enum t_direction direction) { + // int idx, t_direction direction=AUTOMATIC + if (idx > count() - 1) { + direction = m_vertical ? TOP2BOTTOM : RIGHT2LEFT; + idx = (idx) % count(); + } + else if (idx < 0) { + direction = m_vertical ? BOTTOM2TOP: LEFT2RIGHT; + idx = (idx + count()) % count(); + } + slideInWgtImpl(widget(idx), direction); + // widget() is a function inherited from QStackedWidget +} + +void SlidingStackedWidget::slideInWidget(QWidget *widget, SlidingStackedWidget::t_direction direction) +{ + Q_UNUSED(direction); + +#ifdef Q_OS_WIN + int idx = indexOf(widget); + slideInIdx(idx, direction); +#endif + +#ifdef Q_OS_MAC + setCurrentWidget(widget); +#endif +} + +void SlidingStackedWidget::slideInWgtImpl(QWidget * newwidget, enum t_direction direction) { + if (m_active) { + return; + } + else m_active = true; + + enum t_direction directionhint; + int now = currentIndex(); // currentIndex() is a function inherited from QStackedWidget + int next = indexOf(newwidget); + if (now == next) { + m_active = false; + return; + } + else if (now < next) { + directionhint = m_vertical ? TOP2BOTTOM : RIGHT2LEFT; + } + else { + directionhint = m_vertical ? BOTTOM2TOP : LEFT2RIGHT; + } + if (direction == AUTOMATIC) { + direction = directionhint; + } + // NOW.... + // calculate the shifts + + int offsetx = frameRect().width(); // inherited from mother + int offsety = frameRect().height(); // inherited from mother + + // the following is important, to ensure that the new widget + // has correct geometry information when sliding in first time + widget(next)->setGeometry(0, 0, offsetx, offsety); + + if (direction == BOTTOM2TOP) { + offsetx = 0; + offsety = -offsety; + } + else if (direction == TOP2BOTTOM) { + offsetx = 0; + // offsety = offsety; + } + else if (direction == RIGHT2LEFT) { + offsetx = -offsetx; + offsety = 0; + } + else if (direction == LEFT2RIGHT) { + // offsetx = offsetx; + offsety = 0; + } + // re-position the next widget outside/aside of the display area + QPoint pnext = widget(next)->pos(); + QPoint pnow = widget(now)->pos(); + m_pnow = pnow; + + widget(next)->move(pnext.x() - offsetx, pnext.y() - offsety); + // make it visible/show + widget(next)->show(); + widget(next)->raise(); + + // animate both, the now and next widget to the side, using animation framework + QPropertyAnimation *animnow = new QPropertyAnimation(widget(now), "pos"); + + animnow->setDuration(m_speed); + animnow->setEasingCurve(m_animationtype); + animnow->setStartValue(QPoint(pnow.x(), pnow.y())); + animnow->setEndValue(QPoint(offsetx + pnow.x(), offsety + pnow.y())); + QPropertyAnimation *animnext = new QPropertyAnimation(widget(next), "pos"); + animnext->setDuration(m_speed); + animnext->setEasingCurve(m_animationtype); + animnext->setStartValue(QPoint(-offsetx + pnext.x(), offsety + pnext.y())); + animnext->setEndValue(QPoint(pnext.x(), pnext.y())); + + QParallelAnimationGroup *animgroup = new QParallelAnimationGroup; + + animgroup->addAnimation(animnow); + animgroup->addAnimation(animnext); + + QObject::connect(animgroup, SIGNAL(finished()),this,SLOT(animationDoneSlot())); + m_next = next; + m_now = now; + m_active = true; + animgroup->start(); + + // note; the rest is done via a connect from the animation ready; + // animation->finished() provides a signal when animation is done; + // so we connect this to some post processing slot, + // that we implement here below in animationDoneSlot. +} + +void SlidingStackedWidget::animationDoneSlot(void) { + // when ready, call the QStackedWidget slot setCurrentIndex(int) + setCurrentIndex(m_next); // this function is inherited from QStackedWidget + // then hide the outshifted widget now, and (may be done already implicitely by QStackedWidget) + widget(m_now)->hide(); + // then set the position of the outshifted widget now back to its original + widget(m_now)->move(m_pnow); + // so that the application could also still call the QStackedWidget original functions/slots for changings + // widget(m_now)->update(); + // setCurrentIndex(m_next); // this function is inherit from QStackedWidget + m_active = false; + emit animationFinished(); +} diff --git a/client/ui/Controls/SlidingStackedWidget.h b/client/ui/Controls/SlidingStackedWidget.h new file mode 100644 index 000000000..979e8f6ab --- /dev/null +++ b/client/ui/Controls/SlidingStackedWidget.h @@ -0,0 +1,76 @@ +#ifndef SLIDINGSTACKEDWIDGET_H +#define SLIDINGSTACKEDWIDGET_H + +#include + +#include +#include +#include +#include +#include + +/* Description + + SlidingStackedWidget is a class that is derived from QtStackedWidget + and allows smooth side shifting of widgets, in addition + to the original hard switching from one to another as offered by + QStackedWidget itself. +*/ + +class SlidingStackedWidget : public QStackedWidget { + Q_OBJECT + +public: + // This enumeration is used to define the animation direction + enum t_direction { + LEFT2RIGHT, + RIGHT2LEFT, + TOP2BOTTOM, + BOTTOM2TOP, + AUTOMATIC + }; + + // The Constructor and Destructor + SlidingStackedWidget(QWidget *parent); + ~SlidingStackedWidget(void); + +public slots: + // Some basic settings API + void setSpeed(int speed); // animation duration in milliseconds + void setAnimation(enum QEasingCurve::Type animationtype); // check out the QEasingCurve documentation for different styles + void setVerticalMode(bool vertical=true); + void setWrap(bool wrap); // wrapping is related to slideInNext/Prev;it defines the behaviour when reaching last/first page + + // The Animation / Page Change API + void slideInNext(); + void slideInPrev(); + void slideInIdx(int idx, enum t_direction direction = AUTOMATIC); + void slideInWidget(QWidget *widget, enum t_direction direction = AUTOMATIC); + +signals: + // this is used for internal purposes in the class engine + void animationFinished(void); + +protected slots: + // this is used for internal purposes in the class engine + void animationDoneSlot(void); + +protected: + // this is used for internal purposes in the class engine + void slideInWgtImpl(QWidget *widget, enum t_direction direction = AUTOMATIC); + + QWidget *m_mainwindow; + + int m_speed; + enum QEasingCurve::Type m_animationtype; + bool m_vertical; + int m_now; + int m_next; + bool m_wrap; + QPoint m_pnow; + bool m_active; + + QList blockedPageList; +}; + +#endif // SLIDINGSTACKEDWIDGET_H diff --git a/client/ui/customshadoweffect.cpp b/client/ui/customshadoweffect.cpp new file mode 100644 index 000000000..a719e81ff --- /dev/null +++ b/client/ui/customshadoweffect.cpp @@ -0,0 +1,76 @@ +#include "customshadoweffect.h" +#include + +CustomShadowEffect::CustomShadowEffect(QObject *parent) : + QGraphicsEffect(parent), + _distance(4.0f), + _blurRadius(10.0f), + _color(0, 0, 0, 80) +{ +} + +QT_BEGIN_NAMESPACE + extern Q_WIDGETS_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0 ); +QT_END_NAMESPACE + +void CustomShadowEffect::draw(QPainter* painter) +{ + // if nothing to show outside the item, just draw source + if ((blurRadius() + distance()) <= 0) { + drawSource(painter); + return; + } + + PixmapPadMode mode = QGraphicsEffect::PadToEffectiveBoundingRect; + QPoint offset; + const QPixmap px = sourcePixmap(Qt::DeviceCoordinates, &offset, mode); + + // return if no source + if (px.isNull()) + return; + + // save world transform + QTransform restoreTransform = painter->worldTransform(); + painter->setWorldTransform(QTransform()); + + // Calculate size for the background image + QSize szi(px.size().width() + 2 * distance(), px.size().height() + 2 * distance()); + + QImage tmp(szi, QImage::Format_ARGB32_Premultiplied); + QPixmap scaled = px.scaled(szi); + tmp.fill(0); + QPainter tmpPainter(&tmp); + tmpPainter.setCompositionMode(QPainter::CompositionMode_Source); + tmpPainter.drawPixmap(QPointF(-distance(), -distance()), scaled); + tmpPainter.end(); + + // blur the alpha channel + QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied); + blurred.fill(0); + QPainter blurPainter(&blurred); + qt_blurImage(&blurPainter, tmp, blurRadius(), false, true); + blurPainter.end(); + + tmp = blurred; + + // blacken the image... + tmpPainter.begin(&tmp); + tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); + tmpPainter.fillRect(tmp.rect(), color()); + tmpPainter.end(); + + // draw the blurred shadow... + painter->drawImage(offset, tmp); + + // draw the actual pixmap... + painter->drawPixmap(offset, px, QRectF()); + + // restore world transform + painter->setWorldTransform(restoreTransform); +} + +QRectF CustomShadowEffect::boundingRectFor(const QRectF& rect) const +{ + qreal delta = blurRadius() + distance(); + return rect.united(rect.adjusted(-delta, -delta, delta, delta)); +} diff --git a/client/ui/customshadoweffect.h b/client/ui/customshadoweffect.h new file mode 100644 index 000000000..629986f26 --- /dev/null +++ b/client/ui/customshadoweffect.h @@ -0,0 +1,31 @@ +#ifndef CUSTOMSHADOWEFFECT_H +#define CUSTOMSHADOWEFFECT_H + +#include +#include + +class CustomShadowEffect : public QGraphicsEffect +{ + Q_OBJECT +public: + explicit CustomShadowEffect(QObject *parent = 0); + + void draw(QPainter* painter); + QRectF boundingRectFor(const QRectF& rect) const; + + inline void setDistance(qreal distance) { _distance = distance; updateBoundingRect(); } + inline qreal distance() const { return _distance; } + + inline void setBlurRadius(qreal blurRadius) { _blurRadius = blurRadius; updateBoundingRect(); } + inline qreal blurRadius() const { return _blurRadius; } + + inline void setColor(const QColor& color) { _color = color; } + inline QColor color() const { return _color; } + +private: + qreal _distance; + qreal _blurRadius; + QColor _color; +}; + +#endif // CUSTOMSHADOWEFFECT_H diff --git a/client/ui/mainwindow.cpp b/client/ui/mainwindow.cpp new file mode 100644 index 000000000..72b9d8610 --- /dev/null +++ b/client/ui/mainwindow.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mainwindow.h" + + +#ifdef Q_OS_WIN +#include "ui_mainwindow.h" +#endif + +#ifdef Q_OS_MAC +#include "ui_mainwindow_mac.h" +#include "publib/macos_functions.h" +#endif + + +MainWindow::MainWindow(bool useForceUseBrightIcons, QWidget *parent) : QMainWindow(parent), + ui(new Ui::MainWindow), + forceUseBrightIcons(useForceUseBrightIcons) +{ + ui->setupUi(this); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + diff --git a/client/ui/mainwindow.h b/client/ui/mainwindow.h new file mode 100644 index 000000000..58b610e25 --- /dev/null +++ b/client/ui/mainwindow.h @@ -0,0 +1,43 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "customshadoweffect.h" + + + +namespace Ui { +class MainWindow; +} + +/** + * @brief The MainWindow class - Main application window + */ +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(bool setForceUseBrightIcons = false, QWidget *parent = nullptr); + ~MainWindow(); + +public slots: + + +private slots: + +private: + Ui::MainWindow *ui; + bool forceUseBrightIcons = false; +}; + +#endif // MAINWINDOW_H diff --git a/client/ui/mainwindow.ui b/client/ui/mainwindow.ui new file mode 100644 index 000000000..2cfad3090 --- /dev/null +++ b/client/ui/mainwindow.ui @@ -0,0 +1,1293 @@ + + + MainWindow + + + + 0 + 0 + 390 + 685 + + + + + + + QWidget { + font: 16px "Lato"; + outline: none; + font-style: normal; + font-weight: normal; +} + +/*----------------------*/ + +QPushButton { + border: none; + color: rgb(216, 216, 216); +} +QPushButton:disabled { + border: none; + color: rgb(127, 127, 127); +} + +/*----------------------*/ + +QLabel { + color: #181922; +} +QLabel:disabled { + color: #A7A7A7; +} + +/*----------------------*/ + +QMessageBox { + background-color: #333333; +} +QMessageBox QLabel { + color: #aaa; +} + +/*----------------------*/ + +QLineEdit { + border: none; + border-bottom:2px solid rgb(120, 120, 120); + + color: rgb(140, 140, 140); + + /*font: 13pt "JMH Cthulhumbus";*/ + + background:transparent; + + selection-background-color: darkgray; +} + +QLineEdit:focus { + border-bottom:2px solid rgb(200, 200, 200); +} +QLineEdit[error] { + border-bottom:2px solid rgb(213, 40, 60); + color: rgb(213, 40, 60); +} +QLineEdit:disabled { + border-bottom:2px solid rgb(127, 127, 127); + color: rgb(127, 127, 127); +} + + +QCheckBox { + color: rgb(200, 200, 200); + + font: 63 11pt "Open Sans"; + /*font: 11pt "JMH Cthulhumbus";*/ + background: transparent; + + +} + +QCheckBox::indicator { +min-height: 20px; +min-width: 20px; + +border-image: url(:/images/controls/checkbox_unchecked.png) 0 0 0 0 stretch stretch; +} + +QCheckBox::indicator:unchecked { +border-image: url(:/images/controls/checkbox_unchecked.png) 0 0 0 0 stretch stretch; +} +QCheckBox::indicator:unchecked:hover { +border-image: url(:/images/controls/checkbox_hover.png); +} + +QCheckBox::indicator:checked { +border-image: url(:/images/controls/checkbox_checked.png); + +} + + + +QScrollBar:vertical { /* The area behind the scrollbar covering entire height. */ + background-color: black; + opacity: 100; + width: 7px; /* set width to zero to hide scrollbar entirely. Can look quite clean and scrolling still works with mousewheel. */ + margin: 0px 0px; /* Takes the height of the buttons + 3 extra pixels to leave some free space between handle and buttons */ + +} + +QScrollBar::handle:vertical { /* The handle you scroll with */ + image-position: center; /* image is used as a small gripper in the center of the scrollbar.. You can also use background-image to use two images */ + background-color: rgb(200, 200, 200); + border-radius: 1px; + min-height: 10px; +} +QScrollBar::handle:vertical:hover { /* state when you hover over the handle */ + background-color: rgb(160, 160, 160); +} +QScrollBar::handle:vertical:pressed { /* state when you hover over the handle */ + background-color: rgb(120, 120, 120); +} +QScrollBar::sub-line:vertical { /* button to scroll up */ + background-color: rgb(240,240,240); + height: 0px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover { /* hover state of button to scroll up */ + background-color: rgb(200, 200, 200); +} + +QScrollBar::up-arrow:vertical { /* arrow to scroll up with */ + top: 2px; +} + +QScrollBar::add-line:vertical { /* Button to scroll down */ + background-color: rgb(240,240,240); + height: 0px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} +QScrollBar::add-line:vertical:hover { /* hover state of button to scroll down */ + background-color: rgb(200, 200, 200); +} + +QScrollBar::down-arrow:vertical { /* arrow to scroll down with */ + bottom: 3px; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background-color: black; +} + + + + + + + + + 5 + 5 + 380 + 670 + + + + QWidget #widget_main { + background: white; +} + + + + + + 0 + 0 + 380 + 30 + + + + true + + + background: #F5F5F5; + + + + + + 330 + 10 + 16 + 16 + + + + PointingHandCursor + + + image: url(:/images/listitembg.png); +image-position: right; + + + + + + + + + + 360 + 8 + 13 + 13 + + + + PointingHandCursor + + + + +QPushButton { +image-position: right; +image: url(:/images/close.png); + + padding:1px; +} +QPushButton:hover { + padding:0px; +} + + + + + + + + + + + 0 + 30 + 380 + 640 + + + + QStackedWidget#stackedWidget_main{ + background: transparent; +} + +QStackedWidget QWidget { + background: transparent; +} + + + + + + + 60 + 20 + 121 + 101 + + + + PointingHandCursor + + + image: url(:/images/tray/active.png); + + + + + + true + + + + + + 190 + 40 + 131 + 71 + + + + PointingHandCursor + + + image: url(:/images/AmneziaVPN.png); + + + + + + true + + + + + + 10 + 150 + 361 + 71 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 24px; +line-height: 25px; + + + Подключите ваш сервер, + чтобы использовать VPN + + + Qt::AlignCenter + + + + + + 40 + 290 + 171 + 21 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +/* or 24px */ + +/* text */ +color: #333333; + + + IP-адрес сервера + + + + + + 40 + 370 + 261 + 21 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +/* or 24px */ + +/* text */ +color: #333333; + + + Логин для подключения по SSH + + + + + + 40 + 450 + 171 + 21 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +/* or 24px */ + +/* text */ +color: #333333; + + + Пароль + + + + + + 40 + 320 + 301 + 31 + + + + background: #F4F4F4; + +/* grey */ +border: 1px solid #A7A7A7; +box-sizing: border-box; +color: #333333; + + + 51.83.180.158 + + + + + + 40 + 400 + 301 + 31 + + + + background: #F4F4F4; + +/* grey */ +border: 1px solid #A7A7A7; +box-sizing: border-box; +color: #333333; + + + root + + + + + + 40 + 480 + 301 + 31 + + + + background: #F4F4F4; + +/* grey */ +border: 1px solid #A7A7A7; +box-sizing: border-box; +color: #333333; + + + qazqazwsxwsx + + + QLineEdit::Password + + + + + + 40 + 550 + 301 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} + + + + Подключить + + + + + + 50 + 230 + 281 + 16 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 20px; + +/* or 125% */ +display: flex; +align-items: center; +text-align: center; + +/* акцент */ +color: #15CDCB; + + + Где взять данные для подключения → + + + + + + 40 + 550 + 301 + 41 + + + + background: #181922; +border-radius: 4px; + + + 24 + + + Qt::AlignCenter + + + true + + + Подключение... + + + progressBar + pushButton_amnezia_logo_2 + pushButton_amnezia_logo_3 + label_2 + label_4 + label_5 + label_6 + lineEdit_new_server_ip + lineEdit_new_server_login + lineEdit_new_server_password + pushButton_new_server + pushButton + + + + + + + + + 0 + 200 + 380 + 25 + + + + Discovering network... + + + Qt::AlignCenter + + + true + + + + + + 119 + 30 + 142 + 122 + + + + + + + Qt::AlignCenter + + + true + + + + + + 0 + 225 + 380 + 25 + + + + + + + Qt::AlignCenter + + + true + + + + + + 0 + 250 + 380 + 25 + + + + + + + Qt::AlignCenter + + + true + + + + + + 0 + 230 + 380 + 41 + + + + + + + Qt::AlignCenter + + + true + + + + + + 270 + 670 + 91 + 31 + + + + /*font: 8pt "JMH Cthulhumbus";*/ +font-size: 10px; + +color: rgb(62, 62, 62); + + + + Build v. 1.1 + 07 Oct 2020 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + + 0 + 0 + 380 + 200 + + + + PointingHandCursor + + + image: url(:/images/tray/active.png); + + + + + + true + + + + + + 0 + 370 + 380 + 51 + + + + + + + + + 53 + 10 + 15 + 15 + + + + image: url(:/images/download.png); + + + + + + + + + 311 + 10 + 15 + 15 + + + + image: url(:/images/upload.png); + + + + + + + + + 260 + 20 + 118 + 30 + + + + + Lato + 12 + 7 + false + false + + + + color: rgb(66, 209, 133); +font: 63 12pt "Lato"; + + + 0 Mbps + + + Qt::AlignCenter + + + + + + 0 + 20 + 127 + 30 + + + + + Lato + 12 + 7 + false + false + + + + color: rgb(65, 113, 214); +font: 63 12pt "Lato"; + + + 0 Mbps + + + Qt::AlignCenter + + + + + + + 20 + 550 + 341 + 40 + + + + PointingHandCursor + + + QPushButton { + font-size: 13pt; + font: "Open Sans Semibold"; + color:rgb(212, 212, 212); + +background: #181922; +border-radius: 4px; + +font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 21px; + +} + + + + Добавить сайт + + + + + + 340 + 10 + 31 + 31 + + + + PointingHandCursor + + + image: url(:/images/settings.png); + + + + + + + + + 150 + 200 + 80 + 40 + + + + QPushButton:!checked { +image: url(:/images/connect_button_disconnected.png); +} + +QPushButton:checked { +image: url(:/images/connect_button_connected.png); +} + + + + + + true + + + false + + + + + + 0 + 250 + 380 + 31 + + + + font-family: "Lato"; + +font-style: normal; +font-weight: 600; +font-size: 15px; + +color: #181922; + + + + Подключено + + + Qt::AlignCenter + + + + + + 20 + 424 + 341 + 1 + + + + background-image: url(:/images/Line.png); + + + + + + + + + 20 + 450 + 281 + 31 + + + + font-family: "Lato"; + +font-style: normal; +font-weight: 600; +font-size: 15px; + +color: #181922; + + + + + Как использовать VPN + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + false + + + + 20 + 490 + 341 + 19 + + + + Для всех соеднинений + + + + + false + + + + 20 + 520 + 341 + 19 + + + + Для определённых сайтов + + + true + + + + + + +QListView { + outline: 0; + background: transparent; + border: none; + + gridline-color: darkgray; +} + +QListView::item +{ + padding-left: 5px; + border: none; +color: #181922; + +} + +QListView::item:disabled +{ + padding-left: 5px; + border: none; +color: #181922; +} + +QListView::item:selected { + border: none; +background: rgba(167, 167, 167, 0.1); +color: #181922; +} + + + + + 0 + 0 + 381 + 0 + + + + PointingHandCursor + + + QAbstractItemView::NoEditTriggers + + + + + + 10 + 0 + 381 + 25 + + + + PointingHandCursor + + + QPushButton { + image: url(:/images/arrow_right.png); + image-position: left; + text-align: left; + /*font: 17pt "Ancient";*/ + + padding: 1px; + image: url(:/images/arrow_left.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + Back + + + + + + 10 + 0 + 360 + 0 + + + + List of most popular prohibited sites + + + Qt::AlignCenter + + + true + + + + + true + + + + 19 + 50 + 341 + 41 + + + + font-family: Lato; +font-style: normal; +font-weight: bold; +font-size: 20px; +line-height: 25px; + +/* or 125% */ + +/* black */ +color: #181922; + + + Эти сайты будут открываться через VPN + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + 20 + 200 + 341 + 361 + + + + PointingHandCursor + + + QAbstractItemView::NoEditTriggers + + + + + + 20 + 150 + 281 + 31 + + + + + Lato + -1 + 50 + false + false + + + + background: #FFFFFF; + +/* grey */ +border: 1px solid #A7A7A7; +box-sizing: border-box; + + + + + + Qt::AlignCenter + + + Например, rutor.org или 17.21.111.8 + + + + + true + + + + 310 + 150 + 51 + 31 + + + + PointingHandCursor + + + /* black */ +background: #181922; +border-radius: 4px; +font-size: 18pt; + + + + + + + + + true + + + + 90 + 584 + 201 + 21 + + + + PointingHandCursor + + + color: #181922; + + + Удалить выбранный + + + + + + 20 + 115 + 311 + 21 + + + + font-family: Lato; +font-style: normal; +font-weight: normal; +font-size: 16px; +line-height: 150%; + +/* identical to box height, or 24px */ + +/* text */ +color: #333333; + + + Адрес сайта или ip-адрес + + + + + + + + + + + SlidingStackedWidget + QStackedWidget +
ui/Controls/SlidingStackedWidget.h
+ 1 +
+
+ + +
diff --git a/client/ui/mainwindow_mac.ui b/client/ui/mainwindow_mac.ui new file mode 100644 index 000000000..dc9a01d0a --- /dev/null +++ b/client/ui/mainwindow_mac.ui @@ -0,0 +1,1665 @@ + + + MainWindow + + + + 0 + 0 + 380 + 565 + + + + + + + QWidget { + font-size: 15px; + outline: none; + color: "#6B7C93"; +} +QPushButton { + border: none; + border-radius: 5px; +} + +QLineEdit { + border:1px solid rgb(120, 120, 120); + border-radius: 3px; + color: rgb(40, 40, 40); + + /*selection-background-color: darkgray;*/ + padding-left: 15px; +} +QLineEdit:focus { + /*border:2px solid rgb(66, 209, 133);*/ + border:2px solid white; +} +QLineEdit[error] { + border-bottom:1px solid rgb(213, 40, 60); + color: rgb(213, 40, 60); + background-color: rgb(40, 38, 38); +} +QLineEdit:disabled { + border-bottom:1px solid rgb(213, 40, 60); + color: rgb(213, 40, 60); + background-color: rgb(40, 38, 38); +} + +QCheckBox { + color: "#777777"; +} + + + + + + + 0 + 0 + 380 + 565 + + + + QWidget #widget_main { + background-color: white; +} + + + + + + 0 + 0 + 380 + 0 + + + + true + + + QPushButton { + padding:5px; +} +QPushButton:hover { + padding:0px; +} + + + + + + 344 + 8 + 20 + 20 + + + + image: url(:/images/close.png); + + + + + + + + + 299 + 13 + 20 + 20 + + + + image: url(:/images/min.png); + + + + + + + + + 39 + 2 + 200 + 30 + + + + true + + + AmneziaVPN + + + + + + 13 + 6 + 20 + 20 + + + + true + + + image: url(:/images/headericon.png); + + + + + + + + + + 0 + 0 + 380 + 565 + + + + QStackedWidget#stackedWidget_main{ +background: transparent; +} + + + + + QWidget#page_login{ +background: transparent; +} + + + + + + 90 + 45 + 200 + 59 + + + + image: url(:/images/amneziavpnimage.png); + + + + + + + + + 40 + 143 + 291 + 16 + + + + + + + Username + + + + + + 40 + 228 + 91 + 16 + + + + + -1 + + + + + + + Password + + + + + + 40 + 169 + 300 + 40 + + + + + + + 128 + + + Enter Username + + + + + + 40 + 254 + 300 + 40 + + + + + + + 128 + + + QLineEdit::Password + + + Enter Password + + + + + + 70 + 354 + 240 + 40 + + + + PointingHandCursor + + + QPushButton { + color: rgb(255, 255, 255); + background-color: "#42d185"; +} + +QPushButton:hover { + background-color: rgb(92, 228, 156); +} + + + Login + + + + + + 60 + 505 + 305 + 30 + + + + Launch AmneziaVPN on startup + + + + + + 60 + 465 + 305 + 30 + + + + + -1 + + + + Save Password + + + + + + 0 + 405 + 380 + 51 + + + + background-color: rgb(255, 255, 255); +color: rgb(255, 0, 0); + + + + + + Qt::AlignCenter + + + true + + + + + + 0 + 413 + 380 + 30 + + + + PointingHandCursor + + + QPushButton { + color: "#4171d6"; +} + +QPushButton:hover { + text-decoration: underline; +} + + + Do not have account? + + + + + + 140 + 395 + 81 + 10 + + + + + Open Sans + 11 + 50 + false + false + true + + + + PointingHandCursor + + + font: 11pt "Open Sans"; +color: rgb(74, 74, 74); + + + + + + + + + 126 + 300 + 211 + 25 + + + + PointingHandCursor + + + QPushButton { + color: "#4171d6"; + text-align:right; +} + +QPushButton:hover { + text-decoration: underline; +} + + + Forgot Password? + + + + + + + + + + + 25 + 65 + 331 + 44 + + + + 0 + + + + + + + + + 0 + 39 + 331 + 0 + + + + border-image: url(:/images/underline.png); + + + + + + + + + 100 + 9 + 161 + 30 + + + + font-size: 20px; + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 70 + 13 + 20 + 20 + + + + + + + + + + true + + + + + + 321 + 9 + 0 + 30 + + + + + + + + + + label_3 + label_detected_country + label_detected_flag + label_detected_location + + + + + + + 0 + 55 + 380 + 16 + + + + font-size: 12px; + + + Your current IP + + + Qt::AlignCenter + + + + + + 0 + 114 + 380 + 261 + + + + + + + 0 + 24 + 380 + 212 + + + + PointingHandCursor + + + image: url(:/images/connectbutton.png); + + + + + + true + + + + + + + + 0 + 24 + 380 + 212 + + + + PointingHandCursor + + + + + + + + + true + + + + + + 0 + 24 + 380 + 212 + + + + + + + Qt::AlignCenter + + + label_conn_animation + pushButton_cancelConnect + + + + + + 0 + 24 + 380 + 212 + + + + ArrowCursor + + + image: url(:/images/connected_green.png); + + + + + + true + + + + + + 0 + 24 + 380 + 212 + + + + ArrowCursor + + + image: url(:/images/connected_gray.png); + + + + + + true + + + + + + 114 + 149 + 148 + 3 + + + + Qt::Horizontal + + + + + + 0 + 151 + 380 + 59 + + + + PointingHandCursor + + + image: url(:/images/power.png); + + + + + + + + + 0 + 76 + 380 + 25 + + + + color: rgb(168, 168, 168); + + + DURATION + + + Qt::AlignCenter + + + + + + 0 + 101 + 380 + 40 + + + + + Open Sans + 24 + 50 + false + false + + + + color: rgb(44, 83, 120); +font: 24pt "Open Sans"; + + + 00:00:00 + + + Qt::AlignCenter + + + pushButton_d1 + pushButton_d2 + line + label_7 + label_duration + pushButton_disconnect + + + + + + 0 + 423 + 380 + 1 + + + + image: url(:/images/underline.png); +background: transparent; + + + + + + + + + 78 + 386 + 221 + 30 + + + + UK - Berkshire + + + + + + 40 + 386 + 30 + 30 + + + + + + + + + + true + + + + + + 314 + 394 + 21 + 16 + + + + > + + + + + + 20 + 385 + 331 + 41 + + + + PointingHandCursor + + + + + + + + + + + + 140 + 434 + 121 + 16 + + + + + -1 + + + + font-size: 10px; +color: rgb(180, 180, 180); + + + Select Location + + + + + + 0 + 455 + 380 + 101 + + + + + + + 78 + 20 + 283 + 41 + + + + Automatically select server + + + + + + + + 100 + 63 + 91 + 16 + + + + + + + VPN Status - + + + + + + 200 + 63 + 91 + 16 + + + + color: rgb(66, 209, 133); + + + Connected + + + + + + 0 + 80 + 380 + 20 + + + + + Open Sans + 10 + 50 + false + false + + + + font: 10pt "Open Sans"; +color: rgb(180, 180, 180); + + + + + + Qt::AlignCenter + + + + + + 0 + 7 + 380 + 50 + + + + + + 252 + 3 + 101 + 20 + + + + + -1 + + + + color: rgb(66, 209, 133); + + + Upload speed + + + + + + 252 + 19 + 118 + 30 + + + + + Open Sans Semibold + 14 + 7 + false + false + + + + color: rgb(66, 209, 133); +font: 63 14pt "Open Sans Semibold"; + + + 55.55 Mbps + + + + + + 14 + 10 + 29 + 29 + + + + image: url(:/images/download.png); + + + + + + + + + 48 + 3 + 131 + 20 + + + + + -1 + + + + color: rgb(65, 113, 214); + + + Download speed + + + + + + 48 + 19 + 118 + 30 + + + + + Open Sans Semibold + 14 + 7 + false + false + + + + color: rgb(65, 113, 214); +font: 63 14pt "Open Sans Semibold"; + + + 55.55 Mbps + + + + + + 215 + 10 + 29 + 29 + + + + image: url(:/images/upload.png); + + + + + + + widget_conn_speed + label_18 + label_19 + label_port_forward + + + + + + 0 + 350 + 380 + 20 + + + + font: 9pt "Open Sans"; + + + + + + + Qt::AlignCenter + + + + + + 330 + 10 + 30 + 30 + + + + PointingHandCursor + + + +QPushButton { + padding:0px; /* 1px for zooming */ + image: url(:/images_mac/settings.png); +} +QPushButton:hover { + padding:0px; +} + + + + + + + + + + QWidget#page_servers { + background: #ffffff; +} + +QPushButton { + color: "#4171D6"; + border-radius: 0px; + border : 2px solid "#4171D6"; + font-size: 13px; +} + +QPushButton:checked { + background: "#4171D6"; + color: white; +} + +QTableView { + outline: 0; + alternate-background-color: rgb(247, 249, 249); + background-color: white; + border-bottom-left-radius:10px; + border-bottom-right-radius:10px; + + gridline-color: white; +} + +QTableView::item +{ + padding-left: 5px; + + border-top: 1px solid lightgray; +} + +/* +QTableView::item::selected +{ + border: 0px; + padding-left: 5px; + background-color: rgb(99, 180, 251); + + border: : rgb(99, 180, 251); + +} +*/ +QTableView::item::hover +{ + border: 0px; + padding-left: 5px; + background-color: rgb(99, 180, 251); + border: : rgb(99, 180, 251); +} + + + +QScrollBar:vertical { /* The area behind the scrollbar covering entire height. */ + background-color: rgba(0, 0, 0,0); + opacity: 100; + width: 10px; /* set width to zero to hide scrollbar entirely. Can look quite clean and scrolling still works with mousewheel. */ + margin: 10px px; /* Takes the height of the buttons + 3 extra pixels to leave some free space between handle and buttons */ + +} + +QScrollBar::handle:vertical { /* The handle you scroll with */ + image-position: center; /* image is used as a small gripper in the center of the scrollbar.. You can also use background-image to use two images */ + background-color: rgb(200, 200, 200); + border: 2px solid rgb(240,240,240); + border-radius: 1px; + min-height: 10px; +} +QScrollBar::handle:vertical:hover { /* state when you hover over the handle */ + background-color: rgb(160, 160, 160); +} +QScrollBar::handle:vertical:pressed { /* state when you hover over the handle */ + background-color: rgb(120, 120, 120); +} +QScrollBar::sub-line:vertical { /* button to scroll up */ + background-color: rgb(240,240,240); + height: 10px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover { /* hover state of button to scroll up */ + background-color: rgb(200, 200, 200); +} + +QScrollBar::up-arrow:vertical { /* arrow to scroll up with */ + top: 2px; +} + +QScrollBar::add-line:vertical { /* Button to scroll down */ + background-color: rgb(240,240,240); + height: 10px; + padding-top: 2px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} +QScrollBar::add-line:vertical:hover { /* hover state of button to scroll down */ + background-color: rgb(200, 200, 200); +} + +QScrollBar::down-arrow:vertical { /* arrow to scroll down with */ + bottom: 3px; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background-color: rgb(240,240,240); + +} + + + + + + + 10 + 50 + 121 + 30 + + + + border-top-left-radius: 4px; +border-bottom-left-radius: 4px; + + + All + + + true + + + true + + + true + + + + + + 129 + 50 + 122 + 30 + + + + Recommended + + + true + + + true + + + + + + 249 + 50 + 121 + 30 + + + + border-top-right-radius: 4px; +border-bottom-right-radius: 4px; + + + Favorites + + + true + + + true + + + + + + 20 + 17 + 25 + 17 + + + + PointingHandCursor + + + QPushButton { + padding: 1px; + border: none; + image: url(:/images/arrow_back.png); +} +QPushButton:hover { + padding: 0px; +} + + + + + + + + + + + 0 + 94 + 380 + 462 + + + + PointingHandCursor + + + true + + + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOff + + + QAbstractItemView::NoSelection + + + QAbstractItemView::SelectRows + + + false + + + Qt::NoPen + + + false + + + true + + + false + + + + + + 0 + 92 + 370 + 5 + + + + background-color: rgb(255, 255, 255); + + + + + + + + + + 330 + 10 + 0 + 30 + + + + PointingHandCursor + + + +QPushButton { + padding:1px; + image: url(:/images_mac/settings.png); +} +QPushButton:hover { + padding:0px; +} + + + + + + + + + + 0 + 15 + 380 + 21 + + + + font-size: 20px; +color: "#6B7C93"; + + + Servers + + + Qt::AlignCenter + + + pushButton_servers_all + pushButton_servers_recommended + pushButton_servers_favorites + tableView_servers + label_hide_first_line + pushButton_settings_2 + label_15 + pushButton_cancel + + + + + + 0 + 45 + 380 + 41 + + + + font-size: 30px; + + + Sign Up + + + Qt::AlignCenter + + + + + + 70 + 354 + 240 + 40 + + + + PointingHandCursor + + + QPushButton { + color: rgb(255, 255, 255); + background-color: "#42d185"; +} + +QPushButton:hover { + background-color: rgb(92, 228, 156); +} + + + Login + + + + + + 0 + 413 + 380 + 30 + + + + PointingHandCursor + + + QPushButton { + color: "#4171d6"; +} + +QPushButton:hover { + text-decoration: underline; +} + + + Do not have account? + + + + + + 40 + 143 + 291 + 16 + + + + + + + Username + + + + + + 40 + 254 + 300 + 40 + + + + + + + 128 + + + QLineEdit::Password + + + + + + + + + 40 + 169 + 300 + 40 + + + + + + + 128 + + + Enter Username + + + + + + 40 + 228 + 91 + 16 + + + + + -1 + + + + + + + Password + + + + + + 0 + 520 + 380 + 25 + + + + PointingHandCursor + + + QPushButton { + color: "#4171d6"; +} + +QPushButton:hover { + text-decoration: underline; +} + + + Forgot Password? + + + + + + + + + + + SlidingStackedWidget + QStackedWidget +
ui/Controls/SlidingStackedWidget.h
+ 1 +
+ + ServersTableView + QTableView +
ui/Controls/serverstableview.h
+
+
+ + +