From 6a478408eeef9464d5edac472bf39d3ccfa82d0b Mon Sep 17 00:00:00 2001 From: kokekanon <114332266+kokekanon@users.noreply.github.com> Date: Tue, 12 May 2026 19:47:00 -0400 Subject: [PATCH] ci: build apk android with github actions (#1715) New Features: - Added scrollable areas to general options, action bar settings, and game panel controls for improved navigation on compact displays. - Integrated Android APK build automation into the CI pipeline. Chores: - Enhanced build system to support flexible Android architecture configuration during automated builds. --- .github/workflows/ci.yml | 35 + .../workflows/reusable-build-android-apk.yml | 231 +++++++ android/app/build.gradle.kts | 10 +- build_luajit_android.sh | 76 ++- .../styles/controls/general.otui | 433 ++++++------ .../styles/interface/actionbars.otui | 628 +++++++++--------- .../option_control_buttons.otui | 302 +++++---- 7 files changed, 1029 insertions(+), 686 deletions(-) create mode 100644 .github/workflows/reusable-build-android-apk.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15b16d418..4d404fec2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,7 @@ on: - "src/**" - "tests/**" - "cmake/**" + - "android/**" - "browser/**" - "data/**" - "mods/**" @@ -20,6 +21,12 @@ on: - "Dockerfile" - "Dockerfile.browser" - "Dockerfile.browser.sh" + - "build_luajit_android.sh" + - "setup_android_deps.sh" + - "init.lua" + - "otclientrc.lua" + - "cacert.pem" + - "config.ini" - ".dockerignore" - ".yamllint.yaml" - ".reviewdog.yml" @@ -32,6 +39,7 @@ on: - "src/**" - "tests/**" - "cmake/**" + - "android/**" - "browser/**" - "data/**" - "mods/**" @@ -44,6 +52,12 @@ on: - "Dockerfile" - "Dockerfile.browser" - "Dockerfile.browser.sh" + - "build_luajit_android.sh" + - "setup_android_deps.sh" + - "init.lua" + - "otclientrc.lua" + - "cacert.pem" + - "config.ini" - ".dockerignore" - ".yamllint.yaml" - ".reviewdog.yml" @@ -61,6 +75,7 @@ jobs: contents: read outputs: compile: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'merge_group') && 'true' || steps.filter.outputs.compile }} + android: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'merge_group') && 'true' || steps.filter.outputs.android }} docker: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'merge_group') && 'true' || steps.filter.outputs.docker }} browser: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'merge_group') && 'true' || steps.filter.outputs.browser }} steps: @@ -90,6 +105,16 @@ jobs: - ".github/workflows/reusable-build-windows.yml" - ".github/workflows/reusable-checks.yml" - ".github/workflows/reusable-tests-lua.yml" + android: + - "src/**" + - "android/**" + - "cmake/**" + - "CMakeLists.txt" + - "vcpkg.json" + - "build_luajit_android.sh" + - "setup_android_deps.sh" + - ".github/workflows/ci.yml" + - ".github/workflows/reusable-build-android-apk.yml" docker: - "Dockerfile" - ".dockerignore" @@ -151,6 +176,16 @@ jobs: uses: ./.github/workflows/reusable-build-windows.yml secrets: inherit + build-android-apk: + name: Build - Android APK + needs: [changes, checks, tests-lua] + if: needs.changes.outputs.android == 'true' && needs.checks.result == 'success' && needs.tests-lua.result == 'success' && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) + permissions: + contents: read + pull-requests: read + uses: ./.github/workflows/reusable-build-android-apk.yml + secrets: inherit + build-docker: name: Build - Docker needs: [changes, checks, tests-lua] diff --git a/.github/workflows/reusable-build-android-apk.yml b/.github/workflows/reusable-build-android-apk.yml new file mode 100644 index 000000000..b387bbcce --- /dev/null +++ b/.github/workflows/reusable-build-android-apk.yml @@ -0,0 +1,231 @@ +name: Reusable Android APK Build + +on: + workflow_call: + +permissions: + contents: read + pull-requests: read + +env: + JAVA_VERSION: "17" + NDK_VERSION: "29.0.13599879" + CMAKE_VERSION: "3.22.1" + COMPILE_SDK: "36" + BUILD_TOOLS_VERSION: "36.0.0" + CI_ANDROID_ABIS: "arm64-v8a" + CI_VCPKG_TRIPLET: "arm64-android" + LUAJIT_COMMIT: "d0e88930ddde28ff662503f9f20facf34f7265aa" + VCPKG_ROOT: ${{ github.workspace }}/vcpkg + VCPKG_FEATURE_FLAGS: versions,binarycaching + +concurrency: + group: otclient-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + if: github.event_name != 'pull_request' || github.event.pull_request.draft == false + name: Android release APK + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Set up JDK ${{ env.JAVA_VERSION }} + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: temurin + cache: gradle + cache-dependency-path: | + android/**/*.gradle + android/**/*.gradle.kts + android/gradle/wrapper/gradle-wrapper.properties + + - name: Set up Android SDK + uses: android-actions/setup-android@v3 + + - name: Install host build packages + run: | + set -euo pipefail + sudo apt-get update + sudo apt-get install -y \ + build-essential \ + curl \ + g++-multilib \ + gcc-multilib \ + git \ + make \ + ninja-build \ + pkg-config \ + python3 \ + unzip \ + zip + + - name: Install Android SDK packages + run: | + set -euo pipefail + sdk_root="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" + if [[ -z "${sdk_root}" ]]; then + echo "::error title=Missing Android SDK::ANDROID_SDK_ROOT or ANDROID_HOME must be set." + exit 1 + fi + + sdkmanager --install \ + "platform-tools" \ + "platforms;android-${COMPILE_SDK}" \ + "build-tools;${BUILD_TOOLS_VERSION}" \ + "cmake;${CMAKE_VERSION}" \ + "ndk;${NDK_VERSION}" + + ndk_dir="${sdk_root}/ndk/${NDK_VERSION}" + if [[ ! -d "${ndk_dir}" ]]; then + ndk_dir="$(find "${sdk_root}/ndk" -maxdepth 1 -type d -name "${NDK_VERSION}*" | sort | head -n 1)" + fi + if [[ -z "${ndk_dir}" || ! -d "${ndk_dir}" ]]; then + echo "::error title=Missing Android NDK::NDK ${NDK_VERSION} was not installed." + exit 1 + fi + + echo "ANDROID_HOME=${sdk_root}" >> "${GITHUB_ENV}" + echo "ANDROID_SDK_ROOT=${sdk_root}" >> "${GITHUB_ENV}" + echo "ANDROID_NDK_HOME=${ndk_dir}" >> "${GITHUB_ENV}" + echo "ANDROID_NDK_ROOT=${ndk_dir}" >> "${GITHUB_ENV}" + + - name: Read vcpkg baseline + id: vcpkg + run: | + set -euo pipefail + baseline="$(python3 -c 'import json; print(json.load(open("vcpkg.json"))["builtin-baseline"])')" + if [[ ! "${baseline}" =~ ^[0-9a-f]{40}$ ]]; then + echo "::error title=Invalid vcpkg baseline::vcpkg.json must contain a full 40-character builtin-baseline SHA." + exit 1 + fi + echo "baseline=${baseline}" >> "${GITHUB_OUTPUT}" + + - name: Cache vcpkg checkout + uses: actions/cache@v4 + with: + path: ${{ env.VCPKG_ROOT }} + key: vcpkg-${{ runner.os }}-${{ steps.vcpkg.outputs.baseline }} + + - name: Bootstrap vcpkg + run: | + set -euo pipefail + if [[ ! -d "${VCPKG_ROOT}/.git" ]]; then + git clone https://github.com/microsoft/vcpkg.git "${VCPKG_ROOT}" + fi + git -C "${VCPKG_ROOT}" fetch --depth 1 origin "${{ steps.vcpkg.outputs.baseline }}" + git -C "${VCPKG_ROOT}" checkout "${{ steps.vcpkg.outputs.baseline }}" + "${VCPKG_ROOT}/bootstrap-vcpkg.sh" -disableMetrics + + - name: Export vcpkg GitHub Actions cache variables + uses: actions/github-script@v9 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + core.exportVariable('VCPKG_BINARY_SOURCES', 'clear;x-gha,readwrite'); + + - name: Cache LuaJIT Android libraries + id: luajit-cache + uses: actions/cache@v4 + with: + path: | + luajit-src + android/app/libs + key: luajit-android-${{ runner.os }}-${{ env.CI_ANDROID_ABIS }}-ndk-${{ env.NDK_VERSION }}-${{ env.LUAJIT_COMMIT }}-${{ hashFiles('build_luajit_android.sh') }} + + - name: Fetch LuaJIT source + if: steps.luajit-cache.outputs.cache-hit != 'true' + run: | + set -euo pipefail + git clone https://github.com/LuaJIT/LuaJIT.git luajit-src + git -C luajit-src checkout "${LUAJIT_COMMIT}" + + - name: Build LuaJIT for Android + if: steps.luajit-cache.outputs.cache-hit != 'true' + env: + OTCLIENT_ANDROID_ABIS: ${{ env.CI_ANDROID_ABIS }} + run: | + set -euo pipefail + chmod +x build_luajit_android.sh + ./build_luajit_android.sh + + - name: Pack game assets into data.zip + run: | + set -euo pipefail + mkdir -p android/app/src/main/assets + python3 - <<'PY' + from pathlib import Path + import zipfile + + output = Path("android/app/src/main/assets/data.zip") + roots = [Path("data"), Path("mods"), Path("modules")] + files = [Path("init.lua"), Path("otclientrc.lua"), Path("cacert.pem"), Path("config.ini")] + + with zipfile.ZipFile(output, "w", zipfile.ZIP_DEFLATED) as archive: + for root in roots: + if not root.exists(): + raise SystemExit(f"Missing asset directory: {root}") + for path in sorted(root.rglob("*")): + if path.is_file(): + archive.write(path, path.as_posix()) + + for path in files: + if path.exists(): + archive.write(path, path.as_posix()) + + print(f"Wrote {output} ({output.stat().st_size} bytes)") + PY + + - name: Create fallback release keystore + run: | + set -euo pipefail + mkdir -p "${HOME}/.android" + if [[ ! -f "${HOME}/.android/debug.keystore" ]]; then + keytool -genkeypair \ + -keystore "${HOME}/.android/debug.keystore" \ + -storepass android \ + -keypass android \ + -alias androiddebugkey \ + -keyalg RSA \ + -keysize 2048 \ + -validity 10000 \ + -dname "CN=Android Debug,O=Android,C=US" + fi + + - name: Make Gradle wrapper executable + run: chmod +x android/gradlew + + - name: Build APK + working-directory: android + env: + OTCLIENT_ANDROID_ABIS: ${{ env.CI_ANDROID_ABIS }} + VCPKG_ROOT: ${{ env.VCPKG_ROOT }} + run: ./gradlew :app:assembleRelease --no-daemon --stacktrace --info + + - name: List APK outputs + run: find android/app/build/outputs/apk/release -maxdepth 1 -type f -name "*.apk" -print + + - name: Upload APK artifact + uses: actions/upload-artifact@v7 + with: + name: otclient-android-release-${{ github.sha }} + path: android/app/build/outputs/apk/release/*.apk + if-no-files-found: error + retention-days: 14 + + - name: Write download summary + run: | + { + echo "## Android APK" + echo "" + echo "The APK was uploaded as the workflow artifact:" + echo "" + echo "- otclient-android-release-${GITHUB_SHA}" + } >> "${GITHUB_STEP_SUMMARY}" diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index d69b9132d..ab0ff1d63 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -3,6 +3,14 @@ plugins { id("org.jetbrains.kotlin.android") } +val ciAbiFilters = providers.gradleProperty("otclient.android.abis") + .orElse(providers.environmentVariable("OTCLIENT_ANDROID_ABIS")) + .orNull + ?.split(",") + ?.map { it.trim() } + ?.filter { it.isNotEmpty() } + ?: listOf("arm64-v8a", "armeabi-v7a", "x86_64", "x86") + android { namespace = "com.github.otclient" compileSdk = 36 @@ -16,7 +24,7 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" ndk { - abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64", "x86") + abiFilters += ciAbiFilters } externalNativeBuild { diff --git a/build_luajit_android.sh b/build_luajit_android.sh index 6416f4f9f..3cea3d885 100644 --- a/build_luajit_android.sh +++ b/build_luajit_android.sh @@ -1,17 +1,17 @@ #!/bin/bash set -euo pipefail -# Build LuaJIT 2.1 for all Android ABIs using NDK cross-compilation -# Based on official LuaJIT docs (luajit.org/install.html) and vcpkg build flags +# Build LuaJIT 2.1 for Android ABIs using NDK cross-compilation. # # Requirements: # - ANDROID_NDK_HOME set (NDK 25+) -# - gcc-multilib installed (for 32-bit targets: sudo apt install gcc-multilib) +# - gcc-multilib installed when building 32-bit ABIs # - LuaJIT source at ./luajit-src/ (commit d0e88930 recommended for vcpkg compat) SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" NDK="${ANDROID_NDK_HOME:-/home/dev/android-sdk/ndk/29.0.13599879}" NDKBIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin" LUAJIT_SRC="$SCRIPT_DIR/luajit-src" INSTALL_BASE="$SCRIPT_DIR/android/app/libs" +REQUESTED_ABIS="${OTCLIENT_ANDROID_ABIS:-arm64-v8a,armeabi-v7a,x86_64,x86}" if [ ! -d "$LUAJIT_SRC/src" ]; then echo "ERROR: LuaJIT source not found at $LUAJIT_SRC" @@ -19,10 +19,21 @@ if [ ! -d "$LUAJIT_SRC/src" ]; then exit 1 fi -# Verify gcc -m32 works (needed for 32-bit targets) -if ! gcc -m32 -x c -c /dev/null -o /dev/null 2>/dev/null; then - echo "Installing gcc-multilib for 32-bit cross-compilation..." - sudo apt-get install -y gcc-multilib g++-multilib +IFS=',' read -r -a ABI_LIST <<< "$REQUESTED_ABIS" +needs_32bit=false +for ABI in "${ABI_LIST[@]}"; do + ABI_TRIMMED="$(echo "$ABI" | xargs)" + if [ "$ABI_TRIMMED" = "armeabi-v7a" ] || [ "$ABI_TRIMMED" = "x86" ]; then + needs_32bit=true + break + fi +done + +if [ "$needs_32bit" = true ]; then + if ! gcc -m32 -x c -c /dev/null -o /dev/null 2>/dev/null; then + echo "Installing gcc-multilib for 32-bit cross-compilation..." + sudo apt-get install -y gcc-multilib g++-multilib + fi fi build_luajit() { @@ -32,14 +43,7 @@ build_luajit() { cd "$LUAJIT_SRC" make clean 2>/dev/null || true - # Official LuaJIT cross-compilation approach: - # - HOST_CC="gcc -m32" for 32-bit targets (correct struct offsets in buildvm) - # - CROSS= for NDK toolchain prefix - # - STATIC_CC/DYNAMIC_CC for clang compiler - # - TARGET_CFLAGS with -DLUAJIT_UNWIND_EXTERNAL (required for Android NDK C++ interop) - # - Never use TARGET_SYS=Android (causes crashes, LuaJIT Issue #440) - # - Use 'amalg' target for optimized single-file compilation - make -j$(nproc) amalg \ + make -j"$(nproc)" amalg \ HOST_CC="$HOST_CC" \ CROSS="${NDKBIN}/${CROSS_PREFIX}" \ STATIC_CC="${NDKBIN}/${CC_PREFIX}clang" \ @@ -50,26 +54,34 @@ build_luajit() { TARGET_CFLAGS="-fPIC -DLUAJIT_UNWIND_EXTERNAL -fno-stack-protector" \ BUILDMODE=static - # Install lib local LIB_DIR="$INSTALL_BASE/lib/$ABI" mkdir -p "$LIB_DIR" cp src/libluajit.a "$LIB_DIR/libluajit-5.1.a" echo " -> $LIB_DIR/libluajit-5.1.a ($(du -h "$LIB_DIR/libluajit-5.1.a" | cut -f1))" } -# arm64-v8a: 64-bit ARM (most modern Android devices) -build_luajit "arm64-v8a" "aarch64-linux-android-" "aarch64-linux-android21-" "gcc" +for ABI in "${ABI_LIST[@]}"; do + ABI_TRIMMED="$(echo "$ABI" | xargs)" + case "$ABI_TRIMMED" in + arm64-v8a) + build_luajit "arm64-v8a" "aarch64-linux-android-" "aarch64-linux-android21-" "gcc" + ;; + armeabi-v7a) + build_luajit "armeabi-v7a" "arm-linux-androideabi-" "armv7a-linux-androideabi21-" "gcc -m32" + ;; + x86_64) + build_luajit "x86_64" "x86_64-linux-android-" "x86_64-linux-android21-" "gcc" + ;; + x86) + build_luajit "x86" "i686-linux-android-" "i686-linux-android21-" "gcc -m32" + ;; + *) + echo "ERROR: Unsupported ABI '$ABI_TRIMMED'" + exit 1 + ;; + esac +done -# armeabi-v7a: 32-bit ARM (older devices) — requires HOST_CC="gcc -m32" -build_luajit "armeabi-v7a" "arm-linux-androideabi-" "armv7a-linux-androideabi21-" "gcc -m32" - -# x86_64: 64-bit x86 (emulators, Chromebooks) -build_luajit "x86_64" "x86_64-linux-android-" "x86_64-linux-android21-" "gcc" - -# x86: 32-bit x86 (older emulators) — requires HOST_CC="gcc -m32" -build_luajit "x86" "i686-linux-android-" "i686-linux-android21-" "gcc -m32" - -# Install headers (shared across all ABIs) echo "" echo "=== Installing headers ===" mkdir -p "$INSTALL_BASE/include/luajit" @@ -77,7 +89,6 @@ cp "$LUAJIT_SRC/src/lua.h" "$LUAJIT_SRC/src/lualib.h" "$LUAJIT_SRC/src/lauxlib.h "$LUAJIT_SRC/src/luaconf.h" "$LUAJIT_SRC/src/luajit.h" \ "$INSTALL_BASE/include/luajit/" -# Create lua.hpp C++ wrapper cat > "$INSTALL_BASE/include/luajit/lua.hpp" << 'LUAHPP' // C++ wrapper for LuaJIT header files. @@ -90,5 +101,8 @@ extern "C" { LUAHPP echo "" -echo "=== All ABIs built successfully ===" -ls -lh "$INSTALL_BASE/lib/"*/libluajit-5.1.a +echo "=== Requested ABIs built successfully ===" +for ABI in "${ABI_LIST[@]}"; do + ABI_TRIMMED="$(echo "$ABI" | xargs)" + ls -lh "$INSTALL_BASE/lib/$ABI_TRIMMED/libluajit-5.1.a" +done diff --git a/modules/client_options/styles/controls/general.otui b/modules/client_options/styles/controls/general.otui index 160426b99..45ebc172f 100644 --- a/modules/client_options/styles/controls/general.otui +++ b/modules/client_options/styles/controls/general.otui @@ -1,218 +1,237 @@ UIWidget anchors.fill: parent visible: false - SmallReversedQtPanel + + UIScrollArea + id: generalScrollArea anchors.left: parent.left - anchors.right: parent.right + anchors.right: generalScrollBar.left anchors.top: parent.top - height: 22 + anchors.bottom: parent.bottom + vertical-scrollbar: generalScrollBar - OptionCheckBoxMarked - id: showPing - !text: tr('Show connection ping') - !tooltip: tr('Display connection speed to the server (milliseconds)') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - height: 32 - margin-top: 7 - - $mobile: - height: 0 - margin-top: 0 - visible: false - - Label - id: mouseControlLabel + SmallReversedQtPanel anchors.left: parent.left - margin-left: 18 - color: #c0c0c0ff - anchors.verticalCenter: parent.verticalCenter - text-align: left - !text: tr('Mouse Control:') - - QtComboBox - id: mouseControlMode - width: 120 - margin-left: 10 - anchors.verticalCenter: prev.verticalCenter - anchors.left: prev.right - mouse-scroll: false - !tooltip: tr('Regular Controls: Right-click opens menu, use Ctrl+Click for direct item use\nClassic Controls: Right-click for direct use\nLeft Smart-Click: Left-click for direct item use, look at non-walkable objects, or walk to walkable objects. Right-click opens menu') - + anchors.right: parent.right + anchors.top: parent.top + height: 22 + + OptionCheckBoxMarked + id: showPing + !text: tr('Show connection ping') + !tooltip: tr('Display connection speed to the server (milliseconds)') + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + height: 32 + margin-top: 7 + $mobile: + height: 0 + margin-top: 0 visible: false - - QtComboBox - id: lootControlMode - width: 120 - margin-left: 10 - anchors.verticalCenter: prev.verticalCenter - anchors.left: prev.right - mouse-scroll: false - !tooltip: tr('Choose how to loot items when using Classic Controls\nLoot: Right - Use right-click to quickloot AND open containers/corpses\nLoot: SHIFT+Right - Use SHIFT+right-click for quick looting (right-click maintains normal use/open behavior)\nLoot: Left - Use left-click for quick looting only (right-click maintains normal use/open behavior)') - visible: false - SmallReversedQtPanel - anchors.left: parent.left + Label + id: mouseControlLabel + anchors.left: parent.left + margin-left: 18 + color: #c0c0c0ff + anchors.verticalCenter: parent.verticalCenter + text-align: left + !text: tr('Mouse Control:') + + QtComboBox + id: mouseControlMode + width: 120 + margin-left: 10 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + mouse-scroll: false + !tooltip: tr('Regular Controls: Right-click opens menu, use Ctrl+Click for direct item use\nClassic Controls: Right-click for direct use\nLeft Smart-Click: Left-click for direct item use, look at non-walkable objects, or walk to walkable objects. Right-click opens menu') + + $mobile: + visible: false + + QtComboBox + id: lootControlMode + width: 120 + margin-left: 10 + anchors.verticalCenter: prev.verticalCenter + anchors.left: prev.right + mouse-scroll: false + !tooltip: tr('Choose how to loot items when using Classic Controls\nLoot: Right - Use right-click to quickloot AND open containers/corpses\nLoot: SHIFT+Right - Use SHIFT+right-click for quick looting (right-click maintains normal use/open behavior)\nLoot: Left - Use left-click for quick looting only (right-click maintains normal use/open behavior)') + visible: false + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionCheckBox + id: autoChaseOverride + !text: tr('Allow auto chase override') + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionCheckBox + id: talkOnRightClick + !text: tr('Right-click talk to NPC') + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionCheckBoxMarked + id: returnDisablesChat + !text: tr('Enter to disable chat') + !tooltip: tr('Enables disabling chat and enabling WASD when pressed Enter.') + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionCheckBox + id: moveStack + !text: tr('Move stacks directly') + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionCheckBoxMarked + id: smartWalk + !text: tr('Enable smart walking') + !tooltip: tr('Will detect when to use diagonal step based on the\nkeys you are pressing') + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionCheckBox + id: openMaximized + !text: tr('Open containers maximized') + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionCheckBox + id: displayText + !text: tr('Display text messages') + + SmallReversedQtPanel + id: hotkeyDelay_label + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionScaleScroll + id: hotkeyDelay + !text: tr('Hotkey delay: 30ms') + anchors.fill: parent + &minimumScrollValue: 30 + &maximumScrollValue: 250 + &scrollSize: 21 + @onSetup: | + local value = modules.client_options.getOption('hotkeyDelay') + self:setText(tr('Hotkey delay: %dms', value)) + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionScaleScroll + id: walkTurnDelay + !text: tr('Walk delay after turn: 50ms') + anchors.fill: parent + &minimumScrollValue: 10 + &maximumScrollValue: 500 + &scrollSize: 21 + @onSetup: | + local value = modules.client_options.getOption('walkTurnDelay') + self:setText(tr('Walk delay after turn: %dms', value)) + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionScaleScroll + id: walkTeleportDelay + !text: tr('Walk delay after teleport: 200ms') + anchors.fill: parent + &minimumScrollValue: 50 + &maximumScrollValue: 500 + &scrollSize: 21 + @onSetup: | + local value = modules.client_options.getOption('walkTeleportDelay') + self:setText(tr('Walk delay after turn: %dms', value)) + + SmallReversedQtPanel + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionScaleScroll + id: walkStairsDelay + !text: tr('Walk delay after floor change: 200ms') + anchors.fill: parent + &minimumScrollValue: 50 + &maximumScrollValue: 500 + &scrollSize: 21 + @onSetup: | + local value = modules.client_options.getOption('walkStairsDelay') + self:setText(tr('Walk delay after turn: %dms', value)) + + QtButton + id: hotkeysButton + !text: tr('Hotkeys Manager') + @onClick: modules.game_hotkeys.show() + anchors.top: prev.bottom + anchors.left: parent.left + margin-top: 12 + + size: 120 20 + + VerticalScrollBar + id: generalScrollBar + anchors.top: parent.top + anchors.bottom: parent.bottom anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: autoChaseOverride - !text: tr('Allow auto chase override') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: talkOnRightClick - !text: tr('Right-click talk to NPC') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: returnDisablesChat - !text: tr('Enter to disable chat') - !tooltip: tr('Enables disabling chat and enabling WASD when pressed Enter.') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: moveStack - !text: tr('Move stacks directly') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: smartWalk - !text: tr('Enable smart walking') - !tooltip: tr('Will detect when to use diagonal step based on the\nkeys you are pressing') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: openMaximized - !text: tr('Open containers maximized') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBox - id: displayText - !text: tr('Display text messages') - - SmallReversedQtPanel - id: hotkeyDelay_label - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: hotkeyDelay - !text: tr('Hotkey delay: 30ms') - anchors.fill: parent - &minimumScrollValue: 30 - &maximumScrollValue: 250 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('hotkeyDelay') - self:setText(tr('Hotkey delay: %dms', value)) - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: walkTurnDelay - !text: tr('Walk delay after turn: 50ms') - anchors.fill: parent - &minimumScrollValue: 10 - &maximumScrollValue: 500 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('walkTurnDelay') - self:setText(tr('Walk delay after turn: %dms', value)) - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: walkTeleportDelay - !text: tr('Walk delay after teleport: 200ms') - anchors.fill: parent - &minimumScrollValue: 50 - &maximumScrollValue: 500 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('walkTeleportDelay') - self:setText(tr('Walk delay after turn: %dms', value)) - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionScaleScroll - id: walkStairsDelay - !text: tr('Walk delay after floor change: 200ms') - anchors.fill: parent - &minimumScrollValue: 50 - &maximumScrollValue: 500 - &scrollSize: 21 - @onSetup: | - local value = modules.client_options.getOption('walkStairsDelay') - self:setText(tr('Walk delay after turn: %dms', value)) - - QtButton - id: hotkeysButton - !text: tr('Hotkeys Manager') - @onClick: modules.game_hotkeys.show() - anchors.top: prev.bottom - anchors.left: parent.left - margin-top: 12 - - size: 120 20 + step: 14 + pixels-scroll: true + $!mobile: + visible: false \ No newline at end of file diff --git a/modules/client_options/styles/interface/actionbars.otui b/modules/client_options/styles/interface/actionbars.otui index f3341fe1c..817566bf9 100644 --- a/modules/client_options/styles/interface/actionbars.otui +++ b/modules/client_options/styles/interface/actionbars.otui @@ -2,340 +2,356 @@ UIWidget anchors.fill: parent visible: false - SmallReversedQtPanel + UIScrollArea + id: actionBarsScrollArea anchors.left: parent.left - anchors.right: parent.right + anchors.right: actionBarsScrollBar.left anchors.top: parent.top - height: 67 + anchors.bottom: parent.bottom + vertical-scrollbar: actionBarsScrollBar - Label - !text: tr('Show Bottom Action Bars:') + SmallReversedQtPanel anchors.left: parent.left + anchors.right: parent.right anchors.top: parent.top - margin-top: 5 - color: #c0c0c0ff + height: 67 - OptionCheckBox - id: allActionBar13 - !text: tr('All') - anchors.left: prev.right - anchors.top: parent.top - margin-top: 5 - margin-left: 12 + Label + !text: tr('Show Bottom Action Bars:') + anchors.left: parent.left + anchors.top: parent.top + margin-top: 5 + color: #c0c0c0ff - OptionCheckBox - id: actionBarShowBottom1 - !text: tr('Bar 1') - anchors.left: prev.left - anchors.top: parent.top - text-offset: 14 0 - margin-top: 5 - margin-left: 53 + OptionCheckBox + id: allActionBar13 + !text: tr('All') + anchors.left: prev.right + anchors.top: parent.top + margin-top: 5 + margin-left: 12 - OptionCheckBox - id: actionBarShowBottom2 - !text: tr('Bar 2') - anchors.left: prev.left - anchors.top: parent.top - margin-top: 5 - margin-left: 53 - text-offset: 14 0 - OptionCheckBox - id: actionBarShowBottom3 - !text: tr('Bar 3') - anchors.left: prev.left - anchors.top: parent.top - margin-top: 5 - margin-left: 53 - text-offset: 14 0 - Label - id: leftActionLabel - !text: tr('Show Left Action Bars:') + OptionCheckBox + id: actionBarShowBottom1 + !text: tr('Bar 1') + anchors.left: prev.left + anchors.top: parent.top + text-offset: 14 0 + margin-top: 5 + margin-left: 53 + + OptionCheckBox + id: actionBarShowBottom2 + !text: tr('Bar 2') + anchors.left: prev.left + anchors.top: parent.top + margin-top: 5 + margin-left: 53 + text-offset: 14 0 + OptionCheckBox + id: actionBarShowBottom3 + !text: tr('Bar 3') + anchors.left: prev.left + anchors.top: parent.top + margin-top: 5 + margin-left: 53 + text-offset: 14 0 + Label + id: leftActionLabel + !text: tr('Show Left Action Bars:') + anchors.left: parent.left + anchors.top: prev.bottom + margin-top: 5 + color: #c0c0c0ff + + OptionCheckBox + id: allActionBar46 + !text: tr('All') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 30 + + OptionCheckBox + id: actionBarShowLeft1 + !text: tr('Bar 1') + text-offset: 14 0 + anchors.left: prev.left + anchors.top: prev.top + margin-left: 53 + + OptionCheckBox + id: actionBarShowLeft2 + !text: tr('Bar 2') + anchors.left: prev.left + anchors.top: prev.top + margin-left: 53 + text-offset: 14 0 + OptionCheckBox + id: actionBarShowLeft3 + !text: tr('Bar 3') + anchors.left: prev.left + anchors.top: prev.top + margin-left: 53 + text-offset: 14 0 + Label + id: rightActionLabel + !text: tr('Show Right Action Bars:') + anchors.left: parent.left + anchors.top: leftActionLabel.bottom + margin-top: 5 + color: #c0c0c0ff + + OptionCheckBox + id: allActionBar79 + !text: tr('All') + anchors.left: prev.right + anchors.top: prev.top + margin-left: 23 + + OptionCheckBox + id: actionBarShowRight1 + !text: tr('Bar 1') + text-offset: 14 0 + anchors.left: prev.left + anchors.top: prev.top + margin-left: 53 + + OptionCheckBox + id: actionBarShowRight2 + !text: tr('Bar 2') + text-offset: 14 0 + anchors.left: prev.left + anchors.top: prev.top + margin-left: 54 + + OptionCheckBox + id: actionBarShowRight3 + !text: tr('Bar 3') + text-offset: 14 0 + anchors.left: prev.left + anchors.top: prev.top + margin-left: 53 + + SmallReversedQtPanel anchors.left: parent.left + anchors.right: parent.right anchors.top: prev.bottom - margin-top: 5 - color: #c0c0c0ff + margin-top: 7 + height: 22 - OptionCheckBox - id: allActionBar46 - !text: tr('All') - anchors.left: prev.right - anchors.top: prev.top - margin-left: 30 + OptionCheckBoxMarked + id: showAssignedHKButton + !text: tr('Show Assigned Hotkey for Action Button') + !tooltip: tr('Display the hotkey assigned to each action button') - OptionCheckBox - id: actionBarShowLeft1 - !text: tr('Bar 1') - text-offset: 14 0 - anchors.left: prev.left - anchors.top: prev.top - margin-left: 53 - - OptionCheckBox - id: actionBarShowLeft2 - !text: tr('Bar 2') - anchors.left: prev.left - anchors.top: prev.top - margin-left: 53 - text-offset: 14 0 - OptionCheckBox - id: actionBarShowLeft3 - !text: tr('Bar 3') - anchors.left: prev.left - anchors.top: prev.top - margin-left: 53 - text-offset: 14 0 - Label - id: rightActionLabel - !text: tr('Show Right Action Bars:') + SmallReversedQtPanel anchors.left: parent.left - anchors.top: leftActionLabel.bottom - margin-top: 5 - color: #c0c0c0ff + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 - OptionCheckBox - id: allActionBar79 - !text: tr('All') - anchors.left: prev.right - anchors.top: prev.top - margin-left: 23 + OptionCheckBoxMarked + id: showHKObjectsBars + !text: tr('Show Amount of Assigned Objects') + !tooltip: tr('Display the quantity of items assigned to action buttons') - OptionCheckBox - id: actionBarShowRight1 - !text: tr('Bar 1') - text-offset: 14 0 - anchors.left: prev.left - anchors.top: prev.top - margin-left: 53 - - - OptionCheckBox - id: actionBarShowRight2 - !text: tr('Bar 2') - text-offset: 14 0 - anchors.left: prev.left - anchors.top: prev.top - margin-left: 54 - - - OptionCheckBox - id: actionBarShowRight3 - !text: tr('Bar 3') - text-offset: 14 0 - anchors.left: prev.left - anchors.top: prev.top - margin-left: 53 - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: showAssignedHKButton - !text: tr('Show Assigned Hotkey for Action Button') - !tooltip: tr('Display the hotkey assigned to each action button') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: showHKObjectsBars - !text: tr('Show Amount of Assigned Objects') - !tooltip: tr('Display the quantity of items assigned to action buttons') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: showSpellParameters - !text: tr('Show Spell Parameters') - !tooltip: tr('Display spell parameters on action buttons') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: graphicalCooldown - !text: tr('Show Graphical Cooldown') - !tooltip: tr('Display visual cooldown animation on action buttons') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: cooldownSecond - !text: tr('Show Cooldown in Seconds') - !tooltip: tr('Display remaining cooldown time in seconds') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: actionTooltip - !text: tr('Show Action Button Tooltip') - !tooltip: tr('Display tooltips when hovering over action buttons') - - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 75 - - Label - !text: tr('Clear Bottom Action Bars:') + SmallReversedQtPanel anchors.left: parent.left - anchors.top: parent.top - margin-left: 10 - margin-top: 5 - color: #c0c0c0ff + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 - UIWidget - id: toolTipWidgetClearBottom - image-source: /images/icons/show_gui_help_grey - size: 12 12 - anchors.right: parent.right - anchors.top: parent.top - margin-right: 3 - margin-top: 5 - !tooltip: tr('Clear all assignments from bottom action bars') + OptionCheckBoxMarked + id: showSpellParameters + !text: tr('Show Spell Parameters') + !tooltip: tr('Display spell parameters on action buttons') - QtButton - id: clearBottomBar1 - !text: tr('Bar 1') - width: 60 - height: 18 - anchors.right: parent.right - anchors.top: parent.top - margin-right: 130 - margin-top: 3 - @onClick: modules.game_actionbar.resetAction(1) - QtButton - id: clearBottomBar2 - !text: tr('Bar 2') - width: 60 - height: 18 - anchors.right: parent.right - anchors.top: parent.top - margin-right: 65 - margin-top: 3 - @onClick: modules.game_actionbar.resetAction(2) - QtButton - id: clearBottomBar3 - !text: tr('Bar 3') - width: 60 - height: 18 - anchors.right: parent.right - anchors.top: parent.top - margin-right: 0 - margin-top: 3 - @onClick: modules.game_actionbar.resetAction(3) - Label - !text: tr('Clear Left Action Bars:') + SmallReversedQtPanel anchors.left: parent.left - anchors.top: clearBottomBar1.bottom - margin-left: 10 - margin-top: 5 - color: #c0c0c0ff + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 - QtButton - id: clearLeftBar1 - !text: tr('Bar 1') - width: 60 - height: 18 - anchors.right: parent.right - anchors.top: clearBottomBar1.bottom - margin-right: 130 - margin-top: 3 - @onClick: modules.game_actionbar.resetAction(4) - QtButton - id: clearLeftBar2 - !text: tr('Bar 2') - width: 60 - height: 18 - anchors.right: parent.right - anchors.top: clearBottomBar2.bottom - margin-right: 65 - margin-top: 3 - @onClick: modules.game_actionbar.resetAction(5) - QtButton - id: clearLeftBar3 - !text: tr('Bar 3') - width: 60 - height: 18 - anchors.right: parent.right - anchors.top: clearBottomBar3.bottom - margin-right: 0 - margin-top: 3 - @onClick: modules.game_actionbar.resetAction(6) - Label - !text: tr('Clear Right Action Bars:') + OptionCheckBoxMarked + id: graphicalCooldown + !text: tr('Show Graphical Cooldown') + !tooltip: tr('Display visual cooldown animation on action buttons') + + SmallReversedQtPanel anchors.left: parent.left - anchors.top: clearLeftBar1.bottom - margin-left: 10 - margin-top: 5 - color: #c0c0c0ff + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 7 + height: 22 - QtButton - id: clearRightBar1 - !text: tr('Bar 1') - width: 60 - height: 18 + OptionCheckBoxMarked + id: cooldownSecond + !text: tr('Show Cooldown in Seconds') + !tooltip: tr('Display remaining cooldown time in seconds') + + SmallReversedQtPanel + anchors.left: parent.left anchors.right: parent.right - anchors.top: clearLeftBar1.bottom - margin-right: 130 - margin-top: 3 - @onClick: modules.game_actionbar.resetAction(7) - QtButton - id: clearRightBar2 - !text: tr('Bar 2') - width: 60 - height: 18 + anchors.top: prev.bottom + margin-top: 7 + height: 22 + + OptionCheckBoxMarked + id: actionTooltip + !text: tr('Show Action Button Tooltip') + !tooltip: tr('Display tooltips when hovering over action buttons') + + SmallReversedQtPanel + anchors.left: parent.left anchors.right: parent.right - anchors.top: clearLeftBar2.bottom - margin-right: 65 - margin-top: 3 - @onClick: modules.game_actionbar.resetAction(8) + anchors.top: prev.bottom + margin-top: 7 + height: 75 + + Label + !text: tr('Clear Bottom Action Bars:') + anchors.left: parent.left + anchors.top: parent.top + margin-left: 10 + margin-top: 5 + color: #c0c0c0ff + + UIWidget + id: toolTipWidgetClearBottom + image-source: /images/icons/show_gui_help_grey + size: 12 12 + anchors.right: parent.right + anchors.top: parent.top + margin-right: 3 + margin-top: 5 + !tooltip: tr('Clear all assignments from bottom action bars') + + QtButton + id: clearBottomBar1 + !text: tr('Bar 1') + width: 60 + height: 18 + anchors.right: parent.right + anchors.top: parent.top + margin-right: 130 + margin-top: 3 + @onClick: modules.game_actionbar.resetAction(1) + QtButton + id: clearBottomBar2 + !text: tr('Bar 2') + width: 60 + height: 18 + anchors.right: parent.right + anchors.top: parent.top + margin-right: 65 + margin-top: 3 + @onClick: modules.game_actionbar.resetAction(2) + QtButton + id: clearBottomBar3 + !text: tr('Bar 3') + width: 60 + height: 18 + anchors.right: parent.right + anchors.top: parent.top + margin-right: 0 + margin-top: 3 + @onClick: modules.game_actionbar.resetAction(3) + Label + !text: tr('Clear Left Action Bars:') + anchors.left: parent.left + anchors.top: clearBottomBar1.bottom + margin-left: 10 + margin-top: 5 + color: #c0c0c0ff + + QtButton + id: clearLeftBar1 + !text: tr('Bar 1') + width: 60 + height: 18 + anchors.right: parent.right + anchors.top: clearBottomBar1.bottom + margin-right: 130 + margin-top: 3 + @onClick: modules.game_actionbar.resetAction(4) + QtButton + id: clearLeftBar2 + !text: tr('Bar 2') + width: 60 + height: 18 + anchors.right: parent.right + anchors.top: clearBottomBar2.bottom + margin-right: 65 + margin-top: 3 + @onClick: modules.game_actionbar.resetAction(5) + QtButton + id: clearLeftBar3 + !text: tr('Bar 3') + width: 60 + height: 18 + anchors.right: parent.right + anchors.top: clearBottomBar3.bottom + margin-right: 0 + margin-top: 3 + @onClick: modules.game_actionbar.resetAction(6) + Label + !text: tr('Clear Right Action Bars:') + anchors.left: parent.left + anchors.top: clearLeftBar1.bottom + margin-left: 10 + margin-top: 5 + color: #c0c0c0ff + + QtButton + id: clearRightBar1 + !text: tr('Bar 1') + width: 60 + height: 18 + anchors.right: parent.right + anchors.top: clearLeftBar1.bottom + margin-right: 130 + margin-top: 3 + @onClick: modules.game_actionbar.resetAction(7) + QtButton + id: clearRightBar2 + !text: tr('Bar 2') + width: 60 + height: 18 + anchors.right: parent.right + anchors.top: clearLeftBar2.bottom + margin-right: 65 + margin-top: 3 + @onClick: modules.game_actionbar.resetAction(8) + QtButton + id: clearRightBar3 + !text: tr('Bar 3') + width: 60 + height: 18 + anchors.right: parent.right + anchors.top: clearLeftBar3.bottom + margin-right: 0 + margin-top: 3 + @onClick: modules.game_actionbar.resetAction(7) + QtButton id: clearRightBar3 - !text: tr('Bar 3') + !text: tr('reset') width: 60 height: 18 anchors.right: parent.right - anchors.top: clearLeftBar3.bottom - margin-right: 0 - margin-top: 3 - @onClick: modules.game_actionbar.resetAction(7) + anchors.top: prev.bottom + margin-top: 12 + @onClick: modules.game_actionbar.resetActionBars() - QtButton - id: clearRightBar3 - !text: tr('reset') - width: 60 - height: 18 - anchors.right: parent.right + VerticalScrollBar + id: actionBarsScrollBar + anchors.top: parent.top anchors.bottom: parent.bottom - margin-top: 3 - @onClick: modules.game_actionbar.resetActionBars() + anchors.right: parent.right + step: 14 + pixels-scroll: true + $!mobile: + visible: false \ No newline at end of file diff --git a/modules/game_mainpanel/option_control_buttons.otui b/modules/game_mainpanel/option_control_buttons.otui index 7cdae8e03..71fa4dd52 100644 --- a/modules/game_mainpanel/option_control_buttons.otui +++ b/modules/game_mainpanel/option_control_buttons.otui @@ -1,148 +1,168 @@ UIWidget anchors.fill: parent visible: false - QtButton - id: reset - text: "Reset" - anchors.right: parent.right - anchors.bottom: parent.bottom - @onClick: reset() - Panel - id: panelDisplayedButtons + UIScrollArea + id: optionControlButtonsScrollArea anchors.left: parent.left - anchors.right: parent.right + anchors.right: optionControlButtonsScrollBar.left anchors.top: parent.top - size: 502 248 - border-width-top: 1 - border-color-top: black - border-width-left: 1 - border-color-left: black - border-width-bottom: 1 - border-color-bottom: #747474 - border-width-right: 1 - border-color-right: #747474 - - Label - id: displayedButtonsLabel - !text: tr('Displayed Buttons') - anchors.top: parent.top - anchors.left: parent.left - margin-top: 5 - margin-left: 10 - color: #C0C0C0 - - TextList - id: displayedButtonsList - anchors.top: displayedButtonsLabel.bottom - anchors.left: parent.left - anchors.right: parent.right - height: 200 - margin-top: 5 - margin-left: 10 - margin-right: 35 - vertical-scrollbar: displayedButtonsScrollBar - background-color: #404040 - VerticalQtScrollBar - id: displayedButtonsScrollBar - anchors.top: displayedButtonsList.top - anchors.bottom: displayedButtonsList.bottom - anchors.right: displayedButtonsList.right - step: 14 - pixels-scroll: true - - UIButton - id: moveToDisplayedAvailableButtonsList - anchors.top: displayedButtonsList.top - anchors.right: parent.right - margin-right: 10 - image-source: /images/ui/buttons/button-clear-18x18-up - image-clip: 0 0 20 20 - width: 20 - @onClick: moveToAvailable() - $pressed: - image-source: /images/ui/buttons/button-clear-18x18-down - - UIButton - id: reordenUp - anchors.top: prev.bottom - anchors.right: parent.right - margin-right: 10 - margin-top: 5 - image-source: /images/ui/buttons/automap-button-moveup-up - image-clip: 0 0 20 20 - width: 20 - @onClick: moveButtonUp() - $pressed: - image-source: /images/ui/buttons/automap-button-moveup-down - - UIButton - id: reordenDown - anchors.top: prev.bottom - anchors.right: parent.right - margin-right: 10 - margin-top: 5 - image-source: /images/ui/buttons/automap-button-movedown-up - image-clip: 0 0 20 20 - width: 20 - @onClick: moveButtonDown() - $pressed: - image-source: /images/ui/buttons/automap-button-movedown-down - - Panel - id: panelAvailableButtons - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - size: 508 100 - margin-top: 10 - border-width-top: 1 - border-color-top: black - border-width-left: 1 - border-color-left: black - border-width-bottom: 1 - border-color-bottom: #747474 - border-width-right: 1 - border-color-right: #747474 - Label - id: displayedButtonsLabel - !text: tr('Available Buttons') - anchors.top: parent.top - anchors.left: parent.left - margin-top: 5 - margin-left: 10 - color: #C0C0C0 - - TextList - id: displayedAvailableButtonsList - anchors.top: displayedButtonsLabel.bottom - anchors.left: parent.left - anchors.right: parent.right - height: 74 - margin-top: 5 - margin-left: 10 - margin-right: 35 - vertical-scrollbar: displayedButtonsScrollBar - background-color: #404040 - VerticalQtScrollBar - id: displayedButtonsScrollBar - anchors.top: prev.top - anchors.bottom: prev.bottom - anchors.right: prev.right - step: 14 - pixels-scroll: true - UIButton - id: moveToDisplayedButtonsList - anchors.top: prev.top - anchors.right: parent.right - margin-right: 10 - image-source: /images/options/button_control - width: 20 - @onClick: moveToDisplayed() - image-clip: 0 0 20 20 - image-border: 3 - $pressed: - image-clip: 20 0 20 20 + anchors.bottom: parent.bottom + vertical-scrollbar: optionControlButtonsScrollBar - $on: - image-clip: 20 0 20 20 + Panel + id: panelDisplayedButtons + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + size: 502 248 + border-width-top: 1 + border-color-top: black + border-width-left: 1 + border-color-left: black + border-width-bottom: 1 + border-color-bottom: #747474 + border-width-right: 1 + border-color-right: #747474 + + Label + id: displayedButtonsLabel + !text: tr('Displayed Buttons') + anchors.top: parent.top + anchors.left: parent.left + margin-top: 5 + margin-left: 10 + color: #C0C0C0 + + TextList + id: displayedButtonsList + anchors.top: displayedButtonsLabel.bottom + anchors.left: parent.left + anchors.right: parent.right + height: 200 + margin-top: 5 + margin-left: 10 + margin-right: 35 + vertical-scrollbar: displayedButtonsScrollBar + background-color: #404040 + VerticalQtScrollBar + id: displayedButtonsScrollBar + anchors.top: displayedButtonsList.top + anchors.bottom: displayedButtonsList.bottom + anchors.right: displayedButtonsList.right + step: 14 + pixels-scroll: true + + UIButton + id: moveToDisplayedAvailableButtonsList + anchors.top: displayedButtonsList.top + anchors.right: parent.right + margin-right: 10 + image-source: /images/ui/buttons/button-clear-18x18-up + image-clip: 0 0 20 20 + width: 20 + @onClick: moveToAvailable() + $pressed: + image-source: /images/ui/buttons/button-clear-18x18-down + + UIButton + id: reordenUp + anchors.top: prev.bottom + anchors.right: parent.right + margin-right: 10 + margin-top: 5 + image-source: /images/ui/buttons/automap-button-moveup-up + image-clip: 0 0 20 20 + width: 20 + @onClick: moveButtonUp() + $pressed: + image-source: /images/ui/buttons/automap-button-moveup-down + + UIButton + id: reordenDown + anchors.top: prev.bottom + anchors.right: parent.right + margin-right: 10 + margin-top: 5 + image-source: /images/ui/buttons/automap-button-movedown-up + image-clip: 0 0 20 20 + width: 20 + @onClick: moveButtonDown() + $pressed: + image-source: /images/ui/buttons/automap-button-movedown-down + + Panel + id: panelAvailableButtons + anchors.left: parent.left + anchors.right: parent.right + anchors.top: prev.bottom + size: 508 100 + margin-top: 10 + border-width-top: 1 + border-color-top: black + border-width-left: 1 + border-color-left: black + border-width-bottom: 1 + border-color-bottom: #747474 + border-width-right: 1 + border-color-right: #747474 + Label + id: displayedButtonsLabel + !text: tr('Available Buttons') + anchors.top: parent.top + anchors.left: parent.left + margin-top: 5 + margin-left: 10 + color: #C0C0C0 + + TextList + id: displayedAvailableButtonsList + anchors.top: displayedButtonsLabel.bottom + anchors.left: parent.left + anchors.right: parent.right + height: 74 + margin-top: 5 + margin-left: 10 + margin-right: 35 + vertical-scrollbar: displayedButtonsScrollBar + background-color: #404040 + VerticalQtScrollBar + id: displayedButtonsScrollBar + anchors.top: prev.top + anchors.bottom: prev.bottom + anchors.right: prev.right + step: 14 + pixels-scroll: true + UIButton + id: moveToDisplayedButtonsList + anchors.top: prev.top + anchors.right: parent.right + margin-right: 10 + image-source: /images/options/button_control + width: 20 + @onClick: moveToDisplayed() + image-clip: 0 0 20 20 + image-border: 3 + $pressed: + image-clip: 20 0 20 20 + + $on: + image-clip: 20 0 20 20 + + QtButton + id: reset + text: "Reset" + anchors.right: parent.right + anchors.top: prev.bottom + margin-top: 10 + @onClick: reset() + + VerticalScrollBar + id: optionControlButtonsScrollBar + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + step: 14 + pixels-scroll: true + $!mobile: + visible: false