pax_global_header00006660000000000000000000000064152632176760014531gustar00rootroot0000000000000052 comment=97076f16ef808317c14238cbbb60b9f2da9b6cb8 epasveer-seer-97076f1/000077500000000000000000000000001526321767600145645ustar00rootroot00000000000000epasveer-seer-97076f1/.github/000077500000000000000000000000001526321767600161245ustar00rootroot00000000000000epasveer-seer-97076f1/.github/scripts/000077500000000000000000000000001526321767600176135ustar00rootroot00000000000000epasveer-seer-97076f1/.github/scripts/generate_stargazer_map.py000066400000000000000000000075241526321767600247060ustar00rootroot00000000000000import os import requests import pandas as pd import plotly.express as px from collections import Counter GITHUB_TOKEN = os.environ["GITHUB_TOKEN"] REPO = os.environ["REPO"] HEADERS = { "Authorization": f"Bearer {GITHUB_TOKEN}", "Accept": "application/vnd.github+json", } def get_all_stargazers(): """Fetch all stargazers (paginated).""" stargazers = [] page = 1 while True: url = f"https://api.github.com/repos/{REPO}/stargazers?per_page=100&page={page}" resp = requests.get(url, headers=HEADERS) resp.raise_for_status() data = resp.json() if not data: break stargazers.extend(data) page += 1 print(f"Total stargazers: {len(stargazers)}") return stargazers def get_user_location(username): """Fetch location field from a user's profile.""" url = f"https://api.github.com/users/{username}" resp = requests.get(url, headers=HEADERS) if resp.status_code == 200: return resp.json().get("location", None) return None def geocode_location(location, session, cache): """Use Nominatim (OSM) to geocode a location string.""" if not location or location in cache: return cache.get(location) try: url = "https://nominatim.openstreetmap.org/search" params = {"q": location, "format": "json", "limit": 1} resp = session.get(url, params=params, timeout=5, headers={"User-Agent": f"StargazerMap/{REPO}"}) results = resp.json() if results: lat = float(results[0]["lat"]) lon = float(results[0]["lon"]) cache[location] = (lat, lon) return (lat, lon) except Exception: pass cache[location] = None return None def generate_map(points): """Generate an interactive Plotly world map.""" df = pd.DataFrame(points, columns=["lat", "lon", "location"]) country_counts = Counter(df["location"]) df["count"] = df["location"].map(country_counts) fig = px.scatter_geo( df, lat="lat", lon="lon", hover_name="location", size="count", size_max=30, color="count", color_continuous_scale="Plasma", projection="natural earth", title=f"� Stargazers of {REPO}", template="plotly_dark", ) fig.update_layout( title_font_size=22, geo=dict( showframe=False, showcoastlines=True, coastlinecolor="rgba(255,255,255,0.2)", showland=True, landcolor="rgb(30, 30, 50)", showocean=True, oceancolor="rgb(15, 15, 35)", showcountries=True, countrycolor="rgba(255,255,255,0.1)", ), paper_bgcolor="rgb(10, 10, 25)", font_color="white", coloraxis_showscale=False, margin=dict(l=0, r=0, t=50, b=0), ) os.makedirs("images", exist_ok=True) fig.write_html("images/stargazer-map.html", include_plotlyjs="cdn") fig.write_image("images/stargazer-map.svg", width=1200, height=600) print("Map saved to images/stargazer-map.html and images/stargazer-map.svg") def main(): import time stargazers = get_all_stargazers() geocache = {} points = [] session = requests.Session() for i, user in enumerate(stargazers): username = user["login"] location = get_user_location(username) if location: coords = geocode_location(location, session, geocache) if coords: points.append((coords[0], coords[1], location)) # Respect Nominatim rate limit: 1 req/sec if i % 5 == 0: time.sleep(1) print(f"Mapped {len(points)} stargazers with locations.") if points: generate_map(points) else: print("No geocodable locations found.") if __name__ == "__main__": main() epasveer-seer-97076f1/.github/workflows/000077500000000000000000000000001526321767600201615ustar00rootroot00000000000000epasveer-seer-97076f1/.github/workflows/build-latest.yml000066400000000000000000000032121526321767600232730ustar00rootroot00000000000000name: build-latest Development Build on: workflow_dispatch: push: branches: [ main ] pull_request: branches: [ main ] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Update Ubuntu run: | sudo apt-get update - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.6 install-deps: 'true' modules: 'qtcharts' - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` epasveer-seer-97076f1/.github/workflows/contributor-map.yml000066400000000000000000000004451526321767600240340ustar00rootroot00000000000000name: Create Contributor Map on: workflow_dispatch: jobs: build-and-push-image: runs-on: ubuntu-latest steps: - name: Contributor Map uses: tunaitis/contributor-map@v1 with: repository: epasveer/seer output: images/contributor-map.svg epasveer-seer-97076f1/.github/workflows/debian-latest.yml000066400000000000000000000042651526321767600234270ustar00rootroot00000000000000name: debian-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: debian-latest steps: - uses: actions/checkout@v3 - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.* install-deps: 'true' modules: 'qtcharts' - name: Update debian run: | sudo apt-get update sudo apt list --installed | grep mesa - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` - name: Tar run: | cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results run: | cd src ls -l build/ - name: Build Debian Development Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "debian-latest" prerelease: true title: "Debian Development Release" files: | src/build/seergdb.tar.gz epasveer-seer-97076f1/.github/workflows/debian-package.yml000066400000000000000000000046551526321767600235310ustar00rootroot00000000000000name: debian-latest Package Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Update Ubuntu run: | sudo apt-get update - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.6 install-deps: 'true' modules: 'qtcharts' - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` - name: List Results run: | cd src ls -l build/ debian-pkg: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install build dependencies run: | sudo apt-get update sudo apt-get -y install devscripts build-essential dpkg-dev equivs sudo mk-build-deps --install --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control - name: Build Debian package run: dpkg-buildpackage --unsigned-source --unsigned-changes - name: Upload debian package Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "debian-pkg-latest" prerelease: true title: "Debian Package Release" files: | ../seergdb_*_amd64.deb epasveer-seer-97076f1/.github/workflows/flatpak-latest.yml000066400000000000000000000025541526321767600236260ustar00rootroot00000000000000name: flatpak-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: flatpak: name: Build Flatpak runs-on: ubuntu-latest container: image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.10 options: --privileged steps: - name: Where Am I run: | pwd ls -l lscpu - name: Checkout code uses: actions/checkout@v5 - name: Build Flatpak uses: flatpak/flatpak-github-actions/flatpak-builder@v6 with: branch: main bundle: seer.flatpak manifest-path: src/resources/flathub/io.github.epasveer.seer.github.yml # Builds the checked out code. cache-key: flatpak-builder-${{ github.sha }} - name: Create/update tag uses: rickstaa/action-create-tag@v1 with: tag: flatpak-latest message: Tag from latest ${{ github.ref_name }} branch. force_push_tag: true - name: Create Release uses: softprops/action-gh-release@v2 with: name: Flatpak Development Release body: Build from latest ${{ github.ref_name }} branch. files: | seer.flatpak tag_name: flatpak-latest draft: false prerelease: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} epasveer-seer-97076f1/.github/workflows/macos-latest.yml000066400000000000000000000050161526321767600233020ustar00rootroot00000000000000name: macos-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: macos-latest steps: - uses: actions/checkout@v3 - name: Install dependencies run: | export \ HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 \ HOMEBREW_NO_INSTALL_CLEANUP=1 brew update > /dev/null brew install \ cmake ninja - name: Setup ccache uses: Chocobo1/setup-ccache-action@v1 with: update_packager_index: false - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.* install-deps: 'true' modules: 'qtcharts' - name: Where am I run: | pwd ls -l - name: Tool versions run: | g++ --version cmake --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel 4 - name: Tar run: | cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results run: | cd src ls -l build/ - name: Build MacOS Development Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "macos-latest" prerelease: true title: "MacOS Development Release" files: | src/build/seergdb.tar.gz epasveer-seer-97076f1/.github/workflows/mint-latest.yml000066400000000000000000000041761526321767600231550ustar00rootroot00000000000000name: mint-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Update Mint run: | sudo apt-get update - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.4.2 install-deps: 'true' modules: 'qtcharts' - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` - name: Tar run: | cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results run: | cd src ls -l build/ - name: Build Mint Development Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "mint-latest" prerelease: true title: "Mint Development Release" files: | src/build/seergdb.tar.gz epasveer-seer-97076f1/.github/workflows/snap-latest.yml000066400000000000000000000015301526321767600231360ustar00rootroot00000000000000name: snap-latest Development Build on: workflow_dispatch: jobs: snap: name: Build Snap runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Create/update tag uses: rickstaa/action-create-tag@v1 with: tag: snap-latest message: Tag from latest ${{ github.ref_name }} branch. force_push_tag: true - name: Build snap uses: snapcore/action-build@v1 id: build - name: Create Release uses: softprops/action-gh-release@v2 with: name: Snap Development Release body: Build from latest ${{ github.ref_name }} branch. files: | ${{ steps.build.outputs.snap }} tag_name: snap-latest draft: false prerelease: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} epasveer-seer-97076f1/.github/workflows/stargazers-map.yml000066400000000000000000000017431526321767600236510ustar00rootroot00000000000000name: Create Stargazer Map on: workflow_dispatch: jobs: generate-stargazer-map: runs-on: ubuntu-latest name: Generate Stargazer World Map steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install dependencies run: pip install requests plotly pandas kaleido - name: Generate stargazer map env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.repository }} run: python .github/scripts/generate_stargazer_map.py - name: Commit and push map run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add images/stargazer-map.svg images/stargazer-map.html git diff --staged --quiet || git commit -m "� Update stargazer world map [skip ci]" git push epasveer-seer-97076f1/.github/workflows/ubuntu-arm64-latest.yml000066400000000000000000000042431526321767600244520ustar00rootroot00000000000000name: ubuntu-arm64-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-24.04-arm64 steps: - uses: actions/checkout@v3 - name: Update Ubuntu ARM64 run: | sudo apt-get update - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.6 install-deps: 'true' modules: 'qtcharts' - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` - name: Tar run: | cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results run: | cd src ls -l build/ - name: Build Ubuntu Development Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "ubuntu-arm64-latest" prerelease: true title: "Ubuntu ARM64 Development Release" files: | src/build/seergdb.tar.gz epasveer-seer-97076f1/.github/workflows/ubuntu-latest.yml000066400000000000000000000056471526321767600235340ustar00rootroot00000000000000name: ubuntu-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Update Ubuntu run: | sudo apt-get update - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: 6.6 install-deps: 'true' modules: 'qtcharts' - name: Where Am I run: | pwd ls -l lscpu - name: Versions run: g++ --version - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cd src cmake -B ${{github.workspace}}/src/build -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: | cd src cmake --build ${{github.workspace}}/src/build --config ${{env.BUILD_TYPE}} --target seergdb --parallel `grep -c processor /proc/cpuinfo` - name: Tar run: | cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results run: | cd src ls -l build/ - name: Build Ubuntu Development Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "ubuntu-latest" prerelease: true title: "Ubuntu Development Release" files: | src/build/seergdb.tar.gz debian-pkg: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install build dependencies run: | sudo apt-get update sudo apt-get -y install devscripts build-essential dpkg-dev equivs sudo mk-build-deps --install --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control - name: Build Debian package run: dpkg-buildpackage --unsigned-source --unsigned-changes - name: Upload debian package Release uses: marvinpinto/action-automatic-releases@latest with: repo_token: ${{ secrets.GITHUB_TOKEN }} automatic_release_tag: "debian-pkg-latest" prerelease: true title: "Debian Package Release" files: | ../seergdb_*_amd64.deb epasveer-seer-97076f1/.github/workflows/windows-latest.yml000066400000000000000000000060051526321767600236710ustar00rootroot00000000000000name: windows-latest Development Build on: workflow_dispatch: env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: runs-on: windows-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup WSL uses: Vampire/setup-wsl@v3 with: distribution: Ubuntu-22.04 - name: Update ubuntu shell: wsl-bash {0} run: | sudo apt update sudo apt search qt6 sudo apt install -y \ build-essential \ cmake \ ninja-build \ pkg-config \ qt6-base-dev \ qt6-base-dev-tools \ libqt6charts6-dev \ libqt6svg6-dev \ libgl1-mesa-dev \ libxkbcommon-dev \ libxcb-xinerama0-dev \ libxcb-cursor-dev sudo ldconfig /usr/lib/x86_64-linux-gnu sudo ldconfig - name: Set Qt6 environment variables shell: wsl-bash {0} run: | # Find Qt6 installation path QT6_PATH=$(dpkg -L qt6-base-dev | grep -E 'lib.*cmake.*Qt6$' | head -1 | sed 's|/lib.*||') echo "Qt6 found at: $QT6_PATH" # Set environment variables for the session echo "export Qt6_DIR=$QT6_PATH" > /tmp/env.sh echo "export CMAKE_PREFIX_PATH=/usr/lib/x86_64-linux-gnu/cmake/Qt6:$QT6_PATH" >> /tmp/env.sh echo "export QT_QPA_PLATFORM_PLUGIN_PATH=$QT6_PATH/lib/qt6/plugins/platforms" >> /tmp/env.sh echo "export QML_IMPORT_PATH=$QT6_PATH/lib/qt6/qml" >> /tmp/env.sh echo "export QT_PLUGIN_PATH=$QT6_PATH/lib/qt6/plugins" >> /tmp/env.sh # Source the updated env.sh cat /tmp/env.sh source /tmp/env.sh # Print environment for debugging echo "SHELL: $SHELL" echo "Qt6_DIR: $Qt6_DIR" dpkg -L qt6-base-dev dpkg -L libqt6charts6 ldconfig -p - name: Where Am I shell: wsl-bash {0} run: | pwd ls -l lscpu - name: Versions shell: wsl-bash {0} run: g++ --version - name: Configure CMake shell: wsl-bash {0} run: | source /tmp/env.sh cd src/build cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DQTVERSION=QT6 \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH=$Qt6_DIR \ -DQt6_DIR=$Qt6_DIR/lib/cmake/Qt6 pwd ls -l - name: Build shell: wsl-bash {0} run: | source /tmp/env.sh cd src/build pwd ls -l make -j$(nproc) - name: Tar shell: wsl-bash {0} run: | source /tmp/env.sh cd src/build cp ../../LICENSE . cp ../../CHANGELOG.md . tar zcvf seergdb.tar.gz LICENSE CHANGELOG.md seergdb - name: List Results shell: wsl-bash {0} run: | source /tmp/env.sh cd src ls -l build/ epasveer-seer-97076f1/CHANGELOG.md000066400000000000000000000503721526321767600164040ustar00rootroot00000000000000 # Seer Change Log ## [2.8.1] - 2026-10-12 * Packaging: Fix the flatpak metainfo so the bundle reports the correct version (was showing 2.7beta). * Packaging: Fix icon paths in the Debian install file. Update the AppStream metainfo release version. * Packaging: The flatpak-latest GitHub action now builds the checked out code. ## [2.8] - 2026-10-12 * ParallelStacks: Add a Parallel Stacks Visualizer. Shows the call stacks of all threads as a merged graph. * ParallelStacks: Add a 'Method View' mode. * ParallelStacks: Add search and filter functions. * ParallelStacks: Highlight the stack that is active in the debugger. * ParallelStacks: Option to limit the number of frames shown in a node. * ParallelStacks: Merge non-debug frames into a single "External Code" frame. * ParallelStacks: Option to show or hide the minimap. * ParallelStacks: Fixed wide nodes caused by long function names, handling of "??" function names, popup frame order/timing/dragging behavior, and node placement. * Editor: Add a minimap to the Source and Assembly editors. Improved for large files. * Visualizers: Add a GDB Monitor visualizer for sending 'monitor' commands to gdbserver, openocd, vgdb, qemu, and the like. * Debug: Add a 'starti' mode to start debugging at the first instruction. Helpful for debugging programs written in assembly. * Icons: Seer handles dark/light color theme changes. Add an Icon Theme option (auto/light/dark). Helpful for themes like KDE's Breeze Dark. * MemoryVisualizer: Highlight bytes that change. * MatrixVisualizer: Add a row-major/column-major selector. Auto-refresh at each stopping point. Bulk update. (Thanks tiresiasfromthebai!) * ArrayVisualizer: Auto-refresh at each stopping point. Faster scatter phase-portrait. (Thanks tiresiasfromthebai!) * ImageVisualizer: Add Ctrl+wheel zoom. Fixed zoom keys under Qt6. (Thanks tiresiasfromthebai!) * SyntaxHighlighting: Add Ada (Thanks mgrojo!) and Fortran (Thanks tiresiasfromthebai!). Reworked the Editor config page to accommodate more languages. * SyntaxHighlighting: Fixed string and class-name rules. (Thanks tiresiasfromthebai!) * Build: Add Snap package generation. * Project: Fixed command-line executable and arguments being overridden by the default project. * Project: Load run/start settings from the correct JSON object. (Thanks tiresiasfromthebai!) * GDB: Read gdb's stderr channel correctly. (Thanks tiresiasfromthebai!) * Breakpoints: Fixed spurious "No such file or directory" warning on restart when no breakpoints are set. * Startup: Improved handling when the DISPLAY variable is not set. * Console: Decode output as UTF-8 instead of Latin-1. (Thanks tiresiasfromthebai!) * ProgressIndicator: Don't paint the indicator when it is stopped. (Thanks tiresiasfromthebai!) * ArrayVisualizer: Fixed empty scatter chart, swapped X/Y axes when plotting one array against another, unstyled scatter markers with large arrays, and handleText stack usage. (Thanks tiresiasfromthebai and lvntky!) * MatrixVisualizer: Fixed min/max value loss and other slips. (Thanks lvntky and tiresiasfromthebai!) * Visualizers: Don't auto-refresh the Array/Matrix visualizers when the program exits. Re-evaluate the visualized variable's address on refresh. (Thanks tiresiasfromthebai!) * Build: Fixed icon colorization for Qt >= 6.6.3. Fixed build on Ubuntu 22. * Docs: Add STYLEGUIDE.md and CONTRIBUTING.md. * Tests: Add a Raspberry Pi 4 gdbserver test. Update STM32 build instructions. (Thanks QuangNguyenMinh123!) ## [2.7.1] - 2026-10-05 * Packaging: Fix .gitattributes so the release source archive includes src/resources/icons/ (hicolor icons). ## [2.7] - 2026-04-06 * SyntaxHighlighting: Refactored syntax highlighting code. Supports C/C++/Rust/Odin. (Thanks RaphGL!) * VariableTracker: Add 'deleteselect' and 'deleteall' to RMB context menu. * VariableLogger: Add 'deleteselect' and 'deleteall' to RMB context menu. * EditorConfig: Show syntax highlighting for C/C++, Rust, and Odin. * Editor: ^F to focus on text search ^L to focus on line search. * Editor: ESC to hide search panel. * Editor: ^B to toggle breakpoint on current line. * Editor: Show cursor all the time. * Breakpoints: Allow multiple filename:line entries for the --break-source option. * Control: Add ^D to toggle record playback direction for RR, Undo, and gdb's Record. * Control: Add SHIFT+F5 (etal) to reverse step (etc.) during record playback for RR, Undo, and gdb's Record. * GDB: Add Seer config to set gdb architecture. * GDB: Add an optional 'launcher' program to start gdb. eg: flatpak-spawn. * Build: Add flatpak generation to github actions. * Assemby: An option to show assembly tab when there is no source file. * Signals: Add an window to show how GDB handles signals. And to set that behavior. * Macros: Add 10 macros for custom commands that are executed by clicking a button (or a hot key). ## [2.6] - 2025-10-07 * Watchpoints: Fixed regression when adding commands to a watchpoint. * Console: Create console once per Seer session. Instead of constant create/destroy. * EditorManager: Fixed regression when ignoring files to be opened in the EditorManager. * MessageTabs: Fixed regression when order of message tabs not being preserved between sessions. * RemoteMode: Connect mode to a gdb server now supports 'remote' and 'extended-remote'. * ConnectMode: Connect mode's 'pre' commands are executed before the 'target connect'. * MessageTabs: Optionally add a timestamp to the Seer and Gdb log widgets. * ConnectMode: Add 'gdbserver debug' checkbox to Connect launch tab. For showing gdb and gdbserver communication debug information in gdb tab. * Skips: Manage gdb skip commands via a new Skip Browser. * LaunchMode: Revamp the "run/start" buttons on the menu bar to be a predominate "terminate" that switches to a "restart". * VariableTracker: Fixed bug when adding variable to tracker. Sometimes would not refresh value. * VariableTracker: Raise Logger or Tracker tab when new variable is added. * CheckpointMode: Implment gdb's "checkpoint" feature. As simple time-travel feature. * Undo: Add preliminary support for Undo's udb time-traveling debugger. * CheckpointMode: Add support for remaining Catchpoint types. * Visualizers: Add a Matrix Visualizer for viewing 2D arrays. * Breakpoints: Add breakpoints from the Function tab. * DefaultProject: When using the Debug dialog, save the debug settings so they can be fast loaded the next time the Debug dialog is used. Kind of a default project. * RR: When using the Debug dialog, check a couple standard locations for the RR trace directory. * ObjectiveC: Add support for printing ObjectiveC object via a '(objc)' pretext. * Registers: Fix bug handling register names of "" in gdb's register list. ## [2.5] - 2024-12-24 * Console now supports a subset of ANSI color codes. * Console can be started in these modes: - Detached - Detached and minimized - Attached in Seer's tab view (with gdb logs and seer logs). * Improved handling of \n \t and other escaped characters in gdb log window. * Show breakpoint info as a tooltip if the breakpoint icon is clicked with LMB and held down. * Show stack as a hex dump, with options to view as short, int, long, ascii, ... * The "go to address" in the Assembly view now works if address it outside current assembly view. * Visualizers can take a gdb expression for input fields for length/size of something. The visualizers are: - ArrayVisualizer - ImageVisualizer - MemoryVisualizer * Fixed regression when setting/saving the editor font setting. * Fixed bug when the Basic Struct visualizer display simple variable types (non-structs). * Source all files in ~/.config/seergdb/scripts/ on startup. * Fixed regression handling ignoring of system header files. * Fixed regression when adding commands to a breakpoint. * Refactored/improved Printpoints. Added 'help' to the Printpoint create dialog. * Fixed regression when display variable value when hovering over the text in the editor window. ## [2.4] - 2024-03-18 * Changed main icon to a more license friendly one. All icons are now GPLv3, CC3.0, or CC4.0 * Fixed string compares for breakpoint conditions (#184) * Added '--bs' command line option to specify a breakpoint at a source.cpp:lineno * Fixed long tooltips text by restricting them to 100 characters. (#189) The text in the various viewing dialogs is still the full length. The 100 limit probably needs to be configurable. * Added register profiles to show only interesting/relevant registers. * Added UTF-8,16,32 support in the Memory Visualizer. * Added an internal "dark" and "light" theme via the View->Style menu. * Added option to open the current source file in an external editor. * Fixed saving of RR parameters in config dialog. * Sped up some visualization views. ## [2.3] - 2023-11-19 * In the margins of the source windows, allow CTRL+DoubleClick to do a quick RunToLine or RunToAddress. * Add --gdb-program and --gdb-arguments to command line to override settings from Seer's config. * Fixed a rare bug with blank lines from gdb causing a segv in GdbMonitor. * Fixed bug specifying path to "rr" debugger. * Add option to reload source file if it changes. * Tighten up the layout by removing some needless whitespace. * Move gdb messages to a tab in the breakpoints window. - Options to raise on every message, never, or important messages. * Add C++ level (11 or 17) depending on qt5 or qt6 compile. * Fixed up column resizing for the Variable logger (#173) * Use monspace font, where it makes sense (#175) * Allow copy to clipboard (#176) * Fixed hovering a variable name and value (#179) * Add nested struct viewing in "locals", "arguments", "logger", and "tracker" tabs. (#180) ## [2.2] - 2023-09-07 * Fixed infinite loop when starting with RR mode. * Reworked RR mode to directly run 'rr replay'. No need to start a 'rr server' and connect to it. https://github.com/epasveer/seer/wiki/RR-and-Seer * Fixed Source handling in source browser. Qt5 mode was broken. Qt6 works. Directory paths need a tailing "/*" ## [2.1] - 2023-08-23 * Add Execution dialog to record breakpoint events. This solves the problem of too many break/error dialogs to "swat away" as the program is debugged. * Add a method to add/change gdb commands to execute when a breakpoint (breakpoint, watchpoint, catchpoint) is reached. * Add a method to add/change a breakpoint's condition command. * Add a method to add/change a breakpoint's ignore count. * Add a method to add/change a breakpoint's command list. * Debug dialog for "attach" mode now detects executable name and path from /proc//exe. * Commandline for "attach" mode now detects executable name and path from /proc//exe. ## [2.0] - 2023-03-06 * Seer is Qt6 based. Still compiles with Qt5. * See Seer's Wiki page for compile instructions. https://github.com/epasveer/seer/wiki ## [1.17] - 2023-04-23 * Add support for the RR debugger. https://github.com/epasveer/seer/wiki/RR-and-Seer * Add a dialog when a breakpoint is reached. ## [1.16] - 2023-04-07 * Add pid to main window and console title bars. * The Pending flag is automatically supplied to the breakpoint function in the Debug dialog for the Run mode. Some apps use deferred loading of code with dlopen(). * Fixed bug when restoring from project file with 'start' mode. * ADA: Improve visualizers for Ada arrays. "(system.address) 0x7fffffffcf10" * ADA: Add Ada task browser. * ADA: Add Ada specific catchpoints. * ADA: Add Ada exception brower. * Add a Shortcut (CTRL-I) to interrupt the running program. ## [1.15] - 2023-03-04 * Revamp Debug dialog. Move debug modes into "tabs". * Add "help" icon to each debug mode in Debug dialog. * Add 'pre' and 'post' gdb commands that can be executed just before and just after the program is loaded into gdb. * Add the concept of 'project' files that can be created and loaded. Project files contain all settings available in the Debug dialog. * Assembly view can now be shown in 2 modes. See "Settings->Configure->Assembly" - Function. The view shows all assembly in the function the $PC is in. - Length. The view shows N bytes of assembly after the $PC. Used for code that is pure assembly or has no debug information. * Minor fixes when debugging corefiles. * Fixed breakpoints with conditional statements. * Fixed up icons and Debian "copyright" file for Debian Intent-To-Package. * Double-clicking on a breakpoint in the source window will delete it. Previously it would disable it. * Assembly Tab - show only Nexti and Stepi buttons. Source tabs - show only Next and Step buttons. * Hide certains buttons (Run, Start, ...) depending on Debug mode (run, attach, connect, etc...) * Save state of tabs (tab order and current tab). So next session will get them. ## [1.14] - 2023-01-02 * Happy New Year! * Add 'tabsize' property to Source Editors to properly display source files containing tab characters. Default is 4. Can be changed by the Editor config page. * Fixed '\t' character returned by some flavors of gdb that display the disassembly. * Remove whitespace from C/C++ lines in the Assembly tab. * Allow assembly code to have its own font format. See Config->Editor->AssemblyText. * Add Nexti and Stepi toolbar buttons if Assembly tab is shown. * Add PC, SP, FLAGS status bar to Assembly tab. * Re-added the original struct visualizers as "Basic Struct Visualizer". The advanced version is called "Struct Visualizer". * Moved selection of visualizers into a sub menu called "Visualizers" on the menu bar. * Added alternate file to load symbols from (instead of the debugee executable. ## [1.13] - 2022-12-02 * Improve specifying an alternate directory if the source has moved. Fewer mouse clicks. * Add new Image Visualizer. - View RGB888 and RGBA8888 images. * Assembly Tab can show source lines along with assembly. * Add CRC16 checksum to Memory Visualizer. * Add help for the main window's tab bar. ## [1.12] - 2022-10-22 * Added Gdb's Reverse Debugging mode. - Turn on/off gdb instruction recording. - Set play-back direction. * Added Gdb's Non-Stop mode. - https://sourceware.org/gdb/onlinedocs/gdb/Non_002dStop-Mode.html - A new --non-stop-mode command line flag - A new entry in the Debug dialog. - A new entry in Seer's config dialog under the gdb section. * Added support for the older QT5.12 library. - Expect rendering problems with the builtin help system. - Urge to move to QT5.15 library. * Main execute buttons. - Add '--all threads' for main execute buttons. - run/start/next/step/finish/continue/interrupt. - Individual threads can be managed by the Thread Manager. * Thread Manager changes. - Thread Frame browser. - Allow multiple threads to be select. Selecting 1 thread will select stack frame. - Add next/step/finish/continue/interrupt for selected thread(s). - Thread Id browser. - Allow multiple threads to be select. Selecting 1 thread will select stack frame. - Add next/step/finish/continue/interrupt for selected thread(s). - Thread Group browser. - Allow multiple thread groups to be select. - Add continue/interrupt for selected thread group(s). - Add run/start for selected thread group(s). Disabled for now. * Assembly view changes. - Showing Address, Offset, and Opcodes columns are configuable from the Config Dialog. - ^F in the Assembly editor can do quick changes. * Changing the Qt Style can be saved using Settings->Save Configuration. * Added valgrind support. - https://github.com/epasveer/seer/wiki/Valgrind-and-Seer. ## [1.11] - 2022-09-26 * Thread/Process manager. - Add a fork/vfork mode. Follow: - Parent process. - Child process. - Both (switchable via thread manager) - (see gdb's follow-fork-mode and detach-on-fork modes) - Add thread execution mode. Execute: - Selected thread only. - All threads - (see gdb's scheduler-locking mode) - Add multi-process execution mode. - Execute selected process. - Execute all processes. - (see gdb's schedule-multiple mode) * Add Help to Thread/Process browser. * Add Help to Stack Frame browser. * Add Help to Variable/Register browser. * Add Help to Source/Symbol/Library browser. * Add Help to Struct Visualizer. * Add Help to Memory Visualizer. * Add Help to Array Visualizer. * Add Help to Code Manager. * Add Help to Breakpoint/Gdb log Manager. * Add RMB menu to progress indicator to select indicator type. ## [1.10] - 2022-09-22 * New Struct Visualizer. - Built apon gdb's -var-obj framework. - Can recursively show the contents of a struct/class. - Show datatype of each member. (Value or pointer) - Can modify values of simple datatypes. * Improve Source Browsing. - See new options in 'Source' config page. - Ignore opening files from a list of directories. Like system directories that don't exist. - Better sorting of program's files into "Source", "Header", and "Misc" folders in the SourceBrowser by having a list of filename patterns for each folder. * The list of C/C++ file suffixes for syntax highlighting is configurable. * Changed to CreativeCommons and GPLv3 icons. - Friendlier license to use icons. - Breeze Icon set for most things. (GPLv3) - Icons from these sites that require CreativeCommon license. (Simple attribution). icon-icons.com thenounproject.com ## [1.9] - 2022-08-30 * Rename 'seer' binary to 'seergdb'. The name conflicts with another opensource project. * Prepare for better Debian (and other distros) packaging and releasing. * Add history (up/down arrows) to all line input fields. - Variable logger, tracker browsers. - Source, function, types, statics, library browsers. - Struct, memory, array visualizers. - Code and assembly editors. - Console. * Add StructVisualizer to source/assembly editors and stack arguments/locals browsers. * Add a RMB to launch Memory/Array/Struct viewer from a running Struct viewer. * Change 'detachtab' to use RMB context menu instead of a double-click. * Allow filenames with spaces when setting breakpoints. ## [1.8] - 2022-08-08 * Add StructVisualizer - New visualizer to view the contents of a C/C++ struct or a C++ class in a tree. - Click on the "StructVisualizer" in the menubar or "View -> Struct Visualizer". - Enter the name of the variable in the text section. - examples: "*this" "mystruct" "mystruct.member" - The variable text section has a history. So you can use the UP and DOWN arrows to select previous entries. - Manually refresh the view or click on "Auto" to refresh the view at each stopping point (after a step/next/breakpoint). * Add Dark theme option for Seer's code editor. Set in Seer config page. - Works for C/C++ source tabs and the assembly tab. * Register browser. - Can now edit register values. - Either by double-clicking the register value or by RMB context menu to bring up a dialog. - Add format selector for register values. - Improve detection of changed register values from previous stopping point. * Assembly support. - Add assembly config page for certain assembly settings. - assembly style - C++ symbol demangling. - Keep assembly tab on top. - Show assembly tab on Seer startup. - Launch MemoryVisualizer and ArrayVisualizer from the Assembly tab on highlighter text. * Debug options for launching program. - No break on program start. - Break in "main". - Break in function. - Break at address. - Randomize program's start address. * ArrayVisualizer and MemoryVisualizer now allow an address as the variable name. * A menu to experiment setting Seer with different Qt gui styles. - See "View -> Styles" * Bugs fixes. - Fixed double refresh bug in code editor. - Fixed bug when displaying assembly for the first time. It wasn't showing the current line. - Fixed background color problem in MemoryVisualizer for disassembly. ## [1.7] - 2022-07-04 * Add an assembly tab, along side the source tabs in the Code Manager. - Shows the program's assembly. - Enable with "View -> Assembly View" - Can set and show breakpoints. - Highlight the current instruction. - Step by instruction (Nexti and Stepi). - Double-clicking on entries in the "Breakpoints" tab and the "Stack frames" tab will show the assembly for those addresses. - ^F to bring up search bar in Assembly tab. * Fix some minor bugs. epasveer-seer-97076f1/CONTRIBUTING.md000066400000000000000000000003201526321767600170100ustar00rootroot00000000000000Contributions are welcomed as a Pull Request. Features and bug reports as GitHub issues or a simple email to epasveer@att.net. Consult Seer's style [guide](STYLEGUIDE.md) for the coding format used in Seer. epasveer-seer-97076f1/LICENSE000066400000000000000000001045151526321767600155770ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . epasveer-seer-97076f1/README.md000066400000000000000000000226251526321767600160520ustar00rootroot00000000000000Introduction ============ Seer - a gui frontend to gdb for Linux. (Ernie Pasveer epasveer@att.net) This project is actively worked on. The aim is a simple, yet pleasing gui to gdb. Please report any bugs or desired features to my email or create a [task](https://github.com/epasveer/seer/issues) in my GitHub project page. Installation ============ Seer can be installed either from a package manager or from source. > [!NOTE] > Make sure the requirements are met before installing. Requirements --------- * Linux * C++17 * gdb with "mi" interpreter (check by running: `gdb --interpreter=mi`) * CMake (3.5.0 or newer) * QT6 * When building Seer from source, you will need the QT6 "devel" packages installed on your system for your distribution. * Core * Gui * Widgets * PrintSupport * Charts * Svg * Qt6 build instructions are here: https://github.com/epasveer/seer/wiki/Building-Seer---Qt6 * QT5 * **Seer no longer compiles with Qt5.** The 2.3 source tree is the last one that does. * Qt5 build instructions are here: https://github.com/epasveer/seer/wiki/Building-Seer---Qt5 Install from package --------- Available through the following package managers: ### Pamac (Manjaro) $ pamac install seer ### zypper (openSUSE Tumbleweed) $ zypper install seergdb ### Flathub Flathub website. [Here](https://flathub.org/en/apps/io.github.epasveer.seer) $ flatpak install flathub io.github.epasveer.seer ### Flatpak Beta Seer versions. [Seer's release page](https://github.com/epasveer/seer/releases/tag/flatpak-latest) on github. **Important**: `flatpak-spawn --host`, needed in `GDB Launcher` to run gdb. See https://github.com/epasveer/seer/issues/377#issuecomment-3620844808. Download ```seer.flatpak```. Install it: $ flatpak install -y --bundle --user seer.flatpak ### Snap Beta Seer versions. [Seer's release page](https://github.com/epasveer/seer/releases/tag/snap-latest) on github. $ snap install seergdb_.snap --dangerous Install from source --------- (Recommended) Seer can be built with Qt6 by following the instructions below. https://github.com/epasveer/seer/wiki/Building-Seer---Qt6 It can still be built with Qt5, for the time being by following the instructions below. https://github.com/epasveer/seer/wiki/Building-Seer---Qt5 NEWS ==== Check out [Seer's Wiki page](https://github.com/epasveer/seer/wiki) on github. * Version v1.17 will be the last Qt5 release. * The next release will be v2.0 and will be Qt6 based. However, for the time being, it's still able to be compiled with Qt5. * If you want the latest stable Qt5 source, grab v1.17 from here: https://github.com/epasveer/seer/releases/tag/v1.17 Starting Seer ============= Seer is meant to easily start the program to debug from the command line. gdb has multiple methods for debugging a program. So Seer naturally does too. Go to the Wiki to see all the ways to run Seer. https://github.com/epasveer/seer/wiki/Starting-Seer GUI overview ============ Examples of the various Seer views and dialogs. Main View --------- The main view for Seer looks like this: ![](images/mainview.png) * Source/Function/Types/Variables/Libraries * The list of source/header files that were used in the program. * Search for Functions, Types, and Static Variables. Dobule clicking will open the source file. * The list of shared libraries referenced by the program. * The list of source/header files can be searched. This will "shrink" the list of files shown. * Double clicking on a file will open it in the Code Manager. * Variable/Register Info * Show variable and register values. * "Logger" - log the value of a variable. Manually enter it or double click on the variable in the file that is opened in the code manager. * "Tracker" - create a list of variables to show the value for whenever gdb reaches a stopping point (step, next, finish, etc.). When the stopping point is reached, all variables in the list will show their potentially new value. * "Registers" - show the values of all cpu registers. * Code Manager. * The large area of the middle part of the Seer gui. * Source files are opened in this view. * Text in a file can be seached for with ^F. * Variables can be added to the "Logger" by double clicking the variable name. Double click with CTLR key pressed will prepend variable with "*". Double click with SHIFT key pressed will prepend variable with "&". Double click with CTRL+SHIFT key pressed will prepend variable with "*&". * Variables can be added to the "Tracker" by selecting the variable name and RMB and select "Add variable to Tracker". * Variables can be added to the "Memory Visualizer" by selecting the variable name and RMB and select "Add variable to Memory Visualizer". * A breakpoint/printpoint can be created by RMB on a specific line. * Can execute to a specific line by RMB on a specific line. * Tabs in this view can be detached by double-clicking a tab. * Breakpoints, Watchpoints, Catchpoints, Printpoints, manual gdb commands, and logs. * The area below the Code Manager. * Manual commands. Manually enter a gdb or gdbmi command. The commands are remembered for the next Seer use. * Breakpoint manager. Create and manage breakpoints. * Watchpoint manager. Create and manage watchpoints. A watchpoint monitors when a variable is accessed (read, write, read/write). * Catchpoint manager. Create and manage catchpoints. A catchpoint stops execution on a C++ throw/rethrow/catch call. * Printpoint manager. Create and manage printpoints. A printpoint is like a breakpoint but it allows you to print variables at that printpoint. See gdb's 'dprintf' call. * GDB output. A log of any output from the gdb program itself. * Seer output. A log of any output from the Seer program itself. As diagnostics. * Tabs in this view can be detached by double-clicking a tab. * Stack frame information. * Stack frame list. A frame can be double clicked to change the scope (the current function). * Stack frame arguments. For each frame, print the arguments passed to each function. * Stack locals. For the current function, print the values of the local variables. * Thread information. * Thread ids. A list of all threads. Double click on a thread id to change the scope (the current thread). * Thread frames. For each thread, list its stack frames. * Supports Gdb's Reverse Debugging mode. * Turn instruction recording on or off. * Set playback direction to forward or reverse. Open Dialog ----------- When the open executable dialog is invoked, it looks like this: ![](images/opendialog.png) Seer Console ------------ All text output from the executable will go to the Seer console. Text input for the executable can be entered via the console too. ![](images/console.png) Assembly View ------------- Normally Seer will just show the source code as tabs in the Code Manager. The program's assembly can also be show as a tab. Select "View->Assembly View" and an extra tab will be shown alongside the source code tabs that shows the current assembly being executed. Here is an example. ![](images/mainview_assemby.png ) Like the source code tabs, breakpoints can be set in the assembly tab. The current instruction is highlighted. Double-clicking on entries in the "Breakpoints" tab and the "Stack frames" tab will show the assembly for those addresses. There are "Nexti" and "Stepi" hot-keys, as defined by your config settings. Normally "Ctrl+F5" and "CTRL+F6". Using "^F" in the assembly tab will show a powerful search bar. **The assembly feature in Seer is new. Feel free to suggest changes/features.** Memory Visualizer ----------------- When looking at the contents of raw memory in the Memory Visualizer, it looks like this : Memory | Disassembly --- | --- ![](images/memoryvisualizer.png) | ![](images/memoryvisualizer_asm.png) Array Visualizer ----------------- When looking at the contents of arrays in the Array Visualizer, it looks like this : Normal | Spline | Scatter --- | --- | --- ![](images/arrayvisualizer.png) | ![](images/arrayvisualizer_spline.png) | ![](images/arrayvisualizer_scatter.png) Two arrays can be used as an X-Y plot. For example, this simple 'points' array forms the X-Y outline of a shape. ``` int main() { int points[] = {50,1,20,91,97,35,2,35,79,91,50,1}; return 0; } ``` X values | Y values | XY Values --- | --- | --- ![](images/arrayvisualizer_x.png) | ![](images/arrayvisualizer_y.png) | ![](images/arrayvisualizer_xy.png) Struct Visualizer ----------------- When looking at the contents of a C/C++ struct or a C++ class in the Struct Visualizer, it looks like this. This example shows the contents of "*this" for the current C++ class that Seer is in. All structure members that are basic types can be edited. ![](images/structvisualizer.png) There is also a **Basic Struct Visualizer** that is more light weight, but can not follow pointers and can not be edited. Image Visualizer ----------------- When looking at the contents of raw memory that is an image, the Image Visualizer can be used. ![](images/imagevisualizer.png) Support/Contact =============== Send an email to epasveer@att.net for any bugs or features. Or create a [task](https://github.com/epasveer/seer/issues) in my GitHub project page. Stargazers ========== It's a wonderful world. ![](images/stargazer-map.svg) epasveer-seer-97076f1/STYLEGUIDE.md000066400000000000000000000233471526321767600165750ustar00rootroot00000000000000# Introduction Welcome to Seer, you seasoned developers and contributors. Thanks for your efforts! This file describes the coding style used in Seer. As well as some other design/coding tidbits that Seer follows. Just a preface, **every** developer has their own style when writing code. I'm no different. I don't think there's any right or wrong way to style your code. But I do think one should be consistent. So, this is Seer's style... ## Tabs Hopefully not a contentious area. * Tab size set to 4 spaces. * Use 'Tab to Spaces' mode in your editor. No physical tab characters in the source. ## Line lengths. In this day of large monitors, I see no reason to restrict line lengths to some arbitrary small number of characters. Greater than 100 characters per line is fine with me. ## Code formatters. Code formatters, like clang-format and the ilk, are great tools for formatting code. They may not cover all the formatting cases in this style guide, though. Some manual formatting may still be needed afterwards. One very important point. Don't reformat the entire contents of an existing file. It will likely be rejected in the PR merge process as it makes comparing diffs **extremely** hard. Just format the area that you changed/modified. ## C++ Variable names. Variable names should be descriptive and not overly short, and not excessively long. They should be camel case with the first character being lowercase. ``` int iteration = 10; double dampingFactor = 0.05 + 0.05*iteration; ``` Private variables, such as private members of a C++ Class, should follow the same rule but also add the requirement the variable is prefixed with an underscore ('_') ``` private: QActionGroup* _themeStyleMenuActionGroup; QActionGroup* _iconColorMenuActionGroup; ``` Static variables should be camel case with the first character being uppercase. ``` static int Next_ID = 1; static std::mutex ID_mutex; ``` ## C++ Struct member names. Member names in structs should be camel case with the first character being lowercase. It's ok to prefix the name with an underscore ('_') if you want. Here is an example. ```patternExpression``` and ```charFormat``` are the struct members. ``` struct HighlightingRule { QRegularExpression patternExpression; QTextCharFormat charFormat; }; ``` ## C++ Class and Struct names. Class and struct names should be camel case with the first character being uppercase. Here are a couple examples. ```QZoomChart``` is a class name and ```QDetachTabInfo``` is a struct name. ``` class QZoomChart : public QChart { public: QZoomChart(QGraphicsItem* parent = nullptr, Qt::WindowFlags wFlags = {}); ~QZoomChart(); ... }; struct QDetachTabInfo { QString title; QWidget* widget; QWidget* placeholderWidget; }; ``` ## Getters and Setters. C++ Getter and Setter functions should be camel case with the first letter lowercase. The Setter should start with some action verb, like 'set' or 'make'. The Getter does **not** use the 'get' prefix. ``` void setGdbNonStopMode (bool flag); bool gdbNonStopMode () const; void setGdbServerDebug (bool flag); bool gdbServerDebug () const; ``` ## Where to place '{}' brackets. I put '{' at the end of the same line and not on the next line. The '}' on a new line. Here are some examples for functions, loops, and 'if' statements. ``` // Function int age (int years, int months, int days) { return years*365 + months*31 + days; // Rough number of days. } // Loops for (int i=0; i<30; i++) { } while (i>0) { i--; } // If statements if (j < 0) { cout << "Less" << endl; }else if (j > 0) { cout << "More" << endl; }else{ cout << "Equal" << endl; } ``` ## Where to place '&*' reference/pointer characters. The '&' and '\*' character indicates a variable is a pointer or a reference. I prefer them to *cuddle up* to the datatype and not to the the variable. A simple example: ``` int* values; ``` Not: ``` int *values; ``` Declaring function parameters would look like: ``` void setAData (const QString& label, DataStorage* pData); void setBData (const QString& label, DataStorage* pData); ``` Decalaring the function return type would look like: ``` const QString& aLabel () const; const QString& bLabel () const; ``` ## Const Correctness. For C++, being Const Correct is an advantage. It can help detect some errors at compile time. Const Correctness means using the 'const' keyword in certain places. * At the end of a function declaration to tell the compiler the function doesn't change state of internal variables. * In front of variables/objects that are passed to a function. Which means the function can't attempt to change the value of the variable/object. * In front of the variable/object that is returned from a function. When means the return value can't be changed. * When declaring a variable with a value and not allowing the variable to be changed afterwards. Here are some examples. Declare the function as Const. The 'gdbNonStopMode' function doesn't change any internal state. Can be overridden by using the 'mutable' keyword, though. ``` bool gdbNonStopMode () const; ``` Variables passed to a function can be specified with Const. The tells the compiler the function can't attempt to change them. ``` void gdbSetDebugName(const QString& name, const QString& mode); ``` Declare the return value as Const. The 'gdbDebugName' function returns the value in such a way that it will detect at compile time if the code tries to change the return value of QString. ``` const QString& gdbDebugName () const; ``` Declaring a variable inside a function as Const means the variable is set with a value and can't be changed later. ``` const int age = 65; ``` ## Minimalized header files. This is a style I like. Its aim is solely to keep the header file minimal, yet complete. * Function and variable declarations only. * Don't implement functions in the header file. * The implementation is in the .cpp file. * Doxygen comments/tags go in the .cpp file. Header files then become a minimal and complete reference to your classes. ## Formatting lines into columns. When the opportunity arises, I like to organize code into columns. It's sounds weird, I know. But, visually, I think it makes the code easier to read. I see two main areas that benefit from this. * Declaring functions in a header file. * Connecting Qt signals and slots together. Take this example of declaring functions in a header file. The list of function declarations are put into three *colums*. Return value, Function name, and Function parameters. ``` |Return value............| |Function name...| |Function paramters...................| const QString& aAxis () const; void setAAxis (const QString& axis); const QString& aLabel () const; void setAAddressOffset (unsigned long offset); unsigned long aAddressOffset () const; void setAAddressStride (unsigned long stride); unsigned long aAddressStride () const; unsigned long aSize () const; unsigned long aElementSize () const; void setAArrayMode (SeerArrayWidget::ArrayMode arrayMode); SeerArrayWidget::ArrayMode aArrayMode () const; QString aArrayModeString () const; const QVector& aArrayValues () const; ``` To me, that looks a whole lot better than no columns. ``` const QString& aAxis() const; void setAAxis(const QString& axis); const QString& aLabel() const; void setAAddressOffset(unsigned long offset); unsigned long aAddressOffset() const; void setAAddressStride(unsigned long stride); unsigned long aAddressStride() const; unsigned long aSize()const; unsigned long aElementSize() const; void setAArrayMode(SeerArrayWidget::ArrayMode arrayMode); SeerArrayWidget::ArrayMode aArrayMode() const; QString aArrayModeString() const; const QVector& aArrayValues() const; ``` The code to connect Qt signal and slots together can benefit as well. ``` |Signal parameters....................................................| |Slot parameters.................................| QObject::connect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(showAsLittleEndianCheckBox, &QCheckBox::clicked, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(showUnsignedFloatAsHexCheckBox, &QCheckBox::clicked, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(this, &SeerHexWidget::byteOffsetChanged, this, &SeerHexWidget::handleByteOffsetChanged); ``` Looks much better than with no columns. ``` QObject::connect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(showAsLittleEndianCheckBox, &QCheckBox::clicked, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(showUnsignedFloatAsHexCheckBox, &QCheckBox::clicked, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(this, &SeerHexWidget::byteOffsetChanged, this, &SeerHexWidget::handleByteOffsetChanged); ``` ## That's about it. Again, **many thanks** for your efforts! epasveer-seer-97076f1/src/000077500000000000000000000000001526321767600153535ustar00rootroot00000000000000epasveer-seer-97076f1/src/CMakeLists.txt000066400000000000000000000304341526321767600201170ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.10.0) project(seergdb VERSION 2.8.1 LANGUAGES CXX) set(PROJECT_NAME seergdb) if(NOT DEFINED QTVERSION) set(QTVERSION "QT6" CACHE STRING "" FORCE) endif() if(${QTVERSION} STREQUAL "QT6") message("-- Compile with QT6") elseif(${QTVERSION} STREQUAL "QT5") message("-- Compile with QT5") else() message(FATAL_ERROR "-- Use -DQTVERSION=QT5|QT6 not \"${QTVERSION}\"") endif() # Find includes in the build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_PREFIX_PATH ${QTDIR}) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) if(${QTVERSION} STREQUAL "QT6") find_package(Qt6 COMPONENTS REQUIRED Core) find_package(Qt6 COMPONENTS REQUIRED Gui) find_package(Qt6 COMPONENTS REQUIRED Widgets) find_package(Qt6 COMPONENTS REQUIRED PrintSupport) find_package(Qt6 COMPONENTS REQUIRED Charts) find_package(Qt6 COMPONENTS REQUIRED Svg) find_package(Qt6 COMPONENTS REQUIRED OpenGL) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) elseif(${QTVERSION} STREQUAL "QT5") find_package(Qt5 COMPONENTS REQUIRED Core) find_package(Qt5 COMPONENTS REQUIRED Gui) find_package(Qt5 COMPONENTS REQUIRED Widgets) find_package(Qt5 COMPONENTS REQUIRED PrintSupport) find_package(Qt5 COMPONENTS REQUIRED Charts) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) endif() # Define the source location of header files set(HEADER_FILES GdbMonitor.h QProcessInfo.h QProcessInfoWidget.h QProgressIndicator.h QColorButton.h QColorSwatch.h QDetachTabWidget.h QZoomChartView.h QZoomChart.h QClearLineEdit.h QIndexTreeWidget.h QStringPair.h QHistoryLineEdit.h QEditDelegate.h QHContainerWidget.h QImageViewer.h QAnsiTextEdit.h SeerUtl.h SeerArgumentsDialog.h SeerBreakpointCreateDialog.h SeerMessagesBrowserWidget.h SeerBreakpointsBrowserWidget.h SeerCatchpointCreateDialog.h SeerCatchpointsBrowserWidget.h SeerPrintpointCreateDialog.h SeerPrintpointsBrowserWidget.h SeerCheckpointsBrowserWidget.h SeerCommandLogsWidget.h SeerSeerLogWidget.h SeerConsoleWidget.h SeerConfigDialog.h SeerGdbConfigPage.h SeerRRConfigPage.h SeerEditorConfigPage.h SeerSourceConfigPage.h SeerAssemblyConfigPage.h SeerSeerConfigPage.h SeerKeysConfigPage.h SeerCloseSourceDialog.h SeerDebugDialog.h SeerDirectoryFilterProxyModel.h SeerEditorManagerEntry.h SeerEditorManagerWidget.h SeerEditorWidgetSource.h SeerEditorWidgetAssembly.h SeerExecutableFilterProxyModel.h SeerGdbWidget.h SeerHexWidget.h SeerAsmWidget.h SeerArrayWidget.h SeerMarixWidget.h SeerLogWidget.h SeerMainWindow.h SeerArrayVisualizerWidget.h SeerMatrixVisualizerWidget.h SeerMemoryVisualizerWidget.h SeerStructVisualizerWidget.h SeerVarVisualizerWidget.h SeerImageVisualizerWidget.h SeerParallelStacksVisualizerWidget.h SeerParallelStacksGraphicsView.h SeerParallelStacksCommon.h SeerParallelStacksSettingsDialog.h SeerParallelStacksFilterWidget.h SeerGdbMonitorWidget.h SeerRegisterValuesBrowserWidget.h SeerRegisterEditValueDialog.h SeerRegisterProfileDialog.h SeerRegisterTreeWidgetItem.h SeerSignalValuesBrowserWidget.h SeerSignalProfileDialog.h SeerSignalEditValueDialog.h SeerRunStatusIndicator.h SeerLibraryBrowserWidget.h SeerSourceBrowserWidget.h SeerFunctionBrowserWidget.h SeerTypeBrowserWidget.h SeerStaticBrowserWidget.h SeerSkipBrowserWidget.h SeerSkipCreateDialog.h SeerSourceSymbolLibraryManagerWidget.h SeerStackArgumentsBrowserWidget.h SeerStackFramesBrowserWidget.h SeerStackLocalsBrowserWidget.h SeerStackDumpBrowserWidget.h SeerStackDumpSettingsDialog.h SeerStackManagerWidget.h SeerThreadFramesBrowserWidget.h SeerThreadIdsBrowserWidget.h SeerThreadGroupsBrowserWidget.h SeerAdaTasksBrowserWidget.h SeerAdaExceptionsBrowserWidget.h SeerThreadManagerWidget.h SeerGdbLogWidget.h SeerTildeLogWidget.h SeerVariableLoggerBrowserWidget.h SeerVariableManagerWidget.h SeerVariableTrackerBrowserWidget.h SeerWatchpointCreateDialog.h SeerWatchpointsBrowserWidget.h SeerSourceHighlighter.h SeerAdaSourceHighlighter.h SeerFortranSourceHighlighter.h SeerCppSourceHighlighter.h SeerOdinSourceHighlighter.h SeerRustSourceHighlighter.h SeerAboutDialog.h SeerSlashProcDialog.h SeerHighlighterSettings.h SeerKeySettings.h SeerPlainTextEdit.h SeerHelpPageDialog.h SeerProgressIndicator.h SeerMessagesDialog.h SeerAssemblyPreferenceDialog.h SeerHistoryLineEdit.h SeerMacroEditorDialog.h SeerMacroToolButton.h ) # Define the source location of source files set(SOURCE_FILES GdbMonitor.cpp QProcessInfo.cpp QProcessInfoWidget.cpp QProgressIndicator.cpp QColorButton.cpp QColorSwatch.cpp QDetachTabWidget.cpp QZoomChartView.cpp QZoomChart.cpp QClearLineEdit.cpp QIndexTreeWidget.cpp QHistoryLineEdit.cpp QEditDelegate.cpp QHContainerWidget.cpp QImageViewer.cpp QAnsiTextEdit.cpp SeerUtl.cpp SeerArgumentsDialog.cpp SeerBreakpointCreateDialog.cpp SeerMessagesBrowserWidget.cpp SeerBreakpointsBrowserWidget.cpp SeerCatchpointCreateDialog.cpp SeerCatchpointsBrowserWidget.cpp SeerPrintpointCreateDialog.cpp SeerPrintpointsBrowserWidget.cpp SeerCheckpointsBrowserWidget.cpp SeerCommandLogsWidget.cpp SeerSeerLogWidget.cpp SeerConsoleWidget.cpp SeerConfigDialog.cpp SeerGdbConfigPage.cpp SeerRRConfigPage.cpp SeerEditorConfigPage.cpp SeerSourceConfigPage.cpp SeerAssemblyConfigPage.cpp SeerSeerConfigPage.cpp SeerKeysConfigPage.cpp SeerCloseSourceDialog.cpp SeerDebugDialog.cpp SeerEditorManagerWidget.cpp SeerEditorWidgetSource.cpp SeerEditorWidgetSourceAreas.cpp SeerEditorWidgetAssembly.cpp SeerEditorWidgetAssemblyAreas.cpp SeerGdbWidget.cpp SeerHexWidget.cpp SeerAsmWidget.cpp SeerArrayWidget.cpp SeerMatrixWidget.cpp SeerLogWidget.cpp SeerMainWindow.cpp SeerArrayVisualizerWidget.cpp SeerMatrixVisualizerWidget.cpp SeerMemoryVisualizerWidget.cpp SeerStructVisualizerWidget.cpp SeerVarVisualizerWidget.cpp SeerImageVisualizerWidget.cpp SeerParallelStacksVisualizerWidget.cpp SeerParallelStacksGraphicsView.cpp SeerParallelStacksCommon.cpp SeerParallelStacksSettingsDialog.cpp SeerParallelStacksFilterWidget.cpp SeerGdbMonitorWidget.cpp SeerRegisterValuesBrowserWidget.cpp SeerRegisterEditValueDialog.cpp SeerRegisterProfileDialog.cpp SeerRegisterTreeWidgetItem.cpp SeerSignalValuesBrowserWidget.cpp SeerSignalProfileDialog.cpp SeerSignalEditValueDialog.cpp SeerRunStatusIndicator.cpp SeerLibraryBrowserWidget.cpp SeerSourceBrowserWidget.cpp SeerFunctionBrowserWidget.cpp SeerTypeBrowserWidget.cpp SeerStaticBrowserWidget.cpp SeerSkipBrowserWidget.cpp SeerSkipCreateDialog.cpp SeerSourceSymbolLibraryManagerWidget.cpp SeerStackArgumentsBrowserWidget.cpp SeerStackFramesBrowserWidget.cpp SeerStackLocalsBrowserWidget.cpp SeerStackDumpBrowserWidget.cpp SeerStackDumpSettingsDialog.cpp SeerStackManagerWidget.cpp SeerThreadFramesBrowserWidget.cpp SeerThreadIdsBrowserWidget.cpp SeerThreadGroupsBrowserWidget.cpp SeerAdaTasksBrowserWidget.cpp SeerAdaExceptionsBrowserWidget.cpp SeerThreadManagerWidget.cpp SeerGdbLogWidget.cpp SeerTildeLogWidget.cpp SeerVariableLoggerBrowserWidget.cpp SeerVariableManagerWidget.cpp SeerVariableTrackerBrowserWidget.cpp SeerWatchpointCreateDialog.cpp SeerWatchpointsBrowserWidget.cpp SeerSourceHighlighter.cpp SeerAdaSourceHighlighter.cpp SeerFortranSourceHighlighter.cpp SeerCppSourceHighlighter.cpp SeerOdinSourceHighlighter.cpp SeerRustSourceHighlighter.cpp SeerAboutDialog.cpp SeerSlashProcDialog.cpp SeerHighlighterSettings.cpp SeerKeySettings.cpp SeerPlainTextEdit.cpp SeerHelpPageDialog.cpp SeerProgressIndicator.cpp SeerMessagesDialog.cpp SeerAssemblyPreferenceDialog.cpp SeerHistoryLineEdit.cpp SeerMacroEditorDialog.cpp SeerMacroToolButton.cpp seergdb.cpp ) if(${QTVERSION} STREQUAL "QT6") qt6_add_resources(SOURCE_FILES resource.qrc resources/qdarkstyle/dark/darkstyle.qrc resources/qdarkstyle/light/lightstyle.qrc) elseif(${QTVERSION} STREQUAL "QT5") qt5_add_resources(SOURCE_FILES resource.qrc resources/qdarkstyle/dark/darkstyle.qrc resources/qdarkstyle/light/lightstyle.qrc) endif() # Set non-Debug build as GUI application. # Debug build remains consle application. if(NOT CMAKE_BUILD_TYPE MATCHES Debug) #Release, RelWithDebInfo and MinSizeRel if(WIN32) # Check if we are on Windows set(SYSTEM_TYPE WIN32) endif() message("-- System type is " ${SYSTEM_TYPE}) endif() # for Linux, BSD, Solaris, Minix if(UNIX AND NOT APPLE) add_compile_options(-Wall -Wextra -Wunused-result -pedantic) # -Werror -Wdeprecated-copy endif() add_definitions(-DQT_DISABLE_DEPRECATED_UP_TO=0x060300) add_executable(${PROJECT_NAME} ${SYSTEM_TYPE} ${SOURCE_FILES}) install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) if(${QTVERSION} STREQUAL "QT6") target_link_libraries(${PROJECT_NAME} Qt6::Widgets Qt6::Gui Qt6::Core Qt6::PrintSupport Qt6::Charts Qt6::Svg Qt6::OpenGL) elseif(${QTVERSION} STREQUAL "QT5") target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::Gui Qt5::Core Qt5::PrintSupport Qt5::Charts) endif() # Handle gdb logout debugging. Turn CONFIG_SEER_GDB_LOGOUT=1 to enable gdb logout # -DCONFIG_SEER_GDB_LOGOUT=1 if(NOT DEFINED CONFIG_SEER_GDB_LOGOUT) set(CONFIG_SEER_GDB_LOGOUT 0) endif() target_compile_definitions(${PROJECT_NAME} PRIVATE SEER_GDB_LOGOUT=${CONFIG_SEER_GDB_LOGOUT} ) # Handle default gdb binary name and location. # -DCONFIG_SEER_GDB_NAME=/app/bin/gdb if(NOT DEFINED CONFIG_SEER_GDB_NAME) set(CONFIG_SEER_GDB_NAME "/usr/bin/gdb") endif() target_compile_definitions(${PROJECT_NAME} PRIVATE SEER_GDB_NAME=${CONFIG_SEER_GDB_NAME} ) # Handle default gdb binary launcher (for flatpak, et al) # -DCONFIG_SEER_GDB_LAUNCHER="flatpak-spawn --host" if(NOT DEFINED CONFIG_SEER_GDB_LAUNCHER) set(CONFIG_SEER_GDB_LAUNCHER "") endif() target_compile_definitions(${PROJECT_NAME} PRIVATE SEER_GDB_LAUNCHER=${CONFIG_SEER_GDB_LAUNCHER} ) # Install icons to standard XDG icon directories # -DCONFIG_SEER_INSTALL_ICONS=1 if(CONFIG_SEER_INSTALL_ICONS) message("-- Will install icons to system") install(FILES "${CMAKE_SOURCE_DIR}/resources/icons/hicolor/32x32/seergdb.png" DESTINATION "share/icons/hicolor/32x32/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/icons/hicolor/64x64/seergdb.png" DESTINATION "share/icons/hicolor/64x64/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/icons/hicolor/128x128/seergdb.png" DESTINATION "share/icons/hicolor/128x128/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/icons/hicolor/256x256/seergdb.png" DESTINATION "share/icons/hicolor/256x256/apps") endif() # Install flathub icons to standard XDG icon directories # -DCONFIG_SEER_INSTALL_FLATHUB_FILES=1 if(CONFIG_SEER_INSTALL_FLATHUB_FILES) message("-- Will install flathub icons+files to system") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/icons/hicolor/32x32/io.github.epasveer.seer.png" DESTINATION "share/icons/hicolor/32x32/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/icons/hicolor/64x64/io.github.epasveer.seer.png" DESTINATION "share/icons/hicolor/64x64/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/icons/hicolor/128x128/io.github.epasveer.seer.png" DESTINATION "share/icons/hicolor/128x128/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/icons/hicolor/256x256/io.github.epasveer.seer.png" DESTINATION "share/icons/hicolor/256x256/apps") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/io.github.epasveer.seer.metainfo.xml" DESTINATION "share/metainfo") install(FILES "${CMAKE_SOURCE_DIR}/resources/flathub/io.github.epasveer.seer.desktop" DESTINATION "share/applications") endif() epasveer-seer-97076f1/src/GdbMonitor.cpp000066400000000000000000000115231526321767600201250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "GdbMonitor.h" #include #include #include #include #include static QLoggingCategory LC("seer.gdbmonitor"); GdbMonitor::GdbMonitor (QObject* parent) : QObject(parent) { _process = 0; } GdbMonitor::~GdbMonitor () { } void GdbMonitor::handleErrorOccurred (QProcess::ProcessError error) { Q_UNUSED(error); qCDebug(LC) << error; qApp->exit(); } void GdbMonitor::handleFinished (int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitCode); Q_UNUSED(exitStatus); qCDebug(LC) << exitCode << exitStatus; qApp->exit(); } void GdbMonitor::handleReadyReadStandardError () { qCDebug(LC) << "Ready to read stderr"; QProcess* p = (QProcess*)sender(); // canReadLine()/readLine() work on the current read channel, which // defaults to stdout. Point them at stderr for this handler, then // switch back for the stdout handler. p->setReadChannel(QProcess::StandardError); // Read a line at a time. while (p->canReadLine()) { QByteArray buf = p->readLine(); // Chop off trailing RETURN character. if (buf[buf.size()-1] == '\n') { buf.chop(1); } // Convert to a string. QString text(buf); qCDebug(LC) << text; // Start broadcasting it around. emit allTextOutput(text); } p->setReadChannel(QProcess::StandardOutput); } void GdbMonitor::handleReadyReadStandardOutput () { qCDebug(LC) << "Ready to read stdout"; QProcess* p = (QProcess*)sender(); // Read a line at a time. while (p->canReadLine()) { QByteArray buf = p->readLine(); // Chop off trailing RETURN character. if (buf[buf.size()-1] == '\n') { buf.chop(1); } if (buf.size() == 0) { // Ignore empty lines. continue; } // Convert to a string. QString text(buf); //qDebug() << "Read buffer" << buf.size() << (int)buf[buf.size()-1] << text; qCDebug(LC) << text; #if SEER_GDB_LOGOUT == 1 // Start broadcasting it around. For debugging emit allTextOutput("From GdbMonitor: " + text + "\n"); #endif if (text[0] == '~') { emit tildeTextOutput(text); }else if (text[0] == '=') { emit equalTextOutput(text); }else if (text[0] == '*') { emit astrixTextOutput(text); }else if (text[0] == '^') { emit caretTextOutput(text); }else if (text[0] == '&') { emit ampersandTextOutput(text); }else if (text[0] == '@') { emit atsignTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\~"))) { emit tildeTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\="))) { emit equalTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\*"))) { emit astrixTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\^"))) { emit caretTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\&"))) { emit ampersandTextOutput(text); }else{ emit textOutput(text); } } qCDebug(LC) << "Finished reading stdout"; } void GdbMonitor::handleTextOutput (QString text) { qCDebug(LC) << "Ready to handle text output"; qCDebug(LC) << text; emit allTextOutput(text); if (text[0] == '~') { emit tildeTextOutput(text); }else if (text[0] == '=') { emit equalTextOutput(text); }else if (text[0] == '*') { emit astrixTextOutput(text); }else if (text[0] == '^') { emit caretTextOutput(text); }else if (text[0] == '&') { emit ampersandTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\~"))) { emit tildeTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\="))) { emit equalTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\*"))) { emit astrixTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\^"))) { emit caretTextOutput(text); }else if (text.contains(QRegularExpression("^([0-9]+)\\&"))) { emit ampersandTextOutput(text); }else{ emit textOutput(text); } qCDebug(LC) << "Finished handling text output"; } void GdbMonitor::handleStarted() { qCDebug(LC); } void GdbMonitor::handleStateChanged(QProcess::ProcessState newState) { Q_UNUSED(newState); qCDebug(LC) << newState; } void GdbMonitor::setProcess (QProcess* process) { _process = process; } QProcess* GdbMonitor::process () { return _process; } epasveer-seer-97076f1/src/GdbMonitor.h000066400000000000000000000033321526321767600175710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #ifndef GdbMonitor_H #define GdbMonitor_H #include #include class GdbMonitor : public QObject { Q_OBJECT public: explicit GdbMonitor (QObject* parent = 0); virtual ~GdbMonitor (); void setProcess (QProcess* process); QProcess* process (); signals: void allTextOutput (const QString& text); void tildeTextOutput (const QString& text); void equalTextOutput (const QString& text); void astrixTextOutput (const QString& text); void caretTextOutput (const QString& text); void ampersandTextOutput (const QString& text); void atsignTextOutput (const QString& text); void textOutput (const QString& text); public slots: void handleErrorOccurred (QProcess::ProcessError error); void handleFinished (int exitCode, QProcess::ExitStatus exitStatus); void handleReadyReadStandardError (); void handleReadyReadStandardOutput (); void handleStarted (); void handleStateChanged (QProcess::ProcessState newState); void handleTextOutput (QString text); private: QProcess* _process; }; #endif epasveer-seer-97076f1/src/QAnsiTextEdit.cpp000066400000000000000000000350551526321767600205550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QAnsiTextEdit.h" #include // // // QAnsiTextEditFormattedText::QAnsiTextEditFormattedText(const QString& txt, const QTextCharFormat& fmt) { text = txt; format = fmt; } // // // QList QAnsiTextEditEscapeCodeHandler::parseText (const QAnsiTextEditFormattedText& input) { enum AnsiEscapeCodes { ResetFormat = 0, BoldText = 1, UnderLinedText = 4, TextColorStart = 30, TextColorEnd = 37, RgbTextColor = 38, DefaultTextColor = 39, BackgroundColorStart = 40, BackgroundColorEnd = 47, RgbBackgroundColor = 48, DefaultBackgroundColor = 49 }; const QString escape = "\x1b["; const QChar semicolon = ';'; const QChar colorTerminator = 'm'; const QChar eraseToEol = 'K'; QList outputData; QTextCharFormat charFormat = _previousFormatClosed ? input.format : _previousFormat; QString strippedText; if (_pendingText.isEmpty()) { strippedText = input.text; }else{ strippedText = _pendingText.append(input.text); _pendingText.clear(); } while (!strippedText.isEmpty()) { if (_waitingForTerminator) { // We ignore all escape codes taking string arguments. QString terminator = "\x1b\\"; int terminatorPos = strippedText.indexOf(terminator); if (terminatorPos == -1 && !_alternateTerminator.isEmpty()) { terminator = _alternateTerminator; terminatorPos = strippedText.indexOf(terminator); } if (terminatorPos == -1) { _pendingText = strippedText; break; } _waitingForTerminator = false; _alternateTerminator.clear(); strippedText.remove(0, terminatorPos + terminator.length()); if (strippedText.isEmpty()) { break; } } const int escapePos = strippedText.indexOf(escape.at(0)); if (escapePos < 0) { outputData << QAnsiTextEditFormattedText(strippedText, charFormat); break; }else if (escapePos != 0) { outputData << QAnsiTextEditFormattedText(strippedText.left(escapePos), charFormat); strippedText.remove(0, escapePos); } while (!strippedText.isEmpty() && escape.at(0) == strippedText.at(0)) { if (escape.startsWith(strippedText)) { // control secquence is not complete _pendingText += strippedText; strippedText.clear(); break; } if (!strippedText.startsWith(escape)) { switch (strippedText.at(1).toLatin1()) { case '\\': // Unexpected terminator sequence. Q_FALLTHROUGH(); case 'N': case 'O': // Ignore unsupported single-character sequences. strippedText.remove(0, 2); break; case ']': _alternateTerminator = QChar(7); Q_FALLTHROUGH(); case 'P': case 'X': case '^': case '_': strippedText.remove(0, 2); _waitingForTerminator = true; break; default: // not a control sequence _pendingText.clear(); outputData << QAnsiTextEditFormattedText(strippedText.left(1), charFormat); strippedText.remove(0, 1); continue; } break; } _pendingText += strippedText.mid(0, escape.length()); strippedText.remove(0, escape.length()); // \e[K is not supported. Just strip it. if (strippedText.startsWith(eraseToEol)) { _pendingText.clear(); strippedText.remove(0, 1); continue; } // get the number QString strNumber; QStringList numbers; while (!strippedText.isEmpty()) { if (strippedText.at(0).isDigit()) { strNumber += strippedText.at(0); }else{ if (!strNumber.isEmpty()) { numbers << strNumber; } if (strNumber.isEmpty() || strippedText.at(0) != semicolon) { break; } strNumber.clear(); } _pendingText += strippedText.mid(0, 1); strippedText.remove(0, 1); } if (strippedText.isEmpty()) { break; } // remove terminating char if (!strippedText.startsWith(colorTerminator)) { _pendingText.clear(); strippedText.remove(0, 1); break; } // got consistent control sequence, ok to clear pending text _pendingText.clear(); strippedText.remove(0, 1); if (numbers.isEmpty()) { charFormat = input.format; endFormatScope(); } for (int i = 0; i < numbers.size(); ++i) { const uint code = numbers.at(i).toUInt(); if (code >= TextColorStart && code <= TextColorEnd) { //qDebug() << "TextColorStart/TextColorEnd called"; charFormat.setForeground(ansiColor(code - TextColorStart)); setFormatScope(charFormat); }else if (code >= BackgroundColorStart && code <= BackgroundColorEnd) { //qDebug() << "BackgroundColorStart/BackgroundColorEnd called"; charFormat.setBackground(ansiColor(code - BackgroundColorStart)); setFormatScope(charFormat); }else{ switch (code) { case ResetFormat: //qDebug() << "ResetFormat called"; charFormat.setFontWeight(QFont::Normal); charFormat.setFontUnderline(false); charFormat.setForeground(input.format.foreground()); charFormat.setBackground(input.format.background()); setFormatScope(charFormat); endFormatScope(); break; case BoldText: //qDebug() << "BoldText called"; charFormat.setFontWeight(QFont::ExtraBold); setFormatScope(charFormat); break; case UnderLinedText: //qDebug() << "UnderLinedText called"; charFormat.setFontUnderline(true); setFormatScope(charFormat); break; case DefaultTextColor: //qDebug() << "DefaultTextColor called"; charFormat.setForeground(input.format.foreground()); setFormatScope(charFormat); break; case DefaultBackgroundColor: //qDebug() << "DefaultBackgroundColor called"; charFormat.setBackground(input.format.background()); setFormatScope(charFormat); break; case RgbTextColor: case RgbBackgroundColor: //qDebug() << "RgbTextColor/RgbBackgroundColor called"; // See http://en.wikipedia.org/wiki/ANSI_escape_code#Colors if (++i >= numbers.size()) { break; } switch (numbers.at(i).toInt()) { case 2: // RGB set with format: 38;2;;; if ((i + 3) < numbers.size()) { (code == RgbTextColor) ? charFormat.setForeground(QColor(numbers.at(i + 1).toInt(), numbers.at(i + 2).toInt(), numbers.at(i + 3).toInt())) : charFormat.setBackground(QColor(numbers.at(i + 1).toInt(), numbers.at(i + 2).toInt(), numbers.at(i + 3).toInt())); setFormatScope(charFormat); } i += 3; break; case 5: // 256 color mode with format: 38;5; uint index = numbers.at(i + 1).toUInt(); QColor color; if (index < 8) { // The first 8 colors are standard low-intensity ANSI colors. color = ansiColor(index); }else if (index < 16) { // The next 8 colors are standard high-intensity ANSI colors. color = ansiColor(index - 8).lighter(150); }else if (index < 232) { // The next 216 colors are a 6x6x6 RGB cube. uint o = index - 16; color = QColor((o / 36) * 51, ((o / 6) % 6) * 51, (o % 6) * 51); }else{ // The last 24 colors are a greyscale gradient. int grey = int((index - 232) * 11); color = QColor(grey, grey, grey); } if (code == RgbTextColor) { charFormat.setForeground(color); }else{ charFormat.setBackground(color); } setFormatScope(charFormat); ++i; break; } break; default: qDebug() << "Unkown code:" << code; break; } } } } } return outputData; } void QAnsiTextEditEscapeCodeHandler::endFormatScope () { _previousFormatClosed = true; } void QAnsiTextEditEscapeCodeHandler::setFormatScope (const QTextCharFormat& charFormat) { _previousFormat = charFormat; _previousFormatClosed = false; } QTextCharFormat QAnsiTextEditEscapeCodeHandler::formatScope () const { return _previousFormat; } QColor QAnsiTextEditEscapeCodeHandler::ansiColor(uint code) { const int red = code & 1 ? 170 : 0; const int green = code & 2 ? 170 : 0; const int blue = code & 4 ? 170 : 0; return QColor(red, green, blue); } // // // QAnsiTextEdit::QAnsiTextEdit (QWidget* parent) : QPlainTextEdit(parent) { } QAnsiTextEdit::QAnsiTextEdit (const QString& text, QWidget* parent) : QPlainTextEdit(parent) { setAnsiText(text); } QAnsiTextEdit::~QAnsiTextEdit () { } void QAnsiTextEdit::dumpCharFormat (QString string, QTextCharFormat format) { qDebug() << "dumpCharFormat" << string << "Font" << format.font().toString(); qDebug() << "dumpCharFormat" << string << "Color" << format.foreground().color(); qDebug() << "dumpCharFormat" << string << "FontWeight" << format.fontWeight(); qDebug() << "dumpCharFormat" << string << "UnderLined" << format.fontUnderline(); qDebug() << ""; } void QAnsiTextEdit::setAnsiText (const QString& text) { // Reset the text edit clear(); // Use append method. appendAnsiText(text); } void QAnsiTextEdit::appendAnsiText (const QString& text) { // // Use the 'append' method for the first sub text, then // the 'insert' method for every sub text after that. // // Save current TextCharFormat QTextCharFormat saveFormat = currentCharFormat(); // Create the default text object; QAnsiTextEditFormattedText ftext; ftext.text = text; ftext.format = currentCharFormat(); // Parse it. A list of sub text objects is created. QList ftexts = _escapeCodeHandler.parseText(ftext); // Print each sub text object. Each one has its own text format. bool first = true; for (const QAnsiTextEditFormattedText& ftext : ftexts) { QTextCharFormat format = ftext.format; setCurrentCharFormat(format); if (first) { appendPlainText(ftext.text); first = false; }else{ insertPlainText(ftext.text); } } // Restore current TextCharFormat setCurrentCharFormat(saveFormat); } void QAnsiTextEdit::insertAnsiText (const QString& text) { // // Use the 'insert' method for every sub text. // // Save current TextCharFormat QTextCharFormat saveFormat = currentCharFormat(); // Create the default text object; QAnsiTextEditFormattedText ftext; ftext.text = text; ftext.format = currentCharFormat(); // Parse it. A list of sub text objects is created. QList ftexts = _escapeCodeHandler.parseText(ftext); // Print each sub text object. Each one has its own text format. for (const QAnsiTextEditFormattedText& ftext : ftexts) { QTextCharFormat format = ftext.format; setCurrentCharFormat(format); insertPlainText(ftext.text); } // Restore current TextCharFormat setCurrentCharFormat(saveFormat); } epasveer-seer-97076f1/src/QAnsiTextEdit.h000066400000000000000000000037541526321767600202230ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include #include class QAnsiTextEditFormattedText { public: QAnsiTextEditFormattedText() = default; QAnsiTextEditFormattedText(const QString& txt, const QTextCharFormat& fmt = QTextCharFormat()); QString text; QTextCharFormat format; }; class QAnsiTextEditEscapeCodeHandler { public: QList parseText (const QAnsiTextEditFormattedText& input); void endFormatScope (); void setFormatScope (const QTextCharFormat& charFormat); QTextCharFormat formatScope () const; private: QColor ansiColor (uint code); bool _previousFormatClosed = true; bool _waitingForTerminator = false; QString _alternateTerminator; QTextCharFormat _previousFormat; QString _pendingText; }; class QAnsiTextEdit : public QPlainTextEdit { Q_OBJECT public: explicit QAnsiTextEdit(QWidget* parent = 0); explicit QAnsiTextEdit(const QString& text, QWidget* parent = 0); ~QAnsiTextEdit(); public: void dumpCharFormat (QString string, QTextCharFormat format); public slots: void setAnsiText (const QString& text); void appendAnsiText (const QString& text); void insertAnsiText (const QString& text); private: QAnsiTextEditEscapeCodeHandler _escapeCodeHandler; }; epasveer-seer-97076f1/src/QClearLineEdit.cpp000066400000000000000000000020271526321767600206450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QClearLineEdit.h" #include QClearLineEdit::QClearLineEdit (const QString& contents, QWidget* parent) : QLineEdit(contents, parent) { enableReturnPressedOnClear(); } QClearLineEdit::QClearLineEdit (QWidget* parent) : QLineEdit(parent) { enableReturnPressedOnClear(); } QClearLineEdit::~QClearLineEdit () { } void QClearLineEdit::enableReturnPressedOnClear() { for (int i=0; i (children().at(i))); if (myClearAction) { //qDebug() << myClearAction->objectName(); // Look for only the QLineEdit clear action. // This name could change or be different. if (myClearAction->objectName() == "_q_qlineeditclearaction") { connect(myClearAction, &QAction::triggered, this, &QLineEdit::returnPressed, Qt::QueuedConnection); } } } } epasveer-seer-97076f1/src/QClearLineEdit.h000066400000000000000000000007551526321767600203200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include class QClearLineEdit : public QLineEdit { public: QClearLineEdit (const QString& contents, QWidget* parent = nullptr); QClearLineEdit (QWidget* parent = nullptr); ~QClearLineEdit (); void enableReturnPressedOnClear (); public slots: protected: private: }; epasveer-seer-97076f1/src/QColorButton.cpp000066400000000000000000000022271526321767600204550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QColorButton.h" #include #include #include #include QColorButton::QColorButton(QWidget* parent) : QFrame(parent) { // Construct the UI. setupUi(this); setColor(palette().color(QPalette::Window)); } QColorButton::QColorButton(const QColor& color, QWidget* parent) : QFrame(parent) { // Construct the UI. setupUi(this); // Create color swatch setColor(color); } QColorButton::~QColorButton() { } void QColorButton::mouseDoubleClickEvent (QMouseEvent* e) { Q_UNUSED(e) // Open a color dialog if someone double-clicked. QColor c = QColorDialog::getColor(color(), this); if (c.isValid()) { setColor(c); } } QColor QColorButton::color () const { // Return the current color. return colorSwatch->color(); } void QColorButton::setColor (const QColor& color) { // Save the new color. colorSwatch->setColor(color); colorSwatch->update(); // Notify others that are listening. emit colorChanged(); } epasveer-seer-97076f1/src/QColorButton.h000066400000000000000000000014551526321767600201240ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include #include "ui_QColorButton.h" class QColorButton : public QFrame, protected Ui::QColorButtonForm { Q_OBJECT public: QColorButton(QWidget* parent = 0); QColorButton(const QColor& color, QWidget* parent = 0); ~QColorButton(); void setColor (const QColor& color); QColor color () const; signals: void colorChanged (); protected: void mouseDoubleClickEvent (QMouseEvent* e); }; epasveer-seer-97076f1/src/QColorButton.ui000066400000000000000000000022651526321767600203120ustar00rootroot00000000000000 QColorButtonForm 0 0 400 300 Color Button QFrame::NoFrame QFrame::Plain 0 0 0 0 QColorSwatch QWidget
QColorSwatch.h
1
epasveer-seer-97076f1/src/QColorSwatch.cpp000066400000000000000000000014731526321767600204350ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QColorSwatch.h" #include #include #include QColorSwatch::QColorSwatch(QWidget* parent) : QWidget(parent) { setColor(palette().color(QPalette::Window)); } QColorSwatch::QColorSwatch(const QColor& color, QWidget* parent) : QWidget(parent) { setColor(color); } QColorSwatch::~QColorSwatch() { } void QColorSwatch::setColor (const QColor& color) { _color = color; } QColor QColorSwatch::color () const { return _color; } void QColorSwatch::paintEvent(QPaintEvent* e) { Q_UNUSED(e) // Draw the color to the widget. QPainter painter(this); painter.setPen(Qt::NoPen); painter.setBrush(color()); painter.drawRect(rect()); } epasveer-seer-97076f1/src/QColorSwatch.h000066400000000000000000000012561526321767600201010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include class QColorSwatch : public QWidget { public: QColorSwatch(QWidget* parent = 0); QColorSwatch(const QColor& color, QWidget* parent = 0); ~QColorSwatch(); void setColor (const QColor& color); QColor color () const; protected: void paintEvent (QPaintEvent* e); private: QColor _color; }; epasveer-seer-97076f1/src/QDetachTabWidget.cpp000066400000000000000000000200021526321767600211550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QDetachTabWidget.h" #include #include #include #include #include #include #include #include QDetachTabWidget::QDetachTabWidget(QWidget* parent) : QTabWidget(parent) { tabBar()->setContextMenuPolicy(Qt::CustomContextMenu); QObject::connect(tabBar(), &QTabBar::customContextMenuRequested, this, &QDetachTabWidget::handleShowContextMenu); QObject::connect(this, &QTabWidget::tabCloseRequested, this, &QDetachTabWidget::handleTabClosedRequested); } bool QDetachTabWidget::isDetached (int tabIndex) const { // Get the tab the user selected. QWidget* w = widget(tabIndex); if (w == nullptr) { return false; } // If it's the 'placeholder' it is detached. if (w->objectName() == "QDetachTabWidgetPlaceholder") { return true; } // Otherwise, it's still attached. return false; } QWidget* QDetachTabWidget::tabWidget (int tabIndex) const { if (tabIndex < 0 || tabIndex > _tabInfo.size()) { return nullptr; } return _tabInfo[tabIndex]._widget; } void QDetachTabWidget::detachTab (int tabIndex, bool minimized) { // Get the tab the user selected. QWidget* w = widget(tabIndex); if (w == nullptr) { return; } // It can't be a 'placeholder' as it was already detached. if (w->objectName() == "QDetachTabWidgetPlaceholder") { return; } // Create a blank 'placeholder' tab. QDetachTabWidgetPlaceholder* placeholder = new QDetachTabWidgetPlaceholder(tabIndex); // Create an entry for the tab cache. Remember the real tab and the 'placeholder' tab. Plus the tab title. QDetachTabInfo tabinfo(tabText(tabIndex), w, placeholder); _tabInfo.append(tabinfo); // Remove the real tab. removeTab(tabIndex); // Insert the 'placeholder' in the same position. insertTab(tabIndex, placeholder, tabinfo._title); // Tweak the detached tab to make sure it can't be destroyed as it is now a normal window. w->setParent(0); Qt::WindowFlags flags = w->windowFlags(); Qt::WindowFlags closeFlag = Qt::WindowCloseButtonHint; flags = flags & (~closeFlag); w->setWindowFlags(flags); w->setWindowTitle(tabinfo._title); w->setWindowIcon(windowIcon()); if (minimized) { w->showMinimized(); }else{ w->showNormal(); } // Connect the placeholder's 'reattach' signal to the slot. QObject::connect(placeholder, &QDetachTabWidgetPlaceholder::reattach, this, &QDetachTabWidget::handleTabClosedRequested); // Notify listeners the tab was detached. emit tabDetached(tabIndex); emit tabDetached(w); } void QDetachTabWidget::reattachTab (int tabIndex) { // Get the tab the user selected to re-attach. QWidget* w = widget(tabIndex); if (w == nullptr) { return; } // It must be a 'placeholder' if (w->objectName() != "QDetachTabWidgetPlaceholder") { return; } // Look for the 'placeholder' tab in the tab cache. // Note, we do a scan of the cache because a QTabWidget can have isMovable() enabled. // Using 'tabindex' is not always reliable. QList::iterator it = findPlaceholderWidget(w); if (it == _tabInfo.end()) { return; } // Remove the 'placeholder' tab. removeTab(tabIndex); delete w; // Insert the real tab in the same position. insertTab(tabIndex, it->_widget, it->_title); // Save the real tab's widget before we delete the entry. w = it->_widget; // Delete the entry from the tab cache. _tabInfo.erase(it); // Notify listeners the tab was reattached. emit tabReattached(tabIndex); emit tabReattached(w); } void QDetachTabWidget::closeEvent (QCloseEvent* e) { auto it = _tabInfo.begin(); while (it != _tabInfo.end()) { delete it->_widget; it = _tabInfo.erase(it); // Erase current tab and point to the next one. } QTabWidget::closeEvent(e); } void QDetachTabWidget::handleShowContextMenu (const QPoint& point) { // Don't do anything. if (point.isNull()) { return; } // Get the tab index at the RMB click point. int tabIndex = tabBar()->tabAt(point); // Create the menu. QMenu menu("Window Action", this); QAction* detachAction = menu.addAction(tr("Detach")); QAction* detachMinimizedAction = menu.addAction(tr("Detach Minimized")); QAction* reattachAction = menu.addAction(tr("Reattach")); // Enable/disable depending if it was already detached. QWidget* w = widget(tabIndex); if (w->objectName() == "QDetachTabWidgetPlaceholder") { detachAction->setEnabled(false); detachMinimizedAction->setEnabled(false); reattachAction->setEnabled(true); }else{ detachAction->setEnabled(true); detachMinimizedAction->setEnabled(true); reattachAction->setEnabled(false); } // Exec the menue QAction* action = menu.exec(QCursor::pos()); // // Handle detaching a tab. // if (action == detachAction) { // Detach the tab. detachTab(tabIndex, false); // Set the tabwidget to the placeholder tab. setCurrentIndex(tabIndex); } // // Handle detaching a tab. // if (action == detachMinimizedAction) { // Detach the tab. detachTab(tabIndex, true); // Set the tabwidget to the placeholder tab. setCurrentIndex(tabIndex); } // // Handle reattaching a tab. // if (action == reattachAction) { // Reattach the tab. reattachTab(tabIndex); // Set the tabwidget to the real tab. setCurrentIndex(tabIndex); } } // // The QDetachTabWidget listens for 'tabCloseRequests'. Only to // reattach the widget, if necessary. Normally, you derive from // QDetachTabWidget and add signal/connect to do the same. I'm // counting on mine happening first. // void QDetachTabWidget::handleTabClosedRequested (int tabIndex) { // Reattach the tab. reattachTab(tabIndex); // Set the tabwidget to the real tab. setCurrentIndex(tabIndex); } // // Look for the real widget in the tab cache. // QList::iterator QDetachTabWidget::findWidget (QWidget* widget) { QList::iterator it = _tabInfo.begin(); while (it != _tabInfo.end()) { if (it->_widget == widget) { return it; } it++; } return it; } // // Look for the 'placeholder' widget in the tab cache. // QList::iterator QDetachTabWidget::findPlaceholderWidget (QWidget* widget) { QList::iterator it = _tabInfo.begin(); while (it != _tabInfo.end()) { if (it->_placeholderWidget == widget) { return it; } it++; } return it; } // // A placeholder widget that has a 'reattach' pushbutton. // QDetachTabWidgetPlaceholder::QDetachTabWidgetPlaceholder(int tabIndex, QWidget* parent) : QWidget(parent) { // This the placeholder's object name. Users of this object can focus // on this name if they need too. setObjectName("QDetachTabWidgetPlaceholder"); // Create the 'Reattach' button and add a layout to it. _reattachPushButton = new QPushButton("Reattach", this); _reattachPushButton->setIcon(QIcon(":/qt-project.org/styles/commonstyle/images/right-16.png")); _tabIndex = tabIndex; QHBoxLayout* layout = new QHBoxLayout; layout->addStretch(); layout->addWidget(_reattachPushButton); layout->addStretch(); setLayout(layout); // We'll handle the 'click' signal. QObject::connect(_reattachPushButton, &QPushButton::clicked, this, &QDetachTabWidgetPlaceholder::handlePushButtonClicked); } // Handle the pushbutton 'click' by emitting the 'reattach' signal. void QDetachTabWidgetPlaceholder::handlePushButtonClicked () { emit reattach(_tabIndex); } epasveer-seer-97076f1/src/QDetachTabWidget.h000066400000000000000000000045501526321767600206340ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include struct QDetachTabInfo { QString _title; QWidget* _widget; QWidget* _placeholderWidget; QDetachTabInfo(QString title, QWidget* widget, QWidget* placeholderWidget) : _title(title), _widget(widget), _placeholderWidget(placeholderWidget) {} }; class QDetachTabWidget : public QTabWidget { Q_OBJECT public: QDetachTabWidget(QWidget* parent = 0); bool isDetached (int tabIndex) const; QWidget* tabWidget (int tabIndex) const; public slots: void detachTab (int tabIndex, bool minimized=false); void reattachTab (int tabIndex); signals: void tabDetached (int tabIndex); void tabDetached (QWidget* widget); void tabReattached (int tabIndex); void tabReattached (QWidget* widget); protected: void closeEvent (QCloseEvent* e); protected slots: void handleShowContextMenu (const QPoint& point); void handleTabClosedRequested (int tabIndex); private: QList::iterator findWidget (QWidget* widget); QList::iterator findPlaceholderWidget (QWidget* widget); QList _tabInfo; }; class QDetachTabWidgetPlaceholder : public QWidget { Q_OBJECT public: QDetachTabWidgetPlaceholder(int tabIndex, QWidget* parent = 0); signals: void reattach (int tabIndex); protected slots: void handlePushButtonClicked (); private: QPushButton* _reattachPushButton; int _tabIndex; }; epasveer-seer-97076f1/src/QEditDelegate.cpp000066400000000000000000000020031526321767600205130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QEditDelegate.h" // // QAllowEditDelegate enables a custom editor for a QTreeView column. // QAllowEditDelegate::QAllowEditDelegate(QObject* parent) : QStyledItemDelegate(parent) { } void QAllowEditDelegate::setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { emit editingStarted(index); QStyledItemDelegate::setModelData(editor, model, index); emit editingFinished(index); } // // QNoEditDelegate disables editing in a QTreeView for a column. // It does this by returning a 'null' editor when QTreeView calls QStyledItemDelegate::createEditor() for the cell. // QNoEditDelegate::QNoEditDelegate(QObject* parent) : QStyledItemDelegate(parent) { } QWidget* QNoEditDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { Q_UNUSED(parent); Q_UNUSED(option); Q_UNUSED(index); return 0; } epasveer-seer-97076f1/src/QEditDelegate.h000066400000000000000000000016401526321767600201660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include class QAllowEditDelegate : public QStyledItemDelegate { Q_OBJECT public: QAllowEditDelegate(QObject* parent = nullptr); virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; signals: void editingStarted (const QModelIndex& index) const; void editingFinished (const QModelIndex& index) const; }; class QNoEditDelegate : public QStyledItemDelegate { public: QNoEditDelegate(QObject* parent = nullptr); virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const; }; epasveer-seer-97076f1/src/QHContainerWidget.cpp000066400000000000000000000012151526321767600213750ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QHContainerWidget.h" QHContainerWidget::QHContainerWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets // Connect things. } QHContainerWidget::~QHContainerWidget () { } void QHContainerWidget::setSpacing (int spacing) { horizontalLayout->setSpacing(spacing); } void QHContainerWidget::addWidget (QWidget* widget) { horizontalLayout->addWidget(widget); } void QHContainerWidget::removeWidget (QWidget* widget) { horizontalLayout->removeWidget(widget); } epasveer-seer-97076f1/src/QHContainerWidget.h000066400000000000000000000011461526321767600210450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include "ui_QHContainerWidget.h" class QHContainerWidget : public QWidget, protected Ui::QHContainerWidgetForm { Q_OBJECT public: explicit QHContainerWidget (QWidget* parent = 0); ~QHContainerWidget (); void setSpacing (int spacing); void addWidget (QWidget* widget); void removeWidget (QWidget* widget); private: }; epasveer-seer-97076f1/src/QHContainerWidget.ui000066400000000000000000000015221526321767600212310ustar00rootroot00000000000000 QHContainerWidgetForm 0 0 580 145 QHContainerWidgetForm 0 0 0 0 epasveer-seer-97076f1/src/QHistoryLineEdit.cpp000066400000000000000000000216471526321767600212710ustar00rootroot00000000000000/** * \file * * \author Mattia Basaglia * * \copyright Copyright (C) 2012-2020 Mattia Basaglia * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #include "QHistoryLineEdit.h" #include #include #include #include #include #include #include QHistoryLineEdit::QHistoryLineEdit (const QString& contents, QWidget* parent) : QLineEdit(contents, parent), _currentLine(0), _completer(0), _completionMinchars(1), _completionMax(0) { enableReturnPressedOnClear(); QObject::connect(this, &QLineEdit::returnPressed, this, &QHistoryLineEdit::execute); } QHistoryLineEdit::QHistoryLineEdit (QWidget* parent) : QLineEdit(parent), _currentLine(0), _completer(0), _completionMinchars(1), _completionMax(0) { enableReturnPressedOnClear(); QObject::connect(this, &QLineEdit::returnPressed, this, &QHistoryLineEdit::execute); } /** * \brief Enable "return press" signal on Clear action. */ void QHistoryLineEdit::enableReturnPressedOnClear() { for (int i=0; i (children().at(i))); if (myClearAction) { //qDebug() << myClearAction->objectName(); // Look for only the QLineEdit clear action. // This name could change or be different. if (myClearAction->objectName() == "_q_qlineeditclearaction") { connect(myClearAction, &QAction::triggered, this, &QLineEdit::returnPressed, Qt::QueuedConnection); } } } } /** * \brief Number of available lines */ int QHistoryLineEdit::lineCount () const { return _lines.size(); } /** * \brief Overwrite the line history */ void QHistoryLineEdit::setHistory (const QStringList& history) { _lines = history; _currentLine = _lines.size(); } /** * \brief Stored history */ QStringList QHistoryLineEdit::history () const { return _lines; } /** * \brief Sets the completer used on a per-word completion * * Unlike setCompleter(), this suggests completion at every entered word * * If \c completer is null it will remove the current completer */ void QHistoryLineEdit::setWordCompleter (QCompleter* comp) { if ( _completer ) { QObject::disconnect(_completer, 0, this, 0); _completer->setWidget(0); } _completer = comp; if ( comp ) { /// \todo should set these only when on focus QObject::connect(_completer, QOverload::of(&QCompleter::activated), this, &QHistoryLineEdit::autoComplete); QObject::connect(_completer, QOverload::of(&QCompleter::highlighted), this, &QHistoryLineEdit::autoComplete); _completer->setWidget(this); } } /** * \brief Sets a prefix that is ignored by the word completer */ void QHistoryLineEdit::setWordCompleterPrefix (const QString& prefix) { _completionPrefix = prefix; } /** * \brief Sets the minimum number of characters required to display the word completer */ void QHistoryLineEdit::setWordCompleterMinChars (int minChars) { _completionMinchars = minChars; } /** * \brief Sets the maximum number of suggestions that the completer should show. * * If more than this many suggestions are found the completer isn't shown */ void QHistoryLineEdit::setWordCompleterMaxSuggestions (int max) { _completionMax = max; } /** * \brief Executes the current line */ void QHistoryLineEdit::execute () { // Ignore blank lines. if (text() == "") { return; } // Add the line if it doesn't equal the previous (that is store in the history). if ( _lines.empty() || _lines.back() != text() ) { _lines << text(); } // Set our current position in the history list. _currentLine = _lines.size(); // If it wants to, the calling widget should clear the text line. // clear(); // Emit the entered text. emit lineExecuted(_lines.back()); } void QHistoryLineEdit::keyPressEvent (QKeyEvent* ev) { if ( ev->key() == Qt::Key_Up ) { previousLine(); return; } else if ( ev->key() == Qt::Key_Down ) { nextLine(); return; } else if (_completer && _completer->popup() && _completer->popup()->isVisible()) { switch (ev->key()) { case Qt::Key_Enter: case Qt::Key_Return: case Qt::Key_F4: case Qt::Key_Select: _completer->popup()->hide(); return; } } if ( ev->key() == Qt::Key_Escape ) { emit escapePressed(); } QLineEdit::keyPressEvent(ev); if (_completer) { QString current = current_word(); _completer->setCompletionPrefix(current); if ( current.size() < _completionMinchars || _completer->completionCount() == 0 || (_completionMax > 0 && _completer->completionCount() > _completionMax) ) { _completer->popup()->hide(); } else { // Get the selection status int sel = selectionStart(); int sellength = selectedText().size(); // Get the current cursor position int c = cursorPosition(); // Get the start of the current word setCursorPosition(_wordStart()); // Get the cursor rectangle at the beginning of the current word QRect rect = cursorRect(); // Restore cursor position (clears the selection) setCursorPosition(c); // If we had a selection if ( sel != -1 ) { // If the selection started at the cursor, // it needs to start at the far end and go back // (otherwise it moves the cursor at the end) if ( sel == c ) setSelection(sel+sellength, -sellength); else setSelection(sel, sellength); } // Set the rectangle to the appropriate width rect.setWidth( _completer->popup()->sizeHintForColumn(0) + _completer->popup()->verticalScrollBar()->sizeHint().width()); // Display the _completer under the rectangle _completer->complete(rect); } } } void QHistoryLineEdit::wheelEvent (QWheelEvent* ev) { if ( ev->angleDelta().y() > 0 ) { previousLine(); }else{ nextLine(); } } void QHistoryLineEdit::focusOutEvent (QFocusEvent* ev) { QLineEdit::focusOutEvent(ev); emit lostFocus(); } void QHistoryLineEdit::focusInEvent (QFocusEvent* ev) { QLineEdit::focusInEvent(ev); emit gainedFocus(); } void QHistoryLineEdit::previousLine () { if ( _lines.empty() ) { return; } if ( !text().isEmpty() && ( _currentLine >= _lines.size() || text() != _lines[_currentLine] ) ) { _unfinished = text(); } if ( _currentLine > 0 ) { _currentLine--; } setText(_lines[_currentLine]); } void QHistoryLineEdit::nextLine () { if ( _lines.empty() ) { return; } _currentLine++; if ( _currentLine >= _lines.size() ) { setText(_unfinished); _unfinished = ""; _currentLine = _lines.size(); } else { setText(_lines[_currentLine]); } } /** * \brief Current word being edited (used to fire the completer) */ QString QHistoryLineEdit::current_word () const { int completion_index = _wordStart(); return text().mid(completion_index, cursorPosition() - completion_index); } /** * \brief Autocompletes the current word */ void QHistoryLineEdit::autoComplete (const QString& completion) { int completion_index = _wordStart(); setText(text().replace( completion_index, cursorPosition() - completion_index, completion)); setCursorPosition(completion_index+completion.size()); } /** * \brief Returns the index of the character starting the currently edited word */ int QHistoryLineEdit::_wordStart () const { // lastIndexOf returns the index of the last space or -1 if there are no spaces // so that + 1 returns the index of the character starting the word or 0 int after_space = text().left(cursorPosition()).lastIndexOf(' ') + 1; if ( text().right(text().size()-after_space).startsWith(_completionPrefix) ) { after_space += _completionPrefix.size(); } return after_space; } epasveer-seer-97076f1/src/QHistoryLineEdit.h000066400000000000000000000060761526321767600207350ustar00rootroot00000000000000/** * \file * * \author Mattia Basaglia * * \copyright Copyright (C) 2012-2020 Mattia Basaglia * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #pragma once #include /** * \brief Line edit providing a history of entered text */ class QHistoryLineEdit : public QLineEdit { Q_OBJECT public: QHistoryLineEdit(const QString& contents, QWidget* parent = 0); QHistoryLineEdit(QWidget* parent = 0); void enableReturnPressedOnClear (); int lineCount () const; void setHistory (const QStringList& history); QStringList history () const; void setWordCompleter (QCompleter* completer); void setWordCompleterPrefix (const QString& prefix); void setWordCompleterMinChars (int minChars); void setWordCompleterMaxSuggestions (int max); public slots: void execute (); signals: void lineExecuted (QString text); void lostFocus (); void gainedFocus (); void escapePressed (); protected: void keyPressEvent (QKeyEvent* event) Q_DECL_OVERRIDE; void wheelEvent (QWheelEvent* event) Q_DECL_OVERRIDE; void focusOutEvent (QFocusEvent* event) Q_DECL_OVERRIDE; void focusInEvent (QFocusEvent* event) Q_DECL_OVERRIDE; void previousLine (); void nextLine (); QString current_word () const; private slots: void autoComplete (const QString& completion); private: int _wordStart () const; int _currentLine; QStringList _lines; QString _unfinished; QCompleter* _completer; QString _completionPrefix; int _completionMinchars; int _completionMax; }; epasveer-seer-97076f1/src/QImageViewer.cpp000066400000000000000000000115061526321767600204070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QImageViewer.h" #include #include #include #include #include #include #include #include #include // // https://doc.qt.io/qt-5/qtwidgets-widgets-imageviewer-example.html // https://stackoverflow.com/questions/53193010/how-to-resize-a-qlabel-with-pixmap-inside-a-qscrollarea // QImageViewer::QImageViewer (QWidget* parent) : QWidget(parent) { setFocusPolicy(Qt::StrongFocus); // So the widget can take focus and receive the +/-/ESC zoom keys. _zoomFactor = 1.0; // Setup the widgets QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); _imageLabel = new QLabel(); _imageLabel->setBackgroundRole(QPalette::Base); _imageLabel->setScaledContents(true); _scrollArea = new QScrollArea(this); _scrollArea->setBackgroundRole(QPalette::Dark); _scrollArea->setWidget(_imageLabel); _scrollArea->setWidgetResizable(false); // The scroll area consumes wheel events for scrolling, so watch its // viewport to catch Ctrl+wheel for zooming. _scrollArea->viewport()->installEventFilter(this); layout->addWidget(_scrollArea); clearImage(); } QImageViewer::~QImageViewer () { } bool QImageViewer::loadFile (const QString& file) { QImageReader reader(file); reader.setAutoTransform(true); QImage image = reader.read(); if (image.isNull()) { return false; } setImage(image); return true; } bool QImageViewer::saveFile (const QString& file) { if (file.isEmpty() == true) { return false; } QImageWriter writer(file); bool f = writer.write(_image); if (f == false) { qDebug() << writer.errorString(); } return f; } bool QImageViewer::saveFileDialog (const QString& file) { QString fileName = QFileDialog::getSaveFileName(this, tr("Save Image File"), file, tr("Image Files (*.png *.jpg *.bmp)"), nullptr, QFileDialog::DontUseNativeDialog); return saveFile(fileName); } void QImageViewer::setImage (const QImage& image) { //qDebug() << image; _image = image.copy(); _zoomFactor = 1.0; _imageLabel->setPixmap(QPixmap::fromImage(_image)); zoomReset(); } const QImage& QImageViewer::image () const { return _image; } void QImageViewer::clearImage () { _image = QImage(); _imageLabel->setPixmap(QPixmap()); } void QImageViewer::setText (const QString& text) { _imageLabel->setText(text); } double QImageViewer::zoomFactor () const { return _zoomFactor; } void QImageViewer::zoom (double factor) { _zoomFactor = factor; _imageLabel->resize(_zoomFactor * _imageLabel->pixmap(Qt::ReturnByValue).size()); } void QImageViewer::zoomIn () { zoom(zoomFactor() * 1.25); } void QImageViewer::zoomOut () { zoom(zoomFactor() * 0.8); } void QImageViewer::zoomReset () { zoom(1.0); } void QImageViewer::print () { QPrintDialog dialog(&_printer, this); if (dialog.exec()) { QPainter painter(&_printer); QRect rect = painter.viewport(); QSize size = _imageLabel->pixmap(Qt::ReturnByValue).size(); size.scale(rect.size(), Qt::KeepAspectRatio); painter.setViewport(rect.x(), rect.y(), size.width(), size.height()); painter.setWindow(_imageLabel->pixmap(Qt::ReturnByValue).rect()); painter.drawPixmap(0, 0, _imageLabel->pixmap(Qt::ReturnByValue)); } } void QImageViewer::keyPressEvent (QKeyEvent* event) { //qDebug() << "Key =" << event->key(); switch (event->key()) { case Qt::Key_Escape: zoomReset(); break; case Qt::Key_Plus: zoomIn(); break; case Qt::Key_Minus: zoomOut(); break; default: QWidget::keyPressEvent(event); break; } } bool QImageViewer::eventFilter (QObject* object, QEvent* event) { // Ctrl+wheel over the image zooms in or out. A plain wheel keeps // scrolling the image as usual. if (object == _scrollArea->viewport() && event->type() == QEvent::Wheel) { QWheelEvent* wheelEvent = static_cast(event); if (wheelEvent->modifiers() & Qt::ControlModifier) { if (wheelEvent->angleDelta().y() > 0) { zoomIn(); }else if (wheelEvent->angleDelta().y() < 0) { zoomOut(); } return true; } } return QWidget::eventFilter(object, event); } void QImageViewer::enterEvent (QEnterEvent* event) { Q_UNUSED(event); setFocus(); } void QImageViewer::leaveEvent (QEvent* event) { Q_UNUSED(event); } epasveer-seer-97076f1/src/QImageViewer.h000066400000000000000000000036501526321767600200550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include #include class QImageViewer : public QWidget { Q_OBJECT public: explicit QImageViewer (QWidget* parent = 0); ~QImageViewer (); bool loadFile (const QString& file); bool saveFile (const QString& file); bool saveFileDialog (const QString& file); void setImage (const QImage& image); const QImage& image () const; void clearImage (); void setText (const QString& text); double zoomFactor () const; public slots: void zoom (double factor); void zoomIn (); void zoomOut (); void zoomReset (); void print (); protected slots: void keyPressEvent (QKeyEvent* event); bool eventFilter (QObject* object, QEvent* event) override; void enterEvent (QEnterEvent* event) override; void leaveEvent (QEvent* event) override; private: QImage _image; QScrollArea* _scrollArea; QLabel* _imageLabel; double _zoomFactor; QPrinter _printer; }; epasveer-seer-97076f1/src/QIndexTreeWidget.cpp000066400000000000000000000005741526321767600212410ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QIndexTreeWidget.h" QIndexTreeWidget::QIndexTreeWidget (QWidget* parent) : QTreeWidget(parent) { } QIndexTreeWidget::~QIndexTreeWidget () { } QTreeWidgetItem* QIndexTreeWidget::getItemFromIndex (const QModelIndex& index) const { return itemFromIndex(index); } epasveer-seer-97076f1/src/QIndexTreeWidget.h000066400000000000000000000007461526321767600207070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include class QIndexTreeWidget : public QTreeWidget { public: QIndexTreeWidget(QWidget* parent = nullptr); ~QIndexTreeWidget(); QTreeWidgetItem* getItemFromIndex (const QModelIndex& index) const; }; epasveer-seer-97076f1/src/QProcessInfo.cpp000066400000000000000000000110241526321767600204300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 Baldur Karlsson // SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QProcessInfo.h" #include #include #include #include #include #include #include #include #include #include #include QProcessInfo QProcessInfo::populate(uint32_t pid) { QProcessInfo info; info.setPid(pid); QDir processDir(QStringLiteral("/proc/") + QString::number(pid)); // default to the exe symlink if valid QFileInfo exe(processDir.absoluteFilePath(QStringLiteral("exe"))); exe = QFileInfo(exe.symLinkTarget()); info.setName(exe.completeBaseName()); info.setPath(exe.absolutePath()); // if we didn't get a name from the symlink, check in the status file if (info.name().isEmpty()) { QFile status(processDir.absoluteFilePath(QStringLiteral("status"))); if (status.open(QIODevice::ReadOnly)) { QByteArray contents = status.readAll(); QTextStream in(&contents); while(!in.atEnd()) { QString line = in.readLine(); if (line.startsWith(QStringLiteral("Name:"))) { line.remove(0, 5); // if we're using this name, surround with []s to indicate it's not a file info.setName(QStringLiteral("[%1]").arg(line.trimmed())); info.setPath(""); break; } } status.close(); } } // Get the username. QFile status(processDir.absoluteFilePath(QStringLiteral("status"))); if (status.open(QIODevice::ReadOnly)) { QByteArray contents = status.readAll(); QTextStream in(&contents); while(!in.atEnd()) { QString line = in.readLine(); if (line.startsWith(QStringLiteral("Uid:"))) { info.setUsername(line.split(QRegularExpression("\\s+")).at(1)); break; } } status.close(); struct passwd* pw = getpwuid(info.username().toULong()); if (pw) { info.setUsername(pw->pw_name); } } // Get the command line QFile cmdline(processDir.absoluteFilePath(QStringLiteral("cmdline"))); if (cmdline.open(QIODevice::ReadOnly)) { QByteArray contents = cmdline.readAll(); int nullIdx = contents.indexOf('\0'); if (nullIdx > 0) { QString firstparam = QString::fromUtf8(contents.data(), nullIdx); // if name is a truncated form of a filename, replace it if (firstparam.endsWith(info.name()) && QFileInfo::exists(firstparam)) { info.setName(QFileInfo(firstparam).completeBaseName()); info.setPath(QFileInfo(firstparam).absolutePath()); } // if we don't have a name, replace it but with []s if (info.name().isEmpty()) { info.setName(QStringLiteral("[%1]").arg(firstparam)); info.setPath(""); } contents.replace('\0', ' '); } info.setCommandLine(QString::fromUtf8(contents).trimmed()); cmdline.close(); } return info; } QProcessList QProcessInfo::populate() { QProcessList ret; QDir proc(QStringLiteral("/proc")); QStringList files = proc.entryList(); for (const QString& f : files) { bool ok = false; uint32_t pid = f.toUInt(&ok); if (ok) { // Get process info for pid. QProcessInfo info = QProcessInfo::populate(pid); // Add the process to the list. ret.push_back(info); } } return ret; } QProcessInfo::QProcessInfo() { _pid = 0; } uint32_t QProcessInfo::pid() const { return _pid; } void QProcessInfo::setPid(uint32_t pid) { _pid = pid; } const QString& QProcessInfo::username() const { return _username; } void QProcessInfo::setUsername(const QString& username) { _username = username; } const QString& QProcessInfo::name() const { return _name; } void QProcessInfo::setName(const QString& name) { _name = name; } const QString& QProcessInfo::path() const { return _path; } void QProcessInfo::setPath(const QString& path) { _path = path; } const QString& QProcessInfo::commandLine() const { return _cmdLine; } void QProcessInfo::setCommandLine(const QString& cmd) { _cmdLine = cmd; } epasveer-seer-97076f1/src/QProcessInfo.h000066400000000000000000000022721526321767600201020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include class QProcessInfo; typedef QList QProcessList; class QProcessInfo { public: QProcessInfo(); static QProcessList populate(); static QProcessInfo populate(uint32_t pid); uint32_t pid () const; void setPid (uint32_t pid); const QString& username () const; void setUsername (const QString& username); const QString& name () const; void setName (const QString& name); const QString& path () const; void setPath (const QString& path); const QString& commandLine () const; void setCommandLine (const QString& cmd); private: uint32_t _pid; QString _username; QString _name; QString _path; QString _cmdLine; }; epasveer-seer-97076f1/src/QProcessInfoWidget.cpp000066400000000000000000000165631526321767600216110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QProcessInfoWidget.h" #include "QProcessInfo.h" #include #include #include #include #include #include // // Custom tree item with numeric ordering on column 0. // class QProcessInfoWidgetItem : public QTreeWidgetItem { public: QProcessInfoWidgetItem(QTreeWidget* parent = 0) : QTreeWidgetItem(parent) { } private: bool operator< (const QTreeWidgetItem& other) const { int column = treeWidget()->sortColumn(); if (column == 0) { return text(column).toLong() < other.text(column).toLong(); } return text(column) < other.text(column); } }; // // The main widget starts here. // QProcessInfoWidget::QProcessInfoWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets processTreeWidget->setMouseTracking(true); processTreeWidget->resizeColumnToContents(0); // PID processTreeWidget->resizeColumnToContents(1); // User name processTreeWidget->resizeColumnToContents(2); // Path name processTreeWidget->resizeColumnToContents(3); // Program name //processTreeWidget->resizeColumnToContents(4); // Command line processTreeWidget->setSortingEnabled(true); processTreeWidget->clear(); systemProcessesCheckBox->setChecked(false); // Connect things. QObject::connect(programNameLineEdit, &QLineEdit::textChanged, this, &QProcessInfoWidget::refreshView); QObject::connect(userNameLineEdit, &QLineEdit::textChanged, this, &QProcessInfoWidget::refreshView); QObject::connect(systemProcessesCheckBox, &QCheckBox::clicked, this, &QProcessInfoWidget::refreshView); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &QProcessInfoWidget::refreshList); QObject::connect(processTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QProcessInfoWidget::handleDoubleClicked); // Give focus to the program line edit. programNameLineEdit->setFocus(Qt::OtherFocusReason); // Load the initial process list. refreshList(); } QProcessInfoWidget::~QProcessInfoWidget () { } int QProcessInfoWidget::selectedPid () const { QList items = processTreeWidget->selectedItems(); if (items.size() == 0) { return -1; } return items[0]->text(0).toLong(); } QString QProcessInfoWidget::selectedUsername () const { QList items = processTreeWidget->selectedItems(); if (items.size() == 0) { return ""; } return items[0]->text(1); } QString QProcessInfoWidget::selectedName () const { QList items = processTreeWidget->selectedItems(); if (items.size() == 0) { return ""; } return items[0]->text(3); } QString QProcessInfoWidget::selectedFullname () const { QList items = processTreeWidget->selectedItems(); if (items.size() == 0) { return ""; } return items[0]->text(2) + "/" + items[0]->text(3); } QString QProcessInfoWidget::selectedCommandLine () const { QList items = processTreeWidget->selectedItems(); if (items.size() == 0) { return ""; } return items[0]->text(4); } void QProcessInfoWidget::refreshList () { QApplication::setOverrideCursor(Qt::BusyCursor); // Scan the /proc file system. QProcessList list = QProcessInfo::populate(); // Loop through each entry and add it to our view. processTreeWidget->clear(); for (const QProcessInfo& info : list) { QTreeWidgetItem* item = new QProcessInfoWidgetItem; item->setText(0, QString::number(info.pid())); item->setText(1, info.username()); item->setText(2, info.path()); item->setText(3, info.name()); item->setText(4, info.commandLine()); processTreeWidget->addTopLevelItem(item); } // Adjust the column widths. processTreeWidget->clearSelection(); processTreeWidget->resizeColumnToContents(0); processTreeWidget->resizeColumnToContents(1); processTreeWidget->resizeColumnToContents(2); processTreeWidget->resizeColumnToContents(3); //processTreeWidget->resizeColumnToContents(4); // Don't clear the line edits. // programNameLineEdit->clear(); // userNameLineEdit->clear(); refreshView(); QApplication::restoreOverrideCursor(); } void QProcessInfoWidget::refreshView () { // Get this list of program name matches. Or all if there is no program name provided. QList programNameMatches; if (programNameLineEdit->text() == "") { programNameMatches = processTreeWidget->findItems("*", Qt::MatchWildcard | Qt::MatchRecursive, 3); }else{ if (programNameLineEdit->text().contains('*')) { programNameMatches = processTreeWidget->findItems(programNameLineEdit->text(), Qt::MatchWildcard | Qt::MatchRecursive, 3); }else{ programNameMatches = processTreeWidget->findItems(programNameLineEdit->text(), Qt::MatchStartsWith | Qt::MatchRecursive, 3); } } // Get this list of user name matches. Or all if there is no user name provided. QList userNameMatches; if (userNameLineEdit->text() == "") { userNameMatches = processTreeWidget->findItems("*", Qt::MatchWildcard | Qt::MatchRecursive, 1); }else{ if (userNameLineEdit->text().contains('*')) { userNameMatches = processTreeWidget->findItems(userNameLineEdit->text(), Qt::MatchWildcard | Qt::MatchRecursive, 1); }else{ userNameMatches = processTreeWidget->findItems(userNameLineEdit->text(), Qt::MatchStartsWith | Qt::MatchRecursive, 1); } } // Get this list of process matches. Include one's with [xxx]) or not. QList processMatches; if (systemProcessesCheckBox->isChecked() == true) { processMatches = processTreeWidget->findItems("*", Qt::MatchWildcard | Qt::MatchRecursive, 3); //qDebug() << "Checkbox is on." << processMatches.size(); }else{ // To find [xxx] processes : "^(\\[).*(\\])$" // To exclude [xxx] processes: "^(?!\\[).*(?!\\])$" processMatches = processTreeWidget->findItems("^(?!\\[).*(?!\\])$", Qt::MatchRegularExpression | Qt::MatchRecursive, 3); //qDebug() << "Checkbox is off." << processMatches.size(); } // Go through each item in the tree. If it's in the user, program, and process matches, show it. // Otherwise, hide it. QTreeWidgetItemIterator it(processTreeWidget); while (*it) { if (programNameMatches.contains(*it) && userNameMatches.contains(*it) && processMatches.contains(*it)) { (*it)->setHidden(false); }else{ (*it)->setHidden(true); } ++it; } // Resize the columns. processTreeWidget->resizeColumnToContents(0); processTreeWidget->resizeColumnToContents(1); processTreeWidget->resizeColumnToContents(2); processTreeWidget->resizeColumnToContents(3); //processTreeWidget->resizeColumnToContents(4); } void QProcessInfoWidget::handleDoubleClicked () { emit pidSelected(selectedPid()); } epasveer-seer-97076f1/src/QProcessInfoWidget.h000066400000000000000000000021171526321767600212440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include "ui_QProcessInfoWidget.h" class QProcessInfoWidget : public QWidget, protected Ui::QProcessInfoWidget { Q_OBJECT public: explicit QProcessInfoWidget (QWidget* parent = 0); ~QProcessInfoWidget (); int selectedPid () const; QString selectedUsername () const; QString selectedName () const; QString selectedFullname () const; QString selectedCommandLine () const; signals: void pidSelected (int pid); public slots: protected slots: void refreshList (); void refreshView (); void handleDoubleClicked (); protected: private: }; epasveer-seer-97076f1/src/QProcessInfoWidget.ui000066400000000000000000000065201526321767600214340ustar00rootroot00000000000000 QProcessInfoWidget 0 0 770 488 System Process Browser Show system processes or hide them. System Processes false Refresh the list of processes. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg true 5 PID User Name Program Path Program Name Command Line Search program name in the list of processes. "*" is allowed. Search Program Name... true Search user name in the list of processes. "*" is allowed. Search User Name... true programNameLineEdit userNameLineEdit systemProcessesCheckBox refreshToolButton processTreeWidget epasveer-seer-97076f1/src/QProgressIndicator.cpp000066400000000000000000000172321526321767600216460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QProgressIndicator.h" #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include #define SPIN_INTERVAL 100 // Set timer to wake up every 100ms. QProgressIndicator::QProgressIndicator(QWidget* parent) : QWidget(parent) { _type = QProgressIndicator::line_rotate; _interval = SPIN_INTERVAL; _angle = 0; _scale = 0.0f; _color = Qt::black; setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setFocusPolicy(Qt::NoFocus); _timer = new QTimer(); QObject::connect(_timer, &QTimer::timeout, this, &QProgressIndicator::onTimeout); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &QProgressIndicator::handleThemeChanged); #endif update(); } QProgressIndicator::~QProgressIndicator() { stop(); delete _timer; } void QProgressIndicator::paintEvent(QPaintEvent* e) { Q_UNUSED(e) if (!_timer->isActive()) { _angle = 0; _scale = 0.0f; return; // Draw nothing when stopped. stop() expects the indicator to be erased from the view. } QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); switch (_type) { case QProgressIndicator::line_rotate: drawRotateLine(&painter); break; case QProgressIndicator::line_scale: drawScaleLine((&painter)); break; case QProgressIndicator::ball_rotate: drawRotateBall(&painter); break; case QProgressIndicator::circle_rotate: drawRotateCircle(&painter); break; } } void QProgressIndicator::start() { _timer->start(_interval); } void QProgressIndicator::stop() { _timer->stop(); update(); // Force an update to erase the indicator from the view. } int QProgressIndicator::type () const { return _type; } QString QProgressIndicator::typeName () const { if (_type == line_rotate) { return "LineRotate"; }else if (_type == line_scale) { return "LineScale"; }else if (_type == ball_rotate) { return "BallRotate"; }else if (_type == circle_rotate) { return "CircleRotate"; } return "BallRotate"; } void QProgressIndicator::setType (int type) { _type = type; } void QProgressIndicator::setType (const QString& type) { if (type == "LineRotate") { setType(line_rotate); }else if (type == "LineScale") { setType(line_scale); }else if (type == "BallRotate") { setType(ball_rotate); }else if (type == "CircleRotate") { setType(circle_rotate); }else{ setType(line_rotate); } update(); } QStringList QProgressIndicator::types () const { QStringList list = {"LineRotate", "LineScale", "BallRotate", "CircleRotate"}; return list; } const QColor& QProgressIndicator::color () { return _color; } void QProgressIndicator::setColor (const QColor& color) { _color = color; } int QProgressIndicator::interval () { return _interval; } void QProgressIndicator::setInterval (int interval) { _interval = interval; } void QProgressIndicator::handleThemeChanged () { #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) // Get the current color scheme Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); if (colorScheme == Qt::ColorScheme::Light) { setColor(QColor("black")); }else if (colorScheme == Qt::ColorScheme::Dark) { setColor(QColor("white")); }else{ setColor(QColor("black")); qDebug() << "Bad colorScheme of: " << colorScheme; } #else setColor(QColor("black")); #endif } void QProgressIndicator::onTimeout() { switch (_type) { case line_rotate: case ball_rotate: _angle = (_angle + 45) % 360; break; case circle_rotate: _angle = (_angle + 45) % 360; break; case line_scale: _scale += 0.1f; _scale = _scale > .5f ? 0.0f : _scale; break; } update(); } void QProgressIndicator::drawRotateLine(QPainter* painter) { int width = qMin(this->width(), this->height()); int outerRadius = (width - 4) * 0.5f; int innerRadius = outerRadius * 0.42f; int capsuleHeight = outerRadius - innerRadius; int capsuleWidth = (width > 32 ) ? capsuleHeight * .32f : capsuleHeight * .40f; int capsuleRadius = capsuleWidth / 2; for (int i = 0; i < 8; i++) { QColor color = _color; color.setAlphaF(1.0f - (i / 8.0f)); painter->setPen(Qt::NoPen); painter->setBrush(color); painter->save(); painter->translate(rect().center()); painter->rotate(_angle - i * 45.0f); painter->drawRoundedRect(-capsuleWidth * 0.5, -(innerRadius + capsuleHeight), capsuleWidth, capsuleHeight, capsuleRadius, capsuleRadius); painter->restore(); } } void QProgressIndicator::drawScaleLine(QPainter* painter) { int height = qMin(this->width(), this->height()); qreal lineWidth = height * 0.15f; qreal lineHeight = height * 0.9f; qreal lineRadius = lineWidth / 2.0f; qreal lineGap = lineWidth; qreal margin = (this->width() - lineWidth * 5 - lineGap * 4) / 2.0f; for (int i = 0; i < 5; i++) { painter->setPen(Qt::NoPen); painter->setBrush(_color); int tmp = _scale * 10 + i + 1; if (tmp > 5) { tmp = 5 - tmp % 5; } qreal scale = 0.5f + tmp * 0.1f; qreal h = lineHeight * scale; painter->save(); painter->translate(QPointF(margin + (lineWidth + lineGap) * i, this->height() / 2)); painter->drawRoundedRect(0, -h / 2.0f, lineWidth, h, lineRadius, lineRadius); painter->restore(); } } void QProgressIndicator::drawRotateBall(QPainter* painter) { int width = qMin(this->width(), this->height()); int outerRadius = (width - 4) * 0.5f; int innerRadius = outerRadius * 0.78f; int capsuleRadius = (outerRadius - innerRadius) / 2; for (int i = 0; i < 8; i++) { QColor color = _color; color.setAlphaF(1.0f - (i / 8.0f)); painter->setPen(Qt::NoPen); painter->setBrush(color); qreal radius = capsuleRadius * (1.0f - (i / 16.0f)); painter->save(); painter->translate(rect().center()); painter->rotate(_angle - i * 45.0f); QPointF centre = QPointF(-capsuleRadius, -(innerRadius + capsuleRadius)); painter->drawEllipse(centre, radius * 2, radius * 2); painter->restore(); } } void QProgressIndicator::drawRotateCircle(QPainter* painter) { // My version is based on ProgressInfiniteBar from : https://github.com/przemek83/wble int width = qMin(this->width(), this->height()); int offset = qAbs(this->width() - this->height()) / 2; int penwidth = 3; QRectF r = QRect(offset+penwidth,0+penwidth, width-(2*penwidth),width-(2*penwidth)); QPen pen(_color); pen.setWidth(penwidth); pen.setCapStyle(Qt::RoundCap); painter->setPen(pen); painter->setBrush(_color); int startAngle = 0.0; int spanAngle = 45 * 16; startAngle = (0.0 + _angle) * 16; painter->drawArc(r, -startAngle, -spanAngle); startAngle = (120.0 + _angle) * 16; painter->drawArc(r, -startAngle, -spanAngle); startAngle = (240.0 + _angle) * 16; painter->drawArc(r, -startAngle, -spanAngle); } epasveer-seer-97076f1/src/QProgressIndicator.h000066400000000000000000000040121526321767600213030ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include class QProgressIndicator : public QWidget { Q_OBJECT Q_PROPERTY(int _type READ type WRITE setType) Q_PROPERTY(QColor _color READ color WRITE setColor) Q_PROPERTY(int _interval READ interval WRITE setInterval) public: QProgressIndicator(QWidget* parent = 0); ~QProgressIndicator(); enum { line_rotate, line_scale, ball_rotate, circle_rotate }; void paintEvent (QPaintEvent* e); void start (); void stop (); int type () const; QString typeName () const; void setType (int type); void setType (const QString& type); QStringList types () const; const QColor& color (); void setColor (const QColor &color); int interval (); void setInterval (int interval); private slots: void handleThemeChanged (); void onTimeout (); private: void drawRotateLine (QPainter* painter); void drawScaleLine (QPainter* painter); void drawRotateBall (QPainter* painter); void drawRotateCircle (QPainter* painter); private: int _type; int _interval; QColor _color; int _angle; qreal _scale; QTimer* _timer; }; epasveer-seer-97076f1/src/QStringPair.h000066400000000000000000000003231526321767600177250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include typedef QPair QStringPair; epasveer-seer-97076f1/src/QZoomChart.cpp000066400000000000000000000025211526321767600201060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QZoomChart.h" #include #include #include #include QZoomChart::QZoomChart(QGraphicsItem* parent, Qt::WindowFlags wFlags) : QChart(QChart::ChartTypeCartesian, parent, wFlags) { // Seems that QGraphicsView (QChartView) does not grab gestures. // They can only be grabbed here in the QGraphicsWidget (QChart). grabGesture(Qt::PanGesture); grabGesture(Qt::PinchGesture); } QZoomChart::~QZoomChart() { } bool QZoomChart::sceneEvent(QEvent* event) { if (event->type() == QEvent::Gesture) { return gestureEvent(static_cast(event)); } return QChart::event(event); } bool QZoomChart::gestureEvent(QGestureEvent* event) { if (QGesture* gesture = event->gesture(Qt::PanGesture)) { QPanGesture* pan = static_cast(gesture); QChart::scroll(-(pan->delta().x()), pan->delta().y()); } if (QGesture* gesture = event->gesture(Qt::PinchGesture)) { QPinchGesture* pinch = static_cast(gesture); if (pinch->changeFlags() & QPinchGesture::ScaleFactorChanged) { QChart::zoom(pinch->scaleFactor()); } } return true; } epasveer-seer-97076f1/src/QZoomChart.h000066400000000000000000000010331526321767600175500ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #if QT_VERSION < 0x060000 using namespace QtCharts; #endif class QGestureEvent; class QZoomChart : public QChart { public: QZoomChart(QGraphicsItem* parent = nullptr, Qt::WindowFlags wFlags = {}); ~QZoomChart(); protected: bool sceneEvent (QEvent* event); private: bool gestureEvent (QGestureEvent* event); private: }; epasveer-seer-97076f1/src/QZoomChartView.cpp000066400000000000000000000105711526321767600207450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #include "QZoomChartView.h" #include #include #include #include #include #include QZoomChartView::QZoomChartView (QWidget* parent) : QChartView(parent) { _isDragging = false; setRubberBand(QChartView::RectangleRubberBand); } QZoomChartView::QZoomChartView (QChart* chart, QWidget* parent) : QChartView(chart, parent) { _isDragging = false; setRubberBand(QChartView::RectangleRubberBand); } void QZoomChartView::printView () { QPrinter printer; if (QPrintDialog(&printer).exec() == QDialog::Accepted) { QPainter painter(&printer); painter.setRenderHint(QPainter::Antialiasing); render(&painter); } } bool QZoomChartView::viewportEvent (QEvent* event) { // Disable ToolTip events in the ChartView. They interfer with the 'length' arguments // of the QToolTip::showText() function. // https://bugreports.qt.io/browse/QTBUG-56427 switch (event->type()) { case QEvent::ToolTip: return false; default: break; } return QChartView::viewportEvent(event); } void QZoomChartView::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { _keyboardModifiers = QGuiApplication::keyboardModifiers(); if (_keyboardModifiers == Qt::ShiftModifier) { QApplication::setOverrideCursor(QCursor(Qt::SizeAllCursor)); setRubberBand(QChartView::NoRubberBand); _lastMousePos = event->pos(); _isDragging = true; event->accept(); }else{ setRubberBand(QChartView::RectangleRubberBand); } } QChartView::mousePressEvent(event); } void QZoomChartView::mouseMoveEvent (QMouseEvent* event) { // pan the chart with a left mouse drag if (event->buttons() & Qt::LeftButton) { if (_keyboardModifiers == Qt::ShiftModifier) { auto dPos = event->pos() - _lastMousePos; chart()->scroll(-dPos.x(), dPos.y()); chart()->update(); _lastMousePos = event->pos(); event->accept(); } } QChartView::mouseMoveEvent(event); } void QZoomChartView::mouseReleaseEvent (QMouseEvent* event) { if (_isDragging) { QApplication::restoreOverrideCursor(); _isDragging = false; } QChartView::mouseReleaseEvent(event); } void QZoomChartView::wheelEvent (QWheelEvent* event) { // https://stackoverflow.com/questions/48623595/scale-x-axis-of-qchartview-using-mouse-wheel qreal factor = event->angleDelta().y() > 0 ? 0.5 : 2.0; chart()->zoom(factor); chart()->update(); event->accept(); QChartView::wheelEvent(event); } void QZoomChartView::keyPressEvent (QKeyEvent* event) { switch (event->key()) { case Qt::Key_Plus: chart()->zoomIn(); chart()->update(); break; case Qt::Key_Minus: chart()->zoomOut(); chart()->update(); break; case Qt::Key_Escape: chart()->zoomReset(); chart()->zoom(.9); chart()->update(); break; case Qt::Key_Left: chart()->scroll(-10, 0); chart()->update(); break; case Qt::Key_Right: chart()->scroll(10, 0); chart()->update(); break; case Qt::Key_Up: chart()->scroll(0, 10); chart()->update(); break; case Qt::Key_Down: chart()->scroll(0, -10); chart()->update(); break; case Qt::Key_R: { if (event->modifiers() == Qt::ControlModifier) { chart()->update(); } } break; case Qt::Key_P: { if (event->modifiers() == Qt::ControlModifier) { printView(); } } break; default: QGraphicsView::keyPressEvent(event); break; } } void QZoomChartView::enterEvent (QEvent* event) { Q_UNUSED(event); setFocus(); } void QZoomChartView::leaveEvent (QEvent* event) { Q_UNUSED(event); } epasveer-seer-97076f1/src/QZoomChartView.h000066400000000000000000000025261526321767600204130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #if QT_VERSION < 0x060000 using namespace QtCharts; #endif class QZoomChartView : public QChartView { public: QZoomChartView (QWidget* parent = 0); QZoomChartView (QChart* chart, QWidget* parent = 0); public slots: void printView (); protected: bool viewportEvent (QEvent* event); void mousePressEvent (QMouseEvent* event); void mouseMoveEvent (QMouseEvent* event); void mouseReleaseEvent (QMouseEvent* event); void wheelEvent (QWheelEvent* event); void keyPressEvent (QKeyEvent* event); void enterEvent (QEvent* event); void leaveEvent (QEvent* event); private: bool _isDragging; QPointF _lastMousePos; Qt::KeyboardModifiers _keyboardModifiers; }; epasveer-seer-97076f1/src/SeerAboutDialog.cpp000066400000000000000000000032531526321767600210730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAboutDialog.h" #include "SeerUtl.h" #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include SeerAboutDialog::SeerAboutDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Handle when theme is changed. Change the color of all icons. #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerAboutDialog::handleThemeChanged); #endif // Get the About text from the resource. QFile file(":/seer/resources/ABOUT.md"); bool f = file.open(QFile::ReadOnly | QFile::Text); if (f == false) { return; } QTextStream stream(&file); QString text = stream.readAll(); // Substitute the text holder with the version number. text.replace("VERSIONNUMBER", Seer::version()); // Put the About text in as markdown. Move back to the begining. textBrowser->setMarkdown(text); textBrowser->moveCursor (QTextCursor::Start); // Set the label's icon. handleThemeChanged(); } SeerAboutDialog::~SeerAboutDialog () { } void SeerAboutDialog::handleThemeChanged () { // Get the colorized icon. QIcon icon = Seer::colorizeIcon(QIcon(":/seer/resources/icons/hicolor/256x256/seergdb.png"), Seer::iconColorTheme(), QSize(256,256)); // Set the label's pixmap label->setPixmap(icon.pixmap(QSize(256,256))); } epasveer-seer-97076f1/src/SeerAboutDialog.h000066400000000000000000000007701526321767600205410ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerAboutDialog.h" class SeerAboutDialog : public QDialog, protected Ui::SeerAboutDialogForm { Q_OBJECT public: explicit SeerAboutDialog (QWidget* parent = 0); ~SeerAboutDialog (); public slots: private slots: void handleThemeChanged (); private: }; epasveer-seer-97076f1/src/SeerAboutDialog.ui000066400000000000000000000072061526321767600207300ustar00rootroot00000000000000 SeerAboutDialogForm 0 0 563 556 About Seer false :/seer/resources/icons/hicolor/256x256/seergdb.png false Qt::AlignCenter QFrame::NoFrame QFrame::Plain Qt::ScrollBarAsNeeded QTextEdit::WidgetWidth true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style="-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> true Qt::Horizontal QDialogButtonBox::Ok buttonBox accepted() SeerAboutDialogForm accept() 248 254 157 274 buttonBox rejected() SeerAboutDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerAdaExceptionsBrowserWidget.cpp000066400000000000000000000134631526321767600241440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAdaExceptionsBrowserWidget.h" #include "SeerCatchpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerAdaExceptionsBrowserWidget::SeerAdaExceptionsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets adaExceptionsSearchLineEdit->setPlaceholderText("Search regex..."); adaExceptionsSearchLineEdit->setClearButtonEnabled(true); adaExceptionsTreeWidget->resizeColumnToContents(0); adaExceptionsTreeWidget->resizeColumnToContents(1); adaExceptionsTreeWidget->clear(); // Connect things. QObject::connect(adaExceptionsSearchLineEdit, &QLineEdit::textChanged, this, &SeerAdaExceptionsBrowserWidget::handleSearchLineEdit); QObject::connect(addCatchpointToolButton, &QToolButton::clicked, this, &SeerAdaExceptionsBrowserWidget::handleAddCatchpointToolButtonClicked); } SeerAdaExceptionsBrowserWidget::~SeerAdaExceptionsBrowserWidget () { } void SeerAdaExceptionsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,ada-exceptions={") && text.endsWith("}")) { adaExceptionsTreeWidget->clear(); // -info-ada-exceptions aint // ^done,ada-exceptions={ // nr_rows="2", // nr_cols="2", // hdr=[ // {width="1",alignment="-1",col_name="name",colhdr="Name"}, // {width="1",alignment="-1",col_name="address",colhdr="Address"} // ], // body=[ // {name="constraint_error",address="0x0000000000613da0"}, // {name="const.aint_global_e",address="0x0000000000613b00"} // ] // } QString body_text = Seer::parseFirst(text, "body=", '[', ']', false); //qDebug() << body_text; QStringList exceptions_list = Seer::parse(body_text, "", '{', '}', false); for ( const auto& entry_text : exceptions_list ) { QString name_text = Seer::parseFirst(entry_text, "name=", '"', '"', false); QString address_text = Seer::parseFirst(entry_text, "address=", '"', '"', false); // Add the file to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, name_text); item->setText(1, address_text); adaExceptionsTreeWidget->addTopLevelItem(item); } }else{ // Ignore others. } adaExceptionsTreeWidget->resizeColumnToContents(0); adaExceptionsTreeWidget->resizeColumnToContents(1); adaExceptionsSearchLineEdit->clear(); QApplication::restoreOverrideCursor(); } void SeerAdaExceptionsBrowserWidget::handleSessionTerminated () { // Delete previous contents. adaExceptionsTreeWidget->clear(); } void SeerAdaExceptionsBrowserWidget::handleSearchLineEdit (const QString& text) { // Set everything to a normal font. If there is no search text, unhide everything. // If there is search text, hide everything so the matching ones can be unhidden later on. QTreeWidgetItemIterator it(adaExceptionsTreeWidget); if (*it) { QFont f0 = (*it)->font(0); f0.setBold(false); if (text == "") { while (*it) { (*it)->setHidden(false); // No search text, unhide everything. (*it)->setFont(0,f0); ++it; } }else{ while (*it) { (*it)->setHidden(true); // Has search text, hide everything. Matching items to be unhidden below. (*it)->setFont(0,f0); ++it; } } } // Set selected items to a bold font and unhidden. Move to the first match. if (text != "") { QList matches; matches = adaExceptionsTreeWidget->findItems(text, Qt::MatchRegularExpression | Qt::MatchRecursive, 0); QList::const_iterator it = matches.begin(); QList::const_iterator e = matches.end(); if (it != e) { adaExceptionsTreeWidget->setCurrentItem(*it); QFont f0 = (*it)->font(0); f0.setBold(true); while (it != e) { (*it)->setHidden(false); (*it)->setFont(0,f0); it++; } } //qDebug() << text << matches.size(); } adaExceptionsTreeWidget->resizeColumnToContents(0); adaExceptionsTreeWidget->resizeColumnToContents(1); } void SeerAdaExceptionsBrowserWidget::handleAddCatchpointToolButtonClicked () { SeerCatchpointCreateDialog dlg(this); dlg.setType("exception"); QTreeWidgetItem* item = adaExceptionsTreeWidget->currentItem(); if (item != 0) { dlg.setArguments(item->text(0)); } int ret = dlg.exec(); if (ret == 0) { return; } // Build a catchpoint specification. QString catchpointParameters = dlg.catchpointText(); // If nothing, just return. if (catchpointParameters == "") { return; } // Otherwise send the command to create the catchpoint. emit insertCatchpoint(catchpointParameters); } void SeerAdaExceptionsBrowserWidget::refresh () { emit refreshAdaExceptions(); } void SeerAdaExceptionsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } epasveer-seer-97076f1/src/SeerAdaExceptionsBrowserWidget.h000066400000000000000000000023001526321767600235750ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerAdaExceptionsBrowserWidget.h" class SeerAdaExceptionsBrowserWidget : public QWidget, protected Ui::SeerAdaExceptionsBrowserWidgetForm { Q_OBJECT public: explicit SeerAdaExceptionsBrowserWidget (QWidget* parent = 0); ~SeerAdaExceptionsBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (const QString& text); void handleAddCatchpointToolButtonClicked (); signals: void refreshAdaExceptions (); void insertCatchpoint (QString catchpoint); protected: void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerAdaExceptionsBrowserWidget.ui000066400000000000000000000042721526321767600237750ustar00rootroot00000000000000 SeerAdaExceptionsBrowserWidgetForm 0 0 730 698 Ada Exceptions Browser Search in the list of exceptions. "*" is allowed. Search regex... Add a catchpoint for an Ada exception. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg 2 Name Address QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
epasveer-seer-97076f1/src/SeerAdaSourceHighlighter.cpp000066400000000000000000000125761526321767600227360ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAdaSourceHighlighter.h" SeerAdaSourceHighlighter::SeerAdaSourceHighlighter(QTextDocument *parent) : SeerSourceHighlighter(parent) { // Set to default formats. setHighlighterSettings(SeerHighlighterSettings::populate("")); } void SeerAdaSourceHighlighter::setHighlighterSettings(const SeerHighlighterSettings &settings) { _highlighterSettings = settings; _classFormat = _highlighterSettings.get("Class"); _quotationFormat = _highlighterSettings.get("Quotation"); _functionFormat = _highlighterSettings.get("Function"); _singleLineCommentFormat = _highlighterSettings.get("Comment"); _multiLineCommentFormat = _highlighterSettings.get("Multiline Comment"); _keywordFormat = _highlighterSettings.get("Keyword"); const QString keywordPatterns[] = { QStringLiteral("\\babort\\b"), QStringLiteral("\\babs\\b"), QStringLiteral("\\babstract\\b"), QStringLiteral("\\baccept\\b"), QStringLiteral("\\baccess\\b"), QStringLiteral("\\baliased\\b"), QStringLiteral("\\ball\\b"), QStringLiteral("\\band\\b"), QStringLiteral("\\barray\\b"), QStringLiteral("\\bat\\b"), QStringLiteral("\\bbegin\\b"), QStringLiteral("\\bbody\\b"), QStringLiteral("\\bcase\\b"), QStringLiteral("\\bconstant\\b"), QStringLiteral("\\bdeclare\\b"), QStringLiteral("\\bdelay\\b"), QStringLiteral("\\bdelta\\b"), QStringLiteral("\\bdigits\\b"), QStringLiteral("\\bdo\\b"), QStringLiteral("\\belse\\b"), QStringLiteral("\\belsif\\b"), QStringLiteral("\\bend\\b"), QStringLiteral("\\bentry\\b"), QStringLiteral("\\bexception\\b"), QStringLiteral("\\bexit\\b"), QStringLiteral("\\bfor\\b"), QStringLiteral("\\bfunction\\b"), QStringLiteral("\\bgeneric\\b"), QStringLiteral("\\bgoto\\b"), QStringLiteral("\\bif\\b"), QStringLiteral("\\bin\\b"), QStringLiteral("\\binterface\\b"), QStringLiteral("\\bis\\b"), QStringLiteral("\\blimited\\b"), QStringLiteral("\\bloop\\b"), QStringLiteral("\\bmod\\b"), QStringLiteral("\\bnew\\b"), QStringLiteral("\\bnot\\b"), QStringLiteral("\\bnull\\b"), QStringLiteral("\\bof\\b"), QStringLiteral("\\bor\\b"), QStringLiteral("\\bothers\\b"), QStringLiteral("\\bout\\b"), QStringLiteral("\\boverriding\\b"), QStringLiteral("\\bpackage\\b"), QStringLiteral("\\bpragma\\b"), QStringLiteral("\\bprivate\\b"), QStringLiteral("\\bprocedure\\b"), QStringLiteral("\\bprotected\\b"), QStringLiteral("\\braise\\b"), QStringLiteral("\\brange\\b"), QStringLiteral("\\brecord\\b"), QStringLiteral("\\brem\\b"), QStringLiteral("\\brenames\\b"), QStringLiteral("\\brequeue\\b"), QStringLiteral("\\breturn\\b"), QStringLiteral("\\breverse\\b"), QStringLiteral("\\bselect\\b"), QStringLiteral("\\bseparate\\b"), QStringLiteral("\\bsome\\b"), QStringLiteral("\\bsubtype\\b"), QStringLiteral("\\bsynchronized\\b"),QStringLiteral("\\btagged\\b"), QStringLiteral("\\btask\\b"), QStringLiteral("\\bterminate\\b"), QStringLiteral("\\bthen\\b"), QStringLiteral("\\btype\\b"), QStringLiteral("\\buntil\\b"), QStringLiteral("\\buse\\b"), QStringLiteral("\\bwhen\\b"), QStringLiteral("\\bwhile\\b"), QStringLiteral("\\bwith\\b"), QStringLiteral("\\bxor\\b"), }; _highlightingRules.clear(); // Clear old rules. HighlightingRule rule; // Set class format and expression. // (Ada typically doesn't have a distinguished class case convention, but we can reuse uppercase Start) rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Z][A-Za-z0-9_]*\\b")); rule.format = _classFormat; _highlightingRules.append(rule); // Set function format and expression. // This won't highlight parameterless subprograms, but it's still useful for most cases. rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Za-z0-9_!]+(?=\\s*\\()")); rule.format = _functionFormat; _highlightingRules.append(rule); // Set keywords format and expression (must have precedence over functions) // Ada is case insensitive, so we use case insensitive option. for (const QString &pattern : keywordPatterns) { rule.pattern = QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption); rule.format = _keywordFormat; _highlightingRules.append(rule); } // Set quote format and expression. rule.pattern = QRegularExpression(QStringLiteral("\"[^\"]*\"")); rule.format = _quotationFormat; _highlightingRules.append(rule); // Set single line comment format and expression. (Ada uses --) rule.pattern = QRegularExpression(QStringLiteral("--[^\n]*")); rule.format = _singleLineCommentFormat; _highlightingRules.append(rule); // Multi-line comments are not possible in Ada. // Using a regex that matches nothing to avoid any unintended highlighting. _commentStartExpression = QRegularExpression(QStringLiteral("(?!)")); _commentEndExpression = QRegularExpression(QStringLiteral("(?!)")); } epasveer-seer-97076f1/src/SeerAdaSourceHighlighter.h000066400000000000000000000007251526321767600223740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerHighlighterSettings.h" #include "SeerSourceHighlighter.h" class SeerAdaSourceHighlighter : public SeerSourceHighlighter { Q_OBJECT public: SeerAdaSourceHighlighter(QTextDocument *parent = 0); virtual void setHighlighterSettings (const SeerHighlighterSettings &settings) override; }; epasveer-seer-97076f1/src/SeerAdaTasksBrowserWidget.cpp000066400000000000000000000155431526321767600231110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAdaTasksBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerAdaTasksBrowserWidget::SeerAdaTasksBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets adaTaskTreeWidget->setMouseTracking(true); adaTaskTreeWidget->setSortingEnabled(false); adaTaskTreeWidget->resizeColumnToContents(0); // current adaTaskTreeWidget->resizeColumnToContents(1); // id adaTaskTreeWidget->resizeColumnToContents(2); // taskid adaTaskTreeWidget->resizeColumnToContents(3); // threadid adaTaskTreeWidget->resizeColumnToContents(4); // parentid adaTaskTreeWidget->resizeColumnToContents(5); // priority adaTaskTreeWidget->resizeColumnToContents(6); // state adaTaskTreeWidget->resizeColumnToContents(7); // name adaTaskTreeWidget->clear(); // Connect things. QObject::connect(adaTaskTreeWidget, &QTreeWidget::itemClicked, this, &SeerAdaTasksBrowserWidget::handleItemClicked); } SeerAdaTasksBrowserWidget::~SeerAdaTasksBrowserWidget () { } void SeerAdaTasksBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,tasks={")) { // -ada-task-info [ task-id ] // ^done,tasks={ // nr_rows="3", // nr_cols="8", // hdr=[ // { // width="1",alignment="-1",col_name="current",colhdr="" // }, // { // width="3",alignment="1",col_name="id",colhdr="ID" // }, // { // width="9",alignment="1",col_name="task-id",colhdr="TID" // }, // { // width="4",alignment="1",col_name="thread-id",colhdr="" // }, // { // width="4",alignment="1",col_name="parent-id",colhdr="P-ID" // }, // { // width="3",alignment="1",col_name="priority",colhdr="Pri" // }, // { // width="22",alignment="-1",col_name="state",colhdr="State" // }, // { // width="1",alignment="2",col_name="name",colhdr="Name" // } // ], // body=[ // { // id="1",task-id="45d030",thread-id="1",priority="48",state="Waiting on RV with 2 ",name="main_task" // }, // { // current="*",id="2",task-id="45de30",thread-id="2",parent-id="1",priority="48",state="Runnable",name="task_a" // }, // { // id="3",task-id="461460",thread-id="3",parent-id="1",priority="48",state="Delay Sleep",name="task_b" // } // ] // } //qDebug() << text; adaTaskTreeWidget->clear(); QString body_text = Seer::parseFirst(text, "body=", '[', ']', false); //qDebug() << threads_text; if (body_text != "") { QStringList tasks_list = Seer::parse(body_text, "", '{', '}', false); for ( const auto& task_text : tasks_list ) { QString current_text = Seer::parseFirst(task_text, "current=", '"', '"', false); QString id_text = Seer::parseFirst(task_text, "id=", '"', '"', false); QString taskid_text = Seer::parseFirst(task_text, "task-id=", '"', '"', false); QString threadid_text = Seer::parseFirst(task_text, "thread-id=", '"', '"', false); QString parentid_text = Seer::parseFirst(task_text, "parent-id=", '"', '"', false); QString priority_text = Seer::parseFirst(task_text, "priority=", '"', '"', false); QString state_text = Seer::parseFirst(task_text, "state=", '"', '"', false); QString name_text = Seer::parseFirst(task_text, "name=", '"', '"', false); // Create the item. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, current_text); item->setText(1, id_text); item->setText(2, taskid_text); item->setText(3, threadid_text); item->setText(4, parentid_text); item->setText(5, priority_text); item->setText(6, state_text); item->setText(7, name_text); // Add the frame to the tree. adaTaskTreeWidget->addTopLevelItem(item); } } // Clear the selection and select the one for the current thread-id. adaTaskTreeWidget->clearSelection(); QList matches = adaTaskTreeWidget->findItems("*", Qt::MatchExactly, 0); if (matches.size() > 0) { adaTaskTreeWidget->setCurrentItem(matches.first()); } }else{ // Ignore others. } adaTaskTreeWidget->resizeColumnToContents(0); adaTaskTreeWidget->resizeColumnToContents(1); adaTaskTreeWidget->resizeColumnToContents(2); adaTaskTreeWidget->resizeColumnToContents(3); adaTaskTreeWidget->resizeColumnToContents(4); adaTaskTreeWidget->resizeColumnToContents(5); adaTaskTreeWidget->resizeColumnToContents(6); adaTaskTreeWidget->resizeColumnToContents(7); QApplication::restoreOverrideCursor(); } void SeerAdaTasksBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } refresh(); } void SeerAdaTasksBrowserWidget::handleSessionTerminated () { // Delete previous contents. adaTaskTreeWidget->clear(); } void SeerAdaTasksBrowserWidget::handleItemClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedThread(item->text(3).toInt()); } void SeerAdaTasksBrowserWidget::refresh () { emit refreshAdaTasks(); } void SeerAdaTasksBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } epasveer-seer-97076f1/src/SeerAdaTasksBrowserWidget.h000066400000000000000000000021571526321767600225530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerAdaTasksBrowserWidget.h" class SeerAdaTasksBrowserWidget : public QWidget, protected Ui::SeerAdaTasksBrowserWidgetForm { Q_OBJECT public: explicit SeerAdaTasksBrowserWidget (QWidget* parent = 0); ~SeerAdaTasksBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemClicked (QTreeWidgetItem* item, int column); signals: void refreshAdaTasks (); void selectedThread (int threadid); protected: void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerAdaTasksBrowserWidget.ui000066400000000000000000000032311526321767600227330ustar00rootroot00000000000000 SeerAdaTasksBrowserWidgetForm 0 0 794 528 Form QAbstractItemView::SingleSelection 8 Active Id Task Id Thread Id Parent Id Priority State Name epasveer-seer-97076f1/src/SeerArgumentsDialog.cpp000066400000000000000000000012271526321767600217650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerArgumentsDialog.h" SeerArgumentsDialog::SeerArgumentsDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets setExecutableArguments(""); // Connect things. } SeerArgumentsDialog::~SeerArgumentsDialog () { } void SeerArgumentsDialog::setExecutableArguments (const QString& executableArguments) { executableArgumentsLineEdit->setText(executableArguments); } QString SeerArgumentsDialog::executableArguments () { return executableArgumentsLineEdit->text(); } epasveer-seer-97076f1/src/SeerArgumentsDialog.h000066400000000000000000000012001526321767600214210ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerArgumentsDialog.h" class SeerArgumentsDialog : public QDialog, protected Ui::SeerArgumentsDialogForm { Q_OBJECT public: explicit SeerArgumentsDialog (QWidget* parent = 0); ~SeerArgumentsDialog (); void setExecutableArguments (const QString& executableArguments); QString executableArguments (); public slots: private: }; epasveer-seer-97076f1/src/SeerArgumentsDialog.ui000066400000000000000000000037221526321767600216220ustar00rootroot00000000000000 SeerArgumentsDialogForm 0 0 375 121 Select Executable Arguments to Use Executable Arguments Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerArgumentsDialogForm accept() 187 97 187 60 buttonBox rejected() SeerArgumentsDialogForm reject() 187 97 187 60 epasveer-seer-97076f1/src/SeerArrayVisualizerWidget.cpp000066400000000000000000001306301526321767600232010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerArrayVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include #include #include // // Qt Charts 6.x workaround: scatter marker items can be (re)created without // inheriting the series' pen/brush, leaving near-invisible ~1px markers. // Small arrays usually render fine; large ones (e.g. 4000 points) reliably // degrade. The series-level state is correct in both cases, so the style is // lost at the marker-item level inside Qt Charts. Re-applying the pen/brush // after the series is added pushes the style down to the marker items. // // Two passes suffice, not four. This runs after addSeries(), so the series // already carries the chart theme's pen/brush; setPen(NoPen) and setBrush() // are therefore real value transitions (no built-in Qt theme uses NoPen for // a scatter pen nor this exact colour for the brush) and are not swallowed // by the guarded setters. Even if one were a no-op, the other setter's // update re-pushes both pen and brush to every marker item. Two passes over // the (up to thousands of) marker items instead of four roughly halves this // step's cost, with no visible change to the markers. // static void redecorateScatterSeries (QXYSeries* series) { QScatterSeries* scatter = qobject_cast(series); if (scatter == nullptr) { return; } scatter->setPen(QPen(Qt::NoPen)); scatter->setBrush(QBrush(QColor(31, 119, 180))); } SeerArrayVisualizerWidget::SeerArrayVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _aVariableId = Seer::createID(); // Create id's for A queries. _aMemoryId = Seer::createID(); _aLengthId = Seer::createID(); _aOffsetId = Seer::createID(); _aStrideId = Seer::createID(); _bVariableId = Seer::createID(); // Create id's for B queries. _bMemoryId = Seer::createID(); _bLengthId = Seer::createID(); _bOffsetId = Seer::createID(); _bStrideId = Seer::createID(); _aSeries = 0; _bSeries = 0; // Set up UI. setupUi(this); // Setup the widgets setWindowTitle("Seer Array Visualizer"); setAttribute(Qt::WA_DeleteOnClose); arrayTableWidget->setAAxis(aAxisComboBox->currentText()); arrayTableWidget->setBAxis(bAxisComboBox->currentText()); lineRadioButton->setChecked(true); aArrayDisplayFormatComboBox->setCurrentIndex(0); bArrayDisplayFormatComboBox->setCurrentIndex(0); handleaArrayDisplayFormatComboBox(0); handlebArrayDisplayFormatComboBox(0); aVariableNameLineEdit->enableReturnPressedOnClear(); bVariableNameLineEdit->enableReturnPressedOnClear(); // A single series chart. QChart* chart = new QChart; chart->legend()->hide(); chart->createDefaultAxes(); chart->legend()->setVisible(true); chart->legend()->setAlignment(Qt::AlignBottom); arrayChartView->setRenderHint(QPainter::Antialiasing); arrayChartView->setChart(chart); arrayChartView->setFocusPolicy(Qt::StrongFocus); // Connect things. QObject::connect(aRefreshToolButton, &QToolButton::clicked, this, &SeerArrayVisualizerWidget::handleaRefreshButton); QObject::connect(bRefreshToolButton, &QToolButton::clicked, this, &SeerArrayVisualizerWidget::handlebRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerArrayVisualizerWidget::handleHelpButton); QObject::connect(aVariableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handleaVariableNameLineEdit); QObject::connect(aVariableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handleaVariableNameLineEdit); QObject::connect(aArrayLengthLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handleaRefreshButton); QObject::connect(aArrayLengthLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handleaElementLengthLineEdit); QObject::connect(aArrayOffsetLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handleaRefreshButton); QObject::connect(aArrayOffsetLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handleaElementOffsetLineEdit); QObject::connect(aArrayStrideLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handleaRefreshButton); QObject::connect(aArrayStrideLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handleaElementStrideLineEdit); QObject::connect(aArrayDisplayFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerArrayVisualizerWidget::handleaArrayDisplayFormatComboBox); QObject::connect(aAxisComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerArrayVisualizerWidget::handleaAxisComboBox); QObject::connect(bVariableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handlebVariableNameLineEdit); QObject::connect(bVariableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handlebVariableNameLineEdit); QObject::connect(bArrayLengthLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handlebRefreshButton); QObject::connect(bArrayLengthLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handlebElementLengthLineEdit); QObject::connect(bArrayOffsetLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handlebRefreshButton); QObject::connect(bArrayOffsetLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handlebElementOffsetLineEdit); QObject::connect(bArrayStrideLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handlebRefreshButton); QObject::connect(bArrayStrideLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handlebElementStrideLineEdit); QObject::connect(bArrayDisplayFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerArrayVisualizerWidget::handlebArrayDisplayFormatComboBox); QObject::connect(bAxisComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerArrayVisualizerWidget::handlebAxisComboBox); QObject::connect(arrayTableWidget, &SeerArrayWidget::dataChanged, this, &SeerArrayVisualizerWidget::handleDataChanged); QObject::connect(splitter, &QSplitter::splitterMoved, this, &SeerArrayVisualizerWidget::handleSplitterMoved); QObject::connect(titleLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerArrayVisualizerWidget::handleTitleLineEdit); QObject::connect(titleLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerArrayVisualizerWidget::handleTitleLineEdit); QObject::connect(pointsCheckBox, &QCheckBox::clicked, this, &SeerArrayVisualizerWidget::handlePointsCheckBox); QObject::connect(labelsCheckBox, &QCheckBox::clicked, this, &SeerArrayVisualizerWidget::handleLabelsCheckBox); QObject::connect(lineTypeButtonGroup, QOverload::of(&QButtonGroup::idClicked), this, &SeerArrayVisualizerWidget::handleLineTypeButtonGroup); QObject::connect(printPushButton, &QPushButton::clicked, arrayChartView, &QZoomChartView::printView); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerArrayVisualizerWidget::handleThemeChanged); #endif // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); Seer::colorizeChartViewItem(arrayChartView, Seer::iconColorTheme()); // Restore window settings. readSettings(); } SeerArrayVisualizerWidget::~SeerArrayVisualizerWidget () { } void SeerArrayVisualizerWidget::setAVariableName (const QString& name) { setWindowTitle("Seer Array Visualizer - '" + name + "'"); aVariableNameLineEdit->setText(name); if (aVariableNameLineEdit->text() == "") { aVariableAddressLineEdit->setText(""); aArrayLengthLineEdit->setText(""); aArrayOffsetLineEdit->setText(""); aArrayStrideLineEdit->setText(""); arrayTableWidget->setAData("deleted", 0); return; } // Coalesce this variable's setup (address reset + data/offset/stride) into // a single table rebuild; the guard flushes it when it leaves scope. SeerArrayWidget::BulkUpdate bulk(arrayTableWidget); setAVariableAddress(""); // Clear old contents. QByteArray array; bool ok; arrayTableWidget->setAData(name, new SeerArrayWidget::DataStorageArray(array)); if (aArrayOffsetLineEdit->text() != "") { arrayTableWidget->setAAddressOffset(aArrayOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << aArrayOffsetLineEdit->text(); } }else{ arrayTableWidget->setAAddressOffset(0); } if (aArrayStrideLineEdit->text() != "") { arrayTableWidget->setAAddressStride(aArrayStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << aArrayStrideLineEdit->text(); } }else{ arrayTableWidget->setAAddressStride(1); } // Send signal to get variable address. emit evaluateVariableExpression(_aVariableId, aVariableNameLineEdit->text()); } QString SeerArrayVisualizerWidget::aVariableName () const { return aVariableNameLineEdit->text(); } void SeerArrayVisualizerWidget::setAVariableAddress (const QString& address) { unsigned long offset = 0; bool ok = false; if (address == "") { aVariableAddressLineEdit->setText(""); offset = 0; }else{ // Test for base10 if (ok == false) { offset = address.toULong(&ok, 10); if (ok) { aVariableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } // Test for base16 if (ok == false) { offset = address.toULong(&ok, 16); if (ok) { aVariableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } if (ok == false) { aVariableAddressLineEdit->setText("not an address"); offset = 0; } } arrayTableWidget->setAAddressOffset(0); } QString SeerArrayVisualizerWidget::aVariableAddress () const { return aVariableAddressLineEdit->text(); } void SeerArrayVisualizerWidget::setAVariableLength (const QString& length) { aArrayLengthLineEdit->setText(length); } QString SeerArrayVisualizerWidget::aVariableLength () const { return aArrayLengthLineEdit->text(); } void SeerArrayVisualizerWidget::setAVariableOffset (const QString& offset) { aArrayOffsetLineEdit->setText(offset); } QString SeerArrayVisualizerWidget::aVariableOffset () const { return aArrayOffsetLineEdit->text(); } void SeerArrayVisualizerWidget::setAVariableStride (const QString& stride) { aArrayStrideLineEdit->setText(stride); } QString SeerArrayVisualizerWidget::aVariableStride () const { return aArrayStrideLineEdit->text(); } void SeerArrayVisualizerWidget::setBVariableName (const QString& name) { setWindowTitle("Seer Array Visualizer - '" + name + "'"); bVariableNameLineEdit->setText(name); if (bVariableNameLineEdit->text() == "") { bVariableAddressLineEdit->setText(""); bArrayLengthLineEdit->setText(""); bArrayOffsetLineEdit->setText(""); bArrayStrideLineEdit->setText(""); arrayTableWidget->setBData("deleted", 0); return; } // Coalesce this variable's setup (address reset + data/offset/stride) into // a single table rebuild; the guard flushes it when it leaves scope. SeerArrayWidget::BulkUpdate bulk(arrayTableWidget); setBVariableAddress(""); // Clear old contents. QByteArray array; bool ok; arrayTableWidget->setBData(name, new SeerArrayWidget::DataStorageArray(array)); if (bArrayOffsetLineEdit->text() != "") { arrayTableWidget->setBAddressOffset(bArrayOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << bArrayOffsetLineEdit->text(); } }else{ arrayTableWidget->setBAddressOffset(0); } if (bArrayStrideLineEdit->text() != "") { arrayTableWidget->setBAddressStride(bArrayStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << bArrayStrideLineEdit->text(); } }else{ arrayTableWidget->setBAddressStride(1); } // Send signal to get variable address. emit evaluateVariableExpression(_bVariableId, bVariableNameLineEdit->text()); } QString SeerArrayVisualizerWidget::bVariableName () const { return bVariableNameLineEdit->text(); } void SeerArrayVisualizerWidget::setBVariableAddress (const QString& address) { unsigned long offset = 0; bool ok = false; if (address == "") { bVariableAddressLineEdit->setText(""); offset = 0; }else{ // Test for base10 if (ok == false) { offset = address.toULong(&ok, 10); if (ok) { bVariableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } // Test for base16 if (ok == false) { offset = address.toULong(&ok, 16); if (ok) { bVariableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } if (ok == false) { bVariableAddressLineEdit->setText("not an address"); offset = 0; } } arrayTableWidget->setBAddressOffset(0); } QString SeerArrayVisualizerWidget::bVariableAddress () const { return bVariableAddressLineEdit->text(); } void SeerArrayVisualizerWidget::setBVariableLength (const QString& length) { bArrayLengthLineEdit->setText(length); } QString SeerArrayVisualizerWidget::bVariableLength () const { return bArrayLengthLineEdit->text(); } void SeerArrayVisualizerWidget::setBVariableOffset (const QString& offset) { bArrayOffsetLineEdit->setText(offset); } QString SeerArrayVisualizerWidget::bVariableOffset () const { return bArrayOffsetLineEdit->text(); } void SeerArrayVisualizerWidget::setBVariableStride (const QString& stride) { bArrayStrideLineEdit->setText(stride); } QString SeerArrayVisualizerWidget::bVariableStride () const { return bArrayStrideLineEdit->text(); } void SeerArrayVisualizerWidget::handleText (const QString& text) { //qDebug() << text; static const QRegularExpression valueResponse = QRegularExpression("^([0-9]+)\\^done,value="); static const QRegularExpression memoryResponse = QRegularExpression("^([0-9]+)\\^done,memory="); static const QRegularExpression errorResponse = QRegularExpression("^([0-9]+)\\^error,msg="); if (text.contains(valueResponse)) { // 11^done,value="1" // 11^done,value="0x7fffffffd538" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _aVariableId) { QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); QString address = ""; // Look for an address in the value. if (address == "") { QRegularExpression re("0[xX][0-9a-fA-F]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Look for a number in the value. if (address == "") { QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Set the variable address and read the memory there. setAVariableAddress(address); readaMemory(); } if (id_text.toInt() == _aLengthId) { // Set the memory length. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setAVariableLength(value_text); handleaRefreshButton(); } if (id_text.toInt() == _aOffsetId) { // Set the memory offset. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setAVariableOffset(value_text); handleaRefreshButton(); } if (id_text.toInt() == _aStrideId) { // Set the memory stride. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setAVariableStride(value_text); handleaRefreshButton(); } if (id_text.toInt() == _bVariableId) { QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); QString address = ""; // Look for an address in the value. if (address == "") { QRegularExpression re("0[xX][0-9a-fA-F]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Look for a number in the value. if (address == "") { QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Set the variable address and read the memory there. setBVariableAddress(address); readbMemory(); } if (id_text.toInt() == _bLengthId) { // Set the memory length. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setBVariableLength(value_text); handlebRefreshButton(); } if (id_text.toInt() == _bOffsetId) { // Set the memory offset. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setBVariableOffset(value_text); handlebRefreshButton(); } if (id_text.toInt() == _bStrideId) { // Set the memory stride. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setBVariableStride(value_text); handlebRefreshButton(); } }else if (text.contains(memoryResponse)) { // 3^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613e71",contents="00"}] // 4^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613ed4",contents="000000000000000000000000"}] QString id_text = text.section('^', 0,0); if (id_text.toInt() == _aMemoryId) { QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); // Loop through the memory ranges. for ( const auto& range_text : range_list ) { QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); // Convert hex string to byte array. QByteArray array; for (int i = 0; isetAData(arrayTableWidget->aLabel(), new SeerArrayWidget::DataStorageArray(array)); if (aArrayOffsetLineEdit->text() != "") { arrayTableWidget->setAAddressOffset(aArrayOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << aArrayOffsetLineEdit->text(); } }else{ arrayTableWidget->setAAddressOffset(0); } if (aArrayStrideLineEdit->text() != "") { arrayTableWidget->setAAddressStride(aArrayStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << aArrayStrideLineEdit->text(); } }else{ arrayTableWidget->setAAddressStride(1); } break; // Take just the first range for now. } } if (id_text.toInt() == _bMemoryId) { QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); // Loop through the memory ranges. for ( const auto& range_text : range_list ) { QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); // Convert hex string to byte array. QByteArray array; for (int i = 0; isetBData(arrayTableWidget->bLabel(), new SeerArrayWidget::DataStorageArray(array)); if (bArrayOffsetLineEdit->text() != "") { arrayTableWidget->setBAddressOffset(bArrayOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << bArrayOffsetLineEdit->text(); } }else{ arrayTableWidget->setBAddressOffset(0); } if (bArrayStrideLineEdit->text() != "") { arrayTableWidget->setBAddressStride(bArrayStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << bArrayStrideLineEdit->text(); } }else{ arrayTableWidget->setBAddressStride(1); } break; // Take just the first range for now. } } }else if (text.contains(errorResponse)) { // 12^error,msg="No symbol \"return\" in current context." // 13^error,msg="No symbol \"cout\" in current context." // 3^error,msg="Unable to read memory." QString id_text = text.section('^', 0,0); if (id_text.toInt() == _aVariableId) { aVariableAddressLineEdit->setText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) ); } if (id_text.toInt() == _aMemoryId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); if (msg_text != "") { QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); } } if (id_text.toInt() == _aLengthId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); aArrayLengthLineEdit->setText(""); aArrayLengthLineEdit->setFocus(); } if (id_text.toInt() == _aOffsetId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); aArrayOffsetLineEdit->setText(""); aArrayOffsetLineEdit->setFocus(); } if (id_text.toInt() == _aStrideId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); aArrayStrideLineEdit->setText(""); aArrayStrideLineEdit->setFocus(); } if (id_text.toInt() == _bVariableId) { bVariableAddressLineEdit->setText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) ); } if (id_text.toInt() == _bMemoryId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); if (msg_text != "") { QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); } } if (id_text.toInt() == _bLengthId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); bArrayLengthLineEdit->setText(""); bArrayLengthLineEdit->setFocus(); } if (id_text.toInt() == _bOffsetId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); bArrayOffsetLineEdit->setText(""); bArrayOffsetLineEdit->setFocus(); } if (id_text.toInt() == _bStrideId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); bArrayStrideLineEdit->setText(""); bArrayStrideLineEdit->setFocus(); } // At a stopping point, refresh. Skip the "exited" reasons: the program // is gone and reading the arrays would fail with a memory error. }else if (text.startsWith("*stopped,reason=\"") && text.startsWith("*stopped,reason=\"exited") == false) { if (autoRefreshCheckBox->isChecked()) { handleaRefreshButton(); handlebRefreshButton(); } }else{ // Ignore anything else. } } void SeerArrayVisualizerWidget::handleaRefreshButton () { if (aVariableNameLineEdit->text() == "") { return; } // Re-evaluate the variable's address first: it may have changed since the // last stop (or the variable may not have existed yet). The answer then // reads the memory at the fresh address. See readaMemory(). emit evaluateVariableExpression(_aVariableId, aVariableNameLineEdit->text()); } void SeerArrayVisualizerWidget::handlebRefreshButton () { if (bVariableNameLineEdit->text() == "") { return; } // Re-evaluate the variable's address first: it may have changed since the // last stop (or the variable may not have existed yet). The answer then // reads the memory at the fresh address. See readbMemory(). emit evaluateVariableExpression(_bVariableId, bVariableNameLineEdit->text()); } void SeerArrayVisualizerWidget::readaMemory () { if (aVariableAddressLineEdit->text() == "") { return; } if (aVariableAddressLineEdit->text() == "not an address") { return; } // A null address can't be read (a std::vector before its construction, // for example). Keep the "0x0" visible but don't ask gdb. if (aVariableAddressLineEdit->text() == "0x0") { return; } int bytes = aArrayLengthLineEdit->text().toInt() * Seer::typeBytes(aArrayDisplayFormatComboBox->currentText()); // Nothing to read yet (no length). if (bytes <= 0) { return; } //qDebug() << _aMemoryId << aVariableAddressLineEdit->text() << aArrayLengthLineEdit->text() << aArrayDisplayFormatComboBox->currentText() << bytes; emit evaluateMemoryExpression(_aMemoryId, aVariableAddressLineEdit->text(), bytes); } void SeerArrayVisualizerWidget::readbMemory () { if (bVariableAddressLineEdit->text() == "") { return; } if (bVariableAddressLineEdit->text() == "not an address") { return; } // A null address can't be read (a std::vector before its construction, // for example). Keep the "0x0" visible but don't ask gdb. if (bVariableAddressLineEdit->text() == "0x0") { return; } int bytes = bArrayLengthLineEdit->text().toInt() * Seer::typeBytes(bArrayDisplayFormatComboBox->currentText()); // Nothing to read yet (no length). if (bytes <= 0) { return; } //qDebug() << _bMemoryId << bVariableAddressLineEdit->text() << bArrayLengthLineEdit->text() << bArrayDisplayFormatComboBox->currentText() << bytes; emit evaluateMemoryExpression(_bMemoryId, bVariableAddressLineEdit->text(), bytes); } void SeerArrayVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/ArrayVisualizer.md"); help->show(); help->raise(); } void SeerArrayVisualizerWidget::handleaVariableNameLineEdit () { setAVariableName (aVariableNameLineEdit->text()); } void SeerArrayVisualizerWidget::handlebVariableNameLineEdit () { setBVariableName (bVariableNameLineEdit->text()); } void SeerArrayVisualizerWidget::handleaElementLengthLineEdit () { if (aVariableLength() == "") { return; } emit evaluateVariableExpression(_aLengthId, aVariableLength()); } void SeerArrayVisualizerWidget::handleaElementOffsetLineEdit () { if (aVariableOffset() == "") { return; } emit evaluateVariableExpression(_aOffsetId, aVariableOffset()); } void SeerArrayVisualizerWidget::handleaElementStrideLineEdit () { if (aVariableStride() == "") { return; } emit evaluateVariableExpression(_aStrideId, aVariableStride()); } void SeerArrayVisualizerWidget::handlebElementLengthLineEdit () { if (bVariableLength() == "") { return; } emit evaluateVariableExpression(_bLengthId, bVariableLength()); } void SeerArrayVisualizerWidget::handlebElementOffsetLineEdit () { if (bVariableOffset() == "") { return; } emit evaluateVariableExpression(_bOffsetId, bVariableOffset()); } void SeerArrayVisualizerWidget::handlebElementStrideLineEdit () { if (bVariableStride() == "") { return; } emit evaluateVariableExpression(_bStrideId, bVariableStride()); } void SeerArrayVisualizerWidget::handleaArrayDisplayFormatComboBox (int index) { //qDebug() << index; if (index == 0) { arrayTableWidget->setAArrayMode(SeerArrayWidget::Int16ArrayMode); }else if (index == 1) { arrayTableWidget->setAArrayMode(SeerArrayWidget::Int32ArrayMode); }else if (index == 2) { arrayTableWidget->setAArrayMode(SeerArrayWidget::Int64ArrayMode); }else if (index == 3) { arrayTableWidget->setAArrayMode(SeerArrayWidget::UInt16ArrayMode); }else if (index == 4) { arrayTableWidget->setAArrayMode(SeerArrayWidget::UInt32ArrayMode); }else if (index == 5) { arrayTableWidget->setAArrayMode(SeerArrayWidget::UInt64ArrayMode); }else if (index == 6) { arrayTableWidget->setAArrayMode(SeerArrayWidget::Float32ArrayMode); }else if (index == 7) { arrayTableWidget->setAArrayMode(SeerArrayWidget::Float64ArrayMode); }else{ // Do nothing. } handleaRefreshButton(); } void SeerArrayVisualizerWidget::handlebArrayDisplayFormatComboBox (int index) { //qDebug() << index; if (index == 0) { arrayTableWidget->setBArrayMode(SeerArrayWidget::Int16ArrayMode); }else if (index == 1) { arrayTableWidget->setBArrayMode(SeerArrayWidget::Int32ArrayMode); }else if (index == 2) { arrayTableWidget->setBArrayMode(SeerArrayWidget::Int64ArrayMode); }else if (index == 3) { arrayTableWidget->setBArrayMode(SeerArrayWidget::UInt16ArrayMode); }else if (index == 4) { arrayTableWidget->setBArrayMode(SeerArrayWidget::UInt32ArrayMode); }else if (index == 5) { arrayTableWidget->setBArrayMode(SeerArrayWidget::UInt64ArrayMode); }else if (index == 6) { arrayTableWidget->setBArrayMode(SeerArrayWidget::Float32ArrayMode); }else if (index == 7) { arrayTableWidget->setBArrayMode(SeerArrayWidget::Float64ArrayMode); }else{ // Do nothing. } handlebRefreshButton(); } void SeerArrayVisualizerWidget::handleaAxisComboBox (int index) { arrayTableWidget->setAAxis(aAxisComboBox->itemText(index)); handleDataChanged(); } void SeerArrayVisualizerWidget::handlebAxisComboBox (int index) { arrayTableWidget->setBAxis(bAxisComboBox->itemText(index)); handleDataChanged(); } void SeerArrayVisualizerWidget::handleDataChanged () { // Delete old series. if (_aSeries) { arrayChartView->chart()->removeSeries(_aSeries); arrayChartView->chart()->update(); delete _aSeries; _aSeries = 0; } if (_bSeries) { arrayChartView->chart()->removeSeries(_bSeries); arrayChartView->chart()->update(); delete _bSeries; _bSeries = 0; } // If only the first array is defined, create a series for it. // Handle the X and Y axis. if (arrayTableWidget->aSize() > 0 && arrayTableWidget->bSize() == 0) { createASeries(); // If only the second array is defined, create a series for it. // Handle the X and Y axis. }else if (arrayTableWidget->aSize() == 0 && arrayTableWidget->bSize() > 0) { createBSeries(); } else if (arrayTableWidget->aSize() > 0 && arrayTableWidget->bSize() > 0) { // If the axis is the same for the two arrays, plot them as // two unique series. if (arrayTableWidget->aAxis() == arrayTableWidget->bAxis()) { createASeries(); createBSeries(); // Otherwise, we have an X and Y axis. // Plot one series using the two arrays as an X and as a Y. }else{ if (scatterRadioButton->isChecked()) { QScatterSeries* scatter = new QScatterSeries; scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle); scatter->setMarkerSize(7); _aSeries = scatter; }else if (lineRadioButton->isChecked()) { QLineSeries* line = new QLineSeries; _aSeries = line; }else if (splineRadioButton->isChecked()) { QSplineSeries* line = new QSplineSeries; _aSeries = line; }else{ qWarning() << "Invalid line type."; return; } _aSeries->setPointsVisible(false); _aSeries->setPointLabelsVisible(false); _aSeries->setPointLabelsClipping(true); const QVector& avalues = arrayTableWidget->aArrayValues(); const QVector& bvalues = arrayTableWidget->bArrayValues(); if (arrayTableWidget->aAxis() == "X" && arrayTableWidget->bAxis() == "Y") { for (int i = 0; i < std::min(avalues.size(),bvalues.size()); ++i) { _aSeries->append(avalues[i], bvalues[i]); } }else if (arrayTableWidget->aAxis() == "Y" && arrayTableWidget->bAxis() == "X") { for (int i = 0; i < std::min(avalues.size(),bvalues.size()); ++i) { _aSeries->append(bvalues[i], avalues[i]); } }else{ qWarning() << "Invalid axis type of '" << arrayTableWidget->aAxis() << "'. Not 'X' or 'Y'."; } _aSeries->setName(aVariableName() + "/" + bVariableName()); _aSeries->setName(QString("%1:%2:%3 | %4:%5:%6") .arg(arrayTableWidget->aLabel()).arg(arrayTableWidget->aAddressOffset()).arg(arrayTableWidget->aAddressStride()) .arg(arrayTableWidget->bLabel()).arg(arrayTableWidget->bAddressOffset()).arg(arrayTableWidget->bAddressStride())); } } if (_aSeries) { QObject::connect(_aSeries, &QLineSeries::hovered, this, &SeerArrayVisualizerWidget::handleSeriesHovered); arrayChartView->chart()->addSeries(_aSeries); arrayChartView->chart()->createDefaultAxes(); redecorateScatterSeries(_aSeries); } if (_bSeries) { QObject::connect(_bSeries, &QLineSeries::hovered, this, &SeerArrayVisualizerWidget::handleSeriesHovered); arrayChartView->chart()->addSeries(_bSeries); arrayChartView->chart()->createDefaultAxes(); redecorateScatterSeries(_bSeries); } // Zoom out slightly to allow for text label at edges. arrayChartView->chart()->zoomReset(); arrayChartView->chart()->zoom(.9); arrayChartView->chart()->update(); // Check for points or labels to be shown. handlePointsCheckBox(); handleLabelsCheckBox(); } void SeerArrayVisualizerWidget::writeSettings() { QSettings settings; settings.beginGroup("arrayvisualizerwindow"); { settings.setValue("size", size()); settings.setValue("splitter", splitter->saveState()); } settings.endGroup(); } void SeerArrayVisualizerWidget::readSettings() { QSettings settings; settings.beginGroup("arrayvisualizerwindow"); { resize(settings.value("size", QSize(800, 400)).toSize()); splitter->restoreState(settings.value("splitter").toByteArray()); } settings.endGroup(); } void SeerArrayVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } void SeerArrayVisualizerWidget::handleSplitterMoved (int pos, int index) { Q_UNUSED(pos); Q_UNUSED(index); writeSettings(); } void SeerArrayVisualizerWidget::handleSeriesHovered (const QPointF& point, bool state) { //qDebug() << "QPointF=" << point << "State=" << state << "MapToPosition=" << arrayChartView->chart()->mapToPosition(point) << "MapFromScene=" << arrayChartView->mapFromScene(arrayChartView->chart()->mapToPosition(point)); if (state) { QToolTip::showText(arrayChartView->mapToGlobal(arrayChartView->mapFromScene(arrayChartView->chart()->mapToPosition(point))), QString("%1 / %2").arg(point.x()).arg(point.y()), this, QRect(), 10000); }else{ QToolTip::hideText(); } } void SeerArrayVisualizerWidget::handleTitleLineEdit () { arrayChartView->chart()->setTitle(titleLineEdit->text()); titleLineEdit->setText(""); } void SeerArrayVisualizerWidget::handlePointsCheckBox () { if (_aSeries) { _aSeries->setPointsVisible(pointsCheckBox->isChecked()); arrayChartView->chart()->update(); } if (_bSeries) { _bSeries->setPointsVisible(pointsCheckBox->isChecked()); arrayChartView->chart()->update(); } } void SeerArrayVisualizerWidget::handleLabelsCheckBox () { if (_aSeries) { _aSeries->setPointLabelsVisible(labelsCheckBox->isChecked()); arrayChartView->chart()->update(); } if (_bSeries) { _bSeries->setPointLabelsVisible(labelsCheckBox->isChecked()); arrayChartView->chart()->update(); } } void SeerArrayVisualizerWidget::handleLineTypeButtonGroup () { if (scatterRadioButton->isChecked()) { pointsCheckBox->setChecked(true); pointsCheckBox->setEnabled(false); }else{ pointsCheckBox->setChecked(false); pointsCheckBox->setEnabled(true); } handleDataChanged(); } void SeerArrayVisualizerWidget::handleThemeChanged () { // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); // And the ChartView. Seer::colorizeChartViewItem(arrayChartView, Seer::iconColorTheme()); } void SeerArrayVisualizerWidget::createASeries() { if (scatterRadioButton->isChecked()) { QScatterSeries* scatter = new QScatterSeries; scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle); scatter->setMarkerSize(7); _aSeries = scatter; }else if (lineRadioButton->isChecked()) { QLineSeries* line = new QLineSeries; _aSeries = line; }else if (splineRadioButton->isChecked()) { QSplineSeries* line = new QSplineSeries; _aSeries = line; }else{ qWarning() << "Invalid line type."; return; } _aSeries->setPointsVisible(false); _aSeries->setPointLabelsVisible(false); _aSeries->setPointLabelsClipping(true); const QVector& values = arrayTableWidget->aArrayValues(); if (arrayTableWidget->aAxis() == "Y") { for (int i = 0; i < values.size(); ++i) { _aSeries->append(i, values[i]); } }else if (arrayTableWidget->aAxis() == "X") { for (int i = 0; i < values.size(); ++i) { _aSeries->append(values[i], i); } }else{ qWarning() << "Invalid axis type of '" << arrayTableWidget->aAxis() << "'. Not 'X' or 'Y'."; } _aSeries->setName(QString("%1:%2:%3").arg(arrayTableWidget->aLabel()).arg(arrayTableWidget->aAddressOffset()).arg(arrayTableWidget->aAddressStride())); } void SeerArrayVisualizerWidget::createBSeries() { if (scatterRadioButton->isChecked()) { QScatterSeries* scatter = new QScatterSeries; scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle); scatter->setMarkerSize(7); _bSeries = scatter; }else if (lineRadioButton->isChecked()) { QLineSeries* line = new QLineSeries; _bSeries = line; }else if (splineRadioButton->isChecked()) { QSplineSeries* line = new QSplineSeries; _bSeries = line; }else{ qWarning() << "Invalid line type."; return; } _bSeries->setPointsVisible(false); _bSeries->setPointLabelsVisible(false); _bSeries->setPointLabelsClipping(true); const QVector& values = arrayTableWidget->bArrayValues(); if (arrayTableWidget->bAxis() == "Y") { for (int i = 0; i < values.size(); ++i) { _bSeries->append(i, values[i]); } }else if (arrayTableWidget->bAxis() == "X") { for (int i = 0; i < values.size(); ++i) { _bSeries->append(values[i], i); } }else{ qWarning() << "Invalid axis type of '" << arrayTableWidget->bAxis() << "'. Not 'X' or 'Y'."; } _bSeries->setName(QString("%1:%2:%3").arg(arrayTableWidget->bLabel()).arg(arrayTableWidget->bAddressOffset()).arg(arrayTableWidget->bAddressStride())); } epasveer-seer-97076f1/src/SeerArrayVisualizerWidget.h000066400000000000000000000120051526321767600226410ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerArrayVisualizerWidget.h" class SeerArrayVisualizerWidget : public QWidget, protected Ui::SeerArrayVisualizerWidgetForm { Q_OBJECT public: explicit SeerArrayVisualizerWidget (QWidget* parent = 0); ~SeerArrayVisualizerWidget (); void setAVariableName (const QString& name); QString aVariableName () const; void setAVariableAddress (const QString& address); QString aVariableAddress () const; void setAVariableLength (const QString& length); QString aVariableLength () const; void setAVariableOffset (const QString& offset); QString aVariableOffset () const; void setAVariableStride (const QString& stride); QString aVariableStride () const; void setBVariableName (const QString& name); QString bVariableName () const; void setBVariableAddress (const QString& address); QString bVariableAddress () const; void setBVariableLength (const QString& length); QString bVariableLength () const; void setBVariableOffset (const QString& offset); QString bVariableOffset () const; void setBVariableStride (const QString& stride); QString bVariableStride () const; signals: void evaluateVariableExpression (int expressionid, QString expression); void evaluateMemoryExpression (int expressionid, QString address, int count); public slots: void handleText (const QString& text); protected slots: void handleaRefreshButton (); void handlebRefreshButton (); void handleHelpButton (); void handleaVariableNameLineEdit (); void handlebVariableNameLineEdit (); void handleaElementLengthLineEdit (); void handlebElementLengthLineEdit (); void handleaElementOffsetLineEdit (); void handlebElementOffsetLineEdit (); void handleaElementStrideLineEdit (); void handlebElementStrideLineEdit (); void handleaArrayDisplayFormatComboBox (int index); void handlebArrayDisplayFormatComboBox (int index); void handleaAxisComboBox (int index); void handlebAxisComboBox (int index); void handleDataChanged (); void handleSplitterMoved (int pos, int index); void handleSeriesHovered (const QPointF& point, bool state); void handleTitleLineEdit (); void handlePointsCheckBox (); void handleLabelsCheckBox (); void handleLineTypeButtonGroup (); void handleThemeChanged (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: void readaMemory (); void readbMemory (); void createASeries (); void createBSeries (); QXYSeries* _aSeries; QXYSeries* _bSeries; int _aVariableId; int _bVariableId; int _aMemoryId; int _aLengthId; int _aOffsetId; int _aStrideId; int _bMemoryId; int _bLengthId; int _bOffsetId; int _bStrideId; }; epasveer-seer-97076f1/src/SeerArrayVisualizerWidget.ui000066400000000000000000000420151526321767600230330ustar00rootroot00000000000000 SeerArrayVisualizerWidgetForm 0 0 972 704 Form Element stride between values. (default=1) Array stride true Array data type. int16 int32 int64 uint16 uint32 uint64 float32 float64 Element stride between values. (default=1) Array stride true Total number of elements in array. # elements true Variable name or expression. Variable name true Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Element offset into array. (default=0) Array offset true Total number of elements in array. # elements true Array data type. int16 int32 int64 uint16 uint32 uint64 float32 float64 Variable address. true Variable address false Element offset into array. (default=0) Array offset true Variable address. true Variable address false Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Automatically refresh after each stopping point. Auto Variable name or expression. Variable name true Variable axis type. Y Y X Variable axis type. Y Y X 0 0 Qt::Horizontal 1 0 QLayout::SetDefaultConstraint 100 0 0 0 Set chart title. chart title true Qt::Vertical Line lineTypeButtonGroup Spline lineTypeButtonGroup Scatter lineTypeButtonGroup Qt::Vertical Show chart data points. Points Show chart data labels. Labels Qt::Vertical Print the chart. :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Help on Array Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg SeerArrayWidget QTableWidget
SeerArrayWidget.h
QZoomChartView QGraphicsView
QZoomChartView.h
SeerHistoryLineEdit QLineEdit
SeerHistoryLineEdit.h
aAxisComboBox aVariableNameLineEdit aVariableAddressLineEdit aArrayLengthLineEdit aArrayOffsetLineEdit aArrayStrideLineEdit aArrayDisplayFormatComboBox aRefreshToolButton autoRefreshCheckBox bAxisComboBox bVariableNameLineEdit bVariableAddressLineEdit bArrayLengthLineEdit bArrayOffsetLineEdit bArrayStrideLineEdit bArrayDisplayFormatComboBox bRefreshToolButton arrayTableWidget arrayChartView titleLineEdit lineRadioButton splineRadioButton scatterRadioButton pointsCheckBox labelsCheckBox printPushButton helpToolButton
epasveer-seer-97076f1/src/SeerArrayWidget.cpp000066400000000000000000000370571526321767600211340ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerArrayWidget.h" #include "SeerUtl.h" #include #include #include SeerArrayWidget::SeerArrayWidget(QWidget* parent) : QTableWidget(parent) { QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); setFont(font); setFocusPolicy(Qt::StrongFocus); setEditTriggers(QAbstractItemView::NoEditTriggers); horizontalHeader()->setDefaultAlignment(Qt::AlignRight); _aData = 0; _aAxis = "Y"; _aArrayMode = SeerArrayWidget::UnknownArrayMode; _aAddressOffset = 0; _aAddressStride = 1; _bData = 0; _bAxis = "X"; _bArrayMode = SeerArrayWidget::UnknownArrayMode; _bAddressOffset = 0; _bAddressStride = 1; _bulkUpdateDepth = 0; _createPending = false; setAAddressOffset(0); setAAddressStride(1); setBAddressOffset(0); setBAddressStride(1); } SeerArrayWidget::~SeerArrayWidget() { if (_aData) { delete _aData; } if (_bData) { delete _bData; } } int SeerArrayWidget::elementsPerLine () const { return 1; } const QString& SeerArrayWidget::aAxis () const { return _aAxis; } void SeerArrayWidget::setAAxis (const QString& axis) { _aAxis = axis; } const QString& SeerArrayWidget::aLabel () const { return _aLabel; } void SeerArrayWidget::setAAddressOffset (unsigned long offset) { _aAddressOffset = offset; // Repaint the widget. create(); } unsigned long SeerArrayWidget::aAddressOffset () const { return _aAddressOffset; } void SeerArrayWidget::setAAddressStride (unsigned long stride) { if (stride < 1) { qWarning() << "Stride is not valid." << stride; stride = 1; } _aAddressStride = stride; // Repaint the widget. create(); } unsigned long SeerArrayWidget::aAddressStride () const { return _aAddressStride; } unsigned long SeerArrayWidget::aSize () const { if (_aData) { return _aData->size(); } return 0; } unsigned long SeerArrayWidget::aElementSize () const { if (aArrayMode() == SeerArrayWidget::Int16ArrayMode) { return 2; }else if (aArrayMode() == SeerArrayWidget::UInt16ArrayMode) { return 2; }else if (aArrayMode() == SeerArrayWidget::Int32ArrayMode) { return 4; }else if (aArrayMode() == SeerArrayWidget::UInt32ArrayMode) { return 4; }else if (aArrayMode() == SeerArrayWidget::Int64ArrayMode) { return 8; }else if (aArrayMode() == SeerArrayWidget::UInt64ArrayMode) { return 8; }else if (aArrayMode() == SeerArrayWidget::Float32ArrayMode) { return 4; }else if (aArrayMode() == SeerArrayWidget::Float64ArrayMode) { return 8; } return 0; } void SeerArrayWidget::setAArrayMode (SeerArrayWidget::ArrayMode arrayMode) { _aArrayMode = arrayMode; // This repaints the widget with the new array mode create(); } SeerArrayWidget::ArrayMode SeerArrayWidget::aArrayMode () const { return _aArrayMode; } QString SeerArrayWidget::aArrayModeString () const { if (aArrayMode() == SeerArrayWidget::Int16ArrayMode) { return "int8"; }else if (aArrayMode() == SeerArrayWidget::UInt16ArrayMode) { return "uint16"; }else if (aArrayMode() == SeerArrayWidget::Int32ArrayMode) { return "int32"; }else if (aArrayMode() == SeerArrayWidget::UInt32ArrayMode) { return "uint32"; }else if (aArrayMode() == SeerArrayWidget::Int64ArrayMode) { return "int64"; }else if (aArrayMode() == SeerArrayWidget::UInt64ArrayMode) { return "uint64"; }else if (aArrayMode() == SeerArrayWidget::Float32ArrayMode) { return "float32"; }else if (aArrayMode() == SeerArrayWidget::Float64ArrayMode) { return "float64"; } return "???"; } const QVector& SeerArrayWidget::aArrayValues () const { return _aArrayValues; } const QString& SeerArrayWidget::bAxis () const { return _bAxis; } void SeerArrayWidget::setBAxis (const QString& axis) { _bAxis = axis; } const QString& SeerArrayWidget::bLabel () const { return _bLabel; } void SeerArrayWidget::setBAddressOffset (unsigned long offset) { _bAddressOffset = offset; // Repaint the widget. create(); } unsigned long SeerArrayWidget::bAddressOffset () const { return _bAddressOffset; } void SeerArrayWidget::setBAddressStride (unsigned long stride) { if (stride < 1) { qWarning() << "Stride is not valid." << stride; stride = 1; } _bAddressStride = stride; // Repaint the widget. create(); } unsigned long SeerArrayWidget::bAddressStride () const { return _bAddressStride; } unsigned long SeerArrayWidget::bSize () const { if (_bData) { return _bData->size(); } return 0; } unsigned long SeerArrayWidget::bElementSize () const { if (bArrayMode() == SeerArrayWidget::Int16ArrayMode) { return 2; }else if (bArrayMode() == SeerArrayWidget::UInt16ArrayMode) { return 2; }else if (bArrayMode() == SeerArrayWidget::Int32ArrayMode) { return 4; }else if (bArrayMode() == SeerArrayWidget::UInt32ArrayMode) { return 4; }else if (bArrayMode() == SeerArrayWidget::Int64ArrayMode) { return 8; }else if (bArrayMode() == SeerArrayWidget::UInt64ArrayMode) { return 8; }else if (bArrayMode() == SeerArrayWidget::Float32ArrayMode) { return 4; }else if (bArrayMode() == SeerArrayWidget::Float64ArrayMode) { return 8; } return 0; } void SeerArrayWidget::setBArrayMode (SeerArrayWidget::ArrayMode arrayMode) { _bArrayMode = arrayMode; // This repaints the widget with the new array mode create(); } SeerArrayWidget::ArrayMode SeerArrayWidget::bArrayMode () const { return _bArrayMode; } QString SeerArrayWidget::bArrayModeString () const { if (bArrayMode() == SeerArrayWidget::Int16ArrayMode) { return "int8"; }else if (bArrayMode() == SeerArrayWidget::UInt16ArrayMode) { return "uint16"; }else if (bArrayMode() == SeerArrayWidget::Int32ArrayMode) { return "int32"; }else if (bArrayMode() == SeerArrayWidget::UInt32ArrayMode) { return "uint32"; }else if (bArrayMode() == SeerArrayWidget::Int64ArrayMode) { return "int64"; }else if (bArrayMode() == SeerArrayWidget::UInt64ArrayMode) { return "uint64"; }else if (bArrayMode() == SeerArrayWidget::Float32ArrayMode) { return "float32"; }else if (bArrayMode() == SeerArrayWidget::Float64ArrayMode) { return "float64"; } return "???"; } const QVector& SeerArrayWidget::bArrayValues () const { return _bArrayValues; } void SeerArrayWidget::setAData(const QString& label, SeerArrayWidget::DataStorage* pData) { if (_aData) { delete _aData; } _aLabel = label; _aData = pData; // Repaint the widget. create(); } void SeerArrayWidget::setBData(const QString& label, SeerArrayWidget::DataStorage* pData) { if (_bData) { delete _bData; } _bLabel = label; _bData = pData; // Repaint the widget. create(); } void SeerArrayWidget::create () { // Coalesce a burst of property changes: while a bulk update is active, // defer the (expensive) table rebuild and just record that one is pending. // endBulkUpdate() performs the single rebuild once the burst is complete. if (_bulkUpdateDepth > 0) { _createPending = true; return; } // Clear the table. We're going to recreate it. clear(); setRowCount(0); if (_aData && _bData) { setColumnCount(2); _aColumnId = 0; _bColumnId = 1; }else if (_aData) { setColumnCount(1); _aColumnId = 0; _bColumnId = -1; }else if (_bData) { setColumnCount(1); _aColumnId = -1; _bColumnId = 0; }else{ setColumnCount(0); _aColumnId = -1; _bColumnId = -1; } // Clear the values. _aArrayValues.resize(0); _bArrayValues.resize(0); // If there's no data, do nothing. if (!_aData && !_bData) { emit dataChanged(); return; } if (aElementSize() < 1 && bElementSize() < 1) { emit dataChanged(); return; } if (_aData) { //qDebug() << "_aData" << aElementSize() << aAddressOffset() << aAddressStride() << _aData->size(); setHorizontalHeaderItem(_aColumnId, new QTableWidgetItem(QString("%1:%2:%3").arg(aLabel()).arg(aAddressOffset()).arg(aAddressStride()))); int row = 0; for (int i=aElementSize()*aAddressOffset(); i<_aData->size(); i+=aElementSize()*aAddressStride()) { // Add new row if we need to. Set its label. if (row == rowCount()) { //qDebug() << "Adding row" << row << "for _aData"; insertRow(rowCount()); QTableWidgetItem* rowHeaderitem = new QTableWidgetItem(QString::number(row)); rowHeaderitem->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); setVerticalHeaderItem(row, rowHeaderitem); } QTableWidgetItem* item = new QTableWidgetItem; item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); QByteArray element = _aData->getData(i, aElementSize()); double val = 0.0; if (aArrayMode() == SeerArrayWidget::Int16ArrayMode) { short v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::UInt16ArrayMode) { unsigned short v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::Int32ArrayMode) { int v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::UInt32ArrayMode) { unsigned int v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::Int64ArrayMode) { long v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::UInt64ArrayMode) { unsigned long v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::Float32ArrayMode) { float v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (aArrayMode() == SeerArrayWidget::Float64ArrayMode) { double v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else{ qWarning() << "Unknown data type."; val = 0.0; } //qDebug() << "Adding item" << row << 0 << "for _aData"; setItem(row, _aColumnId, item); _aArrayValues.push_back(val); row++; } } if (_bData) { //qDebug() << "_bData" << bElementSize() << bAddressOffset() << bAddressStride() << _bData->size(); setHorizontalHeaderItem(_bColumnId, new QTableWidgetItem(QString("%1:%2:%3").arg(bLabel()).arg(bAddressOffset()).arg(bAddressStride()))); int row = 0; for (int i=bElementSize()*bAddressOffset(); i<_bData->size(); i+=bElementSize()*bAddressStride()) { // Add new row if we need to. Set its label. if (row == rowCount()) { //qDebug() << "Adding row" << row << "for _bData"; insertRow(rowCount()); QTableWidgetItem* rowHeaderitem = new QTableWidgetItem(QString::number(row)); rowHeaderitem->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); setVerticalHeaderItem(row, rowHeaderitem); } QTableWidgetItem* item = new QTableWidgetItem; item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); QByteArray element = _bData->getData(i, bElementSize()); double val = 0.0; if (bArrayMode() == SeerArrayWidget::Int16ArrayMode) { short v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::UInt16ArrayMode) { unsigned short v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::Int32ArrayMode) { int v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::UInt32ArrayMode) { unsigned int v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::Int64ArrayMode) { long v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::UInt64ArrayMode) { unsigned long v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::Float32ArrayMode) { float v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else if (bArrayMode() == SeerArrayWidget::Float64ArrayMode) { double v = *reinterpret_cast(element.data()); val = v; item->setText(QString::number(v)); }else{ qWarning() << "Unknown data type."; val = 0.0; } //qDebug() << "Adding item" << row << 0 << "for _bData"; setItem(row, _bColumnId, item); _bArrayValues.push_back(val); row++; } } emit dataChanged(); } void SeerArrayWidget::beginBulkUpdate () { _bulkUpdateDepth++; } void SeerArrayWidget::endBulkUpdate () { if (_bulkUpdateDepth > 0) { _bulkUpdateDepth--; } // Once fully unwound, do the single deferred rebuild (if any setter fired). if (_bulkUpdateDepth == 0 && _createPending) { _createPending = false; create(); } } SeerArrayWidget::BulkUpdate::BulkUpdate (SeerArrayWidget* widget) : _widget(widget) { _widget->beginBulkUpdate(); } SeerArrayWidget::BulkUpdate::~BulkUpdate () { _widget->endBulkUpdate(); } SeerArrayWidget::DataStorageArray::DataStorageArray(const QByteArray& arr) { _data = arr; } QByteArray SeerArrayWidget::DataStorageArray::getData(int position, int length) { return _data.mid(position, length); } int SeerArrayWidget::DataStorageArray::size() { return _data.size(); } epasveer-seer-97076f1/src/SeerArrayWidget.h000066400000000000000000000125211526321767600205660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerArrayWidget: public QTableWidget { Q_OBJECT public: class DataStorage { public: virtual ~DataStorage() {}; virtual QByteArray getData(int position, int length) = 0; virtual int size() = 0; }; class DataStorageArray: public DataStorage { public: DataStorageArray(const QByteArray& arr); virtual QByteArray getData(int position, int length); virtual int size(); private: QByteArray _data; }; enum ArrayMode { UnknownArrayMode = 0, Int16ArrayMode = 1, UInt16ArrayMode = 2, Int32ArrayMode = 3, UInt32ArrayMode = 4, Int64ArrayMode = 5, UInt64ArrayMode = 6, Float32ArrayMode = 7, Float64ArrayMode = 8 }; SeerArrayWidget(QWidget* parent = 0); ~SeerArrayWidget(); int elementsPerLine () const; // RAII guard: coalesces a burst of property changes into a single // rebuild. While a guard is alive create() is deferred; the single // rebuild happens when it goes out of scope. Nesting is supported. // Prefer a guard over the private begin/end pair so the matching end // is guaranteed even on early return or exception. class BulkUpdate { public: explicit BulkUpdate (SeerArrayWidget* widget); ~BulkUpdate (); BulkUpdate (const BulkUpdate&) = delete; BulkUpdate& operator= (const BulkUpdate&) = delete; private: SeerArrayWidget* _widget; }; const QString& aAxis () const; void setAAxis (const QString& axis); const QString& aLabel () const; void setAAddressOffset (unsigned long offset); unsigned long aAddressOffset () const; void setAAddressStride (unsigned long stride); unsigned long aAddressStride () const; unsigned long aSize () const; unsigned long aElementSize () const; void setAArrayMode (SeerArrayWidget::ArrayMode arrayMode); SeerArrayWidget::ArrayMode aArrayMode () const; QString aArrayModeString () const; const QVector& aArrayValues () const; const QString& bAxis () const; void setBAxis (const QString& axis); const QString& bLabel () const; void setBAddressOffset (unsigned long offset); unsigned long bAddressOffset () const; void setBAddressStride (unsigned long stride); unsigned long bAddressStride () const; unsigned long bSize () const; unsigned long bElementSize () const; void setBArrayMode (SeerArrayWidget::ArrayMode arrayMode); SeerArrayWidget::ArrayMode bArrayMode () const; QString bArrayModeString () const; const QVector& bArrayValues () const; signals: void dataChanged (); public slots: void setAData (const QString& label, DataStorage* pData); void setBData (const QString& label, DataStorage* pData); protected: private: void create (); void beginBulkUpdate (); void endBulkUpdate (); int _bulkUpdateDepth; bool _createPending; QString _aAxis; QString _aLabel; int _aColumnId; DataStorage* _aData; unsigned long _aAddressOffset; unsigned long _aAddressStride; SeerArrayWidget::ArrayMode _aArrayMode; QVector _aArrayValues; QString _bAxis; QString _bLabel; int _bColumnId; DataStorage* _bData; unsigned long _bAddressOffset; unsigned long _bAddressStride; SeerArrayWidget::ArrayMode _bArrayMode; QVector _bArrayValues; }; epasveer-seer-97076f1/src/SeerAsmWidget.cpp000066400000000000000000000103521526321767600205630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAsmWidget.h" #include "SeerUtl.h" #include #include SeerAsmWidget::SeerAsmWidget(QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); plainTextEdit->setFont(font); plainTextEdit->setFocusPolicy(Qt::StrongFocus); plainTextEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse); plainTextEdit->setWordWrapMode(QTextOption::NoWrap); // Set text formats. _defaultFormat = plainTextEdit->currentCharFormat(); _grayFormat = _defaultFormat; _grayFormat.setBackground(QBrush(Qt::lightGray)); // Connect things. } SeerAsmWidget::~SeerAsmWidget() { } QTextDocument* SeerAsmWidget::document () { return plainTextEdit->document(); } QString SeerAsmWidget::toPlainText () { return plainTextEdit->toPlainText(); } void SeerAsmWidget::setData (const QString& data) { // ^done,asm_insns=[ // {address="0x000000000040093c",func-name="main()",offset="362",inst="mov $0x400aa9,%edi"}, // {address="0x0000000000400941",func-name="main()",offset="367",inst="call 0x400680 "}, // {address="0x0000000000400946",func-name="main()",offset="372",inst="mov -0x30(%rbp),%rax"} // ] // Clear the document. plainTextEdit->clear(); // Get a cursor QTextCursor cursor(plainTextEdit->textCursor()); cursor.movePosition(QTextCursor::Start); // Prepare the 'data' for parsing. QString asm_insns_text = Seer::parseFirst(data, "asm_insns=", '[', ']', false); QStringList asm_list = Seer::parse(asm_insns_text, "", '{', '}', false); // Loop through the asm list to get maximum field widths. int address_width = QString("Address").length(); int opcode_width = QString("Opcode").length(); int inst_width = QString("Assembly").length(); for ( const auto& asm_text : asm_list ) { QString address_text = Seer::parseFirst(asm_text, "address=", '"', '"', false); QString opcodes_text = Seer::parseFirst(asm_text, "opcodes=", '"', '"', false); QString inst_text = Seer::parseFirst(asm_text, "inst=", '"', '"', false); address_width = std::max((qsizetype)address_width, (qsizetype)address_text.length()); opcode_width = std::max((qsizetype)opcode_width, (qsizetype)opcodes_text.length()); inst_width = std::max((qsizetype)inst_width, (qsizetype)inst_text.length()); } // Write header. cursor.insertText (QString("Address").leftJustified(address_width, ' ', true), _grayFormat); cursor.insertText (QString(" "), _defaultFormat); cursor.insertText (QString("Opcodes").leftJustified(opcode_width, ' ', true), _defaultFormat); cursor.insertText (QString(" | "), _defaultFormat); cursor.insertText (QString("Assembly"), _defaultFormat); cursor.insertText (QString("\n"), _defaultFormat); // Loop through the asm list and print each line. for ( const auto& asm_text : asm_list ) { // Get the strings, with padding. QString address_text = Seer::parseFirst(asm_text, "address=", '"', '"', false).leftJustified(address_width, ' ', true); QString opcodes_text = Seer::parseFirst(asm_text, "opcodes=", '"', '"', false).leftJustified(opcode_width, ' ', true); QString inst_text = Seer::parseFirst(asm_text, "inst=", '"', '"', false).leftJustified(inst_width, ' ', true); // Write the text, with spacers. cursor.insertText (address_text, _grayFormat); cursor.insertText (QString(" "), _defaultFormat); cursor.insertText (opcodes_text, _defaultFormat); cursor.insertText (QString(" | "), _defaultFormat); cursor.insertText (inst_text, _defaultFormat); // Write eol to document. cursor.insertText (QString("\n"), _defaultFormat); } // Move to the start of the document. cursor.movePosition(QTextCursor::Start); plainTextEdit->setTextCursor(cursor); } epasveer-seer-97076f1/src/SeerAsmWidget.h000066400000000000000000000013751526321767600202350ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "ui_SeerAsmWidget.h" class SeerAsmWidget: public QWidget, protected Ui::SeerAsmWidgetForm { Q_OBJECT public: SeerAsmWidget(QWidget* parent = 0); ~SeerAsmWidget(); QTextDocument* document (); QString toPlainText (); signals: public slots: void setData (const QString& data); protected: protected slots: private: QTextCharFormat _defaultFormat; QTextCharFormat _grayFormat; }; epasveer-seer-97076f1/src/SeerAsmWidget.ui000066400000000000000000000016641526321767600204240ustar00rootroot00000000000000 SeerAsmWidgetForm 0 0 907 643 Form 0 100 true Qt::NoTextInteraction epasveer-seer-97076f1/src/SeerAssemblyConfigPage.cpp000066400000000000000000000100551526321767600224010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAssemblyConfigPage.h" #include #include SeerAssemblyConfigPage::SeerAssemblyConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Setup the widgets reset(); // Connect things. } SeerAssemblyConfigPage::~SeerAssemblyConfigPage() { } QString SeerAssemblyConfigPage::showAssemblyTabOnStartupMode () const { return showAssemblyTabComboBox->currentText(); } bool SeerAssemblyConfigPage::keepAssemblyTabOnTop () const { return assemblyTabOnTopCheckBox->isChecked(); } QString SeerAssemblyConfigPage::disassemblyFlavor () const { if (attFlavorRadioButton->isChecked()) { return "att"; }else if (intelFlavorRadioButton->isChecked()) { return "intel"; }else{ return ""; } } QString SeerAssemblyConfigPage::symbolDemagling () const { if (demanglingOnRadioButton->isChecked()) { return "on"; }else if (demanglingOffRadioButton->isChecked()) { return "off"; }else{ return ""; } } bool SeerAssemblyConfigPage::showAddressColumn () const { return showAddressCheckBox->isChecked(); } bool SeerAssemblyConfigPage::showOffsetColumn () const { return showOffsetCheckBox->isChecked(); } bool SeerAssemblyConfigPage::showOpcodeColumn () const { return showOpcodeCheckBox->isChecked(); } bool SeerAssemblyConfigPage::showSourceLines () const { return showSourceCheckBox->isChecked(); } QString SeerAssemblyConfigPage::registerFormat () const { return registerFormatComboBox->currentText(); } QString SeerAssemblyConfigPage::disassemblyMode () const { if (pcFunctionRadioButton->isChecked()) { return "function"; }else if (pcLengthRadioButton->isChecked()) { return "length"; }else{ return "unknown"; } } int SeerAssemblyConfigPage::disassemblyBytes () const { return pcLengthSpinBox->value(); } void SeerAssemblyConfigPage::setShowAssemblyTabOnStartupMode (const QString& mode) { showAssemblyTabComboBox->setCurrentText(mode); } void SeerAssemblyConfigPage::setKeepAssemblyTabOnTop (bool flag) { assemblyTabOnTopCheckBox->setChecked(flag); } void SeerAssemblyConfigPage::setDisassemblyFlavor (const QString& flavor) { if (flavor == "att") { attFlavorRadioButton->setChecked(true); }else if (flavor == "intel") { intelFlavorRadioButton->setChecked(true); }else{ } } void SeerAssemblyConfigPage::setSymbolDemagling (const QString& onoff) { if (onoff == "on") { demanglingOnRadioButton->setChecked(true); }else if (onoff == "off") { demanglingOffRadioButton->setChecked(true); }else{ } } void SeerAssemblyConfigPage::setShowAddressColumn (bool flag) { showAddressCheckBox->setChecked(flag); } void SeerAssemblyConfigPage::setShowOffsetColumn (bool flag) { showOffsetCheckBox->setChecked(flag); } void SeerAssemblyConfigPage::setShowOpcodeColumn (bool flag) { showOpcodeCheckBox->setChecked(flag); } void SeerAssemblyConfigPage::setShowSourceLines (bool flag) { showSourceCheckBox->setChecked(flag); } void SeerAssemblyConfigPage::setRegisterFormat (const QString& format) { registerFormatComboBox->setCurrentText(format); } void SeerAssemblyConfigPage::setDisassemblyMode (const QString& mode, int bytes) { if (mode == "function") { pcFunctionRadioButton->setChecked(true); }else if (mode == "length") { pcLengthRadioButton->setChecked(true); }else{ pcFunctionRadioButton->setChecked(true); } pcLengthSpinBox->setValue(bytes); } void SeerAssemblyConfigPage::reset () { setShowAssemblyTabOnStartupMode("never"); setKeepAssemblyTabOnTop(true); setDisassemblyFlavor("att"); setSymbolDemagling("on"); setShowAddressColumn(true); setShowOffsetColumn(false); setShowOpcodeColumn(false); setShowSourceLines(false); setRegisterFormat("Natural"); setDisassemblyMode("function", 256); } epasveer-seer-97076f1/src/SeerAssemblyConfigPage.h000066400000000000000000000047141526321767600220530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerAssemblyConfigPage.h" class SeerAssemblyConfigPage : public QWidget, protected Ui::SeerAssemblyConfigPage { Q_OBJECT public: explicit SeerAssemblyConfigPage (QWidget* parent = 0); ~SeerAssemblyConfigPage (); QString showAssemblyTabOnStartupMode () const; bool keepAssemblyTabOnTop () const; QString disassemblyFlavor () const; QString symbolDemagling () const; bool showAddressColumn () const; bool showOffsetColumn () const; bool showOpcodeColumn () const; bool showSourceLines () const; QString registerFormat () const; QString disassemblyMode () const; int disassemblyBytes () const; void setShowAssemblyTabOnStartupMode (const QString& mode); void setKeepAssemblyTabOnTop (bool flag); void setDisassemblyFlavor (const QString& flavor); void setSymbolDemagling (const QString& onoff); void setShowAddressColumn (bool flag); void setShowOffsetColumn (bool flag); void setShowOpcodeColumn (bool flag); void setShowSourceLines (bool flag); void setRegisterFormat (const QString& format); void setDisassemblyMode (const QString& mode, int bytes); void reset (); protected slots: }; epasveer-seer-97076f1/src/SeerAssemblyConfigPage.ui000066400000000000000000000570261526321767600222450ustar00rootroot00000000000000 SeerAssemblyConfigPage 0 0 926 901 SeerAssemblyConfigPage Assembly Settings Show Assembly tab on startup Qt::Horizontal QSizePolicy::Fixed 27 20 never always auto Qt::Horizontal 616 20 Keep Assembly tab on top Qt::Horizontal 616 20 Qt::Vertical QSizePolicy::Fixed 20 20 Disassembly Flavor Qt::Horizontal QSizePolicy::Fixed 27 20 att disassemblyFlavorButtonGroup intel disassemblyFlavorButtonGroup Qt::Horizontal QSizePolicy::Preferred 616 20 Symbol Demangling Qt::Horizontal QSizePolicy::Fixed 27 20 on assemblyDemangleButtonGroup off assemblyDemangleButtonGroup Qt::Horizontal QSizePolicy::Preferred 616 20 Show Columns in Editor Qt::Horizontal 40 20 Address Offset Opcode Source Register Format Qt::Horizontal QSizePolicy::Fixed 27 20 Natural Hex Octal Binary Decimal Raw Qt::Horizontal QSizePolicy::Preferred 616 20 Disassembly Mode Qt::Horizontal QSizePolicy::Fixed 38 20 Start and end address is defined by current function. Function disassemblyModeButtonGroup <html><head/><body><p>End address is defined by N bytes after current $PC</p></body></html> Length disassemblyModeButtonGroup Number of bytes after current $PC 9999 100 Qt::Horizontal QSizePolicy::Expanding 373 20 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Set various Assembly and Register settings.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">Seer can show the program's assembly as a tab in the Code Manager. The Assembly tab can be shown automatically when Seer starts. There are these start up modes.</span></p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Never. Seer won't show the assembly tab at start up.</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Always. Seer will always show the assembly tab.</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Auto. Seer will show the the assembly tab if there is no source file to show.</li></ul> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">The assembly tab can always be shown with:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Monospace';"> View-&gt;Assembly View</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Monospace';"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">When enabled, the Assembly tab will tend to stay in the background (ie:hidden by any Source tabs) as the program is stepped through. If set, the Assembly tab can be forced to always stay on top, even while stepping through the program. Manually clicking on the tabs will still raise them, though.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">When presenting the assembly, there are 2 flavors. 'att' and 'intel'.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Monospace';"> att: mov 0xc(%ebp),%eax<br /> intel: mov eax, DWORDPTR [ebp+0xc]</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Monospace';"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">When printing certain symbols, the mangled or demangled symbol names can be printed.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Monospace';"> mangled: callq 0x4007b8 &lt;_ZNSolsEPFRSoS_E@plt&gt;<br /> demanlged: callq 0x4007b8 &lt;std::ostream::operator&lt;&lt;(std::ostream&amp;(*)(std::ostream&amp;))@plt&gt;</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Monospace';"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Monospace';"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Monospace';">The Assembly Editor can show different columns along side the assembly. These can be quickly changed in the Assembly Editor using ^F.</span></p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Address</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Offset</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Opcode</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Source</li></ul> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Assembly Editor does its best to show relevant assembly. This means setting the 'start' and 'end' address of the disassembly. There are two modes.</p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Function - The start and end address is defined by the function the current $PC is in. Needs debug information. Otherwise, a blank editor is shown.</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Length - A number of bytes after the current $PC is shown.</li></ul> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">In the Register browser, register values can be shown in various formats:</span></p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">Natural (A predefined format, based on the register name)</span></li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hex</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Octal</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Binary</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decimal</li> <li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Raw</li></ul></body></html> textBrowser printPointGroupBox assemblyTabOnTopCheckBox attFlavorRadioButton intelFlavorRadioButton demanglingOnRadioButton demanglingOffRadioButton showAddressCheckBox showOffsetCheckBox showOpcodeCheckBox registerFormatComboBox textBrowser epasveer-seer-97076f1/src/SeerAssemblyPreferenceDialog.cpp000066400000000000000000000055551526321767600236060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerAssemblyPreferenceDialog.h" #include #include SeerAssemblyPreferenceDialog::SeerAssemblyPreferenceDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets // Connect things. // Restore window settings. readSettings(); } SeerAssemblyPreferenceDialog::~SeerAssemblyPreferenceDialog () { } void SeerAssemblyPreferenceDialog::setRegiserNamePC (const QString& name) { pcLineEdit->setText(name); } QString SeerAssemblyPreferenceDialog::regiserNamePC () const { return pcLineEdit->text(); } void SeerAssemblyPreferenceDialog::setRegiserNameFLAGS (const QString& name) { flagsLineEdit->setText(name); } QString SeerAssemblyPreferenceDialog::regiserNameFLAGS () const { return flagsLineEdit->text(); } void SeerAssemblyPreferenceDialog::setRegiserNameSP (const QString& name) { spLineEdit->setText(name); } QString SeerAssemblyPreferenceDialog::regiserNameSP () const { return spLineEdit->text(); } void SeerAssemblyPreferenceDialog::setShowAssemblyAddress (bool flag) { showAddressCheckBox->setChecked(flag); } bool SeerAssemblyPreferenceDialog::showAssemblyAddress () const { return showAddressCheckBox->isChecked(); } void SeerAssemblyPreferenceDialog::setShowAssemblyOffset (bool flag) { showOffsetCheckBox->setChecked(flag); } bool SeerAssemblyPreferenceDialog::showAssemblyOffset () const { return showOffsetCheckBox->isChecked(); } void SeerAssemblyPreferenceDialog::setShowAssemblyOpcode (bool flag) { showOpcodeCheckBox->setChecked(flag); } bool SeerAssemblyPreferenceDialog::showAssemblyOpcode () const { return showOpcodeCheckBox->isChecked(); } void SeerAssemblyPreferenceDialog::setShowAssemblySource (bool flag) { showSourceCheckBox->setChecked(flag); } bool SeerAssemblyPreferenceDialog::showAssemblySource () const { return showSourceCheckBox->isChecked(); } void SeerAssemblyPreferenceDialog::setConvertUppercase (bool flag) { convertUppercaseRadioButton->setChecked(flag); } bool SeerAssemblyPreferenceDialog::convertUppercase () const { return convertUppercaseRadioButton->isChecked(); } void SeerAssemblyPreferenceDialog::writeSettings() { QSettings settings; settings.beginGroup("registerpreferencedialog"); { settings.setValue("size", size()); }settings.endGroup(); } void SeerAssemblyPreferenceDialog::readSettings() { QSettings settings; settings.beginGroup("registerpreferencedialog"); { resize(settings.value("size", QSize(350, 300)).toSize()); } settings.endGroup(); } void SeerAssemblyPreferenceDialog::resizeEvent (QResizeEvent* event) { // Write window settings. writeSettings(); QWidget::resizeEvent(event); } epasveer-seer-97076f1/src/SeerAssemblyPreferenceDialog.h000066400000000000000000000037651526321767600232540ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerAssemblyPreferenceDialog.h" class SeerAssemblyPreferenceDialog : public QDialog, protected Ui::SeerAssemblyPreferenceDialogForm { Q_OBJECT public: explicit SeerAssemblyPreferenceDialog (QWidget* parent = 0); ~SeerAssemblyPreferenceDialog (); void setRegiserNamePC (const QString& name); QString regiserNamePC () const; void setRegiserNameFLAGS (const QString& name); QString regiserNameFLAGS () const; void setRegiserNameSP (const QString& name); QString regiserNameSP () const; void setShowAssemblyAddress (bool flag); bool showAssemblyAddress () const; void setShowAssemblyOffset (bool flag); bool showAssemblyOffset () const; void setShowAssemblyOpcode (bool flag); bool showAssemblyOpcode () const; void setShowAssemblySource (bool flag); bool showAssemblySource () const; void setConvertUppercase (bool flag); bool convertUppercase () const; public slots: private slots: protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: }; epasveer-seer-97076f1/src/SeerAssemblyPreferenceDialog.ui000066400000000000000000000151561526321767600234370ustar00rootroot00000000000000 SeerAssemblyPreferenceDialogForm 0 0 357 368 Seer - Assembly Preferences Editor CPU Registers PC PC register name PC register name ($pc) true FLAGS CPU flags register name CPU Flags register name ($ps) true SP SP register name SP register name ($sp) true Assembly Details Show assembly address. Address Show assembly offset. Offset Show assembly opcodes. Opcode Show original source code. Source Qt::Horizontal 66 20 Assembly Text Convert Assembly text to uppercase letters. Convert To Uppercase Qt::Vertical 20 27 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok groupBox_2 buttonBox groupBox_1 groupBox_3 pcLineEdit flagsLineEdit spLineEdit showAddressCheckBox showOffsetCheckBox showOpcodeCheckBox showSourceCheckBox buttonBox accepted() SeerAssemblyPreferenceDialogForm accept() 248 254 157 274 buttonBox rejected() SeerAssemblyPreferenceDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerBreakpointCreateDialog.cpp000066400000000000000000000137701526321767600232500ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerBreakpointCreateDialog.h" #include SeerBreakpointCreateDialog::SeerBreakpointCreateDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets setFilename(""); setFunctionName(""); setLabelName(""); setLineNumber(""); setAddress(""); setTemporaryEnabled (false); setHardwareEnabled (false); setPendingEnabled (false); setDisabledEnabled (false); setConditionalEnabled (false); setIgnoreCountEnabled (false); setThreadIdEnabled (false); setConditionalText (""); setIgnoreCountText (""); setThreadIdText (""); filenameLineEdit->setFocus(); // Connect things. QObject::connect(conditionalCheckBox, &QCheckBox::clicked, conditionalLineEdit, &QLineEdit::setEnabled); QObject::connect(ignoreCountCheckBox, &QCheckBox::clicked, ignoreCountLineEdit, &QLineEdit::setEnabled); QObject::connect(threadIdCheckBox, &QCheckBox::clicked, threadIdLineEdit, &QLineEdit::setEnabled); } SeerBreakpointCreateDialog::~SeerBreakpointCreateDialog () { } void SeerBreakpointCreateDialog::setFilename (const QString& text) { filenameLineEdit->setText(text); } void SeerBreakpointCreateDialog::setFunctionName (const QString& text) { functionLineEdit->setText(text); } void SeerBreakpointCreateDialog::setLabelName (const QString& text) { labelLineEdit->setText(text); } void SeerBreakpointCreateDialog::setLineNumber (const QString& text) { lineNumberLineEdit->setText(text); } void SeerBreakpointCreateDialog::setAddress (const QString& text) { addressLineEdit->setText(text); } QString SeerBreakpointCreateDialog::filenameText () const { return filenameLineEdit->text(); } QString SeerBreakpointCreateDialog::functionNameText () const { return functionLineEdit->text(); } QString SeerBreakpointCreateDialog::labelNameText () const { return labelLineEdit->text(); } QString SeerBreakpointCreateDialog::lineNumberText () const { return lineNumberLineEdit->text(); } QString SeerBreakpointCreateDialog::addressText () const { return addressLineEdit->text(); } void SeerBreakpointCreateDialog::setTemporaryEnabled (bool flag) { temporaryCheckBox->setChecked(flag); } void SeerBreakpointCreateDialog::setHardwareEnabled (bool flag) { hardwareCheckBox->setChecked(flag); } void SeerBreakpointCreateDialog::setPendingEnabled (bool flag) { pendingCheckBox->setChecked(flag); } void SeerBreakpointCreateDialog::setDisabledEnabled (bool flag) { disabledCheckBox->setChecked(flag); } void SeerBreakpointCreateDialog::setConditionalEnabled (bool flag) { conditionalCheckBox->setChecked(flag); conditionalLineEdit->setEnabled(flag); } void SeerBreakpointCreateDialog::setIgnoreCountEnabled (bool flag) { ignoreCountCheckBox->setChecked(flag); ignoreCountLineEdit->setEnabled(flag); } void SeerBreakpointCreateDialog::setThreadIdEnabled (bool flag) { threadIdCheckBox->setChecked(flag); threadIdLineEdit->setEnabled(flag); } void SeerBreakpointCreateDialog::setConditionalText (const QString& text) { conditionalLineEdit->setText(text); } void SeerBreakpointCreateDialog::setIgnoreCountText (const QString& text) { ignoreCountLineEdit->setText(text); } void SeerBreakpointCreateDialog::setThreadIdText (const QString& text) { threadIdLineEdit->setText(text); } bool SeerBreakpointCreateDialog::temporaryEnabled () const { return temporaryCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::hardwareEnabled () const { return hardwareCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::pendingEnabled () const { return pendingCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::disabledEnabled () const { return disabledCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::conditionalEnabled () const { return conditionalCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::ignoreCountEnabled () const { return ignoreCountCheckBox->isChecked(); } bool SeerBreakpointCreateDialog::threadIdEnabled () const { return threadIdCheckBox->isChecked(); } QString SeerBreakpointCreateDialog::conditionalText () const { return conditionalLineEdit->text(); } QString SeerBreakpointCreateDialog::ignoreCountText () const { return ignoreCountLineEdit->text(); } QString SeerBreakpointCreateDialog::threadIdText () const { return threadIdLineEdit->text(); } QString SeerBreakpointCreateDialog::breakpointText () const { // Build a breakpoint specification. QString breakpointParameters; if (temporaryEnabled()) { breakpointParameters += " -t"; } if (hardwareEnabled()) { breakpointParameters += " -h"; } if (pendingEnabled()) { breakpointParameters += " -f"; } if (disabledEnabled()) { breakpointParameters += " -d"; } if (conditionalEnabled()) { if (conditionalText() != "") { QString str = conditionalText().replace('"', "\\\""); // Quote " characters. breakpointParameters += " -c \"" + str + "\""; } } if (ignoreCountEnabled()) { if (ignoreCountText() != "") { breakpointParameters += " -i " + ignoreCountText(); } } if (threadIdEnabled()) { if (threadIdText() != "") { breakpointParameters += " -p " + threadIdText(); } } if (filenameText() != "") { breakpointParameters += " --source \"" + filenameText() + "\""; } if (functionNameText() != "") { breakpointParameters += " --function \"" + functionNameText() + "\""; } if (labelNameText() != "") { breakpointParameters += " --label " + labelNameText(); } if (lineNumberText() != "") { breakpointParameters += " --line " + lineNumberText(); } if (addressText() != "") { breakpointParameters += " *" + addressText(); } return breakpointParameters; } epasveer-seer-97076f1/src/SeerBreakpointCreateDialog.h000066400000000000000000000047661526321767600227220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerBreakpointCreateDialog.h" class SeerBreakpointCreateDialog : public QDialog, protected Ui::SeerBreakpointCreateDialogForm { Q_OBJECT public: explicit SeerBreakpointCreateDialog (QWidget* parent = 0); ~SeerBreakpointCreateDialog (); void setFilename (const QString& text); void setFunctionName (const QString& text); void setLabelName (const QString& text); void setLineNumber (const QString& text); void setAddress (const QString& text); QString filenameText () const; QString functionNameText () const; QString labelNameText () const; QString lineNumberText () const; QString addressText () const; void setTemporaryEnabled (bool flag); void setHardwareEnabled (bool flag); void setPendingEnabled (bool flag); void setDisabledEnabled (bool flag); void setConditionalEnabled (bool flag); void setIgnoreCountEnabled (bool flag); void setThreadIdEnabled (bool flag); void setConditionalText (const QString& text); void setIgnoreCountText (const QString& text); void setThreadIdText (const QString& text); bool temporaryEnabled () const; bool hardwareEnabled () const; bool pendingEnabled () const; bool disabledEnabled () const; bool conditionalEnabled () const; bool ignoreCountEnabled () const; bool threadIdEnabled () const; QString conditionalText () const; QString ignoreCountText () const; QString threadIdText () const; QString breakpointText () const; public slots: private: }; epasveer-seer-97076f1/src/SeerBreakpointCreateDialog.ui000066400000000000000000000175361526321767600231070ustar00rootroot00000000000000 SeerBreakpointCreateDialogForm 0 0 525 429 Create a Breakpoint Breakpoint Location Filename true Line number true Qt::Horizontal 40 20 Function true Label true Qt::Horizontal 40 20 Address true Qt::Horizontal 243 20 Breakpoint Type Temporary Condition if: true Hardware Ignore Count true Qt::Horizontal 131 20 Pending Thread Id true Qt::Horizontal 131 20 Disabled Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerBreakpointCreateDialogForm accept() 248 254 157 274 buttonBox rejected() SeerBreakpointCreateDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerBreakpointsBrowserWidget.cpp000066400000000000000000000406171526321767600236770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerBreakpointsBrowserWidget.h" #include "SeerBreakpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerBreakpointsBrowserWidget::SeerBreakpointsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets breakpointsTreeWidget->clear(); breakpointsTreeWidget->setSortingEnabled(false); breakpointsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); breakpointsTreeWidget->resizeColumnToContents(0); // number breakpointsTreeWidget->resizeColumnToContents(1); // type breakpointsTreeWidget->resizeColumnToContents(2); // disp breakpointsTreeWidget->resizeColumnToContents(3); // enabled breakpointsTreeWidget->resizeColumnToContents(4); // addr //breakpointsTreeWidget->resizeColumnToContents(5); // func Too long to show breakpointsTreeWidget->resizeColumnToContents(6); // file //breakpointsTreeWidget->resizeColumnToContents(7); // fullname Too long to show breakpointsTreeWidget->resizeColumnToContents(8); // line breakpointsTreeWidget->resizeColumnToContents(9); // thread-groups breakpointsTreeWidget->resizeColumnToContents(10); // cond breakpointsTreeWidget->resizeColumnToContents(11); // times breakpointsTreeWidget->resizeColumnToContents(12); // ignore //breakpointsTreeWidget->resizeColumnToContents(13); // script Too long to show breakpointsTreeWidget->resizeColumnToContents(14); // original-location /* breakpointsTreeWidget->setColumnHidden(1, true); // ??? Hide or have a config to hide/show columns. breakpointsTreeWidget->setColumnHidden(6, true); */ // Connect things. QObject::connect(breakpointsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerBreakpointsBrowserWidget::handleItemDoubleClicked); QObject::connect(refreshBreakpointsToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleRefreshToolButton); QObject::connect(addBreakpointToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleAddToolButton); QObject::connect(deleteBreakpointsToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleDeleteToolButton); QObject::connect(enableBreakpointsToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleEnableToolButton); QObject::connect(disableBreakpointsToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleDisableToolButton); QObject::connect(conditionBreakpointToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleConditionToolButton); QObject::connect(ignoreBreakpointToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleIgnoreToolButton); QObject::connect(commandsBreakpointToolButton, &QToolButton::clicked, this, &SeerBreakpointsBrowserWidget::handleCommandsToolButton); } SeerBreakpointsBrowserWidget::~SeerBreakpointsBrowserWidget () { } bool SeerBreakpointsBrowserWidget::isEmpty() const { return (breakpointsTreeWidget->topLevelItemCount() == 0); } QStringList SeerBreakpointsBrowserWidget::breakpoints () const { return QStringList(); } void SeerBreakpointsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { breakpointsTreeWidget->clear(); // // ^done,BreakpointTable={ // nr_rows="2",nr_cols="6", // // hdr=[ // {width="7",alignment="-1",col_name="number",colhdr="Num"}, // {width="14",alignment="-1",col_name="type",colhdr="Type"}, // {width="4",alignment="-1",col_name="disp",colhdr="Disp"}, // {width="3",alignment="-1",col_name="enabled",colhdr="Enb"}, // {width="18",alignment="-1",col_name="addr",colhdr="Address"}, // {width="40",alignment="2",col_name="what",colhdr="What"} // ], // // body=[ // bkpt={number="2",type="breakpoint",disp="keep",enabled="y",addr="0x0000000000400c17",func="main(int, char**)",file="helloworld.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp",line="8",thread-groups=["i1"],times="0",original-location="main"}, // bkpt={number="3", // type="breakpoint", // disp="keep", // enabled="y", // addr="0x0000000000400d72", // func="function1(std::__cxx11::basic_string, std::allocator > const&)", // file="function1.cpp", // fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp", // line="7", // thread-groups=["i1"], // cond="1 == 1", // times="0", // script={"print i argc"}, // original-location="function1"} // ] // } // //qDebug().noquote() << bkpt_list; QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString body_text = Seer::parseFirst(text, "body=", '[', ']', false); if (body_text != "") { QStringList bkpt_list = Seer::parse(newtext, "bkpt=", '{', '}', false); for (const auto& bkpt_text : bkpt_list) { // // A different way (better?) of parsing the table output // // Divide test into a list, delimited by a ','. // Then morph that list into a map, delimited by a '='. // Remove bookends. // QStringList items = Seer::parseCommaList(bkpt_text, '[', ']'); QMap keyValueMap = Seer::createKeyValueMap(items, '='); QString number_text = Seer::filterBookends(keyValueMap["number"], '"', '"'); QString type_text = Seer::filterBookends(keyValueMap["type"], '"', '"'); QString disp_text = Seer::filterBookends(keyValueMap["disp"], '"', '"'); QString enabled_text = Seer::filterBookends(keyValueMap["enabled"], '"', '"'); QString addr_text = Seer::filterBookends(keyValueMap["addr"], '"', '"'); QString func_text = Seer::filterBookends(keyValueMap["func"], '"', '"'); QString file_text = Seer::filterBookends(keyValueMap["file"], '"', '"'); QString fullname_text = Seer::filterBookends(keyValueMap["fullname"], '"', '"'); QString line_text = Seer::filterBookends(keyValueMap["line"], '"', '"'); QString thread_groups_text = Seer::filterBookends(keyValueMap["thread-groups"], '[', ']'); QString cond_text = Seer::filterBookends(keyValueMap["cond"], '"', '"'); QString times_text = Seer::filterBookends(keyValueMap["times"], '"', '"'); QString ignore_text = Seer::filterBookends(keyValueMap["ignore"], '"', '"'); QString script_text = Seer::filterBookends(keyValueMap["script"], '[', ']'); QString original_location_text = Seer::filterBookends(keyValueMap["original-location"], '"', '"'); // Only look for 'breakpoint' type break points. if (type_text != "breakpoint") { continue; } script_text = Seer::filterBookends(Seer::parseCommaList(script_text, '{', '}'), '"', '"').join('\n'); // Add the level to the tree. QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, number_text); topItem->setText(1, type_text); topItem->setText(2, disp_text); topItem->setText(3, enabled_text); topItem->setText(4, addr_text); topItem->setText(5, func_text); topItem->setText(6, QFileInfo(file_text).fileName()); topItem->setText(7, fullname_text); topItem->setText(8, line_text); topItem->setText(9, thread_groups_text); topItem->setText(10, cond_text); topItem->setText(11, times_text); topItem->setText(12, ignore_text); topItem->setText(13, script_text); topItem->setText(14, original_location_text); for (int i=0; icolumnCount(); i++) { topItem->setTextAlignment(i, Qt::AlignLeft|Qt::AlignTop); } breakpointsTreeWidget->addTopLevelItem(topItem); } } }else{ // Ignore others. } breakpointsTreeWidget->resizeColumnToContents(0); breakpointsTreeWidget->resizeColumnToContents(1); breakpointsTreeWidget->resizeColumnToContents(2); breakpointsTreeWidget->resizeColumnToContents(3); breakpointsTreeWidget->resizeColumnToContents(4); //breakpointsTreeWidget->resizeColumnToContents(5); breakpointsTreeWidget->resizeColumnToContents(6); //breakpointsTreeWidget->resizeColumnToContents(7); breakpointsTreeWidget->resizeColumnToContents(8); breakpointsTreeWidget->resizeColumnToContents(9); breakpointsTreeWidget->resizeColumnToContents(10); breakpointsTreeWidget->resizeColumnToContents(11); breakpointsTreeWidget->resizeColumnToContents(12); //breakpointsTreeWidget->resizeColumnToContents(13); breakpointsTreeWidget->resizeColumnToContents(14); QApplication::restoreOverrideCursor(); } void SeerBreakpointsBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshBreakpointsList(); } void SeerBreakpointsBrowserWidget::handleSessionTerminated () { // Delete previous contents. breakpointsTreeWidget->clear(); } void SeerBreakpointsBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); int lineno = item->text(8).toInt(); emit selectedFile(item->text(6), item->text(7), lineno); emit maybeSelectedAddress(item->text(6), item->text(7), item->text(4)); } void SeerBreakpointsBrowserWidget::handleRefreshToolButton () { emit refreshBreakpointsList(); } void SeerBreakpointsBrowserWidget::handleAddToolButton () { SeerBreakpointCreateDialog dlg(this); int ret = dlg.exec(); if (ret == 0) { return; } // Build a breakpoint specification. QString breakpointParameters = dlg.breakpointText(); // If nothing, just return. if (breakpointParameters == "") { return; } // Otherwise send the command to create the breakpoint. emit insertBreakpoint(breakpointParameters); } void SeerBreakpointsBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = breakpointsTreeWidget->selectedItems(); // Build a string that is a list of breakpoints. QString breakpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { breakpoints += " "; } breakpoints += (*i)->text(0); } // Don't do anything if the list of breakpoints is empty. if (breakpoints == "") { return; } // Send the signal. emit deleteBreakpoints(breakpoints); } void SeerBreakpointsBrowserWidget::handleEnableToolButton () { // Get selected tree items. QList items = breakpointsTreeWidget->selectedItems(); // Build a string that is a list of breakpoints. QString breakpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { breakpoints += " "; } breakpoints += (*i)->text(0); } // Don't do anything if the list of breakpoints is empty. if (breakpoints == "") { return; } // Send the signal. emit enableBreakpoints(breakpoints); } void SeerBreakpointsBrowserWidget::handleDisableToolButton () { // Get selected tree items. QList items = breakpointsTreeWidget->selectedItems(); // Build a string that is a list of breakpoints. QString breakpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { breakpoints += " "; } breakpoints += (*i)->text(0); } // Don't do anything if the list of breakpoints is empty. if (breakpoints == "") { return; } // Send the signal. emit disableBreakpoints(breakpoints); } void SeerBreakpointsBrowserWidget::handleConditionToolButton () { // Get selected tree items. Only allow one. QList items = breakpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one breakpoint when adding a condition.", QMessageBox::Ok); return; } // Get the condition text. bool ok; QString condition = QInputDialog::getText(this, "Seer", "Enter the condition for this breakpoint.\nA blank condition will remove an existing one.\n\nif:", QLineEdit::Normal, items.front()->text(10), &ok); if (ok == false) { return; } // Get the selected breakpoint number. QString breakpoint = items.front()->text(0); // Send the signal. emit addBreakpointCondition(breakpoint, condition); } void SeerBreakpointsBrowserWidget::handleIgnoreToolButton () { // Get selected tree items. Only allow one. QList items = breakpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one breakpoint when adding an ignore count.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; int count = QInputDialog::getInt(this, "Seer", "Enter the ignore count for this breakpoint.\nA count of 0 will remove an existing one.", items.front()->text(12).toInt(), 0, 2147483647, 1, &ok); if (ok == false) { return; } // Get the selected breakpoint number. QString breakpoint = items.front()->text(0); // Send the signal. emit addBreakpointIgnore(breakpoint, QString::number(count)); } void SeerBreakpointsBrowserWidget::handleCommandsToolButton () { // Get selected tree items. Only allow one. QList items = breakpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one breakpoint when adding commands.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; QString commandstr = QInputDialog::getMultiLineText(this, "Seer", "Enter the commands to execute for this breakpoint.\nA blank list will remove existing ones.", items.front()->text(13), &ok); if (ok == false) { return; } // Get the selected breakpoint number. QString breakpoint = items.front()->text(0); QStringList commands = Seer::quoteChars(commandstr.split('\n', Qt::SkipEmptyParts), "\""); // Send the signal. emit addBreakpointCommands(breakpoint, commands); } void SeerBreakpointsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); emit refreshBreakpointsList(); } epasveer-seer-97076f1/src/SeerBreakpointsBrowserWidget.h000066400000000000000000000047241526321767600233430ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerBreakpointsBrowserWidget.h" class SeerBreakpointsBrowserWidget : public QWidget, protected Ui::SeerBreakpointsBrowserWidgetForm { Q_OBJECT public: explicit SeerBreakpointsBrowserWidget (QWidget* parent = 0); ~SeerBreakpointsBrowserWidget (); bool isEmpty () const; QStringList breakpoints () const; public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); private slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleRefreshToolButton (); void handleAddToolButton (); void handleDeleteToolButton (); void handleEnableToolButton (); void handleDisableToolButton (); void handleConditionToolButton (); void handleIgnoreToolButton (); void handleCommandsToolButton (); signals: void refreshBreakpointsList (); void deleteBreakpoints (QString breakpoints); void enableBreakpoints (QString breakpoints); void disableBreakpoints (QString breakpoints); void addBreakpointCondition (QString breakpoint, QString condition); void addBreakpointIgnore (QString breakpoint, QString count); void addBreakpointCommands (QString breakpoint, QStringList commands); void insertBreakpoint (QString breakpoint); void selectedFile (QString file, QString fullname, int lineno); void selectedAddress (QString address); void maybeSelectedAddress (QString file, QString fullname, QString address); protected: void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerBreakpointsBrowserWidget.ui000066400000000000000000000156061526321767600235320ustar00rootroot00000000000000 SeerBreakpointsBrowserWidgetForm 0 0 1162 625 Form 15 Number Type Disposition Enabled Address Function File Fullname Line Thread Groups Condition Times Ignore Commands Original Location Add a new breakpoint. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Refresh the list of breakpoints. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Enable selected breakpoints. ... :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Disable selected breakpoints. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Add condition to selected breakpoint. ? Add ignore count to selected breakpoint. # Add commands to selected breakpoint. ... :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Delete selected breakpoints. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Vertical 20 40 Qt::Vertical 20 40 epasveer-seer-97076f1/src/SeerCatchpointCreateDialog.cpp000066400000000000000000000116101526321767600232350ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCatchpointCreateDialog.h" #include SeerCatchpointCreateDialog::SeerCatchpointCreateDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets setType(""); setArguments(""); setTemporaryEnabled(false); setDisabledEnabled(false); throwRadioButton->setFocus(); // Connect things. } SeerCatchpointCreateDialog::~SeerCatchpointCreateDialog () { } void SeerCatchpointCreateDialog::setType (const QString& text) { if (text == "throw") { throwRadioButton->setChecked(true); }else if (text == "rethrow") { rethrowRadioButton->setChecked(true); }else if (text == "catch") { catchRadioButton->setChecked(true); }else if (text == "load") { loadRadioButton->setChecked(true); }else if (text == "unload") { unloadRadioButton->setChecked(true); }else if (text == "assert") { adaAssertRadioButton->setChecked(true); }else if (text == "exception") { adaExceptionRadioButton->setChecked(true); }else if (text == "handlers") { adaHandlersRadioButton->setChecked(true); }else if (text == "signal") { signalRadioButton->setChecked(true); }else if (text == "fork") { forkRadioButton->setChecked(true); }else if (text == "vfork") { vforkRadioButton->setChecked(true); }else if (text == "exec") { execRadioButton->setChecked(true); }else if (text == "syscall") { syscallRadioButton->setChecked(true); }else{ throwRadioButton->setChecked(true); } } QString SeerCatchpointCreateDialog::typeText () const { if (throwRadioButton->isChecked()) { return "throw"; }else if (rethrowRadioButton->isChecked()) { return "rethrow"; }else if (catchRadioButton->isChecked()) { return "catch"; }else if (loadRadioButton->isChecked()) { return "load"; }else if (unloadRadioButton->isChecked()) { return "unload"; }else if (adaAssertRadioButton->isChecked()) { return "assert"; }else if (adaExceptionRadioButton->isChecked()) { return "exception"; }else if (adaHandlersRadioButton->isChecked()) { return "handlers"; }else if (signalRadioButton->isChecked()) { return "signal"; }else if (forkRadioButton->isChecked()) { return "fork"; }else if (vforkRadioButton->isChecked()) { return "vfork"; }else if (execRadioButton->isChecked()) { return "exec"; }else if (syscallRadioButton->isChecked()) { return "syscall"; }else{ return "throw"; } } void SeerCatchpointCreateDialog::setTemporaryEnabled (bool flag) { temporaryCheckBox->setChecked(flag); } void SeerCatchpointCreateDialog::setDisabledEnabled (bool flag) { disabledCheckBox->setChecked(flag); } void SeerCatchpointCreateDialog::setArguments (const QString& text) { argumentsLineEdit->setText(text); } QString SeerCatchpointCreateDialog::arguments () const { return argumentsLineEdit->text(); } bool SeerCatchpointCreateDialog::temporaryEnabled () const { return temporaryCheckBox->isChecked(); } bool SeerCatchpointCreateDialog::disabledEnabled () const { return disabledCheckBox->isChecked(); } QString SeerCatchpointCreateDialog::catchpointText () const { // Build a catchpoint specification. QString catchpointParameters = typeText(); if (temporaryEnabled()) { catchpointParameters += " -t"; } if (disabledEnabled()) { catchpointParameters += " -d"; } if (typeText() == "assert") { // Handle Ada 'assert'. Nothing to add here. }else if (typeText() == "exception") { // Handle Ada 'exception'. if (arguments() != "") { catchpointParameters += " -e " + arguments(); } }else if (typeText() == "handlers") { // Handle Ada 'handlers'. if (arguments() != "") { catchpointParameters += " -e " + arguments(); } }else if (typeText() == "load") { // Handle library 'load'. Must have a name. catchpointParameters += " " + arguments(); }else if (typeText() == "unload") { // Handle library 'unload'. Must have a name. catchpointParameters += " " + arguments(); }else if (typeText() == "signal") { // Handle library 'unload'. Must have a name. catchpointParameters += " " + arguments(); }else if (typeText() == "syscall") { // Handle library 'unload'. Must have a name. catchpointParameters += " " + arguments(); }else{ // C++ throw, rethrow, catch. These require '-r', but only if there is a name. if (arguments() != "") { catchpointParameters += " -r " + arguments(); } } // qDebug() << catchpointParameters; return catchpointParameters; } epasveer-seer-97076f1/src/SeerCatchpointCreateDialog.h000066400000000000000000000023031526321767600227010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerCatchpointCreateDialog.h" class SeerCatchpointCreateDialog : public QDialog, protected Ui::SeerCatchpointCreateDialogForm { Q_OBJECT public: explicit SeerCatchpointCreateDialog (QWidget* parent = 0); ~SeerCatchpointCreateDialog (); void setType (const QString& text); QString typeText () const; void setTemporaryEnabled (bool flag); bool temporaryEnabled () const; void setDisabledEnabled (bool flag); bool disabledEnabled () const; void setNameEnabled (bool flag); bool nameEnabled () const; void setArguments (const QString& text); QString arguments () const; QString catchpointText () const; public slots: private: }; epasveer-seer-97076f1/src/SeerCatchpointCreateDialog.ui000066400000000000000000000211521526321767600230720ustar00rootroot00000000000000 SeerCatchpointCreateDialogForm 0 0 543 403 Create a Catchpoint Catchpoint Type Catch on 'throw' typeButtonGroup Catch on library 'load' typeButtonGroup Catch on Ada 'assert' typeButtonGroup Catch on 'rethrow' typeButtonGroup Catch on library 'unload' typeButtonGroup Catch on Ada 'exception' typeButtonGroup Catch on 'catch' typeButtonGroup Catch on Ada 'handlers' typeButtonGroup Catch on 'signal' typeButtonGroup Catch on 'fork' typeButtonGroup Catch on 'exec' typeButtonGroup Catch on 'syscall' typeButtonGroup Catch on 'vfork' typeButtonGroup Catchpoint Details Create a temporary catchpoint. Temporary Create a disabled catchpoint. Disabled Qt::Horizontal 40 20 Arguments Optional arguments for selected Catchpoint type. true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok throwRadioButton loadRadioButton adaAssertRadioButton rethrowRadioButton unloadRadioButton adaExceptionRadioButton catchRadioButton adaHandlersRadioButton signalRadioButton forkRadioButton execRadioButton syscallRadioButton vforkRadioButton temporaryCheckBox disabledCheckBox argumentsLineEdit buttonBox accepted() SeerCatchpointCreateDialogForm accept() 257 393 157 274 buttonBox rejected() SeerCatchpointCreateDialogForm reject() 325 393 286 274 epasveer-seer-97076f1/src/SeerCatchpointsBrowserWidget.cpp000066400000000000000000000426221526321767600236730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCatchpointsBrowserWidget.h" #include "SeerCatchpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include SeerCatchpointsBrowserWidget::SeerCatchpointsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets catchpointsTreeWidget->clear(); catchpointsTreeWidget->setSortingEnabled(false); catchpointsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); catchpointsTreeWidget->resizeColumnToContents(0); // number catchpointsTreeWidget->resizeColumnToContents(1); // type catchpointsTreeWidget->resizeColumnToContents(2); // disp catchpointsTreeWidget->resizeColumnToContents(3); // enabled catchpointsTreeWidget->resizeColumnToContents(4); // what catchpointsTreeWidget->resizeColumnToContents(5); // catch-type catchpointsTreeWidget->resizeColumnToContents(6); // name catchpointsTreeWidget->resizeColumnToContents(7); // thread-groups catchpointsTreeWidget->resizeColumnToContents(8); // cond catchpointsTreeWidget->resizeColumnToContents(9); // times catchpointsTreeWidget->resizeColumnToContents(10); // ignore //catchpointsTreeWidget->resizeColumnToContents(11); // script Too long to show catchpointsTreeWidget->setColumnHidden(12, true); // Hide the 'used' column. catchpointsTreeWidget->clear(); // Connect things. QObject::connect(refreshCatchpointsToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleRefreshToolButton); QObject::connect(addCatchpointToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleAddToolButton); QObject::connect(deleteCatchpointsToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleDeleteToolButton); QObject::connect(enableCatchpointsToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleEnableToolButton); QObject::connect(disableCatchpointsToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleDisableToolButton); QObject::connect(conditionCatchpointToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleConditionToolButton); QObject::connect(ignoreCatchpointToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleIgnoreToolButton); QObject::connect(commandsCatchpointToolButton, &QToolButton::clicked, this, &SeerCatchpointsBrowserWidget::handleCommandsToolButton); } SeerCatchpointsBrowserWidget::~SeerCatchpointsBrowserWidget () { } bool SeerCatchpointsBrowserWidget::isEmpty() const { return (catchpointsTreeWidget->topLevelItemCount() == 0); } QStringList SeerCatchpointsBrowserWidget::breakpoints () const { return QStringList(); } void SeerCatchpointsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } //qDebug() << text; QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { // ^done,BreakpointTable={ // nr_rows="3", nr_cols="6", // // hdr=[ // {width="7",alignment="-1",col_name="number",colhdr="Num"}, // {width="14",alignment="-1",col_name="type",colhdr="Type"}, // {width="4",alignment="-1",col_name="disp",colhdr="Disp"}, // {width="3",alignment="-1",col_name="enabled",colhdr="Enb"}, // {width="18",alignment="-1",col_name="addr",colhdr="Address"}, // {width="40",alignment="2",col_name="what",colhdr="What"} // ], // // body=[ // bkpt={number="2",type="catchpoint",disp="keep",enabled="y",what="exception catch",catch-type="catch",thread-groups=["i1"],times="0"}, // bkpt={number="3", // type="catchpoint", // disp="keep", // enabled="y", // what="exception throw", // catch-type="throw", // thread-groups=["i1"], // regexp="Exception*", // times="0"} // ] // // body=[ // bkpt={number="2", // type="catchpoint", // disp="keep", // enabled="y", // what="", // catch-type="signal", // thread-groups=["i1"], // times="1"} // ] // QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString body_text = Seer::parseFirst(newtext, "body=", '[', ']', false); //qDebug() << body_text; // No rows? Just clear the tree. if (body_text == "") { catchpointsTreeWidget->clear(); // Otherwise, populate it. }else{ // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(catchpointsTreeWidget); while (*it) { (*it)->setText(12, "unused"); ++it; } QStringList bkpt_list = Seer::parse(newtext, "bkpt=", '{', '}', false); for ( const auto& bkpt_text : bkpt_list ) { QString number_text = Seer::parseFirst(bkpt_text, "number=", '"', '"', false); QString type_text = Seer::parseFirst(bkpt_text, "type=", '"', '"', false); QString disp_text = Seer::parseFirst(bkpt_text, "disp=", '"', '"', false); QString enabled_text = Seer::parseFirst(bkpt_text, "enabled=", '"', '"', false); QString what_text = Seer::parseFirst(bkpt_text, "what=", '"', '"', false); QString catch_type_text = Seer::parseFirst(bkpt_text, "catch-type=", '"', '"', false); QString name_text = Seer::parseFirst(bkpt_text, "regexp=", '"', '"', false); QString thread_groups_text = Seer::parseFirst(bkpt_text, "thread-groups=", '[', ']', false); QString cond_text = Seer::parseFirst(bkpt_text, "cond=", '"', '"', false); QString times_text = Seer::parseFirst(bkpt_text, "times=", '"', '"', false); QString ignore_text = Seer::parseFirst(bkpt_text, "ignore=", '"', '"', false); QString script_text = Seer::parseFirst(bkpt_text, "script=", '{', '}', false); // Only look for 'catchpoint' type break points. if (type_text != "catchpoint") { continue; } script_text = Seer::filterBookends(Seer::parseCommaList(script_text, '{', '}'), '"', '"').join('\n'); // Hack for library 'load' and 'unload' catchpoints. // Unlike 'catch' catchpoints, the "regexp" field is blank. The // name is buried in the "what" field. So extract it. // // what="load of library matching libSampVar.so" // what="unload of library matching libSampVar.so" // if (name_text == "") { QString loadsearch("load of library matching "); QString unloadsearch("unload of library matching "); if (what_text.startsWith(loadsearch)) { name_text = what_text.mid(loadsearch.length()); } if (what_text.startsWith(unloadsearch)) { name_text = what_text.mid(unloadsearch.length()); } } // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. QList matches = catchpointsTreeWidget->findItems(number_text, Qt::MatchExactly, 0); // No matches. So can't reuse. Add the new entry. if (matches.size() == 0) { // Add the level to the tree. QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, number_text); topItem->setText(1, type_text); topItem->setText(2, disp_text); topItem->setText(3, enabled_text); topItem->setText(4, what_text); topItem->setText(5, catch_type_text); topItem->setText(6, name_text); topItem->setText(7, thread_groups_text); topItem->setText(8, cond_text); topItem->setText(9, times_text); topItem->setText(10, ignore_text); topItem->setText(11, script_text); topItem->setText(12, "new"); for (int i=0; icolumnCount(); i++) { topItem->setTextAlignment(i, Qt::AlignLeft|Qt::AlignTop); } catchpointsTreeWidget->addTopLevelItem(topItem); // Found a match. Reuse it. }else{ QTreeWidgetItem* topItem = matches.takeFirst(); topItem->setText(0, number_text); topItem->setText(1, type_text); topItem->setText(2, disp_text); topItem->setText(3, enabled_text); topItem->setText(4, what_text); topItem->setText(5, catch_type_text); topItem->setText(6, name_text); topItem->setText(7, thread_groups_text); topItem->setText(8, cond_text); topItem->setText(9, times_text); topItem->setText(10, ignore_text); topItem->setText(11, script_text); topItem->setText(12, "reused"); } } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. QList matches = catchpointsTreeWidget->findItems("unused", Qt::MatchExactly, 12); qDeleteAll(matches); } }else{ // Ignore others. } catchpointsTreeWidget->resizeColumnToContents(0); catchpointsTreeWidget->resizeColumnToContents(1); catchpointsTreeWidget->resizeColumnToContents(2); catchpointsTreeWidget->resizeColumnToContents(3); catchpointsTreeWidget->resizeColumnToContents(4); catchpointsTreeWidget->resizeColumnToContents(5); catchpointsTreeWidget->resizeColumnToContents(6); catchpointsTreeWidget->resizeColumnToContents(7); catchpointsTreeWidget->resizeColumnToContents(8); catchpointsTreeWidget->resizeColumnToContents(9); catchpointsTreeWidget->resizeColumnToContents(10); //catchpointsTreeWidget->resizeColumnToContents(11); catchpointsTreeWidget->resizeColumnToContents(12); QApplication::restoreOverrideCursor(); } void SeerCatchpointsBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshCatchpointsList(); } void SeerCatchpointsBrowserWidget::handleSessionTerminated () { // Delete previous contents. catchpointsTreeWidget->clear(); } void SeerCatchpointsBrowserWidget::handleRefreshToolButton () { emit refreshCatchpointsList(); } void SeerCatchpointsBrowserWidget::handleAddToolButton () { SeerCatchpointCreateDialog dlg(this); int ret = dlg.exec(); if (ret == 0) { return; } // Build a catchpoint specification. QString catchpointParameters = dlg.catchpointText(); // If nothing, just return. if (catchpointParameters == "") { return; } // Otherwise send the command to create the catchpoint. emit insertCatchpoint(catchpointParameters); } void SeerCatchpointsBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = catchpointsTreeWidget->selectedItems(); // Build a string that is a list of catchpoints. QString catchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { catchpoints += " "; } catchpoints += (*i)->text(0); } // Don't do anything if the list of catchpoints is empty. if (catchpoints == "") { return; } // Send the signal. emit deleteCatchpoints(catchpoints); } void SeerCatchpointsBrowserWidget::handleEnableToolButton () { // Get selected tree items. QList items = catchpointsTreeWidget->selectedItems(); // Build a string that is a list of catchpoints. QString catchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { catchpoints += " "; } catchpoints += (*i)->text(0); } // Don't do anything if the list of catchpoints is empty. if (catchpoints == "") { return; } // Send the signal. emit enableCatchpoints(catchpoints); } void SeerCatchpointsBrowserWidget::handleDisableToolButton () { // Get selected tree items. QList items = catchpointsTreeWidget->selectedItems(); // Build a string that is a list of catchpoints. QString catchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { catchpoints += " "; } catchpoints += (*i)->text(0); } // Don't do anything if the list of catchpoints is empty. if (catchpoints == "") { return; } // Send the signal. emit disableCatchpoints(catchpoints); } void SeerCatchpointsBrowserWidget::handleConditionToolButton () { // Get selected tree items. Only allow one. QList items = catchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one catchpoint when adding a condition.", QMessageBox::Ok); return; } // Get the condition text. bool ok; QString condition = QInputDialog::getText(this, "Seer", "Enter the condition for this catchpoint.\nA blank condition will remove an existing one.", QLineEdit::Normal, items.front()->text(8), &ok); if (ok == false) { return; } // Get the selected catchpoint number. QString catchpoint = items.front()->text(0); // Send the signal. emit addBreakpointCondition(catchpoint, condition); } void SeerCatchpointsBrowserWidget::handleIgnoreToolButton () { // Get selected tree items. Only allow one. QList items = catchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one catchpoint when adding an ignore count.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; int count = QInputDialog::getInt(this, "Seer", "Enter the ignore count for this catchpoint.\nA count of 0 will remove an existing one.", items.front()->text(10).toInt(), 0, 2147483647, 1, &ok); if (ok == false) { return; } // Get the selected catchpoint number. QString catchpoint = items.front()->text(0); // Send the signal. emit addBreakpointIgnore(catchpoint, QString::number(count)); } void SeerCatchpointsBrowserWidget::handleCommandsToolButton () { // Get selected tree items. Only allow one. QList items = catchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one watcpoint when adding commands.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; QString commandstr = QInputDialog::getMultiLineText(this, "Seer", "Enter the commands to execute for this catchpoint.\nA blank list will remove existing ones.", items.front()->text(11), &ok); if (ok == false) { return; } // Get the selected catchpoint number. QString catchpoint = items.front()->text(0); QStringList commands = Seer::quoteChars(commandstr.split('\n', Qt::SkipEmptyParts), "\""); // Send the signal. emit addBreakpointCommands(catchpoint, commands); } void SeerCatchpointsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); emit refreshCatchpointsList(); } epasveer-seer-97076f1/src/SeerCatchpointsBrowserWidget.h000066400000000000000000000041331526321767600233330ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerCatchpointsBrowserWidget.h" class SeerCatchpointsBrowserWidget : public QWidget, protected Ui::SeerCatchpointsBrowserWidgetForm { Q_OBJECT public: explicit SeerCatchpointsBrowserWidget (QWidget* parent = 0); ~SeerCatchpointsBrowserWidget (); bool isEmpty () const; QStringList breakpoints () const; public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); private slots: void handleRefreshToolButton (); void handleAddToolButton (); void handleDeleteToolButton (); void handleEnableToolButton (); void handleDisableToolButton (); void handleConditionToolButton (); void handleIgnoreToolButton (); void handleCommandsToolButton (); signals: void refreshCatchpointsList (); void deleteCatchpoints (QString catchpoints); void enableCatchpoints (QString catchpoints); void disableCatchpoints (QString catchpoints); void addBreakpointCondition (QString catchpoint, QString condition); void addBreakpointIgnore (QString catchpoint, QString count); void addBreakpointCommands (QString catchpoint, QStringList commands); void insertCatchpoint (QString catchpoint); protected: void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerCatchpointsBrowserWidget.ui000066400000000000000000000152411526321767600235230ustar00rootroot00000000000000 SeerCatchpointsBrowserWidgetForm 0 0 1052 485 Form 13 Number Type Disposition Enabled What Catch Type Name Thread Groups Condtion Times Ignore Commands Used Add a new catchpoint. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Refresh the list of catchpoints. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Enable selected catchpoints. ... :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Disable selected catchpoints. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Add condition to selected catchpoint. ? Add ignore count to selected catchpoint. # Add commands to selected catchpoint. ... :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Delete selected catchpoints. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Vertical 20 40 Qt::Vertical 20 40 epasveer-seer-97076f1/src/SeerCheckpointsBrowserWidget.cpp000066400000000000000000000164201526321767600236630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCheckpointsBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerCheckpointsBrowserWidget::SeerCheckpointsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets checkpointsTreeWidget->clear(); checkpointsTreeWidget->setSortingEnabled(false); checkpointsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); checkpointsTreeWidget->resizeColumnToContents(0); // state checkpointsTreeWidget->resizeColumnToContents(1); // number checkpointsTreeWidget->resizeColumnToContents(2); // process checkpointsTreeWidget->resizeColumnToContents(3); // file checkpointsTreeWidget->resizeColumnToContents(4); // line // Connect things. QObject::connect(checkpointsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerCheckpointsBrowserWidget::handleItemDoubleClicked); QObject::connect(refreshCheckpointsToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleRefreshToolButton); QObject::connect(addCheckpointToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleAddToolButton); QObject::connect(deleteCheckpointsToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleDeleteToolButton); QObject::connect(selectCheckpointToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleSelectToolButton); } SeerCheckpointsBrowserWidget::~SeerCheckpointsBrowserWidget () { } void SeerCheckpointsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } if (text.startsWith("^done,checkpoints=[") && text.endsWith("]")) { // // "^done,checkpoints=[ // {id="0",state="*",process="Thread 0x7ffff7e7f740 (LWP 31803) (main process) at 0x0",file="",line=""}, // {id="1",state=" ",process="process 31806 at 0x55555555513f",file="hellostruct.cpp",line="49"}, // {id="2",state=" ",process="process 31807 at 0x5555555552a0",file="hellostruct.cpp",line="62"} // ] // checkpointsTreeWidget->clear(); checkpointsTreeWidget->setSortingEnabled(false); checkpointsTreeWidget->sortByColumn(-1, Qt::AscendingOrder); QString checkpoints_text = Seer::parseFirst(text, "checkpoints=", '[', ']', false); QStringList checkpoints_list = Seer::parse(checkpoints_text, "", '{', '}', false); for (const auto& checkpoint_entry : checkpoints_list) { QString id_text = Seer::parseFirst(checkpoint_entry, "id=", '"', '"', false); QString state_text = Seer::parseFirst(checkpoint_entry, "state=", '"', '"', false); QString process_text = Seer::parseFirst(checkpoint_entry, "process=", '"', '"', false); QString file_text = Seer::parseFirst(checkpoint_entry, "file=", '"', '"', false); QString line_text = Seer::parseFirst(checkpoint_entry, "line=", '"', '"', false); // Add the function to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, state_text); item->setText(1, id_text); item->setText(2, process_text); item->setText(3, file_text); item->setText(4, line_text); checkpointsTreeWidget->addTopLevelItem(item); } }else{ // Ignore others. } checkpointsTreeWidget->resizeColumnToContents(0); checkpointsTreeWidget->resizeColumnToContents(1); checkpointsTreeWidget->resizeColumnToContents(2); checkpointsTreeWidget->resizeColumnToContents(3); checkpointsTreeWidget->resizeColumnToContents(4); QApplication::restoreOverrideCursor(); } void SeerCheckpointsBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshCheckpointsList(); } void SeerCheckpointsBrowserWidget::handleSessionTerminated () { // Delete previous contents. checkpointsTreeWidget->clear(); } void SeerCheckpointsBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectCheckpoint(item->text(1)); } void SeerCheckpointsBrowserWidget::handleRefreshToolButton () { emit refreshCheckpointsList(); } void SeerCheckpointsBrowserWidget::handleAddToolButton () { // Otherwise send the command to create the checkpoint. emit insertCheckpoint(); } void SeerCheckpointsBrowserWidget::handleSelectToolButton () { // Any items in the tree? if (checkpointsTreeWidget->topLevelItemCount() == 0) { QMessageBox::warning(this, "Seer", QString("There are no checkpoints to switch to."), QMessageBox::Ok, QMessageBox::Ok); return; } // Get selected tree items. QList items = checkpointsTreeWidget->selectedItems(); if (items.count() == 0) { QMessageBox::warning(this, "Seer", QString("Selected a checkpoint to switch to."), QMessageBox::Ok, QMessageBox::Ok); return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", QString("Select only 1 checkpoint to switch to."), QMessageBox::Ok, QMessageBox::Ok); return; } // Build a string that is a list of checkpoints. QString checkpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { checkpoints += " "; } checkpoints += (*i)->text(1); } // Don't do anything if the list of checkpoints is empty. if (checkpoints == "") { return; } // Send the signal. emit selectCheckpoint(checkpoints); } void SeerCheckpointsBrowserWidget::handleDeleteToolButton () { // Any items in the tree? if (checkpointsTreeWidget->topLevelItemCount() == 0) { QMessageBox::warning(this, "Seer", QString("There are no checkpoints to delete."), QMessageBox::Ok, QMessageBox::Ok); return; } // Get selected tree items. QList items = checkpointsTreeWidget->selectedItems(); if (items.count() == 0) { QMessageBox::warning(this, "Seer", QString("Select checkpoints to delete."), QMessageBox::Ok, QMessageBox::Ok); return; } // Build a string that is a list of checkpoints. QString checkpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { checkpoints += " "; } checkpoints += (*i)->text(1); } // Don't do anything if the list of checkpoints is empty. if (checkpoints == "") { return; } // Send the signal. emit deleteCheckpoints(checkpoints); } void SeerCheckpointsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); emit refreshCheckpointsList(); } epasveer-seer-97076f1/src/SeerCheckpointsBrowserWidget.h000066400000000000000000000026771526321767600233410ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerCheckpointsBrowserWidget.h" class SeerCheckpointsBrowserWidget : public QWidget, protected Ui::SeerCheckpointsBrowserWidgetForm { Q_OBJECT public: explicit SeerCheckpointsBrowserWidget (QWidget* parent = 0); ~SeerCheckpointsBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); private slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleRefreshToolButton (); void handleAddToolButton (); void handleDeleteToolButton (); void handleSelectToolButton (); signals: void refreshCheckpointsList (); void insertCheckpoint (); void selectCheckpoint (QString checkpoint); void deleteCheckpoints (QString checkpoints); protected: void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerCheckpointsBrowserWidget.ui000066400000000000000000000102321526321767600235110ustar00rootroot00000000000000 SeerCheckpointsBrowserWidgetForm 0 0 1162 625 Form 5 Active Number Process File Line Add a new checkpoint at the current spot in the program. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Refresh the list of checkpoints. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Switch to the selected breakpoint. ... :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Delete selected checkpoints. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Vertical 20 40 Qt::Vertical 20 40 epasveer-seer-97076f1/src/SeerCloseSourceDialog.cpp000066400000000000000000000047031526321767600222500ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCloseSourceDialog.h" #include #include #include #include SeerCloseSourceDialog::SeerCloseSourceDialog(QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets // Connect things. // Restore window settings. readSettings(); } SeerCloseSourceDialog::~SeerCloseSourceDialog() { } void SeerCloseSourceDialog::setFiles (const SeerEditorManagerFiles& files) { for (int i=0; isetText(0, files[i].file); topItem->setText(1, files[i].fullname); filenamesTreeWidget->addTopLevelItem(topItem); } filenamesTreeWidget->resizeColumnToContents(0); filenamesTreeWidget->resizeColumnToContents(1); } SeerEditorManagerFiles SeerCloseSourceDialog::files () const { SeerEditorManagerFiles files; QList items = filenamesTreeWidget->findItems(QString("*"), Qt::MatchWrap|Qt::MatchWildcard|Qt::MatchRecursive); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { SeerEditorManagerFile f; f.file = (*i)->text(0); f.fullname = (*i)->text(1); files.push_back(f); } return files; } SeerEditorManagerFiles SeerCloseSourceDialog::selectedFiles () const { SeerEditorManagerFiles files; QList items = filenamesTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { SeerEditorManagerFile f; f.file = (*i)->text(0); f.fullname = (*i)->text(1); files.push_back(f); } return files; } void SeerCloseSourceDialog::writeSettings() { QSettings settings; settings.beginGroup("closesourcedialog"); { settings.setValue("size", size()); } settings.endGroup(); //qDebug() << size(); } void SeerCloseSourceDialog::readSettings() { QSettings settings; settings.beginGroup("closesourcedialog"); { resize(settings.value("size", QSize(400, 300)).toSize()); } settings.endGroup(); //qDebug() << size(); } void SeerCloseSourceDialog::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } epasveer-seer-97076f1/src/SeerCloseSourceDialog.h000066400000000000000000000017511526321767600217150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerEditorManagerEntry.h" #include #include #include "ui_SeerCloseSourceDialog.h" class SeerCloseSourceDialog : public QDialog, public Ui::SeerCloseSourceDialogForm { Q_OBJECT public: explicit SeerCloseSourceDialog (QWidget* parent = 0); ~SeerCloseSourceDialog (); void setFiles (const SeerEditorManagerFiles& files); SeerEditorManagerFiles files () const; SeerEditorManagerFiles selectedFiles () const; protected slots: protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: }; epasveer-seer-97076f1/src/SeerCloseSourceDialog.ui000066400000000000000000000044461526321767600221070ustar00rootroot00000000000000 SeerCloseSourceDialogForm 0 0 400 300 Seer - Select files to close Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok Select the files to close. QAbstractItemView::NoEditTriggers QAbstractItemView::ExtendedSelection QAbstractItemView::SelectRows true File Full Name buttonBox accepted() SeerCloseSourceDialogForm accept() 248 254 157 274 buttonBox rejected() SeerCloseSourceDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerCommandLogsWidget.cpp000066400000000000000000000562621526321767600222600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCommandLogsWidget.h" #include "SeerMacroToolButton.h" #include "SeerLogWidget.h" #include "SeerHelpPageDialog.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include #include #include #include SeerCommandLogsWidget::SeerCommandLogsWidget (QWidget* parent) : QWidget(parent) { _consoleWidget = 0; _consoleIndex = -1; _consoleScrollLines = 1000; _rememberManualCommandCount = 10; _aboutToQuit = false; setupUi(this); // Setup the widgets QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); m1ToolButton->setMacroName("M1"); m2ToolButton->setMacroName("M2"); m3ToolButton->setMacroName("M3"); m4ToolButton->setMacroName("M4"); m5ToolButton->setMacroName("M5"); m6ToolButton->setMacroName("M6"); m7ToolButton->setMacroName("M7"); m8ToolButton->setMacroName("M8"); m9ToolButton->setMacroName("M9"); m0ToolButton->setMacroName("M0"); _messagesBrowserWidget = new SeerMessagesBrowserWidget(this); _breakpointsBrowserWidget = new SeerBreakpointsBrowserWidget(this); _watchpointsBrowserWidget = new SeerWatchpointsBrowserWidget(this); _catchpointsBrowserWidget = new SeerCatchpointsBrowserWidget(this); _printpointsBrowserWidget = new SeerPrintpointsBrowserWidget(this); _checkpointsBrowserWidget = new SeerCheckpointsBrowserWidget(this); _gdbOutputLog = new SeerGdbLogWidget(this); _seerOutputLog = new SeerSeerLogWidget(this); _gdbOutputLog->setPlaceholderText("[gdb output]"); _seerOutputLog->setPlaceholderText("[seer output]"); logsTabWidget->clear(); logsTabWidget->addTab(_messagesBrowserWidget, "Messages"); logsTabWidget->addTab(_breakpointsBrowserWidget, "Breakpoints"); logsTabWidget->addTab(_watchpointsBrowserWidget, "Watchpoints"); logsTabWidget->addTab(_catchpointsBrowserWidget, "Catchpoints"); logsTabWidget->addTab(_printpointsBrowserWidget, "Printpoints"); logsTabWidget->addTab(_checkpointsBrowserWidget, "Checkpoints"); logsTabWidget->addTab(_gdbOutputLog, "GDB output"); logsTabWidget->addTab(_seerOutputLog, "Seer output"); logsTabWidget->setCurrentIndex(0); QToolButton* tabsContextMenuButton = new QToolButton(logsTabWidget); tabsContextMenuButton->setIcon(QIcon(":/seer/resources/thenounproject/preferences.svg")); tabsContextMenuButton->setToolTip("Show/Hide tabs."); tabsContextMenuButton->setContextMenuPolicy(Qt::CustomContextMenu); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(tabsContextMenuButton); logsTabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Create the console tab. // Each RUN method will create and connect to the console's terminal. createConsole(); // Set manual command settings. manualCommandComboBox->setFont(font); manualCommandComboBox->setEditable(true); manualCommandComboBox->lineEdit()->setPlaceholderText("Manually enter a gdb/mi command..."); manualCommandComboBox->lineEdit()->setToolTip("Manually enter a gdb/mi command."); manualCommandComboBox->lineEdit()->setClearButtonEnabled(true); // Restore tab ordering and manual command history. readSettings(); readHistorySettings(); readLogSettings(); // Connect things. QObject::connect(tabsContextMenuButton, &QToolButton::clicked, this, &SeerCommandLogsWidget::handleTabsContextMenuButtonClicked); QObject::connect(logsTabWidget->tabBar(), &QTabBar::tabMoved, this, &SeerCommandLogsWidget::handleLogsTabMoved); QObject::connect(logsTabWidget->tabBar(), &QTabBar::currentChanged, this, &SeerCommandLogsWidget::handleLogsTabChanged); QObject::connect(manualCommandComboBox->lineEdit(), &QLineEdit::returnPressed, this, &SeerCommandLogsWidget::handleManualCommandExecute); QObject::connect(manualCommandComboBox, QOverload::of(&QComboBox::activated), this, &SeerCommandLogsWidget::handleManualCommandChanged); QObject::connect(_messagesBrowserWidget, &SeerMessagesBrowserWidget::showMessages, this, &SeerCommandLogsWidget::handleRaiseMessageTab); QObject::connect(_gdbOutputLog, &SeerLogWidget::logEnabledChanged, this, &SeerCommandLogsWidget::handleLogOutputChanged); QObject::connect(_gdbOutputLog, &SeerLogWidget::logTimeStampChanged, this, &SeerCommandLogsWidget::handleLogOutputChanged); QObject::connect(_seerOutputLog, &SeerLogWidget::logEnabledChanged, this, &SeerCommandLogsWidget::handleLogOutputChanged); QObject::connect(_seerOutputLog, &SeerLogWidget::logTimeStampChanged, this, &SeerCommandLogsWidget::handleLogOutputChanged); QObject::connect(breakpointsLoadToolButton, &QToolButton::clicked, this, &SeerCommandLogsWidget::handleGdbLoadBreakpoints); QObject::connect(breakpointsSaveToolButton, &QToolButton::clicked, this, &SeerCommandLogsWidget::handleGdbSaveBreakpoints); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerCommandLogsWidget::handleHelpToolButtonClicked); QObject::connect(macroButtonGroup, &QButtonGroup::buttonClicked, this, &SeerCommandLogsWidget::handleMacroToolButtonClicked); QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &SeerCommandLogsWidget::handleAboutToQuit); } SeerCommandLogsWidget::~SeerCommandLogsWidget () { deleteConsole(); } SeerMessagesBrowserWidget* SeerCommandLogsWidget::messagesBrowser () { return _messagesBrowserWidget; } SeerBreakpointsBrowserWidget* SeerCommandLogsWidget::breakpointsBrowser () { return _breakpointsBrowserWidget; } SeerWatchpointsBrowserWidget* SeerCommandLogsWidget::watchpointsBrowser () { return _watchpointsBrowserWidget; } SeerCatchpointsBrowserWidget* SeerCommandLogsWidget::catchpointsBrowser () { return _catchpointsBrowserWidget; } SeerPrintpointsBrowserWidget* SeerCommandLogsWidget::printpointsBrowser () { return _printpointsBrowserWidget; } SeerCheckpointsBrowserWidget* SeerCommandLogsWidget::checkpointsBrowser () { return _checkpointsBrowserWidget; } SeerGdbLogWidget* SeerCommandLogsWidget::gdbOutputLog () { return _gdbOutputLog; } SeerSeerLogWidget* SeerCommandLogsWidget::seerOutputLog () { return _seerOutputLog; } SeerConsoleWidget* SeerCommandLogsWidget::console () { return _consoleWidget; } void SeerCommandLogsWidget::createConsole () { if (_consoleWidget == 0) { _consoleWidget = new SeerConsoleWidget(0); // The console needs to know when it's detached or reattached. QObject::connect(logsTabWidget, qOverload(&QDetachTabWidget::tabDetached), _consoleWidget, &SeerConsoleWidget::handleTabDetached); QObject::connect(logsTabWidget, qOverload(&QDetachTabWidget::tabReattached), _consoleWidget, &SeerConsoleWidget::handleTabReattached); _consoleIndex = logsTabWidget->addTab(_consoleWidget, "Console output"); QObject::connect(_consoleWidget, &SeerConsoleWidget::newTextAdded, this, &SeerCommandLogsWidget::handleConsoleNewTextAdded); QObject::connect(_consoleWidget, &SeerConsoleWidget::newTextViewed, this, &SeerCommandLogsWidget::handleConsoleNewTextViewed); setConsoleMode(consoleMode()); setConsoleScrollLines(consoleScrollLines()); } } void SeerCommandLogsWidget::deleteConsole () { if (_consoleWidget) { if (_consoleIndex >= 0) { logsTabWidget->removeTab(_consoleIndex); } delete _consoleWidget; _consoleWidget = 0; _consoleIndex = -1; } } void SeerCommandLogsWidget::reattachConsole () { if (_consoleIndex < 0) { return; } if (_consoleWidget == nullptr) { return; } _consoleMode = "attached"; logsTabWidget->reattachTab(_consoleIndex); } void SeerCommandLogsWidget::setConsoleMode (const QString& mode) { _consoleMode = mode; handleConsoleModeChanged(); } QString SeerCommandLogsWidget::consoleMode () const { return _consoleMode; } void SeerCommandLogsWidget::setConsoleScrollLines (int count) { _consoleScrollLines = count; if (_consoleWidget) { _consoleWidget->setScrollLines(_consoleScrollLines); } } int SeerCommandLogsWidget::consoleScrollLines () const { return _consoleScrollLines; } void SeerCommandLogsWidget::setManualCommands (const QStringList& commands) { manualCommandComboBox->clear(); manualCommandComboBox->addItems(commands); // Point to last one. if (manualCommandComboBox->count() > 0) { manualCommandComboBox->setCurrentIndex(manualCommandComboBox->count()-1); } } QStringList SeerCommandLogsWidget::manualCommands(int count) const { // Select all if a zero. if (count == 0) { count = manualCommandComboBox->count(); } // No more than count. if (count > manualCommandComboBox->count()) { count = manualCommandComboBox->count(); } // Calculate starting position in list. int index = manualCommandComboBox->count() - count; // Get the list. QStringList list; for (; indexitemText(index); } return list; } void SeerCommandLogsWidget::setRememberManualCommandCount (int count) { _rememberManualCommandCount = count; } int SeerCommandLogsWidget::rememberManualCommandCount () const { return _rememberManualCommandCount; } void SeerCommandLogsWidget::clearManualCommandHistory () { // Zap the entries in the combobox. manualCommandComboBox->clear(); // Write the history settings. writeHistorySettings(); } void SeerCommandLogsWidget::handleLogsTabMoved (int to, int from) { Q_UNUSED(from); Q_UNUSED(to); // Keep track of console tab if it moved. if (_consoleIndex == from) { _consoleIndex = to; } // Don't handle anything here if Seer is exiting. if (_aboutToQuit) { return; } writeSettings(); } void SeerCommandLogsWidget::handleLogsTabChanged (int index) { Q_UNUSED(index); // Don't handle anything here if Seer is exiting. if (_aboutToQuit) { return; } writeSettings(); } void SeerCommandLogsWidget::handleRaiseMessageTab () { int idx = logsTabWidget->indexOf(_messagesBrowserWidget); if (idx < 0) { return; } logsTabWidget->setCurrentIndex(idx); } void SeerCommandLogsWidget::handleConsoleModeChanged () { if (_consoleIndex < 0) { return; } if (_consoleWidget == nullptr) { return; } if (_consoleMode == "detached") { logsTabWidget->detachTab(_consoleIndex, false); _consoleWidget->raise(); _consoleWidget->resetSize(); }else if (_consoleMode == "detachedminimized") { logsTabWidget->detachTab(_consoleIndex, true); _consoleWidget->resetSize(); }else if (_consoleMode == "attached") { logsTabWidget->reattachTab(_consoleIndex); }else{ logsTabWidget->reattachTab(_consoleIndex); } } void SeerCommandLogsWidget::handleConsoleNewTextAdded () { if (_consoleIndex >= 0) { logsTabWidget->setTabIcon(_consoleIndex, QIcon(":/seer/resources/RelaxLightIcons/data-information.svg")); } } void SeerCommandLogsWidget::handleConsoleNewTextViewed () { if (_consoleIndex >= 0) { logsTabWidget->setTabIcon(_consoleIndex, QIcon()); } } void SeerCommandLogsWidget::handleManualCommandExecute () { // Get new command. QString command = manualCommandComboBox->currentText(); // Do nothing if it is blank. if (command == "") { return; } // Remove the second to last line, if it is blank. if (manualCommandComboBox->count() >= 2) { QString lastCommand = manualCommandComboBox->itemText(manualCommandComboBox->count()-2); if (lastCommand == "") { manualCommandComboBox->removeItem(manualCommandComboBox->count()-2); } } // Remove the last line, if it is blank. if (manualCommandComboBox->count() >= 1) { QString lastCommand = manualCommandComboBox->itemText(manualCommandComboBox->count()-1); if (lastCommand == "") { manualCommandComboBox->removeItem(manualCommandComboBox->count()-1); } } // Add entered command to the end of the list as long as it's not // already there. if (manualCommandComboBox->count() > 0) { QString lastCommand = manualCommandComboBox->itemText(manualCommandComboBox->count()-1); if (lastCommand != command) { manualCommandComboBox->addItem(command); } } // Add a blank entry. It will be removed when the next manual command is entered. manualCommandComboBox->addItem(""); // Point to last one. manualCommandComboBox->setCurrentIndex(manualCommandComboBox->count()-1); // Execute it. emit executeGdbCommand(command); writeHistorySettings(); } void SeerCommandLogsWidget::handleManualCommandChanged () { writeHistorySettings(); } void SeerCommandLogsWidget::handleLogOutputChanged () { writeLogSettings(); } void SeerCommandLogsWidget::handleGdbLoadBreakpoints () { QFileDialog dialog(this, "Seer - Load Breakpoints from a file.", "./", "Breakpoints (*.seer);;All files (*.*)"); dialog.setOptions(QFileDialog::DontUseNativeDialog); dialog.setAcceptMode(QFileDialog::AcceptOpen); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("seer"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } QString fname = files[0]; emit executeGdbCommand("source -v " + fname); emit refreshBreakpointsList(); QMessageBox::information(this, "Seer", "Loaded."); } void SeerCommandLogsWidget::handleGdbSaveBreakpoints () { if (breakpointsBrowser()->isEmpty() && watchpointsBrowser()->isEmpty() && catchpointsBrowser()->isEmpty() && printpointsBrowser()->isEmpty()) { QMessageBox::information(this, "Seer", "No breakpoints of any kind to save."); return; } QFileDialog dialog(this, "Seer - Save Breakpoints to a file.", "./", "Breakpoints (*.seer);;All files (*.*)"); dialog.setOptions(QFileDialog::DontUseNativeDialog); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("seer"); dialog.selectFile("breakpoints.seer"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } QString fname = files[0]; emit executeGdbCommand("save breakpoints " + fname); QMessageBox::information(this, "Seer", "Saved."); } void SeerCommandLogsWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/BreakpointGdbSeerManager.md"); help->show(); help->raise(); } void SeerCommandLogsWidget::handleMacroToolButtonClicked (QAbstractButton* button) { if (button == nullptr) { return; } SeerMacroToolButton* tb = qobject_cast(button); QString macroFileName = tb->macroFileName(); if (macroFileName == "") { return; } QString commands = tb->commands().join('\n'); if (commands == "") { return; } emit executeGdbCommand(commands); } void SeerCommandLogsWidget::writeSettings () { // Build up visible list. QStringList visible; for (int i=0; itabBar()->count(); i++) { visible.append(logsTabWidget->isTabVisible(i) ? "true" : "false"); } // Build up tab order. QStringList tabs; for (int i=0; itabBar()->count(); i++) { tabs.append(logsTabWidget->tabBar()->tabText(i)); } // Build up current tab. QString current = logsTabWidget->tabBar()->tabText(logsTabWidget->tabBar()->currentIndex()); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Write settings. QSettings settings; settings.beginGroup("logsmanagerwindow"); { settings.setValue("taborder", tabs.join(',')); settings.setValue("tabvisible", visible.join(',')); settings.setValue("tabcurrent", current); } settings.endGroup(); } void SeerCommandLogsWidget::readSettings () { QSettings settings; // Read tab order from settings. QStringList tabs; QStringList visible; QString current; settings.beginGroup("logsmanagerwindow"); { tabs = settings.value("taborder").toString().split(','); visible = settings.value("tabvisible").toString().split(','); current = settings.value("tabcurrent").toString(); } settings.endGroup(); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Move tabs to the requested order. for (int i=0; itabBar()->count(); j++) { if (logsTabWidget->tabBar()->tabText(j) == tab) { tb = j; break; } } if (tb != -1) { logsTabWidget->tabBar()->moveTab(tb, i); } } // Find the console tab index. _consoleIndex = -1; for (int i=0; itabBar()->count(); i++) { if (logsTabWidget->tabBar()->tabText(i) == "Console output") { _consoleIndex = i; break; } } if (_consoleIndex < 0) { qDebug() << "The console tab index is not in the settings."; } // Show/Hide tabs. for (int i=0; isetTabVisible(i,true); }else if (flag == "false") { logsTabWidget->setTabVisible(i,false); }else{ logsTabWidget->setTabVisible(i,true); } } // Make a tab current. if (current != "") { for (int i=0; itabBar()->count(); i++) { if (logsTabWidget->tabBar()->tabText(i) == current) { logsTabWidget->setCurrentIndex(i); break; } } }else{ logsTabWidget->setCurrentIndex(0); } } void SeerCommandLogsWidget::writeHistorySettings () { QSettings settings; // Write the manual command history. settings.beginWriteArray("manualgdbcommandshistory"); { QStringList commands = manualCommands(rememberManualCommandCount()); if (commands.size() > 0) { for (int i = 0; i < commands.size(); ++i) { settings.setArrayIndex(i); settings.setValue("command", commands[i]); } } } settings.endArray(); } void SeerCommandLogsWidget::readHistorySettings () { QSettings settings; // Read the manual command history. int size = settings.beginReadArray("manualgdbcommandshistory"); { QStringList commands; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); commands << settings.value("command").toString(); } setManualCommands(commands); } settings.endArray(); } void SeerCommandLogsWidget::writeLogSettings () { QSettings settings; // Write log settings. settings.beginGroup("gdboutputlog"); { settings.setValue("enabled", _gdbOutputLog->isLogEnabled()); settings.setValue("timestamp", _gdbOutputLog->isTimeStampEnabled()); } settings.endGroup(); settings.beginGroup("seeroutputlog"); { settings.setValue("enabled", _seerOutputLog->isLogEnabled()); settings.setValue("timestamp", _seerOutputLog->isTimeStampEnabled()); } settings.endGroup(); } void SeerCommandLogsWidget::readLogSettings () { QSettings settings; // Read log settings. settings.beginGroup("gdboutputlog"); { _gdbOutputLog->setLogEnabled(settings.value("enabled", true).toBool()); _gdbOutputLog->setTimeStampEnabled(settings.value("timestamp", false).toBool()); } settings.endGroup(); settings.beginGroup("seeroutputlog"); { _seerOutputLog->setLogEnabled(settings.value("enabled", true).toBool()); _seerOutputLog->setTimeStampEnabled(settings.value("timestamp", false).toBool()); } settings.endGroup(); } void SeerCommandLogsWidget::handleAboutToQuit () { _aboutToQuit = true; } void SeerCommandLogsWidget::handleTabsContextMenuButtonClicked() { // Build the menu and execute it. QMenu contextMenu; QWidget* container = new QWidget(&contextMenu); QVBoxLayout* layout = new QVBoxLayout(container); for (int i = 0; i < logsTabWidget->count(); i++) { QString title = logsTabWidget->tabText(i); QCheckBox* showTabCheckBox = new QCheckBox(title, container); showTabCheckBox->setChecked(logsTabWidget->isTabVisible(i)); layout->addWidget(showTabCheckBox); QObject::connect(showTabCheckBox, &QCheckBox::toggled, [this, showTabCheckBox, i](bool checked) { // Count visible tabs. int count=0; for (int x=0; xcount(); x++) { if (logsTabWidget->isTabVisible(x)) { count++; } } // Adjust the count. The 'checked' is made before the UI is updated. if (checked == true) { count++; }else{ count--; } // Reset the checkbox UI if the last visible tab was clicked. if (checked == false and count == 0) { showTabCheckBox->setChecked(true); // Don't hide last visible tab. }else if (checked == false and count > 1) { logsTabWidget->setTabVisible(i, checked); // Always show tabs when asked. }else{ logsTabWidget->setTabVisible(i, checked); } writeSettings(); }); } container->setLayout(layout); QWidgetAction* action = new QWidgetAction(&contextMenu); action->setDefaultWidget(container); contextMenu.addAction(action); contextMenu.exec(QCursor::pos()); } epasveer-seer-97076f1/src/SeerCommandLogsWidget.h000066400000000000000000000124631526321767600217200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerConsoleWidget.h" #include "SeerGdbLogWidget.h" #include "SeerSeerLogWidget.h" #include "SeerMessagesBrowserWidget.h" #include "SeerBreakpointsBrowserWidget.h" #include "SeerWatchpointsBrowserWidget.h" #include "SeerCatchpointsBrowserWidget.h" #include "SeerPrintpointsBrowserWidget.h" #include "SeerCheckpointsBrowserWidget.h" #include #include "ui_SeerCommandLogsWidget.h" class SeerCommandLogsWidget : public QWidget, protected Ui::SeerCommandLogsWidgetForm { Q_OBJECT public: explicit SeerCommandLogsWidget (QWidget* parent = 0); ~SeerCommandLogsWidget (); SeerMessagesBrowserWidget* messagesBrowser (); SeerBreakpointsBrowserWidget* breakpointsBrowser (); SeerWatchpointsBrowserWidget* watchpointsBrowser (); SeerCatchpointsBrowserWidget* catchpointsBrowser (); SeerPrintpointsBrowserWidget* printpointsBrowser (); SeerCheckpointsBrowserWidget* checkpointsBrowser (); SeerGdbLogWidget* gdbOutputLog (); SeerSeerLogWidget* seerOutputLog (); void createConsole (); void deleteConsole (); void reattachConsole (); SeerConsoleWidget* console (); void setConsoleMode (const QString& mode); QString consoleMode () const; void setConsoleScrollLines (int count); int consoleScrollLines () const; void setManualCommands (const QStringList& commands); QStringList manualCommands (int count) const; void setRememberManualCommandCount (int count); int rememberManualCommandCount () const; void clearManualCommandHistory (); protected slots: void handleLogsTabMoved (int to, int from); void handleLogsTabChanged (int index); void handleRaiseMessageTab (); void handleConsoleModeChanged (); void handleConsoleNewTextAdded (); void handleConsoleNewTextViewed (); void handleManualCommandExecute (); void handleManualCommandChanged (); void handleLogOutputChanged (); void handleGdbLoadBreakpoints (); void handleGdbSaveBreakpoints (); void handleHelpToolButtonClicked (); void handleMacroToolButtonClicked (QAbstractButton* button); void handleAboutToQuit (); void handleTabsContextMenuButtonClicked (); signals: void executeGdbCommand (QString command); void refreshBreakpointsList (); protected: void writeSettings (); void readSettings (); void writeHistorySettings (); void readHistorySettings (); void writeLogSettings (); void readLogSettings (); private: SeerConsoleWidget* _consoleWidget; int _consoleIndex; QString _consoleMode; int _consoleScrollLines; int _rememberManualCommandCount; bool _aboutToQuit; SeerMessagesBrowserWidget* _messagesBrowserWidget; SeerBreakpointsBrowserWidget* _breakpointsBrowserWidget; SeerWatchpointsBrowserWidget* _watchpointsBrowserWidget; SeerCatchpointsBrowserWidget* _catchpointsBrowserWidget; SeerPrintpointsBrowserWidget* _printpointsBrowserWidget; SeerCheckpointsBrowserWidget* _checkpointsBrowserWidget; SeerGdbLogWidget* _gdbOutputLog; SeerSeerLogWidget* _seerOutputLog; }; epasveer-seer-97076f1/src/SeerCommandLogsWidget.ui000066400000000000000000000154711526321767600221100ustar00rootroot00000000000000 SeerCommandLogsWidgetForm 0 0 975 384 Seer - Commands and Logs 0 0 0 0 M1 Qt::NoArrow macroButtonGroup M2 macroButtonGroup M3 macroButtonGroup M4 macroButtonGroup M5 macroButtonGroup M6 macroButtonGroup M7 macroButtonGroup M8 macroButtonGroup M9 macroButtonGroup M0 macroButtonGroup Qt::Horizontal 578 20 Load previously saved breakpoints. ... :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Save breakpoints to a file. ... :/seer/resources/RelaxLightIcons/document-save.svg:/seer/resources/RelaxLightIcons/document-save.svg Help on Breakpoint/Logs/Commands information. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg false 0 true Tab 1 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
SeerMacroToolButton QToolButton
SeerMacroToolButton.h
epasveer-seer-97076f1/src/SeerConfigDialog.cpp000066400000000000000000000417331526321767600212330ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerConfigDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include SeerConfigDialog::SeerConfigDialog(QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets QSize size(96, 84); int spacing = 12; contentsListWidget->setViewMode(QListView::IconMode); contentsListWidget->setIconSize(size); contentsListWidget->setMovement(QListView::Static); contentsListWidget->setSpacing(spacing); contentsListWidget->setFixedWidth(size.width()+(spacing*3)); contentsListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QPushButton* resetButton = buttonBox->button(QDialogButtonBox::Reset); if (resetButton) { resetButton->setToolTip("Reset configuration for the current page to initial settings."); } QPushButton* okButton = buttonBox->button(QDialogButtonBox::Ok); if (okButton) { okButton->setToolTip("Accept configuration changes to all pages."); } QPushButton* cancelButton = buttonBox->button(QDialogButtonBox::Cancel); if (cancelButton) { cancelButton->setToolTip("Discard configuration changes to all pages."); } // Create pages. _seerConfigPage = new SeerSeerConfigPage; _gdbConfigPage = new SeerGdbConfigPage; _editorConfigPage = new SeerEditorConfigPage; _sourceConfigPage = new SeerSourceConfigPage; _assemblyConfigPage = new SeerAssemblyConfigPage; _keysConfigPage = new SeerKeysConfigPage; _rrConfigPage = new SeerRRConfigPage; // Add the pages to the stacked widget. pagesStackedWidget->addWidget(_seerConfigPage); pagesStackedWidget->addWidget(_gdbConfigPage); pagesStackedWidget->addWidget(_editorConfigPage); pagesStackedWidget->addWidget(_sourceConfigPage); pagesStackedWidget->addWidget(_assemblyConfigPage); pagesStackedWidget->addWidget(_keysConfigPage); pagesStackedWidget->addWidget(_rrConfigPage); // Create icons. QListWidgetItem* configSeerButton = new QListWidgetItem(contentsListWidget); configSeerButton->setIcon(QIcon(":/seer/resources/icons/hicolor/128x128/seergdb.png")); configSeerButton->setText(tr("Seer")); configSeerButton->setTextAlignment(Qt::AlignHCenter); configSeerButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configGdbButton = new QListWidgetItem(contentsListWidget); configGdbButton->setIcon(QIcon(":/seer/resources/icons-icons/gdb.png")); configGdbButton->setText(tr("GDB")); configGdbButton->setTextAlignment(Qt::AlignHCenter); configGdbButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configEditorButton = new QListWidgetItem(contentsListWidget); configEditorButton->setIcon(QIcon(":/seer/resources/icons-icons/editor.png")); configEditorButton->setText(tr("Editor")); configEditorButton->setTextAlignment(Qt::AlignHCenter); configEditorButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configSourceButton = new QListWidgetItem(contentsListWidget); configSourceButton->setIcon(QIcon(":/seer/resources/thenounproject/source.svg")); configSourceButton->setText(tr("Source")); configSourceButton->setTextAlignment(Qt::AlignHCenter); configSourceButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configAssemblyButton = new QListWidgetItem(contentsListWidget); configAssemblyButton->setIcon(QIcon(":/seer/resources/thenounproject/assembly.svg")); configAssemblyButton->setText(tr("Assembly")); configAssemblyButton->setTextAlignment(Qt::AlignHCenter); configAssemblyButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configKeysButton = new QListWidgetItem(contentsListWidget); configKeysButton->setIcon(QIcon(":/seer/resources/thenounproject/keyboard.svg")); configKeysButton->setText(tr("Keys")); configKeysButton->setTextAlignment(Qt::AlignHCenter); configKeysButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QListWidgetItem* configRRButton = new QListWidgetItem(contentsListWidget); configRRButton->setIcon(QIcon(":/seer/resources/icons/hicolor/256x256/rr.png")); configRRButton->setText(tr("RR")); configRRButton->setTextAlignment(Qt::AlignHCenter); configRRButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); // Connect things. connect(contentsListWidget, &QListWidget::currentItemChanged, this, &SeerConfigDialog::handleChangePage); connect(buttonBox, &QDialogButtonBox::clicked, this, &SeerConfigDialog::handleButtonClicked); // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); Seer::colorizeListWidgetItemIcon(configSeerButton, Seer::iconColorTheme(), QSize(128,128)); Seer::colorizeListWidgetItemIcon(configGdbButton, Seer::iconColorTheme(), QSize(128,128)); Seer::colorizeListWidgetItemIcon(configEditorButton, Seer::iconColorTheme(), QSize(128,128)); Seer::colorizeListWidgetItemIcon(configSourceButton, Seer::iconColorTheme(), QSize(128,128)); Seer::colorizeListWidgetItemIcon(configAssemblyButton, Seer::iconColorTheme(), QSize(128,128)); Seer::colorizeListWidgetItemIcon(configKeysButton, Seer::iconColorTheme(), QSize(128,128)); // Seer::colorizeListWidgetItemIcon(configRRButton, Seer::iconColorTheme(), QSize(128,128)); // Don't change. It's a multi-colored icon. // Set to first page. contentsListWidget->setCurrentRow(0); } SeerConfigDialog::~SeerConfigDialog() { } void SeerConfigDialog::setSeerConsoleMode (const QString& mode) { _seerConfigPage->setConsoleMode(mode); } QString SeerConfigDialog::seerConsoleMode () const { return _seerConfigPage->consoleMode(); } void SeerConfigDialog::setSeerConsoleScrollLines (int count) { _seerConfigPage->setConsoleScrollLines(count); } int SeerConfigDialog::seerConsoleScrollLines () const { return _seerConfigPage->consoleScrollLines(); } void SeerConfigDialog::setSeerRememberWindowSizes (bool flag) { _seerConfigPage->setRememberWindowSizes(flag); } bool SeerConfigDialog::seerRememberWindowSizes () const { return _seerConfigPage->rememberWindowSizes(); } void SeerConfigDialog::setSeerRememberManualCommandCount (int count) { _seerConfigPage->setRememberManualCommandCount(count); } int SeerConfigDialog::seerRememberManualCommandCount () const { return _seerConfigPage->rememberManualCommandCount(); } void SeerConfigDialog::setSeerClearManualCommandHistory (bool flag) { _seerConfigPage->setClearManualCommandHistory(flag); } bool SeerConfigDialog::seerClearManualCommandHistory () const { return _seerConfigPage->clearManualCommandHistory(); } void SeerConfigDialog::setGdbLauncher (const QString& launcher) { _gdbConfigPage->setGdbLauncher(launcher); } QString SeerConfigDialog::gdbLauncher () const { return _gdbConfigPage->gdbLauncher(); } void SeerConfigDialog::setGdbProgram (const QString& program) { _gdbConfigPage->setGdbProgram(program); } QString SeerConfigDialog::gdbProgram () const { return _gdbConfigPage->gdbProgram(); } void SeerConfigDialog::setGdbArguments (const QString& arguments) { _gdbConfigPage->setGdbArguments(arguments); } QString SeerConfigDialog::gdbArguments () const { return _gdbConfigPage->gdbArguments(); } void SeerConfigDialog::setGdbAsyncMode (bool flag) { _gdbConfigPage->setGdbAsyncMode(flag); } bool SeerConfigDialog::gdbAsyncMode () const { return _gdbConfigPage->gdbAsyncMode(); } void SeerConfigDialog::setGdbNonStopMode (bool flag) { _gdbConfigPage->setGdbNonStopMode(flag); } bool SeerConfigDialog::gdbNonStopMode () const { return _gdbConfigPage->gdbNonStopMode(); } void SeerConfigDialog::setGdbHandleTerminatingException (bool flag) { _gdbConfigPage->setGdbHandleTerminatingException(flag); } bool SeerConfigDialog::gdbHandleTerminatingException () const { return _gdbConfigPage->gdbHandleTerminatingException(); } void SeerConfigDialog::setGdbRandomizeStartAddress (bool flag) { _gdbConfigPage->setGdbRandomizeStartAddress(flag); } bool SeerConfigDialog::gdbRandomizeStartAddress () const { return _gdbConfigPage->gdbRandomizeStartAddress(); } void SeerConfigDialog::setGdbEnablePrettyPrinting (bool flag) { _gdbConfigPage->setGdbEnablePrettyPrinting(flag); } bool SeerConfigDialog::gdbEnablePrettyPrinting () const { return _gdbConfigPage->gdbEnablePrettyPrinting(); } void SeerConfigDialog::setGdbRemoteTargetType (const QString& type) { _gdbConfigPage->setGdbRemoteTargetType(type); } QString SeerConfigDialog::gdbRemoteTargetType () const { return _gdbConfigPage->gdbRemoteTargetType(); } void SeerConfigDialog::setGdbArchitectureType (const QString& type) { _gdbConfigPage->setGdbArchitectureType(type); } QString SeerConfigDialog::gdbArchitectureType () const { return _gdbConfigPage->gdbArchitectureType(); } void SeerConfigDialog::setEditorFont (const QFont& font) { _editorConfigPage->setEditorFont(font); } const QFont& SeerConfigDialog::editorFont () const { return _editorConfigPage->editorFont(); } void SeerConfigDialog::setEditorTabSize (int spaces) { _editorConfigPage->setEditorTabSize(spaces); } int SeerConfigDialog::editorTabSize () const { return _editorConfigPage->editorTabSize(); } void SeerConfigDialog::setEditorHighlighterSettings (const SeerHighlighterSettings& settings) { _editorConfigPage->setHighlighterSettings(settings); } const SeerHighlighterSettings& SeerConfigDialog::editorHighlighterSettings () const { return _editorConfigPage->highlighterSettings(); } void SeerConfigDialog::setEditorHighlighterEnabled (bool flag) { _editorConfigPage->setHighlighterEnabled(flag); } bool SeerConfigDialog::editorHighlighterEnabled () const { return _editorConfigPage->highlighterEnabled(); } void SeerConfigDialog::setEditorMinimapEnabled (bool flag) { _editorConfigPage->setMinimapEnabled(flag); } bool SeerConfigDialog::editorMinimapEnabled () const { return _editorConfigPage->minimapEnabled(); } void SeerConfigDialog::setExternalEditorCommand (const QString& externalEditorCommand) { _editorConfigPage->setExternalEditorCommand(externalEditorCommand); } QString SeerConfigDialog::externalEditorCommand () const { return _editorConfigPage->externalEditorCommand(); } void SeerConfigDialog::setEditorAutoSourceReload (bool flag) { _editorConfigPage->setAutoSourceReload(flag); } bool SeerConfigDialog::editorAutoSourceReload () const { return _editorConfigPage->autoSourceReload(); } void SeerConfigDialog::setSourceAlternateDirectories (const QStringList& alternateDirectories) { _sourceConfigPage->setAlternateDirectories(alternateDirectories); } QStringList SeerConfigDialog::sourceAlternateDirectories () const { return _sourceConfigPage->alternateDirectories(); } void SeerConfigDialog::setSourceIgnoreFilePatterns (const QStringList& filePatterns) { _sourceConfigPage->setIgnoreFilePatterns(filePatterns); } QStringList SeerConfigDialog::sourceIgnoreFilePatterns () const { return _sourceConfigPage->ignoreFilePatterns(); } void SeerConfigDialog::setSourceMiscFilePatterns (const QStringList& filePatterns) { _sourceConfigPage->setMiscFilePatterns(filePatterns); } QStringList SeerConfigDialog::sourceMiscFilePatterns () const { return _sourceConfigPage->miscFilePatterns(); } void SeerConfigDialog::setSourceSourceFilePatterns (const QStringList& filePatterns) { _sourceConfigPage->setSourceFilePatterns(filePatterns); } QStringList SeerConfigDialog::sourceSourceFilePatterns () const { return _sourceConfigPage->sourceFilePatterns(); } void SeerConfigDialog::setSourceHeaderFilePatterns (const QStringList& filePatterns) { _sourceConfigPage->setHeaderFilePatterns(filePatterns); } QStringList SeerConfigDialog::sourceHeaderFilePatterns () const { return _sourceConfigPage->headerFilePatterns(); } void SeerConfigDialog::setAssemblyShowAssemblyTabOnStartupMode (const QString& mode) { _assemblyConfigPage->setShowAssemblyTabOnStartupMode(mode); } QString SeerConfigDialog::assemblyShowAssemblyTabOnStartupMode () const { return _assemblyConfigPage->showAssemblyTabOnStartupMode(); } void SeerConfigDialog::setAssemblyKeepAssemblyTabOnTop (bool flag) { _assemblyConfigPage->setKeepAssemblyTabOnTop(flag); } bool SeerConfigDialog::assemblyKeepAssemblyTabOnTop () const { return _assemblyConfigPage->keepAssemblyTabOnTop(); } void SeerConfigDialog::setAssemblyDisassemblyFlavor (const QString& flavor) { _assemblyConfigPage->setDisassemblyFlavor(flavor); } QString SeerConfigDialog::assemblyDisassemblyFlavor () const { return _assemblyConfigPage->disassemblyFlavor(); } void SeerConfigDialog::setAssemblySymbolDemagling (const QString& onoff) { _assemblyConfigPage->setSymbolDemagling(onoff); } QString SeerConfigDialog::assemblySymbolDemagling () const { return _assemblyConfigPage->symbolDemagling(); } void SeerConfigDialog::setAssemblyShowAddressColumn (bool flag) { _assemblyConfigPage->setShowAddressColumn(flag); } bool SeerConfigDialog::assemblyShowAddressColumn () const { return _assemblyConfigPage->showAddressColumn(); } void SeerConfigDialog::setAssemblyShowOffsetColumn (bool flag) { _assemblyConfigPage->setShowOffsetColumn(flag); } bool SeerConfigDialog::assemblyShowOffsetColumn () const { return _assemblyConfigPage->showOffsetColumn(); } void SeerConfigDialog::setAssemblyShowOpcodeColumn (bool flag) { _assemblyConfigPage->setShowOpcodeColumn(flag); } bool SeerConfigDialog::assemblyShowOpcodeColumn () const { return _assemblyConfigPage->showOpcodeColumn(); } void SeerConfigDialog::setAssemblyShowSourceLines (bool flag) { _assemblyConfigPage->setShowSourceLines(flag); } bool SeerConfigDialog::assemblyShowSourceLines () const { return _assemblyConfigPage->showSourceLines(); } void SeerConfigDialog::setAssemblyRegisterFormat (const QString& format) { _assemblyConfigPage->setRegisterFormat(format); } QString SeerConfigDialog::assemblyRegisterFormat () const { return _assemblyConfigPage->registerFormat(); } void SeerConfigDialog::setAssemblyDisassemblyMode (const QString& mode, int bytes) { _assemblyConfigPage->setDisassemblyMode(mode, bytes); } QString SeerConfigDialog::assemblyDisassemblyMode () const { return _assemblyConfigPage->disassemblyMode(); } int SeerConfigDialog::assemblyDisassemblyBytes () const { return _assemblyConfigPage->disassemblyBytes(); } void SeerConfigDialog::setKeySettings (const SeerKeySettings& settings) { _keysConfigPage->setKeySettings(settings); } SeerKeySettings SeerConfigDialog::keySettings () const { return _keysConfigPage->keySettings(); } void SeerConfigDialog::setRRProgram (const QString& program) { _rrConfigPage->setRRProgram(program); } QString SeerConfigDialog::rrProgram () const { return _rrConfigPage->rrProgram(); } void SeerConfigDialog::setRRArguments (const QString& arguments) { _rrConfigPage->setRRArguments(arguments); } QString SeerConfigDialog::rrArguments () const { return _rrConfigPage->rrArguments(); } void SeerConfigDialog::setRRGdbArguments (const QString& arguments) { _rrConfigPage->setGdbArguments(arguments); } QString SeerConfigDialog::rrGdbArguments () const { return _rrConfigPage->gdbArguments(); } void SeerConfigDialog::handleChangePage(QListWidgetItem* current, QListWidgetItem* previous) { if (!current) { current = previous; } pagesStackedWidget->setCurrentIndex(contentsListWidget->row(current)); } void SeerConfigDialog::handleButtonClicked (QAbstractButton* button) { // Handle resetting the config pages if "Reset" is clicked. if (buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole) { QString itemLabel = contentsListWidget->currentItem()->text(); int result = QMessageBox::warning(this, "Seer", QString("Reset settings for the '") + itemLabel + "' tab?", QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel); if (result != QMessageBox::Ok) { return; } if (itemLabel == "GDB") { _gdbConfigPage->reset(); }else if (itemLabel == "Editor") { _editorConfigPage->reset(); }else if (itemLabel == "Source") { _sourceConfigPage->reset(); }else if (itemLabel == "Assembly") { _assemblyConfigPage->reset(); }else if (itemLabel == "Keys") { _keysConfigPage->reset(); }else if (itemLabel == "Seer") { _seerConfigPage->reset(); }else if (itemLabel == "RR") { _rrConfigPage->reset(); } } } epasveer-seer-97076f1/src/SeerConfigDialog.h000066400000000000000000000247031526321767600206760ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerGdbConfigPage.h" #include "SeerRRConfigPage.h" #include "SeerEditorConfigPage.h" #include "SeerSourceConfigPage.h" #include "SeerAssemblyConfigPage.h" #include "SeerKeysConfigPage.h" #include "SeerSeerConfigPage.h" #include #include "ui_SeerConfigDialog.h" class QListWidget; class QListWidgetItem; class QStackedWidget; class SeerConfigDialog : public QDialog, protected Ui::SeerConfigDialogForm { Q_OBJECT public: explicit SeerConfigDialog (QWidget* parent = 0); ~SeerConfigDialog (); // Seer settings. void setSeerConsoleMode (const QString& mode); QString seerConsoleMode () const; void setSeerConsoleScrollLines (int count); int seerConsoleScrollLines () const; void setSeerRememberWindowSizes (bool flag); bool seerRememberWindowSizes () const; void setSeerRememberManualCommandCount (int count); int seerRememberManualCommandCount () const; void setSeerClearManualCommandHistory (bool flag); bool seerClearManualCommandHistory () const; // Gdb settings. // Program to launch gdb, rr, etc. Can be blank. Needed by flatpak. void setGdbLauncher (const QString& launcher); QString gdbLauncher () const; void setGdbProgram (const QString& program); QString gdbProgram () const; void setGdbArguments (const QString& arguments); QString gdbArguments () const; void setGdbAsyncMode (bool flag); bool gdbAsyncMode () const; void setGdbNonStopMode (bool flag); bool gdbNonStopMode () const; void setGdbHandleTerminatingException (bool flag); bool gdbHandleTerminatingException () const; void setGdbRandomizeStartAddress (bool flag); bool gdbRandomizeStartAddress () const; void setGdbEnablePrettyPrinting (bool flag); bool gdbEnablePrettyPrinting () const; void setGdbRemoteTargetType (const QString& type); QString gdbRemoteTargetType () const; void setGdbArchitectureType (const QString& type); QString gdbArchitectureType () const; // Editor settings. void setEditorFont (const QFont& font); const QFont& editorFont () const; void setEditorTabSize (int spaces); int editorTabSize () const; void setEditorHighlighterSettings (const SeerHighlighterSettings& settings); const SeerHighlighterSettings& editorHighlighterSettings () const; void setEditorHighlighterEnabled (bool flag); bool editorHighlighterEnabled () const; void setEditorMinimapEnabled (bool flag); bool editorMinimapEnabled () const; void setExternalEditorCommand (const QString& externalEditorCommand); QString externalEditorCommand () const; void setEditorAutoSourceReload (bool flag); bool editorAutoSourceReload () const; // Source settings. void setSourceAlternateDirectories (const QStringList& alternateDirectories); QStringList sourceAlternateDirectories () const; void setSourceIgnoreFilePatterns (const QStringList& filePatterns); QStringList sourceIgnoreFilePatterns () const; void setSourceMiscFilePatterns (const QStringList& filePatterns); QStringList sourceMiscFilePatterns () const; void setSourceSourceFilePatterns (const QStringList& filePatterns); QStringList sourceSourceFilePatterns () const; void setSourceHeaderFilePatterns (const QStringList& filePatterns); QStringList sourceHeaderFilePatterns () const; // Assembly settings. void setAssemblyShowAssemblyTabOnStartupMode (const QString& mode); QString assemblyShowAssemblyTabOnStartupMode () const; void setAssemblyKeepAssemblyTabOnTop (bool flag); bool assemblyKeepAssemblyTabOnTop () const; void setAssemblyDisassemblyFlavor (const QString& flavor); QString assemblyDisassemblyFlavor () const; void setAssemblySymbolDemagling (const QString& onoff); QString assemblySymbolDemagling () const; void setAssemblyShowAddressColumn (bool flag); bool assemblyShowAddressColumn () const; void setAssemblyShowOffsetColumn (bool flag); bool assemblyShowOffsetColumn () const; void setAssemblyShowOpcodeColumn (bool flag); bool assemblyShowOpcodeColumn () const; void setAssemblyShowSourceLines (bool flag); bool assemblyShowSourceLines () const; void setAssemblyRegisterFormat (const QString& format); QString assemblyRegisterFormat () const; void setAssemblyDisassemblyMode (const QString& mode, int bytes); QString assemblyDisassemblyMode () const; int assemblyDisassemblyBytes () const; // Key settings. void setKeySettings (const SeerKeySettings& settings); SeerKeySettings keySettings () const; // RR settings. void setRRProgram (const QString& program); QString rrProgram () const; void setRRArguments (const QString& arguments); QString rrArguments () const; void setRRGdbArguments (const QString& arguments); QString rrGdbArguments () const; public slots: void handleChangePage (QListWidgetItem* current, QListWidgetItem* previous); void handleButtonClicked (QAbstractButton* button); private: SeerGdbConfigPage* _gdbConfigPage; SeerRRConfigPage* _rrConfigPage; SeerEditorConfigPage* _editorConfigPage; SeerSourceConfigPage* _sourceConfigPage; SeerAssemblyConfigPage* _assemblyConfigPage; SeerKeysConfigPage* _keysConfigPage; SeerSeerConfigPage* _seerConfigPage; }; epasveer-seer-97076f1/src/SeerConfigDialog.ui000066400000000000000000000044101526321767600210550ustar00rootroot00000000000000 SeerConfigDialogForm 0 0 736 569 Seer - Configuration 25 0 75 0 1 -1 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset buttonBox accepted() SeerConfigDialogForm accept() 248 254 157 274 buttonBox rejected() SeerConfigDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerConsoleWidget.cpp000066400000000000000000000340441526321767600214510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerConsoleWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SeerConsoleWidget::SeerConsoleWidget (QWidget* parent) : QWidget(parent) { // Init variables. _terminalDeviceName = ""; _ttyFD = -1; _ttyListener = 0; _enableStdout = false; _enableWrap = false; // Set up UI. setupUi(this); // Setup the widgets setWindowTitle("Seer Console"); textEdit->setReadOnly(true); textEdit->setTextInteractionFlags(textEdit->textInteractionFlags() | Qt::TextSelectableByKeyboard); // Show cursor textEdit->setLineWrapMode(QPlainTextEdit::NoWrap); // No wrap // Default font. QFont font; font.setFamily("monospace"); font.setStyleHint(QFont::Monospace); font.setFixedPitch(true); // Set the widget's font. QTextCharFormat format = textEdit->currentCharFormat(); format.setFont(font); textEdit->setCurrentCharFormat(format); textEdit->setFont(font); wrapTextCheckBox->setCheckState(Qt::Unchecked); // No wrap // Connect things. QObject::connect(clearButton, &QPushButton::clicked, this, &SeerConsoleWidget::handleClearButton); QObject::connect(printButton, &QPushButton::clicked, this, &SeerConsoleWidget::handlePrintButton); QObject::connect(saveButton, &QPushButton::clicked, this, &SeerConsoleWidget::handleSaveButton); QObject::connect(fontButton, &QPushButton::clicked, this, &SeerConsoleWidget::handleFontButton); QObject::connect(wrapTextCheckBox, &QCheckBox::clicked, this, &SeerConsoleWidget::handleWrapTextCheckBox); QObject::connect(stdoutCheckBox, &QCheckBox::clicked, this, &SeerConsoleWidget::handleStdoutCheckBox); QObject::connect(stdinLineEdit, &QLineEdit::returnPressed, this, &SeerConsoleWidget::handleStdinLineEdit); // Restore window settings. readSettings(); } SeerConsoleWidget::~SeerConsoleWidget () { deleteTerminal(); // Will disconnect terminal first befor deleting. } void SeerConsoleWidget::handleText (const char* buffer, int count) { if (count < 1) { return; } // Write text to stdout on terminal that started Seer.. // Ignore errors. if (isStdoutEnabled()) { ssize_t n = ::write (STDOUT_FILENO, buffer, count); if (n < count) { qDebug("Can't write stdout to terminal"); } } // Write text to Ansi widget. #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QString str = _utf8Decoder.decode(QByteArrayView(buffer, count)); #else QString str = QString::fromUtf8(buffer, count); #endif textEdit->insertAnsiText(str); textEdit->ensureCursorVisible(); // Send signal of new text if this widget is not visable. if (isVisible() == false) { emit newTextAdded(); } return; } void SeerConsoleWidget::handleChangeWindowTitle (QString title) { if (title == "") { setWindowTitle("Seer Console"); }else{ setWindowTitle("Seer Console - '" + title + "'"); } } void SeerConsoleWidget::handleTabDetached (QWidget* widget) { if (widget != (QWidget*)this) { return; } // Resize the detached console with the size from // the settings. QSettings settings; settings.beginGroup("consolewindow"); { resize(settings.value("size", QSize(800, 600)).toSize()); } settings.endGroup(); } void SeerConsoleWidget::handleTabReattached (QWidget* widget) { // Do nothing for now. Q_UNUSED(widget); } void SeerConsoleWidget::handleClearButton () { textEdit->clear(); } void SeerConsoleWidget::handlePrintButton () { QPrinter printer; QPrintDialog* dlg = new QPrintDialog(&printer, this); if (dlg->exec() != QDialog::Accepted) { return; } QTextDocument* document = textEdit->document(); document->print(&printer); } void SeerConsoleWidget::handleSaveButton () { QFileDialog dialog(this, "Seer log file", "./", "Logs (*.log);;Text files (*.txt);;All files (*.*)"); dialog.setOptions(QFileDialog::DontUseNativeDialog); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("log"); dialog.selectFile("gdboutput.log"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } QFile file(files[0]); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); stream << textEdit->toPlainText(); file.flush(); file.close(); }else{ QMessageBox::critical(this, tr("Error"), tr("Cannot save log to file.")); return; } } void SeerConsoleWidget::handleFontButton () { // Get current format for the font name. bool ok; QFont font = QFontDialog::getFont(&ok, textEdit->font().toString(), this, "Seer - Select Console Font", QFontDialog::DontUseNativeDialog|QFontDialog::MonospacedFonts); if (ok == false) { return; } // Set the widget's font. QTextCharFormat format = textEdit->currentCharFormat(); format.setFont(font); textEdit->setCurrentCharFormat(format); textEdit->setFont(font); writeFontSettings(); } void SeerConsoleWidget::handleWrapTextCheckBox () { if (wrapTextCheckBox->checkState() == Qt::Unchecked) { textEdit->setLineWrapMode(QPlainTextEdit::NoWrap); // No wrap _enableWrap = false; }else{ textEdit->setLineWrapMode(QPlainTextEdit::WidgetWidth); // Wrap at end of widget _enableWrap = true; } writeSettings(); } void SeerConsoleWidget::handleStdoutCheckBox () { // Don't write text to the terminal's stdout. if (stdoutCheckBox->checkState() == Qt::Unchecked) { enableStdout(false); writeSettings(); return; } // If stdout is not valid, don't set it. if (fcntl(STDOUT_FILENO, F_GETFD) == -1) { QMessageBox::critical(this, tr("Error"), tr("stdout file descriptor is not valid.\nDisabling writing to stdout.")); enableStdout(false); writeSettings(); return; } // All good to write to stdout enableStdout(true); writeSettings(); } void SeerConsoleWidget::handleStdinLineEdit () { QString str = stdinLineEdit->text(); stdinLineEdit->clear(); str += '\n'; std::string s = str.toStdString(); if (isTerminalCreated() == false) { return; } int n = write(_ttyFD, s.c_str(), s.length()); if (n != (signed long int)s.length()) { qWarning() << "Not able to process stdin of" << s.length() << "bytes."; } fsync(_ttyFD); } void SeerConsoleWidget::handleTerminalOutput (int socketfd) { if (isTerminalCreated() == false) { return; } Q_UNUSED(socketfd); char buffer[1024]; while (1) { int n = read(_ttyFD, buffer, sizeof(buffer)); if (n < 0) { if (errno == EAGAIN) { break; } if (errno == EIO) { // Disconnect terminal if tty has an I/O error. // Can be reconnected later just before gdb restarts it's target program. disconnectTerminal(); break; } break; } handleText(buffer, n); break; } } void SeerConsoleWidget::createTerminal () { // Is terminal already created? if (isTerminalCreated()) { qDebug() << "Terminal already created!"; return; } // Create tty and its permissions. _ttyFD = posix_openpt(O_RDWR | O_NOCTTY); if (_ttyFD < 0) { qDebug() << "Failed to create tty" << strerror(errno); return; } if (grantpt(_ttyFD)) { qDebug() << "Failed to grant pt" << strerror(errno); ::close(_ttyFD); _ttyFD = -1; return; } if (unlockpt(_ttyFD)) { qDebug() << "Failed to unlock pt" << strerror(errno); ::close(_ttyFD); _ttyFD = -1; return; } // Turn off blocking. fcntl(_ttyFD, F_SETFL, O_NDELAY); // Set window size struct winsize term_winsize; term_winsize.ws_col = 80; term_winsize.ws_row = 20; term_winsize.ws_xpixel = 80 * 8; term_winsize.ws_ypixel = 20 * 8; if (ioctl(_ttyFD, TIOCSWINSZ, &term_winsize) < 0) { qDebug() << "ioctl TIOCSWINSZ failed" << strerror(errno); } // Set controlling if (ioctl(_ttyFD, TIOCSCTTY, (char *)0) < 0) { // Seems to work even though this fails. // qDebug() << "ioctl TIOCSCTTY failed" << strerror(errno); } // Save the device name. _terminalDeviceName = ptsname(_ttyFD); // Set maximum blocks to 0 (unlimited). // The createTerminal can be followed with a setScrollLines() call. setScrollLines(0); } void SeerConsoleWidget::deleteTerminal () { disconnectTerminal(); _terminalDeviceName = ""; if (isTerminalCreated() == false) { return; } ::close(_ttyFD); _ttyFD = -1; } void SeerConsoleWidget::connectTerminal () { if (isTerminalConnected()) { //qDebug() << "Terminal is already connected!"; return; } if (isTerminalCreated() == false) { qDebug() << "Can't connect Terminal. No _ttyFD!"; return; } _ttyListener = new QSocketNotifier(_ttyFD, QSocketNotifier::Read); QObject::connect(_ttyListener, &QSocketNotifier::activated, this, &SeerConsoleWidget::handleTerminalOutput); } void SeerConsoleWidget::disconnectTerminal () { if (isTerminalConnected() == false) { //qDebug() << "Terminal is already disconnected!"; return; } QObject::disconnect(_ttyListener, &QSocketNotifier::activated, this, &SeerConsoleWidget::handleTerminalOutput); delete _ttyListener; _ttyListener = 0; } bool SeerConsoleWidget::isTerminalCreated () const { if (_ttyFD >= 0) { return true; } return false; } bool SeerConsoleWidget::isTerminalConnected () const { if (_ttyListener != nullptr) { return true; } return false; } void SeerConsoleWidget::resetTerminal () { if (isTerminalConnected()) { disconnectTerminal(); } if (isTerminalCreated() == true) { deleteTerminal(); } createTerminal(); } const QString& SeerConsoleWidget::terminalDeviceName () const { return _terminalDeviceName; } void SeerConsoleWidget::setScrollLines (int count) { textEdit->setMaximumBlockCount(count); } int SeerConsoleWidget::scrollLines () const { return textEdit->maximumBlockCount(); } void SeerConsoleWidget::enableStdout (bool flag) { _enableStdout = flag; stdoutCheckBox->setChecked(_enableStdout); } bool SeerConsoleWidget::isStdoutEnabled () const { return _enableStdout; } void SeerConsoleWidget::enableWrap (bool flag) { _enableWrap = flag; wrapTextCheckBox->setChecked(_enableWrap); } bool SeerConsoleWidget::isWrapEnabled () const { return _enableWrap; } void SeerConsoleWidget::resetSize () { // If there's a parent, don't reset the size. // This means the console is attached in the // tab bar and its size has been shrunk. We // only want to resize if the console // has been detached, ie: no parent. if (parent() != 0) { return; } QSettings settings; settings.beginGroup("consolewindow"); { resize(settings.value("size", QSize(800, 600)).toSize()); } settings.endGroup(); } void SeerConsoleWidget::writeSettings() { QSettings settings; settings.beginGroup("consolewindow"); { settings.setValue("stdout", isStdoutEnabled()); settings.setValue("wrap", isWrapEnabled()); }settings.endGroup(); } void SeerConsoleWidget::writeFontSettings() { QSettings settings; settings.beginGroup("consolewindow"); { settings.setValue("font", textEdit->font().toString()); }settings.endGroup(); } void SeerConsoleWidget::writeSizeSettings() { // If there's a parent, don't save the size. // This means the console is attached in the // tab bar and its size has been shrunk. We // only want to save resizes if the console // has been detached, ie: no parent. if (parent() != 0) { return; } QSettings settings; settings.beginGroup("consolewindow"); { settings.setValue("size", size()); }settings.endGroup(); } void SeerConsoleWidget::readSettings() { QSettings settings; settings.beginGroup("consolewindow"); { resize(settings.value("size", QSize(800, 600)).toSize()); enableStdout(settings.value("stdout", false).toBool()); enableWrap(settings.value("wrap", false).toBool()); QFont f; if (settings.contains("font")) { f.fromString(settings.value("font").toString()); }else{ f = QFont("monospace", 10); } // Get current format for the font name. QTextCharFormat format = textEdit->currentCharFormat(); format.setFont(f); textEdit->setCurrentCharFormat(format); textEdit->setFont(f); } settings.endGroup(); } void SeerConsoleWidget::resizeEvent (QResizeEvent* event) { // Write window settings. writeSizeSettings(); QWidget::resizeEvent(event); } void SeerConsoleWidget::showEvent (QShowEvent* event) { // Handle the event as normal. QWidget::showEvent(event); // Set focus on the text input. stdinLineEdit->setFocus(); // Announce we are now visable. emit newTextViewed(); } epasveer-seer-97076f1/src/SeerConsoleWidget.h000066400000000000000000000065421526321767600211200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #endif #include "ui_SeerConsoleWidget.h" class SeerConsoleWidget : public QWidget, protected Ui::SeerConsoleWidgetForm { Q_OBJECT public: explicit SeerConsoleWidget (QWidget* parent = 0); ~SeerConsoleWidget (); void createTerminal (); void deleteTerminal (); void connectTerminal (); void disconnectTerminal (); bool isTerminalCreated () const; bool isTerminalConnected () const; void resetTerminal (); const QString& terminalDeviceName () const; void setScrollLines (int count); int scrollLines () const; void enableStdout (bool flag); bool isStdoutEnabled () const; void enableWrap (bool flag); bool isWrapEnabled () const; void resetSize (); signals: void newTextAdded (); void newTextViewed (); public slots: void handleChangeWindowTitle (QString title); void handleTabDetached (QWidget* widget); void handleTabReattached (QWidget* widget); protected slots: void handleClearButton (); void handlePrintButton (); void handleSaveButton (); void handleFontButton (); void handleWrapTextCheckBox (); void handleStdoutCheckBox (); void handleStdinLineEdit (); void handleTerminalOutput (int socketfd); protected: void handleText (const char* buffer, int count); void writeSettings (); void writeFontSettings (); void writeSizeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); void showEvent (QShowEvent* event); private: QString _terminalDeviceName; int _ttyFD; QSocketNotifier* _ttyListener; bool _enableStdout; bool _enableWrap; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QStringDecoder _utf8Decoder{QStringConverter::Utf8}; // Keeps state across reads so multi-byte sequences split by the 1024-byte buffer decode correctly. #endif }; epasveer-seer-97076f1/src/SeerConsoleWidget.ui000066400000000000000000000106611526321767600213030ustar00rootroot00000000000000 SeerConsoleWidgetForm 0 0 891 589 Seer Console Save the log output to a file. :/seer/resources/RelaxLightIcons/document-save-as.svg:/seer/resources/RelaxLightIcons/document-save-as.svg Clear the log output. :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg QPlainTextEdit::NoWrap false [program output text] Print the log output. :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg 100 0 [stdin input text] true Wrap long lines to the next line. Wrap Select the log output font. :/seer/resources/icons-icons/font.png:/seer/resources/icons-icons/font.png Send output to stdout as well. stdout QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
QAnsiTextEdit QPlainTextEdit
QAnsiTextEdit.h
epasveer-seer-97076f1/src/SeerCppSourceHighlighter.cpp000066400000000000000000000157341526321767600227720ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCppSourceHighlighter.h" SeerCppSourceHighlighter::SeerCppSourceHighlighter (QTextDocument* parent) : SeerSourceHighlighter(parent) { // Set to default formats. setHighlighterSettings(SeerHighlighterSettings::populate("")); } void SeerCppSourceHighlighter::setHighlighterSettings (const SeerHighlighterSettings& settings) { _highlighterSettings = settings; _classFormat = _highlighterSettings.get("Class"); _quotationFormat = _highlighterSettings.get("Quotation"); _functionFormat = _highlighterSettings.get("Function"); _singleLineCommentFormat = _highlighterSettings.get("Comment"); _multiLineCommentFormat = _highlighterSettings.get("Multiline Comment"); _keywordFormat = _highlighterSettings.get("Keyword"); /* List from QT example. const QString keywordPatterns[] = { QStringLiteral("\\bchar\\b"), QStringLiteral("\\bclass\\b"), QStringLiteral("\\bconst\\b"), QStringLiteral("\\bdouble\\b"), QStringLiteral("\\benum\\b"), QStringLiteral("\\bexplicit\\b"), QStringLiteral("\\bfriend\\b"), QStringLiteral("\\binline\\b"), QStringLiteral("\\bint\\b"), QStringLiteral("\\blong\\b"), QStringLiteral("\\bnamespace\\b"), QStringLiteral("\\boperator\\b"), QStringLiteral("\\bprivate\\b"), QStringLiteral("\\bprotected\\b"), QStringLiteral("\\bpublic\\b"), QStringLiteral("\\bshort\\b"), QStringLiteral("\\bsignals\\b"), QStringLiteral("\\bsigned\\b"), QStringLiteral("\\bslots\\b"), QStringLiteral("\\bstatic\\b"), QStringLiteral("\\bstruct\\b"), QStringLiteral("\\btemplate\\b"), QStringLiteral("\\btypedef\\b"), QStringLiteral("\\btypename\\b"), QStringLiteral("\\bunion\\b"), QStringLiteral("\\bunsigned\\b"), QStringLiteral("\\bvirtual\\b"), QStringLiteral("\\bvoid\\b"), QStringLiteral("\\bvolatile\\b"), QStringLiteral("\\bbool\\b") }; */ // List from the kdbg debugger. const QString keywordPatterns[] = { QStringLiteral("\\balignas\\b"), QStringLiteral("\\balignof\\b"), QStringLiteral("\\band\\b"), QStringLiteral("\\band_eq\\b"), QStringLiteral("\\basm\\b"), QStringLiteral("\\bauto\\b"), QStringLiteral("\\bbitand\\b"), QStringLiteral("\\bbitor\\b"), QStringLiteral("\\bbool\\b"), QStringLiteral("\\bbreak\\b"), QStringLiteral("\\bcase\\b"), QStringLiteral("\\bcatch\\b"), QStringLiteral("\\bchar\\b"), QStringLiteral("\\bchar16_t\\b"), QStringLiteral("\\bchar32_t\\b"), QStringLiteral("\\bclass\\b"), QStringLiteral("\\bcompl\\b"), QStringLiteral("\\bconst\\b"), QStringLiteral("\\bconst_cast\\b"), QStringLiteral("\\bconstexpr\\b"), QStringLiteral("\\bcontinue\\b"), QStringLiteral("\\bdecltype\\b"), QStringLiteral("\\bdefault\\b"), QStringLiteral("\\bdelete\\b"), QStringLiteral("\\bdo\\b"), QStringLiteral("\\bdouble\\b"), QStringLiteral("\\bdynamic_cast\\b"), QStringLiteral("\\belse\\b"), QStringLiteral("\\benum\\b"), QStringLiteral("\\bexplicit\\b"), QStringLiteral("\\bexport\\b"), QStringLiteral("\\bextern\\b"), QStringLiteral("\\bfalse\\b"), QStringLiteral("\\bfloat\\b"), QStringLiteral("\\bfor\\b"), QStringLiteral("\\bfriend\\b"), QStringLiteral("\\bgoto\\b"), QStringLiteral("\\bif\\b"), QStringLiteral("\\binline\\b"), QStringLiteral("\\bint\\b"), QStringLiteral("\\blong\\b"), QStringLiteral("\\bmutable\\b"), QStringLiteral("\\bnamespace\\b"), QStringLiteral("\\bnew\\b"), QStringLiteral("\\bnoexcept\\b"), QStringLiteral("\\bnot\\b"), QStringLiteral("\\bnot_eq\\b"), QStringLiteral("\\bnullptr\\b"), QStringLiteral("\\boperator\\b"), QStringLiteral("\\bor\\b"), QStringLiteral("\\bor_eq\\b"), QStringLiteral("\\bprivate\\b"), QStringLiteral("\\bprotected\\b"), QStringLiteral("\\bpublic\\b"), QStringLiteral("\\bregister\\b"), QStringLiteral("\\breinterpret_cast\\b"), QStringLiteral("\\breturn\\b"), QStringLiteral("\\bshort\\b"), QStringLiteral("\\bsigned\\b"), QStringLiteral("\\bsizeof\\b"), QStringLiteral("\\bstatic\\b"), QStringLiteral("\\bstatic_assert\\b"), QStringLiteral("\\bstatic_cast\\b"), QStringLiteral("\\bstruct\\b"), QStringLiteral("\\bswitch\\b"), QStringLiteral("\\btemplate\\b"), QStringLiteral("\\bthis\\b"), QStringLiteral("\\bthread_local\\b"), QStringLiteral("\\bthrow\\b"), QStringLiteral("\\btrue\\b"), QStringLiteral("\\btry\\b"), QStringLiteral("\\btypedef\\b"), QStringLiteral("\\btypeid\\b"), QStringLiteral("\\btypename\\b"), QStringLiteral("\\bunion\\b"), QStringLiteral("\\bunsigned\\b"), QStringLiteral("\\busing\\b"), QStringLiteral("\\bvirtual\\b"), QStringLiteral("\\bvoid\\b"), QStringLiteral("\\bvolatile\\b"), QStringLiteral("\\bwchar_t\\b"), QStringLiteral("\\bwhile\\b"), QStringLiteral("\\bxor\\b"), QStringLiteral("\\bxor_eq\\b"), QStringLiteral("\\bslots\\b"), QStringLiteral("\\bsignals\\b") }; _highlightingRules.clear(); // Clear old rules. HighlightingRule rule; // Set class format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\bQ[A-Za-z]+\\b")); rule.format = _classFormat; _highlightingRules.append(rule); // Set function format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Za-z0-9_]+(?=\\s*\\()")); rule.format = _functionFormat; _highlightingRules.append(rule); // Set keywords format and expression (must have precedence over functions) for (const QString& pattern : keywordPatterns) { rule.pattern = QRegularExpression(pattern); rule.format = _keywordFormat; _highlightingRules.append(rule); } // Set quote format and expression. This rule must come after the function // and keyword rules so that string contents keep the quote format (same // order as the Ada highlighter). rule.pattern = QRegularExpression(QStringLiteral("\"[^\"]*\"")); rule.format = _quotationFormat; _highlightingRules.append(rule); // Set single line comment format and expression. rule.pattern = QRegularExpression(QStringLiteral("//[^\n]*")); rule.format = _singleLineCommentFormat; _highlightingRules.append(rule); // Set multi-line comment expression. Format is defined later. _commentStartExpression = QRegularExpression(QStringLiteral("/\\*")); _commentEndExpression = QRegularExpression(QStringLiteral("\\*/")); } epasveer-seer-97076f1/src/SeerCppSourceHighlighter.h000066400000000000000000000007261526321767600224320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerHighlighterSettings.h" #include "SeerSourceHighlighter.h" class SeerCppSourceHighlighter : public SeerSourceHighlighter { Q_OBJECT public: SeerCppSourceHighlighter(QTextDocument *parent = 0); virtual void setHighlighterSettings (const SeerHighlighterSettings &settings) override; }; epasveer-seer-97076f1/src/SeerCxxSourceHighlighter.cpp000066400000000000000000000131561526321767600230060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerCxxSourceHighlighter.h" #include // // This C++ syntax highlighter is based on the one in the kdbg debugger. // However, it doesn't work well. // // I'll leave it in the Seer source directory for reference purposes. // // Instead, the SeerCppSourceHighlighter is used. // SeerCxxSourceHighlighter::SeerCxxSourceHighlighter (QTextDocument* parent) : QSyntaxHighlighter(parent) { } enum HLState { hlCommentLine = 1, hlCommentBlock, hlIdent, hlString }; static const QString ckw[] = { "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "const", "const_cast", "constexpr", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "template", "this", "thread_local", "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq" }; void SeerCxxSourceHighlighter::highlightBlock (const QString& text) { int state = previousBlockState(); state = highlight(text, state); setCurrentBlockState(state); } int SeerCxxSourceHighlighter::highlight (const QString& text, int state) { if (state == -2) // initial state state = 0; // check for preprocessor line if (state == 0 && text.trimmed().startsWith("#")) { setFormat(0, text.length(), QColor("darkgreen")); return 0; } // a font for keywords QTextCharFormat identFont; identFont.setFontWeight(QFont::Bold); int start = 0; while (start < text.length()) { int end; switch (state) { case hlCommentLine: end = text.length(); state = 0; setFormat(start, end-start, QColor("gray")); break; case hlCommentBlock: end = text.indexOf("*/", start); if (end >= 0) { end += 2, state = 0; }else{ end = text.length(); } setFormat(start, end-start, QColor("gray")); break; case hlString: for (end = start+1; end < int(text.length()); end++) { if (text[end] == '\\') { if (end < int(text.length())) { ++end; } }else if (text[end] == text[start]) { ++end; break; } } state = 0; setFormat(start, end-start, QColor("darkred")); break; case hlIdent: for (end = start+1; end < int(text.length()); end++) { if (!text[end].isLetterOrNumber() && text[end] != '_') { break; } } state = 0; if (isCppKeyword(text.mid(start, end-start))) { setFormat(start, end-start, identFont); }else{ //setFormat(start, end-start, Normal Format); } break; default: for (end = start; end < int(text.length()); end++) { if (text[end] == '/') { if (end+1 < int(text.length())) { if (text[end+1] == '/') { state = hlCommentLine; break; }else if (text[end+1] == '*') { state = hlCommentBlock; break; } } }else if (text[end] == '"' || text[end] == '\'') { state = hlString; break; }else if ((text[end] >= 'A' && text[end] <= 'Z') || (text[end] >= 'a' && text[end] <= 'z') || text[end] == '_') { state = hlIdent; break; } } //setFormat(start, end-start, Normal Format); } start = end; } return state; } bool SeerCxxSourceHighlighter::isCppKeyword (const QString& word) { // std::binary_search requires the search list to be sorted static bool keyword_order_verified = false; if (keyword_order_verified == false) { for (size_t i = 1; i < sizeof(ckw)/sizeof(ckw[0]); ++i) { if (ckw[i-1] > ckw[i]) { qDebug("\"%s\" > \"%s\"", qPrintable(ckw[i-1]), qPrintable(ckw[i])); assert(0); } } keyword_order_verified = true; } return std::binary_search(ckw, ckw + sizeof(ckw)/sizeof(ckw[0]), word); } epasveer-seer-97076f1/src/SeerCxxSourceHighlighter.h000066400000000000000000000013521526321767600224460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include class SeerCxxSourceHighlighter : public QSyntaxHighlighter { Q_OBJECT public: SeerCxxSourceHighlighter (QTextDocument* parent = 0); protected: void highlightBlock (const QString& text) override; int highlight (const QString& text, int state); static bool isCppKeyword (const QString& word); }; epasveer-seer-97076f1/src/SeerDebugDialog.cpp000066400000000000000000001111021526321767600210400ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerDebugDialog.h" #include "SeerExecutableFilterProxyModel.h" #include "SeerDirectoryFilterProxyModel.h" #include "SeerSlashProcDialog.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include #include #include #include #include SeerDebugDialog::SeerDebugDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); buttonBox->button(QDialogButtonBox::Ok)->setText("Launch"); buttonBox->button(QDialogButtonBox::Reset)->setText("Clear"); // Setup the widgets reset(); // Create editor options bar. QToolButton* loadProjectToolButton = new QToolButton(runModeTabWidget); loadProjectToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/document-open.svg")); loadProjectToolButton->setToolTip("Load a Seer project file."); QToolButton* saveProjectToolButton = new QToolButton(runModeTabWidget); saveProjectToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/document-save.svg")); saveProjectToolButton->setToolTip("Save a Seer project file."); QToolButton* helpModeToolButton = new QToolButton(runModeTabWidget); helpModeToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpModeToolButton->setToolTip("Help on the debug launch modes."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(loadProjectToolButton); hcontainer->addWidget(saveProjectToolButton); hcontainer->addWidget(helpModeToolButton); runModeTabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Connect things. QObject::connect(executableNameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleExecutableNameToolButton); QObject::connect(executableSymbolNameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleExecutableSymbolNameToolButton); QObject::connect(executableWorkingDirectoryToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleExecutableWorkingDirectoryToolButton); QObject::connect(loadBreakpointsFilenameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadBreakpointsFilenameToolButton); QObject::connect(rrLoadTraceDirectoryToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadRRTraceDirectoryToolButton); QObject::connect(rrLoadBreakpointsFilenameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadBreakpointsFilenameToolButton); QObject::connect(loadCoreFilenameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadCoreFilenameToolButton); QObject::connect(breakpointInFunctionLineEdit, &QLineEdit::textChanged, this, &SeerDebugDialog::handleBreakpointInFunctionLineEdit); QObject::connect(attachProgramPidToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleProgramPidToolButton); QObject::connect(loadProjectToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadProjectToolButton); QObject::connect(saveProjectToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleSaveProjectToolButton); QObject::connect(helpModeToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpModeToolButtonClicked); QObject::connect(helpRunToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpRunToolButtonClicked); QObject::connect(helpAttachToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpAttachToolButtonClicked); QObject::connect(helpConnectToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpConnectToolButtonClicked); QObject::connect(helpRRToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpRRToolButtonClicked); QObject::connect(helpCorefileToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpCorefileToolButtonClicked); QObject::connect(runModeTabWidget, &QTabWidget::currentChanged, this, &SeerDebugDialog::handleRunModeChanged); QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &SeerDebugDialog::handleLaunchButtonClicked); QObject::connect(buttonBox, &QDialogButtonBox::clicked, this, &SeerDebugDialog::handleResetButtonClicked); // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); // Set initial run mode. handleRunModeChanged(0); // Restore window settings. readSettings(); // Read default project settings, if any. loadDefaultProjectSettings(); } SeerDebugDialog::~SeerDebugDialog () { } void SeerDebugDialog::reset () { // At least retain the launch mode. QString launchmode = launchMode(); // Reset everything else. setExecutableName(""); setExecutableSymbolName(""); setExecutableWorkingDirectory(""); setExecutableArguments(""); setBreakpointsFilename(""); setBreakpointFunctionName(""); setBreakpointSourceName(""); setBreakpointFirstInstruction(false); setBreakpointMode("inmain"); setShowAssemblyTabMode("never"); setRandomizeStartAddress(false); setNonStopMode(false); setPreGdbCommands(QStringList()); setPostGdbCommands(QStringList()); setAttachPid(0); setConnectHostPort(""); setConnectRemoteTargetType("remote"); setConnectGdbserverDebug(false); setRRTraceDirectory(""); setCoreFilename(""); setLaunchMode(launchmode); setProjectFilename(""); } void SeerDebugDialog::setExecutableName (const QString& executableName) { executableNameLineEdit->setText(executableName); } QString SeerDebugDialog::executableName () const { if (executableNameLineEdit->isEnabled()) { return executableNameLineEdit->text(); } return ""; } void SeerDebugDialog::setExecutableSymbolName (const QString& executableSymbolName) { executableSymbolNameLineEdit->setText(executableSymbolName); } QString SeerDebugDialog::executableSymbolName () const { if (executableSymbolNameLineEdit->isEnabled()) { return executableSymbolNameLineEdit->text(); } return ""; } void SeerDebugDialog::setExecutableWorkingDirectory (const QString& executableWorkingDirectory) { executableWorkingDirectoryLineEdit->setText(executableWorkingDirectory); } QString SeerDebugDialog::executableWorkingDirectory () const { if (executableWorkingDirectoryLineEdit->isEnabled()) { return executableWorkingDirectoryLineEdit->text(); } return ""; } void SeerDebugDialog::setExecutableArguments (const QString& executableArguments) { runProgramArgumentsLineEdit->setText(executableArguments); } QString SeerDebugDialog::executableArguments () const { return runProgramArgumentsLineEdit->text(); } void SeerDebugDialog::setBreakpointsFilename (const QString& breakpointsFilename) { // Try to keep these in sync. Arg! loadBreakpointsFilenameLineEdit->setText(breakpointsFilename); rrLoadBreakpointsFilenameLineEdit->setText(breakpointsFilename); } QString SeerDebugDialog::breakpointsFilename () const { return loadBreakpointsFilenameLineEdit->text(); } void SeerDebugDialog::setBreakpointMode (const QString& mode) { if (mode == "none") { noBreakpointRadioButton->setChecked(true); return; }else if (mode == "inmain") { breakpointInMainRadioButton->setChecked(true); return; }else if (mode == "infunction") { breakpointInFunctionRadioButton->setChecked(true); return; }else if (mode == "insource") { breakpointAtSourceRadioButton->setChecked(true); return; }else if (mode == "firstinstruction") { breakpointAtFirstInstructionRadioButton->setChecked(true); return; } // Default of "inmain". breakpointInMainRadioButton->setChecked(true); } QString SeerDebugDialog::breakpointMode () const { if (noBreakpointRadioButton->isChecked()) { return "none"; }else if (breakpointInMainRadioButton->isChecked()) { return "inmain"; }else if (breakpointInFunctionRadioButton->isChecked()) { return "infunction"; }else if (breakpointAtSourceRadioButton->isChecked()) { return "insource"; }else if (breakpointAtFirstInstructionRadioButton->isChecked()) { return "firstinstruction"; } return "inmain"; } void SeerDebugDialog::setBreakpointFunctionName (const QString& nameoraddress) { breakpointInFunctionLineEdit->setText(nameoraddress); if (nameoraddress != "") { breakpointInFunctionRadioButton->setChecked(true); } } QString SeerDebugDialog::breakpointFunctionName () const { return breakpointInFunctionLineEdit->text(); } void SeerDebugDialog::setBreakpointSourceName (const QString& sourceFilenameAndLineno) { breakpointAtSourceLineEdit->setText(sourceFilenameAndLineno); if (sourceFilenameAndLineno != "") { breakpointAtSourceRadioButton->setChecked(true); } } QString SeerDebugDialog::breakpointSourceName () const { return breakpointAtSourceLineEdit->text(); } void SeerDebugDialog::setBreakpointFirstInstruction (bool flag) { breakpointAtFirstInstructionRadioButton->setChecked(flag); } bool SeerDebugDialog::breakpointFirstInstruction () const { return breakpointAtFirstInstructionRadioButton->isChecked(); } void SeerDebugDialog::setShowAssemblyTabMode (const QString& mode) { showAssemblyTabComboBox->setCurrentText(mode); } QString SeerDebugDialog::showAssemblyTabMode () const { return showAssemblyTabComboBox->currentText(); } void SeerDebugDialog::setRandomizeStartAddress (bool flag) { randomizeStartAddressCheckBox->setChecked(flag); } bool SeerDebugDialog::randomizeStartAddress () const { return randomizeStartAddressCheckBox->isChecked(); } void SeerDebugDialog::setNonStopMode (bool flag) { nonStopModeCheckBox->setChecked(flag); } bool SeerDebugDialog::nonStopMode () const { return nonStopModeCheckBox->isChecked(); } void SeerDebugDialog::setPreGdbCommands (const QStringList& preGdbCommands) { preCommandsPlainTextEdit->setPlainText(preGdbCommands.join("\n")); } QStringList SeerDebugDialog::preGdbCommands () const { return preCommandsPlainTextEdit->toPlainText().split("\n"); } void SeerDebugDialog::setPostGdbCommands (const QStringList& postGdbCommands) { postCommandsPlainTextEdit->setPlainText(postGdbCommands.join("\n")); } QStringList SeerDebugDialog::postGdbCommands () const { return postCommandsPlainTextEdit->toPlainText().split("\n"); } void SeerDebugDialog::setCoreFilename (const QString& coreFilename) { loadCoreFilenameLineEdit->setText(coreFilename); } QString SeerDebugDialog::coreFilename () const { return loadCoreFilenameLineEdit->text(); } void SeerDebugDialog::setAttachPid (int pid) { if (pid < 1) { attachProgramPidLineEdit->setText(""); }else{ attachProgramPidLineEdit->setText(QString::number(pid)); } } int SeerDebugDialog::attachPid () const { return attachProgramPidLineEdit->text().toInt(); } void SeerDebugDialog::setConnectHostPort (const QString& connectHostPort) { connectProgramHostPortLineEdit->setText(connectHostPort); } QString SeerDebugDialog::connectHostPort () const { return connectProgramHostPortLineEdit->text(); } void SeerDebugDialog::setConnectRemoteTargetType (const QString& type) { connectRemoteTargetTypeCombo->setCurrentText(type); } QString SeerDebugDialog::connectRemoteTargetType () const { return connectRemoteTargetTypeCombo->currentText(); } void SeerDebugDialog::setConnectGdbserverDebug (bool enable) { connectGdbserverDebugCheckBox->setChecked(enable); } bool SeerDebugDialog::connectGdbserverDebug () const { return connectGdbserverDebugCheckBox->isChecked(); } void SeerDebugDialog::setRRTraceDirectory (const QString& rrTraceDirectory) { rrTraceDirectoryLineEdit->setText(rrTraceDirectory); } QString SeerDebugDialog::rrTraceDirectory () const { return rrTraceDirectoryLineEdit->text(); } void SeerDebugDialog::setLaunchMode (const QString& mode) { if (mode == "start") { runModeTabWidget->setCurrentIndex(0); setBreakpointMode(breakpointMode()); }else if (mode == "run") { runModeTabWidget->setCurrentIndex(0); setBreakpointMode(breakpointMode()); }else if (mode == "attach") { runModeTabWidget->setCurrentIndex(1); }else if (mode == "connect") { runModeTabWidget->setCurrentIndex(2); }else if (mode == "rr") { runModeTabWidget->setCurrentIndex(3); }else if (mode == "corefile") { runModeTabWidget->setCurrentIndex(4); }else if (mode == "") { runModeTabWidget->setCurrentIndex(0); setBreakpointMode("inmain"); }else{ qWarning() << "Unknown launch mode of:" << mode; runModeTabWidget->setCurrentIndex(0); setBreakpointMode("inmain"); } } QString SeerDebugDialog::launchMode () const { if (runModeTabWidget->currentIndex() == 0) { if (breakpointMode() == "inmain") { return "start"; }else if (breakpointMode() == "firstinstruction") { return "run"; }else if (breakpointMode() == "infunction") { return "run"; }else if (breakpointMode() == "none") { return "run"; }else{ return "run"; } }else if (runModeTabWidget->currentIndex() == 1) { return "attach"; }else if (runModeTabWidget->currentIndex() == 2) { return "connect"; }else if (runModeTabWidget->currentIndex() == 3) { return "rr"; }else if (runModeTabWidget->currentIndex() == 4) { return "corefile"; } qWarning() << "Unknown launch mode of:" << runModeTabWidget->currentIndex(); return ""; } void SeerDebugDialog::setProjectFilename (const QString& filename) { _projectFilename = filename; if (_projectFilename != "") { loadProject(_projectFilename, false); } } QString SeerDebugDialog::projectFilename () const { return _projectFilename; } void SeerDebugDialog::handleExecutableNameToolButton () { QString name = QFileDialog::getOpenFileName(this, "Select an Executable to debug.", executableName(), "", nullptr, QFileDialog::DontUseNativeDialog); if (name != "") { setExecutableName(name); } } void SeerDebugDialog::handleExecutableSymbolNameToolButton () { QString name = QFileDialog::getOpenFileName(this, "Select a Symbol File for the executable.", executableSymbolName(), "", nullptr, QFileDialog::DontUseNativeDialog); if (name != "") { setExecutableSymbolName(name); } } void SeerDebugDialog::handleExecutableWorkingDirectoryToolButton () { QString name = QFileDialog::getExistingDirectory(this, "Select a Working Directory to run in.", executableWorkingDirectory(), QFileDialog::ShowDirsOnly|QFileDialog::DontUseNativeDialog); if (name != "") { setExecutableWorkingDirectory(name); } } void SeerDebugDialog::handleBreakpointInFunctionLineEdit () { breakpointInFunctionRadioButton->setChecked(true); } void SeerDebugDialog::handleLoadRRTraceDirectoryToolButton () { QString name = QFileDialog::getExistingDirectory(this, "Select a RR trace-directory to load.", rrTraceDirectory(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (name != "") { setRRTraceDirectory(name); } } void SeerDebugDialog::handleLoadBreakpointsFilenameToolButton () { QString name = QFileDialog::getOpenFileName(this, "Select a breakpoints file to load.", breakpointsFilename(), "Breakpoints (*.seer);;All files (*.*)", nullptr, QFileDialog::DontUseNativeDialog); if (name != "") { setBreakpointsFilename(name); } } void SeerDebugDialog::handleLoadCoreFilenameToolButton () { QString name = QFileDialog::getOpenFileName(this, "Select a core file to debug.", coreFilename(), "Core Files (core core.* *.core)", nullptr, QFileDialog::DontUseNativeDialog); if (name != "") { setCoreFilename(name); } } void SeerDebugDialog::handleProgramPidToolButton () { SeerSlashProcDialog dlg(this); // Execute the dialog and get the result. if (dlg.exec()) { setAttachPid(dlg.selectedPid()); if (executableName() == "") { setExecutableName(dlg.selectedFullname()); } } } void SeerDebugDialog::handleLoadProjectToolButton () { // Get the filename to load from. QString fname = QFileDialog::getOpenFileName(this, "Load a project file.", "project.seer", "Projects (*.seer);;All files (*.*)", nullptr, QFileDialog::DontUseNativeDialog); if (fname == "") { return; } loadProject(fname, true); } void SeerDebugDialog::loadProject (const QString& filename, bool notify) { // Look for the mainwindow to place possible QMessageBox on. QWidget* p = this; if (isHidden() == true) { foreach (QWidget* w, qApp->topLevelWidgets()) { if (QMainWindow* mainWin = qobject_cast(w)) { p = mainWin; break; } } } // Open the project file. QFile loadFile(filename);; bool f = loadFile.open(QIODevice::ReadOnly); if (f == false) { QMessageBox::critical(p, "Error", QString("Can't open the Seer project file '%1'.").arg(filename)); return; } // Populate the JSON document from the project file. QJsonDocument jsonDoc = QJsonDocument::fromJson(loadFile.readAll()); f = loadJsonDoc(jsonDoc, filename); if (f == false) { return; } if (notify) { QMessageBox::information(p, "Success", QString("Loaded the Seer project file '%1'.").arg(filename)); } } QJsonDocument SeerDebugDialog::makeJsonDoc() const { // Build the JSON document. QJsonDocument jsonDoc; QJsonObject rootJson; QJsonObject seerProjectJson; QJsonArray preConnectCommands; QJsonArray postConnectCommands; // Save pre/post gdb commands. QStringList preCommands = preGdbCommands(); QStringList postCommands = postGdbCommands(); for (const auto& i : preCommands) { preConnectCommands.push_back(QJsonValue(i)); } for (const auto& i : postCommands) { postConnectCommands.push_back(QJsonValue(i)); } seerProjectJson["executable"] = QJsonValue(executableNameLineEdit->text()); seerProjectJson["symbolfile"] = QJsonValue(executableSymbolNameLineEdit->text()); seerProjectJson["workingdirectory"] = QJsonValue(executableWorkingDirectoryLineEdit->text()); seerProjectJson["pregdbcommands"] = preConnectCommands; seerProjectJson["postgdbcommands"] = postConnectCommands; // Save RUN project. if (launchMode() == "run") { QJsonObject modeJson; modeJson["arguments"] = runProgramArgumentsLineEdit->text(); modeJson["breakpointsfile"] = loadBreakpointsFilenameLineEdit->text(); modeJson["nobreak"] = noBreakpointRadioButton->isChecked(); modeJson["breakinmain"] = breakpointInMainRadioButton->isChecked(); modeJson["breakinfunction"] = breakpointInFunctionRadioButton->isChecked(); modeJson["breakinfunctionname"] = breakpointInFunctionLineEdit->text(); modeJson["breakatfirstinstruction"] = breakpointAtFirstInstructionRadioButton->isChecked(); modeJson["showassemblytabmode"] = showAssemblyTabComboBox->currentText(); modeJson["nonstopmode"] = nonStopModeCheckBox->isChecked(); modeJson["randomizestartaddress"] = randomizeStartAddressCheckBox->isChecked(); seerProjectJson["runmode"] = modeJson; } // Save START project. if (launchMode() == "start") { QJsonObject modeJson; modeJson["arguments"] = runProgramArgumentsLineEdit->text(); modeJson["breakpointsfile"] = loadBreakpointsFilenameLineEdit->text(); modeJson["nobreak"] = noBreakpointRadioButton->isChecked(); modeJson["breakinmain"] = breakpointInMainRadioButton->isChecked(); modeJson["breakinfunction"] = breakpointInFunctionRadioButton->isChecked(); modeJson["breakinfunctionname"] = breakpointInFunctionLineEdit->text(); modeJson["breakatfirstinstruction"] = breakpointAtFirstInstructionRadioButton->isChecked(); modeJson["showassemblytabmode"] = showAssemblyTabComboBox->currentText(); modeJson["nonstopmode"] = nonStopModeCheckBox->isChecked(); modeJson["randomizestartaddress"] = randomizeStartAddressCheckBox->isChecked(); seerProjectJson["startmode"] = modeJson; } // Save ATTACH project. if (launchMode() == "attach") { QJsonObject modeJson; modeJson["pid"] = attachProgramPidLineEdit->text(); seerProjectJson["attachmode"] = modeJson; } // Save CONNECT project. if (launchMode() == "connect") { QJsonObject modeJson; modeJson["gdbserver"] = connectProgramHostPortLineEdit->text(); modeJson["targettype"] = connectRemoteTargetTypeCombo->currentText(); modeJson["gdbserverdebug"] = connectGdbserverDebugCheckBox->isChecked(); seerProjectJson["connectmode"] = modeJson; } // Save RR project. if (launchMode() == "rr") { QJsonObject modeJson; modeJson["tracedirectory"] = rrTraceDirectoryLineEdit->text(); modeJson["breakpointsfile"] = rrLoadBreakpointsFilenameLineEdit->text(); seerProjectJson["rrmode"] = modeJson; } // Save COREFILE project. if (launchMode() == "corefile") { QJsonObject modeJson; modeJson["corefile"] = loadCoreFilenameLineEdit->text(); seerProjectJson["corefilemode"] = modeJson; } rootJson["seerproject"] = seerProjectJson; jsonDoc.setObject(rootJson); return jsonDoc; } bool SeerDebugDialog::loadJsonDoc (const QJsonDocument& jsonDoc, const QString& filename) { // Look for the mainwindow to place possible QMessageBox on. QWidget* p = this; if (isHidden() == true) { foreach (QWidget* w, qApp->topLevelWidgets()) { if (QMainWindow* mainWin = qobject_cast(w)) { p = mainWin; break; } } } QJsonObject rootJson; QJsonObject seerProjectJson; QJsonObject runModeJson; QJsonObject startModeJson; QJsonObject attachModeJson; QJsonObject connectModeJson; QJsonObject rrModeJson; QJsonObject corefileModeJson; QJsonArray preConnectCommands; QJsonArray postConnectCommands; if (jsonDoc.isObject() == false) { QMessageBox::critical(p, "Error", QString("'%1' is not a Seer project file (bad Json format).").arg(filename)); return false; } rootJson = jsonDoc.object(); seerProjectJson = rootJson.value("seerproject").toObject(); runModeJson = seerProjectJson.value("runmode").toObject(); startModeJson = seerProjectJson.value("startmode").toObject(); attachModeJson = seerProjectJson.value("attachmode").toObject(); connectModeJson = seerProjectJson.value("connectmode").toObject(); rrModeJson = seerProjectJson.value("rrmode").toObject(); corefileModeJson = seerProjectJson.value("corefilemode").toObject(); preConnectCommands = seerProjectJson.value("pregdbcommands").toArray(); postConnectCommands = seerProjectJson.value("postgdbcommands").toArray(); if (seerProjectJson.isEmpty() == true) { QMessageBox::critical(p, "Error", QString("'%1' is not a Seer project file (missing 'seerproject' section).").arg(filename)); return false; } // Load executable/symbol/working directory. executableNameLineEdit->setText(seerProjectJson["executable"].toString()); executableSymbolNameLineEdit->setText(seerProjectJson["symbolfile"].toString()); executableWorkingDirectoryLineEdit->setText(seerProjectJson["workingdirectory"].toString()); // Load pre/post gdb commands. Good for all modes. QStringList preCommands; QStringList postCommands; for (const auto& i : preConnectCommands) { preCommands.push_back(i.toString()); } for (const auto& i : postConnectCommands) { postCommands.push_back(i.toString()); } setPreGdbCommands(preCommands); setPostGdbCommands(postCommands); // Load RUN/START project. if (runModeJson.isEmpty() == false || startModeJson.isEmpty() == false) { if (runModeJson.isEmpty() == false) { runProgramArgumentsLineEdit->setText(runModeJson["arguments"].toString()); loadBreakpointsFilenameLineEdit->setText(runModeJson["breakpointsfile"].toString()); rrLoadBreakpointsFilenameLineEdit->setText(runModeJson["breakpointsfile"].toString()); if (runModeJson["nobreak"].toBool()) { noBreakpointRadioButton->setChecked(true); } if (runModeJson["breakinmain"].toBool()) { breakpointInMainRadioButton->setChecked(true); } if (runModeJson["breakinfunction"].toBool()) { breakpointInFunctionRadioButton->setChecked(true); } if (runModeJson["breakatfirstinstruction"].toBool()) { breakpointAtFirstInstructionRadioButton->setChecked(true); } breakpointInFunctionLineEdit->setText(runModeJson["breakinfunctionname"].toString()); showAssemblyTabComboBox->setCurrentText(runModeJson["showassemblytabmode"].toString()); nonStopModeCheckBox->setChecked(runModeJson["nonstopmode"].toBool()); randomizeStartAddressCheckBox->setChecked(runModeJson["randomizestartaddress"].toBool()); setLaunchMode("run"); }else if (startModeJson.isEmpty() == false) { runProgramArgumentsLineEdit->setText(startModeJson["arguments"].toString()); loadBreakpointsFilenameLineEdit->setText(startModeJson["breakpointsfile"].toString()); rrLoadBreakpointsFilenameLineEdit->setText(startModeJson["breakpointsfile"].toString()); if (startModeJson["nobreak"].toBool()) { noBreakpointRadioButton->setChecked(true); } if (startModeJson["breakinmain"].toBool()) { breakpointInMainRadioButton->setChecked(true); } if (startModeJson["breakinfunction"].toBool()) { breakpointInFunctionRadioButton->setChecked(true); } if (startModeJson["breakatfirstinstruction"].toBool()) { breakpointAtFirstInstructionRadioButton->setChecked(true); } breakpointInFunctionLineEdit->setText(startModeJson["breakinfunctionname"].toString()); showAssemblyTabComboBox->setCurrentText(startModeJson["showassemblytabmode"].toString()); nonStopModeCheckBox->setChecked(startModeJson["nonstopmode"].toBool()); randomizeStartAddressCheckBox->setChecked(startModeJson["randomizestartaddress"].toBool()); setLaunchMode("start"); }else{ setLaunchMode(""); } } // Load ATTACH project. if (attachModeJson.isEmpty() == false) { attachProgramPidLineEdit->setText(attachModeJson["pid"].toString()); setLaunchMode("attach"); } // Load CONNECT project. if (connectModeJson.isEmpty() == false) { connectProgramHostPortLineEdit->setText(connectModeJson["gdbserver"].toString()); if (connectModeJson.contains("targettype")) { connectRemoteTargetTypeCombo->setCurrentText(connectModeJson["targettype"].toString()); } if (connectModeJson.contains("gdbserverdebug")) { connectGdbserverDebugCheckBox->setChecked(connectModeJson["gdbserverdebug"].toBool()); } setLaunchMode("connect"); } // Load RR project. if (rrModeJson.isEmpty() == false) { rrTraceDirectoryLineEdit->setText(rrModeJson["tracedirectory"].toString()); loadBreakpointsFilenameLineEdit->setText(rrModeJson["breakpointsfile"].toString()); rrLoadBreakpointsFilenameLineEdit->setText(rrModeJson["breakpointsfile"].toString()); setLaunchMode("rr"); } // Load COREFILE project. if (corefileModeJson.isEmpty() == false) { loadCoreFilenameLineEdit->setText(corefileModeJson["corefile"].toString()); setLaunchMode("corefile"); } return true; } void SeerDebugDialog::handleSaveProjectToolButton () { // Get the filename to save to. QString fname = QFileDialog::getSaveFileName(this, "Save to a project file.", "project.seer", "Projects (*.seer);;All files (*.*)", nullptr, QFileDialog::DontUseNativeDialog); if (fname == "") { return; } // Make the json document for the debug dialog settings. QJsonDocument jsonDoc = makeJsonDoc(); // Write the JSON document to the project file. QFile saveFile(fname); if (saveFile.open(QIODevice::WriteOnly) == false) { QMessageBox::critical(this, "Error", QString("Can't create the Seer project file '%1'.").arg(fname)); return; } saveFile.write(jsonDoc.toJson()); QMessageBox::information(this, "Success", QString("Created the Seer project file '%1'.").arg(fname)); } void SeerDebugDialog::handleRunModeChanged (int id) { // // Disable all important widgets. // executableNameLineEdit->setEnabled(false); executableNameToolButton->setEnabled(false); executableSymbolNameLineEdit->setEnabled(false); executableSymbolNameToolButton->setEnabled(false); executableWorkingDirectoryLineEdit->setEnabled(false); executableWorkingDirectoryToolButton->setEnabled(false); preCommandsPlainTextEdit->setPlaceholderText(""); postCommandsPlainTextEdit->setPlaceholderText(""); // // Enable the newly selected one. // // ID == 0 RUN/START if (id == 0) { executableNameLineEdit->setEnabled(true); executableNameToolButton->setEnabled(true); executableSymbolNameLineEdit->setEnabled(true); executableSymbolNameToolButton->setEnabled(true); executableWorkingDirectoryLineEdit->setEnabled(true); executableWorkingDirectoryToolButton->setEnabled(true); preCommandsPlainTextEdit->setPlaceholderText("gdb commands before \"run\""); postCommandsPlainTextEdit->setPlaceholderText("gdb commands after \"run\""); } // ID == 1 ATTACH if (id == 1) { executableNameLineEdit->setEnabled(true); executableNameToolButton->setEnabled(true); executableSymbolNameLineEdit->setEnabled(true); executableSymbolNameToolButton->setEnabled(true); executableWorkingDirectoryLineEdit->setEnabled(true); executableWorkingDirectoryToolButton->setEnabled(true); preCommandsPlainTextEdit->setPlaceholderText("gdb commands before \"attach\""); postCommandsPlainTextEdit->setPlaceholderText("gdb commands after \"attach\""); } // ID == 2 CONNECT if (id == 2) { executableNameLineEdit->setEnabled(true); executableNameToolButton->setEnabled(true); executableSymbolNameLineEdit->setEnabled(true); executableSymbolNameToolButton->setEnabled(true); executableWorkingDirectoryLineEdit->setEnabled(true); executableWorkingDirectoryToolButton->setEnabled(true); preCommandsPlainTextEdit->setPlaceholderText("gdb commands before \"connect\""); postCommandsPlainTextEdit->setPlaceholderText("gdb commands after \"connect\""); } // ID == 3 RR if (id == 3) { executableSymbolNameLineEdit->setEnabled(true); executableSymbolNameToolButton->setEnabled(true); preCommandsPlainTextEdit->setPlaceholderText("gdb commands before \"RR trace-directory load\""); postCommandsPlainTextEdit->setPlaceholderText("gdb commands after \"RR trace-directory load\""); // Set default if we can. Otherwise, leave it blank. // if (rrTraceDirectoryLineEdit->text() == "") { QStringList searchPaths = { "$_RR_TRACE_DIR/latest-trace", "$XDG_DATA_HOME/rr/latest-trace", "$HOME/.local/share/rr/latest-trace" }; QString defaultPath = ""; bool f; for (const auto& path : searchPaths) { defaultPath = Seer::expandEnv(path, &f); if (f == false) { continue; } if (QFile::exists(defaultPath)) { setRRTraceDirectory(defaultPath); break; } } } } // ID == 4 COREFILE if (id == 4) { executableNameLineEdit->setEnabled(true); executableNameToolButton->setEnabled(true); executableSymbolNameLineEdit->setEnabled(true); executableSymbolNameToolButton->setEnabled(true); preCommandsPlainTextEdit->setPlaceholderText("gdb commands before loading \"corefile\""); postCommandsPlainTextEdit->setPlaceholderText("gdb commands after loading \"corefile\""); } } void SeerDebugDialog::handleLaunchButtonClicked () { QJsonDocument document = makeJsonDoc(); writeDefaultProjectSettings(document); } void SeerDebugDialog::handleResetButtonClicked (QAbstractButton* button) { // Was the Reset button clicked? QAbstractButton* resetButton = buttonBox->button(QDialogButtonBox::Reset); if (button != resetButton) { return; } // Reset all parameters. reset(); } void SeerDebugDialog::handleHelpModeToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/DebugModes.md"); help->show(); help->raise(); } void SeerDebugDialog::handleHelpRunToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/RunDebugMode.md"); help->show(); help->raise(); } void SeerDebugDialog::handleHelpAttachToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/AttachDebugMode.md"); help->show(); help->raise(); } void SeerDebugDialog::handleHelpConnectToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/ConnectDebugMode.md"); help->show(); help->raise(); } void SeerDebugDialog::handleHelpRRToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/RRDebugMode.md"); help->show(); help->raise(); } void SeerDebugDialog::handleHelpCorefileToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/CorefileDebugMode.md"); help->show(); help->raise(); } void SeerDebugDialog::writeSettings() { QSettings settings; settings.beginGroup("debugdialog"); { settings.setValue("size", size()); } settings.endGroup(); } void SeerDebugDialog::readSettings() { QSettings settings; settings.beginGroup("debugdialog"); { resize(settings.value("size", QSize(800, 600)).toSize()); } settings.endGroup(); } void SeerDebugDialog::writeDefaultProjectSettings (const QJsonDocument& document) { QSettings settings; settings.beginGroup("debugdialog"); { settings.setValue("defaultproject", document.toJson(QJsonDocument::Compact)); } settings.endGroup(); } void SeerDebugDialog::loadDefaultProjectSettings () { QSettings settings; settings.beginGroup("debugdialog"); { QVariant variantData = settings.value("defaultproject"); if (variantData.isValid()) { QJsonDocument jsonDoc = QJsonDocument::fromJson(variantData.toByteArray()); loadJsonDoc(jsonDoc, "defaultproject"); } } settings.endGroup(); } void SeerDebugDialog::resizeEvent (QResizeEvent* event) { // Write window settings. writeSettings(); QWidget::resizeEvent(event); } epasveer-seer-97076f1/src/SeerDebugDialog.h000066400000000000000000000175571526321767600205300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include "ui_SeerDebugDialog.h" class SeerDebugDialog : public QDialog, protected Ui::SeerDebugDialogForm { Q_OBJECT public: explicit SeerDebugDialog (QWidget* parent = 0); ~SeerDebugDialog (); // Reset all void reset (); // For any run mode. void setExecutableName (const QString& executableName); QString executableName () const; void setExecutableSymbolName (const QString& executableSymbolName); QString executableSymbolName () const; void setExecutableWorkingDirectory (const QString& executableWorkingDirectory); QString executableWorkingDirectory () const; // Run or start executable. "run" or "start". void setExecutableArguments (const QString& executableArguments); QString executableArguments () const; void setBreakpointsFilename (const QString& breakpointsFilename); QString breakpointsFilename () const; void setBreakpointMode (const QString& mode); QString breakpointMode () const; void setBreakpointFunctionName (const QString& nameoraddress); QString breakpointFunctionName () const; void setBreakpointSourceName (const QString& sourceFilenameAndLineno); QString breakpointSourceName () const; void setBreakpointFirstInstruction (bool flag); bool breakpointFirstInstruction () const; void setShowAssemblyTabMode (const QString& mode); QString showAssemblyTabMode () const; void setRandomizeStartAddress (bool flag); bool randomizeStartAddress () const; void setNonStopMode (bool flag); bool nonStopMode () const; void setPreGdbCommands (const QStringList& preGdbCommands); QStringList preGdbCommands () const; void setPostGdbCommands (const QStringList& postGdbCommands); QStringList postGdbCommands () const; // Attach to a running process. "attach". void setAttachPid (int pid); int attachPid () const; // Connectect to a GDB server. "connect". void setConnectHostPort (const QString& connectHostPort); QString connectHostPort () const; void setConnectRemoteTargetType (const QString& type); QString connectRemoteTargetType () const; void setConnectGdbserverDebug (bool enable); bool connectGdbserverDebug () const; // Connectect to a RR server. "rr". void setRRTraceDirectory (const QString& rrTraceDirectory); QString rrTraceDirectory () const; QString rrBreakpointsFilename () const; // Load a core file. "corefile". void setCoreFilename (const QString& coreFilename); QString coreFilename () const; // Get the launch mode. void setLaunchMode (const QString& mode); QString launchMode () const; // Get the project filename. void setProjectFilename (const QString& filename); QString projectFilename () const; void loadProject (const QString& filename, bool notify); void loadDefaultProjectSettings (); // Make a json document of the current debug dialog settings. QJsonDocument makeJsonDoc () const; bool loadJsonDoc (const QJsonDocument& jsonDoc, const QString& filename); protected slots: void handleExecutableNameToolButton (); void handleExecutableSymbolNameToolButton (); void handleExecutableWorkingDirectoryToolButton (); void handleLoadBreakpointsFilenameToolButton (); void handleBreakpointInFunctionLineEdit (); void handleLoadRRTraceDirectoryToolButton (); void handleLoadCoreFilenameToolButton (); void handleProgramPidToolButton (); void handleLoadProjectToolButton (); void handleSaveProjectToolButton (); void handleRunModeChanged (int id); void handleLaunchButtonClicked (); void handleResetButtonClicked (QAbstractButton* button); private slots: void handleHelpModeToolButtonClicked (); void handleHelpRunToolButtonClicked (); void handleHelpAttachToolButtonClicked (); void handleHelpConnectToolButtonClicked (); void handleHelpRRToolButtonClicked (); void handleHelpCorefileToolButtonClicked (); protected: void writeSettings (); void readSettings (); void writeDefaultProjectSettings (const QJsonDocument& document); void resizeEvent (QResizeEvent* event); private: QString _projectFilename; }; epasveer-seer-97076f1/src/SeerDebugDialog.ui000066400000000000000000001252241526321767600207050ustar00rootroot00000000000000 SeerDebugDialogForm 0 0 758 1086 Select Executable to Debug Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset Working Directory Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop The working directory path to tell GDB. Default current directory. The working directory path to tell GDB. Default current directory. true Open a dialog to select a path. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Executable Name Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop false 0 0 The path and name of an executable to debug. The path and name of an executable to debug. true 0 0 Open a dialog to select an executable. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Symbol File Name Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop false 0 0 Optional path and name of a symbol file for the executable. Optional path and name of a symbol file for the executable. true 0 0 Open a dialog to select the symbol file for the executable. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg 0 100 Launch Method 0 10 0 0 0 Run Arguments 100 0 The arguments to pass to the program. optional program arguments true Breakpoints file 100 0 A file containing previously saved breakpoints. breakpoints.seer true Open a dialog to select a breakpoints file. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg No initial breakpoint. No breakpoint true breakpointButtonGroup Set a breakpoint at a line number in a source file. Break at breakpointButtonGroup Break at first instruction of program. Break at breakpointButtonGroup Set a breakpoint in "main". Break in breakpointButtonGroup true First CPU instruction The breakpoint using filename and lineno. sourcefile.cpp:line true The breakpoint function or address. _function or 0xaddress true Set a breakpoint in a function or at an address. Break in breakpointButtonGroup "main" Run and debug an executable. Qt::Horizontal 40 20 Help for Run launch method. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Allow other threads to continue if any thread reaches a breakpoint. Non-stop mode Randomize the process start address. Randomize start address Qt::Horizontal 258 20 0 0 Show Assembly tab on startup 0 0 never always auto Qt::Horizontal QSizePolicy::Expanding 385 23 Attach Attach and debug a running process on the local machine. Qt::Horizontal 40 20 Help for Attach launch method. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Process PID 100 0 The process pid. 9999999 pid true Open a dialog to select a pid on the local system. ... Qt::Vertical 20 192 Connect Connect to a gdbserver (or similar) session. Qt::Horizontal 248 20 Help for Connect launch method. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Gdbserver 100 0 How to access the gdbserver. host:port or /dev/serialport true Remote target type 0 0 Select the type of remote target connection. remote extended-remote Qt::Horizontal QSizePolicy::Expanding 308 23 Enable debug communication between gdb and the gdbserver. Gdbserver debug Qt::Horizontal QSizePolicy::Expanding 408 23 Qt::Vertical 20 151 RR Load a RR trace session. Qt::Horizontal 248 20 Help for RR launch method. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg RR trace directory 100 0 How to access the RR trace session. /path/to/rr/trace/directory true Open a dialog to load a RR trace-directory. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Breakpoints file 100 0 A file containing previously saved breakpoints. breakpoints.seer true Open a dialog to select a breakpoints file. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Qt::Vertical 20 113 Corefile Analyze a corefile. Qt::Horizontal 40 20 Help for Corefile launch method. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Core file 100 0 The path and name of a core file. The path and name of the core file. true Open a dialog to select a core file. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Qt::Vertical 20 478 0 40 0 40 executableNameGroupBox buttonBox executableSymbolNameGroupBox executableWorkingDirectoryGroupBox launchMethodGroupBox executableNameLineEdit executableNameToolButton executableSymbolNameLineEdit executableSymbolNameToolButton executableWorkingDirectoryLineEdit executableWorkingDirectoryToolButton runModeTabWidget helpRunToolButton runProgramArgumentsLineEdit loadBreakpointsFilenameLineEdit loadBreakpointsFilenameToolButton breakpointInMainRadioButton breakpointInFunctionRadioButton breakpointInFunctionLineEdit breakpointAtSourceRadioButton breakpointAtSourceLineEdit breakpointAtFirstInstructionRadioButton noBreakpointRadioButton nonStopModeCheckBox randomizeStartAddressCheckBox showAssemblyTabComboBox preCommandsPlainTextEdit postCommandsPlainTextEdit helpAttachToolButton attachProgramPidLineEdit attachProgramPidToolButton helpRRToolButton rrTraceDirectoryLineEdit rrLoadTraceDirectoryToolButton rrLoadBreakpointsFilenameLineEdit rrLoadBreakpointsFilenameToolButton helpCorefileToolButton loadCoreFilenameLineEdit loadCoreFilenameToolButton connectProgramHostPortLineEdit connectRemoteTargetTypeCombo connectGdbserverDebugCheckBox helpConnectToolButton buttonBox accepted() SeerDebugDialogForm accept() 257 1076 157 274 buttonBox rejected() SeerDebugDialogForm reject() 325 1076 286 274 epasveer-seer-97076f1/src/SeerDirectoryFilterProxyModel.h000066400000000000000000000012741526321767600235040ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerDirectoryFilterProxyModel : public QSortFilterProxyModel { bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { QFileSystemModel* fileModel = qobject_cast(sourceModel()); QFileInfo file(fileModel->filePath(sourceModel()->index(sourceRow, 0, sourceParent))); if (file.isDir() == true || file.isHidden()) { return true; }else{ return false; } } }; epasveer-seer-97076f1/src/SeerEditorConfigPage.cpp000066400000000000000000000421241526321767600220520ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorConfigPage.h" #include "QColorButton.h" #include #include #include #include #include #include SeerEditorConfigPage::SeerEditorConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // // Setup the widgets // // Connect things. QObject::connect(fontMonoRadioButton, &QRadioButton::clicked, this, &SeerEditorConfigPage::handleFontMonoChanged); QObject::connect(fontSizeComboBox, &QComboBox::currentTextChanged, this, &SeerEditorConfigPage::handleFontSizeChanged); QObject::connect(fontNameComboBox, &QFontComboBox::currentFontChanged, this, &SeerEditorConfigPage::handleFontChanged); QObject::connect(fontDialogButton, &QToolButton::clicked, this, &SeerEditorConfigPage::handleFontDialog); QObject::connect(highlighterEnabledCheckBox, &QToolButton::clicked, this, &SeerEditorConfigPage::handleHighlighterEnabledChanged); QObject::connect(minimapEnabledCheckBox, &QToolButton::clicked, this, &SeerEditorConfigPage::handleMinimapEnabledChanged); QObject::connect(cppSuffixesLineEdit, &QHistoryLineEdit::lostFocus, this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(rustSuffixesLineEdit, &QHistoryLineEdit::lostFocus, this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(odinSuffixesLineEdit, &QHistoryLineEdit::lostFocus, this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(adaSuffixesLineEdit, &QHistoryLineEdit::lostFocus, this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(fortranSuffixesLineEdit, &QHistoryLineEdit::lostFocus, this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(languageTabWidget, &QTabWidget::currentChanged, this, &SeerEditorConfigPage::handleLanguageTabChanged); QObject::connect(themeApplyToolButton, &QToolButton::clicked, this, &SeerEditorConfigPage::handleApplyTheme); // Set the defaults. reset(); // Fill in the available theme names. themeComboBox->addItems(SeerHighlighterSettings::themeNames()); // Set example text. handleLanguageTabChanged(0); } SeerEditorConfigPage::~SeerEditorConfigPage() { } void SeerEditorConfigPage::setEditorFont (const QFont& font) { handleFontChanged(font); } const QFont& SeerEditorConfigPage::editorFont () const { return _font; } void SeerEditorConfigPage::setEditorTabSize (int spaces) { tabSpinBox->setValue(spaces); } int SeerEditorConfigPage::editorTabSize () const { return tabSpinBox->value(); } void SeerEditorConfigPage::setHighlighterSettings (const SeerHighlighterSettings& settings) { _highlighterSettings = settings; // Clear the table contents. highlighterTableWidget->setRowCount(0); // Get a list of keys from the highlighter. QStringList keys = _highlighterSettings.keys(); // Loop through each key and get its info. // Construct a table entry. for (int r=0; rinsertRow(r); // Insert the font weight. QComboBox* fontWeightBox = new QComboBox; fontWeightBox->addItem("Normal"); fontWeightBox->addItem("Bold"); if (format.fontWeight() == QFont::Normal) { fontWeightBox->setCurrentText("Normal"); }else if (format.fontWeight() == QFont::Bold) { fontWeightBox->setCurrentText("Bold"); }else{ fontWeightBox->setCurrentText("Normal"); } highlighterTableWidget->setCellWidget(r, 0, fontWeightBox); // Insert the font italic. QComboBox* fontItalicBox = new QComboBox; fontItalicBox->addItem("Normal"); fontItalicBox->addItem("Italic"); if (format.fontItalic() == false) { fontItalicBox->setCurrentText("Normal"); }else if (format.fontItalic() == true) { fontItalicBox->setCurrentText("Italic"); }else{ fontItalicBox->setCurrentText("Normal"); } highlighterTableWidget->setCellWidget(r, 1, fontItalicBox); // Insert the font color. QColorButton* foregroundColorButton = new QColorButton; foregroundColorButton->setColor(format.foreground().color()); QColorButton* backgroundColorButton = new QColorButton; backgroundColorButton->setColor(format.background().color()); highlighterTableWidget->setCellWidget(r, 2, foregroundColorButton); highlighterTableWidget->setCellWidget(r, 3, backgroundColorButton); // Connect things to watch for changes. QObject::connect(fontWeightBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(fontItalicBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(foregroundColorButton, &QColorButton::colorChanged, this, &SeerEditorConfigPage::handleHighlighterChanged); QObject::connect(backgroundColorButton, &QColorButton::colorChanged, this, &SeerEditorConfigPage::handleHighlighterChanged); } highlighterTableWidget->setVerticalHeaderLabels(keys); highlighterTableWidget->resizeColumnToContents(0); // Weight highlighterTableWidget->resizeColumnToContents(1); // Italic highlighterTableWidget->resizeColumnToContents(2); // Foreground color highlighterTableWidget->resizeColumnToContents(3); // Background color cppSuffixesLineEdit->setText(_highlighterSettings.cppSourceSuffixes()); cppSuffixesLineEdit->setCursorPosition(0); rustSuffixesLineEdit->setText(_highlighterSettings.rustSourceSuffixes()); rustSuffixesLineEdit->setCursorPosition(0); odinSuffixesLineEdit->setText(_highlighterSettings.odinSourceSuffixes()); odinSuffixesLineEdit->setCursorPosition(0); adaSuffixesLineEdit->setText(_highlighterSettings.adaSourceSuffixes()); adaSuffixesLineEdit->setCursorPosition(0); fortranSuffixesLineEdit->setText(_highlighterSettings.fortranSourceSuffixes()); fortranSuffixesLineEdit->setCursorPosition(0); // Update our sample editor. editorWidget->sourceArea()->setHighlighterSettings(highlighterSettings()); editorWidget->sourceArea()->setCurrentLine(0); } const SeerHighlighterSettings& SeerEditorConfigPage::highlighterSettings() const { return _highlighterSettings; } void SeerEditorConfigPage::setHighlighterEnabled (bool flag) { highlighterEnabledCheckBox->setChecked(flag); editorWidget->sourceArea()->setHighlighterEnabled(flag); } bool SeerEditorConfigPage::highlighterEnabled () const { return editorWidget->sourceArea()->highlighterEnabled(); } void SeerEditorConfigPage::setMinimapEnabled (bool flag) { minimapEnabledCheckBox->setChecked(flag); editorWidget->sourceArea()->enableMiniMapArea(flag); } bool SeerEditorConfigPage::minimapEnabled () const { return editorWidget->sourceArea()->miniMapAreaEnabled(); } void SeerEditorConfigPage::setExternalEditorCommand (const QString& externalEditorCommand) { externalEditorCommandLineEdit->setText(externalEditorCommand); } QString SeerEditorConfigPage::externalEditorCommand () const { return externalEditorCommandLineEdit->text(); } void SeerEditorConfigPage::setAutoSourceReload (bool flag) { autoReloadSourceFileCheckBox->setChecked(flag); } bool SeerEditorConfigPage::autoSourceReload () const { return autoReloadSourceFileCheckBox->isChecked(); } void SeerEditorConfigPage::reset () { setEditorFont(QFont("monospace", 10)); setEditorTabSize(4); setHighlighterSettings(SeerHighlighterSettings::populate("")); setHighlighterEnabled(true); setMinimapEnabled(false); setExternalEditorCommand(""); setAutoSourceReload(false); } void SeerEditorConfigPage::handleFontMonoChanged () { if (fontMonoRadioButton->isChecked()) { fontNameComboBox->setFontFilters(QFontComboBox::MonospacedFonts); }else{ fontNameComboBox->setFontFilters(QFontComboBox::AllFonts); } } void SeerEditorConfigPage::handleFontSizeChanged (const QString& text) { // Convert the text size to a number. int size = text.toInt(); // Guard against a bad size. if (size <= 0) { return; } // Set its size. _font.setPointSize(size); // Display our example text with the new font. editorWidget->sourceArea()->setFont(_font); } void SeerEditorConfigPage::handleFontChanged (const QFont& font) { // Clear the font size list. QStringList sizes; fontSizeComboBox->clear(); // Populate the font size list from the given font. foreach (int points, QFontDatabase::smoothSizes(font.family(), font.styleName())) { sizes.append(QString::number(points)); } fontSizeComboBox->addItems(sizes); // Set the current font size in the list. fontSizeComboBox->setCurrentText(QString::number(font.pointSize())); // Set the current font family in the list. fontNameComboBox->setCurrentFont(font); // Display our example text with the new font. editorWidget->sourceArea()->setFont(font); // Save the new font. _font = font; } void SeerEditorConfigPage::handleFontDialog () { bool ok; QFont font; if (fontMonoRadioButton->isChecked()) { font = QFontDialog::getFont(&ok, _font, this, "Select a font for the editors", QFontDialog::MonospacedFonts); }else{ font = QFontDialog::getFont(&ok, _font, this, "Select a font for the editors"); } if (ok) { handleFontChanged(font); } } void SeerEditorConfigPage::handleHighlighterChanged () { SeerHighlighterSettings languageSettings; for (int r=0; rrowCount(); r++) { // Get the key (label) for this row. QString key = highlighterTableWidget->verticalHeaderItem(r)->text(); // Get widgets for this row. QComboBox* fontWeightBox = dynamic_cast(highlighterTableWidget->cellWidget(r,0)); QComboBox* fontItalicBox = dynamic_cast(highlighterTableWidget->cellWidget(r,1)); QColorButton* foregroundColorButton = dynamic_cast(highlighterTableWidget->cellWidget(r,2)); QColorButton* backgroundColorButton = dynamic_cast(highlighterTableWidget->cellWidget(r,3)); // Create an empty format. QTextCharFormat format; // Set the font weight. if (fontWeightBox->currentText() == "Normal") { format.setFontWeight(QFont::Normal); }else if (fontWeightBox->currentText() == "Bold") { format.setFontWeight(QFont::Bold); }else{ format.setFontWeight(QFont::Normal); } // Set the font italic. if (fontItalicBox->currentText() == "Normal") { format.setFontItalic(false); }else if (fontItalicBox->currentText() == "Italic") { format.setFontItalic(true); }else{ format.setFontItalic(false); } // Set the font color. format.setForeground(foregroundColorButton->color()); format.setBackground(backgroundColorButton->color()); // Add the format to our settings. languageSettings.add(key, format); } // Get list of source suffixes. languageSettings.setCppSourceSuffixes(cppSuffixesLineEdit->text()); languageSettings.setRustSourceSuffixes(rustSuffixesLineEdit->text()); languageSettings.setOdinSourceSuffixes(odinSuffixesLineEdit->text()); languageSettings.setAdaSourceSuffixes(adaSuffixesLineEdit->text()); languageSettings.setFortranSourceSuffixes(fortranSuffixesLineEdit->text()); // Update our view. setHighlighterSettings(languageSettings); } void SeerEditorConfigPage::handleHighlighterEnabledChanged () { setHighlighterEnabled(highlighterEnabledCheckBox->isChecked()); } void SeerEditorConfigPage::handleMinimapEnabledChanged () { setMinimapEnabled(minimapEnabledCheckBox->isChecked()); } void SeerEditorConfigPage::handleApplyTheme () { setHighlighterSettings(SeerHighlighterSettings::populate(themeComboBox->currentText())); } void SeerEditorConfigPage::handleLanguageTabChanged (int index) { if (index == 0) { // C/C++ editorWidget->sourceArea()->openText("/*\n" " * Seer, Copyright 2021 (c)\n" " * Ernie Pasveer (epasveer@att.net)\n" " * C/C++ example\n" " */\n" "\n" "// This is the main function.\n" "int main(int argc, char* argv[]) {\n" "\n" " std::cout << \"Hello, Seer!\"; // Greetings\n" "\n" " return 0;\n" "}", "sample.cpp"); } else if (index == 1) { // Rust editorWidget->sourceArea()->openText("/*\n" " * Seer, Copyright 2021 (c)\n" " * Ernie Pasveer (epasveer@att.net)\n" " * Rust example\n" " */\n" "\n" "// This is the main function.\n" "fn main() {\n" " // Print text to the console.\n" " println!(\"Hello World!\");\n" "}", "sample.rs"); } else if (index == 2) { // Odin editorWidget->sourceArea()->openText("/*\n" " * Seer, Copyright 2021 (c)\n" " * Ernie Pasveer (epasveer@att.net)\n" " * Odin example\n" " */\n" "package main\n" "\n" "import \"core:fmt\"\n" "\n" "// This is the main function.\n" "main :: proc() {\n" " fmt.println(\"Hello, World!\")\n" "}", "sample.odin"); } else if (index == 3) { // Ada editorWidget->sourceArea()->openText("--\n" "-- Seer, Copyright 2021 (c)\n" "-- Ernie Pasveer (epasveer@att.net)\n" "-- Ada example\n" "--\n" "with Ada.Text_IO;\n" "use Ada.Text_IO;\n" "\n" "-- This is the main procedure.\n" "procedure Main is\n" "begin\n" " Put_Line (\"Hello, Seer!\"); -- Greetings\n" "end Main;", "sample.adb"); } else if (index == 4) { // Fortran90 editorWidget->sourceArea()->openText("!\n" "! Seer, Copyright 2026 (c)\n" "! Ernie Pasveer (epasveer@att.net)\n" "! Fortran90 example\n" "!\n" "program hello_world\n" " implicit none\n" " print *, \"Hello, World!\"\n" "end program hello_world\n", "sample.f90"); } editorWidget->sourceArea()->setCurrentLine(0); } epasveer-seer-97076f1/src/SeerEditorConfigPage.h000066400000000000000000000053051526321767600215170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerHighlighterSettings.h" #include #include #include "ui_SeerEditorConfigPage.h" class SeerEditorConfigPage : public QWidget, public Ui::SeerEditorConfigPage { Q_OBJECT public: explicit SeerEditorConfigPage (QWidget* parent = 0); ~SeerEditorConfigPage (); void setEditorFont (const QFont& font); const QFont& editorFont () const; void setEditorTabSize (int spaces); int editorTabSize () const; void setHighlighterSettings (const SeerHighlighterSettings& settings); const SeerHighlighterSettings& highlighterSettings () const; void setHighlighterEnabled (bool flag); bool highlighterEnabled () const; void setMinimapEnabled (bool flag); bool minimapEnabled () const; void setExternalEditorCommand (const QString& externalEditorCommand); QString externalEditorCommand () const; void setAutoSourceReload (bool flag); bool autoSourceReload () const; void reset (); protected slots: void handleFontMonoChanged (); void handleFontSizeChanged (const QString& text); void handleFontChanged (const QFont& font); void handleFontDialog (); void handleHighlighterChanged (); void handleHighlighterEnabledChanged (); void handleMinimapEnabledChanged (); void handleApplyTheme (); void handleLanguageTabChanged (int index); private: QFont _font; SeerHighlighterSettings _highlighterSettings; }; epasveer-seer-97076f1/src/SeerEditorConfigPage.ui000066400000000000000000000453171526321767600217140ustar00rootroot00000000000000 SeerEditorConfigPage 0 0 660 861 SeerEditorConfigPage 50 0 QFontComboBox::MonospacedFonts :/seer/resources/icons-icons/font.png:/seer/resources/icons-icons/font.png Show only Mono Spaced fonts. Mono true Theme Select Light or Dark theme. 0 0 Apply Qt::Vertical Tab Size Set tab width, in spaces, for Editors. 1 10 4 Qt::Vertical Enable or disable highlighting for supported languages' files. Syntax highlighting Enable or disable the minimap for source and assembly editors. Minimap Qt::Horizontal 40 20 0 C/C++ Suffixes: C/C++ source suffixes. Separated by '|'. C/C++ source suffixes. true Rust Suffixes: Rust source suffixes. Separated by '|'. Rust source suffixes. true Odin Suffixes: Odin source suffixes. Separated by '|'. Odin source suffixes. true Ada Suffixes: Ada source suffixes. Separated by '|'. Ada source suffixes. true Fortran Suffixes: Fortran source suffixes. Separated by '|'. Fortran source suffixes. true 0 50 0 50 Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded 0 false false true false Weight Style Foreground Background Auto Source Reload External Editor Command Command to launch external editor. myeditor --line %{line} "%{file}" true Automatically reload source files if they are externally modified. 0 50 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Specify font and syntax highlighting colors for the code editor.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These formats apply only when highlighting is enabled and if the file is one of the listed source suffixes.</p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Class</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Comment</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Multiline Comment</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Function</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Keyword</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Quotation</li></ul> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These formats apply for any type of file. </p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Margin</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Text</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Assembly Text</li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current Line</li></ul> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A note about fonts. Sometimes Qt will not list some Mono Spaced fonts even though they are. If this is the case for you, disable the Mono button. All fonts will then be listed.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Syntax highlighting can be enabled or disabled. The list of suffixes for supported source files can be changed. For example, C/C++ source files:</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&quot;.h|.cpp|.c&quot;</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The tab size, in spaces, can be set to properly display source files that contain tab characters.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You can specify a command to launch an external editor. While in a source window, you can use the RMB menu to launch the external editor on the current file. However, these changes are not recognized by Seer. When specifying the command, you have these two variables. One for the name of the source file, and one for the line number to tell the editor to go to. Here are a few examples:</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'monospace';">geany &quot;%{file}&quot;:%{line}<br />kate --line %{line} &quot;%{file}&quot;<br />gedit &quot;%{file}&quot; +%{line}<br />konsole -e vim &quot;%{file}&quot; +%{line}<br /><br /></span>Seer detects if the underlining source file is modified externally. Seer can automatically reload the file or prompt you to reload it.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You may need to close and reopen the source files for changes to take effect.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Seer detects if the underlining source file is modified. Seer can automatically reload the file or prompt you to reload it.</p> <p style="-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> SeerEditorWidgetSource QWidget
SeerEditorWidgetSource.h
1
QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
epasveer-seer-97076f1/src/SeerEditorManagerEntry.h000066400000000000000000000011611526321767600221050ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerEditorWidgetSource.h" #include #include #include struct SeerEditorManagerEntry { QString fullname; QString file; SeerEditorWidgetSource* widget; }; typedef QMap SeerEditorManagerEntries; struct SeerEditorManagerFile { QString fullname; QString file; }; typedef QVector SeerEditorManagerFiles; epasveer-seer-97076f1/src/SeerEditorManagerWidget.cpp000066400000000000000000002016411526321767600225670ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorManagerWidget.h" #include "SeerEditorWidgetSource.h" #include "SeerEditorWidgetAssembly.h" #include "SeerCloseSourceDialog.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include "QHContainerWidget.h" #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include #include #include #include #include #include SeerEditorManagerWidget::SeerEditorManagerWidget (QWidget* parent) : QWidget(parent) { // Initialize private data _editorFont = QFont("monospace", 10); // Default font. _editorHighlighterSettings = SeerHighlighterSettings::populate(""); // Default syntax highlighting. _editorHighlighterEnabled = true; _editorMinimapEnabled = false; _editorKeySettings = SeerKeySettings::populate(); // Default key settings. _editorTabSize = 4; _editorExternalEditorCommand = ""; _editorAutoSourceReload = false; _assemblyWidget = 0; _showAssemblyTabOnStartupMode = "never"; _keepAssemblyTabOnTop = true; _showAddressColumn = true; _showOffsetColumn = false; _showOpcodeColumn = false; _showSourceLines = false; _notifyAssemblyTabShown = true; _idFunctionDefinition = Seer::createID(); _idVariableDefinition = Seer::createID(); _idTypeDefinition = Seer::createID(); // Setup UI setupUi(this); // Setup the widgets tabWidget->setMovable(true); tabWidget->setTabsClosable(true); // Create editor options bar. QToolButton* fileOpenToolButton = new QToolButton(tabWidget); fileOpenToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/document-open.svg")); fileOpenToolButton->setToolTip("Open a file."); QToolButton* fileCloseToolButton = new QToolButton(tabWidget); fileCloseToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg")); fileCloseToolButton->setToolTip("Close opened files."); QToolButton* textSearchToolButton = new QToolButton(tabWidget); textSearchToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/edit-find.svg")); textSearchToolButton->setToolTip("Show search bar."); QToolButton* helpToolButton = new QToolButton(tabWidget); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on the code manager."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(fileOpenToolButton); hcontainer->addWidget(fileCloseToolButton); hcontainer->addWidget(textSearchToolButton); hcontainer->addWidget(helpToolButton); tabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Create a place holder tab with a special name of "". createEditorWidgetTab("", ""); // Connect things. QObject::connect(tabWidget, &QTabWidget::tabCloseRequested, this, &SeerEditorManagerWidget::handleTabCloseRequested); QObject::connect(tabWidget, &QTabWidget::currentChanged, this, &SeerEditorManagerWidget::handleTabCurrentChanged); QObject::connect(fileOpenToolButton, &QToolButton::clicked, this, &SeerEditorManagerWidget::handleFileOpenToolButtonClicked); QObject::connect(fileCloseToolButton, &QToolButton::clicked, this, &SeerEditorManagerWidget::handleFileCloseToolButtonClicked); QObject::connect(textSearchToolButton, &QToolButton::clicked, this, &SeerEditorManagerWidget::handleTextSearchToolButtonClicked); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerEditorManagerWidget::handleHelpToolButtonClicked); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerEditorManagerWidget::handleThemeChanged); #endif // Add combination shortcut for re-open closed file (Ctrl + Shift + T) QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+Shift+T"), this); QObject::connect(shortcut, &QShortcut::activated, [this] () { if (!_stackClosedFiles.empty()) { SeerEditorWidgetSourceArea::SeerCurrentFile topValue = _stackClosedFiles.top(); // read the top _stackClosedFiles.pop(); handleOpenFileWithDetails(topValue.file, topValue.fullname, topValue.cursorRow, topValue.cursorCol, topValue.firstDisplayLine); } } ); } SeerEditorManagerWidget::~SeerEditorManagerWidget () { _notifyAssemblyTabShown = false; deleteAssemblyWidgetTab(); } SeerEditorManagerEntries& SeerEditorManagerWidget::entries() { return _entries; } const SeerEditorManagerEntries& SeerEditorManagerWidget::entries() const { return _entries; } void SeerEditorManagerWidget::dumpEntries () const { qDebug(); SeerEditorManagerEntries::const_iterator b = beginEntry(); SeerEditorManagerEntries::const_iterator e = endEntry(); qDebug() << "Start"; while (b != e) { qDebug() << "\tFullname:" << b->fullname << "File:" << b->file; b++; } qDebug() << "End"; } bool SeerEditorManagerWidget::hasEntry (const QString& fullname) const { if (_entries.find(fullname) != _entries.end()) { return true; } return false; } SeerEditorManagerEntries::iterator SeerEditorManagerWidget::addEntry (const QString& fullname, const QString& file) { //qDebug() << "Add entry:" << fullname << file; SeerEditorManagerEntry entry; entry.fullname = fullname; entry.file = file; entry.widget = 0; return _entries.insert(fullname, entry); } SeerEditorManagerEntries::iterator SeerEditorManagerWidget::findEntry (const QString& fullname) { return _entries.find(fullname); } SeerEditorManagerEntries::const_iterator SeerEditorManagerWidget::findEntry (const QString& fullname) const { return _entries.find(fullname); } SeerEditorManagerEntries::iterator SeerEditorManagerWidget::beginEntry () { return _entries.begin(); } SeerEditorManagerEntries::const_iterator SeerEditorManagerWidget::beginEntry () const { return _entries.begin(); } SeerEditorManagerEntries::iterator SeerEditorManagerWidget::endEntry () { return _entries.end(); } SeerEditorManagerEntries::const_iterator SeerEditorManagerWidget::endEntry () const { return _entries.end(); } void SeerEditorManagerWidget::deleteEntry (SeerEditorManagerEntries::iterator i) { _entries.erase(i); } void SeerEditorManagerWidget::maybeShowAssembly () { if (showAssemblyTabOnStartupMode() == "always") { showAssembly(); } } void SeerEditorManagerWidget::showAssembly () { // Create and show the assembly widget if it isn't already. if (assemblyWidgetTab() == 0) { createAssemblyWidgetTab(); } assemblyWidgetTab()->assemblyArea()->setAddress("$pc"); assemblyWidgetTab()->reloadRegisters(); } SeerEditorWidgetAssembly* SeerEditorManagerWidget::assemblyWidgetTab () { return _assemblyWidget; } void SeerEditorManagerWidget::setKeepAssemblyTabOnTop (bool flag) { _keepAssemblyTabOnTop = flag; } bool SeerEditorManagerWidget::keepAssemblyTabOnTop () const { return _keepAssemblyTabOnTop; } void SeerEditorManagerWidget::setShowAssemblyTabOnStartupMode (const QString& mode) { _showAssemblyTabOnStartupMode = mode; } QString SeerEditorManagerWidget::showAssemblyTabOnStartupMode () const { return _showAssemblyTabOnStartupMode; } void SeerEditorManagerWidget::setAssemblyShowAddressColumn (bool flag) { _showAddressColumn = flag; if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->setShowAddressColumn(_showAddressColumn); } } bool SeerEditorManagerWidget::assemblyShowAddressColumn () const { return _showAddressColumn; } void SeerEditorManagerWidget::setAssemblyShowOffsetColumn (bool flag) { _showOffsetColumn = flag; if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->setShowOffsetColumn(_showOffsetColumn); } } bool SeerEditorManagerWidget::assemblyShowOffsetColumn () const { return _showOffsetColumn; } void SeerEditorManagerWidget::setAssemblyShowOpcodeColumn (bool flag) { _showOpcodeColumn = flag; if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->setShowOpcodeColumn(_showOpcodeColumn); } } bool SeerEditorManagerWidget::assemblyShowOpcodeColumn () const { return _showOpcodeColumn; } void SeerEditorManagerWidget::setAssemblyShowSourceLines (bool flag) { _showSourceLines = flag; if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->setShowSourceLines(_showSourceLines); } } bool SeerEditorManagerWidget::assemblyShowSourceLines () const { return _showSourceLines; } SeerEditorManagerFiles SeerEditorManagerWidget::openedFiles () const { SeerEditorManagerFiles files; SeerEditorManagerEntries::const_iterator b = beginEntry(); SeerEditorManagerEntries::const_iterator e = endEntry(); while (b != e) { SeerEditorManagerFile f; f.file = b->file; f.fullname = b->fullname; files.push_back(f); b++; } return files; } void SeerEditorManagerWidget::setEditorFont (const QFont& font) { _editorFont = font; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setEditorFont(editorFont()); b++; } // Don't forget about the assembly widget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->setEditorFont(editorFont()); } } const QFont& SeerEditorManagerWidget::editorFont () const { return _editorFont; } void SeerEditorManagerWidget::setEditorHighlighterSettings (const SeerHighlighterSettings& settings) { _editorHighlighterSettings = settings; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setHighlighterSettings(_editorHighlighterSettings); b++; } // Don't forget about the assembly widget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->setHighlighterSettings(_editorHighlighterSettings); } } const SeerHighlighterSettings& SeerEditorManagerWidget::editorHighlighterSettings () const { return _editorHighlighterSettings; } void SeerEditorManagerWidget::setEditorHighlighterEnabled (bool flag) { _editorHighlighterEnabled = flag; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setHighlighterEnabled(_editorHighlighterEnabled); b++; } // Don't forget about the assembly widget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->setHighlighterEnabled(editorHighlighterEnabled()); } } bool SeerEditorManagerWidget::editorHighlighterEnabled () const { return _editorHighlighterEnabled; } void SeerEditorManagerWidget::setEditorMinimapEnabled (bool flag) { _editorMinimapEnabled = flag; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->enableMiniMapArea(_editorMinimapEnabled); b++; } // Don't forget about the assembly widget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->enableMiniMapArea(_editorMinimapEnabled); } } bool SeerEditorManagerWidget::editorMinimapEnabled () const { return _editorMinimapEnabled; } void SeerEditorManagerWidget::setEditorAlternateDirectories (const QStringList alternateDirectories) { _editorAlternateDirectories = alternateDirectories; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setAlternateDirectories(_editorAlternateDirectories); b++; } } const QStringList& SeerEditorManagerWidget::editorAlternateDirectories () const { return _editorAlternateDirectories; } void SeerEditorManagerWidget::setEditorIgnoreDirectories (const QStringList ignoreDirectories) { _editorIgnoreDirectories = ignoreDirectories; } const QStringList& SeerEditorManagerWidget::editorIgnoreDirectories () const { return _editorIgnoreDirectories; } void SeerEditorManagerWidget::setEditorKeySettings (const SeerKeySettings& settings) { _editorKeySettings = settings; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->setKeySettings(_editorKeySettings); b++; } // Don't forget about the assembly widget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->setKeySettings(editorKeySettings()); } } const SeerKeySettings& SeerEditorManagerWidget::editorKeySettings () const { return _editorKeySettings; } void SeerEditorManagerWidget::setEditorTabSize (int spaces) { _editorTabSize = spaces; } int SeerEditorManagerWidget::editorTabSize () const { return _editorTabSize; } void SeerEditorManagerWidget::setEditorExternalEditorCommand (const QString& externalEditorCommand) { _editorExternalEditorCommand = externalEditorCommand; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setExternalEditorCommand(_editorExternalEditorCommand); b++; } } const QString& SeerEditorManagerWidget::editorExternalEditorCommand () const { return _editorExternalEditorCommand; } void SeerEditorManagerWidget::setEditorAutoSourceReload (bool flag) { _editorAutoSourceReload = flag; // Update current editors. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setAutoSourceReload(_editorAutoSourceReload); b++; } } bool SeerEditorManagerWidget::editorAutoSourceReload () const { return _editorAutoSourceReload; } void SeerEditorManagerWidget::handleText (const QString& text) { // Update the current line. if (text.startsWith("*stopped")) { //qDebug() << ":stopped:" << text; QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "frame=", '{', '}', false); if (frame_text == "") { return; } QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); //qDebug() << frame_text; //qDebug() << fullname_text << file_text << line_text; // If there is a file to open, open it. if (fullname_text != "" && file_text != "") { // Get the EditorWidget for the file. Create one if needed. SeerEditorWidgetSource* editorWidget = editorWidgetTab(fullname_text); if (editorWidget == 0) { editorWidget = createEditorWidgetTab(fullname_text, file_text, text); } // Can still be null, if the file is ignored. if (editorWidget == 0) { return; } // Push this tab to the top only if the current one in not the "Assembly" tab. QString tabtext = ""; if (tabWidget->currentIndex() >= 0) { tabtext = tabWidget->tabText(tabWidget->currentIndex()); } if (keepAssemblyTabOnTop() && tabtext == "Assembly") { // Do nothing. The "Assembly" tab is already on top. }else{ tabWidget->setCurrentWidget(editorWidget); } // Give the EditorWidget the command text (read file, set line number, etc.). editorWidget->sourceArea()->handleText(text); } // Get the AssemblyWidget, if there is one. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); assemblyWidget->handleText(text); } // Handle certain reasons uniquely. QString reason_text = Seer::parseFirst(newtext, "reason=", '"', '"', false); if (reason_text == "breakpoint-hit") { QString disp_text = Seer::parseFirst(newtext, "disp=", '"', '"', false); // Ask for the breakpoint list to be resent, in case the encountered breakpoint was temporary. if (disp_text == "del") { emit refreshBreakpointsList(); } } return; // Refresh the breakpoints for all opened files. }else if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { // // See SeerBreakpointsBrowserWidget.cpp // // ^done,BreakpointTable={ // ... // } // // We have a breakpoint table. Start by clearing all breakpoints // in the editor widgets that are opened. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->clearBreakpoints(); b++; } // Tell the assembly widget to clear its breakpoints. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->clearBreakpoints(); } // Now parse the table and re-add the breakpoints. QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString body_text = Seer::parseFirst(newtext, "body=", '[', ']', false); //qDebug() << body_text; if (body_text != "") { QStringList bkpt_list = Seer::parse(newtext, "bkpt=", '{', '}', false); for ( const auto& bkpt_text : bkpt_list ) { QString number_text = Seer::parseFirst(bkpt_text, "number=", '"', '"', false); QString type_text = Seer::parseFirst(bkpt_text, "type=", '"', '"', false); QString disp_text = Seer::parseFirst(bkpt_text, "disp=", '"', '"', false); QString enabled_text = Seer::parseFirst(bkpt_text, "enabled=", '"', '"', false); QString addr_text = Seer::parseFirst(bkpt_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(bkpt_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(bkpt_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(bkpt_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(bkpt_text, "line=", '"', '"', false); QString thread_groups_text = Seer::parseFirst(bkpt_text, "thread-groups=", '[', ']', false); QString times_text = Seer::parseFirst(bkpt_text, "times=", '"', '"', false); QString original_location_text = Seer::parseFirst(bkpt_text, "original-location=", '"', '"', false); // Find the appropriate source file and update its breakpoints SeerEditorManagerEntries::iterator i = findEntry(fullname_text); SeerEditorManagerEntries::iterator e = endEntry(); if (i != e) { i->widget->sourceArea()->addBreakpoint(number_text.toInt(), line_text.toInt(), (enabled_text == "y" ? true : false)); } // Tell the assembly widget about the breakpoint. If the address is in its range, it will add it. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->addBreakpoint(number_text.toInt(), addr_text, (enabled_text == "y" ? true : false)); } } } // Send the info for an individual breakpoint to all opened files. // Each opened file can accept it (or reject it) to display the // info as a ToolTip. }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,BreakpointTable={")) && text.endsWith("}")) { // // See SeerBreakpointsBrowserWidget.cpp // // 7^done,BreakpointTable={ // ... // } // // Loop through each opened file and forward the text. SeerEditorManagerEntries::iterator i = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (i != e) { i->widget->sourceArea()->handleText(text); i++; } // Forward the text to the assembly widget, if there is one. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); } }else if (text.startsWith("^done,stack=[") && text.endsWith("]")) { //qDebug() << ":stack:" << text; // // See SeerStackFramesBrowserWidget.cpp // ^done,stack=[ // ... // ] // // Now parse the table and re-add the breakpoints. QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString stack_text = Seer::parseFirst(newtext, "stack=", '[', ']', false); if (stack_text != "") { // Clear current lines in all opened editor widgets. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { //b->widget->setCurrentLine(0); b->widget->sourceArea()->clearCurrentLines(); b++; } // Parse through the frame list and set the current lines that are in the frame list. QStringList frame_list = Seer::parse(newtext, "frame=", '{', '}', false); _lastFrameList = frame_list; SeerEditorManagerEntries::iterator i_later=endEntry(); int lineToPrintLater = -1; for ( const auto& frame_text : frame_list ) { QString level_text = Seer::parseFirst(frame_text, "level=", '"', '"', false); QString addr_text = Seer::parseFirst(frame_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(frame_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); QString arch_text = Seer::parseFirst(frame_text, "arch=", '"', '"', false); SeerEditorManagerEntries::iterator i = findEntry(fullname_text); SeerEditorManagerEntries::iterator e = endEntry(); if (level_text.toInt() == 0) // if current line level = 0, save command and paint it later, fix recursive painting { i_later = i; lineToPrintLater = line_text.toInt(); continue; } if (i != e) { i->widget->sourceArea()->addCurrentLine(line_text.toInt(), level_text.toInt()); } } if (i_later != endEntry() && lineToPrintLater != -1) { i_later->widget->sourceArea()->addCurrentLine(lineToPrintLater, 0); } } // Get the AssemblyWidget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); assemblyWidget->handleText(text); } }else if (text.startsWith("^done,asm_insns=")) { // Get the AssemblyWidget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); assemblyWidget->handleText(text); } }else if (text.startsWith("^error,msg=\"-data-disassemble:")) { // Get the AssemblyWidget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); assemblyWidget->handleText(text); } }else if (text.startsWith("^error,msg=\"No registers.\"")) { //qDebug() << text; // Clear current lines in all opened editor widgets. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setCurrentLine(0); b++; } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // 10^done,value="1" // 11^done,value="0x7fffffffd538" QWidget* w = tabWidget->currentWidget(); if (w) { static_cast(w)->sourceArea()->handleText(text); } SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); if (assemblyWidget) { assemblyWidget->assemblyArea()->handleText(text); assemblyWidget->handleText(text); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // 12^error,msg="No symbol \"return\" in current context." // 13^error,msg="No symbol \"cout\" in current context." QWidget* w = tabWidget->currentWidget(); if (w) { static_cast(w)->sourceArea()->handleText(text); } }else if (text.startsWith("*running")) { // target / program is running, should erase 'yellow' color is for the current line // _lastFrameList is invoked to erase previously "colored" line for ( const auto& frame_text : _lastFrameList ) { QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); SeerEditorManagerEntries::iterator i = findEntry(fullname_text); SeerEditorManagerEntries::iterator e = endEntry(); if (i != e) { i->widget->sourceArea()->eraseColorCurrentLine(line_text.toInt()); } } }else if ( text.contains(QRegularExpression("^([0-9]+)\\^done,symbols={"))) { if (text.startsWith(QString::number(_idTypeDefinition) + "^done,symbols={") || text.startsWith(QString::number(_idFunctionDefinition) + "^done,symbols={") || text.startsWith(QString::number(_idVariableDefinition) + "^done,symbols={")) { // Handle Go to Definition //^10done,symbols={debug=[{filename=" ",fullname=" ", // symbols=[{line=" ",name="uwTick",type="volatile uint32_t",description="volatile uint32_t uwTick;"},}]}] QString debug_text = Seer::parseFirst(text, "debug=", '[', ']', false); QStringList filenames_list = Seer::parse(debug_text, "", '{', '}', false); for (const auto& filename_entry : filenames_list) { QString filename_text = Seer::parseFirst(filename_entry, "filename=", '"', '"', false); QString fullname_text = Seer::parseFirst(filename_entry, "fullname=", '"', '"', false); QString symbols_text = Seer::parseFirst(filename_entry, "symbols=", '[', ']', false); QStringList symbols_list = Seer::parse(symbols_text, "", '{', '}', false); for (const auto& symbol_entry : symbols_list) { QString line_text = Seer::parseFirst(symbol_entry, "line=", '"', '"', false); QString name_text = Seer::parseFirst(symbol_entry, "name=", '"', '"', false); // name_text may be st like: function_name(params...) , so only extract function_name part name_text = name_text.section('(', 0, 0).trimmed(); if (name_text == _gotoDefIdentifier) { // you found it! Open file handleOpenFile(filename_text, fullname_text, line_text.toInt()); } } } } }else{ // Ignore others. return; } } void SeerEditorManagerWidget::handleTabCloseRequested (int index) { //qDebug() << index << tabWidget->count() << tabWidget->tabText(0); // If it is the place holder, don't delete it. if (tabWidget->tabText(index) == "") { return; } // Push to _stackClosedFiles before deleting QString fullname = tabWidget->tabToolTip(index).section(" : ", 1, 1); if (fullname != "") { // Don't push place holder or Assembly tab SeerEditorManagerEntries::iterator i = findEntry(fullname); SeerEditorWidgetSourceArea::SeerCurrentFile current = i->widget->sourceArea()->readCurrentPosition(); _stackClosedFiles.push(current); } // Delete the tab. deleteEditorWidgetTab(index); // If there are no tabs left, create a place holder. if (tabWidget->count() == 0) { createEditorWidgetTab("", ""); } } void SeerEditorManagerWidget::handleTabCurrentChanged (int index) { if (_notifyAssemblyTabShown == false) { return; } if (tabWidget->tabText(index) == "Assembly") { emit assemblyTabShown(true); }else{ emit assemblyTabShown(false); } } void SeerEditorManagerWidget::handleOpenFile (const QString& file, const QString& fullname, int lineno) { // Open file and scroll to lineno handleOpenFileWithDetails(file, fullname, lineno, 0, 0); } void SeerEditorManagerWidget::handleOpenFileWithDetails (const QString& file, const QString& fullname, int cursorRow, int cursorCol, int firstDisplayLine) { // Must have a valid filename. if (file == "" || fullname == "") { return; } // Get the EditorWidget for the file. Create one if needed. SeerEditorWidgetSource* editorWidget = editorWidgetTab(fullname); if (editorWidget == 0) { editorWidget = createEditorWidgetTab(fullname, file); } // Can still be null, if the file is ignored. if (editorWidget == 0) { return; } // Push this tab to the top only if the current one in not the "Assembly" tab. QString tabtext = ""; if (tabWidget->currentIndex() >= 0) { tabtext = tabWidget->tabText(tabWidget->currentIndex()); } if (keepAssemblyTabOnTop() && tabtext == "Assembly") { // Do nothing. The "Assembly" tab is already on top. }else{ tabWidget->setCurrentWidget(editorWidget); } if (firstDisplayLine > 0) { // firstDisplayLine is always > 0 // this means the function is handling open closed files, set cursor position and first display line QPlainTextEdit* textEdit = editorWidget->sourceArea(); // Create a small helper lambda that does the actual restoration auto restoreView = [textEdit, cursorRow, cursorCol, firstDisplayLine, this]() { QTextDocument* doc = textEdit->document(); int lineIndex = cursorRow - 1; // 0-based if (lineIndex >= doc->lineCount()) { return; } QTextBlock block = doc->findBlockByLineNumber(lineIndex); if (!block.isValid()) { return; } QTextCursor cursor(block); cursor.setPosition(block.position() + qMax(0, cursorCol - 1)); textEdit->setTextCursor(cursor); if (firstDisplayLine > 0) { QScrollBar* sb = textEdit->verticalScrollBar(); sb->setValue(firstDisplayLine * sb->singleStep() - sb->singleStep()/2 - 1); } }; QTimer::singleShot(0, textEdit, restoreView); } else { // otherwise, just open file and scroll to cursorRow if (cursorRow > 0) { editorWidget->sourceArea()->scrollToLine(cursorRow); } } handleAddToMouseNavigation({file, fullname, cursorRow, 1, editorWidget->sourceArea()->firstDisplayLine()}); // Ask for the breakpoint list to be resent, in case this file has breakpoints. emit refreshBreakpointsList(); // Ask for the stackframe list to be resent, in case this file has currently executing lines. emit refreshStackFrames(); } void SeerEditorManagerWidget::handleOpenAddress (const QString& address) { // Must have a valid address. if (address == "") { return; } // Get the AssemblyWidget so the address can be loaded. Return if there is no widget. SeerEditorWidgetAssembly* assemblyWidget = assemblyWidgetTab(); // Create assembly widget, if allowed. if (assemblyWidget == 0) { assemblyWidget = createAssemblyWidgetTab(); } // No assembly widget, return. if (assemblyWidget == 0) { return; } // Update assembly widget. assemblyWidget->assemblyArea()->setAddress(address); assemblyWidget->reloadRegisters(); } void SeerEditorManagerWidget::handleMaybeOpenAddress (const QString& file, const QString& fullname, const QString& address) { // Must have a valid address. if (address == "") { return; } // Don't open the assembly tab if told not to. if (showAssemblyTabOnStartupMode() == "never") { return; } // Open the assembly tab. if (showAssemblyTabOnStartupMode() == "always") { handleOpenAddress(address); return; } // If the mode is 'auto', open the assembly tab if there's no source file for the address. if (showAssemblyTabOnStartupMode() == "auto") { if (file != "" && fullname != "") { return; } handleOpenAddress(address); } } SeerEditorWidgetSource* SeerEditorManagerWidget::currentEditorWidgetTab () { QWidget* w = tabWidget->currentWidget(); if (w == 0) { return 0; } return dynamic_cast(w); } SeerEditorWidgetSource* SeerEditorManagerWidget::editorWidgetTab (const QString& fullname) { // Do we have an entry for 'fullname'? SeerEditorManagerEntries::iterator i = findEntry(fullname); if (i == endEntry()) { return 0; } // Return the editor widget. return i->widget; } SeerEditorWidgetSource* SeerEditorManagerWidget::createEditorWidgetTab (const QString& fullname, const QString& file, const QString& text) { //qDebug() << "1:" << fullname << file << tabWidget->count() << tabWidget->tabText(0); //dumpEntries(); // Are we asked to ignore this file? if (Seer::matchesWildcard(editorIgnoreDirectories(), fullname) == true) { emit showMessage(QString("Ignored opening of: '%1'").arg(fullname), 3000); return 0; } // Remove the place holder tab, if present. if (tabWidget->count() == 1 && tabWidget->tabText(0) == "") { deleteEditorWidgetTab(0); } // Create the Editor widget and add it to the tab. SeerEditorWidgetSource* editorWidget = new SeerEditorWidgetSource(this); editorWidget->sourceArea()->setEditorFont(editorFont()); editorWidget->sourceArea()->setEditorTabSize(editorTabSize()); editorWidget->sourceArea()->setExternalEditorCommand(editorExternalEditorCommand()); editorWidget->sourceArea()->setAutoSourceReload(editorAutoSourceReload()); editorWidget->sourceArea()->setHighlighterSettings(editorHighlighterSettings()); editorWidget->sourceArea()->setHighlighterEnabled(editorHighlighterEnabled()); editorWidget->sourceArea()->setAlternateDirectories(editorAlternateDirectories()); editorWidget->sourceArea()->enableMiniMapArea(editorMinimapEnabled()); editorWidget->setKeySettings(editorKeySettings()); // Set the tooltip for the tab. int tabno = tabWidget->addTab(editorWidget, QFileInfo(file).fileName()); tabWidget->setTabToolTip(tabno, QFileInfo(file).fileName() + " : " + fullname); // Connect signals. QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::insertBreakpoint, this, &SeerEditorManagerWidget::handleInsertBreakpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::insertPrintpoint, this, &SeerEditorManagerWidget::handleInsertPrintpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::deleteBreakpoints, this, &SeerEditorManagerWidget::handleDeleteBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::enableBreakpoints, this, &SeerEditorManagerWidget::handleEnableBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::disableBreakpoints, this, &SeerEditorManagerWidget::handleDisableBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::infoBreakpoint, this, &SeerEditorManagerWidget::handleInfoBreakpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::refreshBreakpointsStackFrames, this, &SeerEditorManagerWidget::handleRefreshBreakpointsStackFrames); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::runToLine, this, &SeerEditorManagerWidget::handleRunToLine); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addVariableLoggerExpression, this, &SeerEditorManagerWidget::handleAddVariableLoggerExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addVariableTrackerExpression, this, &SeerEditorManagerWidget::handleAddVariableTrackerExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::refreshVariableTrackerValues, this, &SeerEditorManagerWidget::handleRefreshVariableTrackerValues); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::evaluateVariableExpression, this, &SeerEditorManagerWidget::handleEvaluateVariableExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMemoryVisualizer, this, &SeerEditorManagerWidget::handleAddMemoryVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addArrayVisualizer, this, &SeerEditorManagerWidget::handleAddArrayVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMatrixVisualizer, this, &SeerEditorManagerWidget::handleAddMatrixVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer); QObject::connect(editorWidget, &SeerEditorWidgetSource::addAlternateDirectory, this, &SeerEditorManagerWidget::handleAddAlternateDirectory); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addToMouseNavigation, this, &SeerEditorManagerWidget::handleAddToMouseNavigation); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::signalGotoDefinition, this, &SeerEditorManagerWidget::gotoDefinitionForwarder); // Send the Editor widget the command to load the file. ??? Do better than this. editorWidget->sourceArea()->handleText(text); // Add an entry to our table. SeerEditorManagerEntries::iterator i = addEntry(fullname, QFileInfo(file).fileName()); i->widget = editorWidget; // Return the editor widget. return i->widget; } SeerEditorWidgetSource* SeerEditorManagerWidget::createEditorWidgetTab (const QString& fullname, const QString& file) { //qDebug() << "2:" << fullname << file << tabWidget->count() << tabWidget->tabText(0); //dumpEntries(); // Are we asked to ignore this file? if (Seer::matchesWildcard(editorIgnoreDirectories(), fullname) == true) { emit showMessage(QString("Ignored opening of: '%1'").arg(fullname), 3000); return 0; } // Remove the place holder tab, if present. if (tabWidget->count() == 1 && tabWidget->tabText(0) == "") { deleteEditorWidgetTab(0); } // Create the Editor widget and add it to the tab. SeerEditorWidgetSource* editorWidget = new SeerEditorWidgetSource(this); editorWidget->sourceArea()->setEditorFont(editorFont()); editorWidget->sourceArea()->setEditorTabSize(editorTabSize()); editorWidget->sourceArea()->setExternalEditorCommand(editorExternalEditorCommand()); editorWidget->sourceArea()->setAutoSourceReload(editorAutoSourceReload()); editorWidget->sourceArea()->setHighlighterSettings(editorHighlighterSettings()); editorWidget->sourceArea()->setHighlighterEnabled(editorHighlighterEnabled()); editorWidget->sourceArea()->setAlternateDirectories(editorAlternateDirectories()); editorWidget->sourceArea()->enableMiniMapArea(editorMinimapEnabled()); editorWidget->setKeySettings(editorKeySettings()); // Set the tooltip for the tab. int tabno = tabWidget->addTab(editorWidget, QFileInfo(file).fileName()); tabWidget->setTabToolTip(tabno, QFileInfo(file).fileName() + " : " + fullname); // Connect signals. QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::insertBreakpoint, this, &SeerEditorManagerWidget::handleInsertBreakpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::insertPrintpoint, this, &SeerEditorManagerWidget::handleInsertPrintpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::deleteBreakpoints, this, &SeerEditorManagerWidget::handleDeleteBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::enableBreakpoints, this, &SeerEditorManagerWidget::handleEnableBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::disableBreakpoints, this, &SeerEditorManagerWidget::handleDisableBreakpoints); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::infoBreakpoint, this, &SeerEditorManagerWidget::handleInfoBreakpoint); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::refreshBreakpointsStackFrames, this, &SeerEditorManagerWidget::handleRefreshBreakpointsStackFrames); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::runToLine, this, &SeerEditorManagerWidget::handleRunToLine); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addVariableLoggerExpression, this, &SeerEditorManagerWidget::handleAddVariableLoggerExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addVariableTrackerExpression, this, &SeerEditorManagerWidget::handleAddVariableTrackerExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::refreshVariableTrackerValues, this, &SeerEditorManagerWidget::handleRefreshVariableTrackerValues); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::evaluateVariableExpression, this, &SeerEditorManagerWidget::handleEvaluateVariableExpression); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMemoryVisualizer, this, &SeerEditorManagerWidget::handleAddMemoryVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addArrayVisualizer, this, &SeerEditorManagerWidget::handleAddArrayVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMatrixVisualizer, this, &SeerEditorManagerWidget::handleAddMatrixVisualizer); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer); QObject::connect(editorWidget, &SeerEditorWidgetSource::addAlternateDirectory, this, &SeerEditorManagerWidget::handleAddAlternateDirectory); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addToMouseNavigation, this, &SeerEditorManagerWidget::handleAddToMouseNavigation); QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::signalGotoDefinition, this, &SeerEditorManagerWidget::gotoDefinitionForwarder); // Load the file. editorWidget->sourceArea()->open(fullname, QFileInfo(file).fileName()); // Add an entry to our table. SeerEditorManagerEntries::iterator i = addEntry(fullname, QFileInfo(file).fileName()); i->widget = editorWidget; // Return the editor widget. return i->widget; } void SeerEditorManagerWidget::deleteEditorWidgetTab (int index) { //qDebug() << index << tabWidget->count() << tabWidget->tabText(index); // Get the editor widget. Try as a SeerEditorWidgetSource. SeerEditorWidgetSource* editorWidget = dynamic_cast(tabWidget->widget(index)); if (editorWidget != 0) { // Look for the matching entry for the EditorWidget. // If found, delete it and clean up the map. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { if (editorWidget == b->widget) { deleteEntry(b); // Delete the entry from the map. tabWidget->removeTab(index); // Remove the tab. delete editorWidget; // Delete the actual EditorWidget break; } b++; } return; } // Get the editor widget. Try as a SeerEditorWidgetAssembly. SeerEditorWidgetAssembly* assemblyWidget = dynamic_cast(tabWidget->widget(index)); if (assemblyWidget != 0) { deleteAssemblyWidgetTab(); return; } } SeerEditorWidgetAssembly* SeerEditorManagerWidget::createAssemblyWidgetTab () { // Does it already exist? if (assemblyWidgetTab() != 0) { return assemblyWidgetTab(); } //qDebug() << tabWidget->count() << tabWidget->tabText(0); // Remove the place holder tab, if present. if (tabWidget->count() == 1 && tabWidget->tabText(0) == "") { deleteEditorWidgetTab(0); } // Create the Editor widget and add it to the tab. // Raise it to the top. SeerEditorWidgetAssembly* assemblyWidget = new SeerEditorWidgetAssembly(this); assemblyWidget->assemblyArea()->setEditorFont(editorFont()); assemblyWidget->assemblyArea()->setEditorTabSize(editorTabSize()); assemblyWidget->assemblyArea()->setHighlighterSettings(editorHighlighterSettings()); assemblyWidget->assemblyArea()->setHighlighterEnabled(editorHighlighterEnabled()); assemblyWidget->assemblyArea()->enableMiniMapArea(editorMinimapEnabled()); assemblyWidget->setShowAddressColumn(assemblyShowAddressColumn()); assemblyWidget->setShowOffsetColumn(assemblyShowOffsetColumn()); assemblyWidget->setShowOpcodeColumn(assemblyShowOpcodeColumn()); assemblyWidget->setShowSourceLines(assemblyShowSourceLines()); _assemblyIndex= tabWidget->addTab(assemblyWidget, "Assembly"); tabWidget->setCurrentWidget(assemblyWidget); // Set the tooltip for the tab. tabWidget->setTabToolTip(_assemblyIndex, "Assembly"); // Connect signals. QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::insertBreakpoint, this, &SeerEditorManagerWidget::handleInsertBreakpoint); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::deleteBreakpoints, this, &SeerEditorManagerWidget::handleDeleteBreakpoints); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::enableBreakpoints, this, &SeerEditorManagerWidget::handleEnableBreakpoints); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::disableBreakpoints, this, &SeerEditorManagerWidget::handleDisableBreakpoints); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::refreshBreakpointsStackFrames, this, &SeerEditorManagerWidget::handleRefreshBreakpointsStackFrames); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::runToAddress, this, &SeerEditorManagerWidget::handleRunToAddress); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::requestAssembly, this, &SeerEditorManagerWidget::handleRequestAssembly); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::requestSourceAndAssembly, this, &SeerEditorManagerWidget::handleRequestSourceAndAssembly); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::addMemoryVisualizer, this, &SeerEditorManagerWidget::handleAddMemoryVisualizer); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::addArrayVisualizer, this, &SeerEditorManagerWidget::handleAddArrayVisualizer); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::addMatrixVisualizer, this, &SeerEditorManagerWidget::handleAddMatrixVisualizer); QObject::connect(assemblyWidget->assemblyArea(), &SeerEditorWidgetAssemblyArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer); QObject::connect(assemblyWidget, &SeerEditorWidgetAssembly::evaluateVariableExpression, this, &SeerEditorManagerWidget::handleEvaluateVariableExpression); // Load the file. assemblyWidget->assemblyArea()->setPlainText(""); // Add an entry to our table. _assemblyWidget = assemblyWidget; // Send a signal to enable the Nexti/Stepi buttons. emit assemblyTabShown(true); // Return the editor widget. return assemblyWidget; } void SeerEditorManagerWidget::deleteAssemblyWidgetTab () { if (_assemblyWidget == 0) { return; } //qDebug() << "Delete AssemblyWidget"; tabWidget->removeTab(_assemblyIndex); // Remove the tab. delete _assemblyWidget; // Delete the actual EditorWidget _assemblyWidget = 0; // Send a signal to disable the Nexti/Stepi buttons. if (_notifyAssemblyTabShown) { emit assemblyTabShown(false); } } void SeerEditorManagerWidget::handleFileOpenToolButtonClicked () { QString filename = QFileDialog::getOpenFileName(this, tr("Open Source File"), "./", tr("Source files (*.*)"), nullptr, QFileDialog::DontUseNativeDialog); if (filename == "") { return; } QFileInfo info(filename); info.makeAbsolute(); handleOpenFile(info.fileName(), info.filePath(), 0); } void SeerEditorManagerWidget::handleFileCloseToolButtonClicked () { SeerCloseSourceDialog dlg(this); dlg.setFiles(openedFiles()); int ret = dlg.exec(); if (ret == 0) { return; } SeerEditorManagerFiles files = dlg.selectedFiles(); for (int i=0; iindexOf(w); if (idx < 0) { qWarning() << "Can't find tab index for:" << files[i].fullname; continue; } deleteEditorWidgetTab(idx); } // If there are no tabs left, create a place holder. if (tabWidget->count() == 0) { createEditorWidgetTab("", ""); } } void SeerEditorManagerWidget::handleTextSearchToolButtonClicked () { QWidget* tab = tabWidget->currentWidget(); SeerEditorWidgetSource* sourcew = dynamic_cast(tab); if (sourcew != 0) { if (sourcew->isSearchBarShown() == true) { sourcew->showSearchBar(false); }else{ sourcew->showSearchBar(true); } return; } SeerEditorWidgetAssembly* assemblyw = dynamic_cast(tab); if (assemblyw != 0) { if (assemblyw->isSearchBarShown() == true) { assemblyw->showSearchBar(false); }else{ assemblyw->showSearchBar(true); } return; } } void SeerEditorManagerWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/CodeManager.md"); help->show(); help->raise(); } void SeerEditorManagerWidget::handleAddAlternateDirectory (QString path) { // Don't re-add it if it already exists in the list. if (_editorAlternateDirectories.contains(path) == true) { QMessageBox::warning(this, "Note.", "The directory '" + path +"' is already in the alternate directories list."); return; } // Add the new path to our list. _editorAlternateDirectories << path; // Update any open editors. Future editors will get the updated list normally. SeerEditorManagerEntries::iterator b = beginEntry(); SeerEditorManagerEntries::iterator e = endEntry(); while (b != e) { b->widget->sourceArea()->setAlternateDirectories(_editorAlternateDirectories); b++; } QMessageBox::information(this, "Note.", "Added '" + path +"' to the alternate directories list."); } void SeerEditorManagerWidget::handleInsertBreakpoint (QString breakpoint) { // rethrow emit insertBreakpoint (breakpoint); } void SeerEditorManagerWidget::handleInsertPrintpoint (QString type, QString function, QString channel, QString parameters) { // rethrow emit insertPrintpoint (type, function, channel, parameters); } void SeerEditorManagerWidget::handleDeleteBreakpoints (QString breakpoints) { // rethrow emit deleteBreakpoints (breakpoints); } void SeerEditorManagerWidget::handleEnableBreakpoints (QString breakpoints) { // rethrow emit enableBreakpoints (breakpoints); } void SeerEditorManagerWidget::handleDisableBreakpoints (QString breakpoints) { // rethrow emit disableBreakpoints (breakpoints); } void SeerEditorManagerWidget::handleInfoBreakpoint (int breakpointid, QString breakpoint) { // rethrow emit infoBreakpoint (breakpointid, breakpoint); } void SeerEditorManagerWidget::handleRefreshBreakpointsStackFrames () { // Ask for the breakpoint list to be resent, in case files have breakpoints. emit refreshBreakpointsList(); // Ask for the stackframe list to be resent, in case files have currently executing lines. emit refreshStackFrames(); } void SeerEditorManagerWidget::handleRunToLine (QString fullname, int lineno) { // rethrow emit runToLine (fullname, lineno); } void SeerEditorManagerWidget::handleRunToAddress (QString address) { // rethrow if (address != "") { emit runToAddress (address); } } void SeerEditorManagerWidget::handleRunToSelectedLine () { SeerEditorWidgetSource* sourceTab = currentEditorWidgetTab(); SeerEditorWidgetAssembly* assemblyTab = assemblyWidgetTab(); if (sourceTab) { emit runToLine (sourceTab->sourceArea()->fullname(), sourceTab->sourceArea()->currentLine()); } if (assemblyTab) { QString address = assemblyTab->assemblyArea()->currentLine(); if (address != "") { emit runToAddress (address); } } } void SeerEditorManagerWidget::handleAddVariableLoggerExpression (QString expression) { // rethrow emit addVariableLoggerExpression (expression); } void SeerEditorManagerWidget::handleAddVariableTrackerExpression (QString expression) { // rethrow emit addVariableTrackerExpression (expression); } void SeerEditorManagerWidget::handleRefreshVariableTrackerValues () { // rethrow emit refreshVariableTrackerValues (); } void SeerEditorManagerWidget::handleEvaluateVariableExpression (int expressionid, QString expression) { // rethrow emit evaluateVariableExpression (expressionid, expression); } void SeerEditorManagerWidget::handleAddMemoryVisualizer (QString expression) { // rethrow emit addMemoryVisualizer (expression); } void SeerEditorManagerWidget::handleAddArrayVisualizer (QString expression) { // rethrow emit addArrayVisualizer (expression); } void SeerEditorManagerWidget::handleAddMatrixVisualizer (QString expression) { // rethrow emit addMatrixVisualizer (expression); } void SeerEditorManagerWidget::handleAddStructVisualizer (QString expression) { // rethrow emit addStructVisualizer (expression); } void SeerEditorManagerWidget::handleRequestAssembly (QString address) { // rethrow emit requestAssembly (address); // Ask for the stackframe list to be resent, this will highlight current line when the // assembly tab is shown for the first time. emit refreshStackFrames(); } void SeerEditorManagerWidget::handleRequestSourceAndAssembly (QString address) { // rethrow emit requestSourceAndAssembly (address); // Ask for the stackframe list to be resent, this will highlight current line when the // assembly tab is shown for the first time. emit refreshStackFrames(); } void SeerEditorManagerWidget::handleAssemblyConfigChanged () { // Tell the assembly tab to refresh. if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->reloadAssembly(); } } void SeerEditorManagerWidget::handleSessionTerminated () { // Clear current editors. for (auto entry : entries()) { entry.widget->sourceArea()->clearCurrentLines(); } // Clear assembly editor. if (assemblyWidgetTab() != 0) { assemblyWidgetTab()->assemblyArea()->clearCurrentLines(); } } // Clear the stack of recently closed files backward/forward list whenever a new gdb session starts void SeerEditorManagerWidget::handleGdbStateChanged() { while (!_stackClosedFiles.empty()) { _stackClosedFiles.pop(); } _listForwardFiles.clear(); _forwardFilesIndex = -1; } /*********************************************************************************************************************** * Function for handling mouse navigation **********************************************************************************************************************/ void SeerEditorManagerWidget::handleAddToMouseNavigation(const SeerEditorWidgetSourceArea::SeerCurrentFile& currentFile) { // Record this file in the forward list. if (currentFile.file != "") { // Check if the last added file is the same as currentFile if (!_listForwardFiles.empty()) { const SeerEditorWidgetSourceArea::SeerCurrentFile& lastFile = _listForwardFiles[_listForwardFiles.size() -1]; if (currentFile == lastFile) { return; } } // if _forwardFilesIndex is at the end of the list, just append if (_forwardFilesIndex >= _listForwardFiles.size() - 1) { _listForwardFiles.append(currentFile); _forwardFilesIndex ++; } else { // else remove all entries after _forwardFilesIndex and then append int removeCount = _listForwardFiles.size() - 1 - _forwardFilesIndex; if ((currentFile == _listForwardFiles[_listForwardFiles.size() -1]) || (currentFile == _listForwardFiles[0]) || (currentFile == _listForwardFiles[_listForwardFiles.size() - 1 - removeCount]) ) { return; } for (int i=0; i < removeCount; i++) { _listForwardFiles.removeLast(); } _listForwardFiles.append(currentFile); _forwardFilesIndex = _listForwardFiles.size() -1; } } } void SeerEditorManagerWidget::handleOpenForwardBackward(const SeerEditorWidgetSourceArea::SeerCurrentFile& fileInfo) { // Get the EditorWidget for the file. Create one if needed. SeerEditorWidgetSource* editorWidget = editorWidgetTab(fileInfo.fullname); if (editorWidget == 0) { editorWidget = createEditorWidgetTab(fileInfo.fullname, fileInfo.file); } // Can still be null, if the file is ignored. if (editorWidget == 0) { return; } // Push this tab to the top only if the current one in not the "Assembly" tab. QString tabtext = ""; if (tabWidget->currentIndex() >= 0) { tabtext = tabWidget->tabText(tabWidget->currentIndex()); } if (keepAssemblyTabOnTop() && tabtext == "Assembly") { // Do nothing. The "Assembly" tab is already on top. }else{ tabWidget->setCurrentWidget(editorWidget); } if (fileInfo.firstDisplayLine > 0) { // scroll to the previous first display line QScrollBar *scrollBar = editorWidget->sourceArea()->verticalScrollBar(); int step = scrollBar->singleStep(); scrollBar->setValue(fileInfo.firstDisplayLine * step - 1); // Set cursor position QTextBlock block = editorWidget->sourceArea()->document()->findBlockByLineNumber(fileInfo.cursorRow-1); QTextCursor cursor = editorWidget->sourceArea()->textCursor(); cursor.setPosition(block.position() + fileInfo.cursorCol - 1); editorWidget->sourceArea()->setTextCursor(cursor); } } void SeerEditorManagerWidget::handleThemeChanged () { // // Normally, we would colorize all the icons in this widget and its // childred, however, this is already handled in SeerMainWindow. // // Instead, we change the editor's color scheme here. // // Switch to the right scheme. SeerHighlighterSettings settings; #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) // Get the current color scheme Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); if (colorScheme == Qt::ColorScheme::Dark) { settings = SeerHighlighterSettings::populate_dark(); }else{ settings = SeerHighlighterSettings::populate_light(); } #else settings = SeerHighlighterSettings::populate_light(); #endif // Set the new color scheme for the editor manager. // This updates all existing editors. setEditorHighlighterSettings(settings); } // Handle mouse press events for navigation void SeerEditorManagerWidget::mousePressEvent(QMouseEvent *event) { // Back button (XButton1) clicked if (event->button() == Qt::XButton1) { if (_forwardFilesIndex - 1 < 0) return; --_forwardFilesIndex; const SeerEditorWidgetSourceArea::SeerCurrentFile &info = _listForwardFiles.at(_forwardFilesIndex); handleOpenForwardBackward(info); } // Forward button (XButton2) clicked else if (event->button() == Qt::XButton2) { if (_forwardFilesIndex + 1 > _listForwardFiles.size() - 1) return; ++ _forwardFilesIndex; const SeerEditorWidgetSourceArea::SeerCurrentFile &info = _listForwardFiles.at(_forwardFilesIndex); handleOpenForwardBackward(info); } else { QWidget::mousePressEvent(event); } } /*********************************************************************************************************************** * Functions for handling tracing identifier * **********************************************************************************************************************/ void SeerEditorManagerWidget::gotoDefinitionForwarder(const QString& identifier) { _gotoDefIdentifier = identifier; // Ask for identifier matches for Functions, Variables, and Types. // // Sometimes symbols have or don't have arguments. // Searching for: "^functionName(.*)$" "^functionName$". // Searching for: "^functionName$". // emit refreshFunctionList(_idFunctionDefinition, "^" + _gotoDefIdentifier + "$"); emit refreshFunctionList(_idFunctionDefinition, "^" + _gotoDefIdentifier + "\\(.*\\)$"); emit refreshVariableList(_idVariableDefinition, _gotoDefIdentifier, ""); emit refreshTypeList(_idTypeDefinition, _gotoDefIdentifier); } epasveer-seer-97076f1/src/SeerEditorManagerWidget.h000066400000000000000000000412141526321767600222320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerEditorWidgetAssembly.h" #include "SeerEditorManagerEntry.h" #include "SeerHighlighterSettings.h" #include "SeerKeySettings.h" #include #include #include #include #include #include #include "ui_SeerEditorManagerWidget.h" class SeerEditorManagerWidget : public QWidget, protected Ui::SeerEditorManagerWidgetForm { Q_OBJECT public: explicit SeerEditorManagerWidget (QWidget* parent = 0); ~SeerEditorManagerWidget (); void dumpEntries () const; SeerEditorManagerEntries& entries (); const SeerEditorManagerEntries& entries () const; bool hasEntry (const QString& fullname) const; SeerEditorManagerEntries::iterator addEntry (const QString& fullname, const QString& file); SeerEditorManagerEntries::iterator findEntry (const QString& fullname); SeerEditorManagerEntries::const_iterator findEntry (const QString& fullname) const; SeerEditorManagerEntries::iterator beginEntry (); SeerEditorManagerEntries::const_iterator beginEntry () const; SeerEditorManagerEntries::iterator endEntry (); SeerEditorManagerEntries::const_iterator endEntry () const; void deleteEntry (SeerEditorManagerEntries::iterator i); void maybeShowAssembly (); void showAssembly (); SeerEditorWidgetAssembly* assemblyWidgetTab (); void setKeepAssemblyTabOnTop (bool flag); bool keepAssemblyTabOnTop () const; void setShowAssemblyTabOnStartupMode (const QString& mode); QString showAssemblyTabOnStartupMode () const; void setAssemblyShowAddressColumn (bool flag); bool assemblyShowAddressColumn () const; void setAssemblyShowOffsetColumn (bool flag); bool assemblyShowOffsetColumn () const; void setAssemblyShowOpcodeColumn (bool flag); bool assemblyShowOpcodeColumn () const; void setAssemblyShowSourceLines (bool flag); bool assemblyShowSourceLines () const; SeerEditorManagerFiles openedFiles () const; void setEditorFont (const QFont& font); const QFont& editorFont () const; void setEditorHighlighterSettings (const SeerHighlighterSettings& settings); const SeerHighlighterSettings& editorHighlighterSettings () const; void setEditorHighlighterEnabled (bool flag); bool editorHighlighterEnabled () const; void setEditorMinimapEnabled (bool flag); bool editorMinimapEnabled () const; void setEditorAlternateDirectories (const QStringList alternateDirectories); const QStringList& editorAlternateDirectories () const; void setEditorIgnoreDirectories (const QStringList ignoreDirectories); const QStringList& editorIgnoreDirectories () const; void setEditorKeySettings (const SeerKeySettings& settings); const SeerKeySettings& editorKeySettings () const; void setEditorTabSize (int spaces); int editorTabSize () const; void setEditorExternalEditorCommand (const QString& externalEditorCommand); const QString& editorExternalEditorCommand () const; void setEditorAutoSourceReload (bool flag); bool editorAutoSourceReload () const; public slots: void handleText (const QString& text); void handleTabCloseRequested (int index); void handleTabCurrentChanged (int index); void handleOpenFile (const QString& file, const QString& fullname, int lineno); void handleOpenAddress (const QString& address); void handleMaybeOpenAddress (const QString& file, const QString& fullname, const QString& address); void handleInsertBreakpoint (QString breakpoint); void handleInsertPrintpoint (QString type, QString function, QString channel, QString parameters); void handleDeleteBreakpoints (QString breakpoints); void handleEnableBreakpoints (QString breakpoints); void handleDisableBreakpoints (QString breakpoints); void handleInfoBreakpoint (int breakpointid, QString breakpoint); void handleRefreshBreakpointsStackFrames (); void handleRunToLine (QString fullname, int lineno); void handleRunToAddress (QString address); void handleRunToSelectedLine (); void handleAddVariableLoggerExpression (QString expression); void handleAddVariableTrackerExpression (QString expression); void handleRefreshVariableTrackerValues (); void handleEvaluateVariableExpression (int expressionid, QString expression); void handleAddMemoryVisualizer (QString expression); void handleAddArrayVisualizer (QString expression); void handleAddMatrixVisualizer (QString expression); void handleAddStructVisualizer (QString expression); void handleRequestAssembly (QString address); void handleRequestSourceAndAssembly (QString address); void handleAssemblyConfigChanged (); void handleSessionTerminated (); void handleGdbStateChanged (); void handleAddToMouseNavigation (const SeerEditorWidgetSourceArea::SeerCurrentFile& currentFile); void handleThemeChanged (); protected: void mousePressEvent (QMouseEvent *event) override; private slots: void handleFileOpenToolButtonClicked (); void handleFileCloseToolButtonClicked (); void handleTextSearchToolButtonClicked (); void handleHelpToolButtonClicked (); void handleAddAlternateDirectory (QString path); void gotoDefinitionForwarder (const QString& identifier); signals: void refreshBreakpointsList (); void refreshStackFrames (); void insertBreakpoint (QString breakpoint); void insertPrintpoint (QString type, QString function, QString channel, QString parameters); void deleteBreakpoints (QString breakpoints); void enableBreakpoints (QString breakpoints); void disableBreakpoints (QString breakpoints); void infoBreakpoint (int breakpointid, QString breakpoint); void runToLine (QString file, int lineno); void runToAddress (QString address); void addVariableLoggerExpression (QString expression); void addVariableTrackerExpression (QString expression); void refreshVariableTrackerValues (); void evaluateVariableExpression (int expressionid, QString expression); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); void requestAssembly (QString address); void requestSourceAndAssembly (QString address); void showMessage (QString message, int time); void assemblyTabShown (bool shown); void gotoDefinitionForward (const QString& identifier, bool ignoreErrors = false); void refreshFunctionList (int id, const QString& functionRegex); void refreshVariableList (int id, const QString& staticNameRegex, const QString& staticTypeRegex); void refreshTypeList (int id, const QString& typeRegex); private: SeerEditorWidgetSource* currentEditorWidgetTab (); SeerEditorWidgetSource* editorWidgetTab (const QString& fullname); SeerEditorWidgetSource* createEditorWidgetTab (const QString& fullname, const QString& file, const QString& text); SeerEditorWidgetSource* createEditorWidgetTab (const QString& fullname, const QString& file); void deleteEditorWidgetTab (int index); SeerEditorWidgetAssembly* createAssemblyWidgetTab (); void deleteAssemblyWidgetTab (); void handleOpenFileWithDetails (const QString& file, const QString& fullname, int cursorRow, int cursorCol, int firstDisplayLine); void handleOpenForwardBackward (const SeerEditorWidgetSourceArea::SeerCurrentFile& fileInfo); SeerEditorManagerEntries _entries; SeerHighlighterSettings _editorHighlighterSettings; bool _editorHighlighterEnabled; bool _editorMinimapEnabled; QFont _editorFont; QStringList _editorAlternateDirectories; QStringList _editorIgnoreDirectories; SeerKeySettings _editorKeySettings; int _editorTabSize; QString _editorExternalEditorCommand; bool _editorAutoSourceReload; SeerEditorWidgetAssembly* _assemblyWidget; int _assemblyIndex; QString _showAssemblyTabOnStartupMode; bool _keepAssemblyTabOnTop; bool _showAddressColumn; bool _showOffsetColumn; bool _showOpcodeColumn; bool _showSourceLines; bool _notifyAssemblyTabShown; QStringList _lastFrameList; // variable for saving previous backtrace // list of recently closed files (Ctrl + Shift + T) QStack _stackClosedFiles; // list of cursor positions for mouse navigation (back/forward) QList _listForwardFiles; int _forwardFilesIndex = -1; // _id of identifier for Go to definition int _idFunctionDefinition; int _idVariableDefinition; int _idTypeDefinition; QString _gotoDefIdentifier; }; epasveer-seer-97076f1/src/SeerEditorManagerWidget.ui000066400000000000000000000023421526321767600224170ustar00rootroot00000000000000 SeerEditorManagerWidgetForm 0 0 854 571 Form 0 0 0 0 3 -1 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
epasveer-seer-97076f1/src/SeerEditorWidgetAssembly.cpp000066400000000000000000000464641526321767600230060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorWidgetAssembly.h" #include "SeerAssemblyPreferenceDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SeerEditorWidgetAssembly::SeerEditorWidgetAssembly(QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Set the widgets. assemblyArea()->show(); searchTextLineEdit->enableReturnPressedOnClear(); showSearchBar(false); // Hide the search bar. ctrl+F to show it again. setSearchMatchCase(true); // Search with case sensitivity. _textSearchShortcut = new QShortcut(QKeySequence(tr("Ctrl+F")), this); _textSearchNextShortcut = new QShortcut(QKeySequence(tr("Ctrl+G")), this); _textSearchPrevShortcut = new QShortcut(QKeySequence(tr("Ctrl+Shift+G")), this); _lineSearchShortcut = new QShortcut(QKeySequence(tr("Ctrl+L")), this); _toggleBreakpointShortcut = new QShortcut(QKeySequence(tr("Ctrl+B")), this); setKeySettings(SeerKeySettings::populate()); _pcId = Seer::createID(); _spId = Seer::createID(); _flagsId = Seer::createID(); // Clear PC, SP, and FLAGS. pcLineEdit->clear(); spLineEdit->clear(); flagsLineEdit->clear(); // Preference menu. QMenu* menu = new QMenu(); _editPreferencesAction = menu->addAction("Assembly preferences"); preferencesToolButton->setMenu(menu); preferencesToolButton->setPopupMode(QToolButton::InstantPopup); // Connect things. QObject::connect(searchTextLineEdit, &QHistoryLineEdit::returnPressed, this, &SeerEditorWidgetAssembly::handleSearchTextLineEdit); QObject::connect(searchTextLineEdit, &QHistoryLineEdit::escapePressed, this, &SeerEditorWidgetAssembly::handleEscapePressed); #if QT_VERSION >= 0x060900 QObject::connect(matchCaseCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetAssembly::handleSearchTextLineEdit); #else QObject::connect(matchCaseCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetAssembly::handleSearchTextLineEdit); #endif QObject::connect(searchDownToolButton, &QToolButton::clicked, this, &SeerEditorWidgetAssembly::handleSearchDownToolButton); QObject::connect(searchUpToolButton, &QToolButton::clicked, this, &SeerEditorWidgetAssembly::handleSearchUpToolButton); QObject::connect(searchLineNumberLineEdit, &QHistoryLineEdit::returnPressed, this, &SeerEditorWidgetAssembly::handleSearchLineNumberLineEdit); QObject::connect(searchLineNumberLineEdit, &QHistoryLineEdit::escapePressed, this, &SeerEditorWidgetAssembly::handleEscapePressed); QObject::connect(searchCloseToolButton, &QToolButton::clicked, this, &SeerEditorWidgetAssembly::handleSearchCloseToolButton); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerEditorWidgetAssembly::reloadAssembly); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerEditorWidgetAssembly::reloadRegisters); #if QT_VERSION >= 0x060900 QObject::connect(showAddressCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetAssembly::handleShowAddressColumn); QObject::connect(showOffsetCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetAssembly::handleShowOffsetColumn); QObject::connect(showOpcodeCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetAssembly::handleShowOpcodeColumn); QObject::connect(showSourceCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetAssembly::handleShowSourceLines); #else QObject::connect(showAddressCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetAssembly::handleShowAddressColumn); QObject::connect(showOffsetCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetAssembly::handleShowOffsetColumn); QObject::connect(showOpcodeCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetAssembly::handleShowOpcodeColumn); QObject::connect(showSourceCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetAssembly::handleShowSourceLines); #endif QObject::connect(assemblyWidget, &SeerEditorWidgetAssemblyArea::showSearchBar, this, qOverload(&SeerEditorWidgetAssembly::showSearchBar)); QObject::connect(_textSearchShortcut, &QShortcut::activated, this, &SeerEditorWidgetAssembly::handleTextSearchShortcut); QObject::connect(_textSearchNextShortcut, &QShortcut::activated, this, &SeerEditorWidgetAssembly::handleSearchDownToolButton); QObject::connect(_textSearchPrevShortcut, &QShortcut::activated, this, &SeerEditorWidgetAssembly::handleSearchUpToolButton); QObject::connect(_lineSearchShortcut, &QShortcut::activated, this, &SeerEditorWidgetAssembly::handleLineSearchShortcut); QObject::connect(_toggleBreakpointShortcut, &QShortcut::activated, this, &SeerEditorWidgetAssembly::handleToggleBreakpointShortcut); QObject::connect(_editPreferencesAction, &QAction::triggered, this, &SeerEditorWidgetAssembly::handleEditPreferences); // Set defaults. setShowAddressColumn(true); setShowOffsetColumn(false); setShowOpcodeColumn(false); setShowSourceLines(false); setConvertUppercase(false); setRegiserNamePC("$pc"); setRegiserNameSP("$sp"); setRegiserNameFLAGS("$ps"); // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); readSettings(); } SeerEditorWidgetAssembly::~SeerEditorWidgetAssembly () { } SeerEditorWidgetAssemblyArea* SeerEditorWidgetAssembly::assemblyArea () { return assemblyWidget; } const SeerEditorWidgetAssemblyArea* SeerEditorWidgetAssembly::assemblyArea () const { return assemblyWidget; } bool SeerEditorWidgetAssembly::isSearchBarShown () const { return searchBarWidget->isVisible(); } bool SeerEditorWidgetAssembly::searchMatchCase () const { return matchCaseCheckBox->isChecked(); } bool SeerEditorWidgetAssembly::showAddressColumn () const { return showAddressCheckBox->isChecked(); } bool SeerEditorWidgetAssembly::showOffsetColumn () const { return showOffsetCheckBox->isChecked(); } bool SeerEditorWidgetAssembly::showOpcodeColumn () const { return showOpcodeCheckBox->isChecked(); } bool SeerEditorWidgetAssembly::showSourceLines () const { return showSourceCheckBox->isChecked(); } QString SeerEditorWidgetAssembly::regiserNamePC () const { return _pcName; } QString SeerEditorWidgetAssembly::regiserNameFLAGS () const { return _flagsName; } QString SeerEditorWidgetAssembly::regiserNameSP () const { return _spName; } bool SeerEditorWidgetAssembly::convertUppercase () const { return assemblyArea()->convertUppercase(); } void SeerEditorWidgetAssembly::setKeySettings (const SeerKeySettings& settings) { _keySettings = settings; if (_keySettings.has("SearchText") == true) { _textSearchShortcut->setKey(_keySettings.get("SearchText")._sequence); } if (_keySettings.has("SearchTextNext") == true) { _textSearchNextShortcut->setKey(_keySettings.get("SearchTextNext")._sequence); } if (_keySettings.has("SearchTextPrev") == true) { _textSearchPrevShortcut->setKey(_keySettings.get("SearchTextPrev")._sequence); } if (_keySettings.has("ToggleBreakpoint") == true) { _toggleBreakpointShortcut->setKey(_keySettings.get("ToggleBreakpoint")._sequence); } } const SeerKeySettings& SeerEditorWidgetAssembly::keySettings () const { return _keySettings; } void SeerEditorWidgetAssembly::reloadAssembly () { QString addr = assemblyArea()->address(); assemblyArea()->setAddress(addr, true); pcLineEdit->clear(); spLineEdit->clear(); flagsLineEdit->clear(); // Get the PC, SP, and FLAGS if (regiserNamePC() != "") { emit evaluateVariableExpression(_pcId, regiserNamePC()); } if (regiserNameSP() != "") { emit evaluateVariableExpression(_spId, regiserNameSP()); } if (regiserNameFLAGS() != "") { emit evaluateVariableExpression(_flagsId, regiserNameFLAGS()); } } void SeerEditorWidgetAssembly::reloadRegisters () { pcLineEdit->clear(); spLineEdit->clear(); flagsLineEdit->clear(); // Get the PC, SP, and FLAGS if (regiserNamePC() != "") { emit evaluateVariableExpression(_pcId, regiserNamePC()); } if (regiserNameSP() != "") { emit evaluateVariableExpression(_spId, regiserNameSP()); } if (regiserNameFLAGS() != "") { emit evaluateVariableExpression(_flagsId, regiserNameFLAGS()); } } void SeerEditorWidgetAssembly::showSearchBar (bool flag) { showSearchBar(flag, ""); } void SeerEditorWidgetAssembly::showSearchBar (bool flag, QString field) { searchBarWidget->setVisible(flag); // If 'show', give the searchTextLineEdit or the searchTextLineEdit the focus. if (flag) { if (field == "text") { searchTextLineEdit->setFocus(Qt::MouseFocusReason); }else if (field == "line") { searchLineNumberLineEdit->setFocus(Qt::MouseFocusReason); }else{ searchTextLineEdit->setFocus(Qt::MouseFocusReason); } } } void SeerEditorWidgetAssembly::setSearchMatchCase (bool flag) { matchCaseCheckBox->setChecked(flag); } void SeerEditorWidgetAssembly::setShowAddressColumn (bool flag) { showAddressCheckBox->setChecked(flag); handleShowAddressColumn(); } void SeerEditorWidgetAssembly::setShowOffsetColumn (bool flag) { showOffsetCheckBox->setChecked(flag); handleShowOffsetColumn(); } void SeerEditorWidgetAssembly::setShowOpcodeColumn (bool flag) { showOpcodeCheckBox->setChecked(flag); handleShowOpcodeColumn(); } void SeerEditorWidgetAssembly::setShowSourceLines (bool flag) { showSourceCheckBox->setChecked(flag); handleShowSourceLines(); } void SeerEditorWidgetAssembly::setRegiserNamePC (const QString& name) { _pcName = name; } void SeerEditorWidgetAssembly::setRegiserNameFLAGS (const QString& name) { _flagsName = name; } void SeerEditorWidgetAssembly::setRegiserNameSP (const QString& name) { _spName = name; } void SeerEditorWidgetAssembly::setConvertUppercase (bool flag) { assemblyArea()->setConvertUppercase(flag); } void SeerEditorWidgetAssembly::handleText (const QString& text) { if (text.startsWith("*stopped")) { //qDebug() << text; // *stopped, // // reason="end-stepping-range", // // frame={addr="0x0000000000400b45", // func="main", // args=[{name="argc",value="1"},{name="argv",value="0x7fffffffd5b8"}], // file="helloworld.cpp", // fullname="/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp", // line="7", // arch="i386:x86-64"}, // // thread-id="1", // stopped-threads="all", // core="6" QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "frame=", '{', '}', false); if (frame_text == "") { return; } // Get the PC, SP, and FLAGS if (regiserNamePC() != "") { emit evaluateVariableExpression(_pcId, regiserNamePC()); } if (regiserNameSP() != "") { emit evaluateVariableExpression(_spId, regiserNameSP()); } if (regiserNameFLAGS() != "") { emit evaluateVariableExpression(_flagsId, regiserNameFLAGS()); } return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { QString id_text = text.section('^', 0,0); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); if (id_text == QString::number(_pcId)) { pcLineEdit->setText(Seer::filterEscapes(value_text)); return; } if (id_text == QString::number(_spId)) { spLineEdit->setText(Seer::filterEscapes(value_text)); return; } if (id_text == QString::number(_flagsId)) { flagsLineEdit->setText(Seer::filterEscapes(value_text)); return; } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { QString id_text = text.section('^', 0,0); QString msg_text = Seer::parseFirst(text, "value=", '"', '"', false); if (id_text == QString::number(_pcId)) { pcLineEdit->setText(Seer::filterEscapes(msg_text)); return; } if (id_text == QString::number(_spId)) { spLineEdit->setText(Seer::filterEscapes(msg_text)); return; } if (id_text == QString::number(_flagsId)) { flagsLineEdit->setText(Seer::filterEscapes(msg_text)); return; } }else if (text.startsWith("^error,msg=\"No registers.\"")) { // Clear PC, SP, and FLAGS. pcLineEdit->clear(); spLineEdit->clear(); flagsLineEdit->clear(); }else{ // Ignore others. } } void SeerEditorWidgetAssembly::handleSearchLineNumberLineEdit () { QString address = searchLineNumberLineEdit->text(); if (address == "") { showSearchBar(false); return; } searchLineNumberLineEdit->clear(); // Will emit the load signal, if 'address' is not already loaded. assemblyArea()->setAddress(address); assemblyArea()->setCurrentLine(address); } void SeerEditorWidgetAssembly::handleSearchTextLineEdit () { QString str = searchTextLineEdit->text(); matchesLabel->setText(""); if (str == "") { assemblyArea()->clearFindText(); showSearchBar(false); return; } int nMatches = assemblyArea()->findText(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags())); matchesLabel->setText(QString("(%1)").arg(nMatches)); } void SeerEditorWidgetAssembly::handleSearchDownToolButton () { QString str = searchTextLineEdit->text(); if (str == "") { return; } assemblyArea()->find(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags())); } void SeerEditorWidgetAssembly::handleSearchUpToolButton () { QString str = searchTextLineEdit->text(); if (str == "") { return; } assemblyArea()->find(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags()) | QTextDocument::FindBackward); } void SeerEditorWidgetAssembly::handleSearchCloseToolButton () { showSearchBar(false); } void SeerEditorWidgetAssembly::handleTextSearchShortcut () { if (isSearchBarShown() == true) { showSearchBar(false, ""); }else{ showSearchBar(true, "text"); } } void SeerEditorWidgetAssembly::handleLineSearchShortcut () { if (isSearchBarShown() == true) { showSearchBar(false, ""); }else{ showSearchBar(true, "line"); } } void SeerEditorWidgetAssembly::handleToggleBreakpointShortcut () { assemblyArea()->breakpointToggle(); } void SeerEditorWidgetAssembly::handleShowAddressColumn () { assemblyArea()->enableLineNumberArea(showAddressColumn()); } void SeerEditorWidgetAssembly::handleShowOffsetColumn () { assemblyArea()->enableOffsetArea(showOffsetColumn()); } void SeerEditorWidgetAssembly::handleShowOpcodeColumn () { assemblyArea()->enableOpcodeArea(showOpcodeColumn()); } void SeerEditorWidgetAssembly::handleShowSourceLines () { assemblyArea()->enableSourceLines(showSourceLines()); } void SeerEditorWidgetAssembly::handleEditPreferences () { // Bring up the register profile dialog. SeerAssemblyPreferenceDialog dlg(this); dlg.setRegiserNamePC(regiserNamePC()); dlg.setRegiserNameFLAGS(regiserNameFLAGS()); dlg.setRegiserNameSP(regiserNameSP()); dlg.setShowAssemblyAddress(showAddressColumn()); dlg.setShowAssemblyOffset(showOffsetColumn()); dlg.setShowAssemblyOpcode(showOpcodeColumn()); dlg.setShowAssemblySource(showSourceLines()); dlg.setConvertUppercase(convertUppercase()); if (dlg.exec()) { setRegiserNamePC(dlg.regiserNamePC()); setRegiserNameFLAGS(dlg.regiserNameFLAGS()); setRegiserNameSP(dlg.regiserNameSP()); setShowAddressColumn(dlg.showAssemblyAddress()); setShowOffsetColumn(dlg.showAssemblyOffset()); setShowOpcodeColumn(dlg.showAssemblyOpcode()); setShowSourceLines(dlg.showAssemblySource()); setConvertUppercase(dlg.convertUppercase()); reloadRegisters(); writeSettings(); } } void SeerEditorWidgetAssembly::handleEscapePressed () { showSearchBar(false, ""); } void SeerEditorWidgetAssembly::writeSettings () { QSettings settings; settings.beginGroup("assembly"); { settings.setValue("assemblyregisternamepc", regiserNamePC()); settings.setValue("assemblyregisternameflags", regiserNameFLAGS()); settings.setValue("assemblyregisternamesp", regiserNameSP()); settings.setValue("assemblyshowaddresscolumn", showAddressColumn()); settings.setValue("assemblyshowoffsetcolumn", showOffsetColumn()); settings.setValue("assemblyshowopcodecolumn", showOpcodeColumn()); settings.setValue("assemblyshowsourcelines", showSourceLines()); settings.setValue("assemblyconvertuppercase", convertUppercase()); } settings.endGroup(); } void SeerEditorWidgetAssembly::readSettings () { QSettings settings; settings.beginGroup("assembly"); { setRegiserNamePC (settings.value("assemblyregisternamepc", "$pc").toString()); setRegiserNameFLAGS (settings.value("assemblyregisternameflags", "$ps").toString()); setRegiserNameSP (settings.value("assemblyregisternamesp", "$sp").toString()); setShowAddressColumn (settings.value("assemblyshowaddresscolumn", true).toBool()); setShowOffsetColumn (settings.value("assemblyshowoffsetcolumn", false).toBool()); setShowOpcodeColumn (settings.value("assemblyshowopcodecolumn", false).toBool()); setShowSourceLines (settings.value("assemblyshowsourcelines", false).toBool()); setConvertUppercase (settings.value("assemblyconvertuppercase", false).toBool()); } settings.endGroup(); } epasveer-seer-97076f1/src/SeerEditorWidgetAssembly.h000066400000000000000000000563251526321767600224500ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerCppSourceHighlighter.h" #include "SeerKeySettings.h" #include "SeerPlainTextEdit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include class SeerEditorWidgetAssemblyLineNumberArea; class SeerEditorWidgetAssemblyOffsetArea; class SeerEditorWidgetAssemblyBreakPointArea; class SeerEditorWidgetAssemblyOpcodeArea; class SeerEditorWidgetAssemblyMiniMapArea; class SeerEditorWidgetAssemblyArea : public SeerPlainTextEdit { Q_OBJECT public: SeerEditorWidgetAssemblyArea (QWidget* parent = 0); void enableLineNumberArea (bool flag); bool lineNumberAreaEnabled () const; void enableOffsetArea (bool flag); bool offsetAreaEnabled () const; void enableBreakPointArea (bool flag); bool breakPointAreaEnabled () const; void enableOpcodeArea (bool flag); bool opcodeAreaEnabled () const; void enableMiniMapArea (bool flag); bool miniMapAreaEnabled () const; void enableSourceLines (bool flag); bool sourceLinesEnabled () const; void lineNumberAreaPaintEvent (QPaintEvent* event); int lineNumberAreaWidth (); void offsetAreaPaintEvent (QPaintEvent* event); int offsetAreaWidth (); void breakPointAreaPaintEvent (QPaintEvent* event); int breakPointAreaWidth (); void opcodeAreaPaintEvent (QPaintEvent* event); int opcodeAreaWidth (); void miniMapAreaPaintEvent (QPaintEvent* event); int miniMapAreaWidth (); void jumpToMiniMapY (int y); void setAddress (const QString& address, bool force=false); const QString& address () const; bool setCurrentLine (const QString& address); const QString currentLine () const; void scrollToLine (const QString& address); void clearCurrentLines (); int findText (const QString& text, QTextDocument::FindFlags flags); void clearFindText (); void clearBreakpoints (); void addBreakpoint (int number, const QString& address, bool enabled); bool hasBreakpointNumber (int number) const; bool hasBreakpointAddress (const QString& address) const; const QVector& breakpointNumbers () const; const QVector& breakpointAddresses () const; const QVector& breakpointEnableds () const; int breakpointAddressToNumber (const QString& address) const; bool breakpointAddressEnabled (const QString& address) const; void breakpointToggle (); void showContextMenu (QMouseEvent* event); void showContextMenu (QContextMenuEvent* event); void showContextMenu (const QPoint& pos, const QPointF& globalPos); void setQuickBreakpoint (QMouseEvent* event); void setQuickRunToAddress (QMouseEvent* event); void setHighlighterSettings (const SeerHighlighterSettings& settings); const SeerHighlighterSettings& highlighterSettings () const; void setHighlighterEnabled (bool flag); bool highlighterEnabled () const; QString sourceForLine (const QString& fullname, const QString& file, int line); void setEditorFont (const QFont& font); const QFont& editorFont () const; void setEditorTabSize (int spaces); int editorTabSize () const; void setConvertUppercase (bool flag); bool convertUppercase () const; signals: void insertBreakpoint (QString breakpoint); void insertPrintpoint (QString printpoint); void deleteBreakpoints (QString breakpoints); void enableBreakpoints (QString breakpoints); void disableBreakpoints (QString breakpoints); void refreshBreakpointsStackFrames (); void runToAddress (QString address); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); void requestAssembly (QString address); void requestSourceAndAssembly (QString address); void showSearchBar (bool flag); void highlighterSettingsChanged (); public slots: void handleText (const QString& text); void handleHighlighterSettingsChanged (); protected: void resizeEvent (QResizeEvent* event); bool viewportEvent (QEvent* event) override; void contextMenuEvent (QContextMenuEvent* event); private slots: void refreshExtraSelections (); void updateTextArea (); void updateMarginAreasWidth (int newBlockCount); void updateLineNumberArea (const QRect& rect, int dy); void updateOffsetArea (const QRect& rect, int dy); void updateBreakPointArea (const QRect& rect, int dy); void updateOpcodeArea (const QRect& rect, int dy); void updateMiniMapArea (const QRect& rect, int dy); void invalidateMiniMapCache (); void updateMiniMapGeometry (); private: bool _enableLineNumberArea; bool _enableOffsetArea; bool _enableBreakPointArea; bool _enableOpcodeArea; bool _enableMiniMapArea; bool _enableSourceLines; QVector _breakpointsNumbers; QVector _breakpointsAddresses; QVector _breakpointsEnableds; QList _findExtraSelections; QList _currentLinesExtraSelections; QList _sourceLinesExtraSelections; SeerEditorWidgetAssemblyLineNumberArea* _lineNumberArea; SeerEditorWidgetAssemblyOffsetArea* _offsetArea; SeerEditorWidgetAssemblyOpcodeArea* _opcodeArea; SeerEditorWidgetAssemblyBreakPointArea* _breakPointArea; SeerEditorWidgetAssemblyMiniMapArea* _miniMapArea; QPixmap _miniMapPixmap; bool _miniMapPixmapDirty; SeerHighlighterSettings _sourceHighlighterSettings; bool _sourceHighlighterEnabled; QString _currentAddress; QMap _addressLineMap; QMap _offsetLineMap; QMap _lineAddressMap; QMap _lineOffsetMap; QMap _lineOpcodeMap; // Text from asm_insns command. QString _asm_insns_text; // Source lines for assembly file. QStringList _fileLines; QString _fileFullname; QString _fileName; int _sourceTabSize; bool _convertUppercase; }; class SeerEditorWidgetAssemblyLineNumberArea : public QWidget { Q_OBJECT public: SeerEditorWidgetAssemblyLineNumberArea (SeerEditorWidgetAssemblyArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetAssemblyArea* _editorWidget; }; class SeerEditorWidgetAssemblyOffsetArea : public QWidget { Q_OBJECT public: SeerEditorWidgetAssemblyOffsetArea (SeerEditorWidgetAssemblyArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetAssemblyArea* _editorWidget; }; class SeerEditorWidgetAssemblyOpcodeArea : public QWidget { Q_OBJECT public: SeerEditorWidgetAssemblyOpcodeArea (SeerEditorWidgetAssemblyArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetAssemblyArea* _editorWidget; }; class SeerEditorWidgetAssemblyBreakPointArea : public QWidget { Q_OBJECT public: SeerEditorWidgetAssemblyBreakPointArea (SeerEditorWidgetAssemblyArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetAssemblyArea* _editorWidget; }; class SeerEditorWidgetAssemblyMiniMapArea : public QWidget { Q_OBJECT public: SeerEditorWidgetAssemblyMiniMapArea (SeerEditorWidgetAssemblyArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; void leaveEvent (QEvent* event) override; void wheelEvent (QWheelEvent* event) override; private: SeerEditorWidgetAssemblyArea* _editorWidget; bool _dragging; int _dragStartY; int _dragStartValue; SeerPlainTextMiniMapPreview* _preview; QTimer* _scrollTipTimer; }; #include "ui_SeerEditorWidgetAssembly.h" class SeerEditorWidgetAssembly : public QWidget, protected Ui::SeerEditorWidgetAssemblyForm { Q_OBJECT public: explicit SeerEditorWidgetAssembly (QWidget* parent = 0); ~SeerEditorWidgetAssembly (); SeerEditorWidgetAssemblyArea* assemblyArea (); const SeerEditorWidgetAssemblyArea* assemblyArea () const; bool isSearchBarShown () const; bool searchMatchCase () const; bool showAddressColumn () const; bool showOffsetColumn () const; bool showOpcodeColumn () const; bool showSourceLines () const; QString regiserNamePC () const; QString regiserNameFLAGS () const; QString regiserNameSP () const; bool convertUppercase () const; void setKeySettings (const SeerKeySettings& settings); const SeerKeySettings& keySettings () const; public slots: void reloadAssembly (); void reloadRegisters (); void showSearchBar (bool flag); void showSearchBar (bool flag, QString field); void setSearchMatchCase (bool flag); void setShowAddressColumn (bool flag); void setShowOffsetColumn (bool flag); void setShowOpcodeColumn (bool flag); void setShowSourceLines (bool flag); void setRegiserNamePC (const QString& name); void setRegiserNameFLAGS (const QString& name); void setRegiserNameSP (const QString& name); void setConvertUppercase (bool flag); void handleText (const QString& text); private slots: void handleSearchLineNumberLineEdit (); void handleSearchTextLineEdit (); void handleSearchDownToolButton (); void handleSearchUpToolButton (); void handleSearchCloseToolButton (); void handleTextSearchShortcut (); void handleLineSearchShortcut (); void handleToggleBreakpointShortcut (); void handleShowAddressColumn (); void handleShowOffsetColumn (); void handleShowOpcodeColumn (); void handleShowSourceLines (); void handleEditPreferences (); void handleEscapePressed (); signals: void evaluateVariableExpression (int expressionid, QString expression); protected: void writeSettings (); void readSettings (); private: int _pcId; int _spId; int _flagsId; SeerKeySettings _keySettings; QShortcut* _textSearchShortcut; QShortcut* _textSearchNextShortcut; QShortcut* _textSearchPrevShortcut; QShortcut* _lineSearchShortcut; QShortcut* _toggleBreakpointShortcut; QAction* _editPreferencesAction; QString _pcName; QString _spName; QString _flagsName; }; epasveer-seer-97076f1/src/SeerEditorWidgetAssembly.ui000066400000000000000000000260661526321767600226350ustar00rootroot00000000000000 SeerEditorWidgetAssemblyForm 0 0 788 574 SeerEditorWidgetAssemblyForm 0 100 PC 40 0 Program counter true Program counter FLAGS 20 0 Processor flags true Processor flags SP 20 0 Stack pointer true Stack pointer Preferences :/seer/resources/RelaxLightIcons/application-menu.svg:/seer/resources/RelaxLightIcons/application-menu.svg 0 0 0 0 50 0 Enter text to search for. Enter search text true Match Case Search for the next occurance. ... :/seer/resources/RelaxLightIcons/go-down.svg:/seer/resources/RelaxLightIcons/go-down.svg Search for the previous occurance. ... :/seer/resources/RelaxLightIcons/go-up.svg:/seer/resources/RelaxLightIcons/go-up.svg Qt::Vertical 50 0 Scroll to a specific 0xAddress, +Offset, or line#. Go to 0xAddress, +Offset, or line#. true Qt::Vertical Close the search bar. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Refresh the Assembly view. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Show assembly address. Address Show assembly offset. Offset Show assembly opcodes. Opcode Show original source code. Source Qt::Horizontal 40 20 SeerEditorWidgetAssemblyArea QWidget
SeerEditorWidgetAssembly.h
1
QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
searchTextLineEdit matchCaseCheckBox searchDownToolButton searchUpToolButton searchLineNumberLineEdit searchCloseToolButton refreshToolButton showAddressCheckBox showOffsetCheckBox showOpcodeCheckBox showSourceCheckBox
epasveer-seer-97076f1/src/SeerEditorWidgetAssemblyAreas.cpp000066400000000000000000002006761526321767600237570ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorWidgetAssembly.h" #include "SeerPlainTextEdit.h" #include "SeerBreakpointCreateDialog.h" #include "SeerPrintpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // // Assembly Area // SeerEditorWidgetAssemblyArea::SeerEditorWidgetAssemblyArea(QWidget* parent) : SeerPlainTextEdit(parent) { _enableLineNumberArea = false; _enableOffsetArea = false; _enableOpcodeArea = false; _enableBreakPointArea = false; _enableMiniMapArea = false; _enableSourceLines = false; _sourceTabSize = 4; _convertUppercase = false; _miniMapArea = 0; _miniMapPixmapDirty = true; _addressLineMap.clear(); _offsetLineMap.clear(); _lineAddressMap.clear(); _lineOffsetMap.clear(); _lineOpcodeMap.clear(); QFont font("monospace"); font.setStyleHint(QFont::Monospace); setFont(font); setReadOnly(true); setTextInteractionFlags(textInteractionFlags() | Qt::TextSelectableByKeyboard); setLineWrapMode(QPlainTextEdit::NoWrap); _lineNumberArea = new SeerEditorWidgetAssemblyLineNumberArea(this); _offsetArea = new SeerEditorWidgetAssemblyOffsetArea(this); _breakPointArea = new SeerEditorWidgetAssemblyBreakPointArea(this); _opcodeArea = new SeerEditorWidgetAssemblyOpcodeArea(this); _miniMapArea = new SeerEditorWidgetAssemblyMiniMapArea(this); enableLineNumberArea(true); enableOffsetArea(true); enableOpcodeArea(true); enableBreakPointArea(true); enableMiniMapArea(false); enableSourceLines(true); setConvertUppercase(false); QObject::connect(this, &SeerEditorWidgetAssemblyArea::blockCountChanged, this, &SeerEditorWidgetAssemblyArea::updateMarginAreasWidth); QObject::connect(this, &SeerEditorWidgetAssemblyArea::blockCountChanged, this, &SeerEditorWidgetAssemblyArea::invalidateMiniMapCache); QObject::connect(this, &SeerEditorWidgetAssemblyArea::updateRequest, this, &SeerEditorWidgetAssemblyArea::updateLineNumberArea); QObject::connect(this, &SeerEditorWidgetAssemblyArea::updateRequest, this, &SeerEditorWidgetAssemblyArea::updateOffsetArea); QObject::connect(this, &SeerEditorWidgetAssemblyArea::updateRequest, this, &SeerEditorWidgetAssemblyArea::updateOpcodeArea); QObject::connect(this, &SeerEditorWidgetAssemblyArea::updateRequest, this, &SeerEditorWidgetAssemblyArea::updateBreakPointArea); QObject::connect(this, &SeerEditorWidgetAssemblyArea::updateRequest, this, &SeerEditorWidgetAssemblyArea::updateMiniMapArea); QObject::connect(this, &SeerEditorWidgetAssemblyArea::highlighterSettingsChanged, this, &SeerEditorWidgetAssemblyArea::handleHighlighterSettingsChanged); setCurrentLine(""); updateMarginAreasWidth(0); // Forward the scroll events in the various areas to the text edit. SeerPlainTextWheelEventForwarder* lineNumberAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); SeerPlainTextWheelEventForwarder* offsetAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); SeerPlainTextWheelEventForwarder* opcodeAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); SeerPlainTextWheelEventForwarder* breakPointAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); SeerPlainTextWheelEventForwarder* miniMapAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); _lineNumberArea->installEventFilter(lineNumberAreaWheelForwarder); _offsetArea->installEventFilter(offsetAreaWheelForwarder); _breakPointArea->installEventFilter(breakPointAreaWheelForwarder); _opcodeArea->installEventFilter(opcodeAreaWheelForwarder); _miniMapArea->installEventFilter(miniMapAreaWheelForwarder); // Calling close() will clear the text document. close(); } void SeerEditorWidgetAssemblyArea::enableLineNumberArea (bool flag) { _enableLineNumberArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetAssemblyArea::lineNumberAreaEnabled () const { return _enableLineNumberArea; } void SeerEditorWidgetAssemblyArea::enableOffsetArea (bool flag) { _enableOffsetArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetAssemblyArea::offsetAreaEnabled () const { return _enableOffsetArea; } void SeerEditorWidgetAssemblyArea::enableBreakPointArea (bool flag) { _enableBreakPointArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetAssemblyArea::breakPointAreaEnabled () const { return _enableBreakPointArea; } void SeerEditorWidgetAssemblyArea::enableOpcodeArea (bool flag) { _enableOpcodeArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetAssemblyArea::opcodeAreaEnabled () const { return _enableOpcodeArea; } void SeerEditorWidgetAssemblyArea::enableMiniMapArea (bool flag) { _enableMiniMapArea = flag; setVerticalScrollBarPolicy(flag ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded); invalidateMiniMapCache(); updateMarginAreasWidth(0); } bool SeerEditorWidgetAssemblyArea::miniMapAreaEnabled () const { return _enableMiniMapArea; } void SeerEditorWidgetAssemblyArea::enableSourceLines (bool flag) { _enableSourceLines = flag; QString addr = address(); setAddress(addr, true); } bool SeerEditorWidgetAssemblyArea::sourceLinesEnabled () const { return _enableSourceLines; } void SeerEditorWidgetAssemblyArea::updateTextArea () { // // ^done,asm_insns=[ // src_and_asm_line={ // line="72", // file="helloarray.cpp", // fullname="/home/erniep/Development/Peak/src/seer/tests/helloarray/helloarray.cpp", // line_asm_insn=[ // {address="0x000000000040093c",func-name="main()",offset="362",opcodes="bf a9 0a 40 00",inst="mov $0x400aa9,%edi"}, // {address="0x0000000000400941",func-name="main()",offset="367",opcodes="e8 3a fd ff ff",inst="call 0x400680 "} // ] // }, // src_and_asm_line={ // line="73", // file="helloarray.cpp", // fullname="/home/erniep/Development/Peak/src/seer/tests/helloarray/helloarray.cpp", // line_asm_insn=[ // ] // }, // QApplication::setOverrideCursor(Qt::BusyCursor); // Clear the existing document. document()->clear(); // Clear mappings. _addressLineMap.clear(); _offsetLineMap.clear(); _lineAddressMap.clear(); _lineOffsetMap.clear(); _lineOpcodeMap.clear(); // Clear 'source line' selections. _sourceLinesExtraSelections.clear(); // Get the list of source and assembly lines. QString asm_insns_text = Seer::parseFirst(_asm_insns_text, "asm_insns=", '[', ']', false); QStringList src_and_asm_list = Seer::parse(asm_insns_text, "src_and_asm_line=", '{', '}', false); QStringList asm_list = Seer::parse(asm_insns_text, "", '{', '}', false); if (src_and_asm_list.size() > 0) { //qDebug() << "src_and_asm_text mode."; // Loop through the asm list and print each line. int lineno = 1; for ( const auto& src_and_asm_text : src_and_asm_list ) { // Get the strings, with padding. QString line_text = Seer::parseFirst(src_and_asm_text, "line=", '"', '"', false); QString file_text = Seer::parseFirst(src_and_asm_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(src_and_asm_text, "fullname=", '"', '"', false); // Print source line? if (sourceLinesEnabled() == true) { // Get source for 'line' QString sourceLine = sourceForLine(fullname_text, file_text, line_text.toInt()); sourceLine = Seer::expandTabs(sourceLine, editorTabSize(), false); // Expand tabs. sourceLine = sourceLine.simplified(); // Remove blank spaces at front and end of line. // Write source line to the document. if (convertUppercase()) { appendPlainText(sourceLine.toUpper()); }else{ appendPlainText(sourceLine); } // Highlight it. QTextCharFormat sourceLinesFormat = highlighterSettings().get("Text"); QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); QTextEdit::ExtraSelection selection; selection.format.setForeground(sourceLinesFormat.foreground()); selection.format.setBackground(sourceLinesFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); _sourceLinesExtraSelections.append(selection); lineno++; } // Get the list of assembly lines. QString asm_insns_text = Seer::parseFirst(src_and_asm_text, "line_asm_insn=", '[', ']', false); QStringList asm_list = Seer::parse(asm_insns_text, "", '{', '}', false); for ( const auto& asm_text : asm_list ) { // Get the strings, with padding. QString address_text = Seer::parseFirst(asm_text, "address=", '"', '"', false); QString funcname_text = Seer::parseFirst(asm_text, "func-name=", '"', '"', false); QString offset_num = Seer::parseFirst(asm_text, "offset=", '"', '"', false); QString opcodes_text = Seer::parseFirst(asm_text, "opcodes=", '"', '"', false); QString inst_text = Seer::parseFirst(asm_text, "inst=", '"', '"', false); inst_text = Seer::expandTabs(inst_text, editorTabSize(), true); // Expand tabs. // Write assembly line to the document. if (convertUppercase()) { appendPlainText(inst_text.toUpper()); }else{ appendPlainText(inst_text); } // Highlight it. QTextCharFormat sourceLinesFormat = highlighterSettings().get("Assembly Text"); QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); QTextEdit::ExtraSelection selection; selection.format.setForeground(sourceLinesFormat.foreground()); selection.format.setBackground(sourceLinesFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); _sourceLinesExtraSelections.append(selection); // Add to maps _addressLineMap.insert(address_text.toULongLong(0,0), lineno); _offsetLineMap.insert(offset_num.toULongLong(0,0), lineno); _lineAddressMap.insert(lineno, address_text); _lineOffsetMap.insert(lineno, offset_num.toULongLong(0,0)); _lineOpcodeMap.insert(lineno, opcodes_text); lineno++; } } }else if (asm_list.size() > 0) { //qDebug() << "asm_text mode."; // Loop through the asm list and print each line. int lineno = 1; for ( const auto& asm_text : asm_list ) { // Get the strings, with padding. QString address_text = Seer::parseFirst(asm_text, "address=", '"', '"', false); QString offset_num = Seer::parseFirst(asm_text, "offset=", '"', '"', false); QString opcodes_text = Seer::parseFirst(asm_text, "opcodes=", '"', '"', false); QString inst_text = Seer::parseFirst(asm_text, "inst=", '"', '"', false); inst_text = Seer::expandTabs(inst_text, editorTabSize(), true); // Expand tabs. // Write assembly line to the document. if (convertUppercase()) { appendPlainText(QString(" ") + inst_text.toUpper()); }else{ appendPlainText(QString(" ") + inst_text); } // Highlight it. QTextCharFormat sourceLinesFormat = highlighterSettings().get("Assembly Text"); QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); QTextEdit::ExtraSelection selection; selection.format.setForeground(sourceLinesFormat.foreground()); selection.format.setBackground(sourceLinesFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); _sourceLinesExtraSelections.append(selection); // Add to maps _addressLineMap.insert(address_text.toULongLong(0,0), lineno); _offsetLineMap.insert(offset_num.toULongLong(0,0), lineno); _lineAddressMap.insert(lineno, address_text); _lineOffsetMap.insert(lineno, offset_num.toULongLong(0,0)); _lineOpcodeMap.insert(lineno, opcodes_text); lineno++; } }else{ qDebug() << "src_and_asm_text and asm_text are both empty."; } // Refresh all the extra selections. refreshExtraSelections(); // Move to the start of the document as a default. moveCursor(QTextCursor::Start); // Move to the line that has our address. setCurrentLine(_currentAddress); // Set the cursor back. QApplication::restoreOverrideCursor(); invalidateMiniMapCache(); } void SeerEditorWidgetAssemblyArea::updateMarginAreasWidth (int newBlockCount) { Q_UNUSED(newBlockCount); int leftMarginWidth = lineNumberAreaWidth() + offsetAreaWidth() + breakPointAreaWidth() + opcodeAreaWidth(); int rightMarginWidth = miniMapAreaWidth(); setViewportMargins(leftMarginWidth, 0, rightMarginWidth, 0); } int SeerEditorWidgetAssemblyArea::lineNumberAreaWidth () { if (lineNumberAreaEnabled() == false) { return 0; } int chars = 1; QMap::iterator b = _lineAddressMap.begin(); QMap::iterator e = _lineAddressMap.end(); while (b != e) { chars = qMax(chars, b->length()); b++; } int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * chars; return space; } int SeerEditorWidgetAssemblyArea::miniMapAreaWidth () { if (miniMapAreaEnabled() == false) { return 0; } return 60; } int SeerEditorWidgetAssemblyArea::offsetAreaWidth () { if (offsetAreaEnabled() == false) { return 0; } qulonglong offset = 0; QMap::iterator b = _lineOffsetMap.begin(); QMap::iterator e = _lineOffsetMap.end(); while (b != e) { offset = qMax(offset, b.value()); b++; } QString tmp = QString("<+%1>").arg(offset); int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * tmp.length(); return space; } int SeerEditorWidgetAssemblyArea::opcodeAreaWidth () { if (opcodeAreaEnabled() == false) { return 0; } int chars = 1; QMap::iterator b = _lineOpcodeMap.begin(); QMap::iterator e = _lineOpcodeMap.end(); while (b != e) { chars = qMax(chars, b->length()); b++; } int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * chars; return space; } int SeerEditorWidgetAssemblyArea::breakPointAreaWidth () { if (breakPointAreaEnabled() == false) { return 0; } int space = 3 + 20; return space; } void SeerEditorWidgetAssemblyArea::updateLineNumberArea (const QRect& rect, int dy) { if (lineNumberAreaEnabled() == false) { return; } if (dy) { _lineNumberArea->scroll(0, dy); }else{ _lineNumberArea->update(0, rect.y(), _lineNumberArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetAssemblyArea::updateOffsetArea (const QRect& rect, int dy) { if (offsetAreaEnabled() == false) { return; } if (dy) { _offsetArea->scroll(0, dy); }else{ _offsetArea->update(0, rect.y(), _offsetArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetAssemblyArea::updateOpcodeArea (const QRect& rect, int dy) { if (opcodeAreaEnabled() == false) { return; } if (dy) { _opcodeArea->scroll(0, dy); }else{ _opcodeArea->update(0, rect.y(), _opcodeArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetAssemblyArea::updateBreakPointArea (const QRect& rect, int dy) { if (breakPointAreaEnabled() == false) { return; } if (dy) { _breakPointArea->scroll(0, dy); }else{ _breakPointArea->update(0, rect.y(), _breakPointArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetAssemblyArea::updateMiniMapArea (const QRect& rect, int dy) { Q_UNUSED(rect); Q_UNUSED(dy); if (miniMapAreaEnabled() == false) { return; } // The mini-map's cached content is a whole-document rendering, not a // viewport-following strip, so there's nothing to scroll - just repaint // the (cheap) viewport-position overlay on top of the cached pixmap. _miniMapArea->update(); } void SeerEditorWidgetAssemblyArea::invalidateMiniMapCache () { _miniMapPixmapDirty = true; if (_miniMapArea) { _miniMapArea->update(); } } void SeerEditorWidgetAssemblyArea::lineNumberAreaPaintEvent (QPaintEvent* event) { if (lineNumberAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Margin"); QPainter painter(_lineNumberArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString address; if (_lineAddressMap.contains(blockNumber+1)) { if (convertUppercase()) { address = _lineAddressMap[blockNumber+1].toUpper(); }else{ address = _lineAddressMap[blockNumber+1]; } } painter.drawText(0, top, _lineNumberArea->width(), fontMetrics().height(), Qt::AlignLeft, address); } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetAssemblyArea::offsetAreaPaintEvent (QPaintEvent* event) { if (offsetAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Margin"); QPainter painter(_offsetArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString offset; if (_lineOffsetMap.contains(blockNumber+1)) { offset = QString("<+%1>").arg(_lineOffsetMap[blockNumber+1]); } painter.drawText(0, top, _offsetArea->width(), fontMetrics().height(), Qt::AlignRight, offset); } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetAssemblyArea::breakPointAreaPaintEvent (QPaintEvent* event) { if (breakPointAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Margin"); QPainter painter(_breakPointArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString address = _lineAddressMap[blockNumber+1]; if (address != "" && hasBreakpointAddress(address) == true) { if (breakpointAddressEnabled(address)) { QRect rect(_breakPointArea->width() - 20, top, fontMetrics().height(), fontMetrics().height()); QPainterPath path; path.addEllipse(rect); QPointF bias = QPointF(rect.width() * .25 * 1.0, rect.height() * .25 * -1.0); QRadialGradient gradient(rect.center(), rect.width() / 2.0, rect.center() + bias); gradient.setColorAt(0.0, QColor(Qt::white)); gradient.setColorAt(0.9, QColor(Qt::red)); gradient.setColorAt(1.0, QColor(Qt::transparent)); painter.fillPath(path,QBrush(gradient)); }else{ QRect rect(_breakPointArea->width() - 20, top, fontMetrics().height(), fontMetrics().height()); QPainterPath path; path.addEllipse(rect); QPointF bias = QPointF(rect.width() * .25 * 1.0, rect.height() * .25 * -1.0); QRadialGradient gradient(rect.center(), rect.width() / 2.0, rect.center() + bias); gradient.setColorAt(0.0, QColor(Qt::white)); gradient.setColorAt(0.9, QColor(Qt::darkGray)); gradient.setColorAt(1.0, Qt::transparent); painter.fillPath(path,QBrush(gradient)); } } } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetAssemblyArea::opcodeAreaPaintEvent (QPaintEvent* event) { if (opcodeAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Margin"); QPainter painter(_opcodeArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString opcode; if (_lineOpcodeMap.contains(blockNumber+1)) { if (convertUppercase()) { opcode = " " + _lineOpcodeMap[blockNumber+1].toUpper(); }else{ opcode = " " + _lineOpcodeMap[blockNumber+1]; } } painter.drawText(0, top, _opcodeArea->width(), fontMetrics().height(), Qt::AlignLeft, opcode); } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetAssemblyArea::miniMapAreaPaintEvent (QPaintEvent* event) { Q_UNUSED(event); if (miniMapAreaEnabled() == false) { return; } // The mini-map's background is the gutter's "Margin" color. Characters // use the editor's text color (or their syntax highlighter color). QTextCharFormat marginFormat = highlighterSettings().get("Margin"); QTextCharFormat textFormat = highlighterSettings().get("Text"); // Like Kate, the mini-map always shows the whole document. Rebuild the // cached pixmap if the document, theme, or size changed. // // Characters are drawn as Kate-style marks in the uniform text color - the real // editor colors whole lines differently (source vs. assembly) via // _sourceLinesExtraSelections, but at mini-map scale mixing those line // colors in just looks like wrong/inconsistent colors rather than useful // information, so the mini-map ignores it. if (_miniMapPixmapDirty || _miniMapPixmap.size() != _miniMapArea->size()) { _miniMapPixmap = QPixmap(_miniMapArea->size()); if (_miniMapPixmap.isNull() == false) { SeerPlainTextMiniMap::render(_miniMapPixmap, document(), marginFormat.background().color(), textFormat.foreground().color()); } _miniMapPixmapDirty = false; } QPainter painter(_miniMapArea); painter.drawPixmap(0, 0, _miniMapPixmap); // Overlay: highlight the portion of the document currently visible in the editor. QRectF overlay = SeerPlainTextMiniMap::overlayRect(this, _miniMapArea->width(), _miniMapArea->height()); QTextCharFormat currentLineFormat = highlighterSettings().get("Current Line"); QColor overlayColor = currentLineFormat.background().color(); overlayColor.setAlpha(90); painter.fillRect(overlay, overlayColor); painter.setPen(currentLineFormat.background().color()); painter.drawRect(overlay.adjusted(0, 0, -1, -1)); } void SeerEditorWidgetAssemblyArea::resizeEvent (QResizeEvent* e) { QPlainTextEdit::resizeEvent(e); QRect cr = contentsRect(); int leftbias = 0; if (lineNumberAreaEnabled()) { _lineNumberArea->setGeometry (QRect(cr.left() + leftbias, cr.top(), lineNumberAreaWidth(), cr.height())); leftbias += lineNumberAreaWidth(); } if (offsetAreaEnabled()) { _offsetArea->setGeometry (QRect(cr.left() + leftbias, cr.top(), offsetAreaWidth(), cr.height())); leftbias += offsetAreaWidth(); } if (opcodeAreaEnabled()) { _opcodeArea->setGeometry (QRect(cr.left() + leftbias, cr.top(), opcodeAreaWidth(), cr.height())); leftbias += opcodeAreaWidth(); } if (breakPointAreaEnabled()) { _breakPointArea->setGeometry (QRect(cr.left() + leftbias, cr.top(), breakPointAreaWidth(), cr.height())); leftbias += breakPointAreaWidth(); } updateMiniMapGeometry(); } bool SeerEditorWidgetAssemblyArea::viewportEvent (QEvent* event) { // The viewport can change size without the editor changing size, when the // horizontal scrollbar appears or disappears. if (event->type() == QEvent::Resize) { updateMiniMapGeometry(); } return SeerPlainTextEdit::viewportEvent(event); } void SeerEditorWidgetAssemblyArea::updateMiniMapGeometry () { if (miniMapAreaEnabled() == false) { return; } // Match the viewport's height, so the mini-map doesn't extend behind the // horizontal scrollbar. QRect cr = contentsRect(); QRect vr = viewport()->geometry(); QRect mr = QRect(cr.right() - miniMapAreaWidth() + 1, vr.top(), miniMapAreaWidth(), vr.height()); if (_miniMapArea->geometry() == mr) { return; } _miniMapArea->setGeometry(mr); // The mini-map's height changed, so the cached pixmap's vertical scale is stale. invalidateMiniMapCache(); } void SeerEditorWidgetAssemblyArea::contextMenuEvent (QContextMenuEvent* event) { showContextMenu(event); } void SeerEditorWidgetAssemblyArea::refreshExtraSelections () { // // Merge all the extra selections into one. // // The current line(s) // The searched text. // // Create an empty list of selections. QList extraSelections; // Append the 'source lines' extra selections. extraSelections.append(_sourceLinesExtraSelections); // Append the 'current lines' extra selections. extraSelections.append(_currentLinesExtraSelections); // Append the 'searched text' extra selections. extraSelections.append(_findExtraSelections); // Give the editor the list of selections. // This will remove the old selections and select the new ones. setExtraSelections(extraSelections); } void SeerEditorWidgetAssemblyArea::setAddress (const QString& address, bool force) { // Emit the signal to load the assembly for address 'address' if // it's not already loaded. if (_addressLineMap.contains(address.toULongLong(0,0)) == false || force == true) { // Hack to keep track of address when the assembly hasn't been loaded yet. _currentAddress = address; emit requestSourceAndAssembly(address); } } const QString& SeerEditorWidgetAssemblyArea::address () const { return _currentAddress; } bool SeerEditorWidgetAssemblyArea::setCurrentLine (const QString& address) { // Clear current line selections. _currentLinesExtraSelections.clear(); // See scrollToLine(). // // Initial lineno. bool ok = false; int lineno = 0; // Try parsing as an address. if (ok == false && address.startsWith("0x") == true) { qulonglong addr = address.toULongLong(&ok, 0); // Try it as an '0x.....'. if (ok) { if (_addressLineMap.contains(addr)) { lineno = _addressLineMap[addr]; }else{ ok = false; } } } // Try parsing as an offset. if (ok == false && address.startsWith("+") == true) { qulonglong offset = address.toULongLong(&ok, 0); // Try it as an '+.....'. if (ok) { if (_offsetLineMap.contains(offset)) { lineno = _offsetLineMap[offset]; }else{ ok = false; } } } // Try parsing as an integer. if (ok == false && address.startsWith("0x") == false && address.startsWith("+") == false) { lineno = address.toInt(&ok, 10); // Try it as an 'int'. lineno == 0 on error. } // Stop if no valid lineno. if (ok == false || lineno < 1) { //qDebug() << "address is not in current assembly: '" << address << "'"; return false; } // Highlight if a valid line number is selected. QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); _currentLinesExtraSelections.clear(); QTextCharFormat currentLineFormat = highlighterSettings().get("Current Line"); QTextEdit::ExtraSelection selection; selection.format.setForeground(currentLineFormat.foreground()); selection.format.setBackground(currentLineFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); _currentLinesExtraSelections.append(selection); // Scroll to the line. scrollToLine(address); // Refresh all the extra selections. refreshExtraSelections(); return true; } const QString SeerEditorWidgetAssemblyArea::currentLine () const { // Get current lineno. int lineno = textCursor().blockNumber() + 1; QString address = _lineAddressMap[lineno]; return address; } void SeerEditorWidgetAssemblyArea::scrollToLine (const QString& address) { // Just return. if (address == "") { return; } // // 'address' can be one of these forms: // // 0xdeadbeef An address // +1000 An offset // 10 A linenumber // // Test for which one and convert it to a linenumber using the maps: // // _addressLineMap // _offsetLineMap // // Or just go to the line# // // Initial lineno. bool ok = false; int lineno = 0; // Try parsing as an address. if (ok == false && address.startsWith("0x") == true) { qulonglong addr = address.toULongLong(&ok, 0); // Try it as an '0x.....'. if (ok) { if (_addressLineMap.contains(addr)) { lineno = _addressLineMap[addr]; }else{ ok = false; } } } // Try parsing as an offset. if (ok == false && address.startsWith("+") == true) { qulonglong offset = address.toULongLong(&ok, 0); // Try it as an '+.....'. if (ok) { if (_offsetLineMap.contains(offset)) { lineno = _offsetLineMap[offset]; }else{ ok = false; } } } // Try parsing as an integer. if (ok == false && address.startsWith("0x") == false && address.startsWith("+") == false) { lineno = address.toInt(&ok, 10); // Try it as an 'int'. lineno == 0 on error. } // 'address' is meaningless. Just return. if (ok == false) { if (_currentAddress == "") { // Hack when the assembly hasn't been loaded yet. QMessageBox::warning(this, "Warning.", "Address/offset '" + address + "' not found."); } return; } // Scroll to the first line if we went before it. if (lineno < 1) { lineno = 1; } // Scroll to the last line if we went past it. if (lineno > document()->blockCount()) { lineno = document()->blockCount(); } QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); centerCursor(); } void SeerEditorWidgetAssemblyArea::jumpToMiniMapY (int y) { if (miniMapAreaEnabled() == false) { return; } int lineno = SeerPlainTextMiniMap::lineAt(this, _miniMapArea->height(), y) + 1; // Reuse the existing address/offset/linenumber scroll-to entry point - // a plain integer string is parsed as a line number (see above). scrollToLine(QString::number(lineno)); } void SeerEditorWidgetAssemblyArea::clearCurrentLines () { _currentLinesExtraSelections.clear(); refreshExtraSelections(); } int SeerEditorWidgetAssemblyArea::findText (const QString& text, QTextDocument::FindFlags flags) { _findExtraSelections.clear(); if (document()) { QTextCharFormat matchFormat = highlighterSettings().get("Match"); // Build a list of highlights for all matches. QTextCursor cursor(document()); cursor = document()->find(text, cursor, flags); while (cursor.isNull() == false) { QTextEdit::ExtraSelection extra; extra.format = matchFormat; extra.cursor = cursor; _findExtraSelections.append(extra); cursor = document()->find(text, cursor, flags); } // Move to the next match after out current position. find(text, flags); } refreshExtraSelections(); return _findExtraSelections.size(); } void SeerEditorWidgetAssemblyArea::clearFindText () { _findExtraSelections.clear(); refreshExtraSelections(); } void SeerEditorWidgetAssemblyArea::clearBreakpoints () { _breakpointsNumbers.clear(); _breakpointsAddresses.clear(); _breakpointsEnableds.clear(); repaint(); } void SeerEditorWidgetAssemblyArea::addBreakpoint (int number, const QString& address, bool enabled) { _breakpointsNumbers.push_back(number); _breakpointsAddresses.push_back(address); _breakpointsEnableds.push_back(enabled); repaint(); } bool SeerEditorWidgetAssemblyArea::hasBreakpointNumber (int number) const { return _breakpointsNumbers.contains(number); } bool SeerEditorWidgetAssemblyArea::hasBreakpointAddress (const QString& address) const { return _breakpointsAddresses.contains(address); } const QVector& SeerEditorWidgetAssemblyArea::breakpointNumbers () const { return _breakpointsNumbers; } const QVector& SeerEditorWidgetAssemblyArea::breakpointAddresses () const { return _breakpointsAddresses; } const QVector& SeerEditorWidgetAssemblyArea::breakpointEnableds () const { return _breakpointsEnableds; } int SeerEditorWidgetAssemblyArea::breakpointAddressToNumber (const QString& address) const { // Map address to breakpoint number. int i = _breakpointsAddresses.indexOf(address); if (i < 0) { return 0; } return _breakpointsNumbers[i]; } bool SeerEditorWidgetAssemblyArea::breakpointAddressEnabled (const QString& address) const { // Look for the address and get its index. int i = _breakpointsAddresses.indexOf(address); // Not found, return false. if (i < 0) { return false; } // Otherwise, return the proper status. return _breakpointsEnableds[i]; } void SeerEditorWidgetAssemblyArea::breakpointToggle () { // Get current lineno. int lineno = textCursor().blockNumber() + 1; QString address = _lineAddressMap[lineno]; if (address == "") { return; } // If there is a breakpoint on the line, toggle it. if (hasBreakpointAddress(address)) { // Toggle the breakpoint. // Enable if disabled. Disable if enabled. if (breakpointAddressEnabled(address) == false) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); }else{ // Emit the disable breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); } // Otherwise, do a quick create of a new breakpoint. }else{ emit insertBreakpoint(QString("-f *%1").arg(address)); } } void SeerEditorWidgetAssemblyArea::showContextMenu (QMouseEvent* event) { #if QT_VERSION >= 0x060000 showContextMenu(event->pos(), event->globalPosition()); #else showContextMenu(event->pos(), event->globalPos()); #endif } void SeerEditorWidgetAssemblyArea::showContextMenu (QContextMenuEvent* event) { showContextMenu(event->pos(), event->globalPos()); } void SeerEditorWidgetAssemblyArea::showContextMenu (const QPoint& pos, const QPointF& globalPos) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(pos); int lineno = cursor.blockNumber()+1; QString address = _lineAddressMap[lineno]; // Create the menu actions. QAction* runToAddressAction; QAction* createBreakpointAction; QAction* deleteAction; QAction* enableAction; QAction* disableAction; QAction* addMemoryAddressVisualizerAction; QAction* addArrayAddressVisualizerAction; QAction* addMatrixAddressVisualizerAction; QAction* addStructAddressVisualizerAction; // Enable/disable them depending if the breakpoint already exists. if (hasBreakpointAddress(address) == true) { int breakno = breakpointAddressToNumber(address); runToAddressAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg"), QString("Run to address %1").arg(address), this); createBreakpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create breakpoint on address %1").arg(address), this); deleteAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/edit-delete.svg"), QString("Delete breakpoint %1 on address %2").arg(breakno).arg(address), this); enableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-add.svg"), QString("Enable breakpoint %1 on address %2").arg(breakno).arg(address), this); disableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg"), QString("Disable breakpoint %1 on address %2").arg(breakno).arg(address), this); runToAddressAction->setEnabled(true); createBreakpointAction->setEnabled(false); deleteAction->setEnabled(true); enableAction->setEnabled(true); disableAction->setEnabled(true); }else{ runToAddressAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg"), QString("Run to address %1").arg(address), this); createBreakpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create breakpoint on address %1").arg(address), this); deleteAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/edit-delete.svg"), QString("Delete breakpoint on address %1").arg(address), this); enableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-add.svg"), QString("Enable breakpoint on address %1").arg(address), this); disableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg"), QString("Disable breakpoint on address %1").arg(address), this); runToAddressAction->setEnabled(true); createBreakpointAction->setEnabled(true); deleteAction->setEnabled(false); enableAction->setEnabled(false); disableAction->setEnabled(false); } addMemoryAddressVisualizerAction = new QAction(QString("\"%1\"").arg(textCursor().selectedText())); addArrayAddressVisualizerAction = new QAction(QString("\"%1\"").arg(textCursor().selectedText())); addMatrixAddressVisualizerAction = new QAction(QString("\"%1\"").arg(textCursor().selectedText())); addStructAddressVisualizerAction = new QAction(QString("\"%1\"").arg(textCursor().selectedText())); QMenu menu("Breakpoints", this); menu.setTitle("Breakpoints"); menu.addAction(runToAddressAction); menu.addAction(createBreakpointAction); menu.addAction(deleteAction); menu.addAction(enableAction); menu.addAction(disableAction); QMenu memoryVisualizerMenu("Add address to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryAddressVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add address to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayAddressVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add address to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixAddressVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add address to a Struct Visualizer"); structVisualizerMenu.addAction(addStructAddressVisualizerAction); menu.addMenu(&structVisualizerMenu); // Enable/disable items based on something being selected or not. if (textCursor().selectedText() == "") { addMemoryAddressVisualizerAction->setEnabled(false); addArrayAddressVisualizerAction->setEnabled(false); addMatrixAddressVisualizerAction->setEnabled(false); addStructAddressVisualizerAction->setEnabled(false); }else{ addMemoryAddressVisualizerAction->setEnabled(true); addArrayAddressVisualizerAction->setEnabled(true); addMatrixAddressVisualizerAction->setEnabled(true); addStructAddressVisualizerAction->setEnabled(true); } // Launch the menu. Get the response. QAction* action = menu.exec(globalPos.toPoint()); // Do nothing. if (action == 0) { return; } // Handle running to an address. if (action == runToAddressAction) { // Emit the runToLine signal. emit runToAddress(address); return; } // Handle creating a new breakpoint. if (action == createBreakpointAction) { SeerBreakpointCreateDialog dlg(this); dlg.setAddress(address); int ret = dlg.exec(); if (ret == 0) { return; } // Emit the create breakpoint signal. emit insertBreakpoint(dlg.breakpointText()); return; } // Handle deleting a breakpoint. if (action == deleteAction) { // Emit the delete breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); return; } // Handle enabling a breakpoint. if (action == enableAction) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); return; } // Handle disabling a breakpoint. if (action == disableAction) { // Emit the disable breakpoint signal. emit disableBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); return; } // Handle adding memory to visualize. if (action == addMemoryAddressVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMemoryVisualizer(textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addArrayAddressVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addArrayVisualizer(textCursor().selectedText()); } return; } // Handle adding matrix to visualize. if (action == addMatrixAddressVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMatrixVisualizer(textCursor().selectedText()); } return; } // Handle adding struct to visualize. if (action == addStructAddressVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addStructVisualizer(textCursor().selectedText()); } return; } } void SeerEditorWidgetAssemblyArea::setQuickBreakpoint (QMouseEvent* event) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(event->pos()); int lineno = cursor.blockNumber()+1; QString address = _lineAddressMap[lineno]; // If there is a breakpoint on the line, toggle it. if (hasBreakpointAddress(address)) { // Toggle the breakpoint. // Enable if disabled. Disable if enabled. if (breakpointAddressEnabled(address) == false) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); }else{ // Emit the disable breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointAddressToNumber(address))); } // Otherwise, do a quick create of a new breakpoint. }else{ emit insertBreakpoint(QString("-f *%1").arg(address)); } } void SeerEditorWidgetAssemblyArea::setQuickRunToAddress (QMouseEvent* event) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(event->pos()); int lineno = cursor.blockNumber()+1; QString address = _lineAddressMap[lineno]; //qDebug() << "runToAddress" << address; // Emit the runToAddress signal. if (address != "") { emit runToAddress(address); } return; } void SeerEditorWidgetAssemblyArea::setHighlighterSettings (const SeerHighlighterSettings& settings) { _sourceHighlighterSettings = settings; emit highlighterSettingsChanged(); } const SeerHighlighterSettings& SeerEditorWidgetAssemblyArea::highlighterSettings () const { return _sourceHighlighterSettings; } void SeerEditorWidgetAssemblyArea::setHighlighterEnabled (bool flag) { _sourceHighlighterEnabled = flag; emit highlighterSettingsChanged(); } bool SeerEditorWidgetAssemblyArea::highlighterEnabled () const { return _sourceHighlighterEnabled; } QString SeerEditorWidgetAssemblyArea::sourceForLine (const QString& fullname, const QString& file, int line) { // A new file? Zap the previously cached file. if (fullname != _fileFullname || file != _fileName) { _fileLines = QStringList(); _fileFullname = ""; _fileName = ""; } // Nothing in cache? Open the file and read it. if (_fileFullname == "" || _fileName == "") { _fileFullname = fullname; _fileName = file; if (_fileFullname == "") { return ""; } bool f = Seer::readFile(_fileFullname, _fileLines); if (f == false) { qDebug() << "Can't read:" << _fileFullname; } } // Return the requested line. // 'line' is 1 based. We want it to be 0 based. line --; if (line < 0 || line >= _fileLines.size()) { return ""; } return _fileLines[line]; } void SeerEditorWidgetAssemblyArea::setEditorFont (const QFont& font) { setFont(font); invalidateMiniMapCache(); // See: SeerEditorSourceArea::setEditorFont() } const QFont& SeerEditorWidgetAssemblyArea::editorFont () const { return font(); } void SeerEditorWidgetAssemblyArea::setEditorTabSize (int spaces) { _sourceTabSize = spaces; } int SeerEditorWidgetAssemblyArea::editorTabSize () const { return _sourceTabSize; } void SeerEditorWidgetAssemblyArea::setConvertUppercase (bool flag) { _convertUppercase = flag; } bool SeerEditorWidgetAssemblyArea::convertUppercase () const { return _convertUppercase; } void SeerEditorWidgetAssemblyArea::handleText (const QString& text) { if (text.startsWith("*stopped")) { // *stopped, // // reason="end-stepping-range", // // frame={addr="0x0000000000400b45", // func="main", // args=[{name="argc",value="1"},{name="argv",value="0x7fffffffd5b8"}], // file="helloworld.cpp", // fullname="/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp", // line="7", // arch="i386:x86-64"}, // // thread-id="1", // stopped-threads="all", // core="6" QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "frame=", '{', '}', false); if (frame_text == "") { return; } QString addr_text = Seer::parseFirst(frame_text, "addr=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); //qDebug() << frame_text; //qDebug() << addr_text << fullname_text << file_text << line_text; // Will emit the load signal, if 'addr_text' is not already loaded. setAddress(addr_text); // Set to the line number. setCurrentLine(addr_text); return; }else if (text.startsWith("^done,stack=[") && text.endsWith("]")) { //qDebug() << ":stack:" << text; // // See SeerStackFramesBrowserWidget.cpp // ^done,stack=[ // ... // ] // // Now parse the table and re-add the current line, if possible. QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString stack_text = Seer::parseFirst(newtext, "stack=", '[', ']', false); if (stack_text != "") { // Parse through the frame list and set the current lines that are in the frame list. QStringList frame_list = Seer::parse(newtext, "frame=", '{', '}', false); for ( const auto& frame_text : frame_list ) { QString level_text = Seer::parseFirst(frame_text, "level=", '"', '"', false); QString addr_text = Seer::parseFirst(frame_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(frame_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); QString arch_text = Seer::parseFirst(frame_text, "arch=", '"', '"', false); // If the 'addr' works for the currently loaded assembly, then stop. bool f = setCurrentLine(addr_text); if (f == true) { break; } } } }else if (text.startsWith("^done,asm_insns=")) { _asm_insns_text = text; updateTextArea(); // This function does all the work on _asm_insns_text. }else if (text.startsWith("^error,msg=\"-data-disassemble:")) { QString error_text = Seer::parseFirst(text, "msg=", '"', '"', false); QMessageBox::warning(this, "Warning.", error_text); } } void SeerEditorWidgetAssemblyArea::handleHighlighterSettingsChanged () { // When this handler is called, the new Highlight settings have // already been set. So we just need to redo the text area. updateTextArea(); // Note. // The margins are automatically updated by their own paint events. // The new highlighter settings will be used. } // // LineNumber Area. // SeerEditorWidgetAssemblyLineNumberArea::SeerEditorWidgetAssemblyLineNumberArea(SeerEditorWidgetAssemblyArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetAssemblyLineNumberArea::sizeHint () const { return QSize(_editorWidget->lineNumberAreaWidth(), 0); } void SeerEditorWidgetAssemblyLineNumberArea::paintEvent (QPaintEvent* event) { _editorWidget->lineNumberAreaPaintEvent(event); } void SeerEditorWidgetAssemblyLineNumberArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToAddress(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetAssemblyLineNumberArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetAssemblyLineNumberArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetAssemblyLineNumberArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } // // Offset Area. // SeerEditorWidgetAssemblyOffsetArea::SeerEditorWidgetAssemblyOffsetArea(SeerEditorWidgetAssemblyArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetAssemblyOffsetArea::sizeHint () const { return QSize(_editorWidget->offsetAreaWidth(), 0); } void SeerEditorWidgetAssemblyOffsetArea::paintEvent (QPaintEvent* event) { _editorWidget->offsetAreaPaintEvent(event); } void SeerEditorWidgetAssemblyOffsetArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToAddress(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetAssemblyOffsetArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetAssemblyOffsetArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetAssemblyOffsetArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } // // Opcode Area. // SeerEditorWidgetAssemblyOpcodeArea::SeerEditorWidgetAssemblyOpcodeArea(SeerEditorWidgetAssemblyArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetAssemblyOpcodeArea::sizeHint () const { return QSize(_editorWidget->opcodeAreaWidth(), 0); } void SeerEditorWidgetAssemblyOpcodeArea::paintEvent (QPaintEvent* event) { _editorWidget->opcodeAreaPaintEvent(event); } void SeerEditorWidgetAssemblyOpcodeArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToAddress(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetAssemblyOpcodeArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetAssemblyOpcodeArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetAssemblyOpcodeArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } // // Breakpoint Area. // SeerEditorWidgetAssemblyBreakPointArea::SeerEditorWidgetAssemblyBreakPointArea(SeerEditorWidgetAssemblyArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetAssemblyBreakPointArea::sizeHint () const { return QSize(_editorWidget->breakPointAreaWidth(), 0); } void SeerEditorWidgetAssemblyBreakPointArea::paintEvent (QPaintEvent* event) { _editorWidget->breakPointAreaPaintEvent(event); } void SeerEditorWidgetAssemblyBreakPointArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToAddress(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetAssemblyBreakPointArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetAssemblyBreakPointArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetAssemblyBreakPointArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } SeerEditorWidgetAssemblyMiniMapArea::SeerEditorWidgetAssemblyMiniMapArea(SeerEditorWidgetAssemblyArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; _dragging = false; _dragStartY = 0; _dragStartValue = 0; _preview = new SeerPlainTextMiniMapPreview(this); _scrollTipTimer = new QTimer(this); // Hide the visible-lines tooltip once wheel scrolling stops. _scrollTipTimer->setSingleShot(true); _scrollTipTimer->setInterval(1000); QObject::connect(_scrollTipTimer, &QTimer::timeout, this, []() { QToolTip::hideText(); }); setMouseTracking(true); } QSize SeerEditorWidgetAssemblyMiniMapArea::sizeHint () const { return QSize(_editorWidget->miniMapAreaWidth(), 0); } void SeerEditorWidgetAssemblyMiniMapArea::paintEvent (QPaintEvent* event) { _editorWidget->miniMapAreaPaintEvent(event); } void SeerEditorWidgetAssemblyMiniMapArea::mousePressEvent (QMouseEvent* event) { _preview->hide(); if (event->button() == Qt::LeftButton) { // Clicking outside the overlay jumps there. Then (or when clicking // inside the overlay) dragging moves the overlay with the mouse. QRectF overlay = SeerPlainTextMiniMap::overlayRect(_editorWidget, width(), height()); if (overlay.contains(overlay.center().x(), event->pos().y()) == false) { _editorWidget->jumpToMiniMapY(event->pos().y()); } _dragging = true; _dragStartY = event->pos().y(); _dragStartValue = _editorWidget->verticalScrollBar()->value(); SeerPlainTextMiniMap::showVisibleLinesTip(_editorWidget, this, mapToGlobal(event->pos())); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetAssemblyMiniMapArea::mouseMoveEvent (QMouseEvent* event) { if (_dragging && (event->buttons() & Qt::LeftButton)) { int value = SeerPlainTextMiniMap::dragValue(_editorWidget, height(), _dragStartValue, event->pos().y() - _dragStartY); _editorWidget->verticalScrollBar()->setValue(value); SeerPlainTextMiniMap::showVisibleLinesTip(_editorWidget, this, mapToGlobal(event->pos())); return; } // Hovering shows a preview of the code under the mouse. int y = event->pos().y(); if (event->buttons() == Qt::NoButton && y >= 0 && y < _editorWidget->document()->blockCount() * SeerPlainTextMiniMap::pixelsPerLine(_editorWidget, height())) { const SeerHighlighterSettings& settings = _editorWidget->highlighterSettings(); QTextCharFormat textFormat = settings.get("Text"); QTextCharFormat currentLineFormat = settings.get("Current Line"); QRect globalRect (mapToGlobal(QPoint(0, 0)), size()); int lineno = SeerPlainTextMiniMap::lineAt(_editorWidget, height(), y); _preview->showPreview(_editorWidget, lineno, globalRect, mapToGlobal(event->pos()).y(), textFormat.background().color(), textFormat.foreground().color(), currentLineFormat.background().color()); }else{ _preview->hide(); } QWidget::mouseMoveEvent(event); } void SeerEditorWidgetAssemblyMiniMapArea::mouseReleaseEvent (QMouseEvent* event) { _dragging = false; QToolTip::hideText(); QWidget::mouseReleaseEvent(event); } void SeerEditorWidgetAssemblyMiniMapArea::leaveEvent (QEvent* event) { _preview->hide(); QWidget::leaveEvent(event); } void SeerEditorWidgetAssemblyMiniMapArea::wheelEvent (QWheelEvent* event) { // The wheel itself is forwarded to the editor (see SeerPlainTextWheelEventForwarder), // which has already scrolled by now. _preview->hide(); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) SeerPlainTextMiniMap::showVisibleLinesTip(_editorWidget, this, event->globalPosition().toPoint()); #else SeerPlainTextMiniMap::showVisibleLinesTip(_editorWidget, this, event->globalPos()); #endif _scrollTipTimer->start(); QWidget::wheelEvent(event); } epasveer-seer-97076f1/src/SeerEditorWidgetSource.cpp000066400000000000000000000340571526321767600224620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorWidgetSource.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SeerEditorWidgetSource::SeerEditorWidgetSource(QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Set the widgets. sourceArea()->show(); searchTextLineEdit->enableReturnPressedOnClear(); showSearchBar(false); // Hide the search bar. ctrl+F to show it again. showAlternateBar(false); // Hide the alternate bar. ctrl+O to show it again. showReloadBar(false); // Hide the reload file bar. Automatically shown if file gets updated. setSearchMatchCase(true); // Search with case sensitivity. _textSearchShortcut = new QShortcut(QKeySequence(tr("Ctrl+F")), this); _textSearchNextShortcut = new QShortcut(QKeySequence(tr("Ctrl+G")), this); _textSearchPrevShortcut = new QShortcut(QKeySequence(tr("Ctrl+Shift+G")), this); _textSearchReloadShortcut = new QShortcut(QKeySequence(tr("Ctrl+R")), this); _lineSearchShortcut = new QShortcut(QKeySequence(tr("Ctrl+L")), this); _alternateDirShortcut = new QShortcut(QKeySequence(tr("Ctrl+O")), this); _toggleBreakpointShortcut = new QShortcut(QKeySequence(tr("Ctrl+B")), this); _gotoDefinitionShortcut = new QShortcut(QKeySequence(tr("F12")), this); setKeySettings(SeerKeySettings::populate()); // Connect things. QObject::connect(searchTextLineEdit, &QHistoryLineEdit::returnPressed, this, &SeerEditorWidgetSource::handleSearchTextLineEdit); QObject::connect(searchTextLineEdit, &QHistoryLineEdit::escapePressed, this, &SeerEditorWidgetSource::handleEscapePressed); #if QT_VERSION >= 0x060900 QObject::connect(matchCaseCheckBox, &QCheckBox::checkStateChanged, this, &SeerEditorWidgetSource::handleSearchTextLineEdit); #else QObject::connect(matchCaseCheckBox, &QCheckBox::stateChanged, this, &SeerEditorWidgetSource::handleSearchTextLineEdit); #endif QObject::connect(searchDownToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleSearchDownToolButton); QObject::connect(searchUpToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleSearchUpToolButton); QObject::connect(searchLineNumberLineEdit, &QHistoryLineEdit::returnPressed, this, &SeerEditorWidgetSource::handleSearchLineNumberLineEdit); QObject::connect(searchLineNumberLineEdit, &QHistoryLineEdit::escapePressed, this, &SeerEditorWidgetSource::handleEscapePressed); QObject::connect(searchReloadToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleReloadToolButton); QObject::connect(searchCloseToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleSearchCloseToolButton); QObject::connect(alternateCloseToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleAlternateCloseToolButton); QObject::connect(alternateFileOpenToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleAlternateFileOpenToolButton); QObject::connect(alternateLineEdit, &QHistoryLineEdit::returnPressed, this, &SeerEditorWidgetSource::handleAlternateLineEdit); QObject::connect(reloadToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleReloadToolButton); QObject::connect(reloadCloseToolButton, &QToolButton::clicked, this, &SeerEditorWidgetSource::handleReloadCloseToolButton); QObject::connect(sourceWidget, &SeerEditorWidgetSourceArea::showSearchBar, this, qOverload(&SeerEditorWidgetSource::showSearchBar)); QObject::connect(sourceWidget, &SeerEditorWidgetSourceArea::showAlternateBar, this, &SeerEditorWidgetSource::showAlternateBar); QObject::connect(sourceWidget, &SeerEditorWidgetSourceArea::showReloadBar, this, &SeerEditorWidgetSource::showReloadBar); QObject::connect(_textSearchShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleTextSearchShortcut); QObject::connect(_textSearchNextShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleSearchDownToolButton); QObject::connect(_textSearchPrevShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleSearchUpToolButton); QObject::connect(_textSearchReloadShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleReloadToolButton); QObject::connect(_lineSearchShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleLineSearchShortcut); QObject::connect(_alternateDirShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleAlternateDirectoryShortcut); QObject::connect(_toggleBreakpointShortcut, &QShortcut::activated, this, &SeerEditorWidgetSource::handleToggleBreakpointShortcut); QObject::connect(_gotoDefinitionShortcut, &QShortcut::activated, sourceArea(), &SeerEditorWidgetSourceArea::handleGotoDefinition); // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); } SeerEditorWidgetSource::~SeerEditorWidgetSource () { } SeerEditorWidgetSourceArea* SeerEditorWidgetSource::sourceArea () { return sourceWidget; } bool SeerEditorWidgetSource::isSearchBarShown () const { return searchBarWidget->isVisible(); } bool SeerEditorWidgetSource::searchMatchCase () const { return matchCaseCheckBox->isChecked(); } bool SeerEditorWidgetSource::isAlternateBarShown () const { return alternateBarWidget->isVisible(); } void SeerEditorWidgetSource::setKeySettings (const SeerKeySettings& settings) { _keySettings = settings; if (_keySettings.has("SearchText") == true) { _textSearchShortcut->setKey(_keySettings.get("SearchText")._sequence); } if (_keySettings.has("SearchTextNext") == true) { _textSearchNextShortcut->setKey(_keySettings.get("SearchTextNext")._sequence); } if (_keySettings.has("SearchTextPrev") == true) { _textSearchPrevShortcut->setKey(_keySettings.get("SearchTextPrev")._sequence); } if (_keySettings.has("AlternateDir") == true) { _alternateDirShortcut->setKey(_keySettings.get("AlternateDir")._sequence); } if (_keySettings.has("ToggleBreakpoint") == true) { _toggleBreakpointShortcut->setKey(_keySettings.get("ToggleBreakpoint")._sequence); } if (_keySettings.has("GoToDefinition") == true) { _gotoDefinitionShortcut->setKey(_keySettings.get("GoToDefinition")._sequence); } } const SeerKeySettings& SeerEditorWidgetSource::keySettings () const { return _keySettings; } void SeerEditorWidgetSource::showSearchBar (bool flag) { showSearchBar(flag, ""); } void SeerEditorWidgetSource::showSearchBar (bool flag, QString field) { searchBarWidget->setVisible(flag); // If 'show', give the searchTextLineEdit or the searchTextLineEdit the focus. if (flag) { if (field == "text") { searchTextLineEdit->setFocus(Qt::MouseFocusReason); }else if (field == "line") { searchLineNumberLineEdit->setFocus(Qt::MouseFocusReason); }else{ searchTextLineEdit->setFocus(Qt::MouseFocusReason); } } } void SeerEditorWidgetSource::setSearchMatchCase (bool flag) { matchCaseCheckBox->setChecked(flag); } void SeerEditorWidgetSource::showAlternateBar (bool flag) { alternateBarWidget->setVisible(flag); if (flag) { originalLineEdit->setText(sourceArea()->fullname()); // Set the original text. rememberAlternateCheckBox->setChecked(true); // Set the default remember setting. alternateLineEdit->setFocus(Qt::MouseFocusReason); // If 'show', give the alternateLineEdit the focus. } } void SeerEditorWidgetSource::showReloadBar (bool flag) { reloadBarWidget->setVisible(flag); reloadBarWidget->setStyleSheet("QWidget { background-color : #00AA00; color : #FFFF00; }"); if (flag) { int elideLength = 50; if (sourceArea()->autoSourceReload()) { reloadFilenameLabel->setText("The file \"" + Seer::elideText(sourceArea()->file(),Qt::ElideLeft,elideLength) + "\" has changed on disk. RELOADING..."); reloadFilenameLabel->setToolTip(sourceArea()->file()); reloadToolButton->setFocus(Qt::MouseFocusReason); // Give the reload button the focus. // Schedule the reload. QTimer::singleShot(1000, this, &SeerEditorWidgetSource::handleReloadToolButton); }else{ reloadFilenameLabel->setText("The file \"" + Seer::elideText(sourceArea()->file(),Qt::ElideLeft,elideLength) + "\" has changed on disk."); reloadFilenameLabel->setToolTip(sourceArea()->file()); reloadToolButton->setFocus(Qt::MouseFocusReason); // Give the reload button the focus. } }else{ reloadFilenameLabel->setText(""); reloadFilenameLabel->setToolTip(""); } } void SeerEditorWidgetSource::handleSearchLineNumberLineEdit () { QString str = searchLineNumberLineEdit->text(); if (str == "") { showSearchBar(false); return; } int lineno = str.toInt(); if (lineno < 1) { return; } searchLineNumberLineEdit->clear(); sourceArea()->scrollToLine(lineno); } void SeerEditorWidgetSource::handleSearchTextLineEdit () { QString str = searchTextLineEdit->text(); matchesLabel->setText(""); if (str == "") { sourceArea()->clearFindText(); showSearchBar(false); return; } int nMatches = sourceArea()->findText(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags())); matchesLabel->setText(QString("(%1)").arg(nMatches)); } void SeerEditorWidgetSource::handleSearchDownToolButton () { QString str = searchTextLineEdit->text(); if (str == "") { return; } sourceArea()->find(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags())); } void SeerEditorWidgetSource::handleSearchUpToolButton () { QString str = searchTextLineEdit->text(); if (str == "") { return; } sourceArea()->find(str, (searchMatchCase() ? QTextDocument::FindCaseSensitively : QTextDocument::FindFlags()) | QTextDocument::FindBackward); } void SeerEditorWidgetSource::handleSearchCloseToolButton () { showSearchBar(false); } void SeerEditorWidgetSource::handleAlternateCloseToolButton () { showAlternateBar(false); } void SeerEditorWidgetSource::handleAlternateFileOpenToolButton () { //qDebug() << "fullname =" << sourceArea()->fullname(); //qDebug() << "file =" << sourceArea()->file(); QString filename = QFileDialog::getOpenFileName(this, "Locate File", sourceArea()->fullname(), QString("File (%1)").arg(sourceArea()->file()), nullptr, QFileDialog::DontUseNativeDialog); //qDebug() << "location =" << filename; //qDebug() << "directory=" << QFileInfo(filename).absolutePath(); if (filename != "") { alternateLineEdit->setText(QFileInfo(filename).absolutePath()); } handleAlternateLineEdit(); } void SeerEditorWidgetSource::handleAlternateLineEdit () { showAlternateBar(false); // Get the base path. QString dirname = alternateLineEdit->text(); if (dirname == "") { return; } //qDebug() << "alternate dirname=" << dirname; // Attempt to open the file. sourceArea()->open(sourceArea()->fullname(), sourceArea()->file(), dirname); // Add to global alternate list. if (rememberAlternateCheckBox->isChecked()) { emit addAlternateDirectory(dirname); } } void SeerEditorWidgetSource::handleTextSearchShortcut () { if (isSearchBarShown() == true) { showSearchBar(false, ""); }else{ showSearchBar(true, "text"); } } void SeerEditorWidgetSource::handleLineSearchShortcut () { if (isSearchBarShown() == true) { showSearchBar(false, ""); }else{ showSearchBar(true, "line"); } } void SeerEditorWidgetSource::handleAlternateDirectoryShortcut () { if (isAlternateBarShown() == true) { showAlternateBar(false); }else{ showAlternateBar(true); } } void SeerEditorWidgetSource::handleToggleBreakpointShortcut () { sourceArea()->breakpointToggle(); } void SeerEditorWidgetSource::handleReloadToolButton () { showReloadBar(false); sourceArea()->reload(); } void SeerEditorWidgetSource::handleReloadCloseToolButton () { showReloadBar(false); } void SeerEditorWidgetSource::handleEscapePressed () { showSearchBar(false, ""); } epasveer-seer-97076f1/src/SeerEditorWidgetSource.h000066400000000000000000000571631526321767600221320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerSourceHighlighter.h" #include "SeerKeySettings.h" #include "SeerPlainTextEdit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class SeerEditorWidgetSourceLineNumberArea; class SeerEditorWidgetSourceBreakPointArea; class SeerEditorWidgetSourceMiniMapArea; class SeerEditorWidgetSourceArea : public SeerPlainTextEdit { Q_OBJECT public: struct SeerCurrentFile { QString file; QString fullname; int cursorRow; // line to set the cursor to int cursorCol; // column to set the cursor to int firstDisplayLine; // line to display at top bool operator==(const SeerCurrentFile& other) const { return (fullname == other.fullname) && (cursorRow == other.cursorRow) && (cursorCol == other.cursorCol) && (firstDisplayLine == other.firstDisplayLine); } bool operator!=(const SeerCurrentFile& other) const { return (fullname != other.fullname) | (cursorRow != other.cursorRow) | (cursorCol != other.cursorCol) | (firstDisplayLine != other.firstDisplayLine); } }; SeerEditorWidgetSourceArea (QWidget* parent = 0); void enableLineNumberArea (bool flag); bool lineNumberAreaEnabled () const; void enableBreakPointArea (bool flag); bool breakPointAreaEnabled () const; void enableMiniMapArea (bool flag); bool miniMapAreaEnabled () const; void lineNumberAreaPaintEvent (QPaintEvent* event); int lineNumberAreaWidth (); void breakPointAreaPaintEvent (QPaintEvent* event); int breakPointAreaWidth (); void miniMapAreaPaintEvent (QPaintEvent* event); int miniMapAreaWidth (); void jumpToMiniMapY (int y); bool isOpen () const; void open (const QString& fullname, const QString& file, const QString& alternateDirectory=""); void openText (const QString& text, const QString& file); void close (); void reload (); const QString& fullname () const; const QString& file () const; void setAlternateDirectory (const QString& alternateDirectory); const QString& alternateDirectory () const; void setAlternateDirectories (const QStringList& alternateDirectories); const QStringList& alternateDirectories () const; QString findFile (const QString& file, const QString& fullname, const QString& alternateDirectory, const QStringList& alternateDirectories); void setCurrentLine (int lineno); void setCurrentColumn (int colno); int currentLine () const; int currentColumn () const; int firstDisplayLine () const; void scrollToLine (int lineno); void clearCurrentLines (); void addCurrentLine (int lineno, int level); int findText (const QString& text, QTextDocument::FindFlags flags); void clearFindText (); void clearBreakpoints (); void addBreakpoint (int number, int lineno, bool enabled); bool hasBreakpointNumber (int number) const; bool hasBreakpointLine (int lineno) const; const QVector& breakpointNumbers () const; const QVector& breakpointLines () const; const QVector& breakpointEnableds () const; int breakpointLineToNumber (int lineno) const; bool breakpointLineEnabled (int lineno) const; void breakpointToggle (); void runToSelectedLine (); void showContextMenu (QMouseEvent* event); void showContextMenu (QContextMenuEvent* event); void showContextMenu (const QPoint& pos, const QPointF& globalPos); void setQuickBreakpoint (QMouseEvent* event); void setQuickRunToLine (QMouseEvent* event); void showBreakpointToolTip (QMouseEvent* event); void clearExpression (); void setHighlighterSettings (const SeerHighlighterSettings& settings); const SeerHighlighterSettings& highlighterSettings () const; void setHighlighterEnabled (bool flag); bool highlighterEnabled () const; void setEditorFont (const QFont& font); const QFont& editorFont () const; void setEditorTabSize (int spaces); int editorTabSize () const; void setExternalEditorCommand (const QString& externalEditorCommand); const QString& externalEditorCommand (); void setAutoSourceReload (bool flag); bool autoSourceReload () const; SeerCurrentFile readCurrentPosition (); void eraseColorCurrentLine (int lineno); signals: void insertBreakpoint (QString breakpoint); void insertPrintpoint (QString type, QString function, QString channel, QString parameters); void deleteBreakpoints (QString breakpoints); void enableBreakpoints (QString breakpoints); void disableBreakpoints (QString breakpoints); void infoBreakpoint (int breakpointid, QString breakpoint); void refreshBreakpointsStackFrames (); void runToLine (QString fullname, int lineno); void addVariableLoggerExpression (QString expression); void addVariableTrackerExpression (QString expression); void refreshVariableTrackerValues (); void evaluateVariableExpression (int expressionid, QString expression); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); void showSearchBar (bool flag); void showAlternateBar (bool flag); void showReloadBar (bool flag); void highlighterSettingsChanged (); void addToMouseNavigation (const SeerCurrentFile& currentFile); void signalGotoDefinition (const QString& identifier); public slots: void handleText (const QString& text); void handleHighlighterSettingsChanged (); void handleWatchFileModified (const QString& path); void handleBreakpointToolTip (QPoint pos, const QString& text); void handleGotoDefinition (); protected: void resizeEvent (QResizeEvent* event); bool viewportEvent (QEvent* event) override; void contextMenuEvent (QContextMenuEvent* event); void mouseReleaseEvent (QMouseEvent* event); bool event (QEvent* event); void showExpressionTooltip (); void hideExpressionTooltip (); void mousePressEvent (QMouseEvent *event) override; void keyPressEvent (QKeyEvent* event) override; void keyReleaseEvent (QKeyEvent* event) override; private slots: void refreshExtraSelections (); void updateMarginAreasWidth (int newBlockCount); void updateLineNumberArea (const QRect& rect, int dy); void updateBreakPointArea (const QRect& rect, int dy); void updateMiniMapArea (const QRect& rect, int dy); void invalidateMiniMapCache (); void updateMiniMapGeometry (); private: void handleCursorPositionChanged (); void updateCursor (const QPoint &pos); bool isOverWord (const QPoint &pos); QString wordUnderCursor (const QPoint &pos) const; bool isValidIdentifier (const QString& text); QString _fullname; QString _file; QString _alternateDirectory; QStringList _alternateDirectories; QFileSystemWatcher* _fileWatcher; bool _enableLineNumberArea; bool _enableBreakPointArea; bool _enableMiniMapArea; QVector _breakpointsNumbers; QVector _breakpointsLineNumbers; QVector _breakpointsEnableds; QList _findExtraSelections; QList _currentLinesExtraSelections; QTextCursor _selectedExpressionCursor; QPoint _selectedExpressionPosition; int _selectedExpressionId; QString _selectedExpressionName; QString _selectedExpressionValue; QPoint _selectedBreakpointPosition; int _selectedBreakpointId; SeerEditorWidgetSourceLineNumberArea* _lineNumberArea; SeerEditorWidgetSourceBreakPointArea* _breakPointArea; SeerEditorWidgetSourceMiniMapArea* _miniMapArea; QPixmap _miniMapPixmap; bool _miniMapPixmapDirty; SeerSourceHighlighter* _sourceHighlighter; SeerHighlighterSettings _sourceHighlighterSettings; bool _sourceHighlighterEnabled; int _sourceTabSize; QString _externalEditorCommand; bool _autoSourceReload; int _ignoreThumbMouseEvent = 0; // Variables for Goto Definition (Alt + Click) static QTimer* _altHeldTimer; static bool _altHeld; QString _wordUnderCursor; }; class SeerEditorWidgetSourceLineNumberArea : public QWidget { Q_OBJECT public: SeerEditorWidgetSourceLineNumberArea (SeerEditorWidgetSourceArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetSourceArea* _editorWidget; }; class SeerEditorWidgetSourceBreakPointArea : public QWidget { Q_OBJECT public: SeerEditorWidgetSourceBreakPointArea (SeerEditorWidgetSourceArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mouseDoubleClickEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: SeerEditorWidgetSourceArea* _editorWidget; }; class SeerEditorWidgetSourceMiniMapArea : public QWidget { Q_OBJECT public: SeerEditorWidgetSourceMiniMapArea (SeerEditorWidgetSourceArea* editorWidget); QSize sizeHint () const override; protected: void paintEvent (QPaintEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; void leaveEvent (QEvent* event) override; void wheelEvent (QWheelEvent* event) override; private: SeerEditorWidgetSourceArea* _editorWidget; bool _dragging; int _dragStartY; int _dragStartValue; SeerPlainTextMiniMapPreview* _preview; QTimer* _scrollTipTimer; }; #include "ui_SeerEditorWidgetSource.h" class SeerEditorWidgetSource : public QWidget, protected Ui::SeerEditorWidgetSourceForm { Q_OBJECT public: explicit SeerEditorWidgetSource (QWidget* parent = 0); ~SeerEditorWidgetSource (); SeerEditorWidgetSourceArea* sourceArea (); bool isSearchBarShown () const; bool searchMatchCase () const; bool isAlternateBarShown () const; void setKeySettings (const SeerKeySettings& settings); const SeerKeySettings& keySettings () const; public slots: void showSearchBar (bool flag); void showSearchBar (bool flag, QString field); void setSearchMatchCase (bool flag); void showAlternateBar (bool flag); void showReloadBar (bool flag); private slots: void handleSearchLineNumberLineEdit (); void handleSearchTextLineEdit (); void handleSearchDownToolButton (); void handleSearchUpToolButton (); void handleSearchCloseToolButton (); void handleAlternateCloseToolButton (); void handleAlternateFileOpenToolButton (); void handleAlternateLineEdit (); void handleTextSearchShortcut (); void handleLineSearchShortcut (); void handleAlternateDirectoryShortcut (); void handleToggleBreakpointShortcut (); void handleReloadToolButton (); void handleReloadCloseToolButton (); void handleEscapePressed (); signals: void addAlternateDirectory (QString path); private: SeerKeySettings _keySettings; QShortcut* _textSearchShortcut; QShortcut* _textSearchNextShortcut; QShortcut* _textSearchPrevShortcut; QShortcut* _textSearchReloadShortcut; QShortcut* _lineSearchShortcut; QShortcut* _alternateDirShortcut; QShortcut* _toggleBreakpointShortcut; QShortcut* _gotoDefinitionShortcut; }; epasveer-seer-97076f1/src/SeerEditorWidgetSource.ui000066400000000000000000000257171526321767600223200ustar00rootroot00000000000000 SeerEditorWidgetSourceForm 0 0 838 720 SeerEditorWidgetSourceForm 0 0 0 0 Looking for: Original path location. true Alternate path: Enter path for alternate location. Enter /path/to/alternate/location true Open file dialog for alternate location. ... :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Add path to global list of alternate directories. Remember Close the alternate bar. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg 0 0 0 0 Reload source file. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Close the reload bar. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg 0 100 0 0 0 0 50 0 Enter text to search for. Enter search text true Match Case Search for the next occurance. ... :/seer/resources/RelaxLightIcons/go-down.svg:/seer/resources/RelaxLightIcons/go-down.svg Search for the previous occurance. ... :/seer/resources/RelaxLightIcons/go-up.svg:/seer/resources/RelaxLightIcons/go-up.svg Qt::Vertical 50 0 Scroll to a specific line. Go to line # Qt::Vertical Reload source file. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Qt::Vertical Close the search bar. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg SeerEditorWidgetSourceArea QWidget
SeerEditorWidgetSource.h
1
QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
alternateLineEdit alternateFileOpenToolButton rememberAlternateCheckBox alternateCloseToolButton searchTextLineEdit matchCaseCheckBox searchDownToolButton searchUpToolButton searchLineNumberLineEdit searchCloseToolButton
epasveer-seer-97076f1/src/SeerEditorWidgetSourceAreas.cpp000066400000000000000000002460701526321767600234360ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerEditorWidgetSource.h" #include "SeerHighlighterSettings.h" #include "SeerPlainTextEdit.h" #include "SeerBreakpointCreateDialog.h" #include "SeerPrintpointCreateDialog.h" #include "SeerSourceHighlighter.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool SeerEditorWidgetSourceArea::_altHeld = false; QTimer* SeerEditorWidgetSourceArea::_altHeldTimer = new QTimer(); SeerEditorWidgetSourceArea::SeerEditorWidgetSourceArea(QWidget* parent) : SeerPlainTextEdit(parent) { _fileWatcher = 0; _enableLineNumberArea = false; _enableBreakPointArea = false; _enableMiniMapArea = false; _miniMapArea = 0; _miniMapPixmapDirty = true; _sourceHighlighter = 0; _sourceHighlighterEnabled = true; _sourceTabSize = 4; _autoSourceReload = false; _selectedExpressionId = Seer::createID(); _selectedBreakpointId = Seer::createID(); QFont font("monospace"); font.setStyleHint(QFont::Monospace); setEditorFont(font); setEditorTabSize(4); setExternalEditorCommand(""); setReadOnly(true); setTextInteractionFlags(textInteractionFlags() | Qt::TextSelectableByKeyboard); setLineWrapMode(QPlainTextEdit::NoWrap); _lineNumberArea = new SeerEditorWidgetSourceLineNumberArea(this); _breakPointArea = new SeerEditorWidgetSourceBreakPointArea(this); _breakPointArea->setMouseTracking(true); _miniMapArea = new SeerEditorWidgetSourceMiniMapArea(this); enableLineNumberArea(true); enableBreakPointArea(true); enableMiniMapArea(false); _altHeldTimer->setInterval(40); // 40 ms interval = 25Hz update rate QObject::connect(_altHeldTimer, &QTimer::timeout, this, [this]() { updateCursor(QCursor::pos()); }); QObject::connect(this, &SeerEditorWidgetSourceArea::blockCountChanged, this, &SeerEditorWidgetSourceArea::updateMarginAreasWidth); QObject::connect(this, &SeerEditorWidgetSourceArea::blockCountChanged, this, &SeerEditorWidgetSourceArea::invalidateMiniMapCache); QObject::connect(this, &SeerEditorWidgetSourceArea::updateRequest, this, &SeerEditorWidgetSourceArea::updateLineNumberArea); QObject::connect(this, &SeerEditorWidgetSourceArea::updateRequest, this, &SeerEditorWidgetSourceArea::updateBreakPointArea); QObject::connect(this, &SeerEditorWidgetSourceArea::updateRequest, this, &SeerEditorWidgetSourceArea::updateMiniMapArea); QObject::connect(this, &SeerEditorWidgetSourceArea::highlighterSettingsChanged, this, &SeerEditorWidgetSourceArea::handleHighlighterSettingsChanged); // Connect cursor position changed signal. QObject::connect(this, &QPlainTextEdit::cursorPositionChanged, this, &SeerEditorWidgetSourceArea::handleCursorPositionChanged); setCurrentLine(0); updateMarginAreasWidth(0); // Forward the scroll events in the various areas to the text edit. SeerPlainTextWheelEventForwarder* lineNumberAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); SeerPlainTextWheelEventForwarder* breakPointAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); SeerPlainTextWheelEventForwarder* miniMapAreaWheelForwarder = new SeerPlainTextWheelEventForwarder(this); _lineNumberArea->installEventFilter(lineNumberAreaWheelForwarder); _breakPointArea->installEventFilter(breakPointAreaWheelForwarder); _miniMapArea->installEventFilter(miniMapAreaWheelForwarder); _altHeldTimer->start(); // Calling close() will clear the text document. close(); } void SeerEditorWidgetSourceArea::enableLineNumberArea (bool flag) { _enableLineNumberArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetSourceArea::lineNumberAreaEnabled () const { return _enableLineNumberArea; } void SeerEditorWidgetSourceArea::enableBreakPointArea (bool flag) { _enableBreakPointArea = flag; updateMarginAreasWidth(0); } bool SeerEditorWidgetSourceArea::breakPointAreaEnabled () const { return _enableBreakPointArea; } void SeerEditorWidgetSourceArea::enableMiniMapArea (bool flag) { _enableMiniMapArea = flag; setVerticalScrollBarPolicy(flag ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded); invalidateMiniMapCache(); updateMarginAreasWidth(0); } bool SeerEditorWidgetSourceArea::miniMapAreaEnabled () const { return _enableMiniMapArea; } void SeerEditorWidgetSourceArea::updateMarginAreasWidth (int newBlockCount) { Q_UNUSED(newBlockCount); int leftMarginWidth = lineNumberAreaWidth() + breakPointAreaWidth(); int rightMarginWidth = miniMapAreaWidth(); setViewportMargins(leftMarginWidth, 0, rightMarginWidth, 0); } int SeerEditorWidgetSourceArea::lineNumberAreaWidth () { if (lineNumberAreaEnabled() == false) { return 0; } int digits = 1; int max = qMax(1, blockCount()); while (max >= 10) { max /= 10; digits++; } int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits; return space; } int SeerEditorWidgetSourceArea::breakPointAreaWidth () { if (breakPointAreaEnabled() == false) { return 0; } int space = 3 + 20; return space; } int SeerEditorWidgetSourceArea::miniMapAreaWidth () { if (miniMapAreaEnabled() == false) { return 0; } return 60; } void SeerEditorWidgetSourceArea::updateLineNumberArea (const QRect& rect, int dy) { if (lineNumberAreaEnabled() == false) { return; } if (dy) { _lineNumberArea->scroll(0, dy); }else{ _lineNumberArea->update(0, rect.y(), _lineNumberArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetSourceArea::updateBreakPointArea (const QRect& rect, int dy) { if (breakPointAreaEnabled() == false) { return; } if (dy) { _breakPointArea->scroll(0, dy); }else{ _breakPointArea->update(0, rect.y(), _breakPointArea->width(), rect.height()); } if (rect.contains(viewport()->rect())) { updateMarginAreasWidth(0); } } void SeerEditorWidgetSourceArea::updateMiniMapArea (const QRect& rect, int dy) { Q_UNUSED(rect); Q_UNUSED(dy); if (miniMapAreaEnabled() == false) { return; } // The mini-map's cached content is a whole-document rendering, not a // viewport-following strip, so there's nothing to scroll - just repaint // the (cheap) viewport-position overlay on top of the cached pixmap. _miniMapArea->update(); } void SeerEditorWidgetSourceArea::invalidateMiniMapCache () { _miniMapPixmapDirty = true; if (_miniMapArea) { _miniMapArea->update(); } } void SeerEditorWidgetSourceArea::lineNumberAreaPaintEvent (QPaintEvent* event) { if (lineNumberAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Margin"); QPainter painter(_lineNumberArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString number = QString::number(blockNumber + 1); painter.drawText(0, top, _lineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, number); } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetSourceArea::breakPointAreaPaintEvent (QPaintEvent* event) { if (breakPointAreaEnabled() == false) { return; } QTextCharFormat format = highlighterSettings().get("Margin"); QPainter painter(_breakPointArea); painter.fillRect(event->rect(), format.background().color()); painter.setPen(format.foreground().color()); QFont font = painter.font(); font.setItalic(format.fontItalic()); font.setWeight(QFont::Weight(format.fontWeight())); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { if (hasBreakpointLine(blockNumber+1)) { if (breakpointLineEnabled(blockNumber+1)) { QRect rect(_breakPointArea->width() - 20, top, fontMetrics().height(), fontMetrics().height()); QPainterPath path; path.addEllipse(rect); QPointF bias = QPointF(rect.width() * .25 * 1.0, rect.height() * .25 * -1.0); QRadialGradient gradient(rect.center(), rect.width() / 2.0, rect.center() + bias); gradient.setColorAt(0.0, QColor(Qt::white)); gradient.setColorAt(0.9, QColor(Qt::red)); gradient.setColorAt(1.0, QColor(Qt::transparent)); painter.fillPath(path,QBrush(gradient)); }else{ QRect rect(_breakPointArea->width() - 20, top, fontMetrics().height(), fontMetrics().height()); QPainterPath path; path.addEllipse(rect); QPointF bias = QPointF(rect.width() * .25 * 1.0, rect.height() * .25 * -1.0); QRadialGradient gradient(rect.center(), rect.width() / 2.0, rect.center() + bias); gradient.setColorAt(0.0, QColor(Qt::white)); gradient.setColorAt(0.9, QColor(Qt::darkGray)); gradient.setColorAt(1.0, Qt::transparent); painter.fillPath(path,QBrush(gradient)); } } } block = block.next(); top = bottom; bottom = top + qRound(blockBoundingRect(block).height()); blockNumber++; } } void SeerEditorWidgetSourceArea::miniMapAreaPaintEvent (QPaintEvent* event) { Q_UNUSED(event); if (miniMapAreaEnabled() == false) { return; } // The mini-map's background is the gutter's "Margin" color. Characters // use the editor's text color (or their syntax highlighter color). QTextCharFormat marginFormat = highlighterSettings().get("Margin"); QTextCharFormat textFormat = highlighterSettings().get("Text"); // Like Kate, the mini-map always shows the whole document. Rebuild the // cached pixmap if the document, theme, or size changed. // // Characters are drawn as Kate-style marks colored by the syntax highlighter // (see SeerPlainTextMiniMap::render()). if (_miniMapPixmapDirty || _miniMapPixmap.size() != _miniMapArea->size()) { _miniMapPixmap = QPixmap(_miniMapArea->size()); if (_miniMapPixmap.isNull() == false) { SeerPlainTextMiniMap::render(_miniMapPixmap, document(), marginFormat.background().color(), textFormat.foreground().color()); } _miniMapPixmapDirty = false; } QPainter painter(_miniMapArea); painter.drawPixmap(0, 0, _miniMapPixmap); // Overlay: highlight the portion of the document currently visible in the editor. QRectF overlay = SeerPlainTextMiniMap::overlayRect(this, _miniMapArea->width(), _miniMapArea->height()); QTextCharFormat currentLineFormat = highlighterSettings().get("Current Line"); QColor overlayColor = currentLineFormat.background().color(); overlayColor.setAlpha(90); painter.fillRect(overlay, overlayColor); painter.setPen(currentLineFormat.background().color()); painter.drawRect(overlay.adjusted(0, 0, -1, -1)); } void SeerEditorWidgetSourceArea::resizeEvent (QResizeEvent* e) { QPlainTextEdit::resizeEvent(e); QRect cr = contentsRect(); if (lineNumberAreaEnabled()) { _lineNumberArea->setGeometry (QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); } if (breakPointAreaEnabled()) { _breakPointArea->setGeometry (QRect(cr.left() + lineNumberAreaWidth(), cr.top(), breakPointAreaWidth(), cr.height())); } updateMiniMapGeometry(); } bool SeerEditorWidgetSourceArea::viewportEvent (QEvent* event) { // The viewport can change size without the editor changing size, when the // horizontal scrollbar appears or disappears. if (event->type() == QEvent::Resize) { updateMiniMapGeometry(); } return SeerPlainTextEdit::viewportEvent(event); } void SeerEditorWidgetSourceArea::updateMiniMapGeometry () { if (miniMapAreaEnabled() == false) { return; } // Match the viewport's height, so the mini-map doesn't extend behind the // horizontal scrollbar. QRect cr = contentsRect(); QRect vr = viewport()->geometry(); QRect mr = QRect(cr.right() - miniMapAreaWidth() + 1, vr.top(), miniMapAreaWidth(), vr.height()); if (_miniMapArea->geometry() == mr) { return; } _miniMapArea->setGeometry(mr); // The mini-map's height changed, so the cached pixmap's vertical scale is stale. invalidateMiniMapCache(); } void SeerEditorWidgetSourceArea::contextMenuEvent (QContextMenuEvent* event) { showContextMenu(event); } void SeerEditorWidgetSourceArea::mouseReleaseEvent (QMouseEvent* event) { QPlainTextEdit::mouseReleaseEvent(event); if (textCursor().selectedText() == "") { // Nothing selected, clear current expression. clearExpression(); return; } _selectedExpressionCursor = textCursor(); _selectedExpressionPosition = event->pos(); _selectedExpressionValue = ""; // Look for a keyboard modifier to prepend a '*', '&', or '*&'. Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers(); if (modifiers == Qt::ControlModifier) { _selectedExpressionName = QString("*") + textCursor().selectedText(); }else if (modifiers == Qt::ShiftModifier) { _selectedExpressionName = QString("&") + textCursor().selectedText(); }else if (modifiers == (Qt::ShiftModifier | Qt::ControlModifier)) { _selectedExpressionName = QString("*&") + textCursor().selectedText(); }else{ _selectedExpressionName = textCursor().selectedText(); } emit addVariableLoggerExpression(_selectedExpressionName); // For the variable logger. } bool SeerEditorWidgetSourceArea::event(QEvent* event) { // Handle the ToolTip event. if (event->type() == QEvent::ToolTip) { while (1) { // Create a region of the code that does one pass. // Convert the event to a Help event. QHelpEvent* helpEvent = static_cast(event); // Massage the event location to account for the linenumber and breakpoint widgets. QPoint pos = QPoint(helpEvent->pos().x() - _lineNumberArea->width() - _breakPointArea->width(), helpEvent->pos().y()); // Create a cursor at the position so we can get the text underneath at the cursor. QTextCursor cursor = cursorForPosition(pos); cursor.select(QTextCursor::WordUnderCursor); // If the hover text is empty, do nothing. Reset things. Exit this function. QString word = cursor.selectedText(); if (word.isEmpty() == true) { hideExpressionTooltip(); break; } // Is our cursor the same as the previous. if (cursor == _selectedExpressionCursor) { // Same word as before? Display the tooltip value. if (word == _selectedExpressionName) { // If the tooltip is already visible, refreshen it with // the same value, possibly at a new postion. if (QToolTip::isVisible()) { _selectedExpressionPosition = helpEvent->globalPos(); showExpressionTooltip(); // If not already visible, refreshen its value. }else{ emit evaluateVariableExpression(_selectedExpressionId, _selectedExpressionName); // For the tooltip. } // Otherwise, hide any old one. }else{ hideExpressionTooltip(); } // Otherwise it's a different spot. Create a new request to get the variable's value. }else{ hideExpressionTooltip(); _selectedExpressionCursor = cursor; _selectedExpressionPosition = helpEvent->globalPos(); _selectedExpressionName = word; _selectedExpressionValue = ""; emit evaluateVariableExpression(_selectedExpressionId, _selectedExpressionName); // For the tooltip. } break; } return true; } // Pass any others to the base class. return QPlainTextEdit::event(event); } void SeerEditorWidgetSourceArea::showExpressionTooltip () { // qDebug() << "Tooltip:" << _selectedExpressionPosition << _selectedExpressionName << _selectedExpressionValue; QToolTip::hideText(); QToolTip::showText(_selectedExpressionPosition, _selectedExpressionName + ": " + Seer::elideText(_selectedExpressionValue, Qt::ElideRight, 100)); } void SeerEditorWidgetSourceArea::hideExpressionTooltip () { QToolTip::hideText(); _selectedExpressionCursor = QTextCursor(); _selectedExpressionPosition = QPoint(); _selectedExpressionName = ""; _selectedExpressionValue = ""; } void SeerEditorWidgetSourceArea::refreshExtraSelections () { // // Merge all the extra selections into one. // // The current line(s) // The searched text. // // Create an empty list of selections. QList extraSelections; // Append the 'current lines' extra selections. extraSelections.append(_currentLinesExtraSelections); // Append the 'searched text' extra selections. extraSelections.append(_findExtraSelections); // Give the editor the list of selections. // This will remove the old selections and select the new ones. setExtraSelections(extraSelections); } bool SeerEditorWidgetSourceArea::isOpen () const { if (_fullname != "") { return true; } return false; } void SeerEditorWidgetSourceArea::open (const QString& fullname, const QString& file, const QString& alternateDirectory) { // Delete old file watcher, if any. if (_fileWatcher) { delete _fileWatcher; _fileWatcher = 0; } // Close the previous file, if any. if (isOpen()) { close(); } // Save the filename. _fullname = fullname; _file = file; _alternateDirectory = alternateDirectory; setDocumentTitle(_fullname); // If the filename or file is null, it's a placeholder // widget. Show the Seer icon! if (_fullname == "" || _file == "") { setStyleSheet("QPlainTextEdit {" "background: url(:/seer/resources/icons/hicolor/512x512/seergdb.png) center no-repeat;" "border: none;" "}"); return; } // // Open the file. // // See findFile() to see the search paths and order. // QString filename = findFile(_file, _fullname, _alternateDirectory, _alternateDirectories); if (filename == "") { QMessageBox::critical(this, "Can't find source file.", "Can't find : " + _file + "\nIts location may have changed."); emit showAlternateBar(true); return; } QFile inputFile(filename); bool f = inputFile.open(QIODevice::ReadOnly); if (f == false) { QMessageBox::critical(this, "Can't read source file.", "Can't read : " + filename + "\nThe file is there but can't be opened."); emit showAlternateBar(true); return; } // Read the file. QTextStream stream(&inputFile); QString line = stream.readLine(); QString text; while (!line.isNull()) { // Expand tabs line = Seer::expandTabs(line, editorTabSize(), false); // Build up text for file. text += line + "\n"; // Read next line, if available. line = stream.readLine(); }; // Put the contents in the editor. openText(text, _fullname); // Watch the file. _fileWatcher = new QFileSystemWatcher(this); _fileWatcher->addPath(filename); QObject::connect(_fileWatcher, &QFileSystemWatcher::fileChanged, this, &SeerEditorWidgetSourceArea::handleWatchFileModified); } void SeerEditorWidgetSourceArea::openText (const QString& text, const QString& file) { // Put the contents in the editor. setPlainText(text); // Set the text cursor to the first line. QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor, 1); setTextCursor(cursor); // Add a syntax highlighter. if (_sourceHighlighter) { delete _sourceHighlighter; _sourceHighlighter = 0; } _file = file; SeerSourceHighlighter* highlighter = SeerSourceHighlighter::getSourceHighlighter(_file, _sourceHighlighterSettings); if (highlighter) { _sourceHighlighter = highlighter; if (highlighterEnabled()) { _sourceHighlighter->setDocument(document()); }else{ _sourceHighlighter->setDocument(0); } _sourceHighlighter->setHighlighterSettings(_sourceHighlighterSettings); _sourceHighlighter->rehighlight(); } invalidateMiniMapCache(); } void SeerEditorWidgetSourceArea::reload () { // Open the same file again. QString fullname = _fullname; QString file = _file; QString alternateDirectory = _alternateDirectory; if (fullname == "") return; if (file == "") return; // Save old cursor and scroll position. int blockno = textCursor().blockNumber(); int posinblock = textCursor().positionInBlock(); int vscrollpos = verticalScrollBar()->value(); // Reload file. open(fullname, file, alternateDirectory); // Restore to old cursor and scroll position. QTextCursor c = textCursor(); c.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor, 1); c.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, blockno); c.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, posinblock); setTextCursor(c); ensureCursorVisible(); verticalScrollBar()->setValue(vscrollpos); // Refresh any breakpoints or current lines in the stackframes. emit refreshBreakpointsStackFrames(); } void SeerEditorWidgetSourceArea::close () { setDocumentTitle(""); setPlainText(""); clearExpression(); // Delete old file watcher, if any. if (_fileWatcher) { delete _fileWatcher; _fileWatcher = 0; } } const QString& SeerEditorWidgetSourceArea::fullname () const { return _fullname; } const QString& SeerEditorWidgetSourceArea::file () const { return _file; } void SeerEditorWidgetSourceArea::setAlternateDirectory (const QString& alternateDirectory) { _alternateDirectory = alternateDirectory; } const QString& SeerEditorWidgetSourceArea::alternateDirectory () const { return _alternateDirectory; } void SeerEditorWidgetSourceArea::setAlternateDirectories (const QStringList& alternateDirectories) { _alternateDirectories = alternateDirectories; } const QStringList& SeerEditorWidgetSourceArea::alternateDirectories () const { return _alternateDirectories; } QString SeerEditorWidgetSourceArea::findFile (const QString& file, const QString& fullname, const QString& alternateDirectory, const QStringList& alternateDirectories) { // // This function returns the filename to use to load the source file. // // 'file' is the short version of the filename. eg: 'source.cpp' // 'fullname' is the long version. eg: '/path/to/locate/source.cpp' // 'alternateDirectory' is the alternate directory to use if 'fullname' is not found. // 'alternateDirectories' is a list of alternate directories if 'fullname' is not found // and if 'file' is not in 'alternateDirectory'. // // 'alternateDirectory' can be blank ("") and usually is. If it isn't blank, then it // takes presedence over 'fullname' and 'alternateDirectories'. // // 'alternateDirectories' is a list of directory locations. It defines the search order. // Once a location has the 'file', the search stops and that directory is used. // // If the 'file' can't be found in any of the locations, a "" is returned. // // One note about 'fullname'. This is the path that gdb knows of. Gdb extracts the path // from the debug information in the executable when it was compiled and linked. // // Use 'alternateDirectory', if provided. if (alternateDirectory != "") { QString filename = alternateDirectory + "/" + file; if (QFileInfo::exists(filename) == false) { return ""; } return filename; } // Handle 'fullname'. if (QFileInfo::exists(fullname) == true) { return fullname; } // Handle 'alternateDirectories'. QStringListIterator iter(alternateDirectories); while (iter.hasNext()) { QString filename = iter.next() + "/" + file; if (QFileInfo::exists(filename) == true) { return filename; } } // Not found anywhere. return ""; } void SeerEditorWidgetSourceArea::setCurrentLine (int lineno) { // Clear current line selections. _currentLinesExtraSelections.clear(); // Highlight if a valid line number is selected. if (lineno >= 1) { QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); _currentLinesExtraSelections.clear(); QTextCharFormat lineFormat = highlighterSettings().get("Current Line"); QTextEdit::ExtraSelection selection; selection.format.setForeground(lineFormat.foreground()); selection.format.setBackground(lineFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); _currentLinesExtraSelections.append(selection); } // Refresh all the extra selections. refreshExtraSelections(); } void SeerEditorWidgetSourceArea::setCurrentColumn (int colno) { QTextCursor cursor = textCursor(); int lineStartPos = cursor.block().position(); int newPos = lineStartPos + (colno - 1); cursor.setPosition(newPos); setTextCursor(cursor); } int SeerEditorWidgetSourceArea::currentLine () const { QTextCursor cursor = textCursor(); return cursor.blockNumber() + 1;; } int SeerEditorWidgetSourceArea::currentColumn () const { QTextCursor cursor = textCursor(); return cursor.positionInBlock() + 1; } int SeerEditorWidgetSourceArea::firstDisplayLine () const { QTextBlock block = firstVisibleBlock(); return block.blockNumber() + 1; } void SeerEditorWidgetSourceArea::scrollToLine (int lineno) { // Scroll to the first line if we went before it. if (lineno < 1) { lineno = 1; } // Scroll to the last line if we went past it. if (lineno > document()->blockCount()) { lineno = document()->blockCount(); } QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); setTextCursor(cursor); centerCursor(); } void SeerEditorWidgetSourceArea::jumpToMiniMapY (int y) { if (miniMapAreaEnabled() == false) { return; } int lineno = SeerPlainTextMiniMap::lineAt(this, _miniMapArea->height(), y) + 1; scrollToLine(lineno); } void SeerEditorWidgetSourceArea::clearCurrentLines () { _currentLinesExtraSelections.clear(); refreshExtraSelections(); } void SeerEditorWidgetSourceArea::addCurrentLine (int lineno, int level) { // Any line will be highlighted with a yellow line. // The 'yellow' color is for the current line of the most recent stack frame. // The 'grey' color is for older stack frames. QTextCharFormat lineFormat; if (level == 0) { lineFormat = highlighterSettings().get("Current Line"); }else{ lineFormat = highlighterSettings().get("Calling Line"); } // Create a selection at the cursor. QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); QTextEdit::ExtraSelection selection; selection.format.setForeground(lineFormat.foreground()); selection.format.setBackground(lineFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = cursor; selection.cursor.clearSelection(); // Add it to the extra selection list. _currentLinesExtraSelections.append(selection); // Refresh all the extra selections. refreshExtraSelections(); } int SeerEditorWidgetSourceArea::findText (const QString& text, QTextDocument::FindFlags flags) { _findExtraSelections.clear(); if (document()) { QTextCharFormat matchFormat = highlighterSettings().get("Match"); // Build a list of highlights for all matches. QTextCursor cursor(document()); cursor = document()->find(text, cursor, flags); while (cursor.isNull() == false) { QTextEdit::ExtraSelection extra; extra.format = matchFormat; extra.cursor = cursor; _findExtraSelections.append(extra); cursor = document()->find(text, cursor, flags); } // Move to the next match after out current position. find(text, flags); } refreshExtraSelections(); return _findExtraSelections.size(); } void SeerEditorWidgetSourceArea::clearFindText () { _findExtraSelections.clear(); refreshExtraSelections(); } void SeerEditorWidgetSourceArea::clearBreakpoints () { _breakpointsLineNumbers.clear(); _breakpointsNumbers.clear(); _breakpointsEnableds.clear(); repaint(); } void SeerEditorWidgetSourceArea::addBreakpoint (int number, int lineno, bool enabled) { _breakpointsNumbers.push_back(number); _breakpointsLineNumbers.push_back(lineno); _breakpointsEnableds.push_back(enabled); repaint(); } bool SeerEditorWidgetSourceArea::hasBreakpointNumber (int number) const { return _breakpointsNumbers.contains(number); } bool SeerEditorWidgetSourceArea::hasBreakpointLine (int lineno) const { return _breakpointsLineNumbers.contains(lineno); } const QVector& SeerEditorWidgetSourceArea::breakpointNumbers () const { return _breakpointsNumbers; } const QVector& SeerEditorWidgetSourceArea::breakpointLines () const { return _breakpointsLineNumbers; } const QVector& SeerEditorWidgetSourceArea::breakpointEnableds () const { return _breakpointsEnableds; } int SeerEditorWidgetSourceArea::breakpointLineToNumber (int lineno) const { // Map lineno to breakpoint number. int i = _breakpointsLineNumbers.indexOf(lineno); if (i < 0) { return 0; } return _breakpointsNumbers[i]; } bool SeerEditorWidgetSourceArea::breakpointLineEnabled (int lineno) const { // Look for the lineno and get its index. int i = _breakpointsLineNumbers.indexOf(lineno); // Not found, return false. if (i < 0) { return false; } // Otherwise, return the proper status. return _breakpointsEnableds[i]; } void SeerEditorWidgetSourceArea::breakpointToggle () { // Get current lineno. int lineno = textCursor().blockNumber() + 1; // If there is a breakpoint on the line, toggle it. if (hasBreakpointLine(lineno)) { // Toggle the breakpoint. // Enable if disabled. Disable if enabled. if (breakpointLineEnabled(lineno) == false) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); }else{ // Emit the disable breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); } // Otherwise, do a quick create of a new breakpoint. }else{ emit insertBreakpoint(QString("-f --source \"%1\" --line %2").arg(fullname()).arg(lineno)); } } void SeerEditorWidgetSourceArea::runToSelectedLine () { // Emit the runToLine signal. emit runToLine(fullname(), currentLine()); } void SeerEditorWidgetSourceArea::showContextMenu (QMouseEvent* event) { #if QT_VERSION >= 0x060000 showContextMenu(event->pos(), event->globalPosition()); #else showContextMenu(event->pos(), event->globalPos()); #endif } void SeerEditorWidgetSourceArea::showContextMenu (QContextMenuEvent* event) { showContextMenu(event->pos(), event->globalPos()); } void SeerEditorWidgetSourceArea::showContextMenu (const QPoint& pos, const QPointF& globalPos) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(pos); int lineno = cursor.blockNumber()+1; // Create the menu actions. QAction* createBreakpointAction; QAction* createPrintpointAction; QAction* deleteAction; QAction* enableAction; QAction* disableAction; QAction* runToLineAction; QAction* openExternalEditor; QAction* addVariableLoggerExpressionAction; QAction* addVariableLoggerAsteriskExpressionAction; QAction* addVariableLoggerAmpersandExpressionAction; QAction* addVariableLoggerAsteriskAmpersandExpressionAction; QAction* addVariableLoggerObjcExpressionAction; QAction* addVariableTrackerExpressionAction; QAction* addVariableTrackerAsteriskExpressionAction; QAction* addVariableTrackerAmpersandExpressionAction; QAction* addVariableTrackerAsteriskAmpersandExpressionAction; QAction* addVariableTrackerObjcExpressionAction; QAction* addMemoryVisualizerAction; QAction* addMemoryAsteriskVisualizerAction; QAction* addMemoryAmpersandVisualizerAction; QAction* addArrayVisualizerAction; QAction* addArrayAsteriskVisualizerAction; QAction* addArrayAmpersandVisualizerAction; QAction* addMatrixVisualizerAction; QAction* addMatrixAsteriskVisualizerAction; QAction* addMatrixAmpersandVisualizerAction; QAction* addStructVisualizerAction; QAction* addStructAsteriskVisualizerAction; QAction* addStructAmpersandVisualizerAction; // Enable/disable them depending if the breakpoint already exists. if (hasBreakpointLine(lineno) == true) { int breakno = breakpointLineToNumber(lineno); runToLineAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg"), QString("Run to line %1").arg(lineno), this); createBreakpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create breakpoint on line %1").arg(lineno), this); createPrintpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create printpoint on line %1").arg(lineno), this); deleteAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/edit-delete.svg"), QString("Delete breakpoint %1 on line %2").arg(breakno).arg(lineno), this); enableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-add.svg"), QString("Enable breakpoint %1 on line %2").arg(breakno).arg(lineno), this); disableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg"), QString("Disable breakpoint %1 on line %2").arg(breakno).arg(lineno), this); openExternalEditor = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Open external editor on line %1").arg(lineno), this); runToLineAction->setEnabled(true); createBreakpointAction->setEnabled(false); createPrintpointAction->setEnabled(false); deleteAction->setEnabled(true); enableAction->setEnabled(true); disableAction->setEnabled(true); openExternalEditor->setEnabled(true); }else{ runToLineAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg"), QString("Run to line %1").arg(lineno), this); createBreakpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create breakpoint on line %1").arg(lineno), this); createPrintpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create printpoint on line %1").arg(lineno), this); deleteAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/edit-delete.svg"), QString("Delete breakpoint on line %1").arg(lineno), this); enableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-add.svg"), QString("Enable breakpoint on line %1").arg(lineno), this); disableAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg"), QString("Disable breakpoint on line %1").arg(lineno), this); openExternalEditor = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Open file in external editor"), this); runToLineAction->setEnabled(true); createBreakpointAction->setEnabled(true); createPrintpointAction->setEnabled(true); deleteAction->setEnabled(false); enableAction->setEnabled(false); disableAction->setEnabled(false); openExternalEditor->setEnabled(true); } addVariableLoggerExpressionAction = new QAction(QString("%1").arg(textCursor().selectedText())); addVariableLoggerAsteriskExpressionAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addVariableLoggerAmpersandExpressionAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); addVariableLoggerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(textCursor().selectedText())); addVariableLoggerObjcExpressionAction = new QAction(QString("(objc)%1").arg(textCursor().selectedText())); addVariableTrackerExpressionAction = new QAction(QString("%1").arg(textCursor().selectedText())); addVariableTrackerAsteriskExpressionAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addVariableTrackerAmpersandExpressionAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); addVariableTrackerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(textCursor().selectedText())); addVariableTrackerObjcExpressionAction = new QAction(QString("(objc)%1").arg(textCursor().selectedText())); addMemoryVisualizerAction = new QAction(QString("%1").arg(textCursor().selectedText())); addMemoryAsteriskVisualizerAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addMemoryAmpersandVisualizerAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); addArrayVisualizerAction = new QAction(QString("%1").arg(textCursor().selectedText())); addArrayAsteriskVisualizerAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addArrayAmpersandVisualizerAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); addMatrixVisualizerAction = new QAction(QString("%1").arg(textCursor().selectedText())); addMatrixAsteriskVisualizerAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addMatrixAmpersandVisualizerAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); addStructVisualizerAction = new QAction(QString("%1").arg(textCursor().selectedText())); addStructAsteriskVisualizerAction = new QAction(QString("*%1").arg(textCursor().selectedText())); addStructAmpersandVisualizerAction = new QAction(QString("&&%1").arg(textCursor().selectedText())); QMenu menu("Breakpoints", this); menu.setTitle("Breakpoints"); menu.addAction(runToLineAction); menu.addAction(createBreakpointAction); menu.addAction(createPrintpointAction); menu.addAction(deleteAction); menu.addAction(enableAction); menu.addAction(disableAction); menu.addAction(openExternalEditor); QMenu loggerMenu("Add variable to Logger"); loggerMenu.addAction(addVariableLoggerExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskExpressionAction); loggerMenu.addAction(addVariableLoggerAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerObjcExpressionAction); menu.addMenu(&loggerMenu); QMenu trackerMenu("Add variable to Tracker"); trackerMenu.addAction(addVariableTrackerExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskExpressionAction); trackerMenu.addAction(addVariableTrackerAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerObjcExpressionAction); menu.addMenu(&trackerMenu); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); // Enable/disable items based on something being selected or not. if (textCursor().selectedText() == "") { addVariableLoggerExpressionAction->setEnabled(false); addVariableLoggerAsteriskExpressionAction->setEnabled(false); addVariableLoggerAmpersandExpressionAction->setEnabled(false); addVariableLoggerAsteriskAmpersandExpressionAction->setEnabled(false); addVariableLoggerObjcExpressionAction->setEnabled(false); addVariableTrackerExpressionAction->setEnabled(false); addVariableTrackerAsteriskExpressionAction->setEnabled(false); addVariableTrackerAmpersandExpressionAction->setEnabled(false); addVariableTrackerAsteriskAmpersandExpressionAction->setEnabled(false); addMemoryVisualizerAction->setEnabled(false); addMemoryAsteriskVisualizerAction->setEnabled(false); addMemoryAmpersandVisualizerAction->setEnabled(false); addArrayVisualizerAction->setEnabled(false); addArrayAsteriskVisualizerAction->setEnabled(false); addArrayAmpersandVisualizerAction->setEnabled(false); addMatrixVisualizerAction->setEnabled(false); addMatrixAsteriskVisualizerAction->setEnabled(false); addMatrixAmpersandVisualizerAction->setEnabled(false); addStructVisualizerAction->setEnabled(false); addStructAsteriskVisualizerAction->setEnabled(false); addStructAmpersandVisualizerAction->setEnabled(false); }else{ addVariableLoggerExpressionAction->setEnabled(true); addVariableLoggerAsteriskExpressionAction->setEnabled(true); addVariableLoggerAmpersandExpressionAction->setEnabled(true); addVariableLoggerAsteriskAmpersandExpressionAction->setEnabled(true); addVariableLoggerObjcExpressionAction->setEnabled(true); addVariableTrackerExpressionAction->setEnabled(true); addVariableTrackerAsteriskExpressionAction->setEnabled(true); addVariableTrackerAmpersandExpressionAction->setEnabled(true); addVariableTrackerAsteriskAmpersandExpressionAction->setEnabled(true); addMemoryVisualizerAction->setEnabled(true); addMemoryAsteriskVisualizerAction->setEnabled(true); addMemoryAmpersandVisualizerAction->setEnabled(true); addArrayVisualizerAction->setEnabled(true); addArrayAsteriskVisualizerAction->setEnabled(true); addArrayAmpersandVisualizerAction->setEnabled(true); addMatrixVisualizerAction->setEnabled(true); addMatrixAsteriskVisualizerAction->setEnabled(true); addMatrixAmpersandVisualizerAction->setEnabled(true); addStructVisualizerAction->setEnabled(true); addStructAsteriskVisualizerAction->setEnabled(true); addStructAmpersandVisualizerAction->setEnabled(true); } // Launch the menu. Get the response. QAction* action = menu.exec(globalPos.toPoint()); // Do nothing. if (action == 0) { return; } // Handle running to a line number. if (action == runToLineAction) { // Emit the runToLine signal. emit runToLine(fullname(), lineno); return; } // Handle creating a new breakpoint. if (action == createBreakpointAction) { SeerBreakpointCreateDialog dlg(this); dlg.setFilename(fullname()); dlg.setLineNumber(QString("%1").arg(lineno)); int ret = dlg.exec(); if (ret == 0) { return; } // Emit the create breakpoint signal. emit insertBreakpoint(dlg.breakpointText()); return; } // Handle creating a new printpoint. if (action == createPrintpointAction) { SeerPrintpointCreateDialog dlg(this); dlg.setFilename(fullname()); dlg.setLineNumber(QString("%1").arg(lineno)); int ret = dlg.exec(); if (ret == 0) { return; } // Build a printpoint specification. QString type = dlg.dprintfType(); QString function = dlg.dprintfFunction(); QString channel = dlg.dprintfChannel(); QString parameters = dlg.printpointParameters(); // If nothing, just return. if (parameters == "" || type == "") { return; } // Emit the create breakpoint signal. emit insertPrintpoint(type, function, channel, parameters); return; } // Handle deleting a breakpoint. if (action == deleteAction) { // Emit the delete breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); return; } // Handle enabling a breakpoint. if (action == enableAction) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); return; } // Handle disabling a breakpoint. if (action == disableAction) { // Emit the disable breakpoint signal. emit disableBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); return; } // Handle open code editor at a line number. if (action == openExternalEditor) { // External editor examples: // $ export SEERGDB_CustomCodeEditor='geany "%{file}":%{line}' // $ export SEERGDB_CustomCodeEditor='kate --line %{line} "%{file}"' // $ export SEERGDB_CustomCodeEditor='gedit "%{file}" +%{line}' // $ export SEERGDB_CustomCodeEditor='konsole -e vim "%{file}" +%{line}' // QString codeEditorCmd = []() { const char* pc = std::getenv("SEERGDB_CustomCodeEditor"); if(pc) return pc; return ""; } (); QString codeEditorCmd = externalEditorCommand(); if (codeEditorCmd == "") { QMessageBox::critical(this, "Error!", "External editor not set.\n\nSee the Editor Config page to set the editor to use."); return; } // Mark cursor as busy. QApplication::setOverrideCursor(Qt::BusyCursor); codeEditorCmd.replace("%{file}", fullname()); codeEditorCmd.replace("%{line}", QString::number(lineno)); QProcess* process = new QProcess(this); process->startCommand(codeEditorCmd); bool f = process->waitForStarted(5000); // Set the cursor back. QApplication::restoreOverrideCursor(); if (f == false) { QMessageBox::critical(this, "Error!", "Launching external editor failed.\n\nCommand: '" + codeEditorCmd + "'"); qDebug().nospace() << "Launching external editor failed. Command: '" << codeEditorCmd << "'"; qDebug().nospace() << "Error: '" << process->error() << "'"; } return; } // Handle adding a variable to log. if (action == addVariableLoggerExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableLoggerExpression(textCursor().selectedText()); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableLoggerExpression(QString("*") + textCursor().selectedText()); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAmpersandExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableLoggerExpression(QString("&") + textCursor().selectedText()); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskAmpersandExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableLoggerExpression(QString("*&") + textCursor().selectedText()); } return; } // Handle adding a variable to log. if (action == addVariableLoggerObjcExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableLoggerExpression(QString("(objc)") + textCursor().selectedText()); } return; } // Handle adding a variable to track. if (action == addVariableTrackerExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableTrackerExpression(textCursor().selectedText()); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableTrackerExpression(QString("*") + textCursor().selectedText()); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAmpersandExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableTrackerExpression(QString("&") + textCursor().selectedText()); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskAmpersandExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableTrackerExpression(QString("*&") + textCursor().selectedText()); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerObjcExpressionAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addVariableTrackerExpression(QString("(objc)") + textCursor().selectedText()); emit refreshVariableTrackerValues(); } return; } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMemoryVisualizer(textCursor().selectedText()); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMemoryVisualizer(QString("*") + textCursor().selectedText()); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMemoryVisualizer(QString("&") + textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addArrayVisualizer(textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addArrayVisualizer(QString("*") + textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addArrayVisualizer(QString("&") + textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addMatrixVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMatrixVisualizer(textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addMatrixAsteriskVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMatrixVisualizer(QString("*") + textCursor().selectedText()); } return; } // Handle adding array to visualize. if (action == addMatrixAmpersandVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addMatrixVisualizer(QString("&") + textCursor().selectedText()); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addStructVisualizer(textCursor().selectedText()); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addStructVisualizer(QString("*") + textCursor().selectedText()); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { // Emit the signals. if (textCursor().selectedText() != "") { emit addStructVisualizer(QString("&") + textCursor().selectedText()); } return; } } void SeerEditorWidgetSourceArea::setQuickBreakpoint (QMouseEvent* event) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(event->pos()); int lineno = cursor.blockNumber()+1; // If there is a breakpoint on the line, toggle it. if (hasBreakpointLine(lineno)) { // Toggle the breakpoint. // Enable if disabled. Disable if enabled. if (breakpointLineEnabled(lineno) == false) { // Emit the enable breakpoint signal. emit enableBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); }else{ // Emit the disable breakpoint signal. emit deleteBreakpoints(QString("%1").arg(breakpointLineToNumber(lineno))); } // Otherwise, do a quick create of a new breakpoint. }else{ emit insertBreakpoint(QString("-f --source \"%1\" --line %2").arg(fullname()).arg(lineno)); } } void SeerEditorWidgetSourceArea::setQuickRunToLine (QMouseEvent* event) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(event->pos()); int lineno = cursor.blockNumber()+1; // Emit the runToLine signal. emit runToLine(fullname(), lineno); return; } void SeerEditorWidgetSourceArea::showBreakpointToolTip (QMouseEvent* event) { // Get the line number for the cursor position. QTextCursor cursor = cursorForPosition(event->pos()); int lineno = cursor.blockNumber()+1; // If there is a breakpoint on the line, ask for its information. if (hasBreakpointLine(lineno)) { _selectedBreakpointPosition = event->pos(); // Emit the info breakpoint signal. emit infoBreakpoint(_selectedBreakpointId, QString("%1").arg(breakpointLineToNumber(lineno))); }else{ _selectedBreakpointPosition = QPoint(); } } void SeerEditorWidgetSourceArea::clearExpression() { _selectedExpressionCursor = QTextCursor(); _selectedExpressionPosition = QPoint(); _selectedExpressionName = ""; _selectedExpressionValue = ""; _selectedBreakpointPosition = QPoint(); } void SeerEditorWidgetSourceArea::setHighlighterSettings (const SeerHighlighterSettings& settings) { _sourceHighlighterSettings = settings; emit highlighterSettingsChanged(); } const SeerHighlighterSettings& SeerEditorWidgetSourceArea::highlighterSettings () const { return _sourceHighlighterSettings; } void SeerEditorWidgetSourceArea::setHighlighterEnabled (bool flag) { _sourceHighlighterEnabled = flag; emit highlighterSettingsChanged(); } bool SeerEditorWidgetSourceArea::highlighterEnabled () const { return _sourceHighlighterEnabled; } void SeerEditorWidgetSourceArea::setEditorFont (const QFont& font) { setFont(font); invalidateMiniMapCache(); /* * None of the tabstops work. Setting tabstops never look the same * as replacing tabs with spaces. Not sure why. * Tried setTabStopDistance() and setTabArray(). Same problem. * Zooming in and out in QPlainTextEdit will also result in bad * tabstops. QFont f = font; f.setLetterSpacing(QFont::PercentageSpacing, 100); f.setWordSpacing(0.0); f.setFixedPitch(true); f.setKerning(false); setFont(f); qreal tabspace = fontMetrics().horizontalAdvance(QLatin1Char(' ')) * 4; //setTabStopDistance(tabspace); QList tabstops; qreal tabpos = 0.0; for (int i=0; i<100; i++) { tabstops.append(tabpos); tabpos += tabspace; } QTextOption opt = document()->defaultTextOption(); opt.setFlags(QTextOption::ShowTabsAndSpaces); opt.setTabArray(tabstops); document()->setDefaultTextOption(opt); */ } const QFont& SeerEditorWidgetSourceArea::editorFont () const { return font(); } void SeerEditorWidgetSourceArea::setEditorTabSize (int spaces) { _sourceTabSize = spaces; } int SeerEditorWidgetSourceArea::editorTabSize () const { return _sourceTabSize; } void SeerEditorWidgetSourceArea::setExternalEditorCommand (const QString& externalEditorCommand) { _externalEditorCommand = externalEditorCommand; } const QString& SeerEditorWidgetSourceArea::externalEditorCommand () { return _externalEditorCommand; } void SeerEditorWidgetSourceArea::setAutoSourceReload (bool flag) { _autoSourceReload = flag; } bool SeerEditorWidgetSourceArea::autoSourceReload () const { return _autoSourceReload; } void SeerEditorWidgetSourceArea::eraseColorCurrentLine (int lineno) { // Erase color of this line QTextCharFormat lineFormat; lineFormat = highlighterSettings().get("Text"); // Create a selection at the cursor. QTextBlock block = document()->findBlockByLineNumber(lineno-1); QTextCursor cursor = textCursor(); cursor.setPosition(block.position()); QTextEdit::ExtraSelection selection; selection.format.setForeground(lineFormat.foreground()); selection.format.setBackground(lineFormat.background()); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = cursor; selection.cursor.clearSelection(); // Add it to the extra selection list. _currentLinesExtraSelections.append(selection); // Refresh all the extra selections. refreshExtraSelections(); } // Read current position in the source area: file name, line, column of cursor and first displayed line SeerEditorWidgetSourceArea::SeerCurrentFile SeerEditorWidgetSourceArea::readCurrentPosition() { SeerCurrentFile info; info.file = QFileInfo(file()).fileName(); // extract file name from full path info.fullname = fullname(); info.cursorRow = currentLine(); info.cursorCol = currentColumn(); info.firstDisplayLine = firstDisplayLine(); return info; } void SeerEditorWidgetSourceArea::handleText (const QString& text) { if (text.startsWith("*stopped")) { // *stopped, // // reason="end-stepping-range", // // frame={addr="0x0000000000400b45", // func="main", // args=[{name="argc",value="1"},{name="argv",value="0x7fffffffd5b8"}], // file="helloworld.cpp", // fullname="/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp", // line="7", // arch="i386:x86-64"}, // // thread-id="1", // stopped-threads="all", // core="6" QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "frame=", '{', '}', false); if (frame_text == "") { return; } QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); // Read the file if it hasn't been read before or if we are reading a different file. if (fullname_text != fullname()) { open(fullname_text, QFileInfo(file_text).fileName()); } // Move to the line number. setCurrentLine(line_text.toInt()); return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // 10^done,value="1" // 11^done,value="0x7fffffffd538" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _selectedExpressionId) { _selectedExpressionValue = Seer::filterEscapes(Seer::parseFirst(text, "value=", '"', '"', false)); showExpressionTooltip(); } return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,BreakpointTable="))) { // 11^done,BreakpointTable={...} QString id_text = text.section('^', 0,0); if (id_text.toInt() == _selectedBreakpointId && _selectedBreakpointPosition != QPoint()) { handleBreakpointToolTip(_selectedBreakpointPosition, text); } return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // 12^error,msg="No symbol \"return\" in current context." // 13^error,msg="No symbol \"cout\" in current context." QString id_text = text.section('^', 0,0); if (id_text.toInt() == _selectedExpressionId) { _selectedExpressionValue = Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)); // Refresh the tooltip event. QHelpEvent* event = new QHelpEvent(QEvent::ToolTip, _selectedExpressionPosition, this->mapToGlobal(_selectedExpressionPosition)); QCoreApplication::postEvent(this, event); } if (id_text.toInt() == _selectedBreakpointId && _selectedBreakpointPosition != QPoint()) { qDebug() << "Error displaying breakpoint info as a ToolTip"; } return; }else{ // Ignore others. return; } } void SeerEditorWidgetSourceArea::handleHighlighterSettingsChanged () { // Set base color for background and text color. // Use the palette to do this. Some people say to use the stylesheet. // But the palettle method works (for now). QTextCharFormat format = highlighterSettings().get("Text"); QPalette p = palette(); p.setColor(QPalette::Base, format.background().color()); p.setColor(QPalette::Text, format.foreground().color()); setPalette(p); // Update the syntax highlighter. if (_sourceHighlighter) { delete _sourceHighlighter; _sourceHighlighter = 0; } SeerSourceHighlighter* highlighter = SeerSourceHighlighter::getSourceHighlighter(_file, _sourceHighlighterSettings); if (highlighter) { _sourceHighlighter = highlighter; if (highlighterEnabled()) { _sourceHighlighter->setDocument(document()); }else{ _sourceHighlighter->setDocument(0); } _sourceHighlighter->setHighlighterSettings(highlighterSettings()); _sourceHighlighter->rehighlight(); } // Note. The margins are automatically updated by their own paint events. // The new highlighter settings will be used. invalidateMiniMapCache(); } void SeerEditorWidgetSourceArea::handleWatchFileModified (const QString& path) { Q_UNUSED(path); emit showReloadBar(true); } void SeerEditorWidgetSourceArea::handleBreakpointToolTip (QPoint pos, const QString& text) { // 11^7^done,BreakpointTable={...} // 7^done,BreakpointTable={ // nr_rows="1", // nr_cols="6", // hdr=[], // body=[ // bkpt={ // number="2", // type="breakpoint", // disp="keep", // enabled="y", // addr="0x0000000000400ccd", // func="main(int, char**)", // file="helloworld.cpp", // fullname="/nas/erniep/Development/seer/tests/helloworld/helloworld.cpp", // line="30", // thread-groups=["i1"], // times="1", // original-location="-source /nas/erniep/Development/seer/tests/helloworld/helloworld.cpp -line 30" // } // ] // } QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString tooltiptext; // // Parse 'body' text. // QString body_text = Seer::parseFirst(newtext, "body=", '[', ']', false); if (body_text != "") { QStringList bkpt_list = Seer::parse(body_text, "bkpt=", '{', '}', false); // Construct the tooltip. tooltiptext += "Breakpoint information\n\n"; for (const auto& bkpt_text : bkpt_list) { QStringList item_list = Seer::parseCommaList(bkpt_text); for (const auto& item_text : item_list) { tooltiptext += item_text + "\n"; } break; // Take the first breakpoint in case, somehow, more are returned. } } QToolTip::showText(mapToGlobal(pos), tooltiptext); } // // LineNumber area. // SeerEditorWidgetSourceLineNumberArea::SeerEditorWidgetSourceLineNumberArea(SeerEditorWidgetSourceArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetSourceLineNumberArea::sizeHint () const { return QSize(_editorWidget->lineNumberAreaWidth(), 0); } void SeerEditorWidgetSourceLineNumberArea::paintEvent (QPaintEvent* event) { _editorWidget->lineNumberAreaPaintEvent(event); } void SeerEditorWidgetSourceLineNumberArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToLine(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetSourceLineNumberArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetSourceLineNumberArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetSourceLineNumberArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } // // Breakpoints Area. // SeerEditorWidgetSourceBreakPointArea::SeerEditorWidgetSourceBreakPointArea(SeerEditorWidgetSourceArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; } QSize SeerEditorWidgetSourceBreakPointArea::sizeHint () const { return QSize(_editorWidget->breakPointAreaWidth(), 0); } void SeerEditorWidgetSourceBreakPointArea::paintEvent (QPaintEvent* event) { _editorWidget->breakPointAreaPaintEvent(event); } void SeerEditorWidgetSourceBreakPointArea::mouseDoubleClickEvent (QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) { _editorWidget->setQuickRunToLine(event); }else{ _editorWidget->setQuickBreakpoint(event); } }else{ QWidget::mouseDoubleClickEvent(event); } } void SeerEditorWidgetSourceBreakPointArea::mouseMoveEvent (QMouseEvent* event) { QWidget::mouseMoveEvent(event); } void SeerEditorWidgetSourceBreakPointArea::mousePressEvent (QMouseEvent* event) { if (event->button() == Qt::RightButton) { _editorWidget->showContextMenu(event); }else if (event->button() == Qt::LeftButton) { _editorWidget->showBreakpointToolTip(event); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetSourceBreakPointArea::mouseReleaseEvent (QMouseEvent* event) { QWidget::mouseReleaseEvent(event); } SeerEditorWidgetSourceMiniMapArea::SeerEditorWidgetSourceMiniMapArea(SeerEditorWidgetSourceArea* editorWidget) : QWidget(editorWidget) { _editorWidget = editorWidget; _dragging = false; _dragStartY = 0; _dragStartValue = 0; _preview = new SeerPlainTextMiniMapPreview(this); _scrollTipTimer = new QTimer(this); // Hide the visible-lines tooltip once wheel scrolling stops. _scrollTipTimer->setSingleShot(true); _scrollTipTimer->setInterval(1000); QObject::connect(_scrollTipTimer, &QTimer::timeout, this, []() { QToolTip::hideText(); }); setMouseTracking(true); } QSize SeerEditorWidgetSourceMiniMapArea::sizeHint () const { return QSize(_editorWidget->miniMapAreaWidth(), 0); } void SeerEditorWidgetSourceMiniMapArea::paintEvent (QPaintEvent* event) { _editorWidget->miniMapAreaPaintEvent(event); } void SeerEditorWidgetSourceMiniMapArea::mousePressEvent (QMouseEvent* event) { _preview->hide(); if (event->button() == Qt::LeftButton) { // Clicking outside the overlay jumps there. Then (or when clicking // inside the overlay) dragging moves the overlay with the mouse. QRectF overlay = SeerPlainTextMiniMap::overlayRect(_editorWidget, width(), height()); if (overlay.contains(overlay.center().x(), event->pos().y()) == false) { _editorWidget->jumpToMiniMapY(event->pos().y()); } _dragging = true; _dragStartY = event->pos().y(); _dragStartValue = _editorWidget->verticalScrollBar()->value(); SeerPlainTextMiniMap::showVisibleLinesTip(_editorWidget, this, mapToGlobal(event->pos())); }else{ QWidget::mousePressEvent(event); } } void SeerEditorWidgetSourceMiniMapArea::mouseMoveEvent (QMouseEvent* event) { if (_dragging && (event->buttons() & Qt::LeftButton)) { int value = SeerPlainTextMiniMap::dragValue(_editorWidget, height(), _dragStartValue, event->pos().y() - _dragStartY); _editorWidget->verticalScrollBar()->setValue(value); SeerPlainTextMiniMap::showVisibleLinesTip(_editorWidget, this, mapToGlobal(event->pos())); return; } // Hovering shows a preview of the code under the mouse. int y = event->pos().y(); if (event->buttons() == Qt::NoButton && y >= 0 && y < _editorWidget->document()->blockCount() * SeerPlainTextMiniMap::pixelsPerLine(_editorWidget, height())) { const SeerHighlighterSettings& settings = _editorWidget->highlighterSettings(); QTextCharFormat textFormat = settings.get("Text"); QTextCharFormat currentLineFormat = settings.get("Current Line"); QRect globalRect (mapToGlobal(QPoint(0, 0)), size()); int lineno = SeerPlainTextMiniMap::lineAt(_editorWidget, height(), y); _preview->showPreview(_editorWidget, lineno, globalRect, mapToGlobal(event->pos()).y(), textFormat.background().color(), textFormat.foreground().color(), currentLineFormat.background().color()); }else{ _preview->hide(); } QWidget::mouseMoveEvent(event); } void SeerEditorWidgetSourceMiniMapArea::mouseReleaseEvent (QMouseEvent* event) { _dragging = false; QToolTip::hideText(); QWidget::mouseReleaseEvent(event); } void SeerEditorWidgetSourceMiniMapArea::leaveEvent (QEvent* event) { _preview->hide(); QWidget::leaveEvent(event); } void SeerEditorWidgetSourceMiniMapArea::wheelEvent (QWheelEvent* event) { // The wheel itself is forwarded to the editor (see SeerPlainTextWheelEventForwarder), // which has already scrolled by now. _preview->hide(); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) SeerPlainTextMiniMap::showVisibleLinesTip(_editorWidget, this, event->globalPosition().toPoint()); #else SeerPlainTextMiniMap::showVisibleLinesTip(_editorWidget, this, event->globalPos()); #endif _scrollTipTimer->start(); QWidget::wheelEvent(event); } /*********************************************************************************************************************** * Functions for mouse navigation feature * **********************************************************************************************************************/ void SeerEditorWidgetSourceArea::mousePressEvent(QMouseEvent *event) { // This part is for mouse navigation feature if (event->button() == Qt::XButton1 || event->button() == Qt::XButton2) { // Avoid the default back/forward action _ignoreThumbMouseEvent ++; SeerCurrentFile firstInfo = readCurrentPosition(); // _ignoreThumbMouseEvent will incremented in mousePressEvent when thumb mouse button is pressed but it may not be decremented // if user just click the thumb mouse button without moving the cursor. So here we check if the position is the same as last time, // which means cursor didn't move, then we reset _ignoreThumbMouseEvent to 0 to avoid blocking future events. QTimer::singleShot(30, this, [this, firstInfo]() { // let's give 30 ms for cursor to move to new position SeerCurrentFile secondInfo = readCurrentPosition(); if (firstInfo == secondInfo) { // cursor didn't move _ignoreThumbMouseEvent = 0; // reset to 0 } } ); } // This part is for Go to definition (Ctrl + Click) feature if (event->button() == Qt::LeftButton && _altHeld) { if (_wordUnderCursor != "") { QApplication::restoreOverrideCursor(); signalGotoDefinition(_wordUnderCursor); event->ignore(); // If we don't ignore the event, the cursor will move to that position, which is not desired return; } } QPlainTextEdit::mousePressEvent(event); } void SeerEditorWidgetSourceArea::handleCursorPositionChanged() { // Emit signal to SeerEditorManagerWidget.cpp and save position // Read current position, deploy a timer SeerCurrentFile firstInfo = readCurrentPosition(); if (_ignoreThumbMouseEvent > 0) { _ignoreThumbMouseEvent --; return; } QTimer::singleShot(2000, this, [this, firstInfo]() { SeerCurrentFile secondInfo = readCurrentPosition(); if (firstInfo == secondInfo) { emit addToMouseNavigation(firstInfo); } } ); } /*********************************************************************************************************************** * Go to definition (F12) feature * **********************************************************************************************************************/ void SeerEditorWidgetSourceArea::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Alt) { _altHeld = true; } QPlainTextEdit::keyPressEvent(event); } void SeerEditorWidgetSourceArea::keyReleaseEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Alt) { _altHeld = false; } QPlainTextEdit::keyReleaseEvent(event); } bool SeerEditorWidgetSourceArea::isOverWord(const QPoint &pos) { QTextCursor cursor = cursorForPosition(pos); cursor.select(QTextCursor::WordUnderCursor); return !cursor.selectedText().isEmpty(); } QString SeerEditorWidgetSourceArea::wordUnderCursor(const QPoint &pos) const { int leftMarginOffset = 0; QMargins margins = viewportMargins(); QPoint adjustedPos = pos; // The correct position to get the word under cursor should subtract the left margin // offset (breakpoint area and line number area) leftMarginOffset = margins.left(); adjustedPos.setX(pos.x() - leftMarginOffset); QTextCursor cursor = cursorForPosition(adjustedPos); cursor.select(QTextCursor::WordUnderCursor); return cursor.selectedText(); } void SeerEditorWidgetSourceArea::updateCursor(const QPoint &pos) { // Why not QApplication::setOverrideCursor()? Because QApplication::setOverrideCursor uses internal stack // It causes delay and sometimes the cursor won't change back to normal when we want it to. // In short, QApplication::setOverrideCursor is global and not real time // In contrary, viewport()->setCursor() is local and real time, apply only for that widget, in this case, the text area QPoint localPos = mapFromGlobal(pos); if (!_altHeld) { viewport()->setCursor(Qt::IBeamCursor); _wordUnderCursor = ""; return; } if (!hasFocus()) return; _wordUnderCursor = wordUnderCursor(localPos); if (isValidIdentifier(_wordUnderCursor)) { viewport()->setCursor(Qt::PointingHandCursor); } else { viewport()->setCursor(Qt::IBeamCursor); _wordUnderCursor = ""; } } // Check text and decide if that text is valid identifier (function, variable, type name) bool SeerEditorWidgetSourceArea::isValidIdentifier(const QString& text) { static const QSet keywords = { // Add your C and C++ keywords as QString literals here "auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "restrict", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local", "alignas", "alignof", "and", "and_eq", "asm", "bitand", "bitor", "bool", "catch", "char16_t", "char32_t", "class", "compl", "const_cast", "constexpr", "decltype", "delete", "dynamic_cast", "explicit", "export", "false", "friend", "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", "public", "reinterpret_cast", "static_assert", "static_cast", "template", "this", "thread_local", "throw", "true", "try", "typeid", "typename", "using", "virtual", "wchar_t", "xor", "xor_eq" }; if (text.isEmpty()) return false; if (keywords.contains(text)) return false; QChar firstChar = text[0]; if (!firstChar.isLetter() && firstChar != '_') return false; for (int i = 1; i < text.size(); ++i) { QChar ch = text[i]; if (!ch.isLetterOrNumber() && ch != '_') return false; } return true; } // When F12 is pressed, try to look for the word under cursor, if it's a valid identifier then emit signalGotoDefinition void SeerEditorWidgetSourceArea::handleGotoDefinition() { QTextCursor cursor = textCursor(); cursor.select(QTextCursor::WordUnderCursor); QString wordUnderCursor = cursor.selectedText(); if (isValidIdentifier(wordUnderCursor)) { emit signalGotoDefinition(wordUnderCursor); } } epasveer-seer-97076f1/src/SeerExecutableFilterProxyModel.h000066400000000000000000000014401526321767600236140ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerExecutableFilterProxyModel : public QSortFilterProxyModel { bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { QFileSystemModel* fileModel = qobject_cast(sourceModel()); QFileInfo file(fileModel->filePath(sourceModel()->index(sourceRow, 0, sourceParent))); /* if (fileModel != NULL) { return false; } */ if (file.isExecutable() == true || file.isHidden()) { return true; }else{ return false; } } }; epasveer-seer-97076f1/src/SeerFortranSourceHighlighter.cpp000066400000000000000000000206711526321767600236570ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerFortranSourceHighlighter.h" SeerFortranSourceHighlighter::SeerFortranSourceHighlighter(QTextDocument *parent) : SeerSourceHighlighter(parent) { // Set to default formats. setHighlighterSettings(SeerHighlighterSettings::populate("")); } void SeerFortranSourceHighlighter::setHighlighterSettings(const SeerHighlighterSettings &settings) { _highlighterSettings = settings; _classFormat = _highlighterSettings.get("Class"); _quotationFormat = _highlighterSettings.get("Quotation"); _functionFormat = _highlighterSettings.get("Function"); _singleLineCommentFormat = _highlighterSettings.get("Comment"); _multiLineCommentFormat = _highlighterSettings.get("Multiline Comment"); _keywordFormat = _highlighterSettings.get("Keyword"); // Free-form Fortran (90 and later). const QString keywordPatterns[] = { QStringLiteral("\\babstract\\b"), QStringLiteral("\\ballocatable\\b"), QStringLiteral("\\ballocate\\b"), QStringLiteral("\\bassignment\\b"), QStringLiteral("\\bassociate\\b"), QStringLiteral("\\basynchronous\\b"), QStringLiteral("\\bbackspace\\b"), QStringLiteral("\\bbind\\b"), QStringLiteral("\\bblock\\b"), QStringLiteral("\\bcall\\b"), QStringLiteral("\\bcase\\b"), QStringLiteral("\\bcharacter\\b"), QStringLiteral("\\bclass\\b"), QStringLiteral("\\bclose\\b"), QStringLiteral("\\bcommon\\b"), QStringLiteral("\\bcomplex\\b"), QStringLiteral("\\bconcurrent\\b"), QStringLiteral("\\bcontains\\b"), QStringLiteral("\\bcontinue\\b"), QStringLiteral("\\bcritical\\b"), QStringLiteral("\\bcycle\\b"), QStringLiteral("\\bdata\\b"), QStringLiteral("\\bdeallocate\\b"), QStringLiteral("\\bdefault\\b"), QStringLiteral("\\bdimension\\b"), QStringLiteral("\\bdo\\b"), QStringLiteral("\\bdouble\\b"), QStringLiteral("\\belemental\\b"), QStringLiteral("\\belse\\b"), QStringLiteral("\\belseif\\b"), QStringLiteral("\\belsewhere\\b"), QStringLiteral("\\bend\\b"), QStringLiteral("\\benddo\\b"), QStringLiteral("\\bendfile\\b"), QStringLiteral("\\bendif\\b"), QStringLiteral("\\bentry\\b"), QStringLiteral("\\benum\\b"), QStringLiteral("\\benumerator\\b"), QStringLiteral("\\bequivalence\\b"), QStringLiteral("\\berror\\b"), QStringLiteral("\\bexit\\b"), QStringLiteral("\\bextends\\b"), QStringLiteral("\\bexternal\\b"), QStringLiteral("\\bfinal\\b"), QStringLiteral("\\bforall\\b"), QStringLiteral("\\bformat\\b"), QStringLiteral("\\bfunction\\b"), QStringLiteral("\\bgeneric\\b"), QStringLiteral("\\bgoto\\b"), QStringLiteral("\\bif\\b"), QStringLiteral("\\bimplicit\\b"), QStringLiteral("\\bimport\\b"), QStringLiteral("\\binclude\\b"), QStringLiteral("\\binout\\b"), QStringLiteral("\\binquire\\b"), QStringLiteral("\\binteger\\b"), QStringLiteral("\\bintent\\b"), QStringLiteral("\\binterface\\b"), QStringLiteral("\\bintrinsic\\b"), QStringLiteral("\\bkind\\b"), QStringLiteral("\\blen\\b"), QStringLiteral("\\blogical\\b"), QStringLiteral("\\bmodule\\b"), QStringLiteral("\\bnamelist\\b"), QStringLiteral("\\bnone\\b"), QStringLiteral("\\bnullify\\b"), QStringLiteral("\\bonly\\b"), QStringLiteral("\\bopen\\b"), QStringLiteral("\\boperator\\b"), QStringLiteral("\\boptional\\b"), QStringLiteral("\\bparameter\\b"), QStringLiteral("\\bpointer\\b"), QStringLiteral("\\bprecision\\b"), QStringLiteral("\\bprint\\b"), QStringLiteral("\\bprivate\\b"), QStringLiteral("\\bprocedure\\b"), QStringLiteral("\\bprogram\\b"), QStringLiteral("\\bprotected\\b"), QStringLiteral("\\bpublic\\b"), QStringLiteral("\\bpure\\b"), QStringLiteral("\\bread\\b"), QStringLiteral("\\breal\\b"), QStringLiteral("\\brecursive\\b"), QStringLiteral("\\bresult\\b"), QStringLiteral("\\breturn\\b"), QStringLiteral("\\brewind\\b"), QStringLiteral("\\bsave\\b"), QStringLiteral("\\bselect\\b"), QStringLiteral("\\bsequence\\b"), QStringLiteral("\\bstop\\b"), QStringLiteral("\\bsubmodule\\b"), QStringLiteral("\\bsubroutine\\b"), QStringLiteral("\\btarget\\b"), QStringLiteral("\\bthen\\b"), QStringLiteral("\\btype\\b"), QStringLiteral("\\buse\\b"), QStringLiteral("\\bvalue\\b"), QStringLiteral("\\bvolatile\\b"), QStringLiteral("\\bwhere\\b"), QStringLiteral("\\bwhile\\b"), QStringLiteral("\\bwrite\\b"), // Dotted logical/relational operators and constants. (The symbolic // forms '==', '/=', ... are left unstyled, like in the C++ highlighter.) QStringLiteral("\\.and\\."), QStringLiteral("\\.or\\."), QStringLiteral("\\.not\\."), QStringLiteral("\\.eqv\\."), QStringLiteral("\\.neqv\\."), QStringLiteral("\\.true\\."), QStringLiteral("\\.false\\."), QStringLiteral("\\.eq\\."), QStringLiteral("\\.ne\\."), QStringLiteral("\\.lt\\."), QStringLiteral("\\.le\\."), QStringLiteral("\\.gt\\."), QStringLiteral("\\.ge\\."), }; _highlightingRules.clear(); // Clear old rules. HighlightingRule rule; // No class rule: Fortran is case insensitive with no reliable case convention, // and derived types are already covered by the 'type'/'class' keywords. // No function rule either: 'name(...)' is also how Fortran references arrays, // so highlighting it as a function call would be wrong half of the time. // Set keywords format and expression. // Fortran is case insensitive, so we use case insensitive option. for (const QString &pattern : keywordPatterns) { rule.pattern = QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption); rule.format = _keywordFormat; _highlightingRules.append(rule); } // Set keyword format for the symbolic operators too, so '==' renders like // its word form '.eq.'. Safe in Fortran: no templates, '<'/'>' are always // relational. Two-character operators first in the alternation. rule.pattern = QRegularExpression(QStringLiteral("//|==|/=|<=|>=|=>|<|>")); rule.format = _keywordFormat; _highlightingRules.append(rule); // Set function format for the common intrinsics, when actually called. // A generic before-parenthesis rule is out (see above), but a closed list // of intrinsics followed by '(' is safe. As a side effect, 'len'/'kind' // stay keywords in declarations ('len=32') and become functions in calls. rule.pattern = QRegularExpression(QStringLiteral( "\\b(?:abs|achar|adjustl|adjustr|aimag|allocated|associated|atan2?|ceiling|char|cmplx|conjg|cosh?|count" "|cpu_time|dble|dot_product|epsilon|exp|floor|huge|iachar|index|int|kind|lbound|len|len_trim|log|log10" "|matmul|max|maxval|merge|min|minval|mod|modulo|nint|norm2|pack|present|product|random_number|random_seed" "|real|repeat|reshape|scan|sign|sinh?|size|spread|sqrt|sum|system_clock|tanh?|tiny|transfer|transpose" "|trim|ubound|unpack|verify)\\b(?=\\s*\\()"), QRegularExpression::CaseInsensitiveOption); rule.format = _functionFormat; _highlightingRules.append(rule); // Set quote format and expression. Fortran strings use either quote character. rule.pattern = QRegularExpression(QStringLiteral("\"[^\"]*\"")); rule.format = _quotationFormat; _highlightingRules.append(rule); rule.pattern = QRegularExpression(QStringLiteral("'[^']*'")); rule.format = _quotationFormat; _highlightingRules.append(rule); // Set single line comment format and expression. (Fortran uses !) // Note '//' is the string concatenation operator in Fortran, not a comment. rule.pattern = QRegularExpression(QStringLiteral("![^\n]*")); rule.format = _singleLineCommentFormat; _highlightingRules.append(rule); // Multi-line comments are not possible in Fortran. // Using a regex that matches nothing to avoid any unintended highlighting. _commentStartExpression = QRegularExpression(QStringLiteral("(?!)")); _commentEndExpression = QRegularExpression(QStringLiteral("(?!)")); } epasveer-seer-97076f1/src/SeerFortranSourceHighlighter.h000066400000000000000000000007351526321767600233230ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerHighlighterSettings.h" #include "SeerSourceHighlighter.h" class SeerFortranSourceHighlighter : public SeerSourceHighlighter { Q_OBJECT public: SeerFortranSourceHighlighter(QTextDocument *parent = 0); virtual void setHighlighterSettings (const SeerHighlighterSettings &settings) override; }; epasveer-seer-97076f1/src/SeerFunctionBrowserWidget.cpp000066400000000000000000000246651526321767600232100ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerFunctionBrowserWidget.h" #include "SeerBreakpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include SeerFunctionBrowserWidget::SeerFunctionBrowserWidget (QWidget* parent) : QWidget(parent) { // Set the state. _id = Seer::createID(); // Construct the UI. setupUi(this); // Setup the widgets functionSearchLineEdit->setPlaceholderText("Search regex..."); functionSearchLineEdit->setClearButtonEnabled(true); functionTreeWidget->setMouseTracking(true); functionTreeWidget->setSortingEnabled(false); functionTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); //functionTreeWidget->resizeColumnToContents(0); // Name functionTreeWidget->resizeColumnToContents(1); // Filename functionTreeWidget->resizeColumnToContents(2); // Line number functionTreeWidget->resizeColumnToContents(3); // Fullname functionTreeWidget->resizeColumnToContents(4); // Type functionTreeWidget->resizeColumnToContents(5); // Description functionTreeWidget->clear(); // Connect things. QObject::connect(functionTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerFunctionBrowserWidget::handleItemDoubleClicked); QObject::connect(functionTreeWidget, &QTreeWidget::itemEntered, this, &SeerFunctionBrowserWidget::handleItemEntered); QObject::connect(functionTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerFunctionBrowserWidget::handleContextMenu); QObject::connect(functionSearchLineEdit, &QLineEdit::returnPressed, this, &SeerFunctionBrowserWidget::handleSearchLineEdit); } SeerFunctionBrowserWidget::~SeerFunctionBrowserWidget () { } void SeerFunctionBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith(QString::number(_id) + "^done,symbols={") && text.endsWith("}")) { functionTreeWidget->clear(); functionTreeWidget->setSortingEnabled(false); functionTreeWidget->sortByColumn(-1, Qt::AscendingOrder); // -symbol-info-functions // ^done,symbols={ // debug=[ // { // filename="elf-init.c", // fullname="/home/abuild/rpmbuild/BUILD/glibc-2.31/csu/elf-init.c", // symbols=[ // { // line="95", // name="__libc_csu_fini", // type="void (void)", // description="void __libc_csu_fini(void);" // }, // { // line="67", // name="__libc_csu_init", // type="void (int, char **, char **)", // description="void __libc_csu_init(int, char **, char **);" // } // ] // }, // ... // ] // } QString debug_text = Seer::parseFirst(text, "debug=", '[', ']', false); QStringList filenames_list = Seer::parse(debug_text, "", '{', '}', false); for (const auto& filename_entry : filenames_list) { QString filename_text = Seer::parseFirst(filename_entry, "filename=", '"', '"', false); QString fullname_text = Seer::parseFirst(filename_entry, "fullname=", '"', '"', false); QString symbols_text = Seer::parseFirst(filename_entry, "symbols=", '[', ']', false); QStringList symbols_list = Seer::parse(symbols_text, "", '{', '}', false); for (const auto& symbol_entry : symbols_list) { QString line_text = Seer::parseFirst(symbol_entry, "line=", '"', '"', false); QString name_text = Seer::parseFirst(symbol_entry, "name=", '"', '"', false); QString type_text = Seer::parseFirst(symbol_entry, "type=", '"', '"', false); QString description_text = Seer::parseFirst(symbol_entry, "type=", '"', '"', false); // Skip function entries that have no line number. if (line_text == "") { continue; } // Add the function to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; QFont f0 = item->font(0); f0.setBold(true); item->setFont(0,f0); item->setText(0, name_text); item->setText(1, filename_text); item->setText(2, line_text); item->setText(3, fullname_text); item->setText(4, type_text); item->setText(5, description_text); functionTreeWidget->addTopLevelItem(item); } } // ---- // -symbol-info-functions // ^done,symbols={ // nondebug=[ // {address="0x0000555555554720",name="putchar@plt"}, // {address="0x00007ffff7c40031",name="putchar[cold]"}, // {address="0x00007ffff7c9561e",name="putchar"}, // {address="0x00007ffff7c9579e",name="putchar_unlocked"} // ] // } QString nondebug_text = Seer::parseFirst(text, "nondebug=", '[', ']', false); QStringList nondebug_list = Seer::parse(nondebug_text, "", '{', '}', false); for (const auto& nondebug_entry : nondebug_list) { QString address_text = Seer::parseFirst(nondebug_entry, "address=", '"', '"', false); QString name_text = Seer::parseFirst(nondebug_entry, "name=", '"', '"', false); // Add the function to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; QFont f0 = item->font(0); f0.setBold(true); item->setFont(0,f0); item->setText(0, name_text); item->setText(1, address_text); functionTreeWidget->addTopLevelItem(item); } }else{ // Ignore others. } //functionTreeWidget->resizeColumnToContents(0); functionTreeWidget->resizeColumnToContents(1); functionTreeWidget->resizeColumnToContents(2); functionTreeWidget->resizeColumnToContents(3); functionTreeWidget->resizeColumnToContents(4); functionTreeWidget->resizeColumnToContents(5); functionTreeWidget->sortByColumn(0, Qt::AscendingOrder); functionTreeWidget->setSortingEnabled(true); QApplication::restoreOverrideCursor(); } void SeerFunctionBrowserWidget::handleSessionTerminated () { // Delete previous contents. functionTreeWidget->clear(); } void SeerFunctionBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedFile(item->text(1), item->text(3), item->text(2).toInt()); } void SeerFunctionBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); QString tip = QString("Function: %1\nFile: %2\nLine: %3\nFullname: %4\nType: %5\nDescription: %6").arg(item->text(0)).arg(item->text(1)).arg(item->text(2)).arg(item->text(3)).arg(item->text(4)).arg(item->text(5)); item->setToolTip(0, tip); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerFunctionBrowserWidget::handleSearchLineEdit () { functionTreeWidget->clear(); functionTreeWidget->setSortingEnabled(false); functionTreeWidget->sortByColumn(-1, Qt::AscendingOrder); //functionTreeWidget->resizeColumnToContents(0); functionTreeWidget->resizeColumnToContents(1); functionTreeWidget->resizeColumnToContents(2); functionTreeWidget->resizeColumnToContents(3); functionTreeWidget->resizeColumnToContents(4); functionTreeWidget->resizeColumnToContents(5); if (functionSearchLineEdit->text() != "") { emit refreshFunctionList(_id, functionSearchLineEdit->text()); } } void SeerFunctionBrowserWidget::refresh () { handleSearchLineEdit(); } void SeerFunctionBrowserWidget::handleContextMenu (const QPoint& pos) { // Get the item at the cursor. QTreeWidgetItem* item = functionTreeWidget->itemAt(pos); if (item == 0) { return; } // Create the menu actions. QAction* createBreakpointAction; QAction* createSkipAction; createBreakpointAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create breakpoint in function: \"%1\"").arg(item->text(0)), this); createSkipAction = new QAction(QIcon(":/seer/resources/RelaxLightIcons/document-new.svg"), QString("Create skip for function: \"%1\"").arg(item->text(0)), this); QMenu menu("Breakpoints", this); menu.setTitle("Breakpoints"); menu.addAction(createBreakpointAction); menu.addAction(createSkipAction); // Launch the menu. Get the response. QAction* action = menu.exec(functionTreeWidget->mapToGlobal(pos + QPoint(0,20))); // Do nothing. if (action == 0) { return; } if (action == createBreakpointAction) { SeerBreakpointCreateDialog dlg(this); dlg.setFunctionName(item->text(0)); dlg.setLineNumber(item->text(2)); dlg.setFilename(item->text(3)); int ret = dlg.exec(); if (ret == 0) { return; } // Emit the create breakpoint signal. emit insertBreakpoint(dlg.breakpointText()); return; } if (action == createSkipAction) { // Emit the create skip signal. emit addSkip("function", item->text(0)); return; } } epasveer-seer-97076f1/src/SeerFunctionBrowserWidget.h000066400000000000000000000027161526321767600226460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerFunctionBrowserWidget.h" class SeerFunctionBrowserWidget : public QWidget, protected Ui::SeerFunctionBrowserWidgetForm { Q_OBJECT public: explicit SeerFunctionBrowserWidget (QWidget* parent = 0); ~SeerFunctionBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (); void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); void handleContextMenu (const QPoint& pos); signals: void refreshFunctionList (int id, const QString& functionRegex); void selectedFile (QString file, QString fullname, int lineno); void insertBreakpoint (QString breakpoint); void addSkip (const QString& skipMode, const QString& skipParameters); protected: private: int _id; }; epasveer-seer-97076f1/src/SeerFunctionBrowserWidget.ui000066400000000000000000000035241526321767600230320ustar00rootroot00000000000000 SeerFunctionBrowserWidgetForm 0 0 730 698 Function Browser 6 Function File/Address Line Full Name Type Description Search in the list of functions. "*" is allowed. QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
epasveer-seer-97076f1/src/SeerGdbConfigPage.cpp000066400000000000000000000073171526321767600213250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerGdbConfigPage.h" #include "SeerUtl.h" #include #include #include SeerGdbConfigPage::SeerGdbConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Connect things. QObject::connect(gdbProgramToolButton, &QToolButton::clicked, this, &SeerGdbConfigPage::handleGdbProgramToolButton); // Setup the defaults. reset(); } SeerGdbConfigPage::~SeerGdbConfigPage() { } QString SeerGdbConfigPage::gdbProgram () const { return gdbProgramLineEdit->text(); } QString SeerGdbConfigPage::gdbLauncher () const { return gdbLauncherLineEdit->text(); } QString SeerGdbConfigPage::gdbArguments () const { return gdbArgumentsLineEdit->text(); } bool SeerGdbConfigPage::gdbAsyncMode () const { return gdbAsyncModeCheckBox->isChecked(); } bool SeerGdbConfigPage::gdbNonStopMode () const { return gdbNonStopModeCheckBox->isChecked(); } bool SeerGdbConfigPage::gdbHandleTerminatingException () const { return gdbHandleTerminateExceptionCheckBox->isChecked(); } bool SeerGdbConfigPage::gdbRandomizeStartAddress () const { return gdbRandomizeStartAddressCheckBox->isChecked(); } bool SeerGdbConfigPage::gdbEnablePrettyPrinting () const { return gdbEnablePrettyPrintingCheckBox->isChecked(); } QString SeerGdbConfigPage::gdbRemoteTargetType () const { return gdbRemoteTargetTypeCombo->currentText(); } QString SeerGdbConfigPage::gdbArchitectureType () const { QString type = gdbArchitectureLineEdit->text(); if (type == "") type = "auto"; return type; } void SeerGdbConfigPage::setGdbProgram (const QString& program) { gdbProgramLineEdit->setText(program); } void SeerGdbConfigPage::setGdbLauncher (const QString& launcher) { return gdbLauncherLineEdit->setText(launcher); } void SeerGdbConfigPage::setGdbArguments (const QString& arguments) { gdbArgumentsLineEdit->setText(arguments); } void SeerGdbConfigPage::setGdbAsyncMode (bool flag) { gdbAsyncModeCheckBox->setChecked(flag); } void SeerGdbConfigPage::setGdbNonStopMode (bool flag) { gdbNonStopModeCheckBox->setChecked(flag); } void SeerGdbConfigPage::setGdbHandleTerminatingException (bool flag) { gdbHandleTerminateExceptionCheckBox->setChecked(flag); } void SeerGdbConfigPage::setGdbRandomizeStartAddress (bool flag) { gdbRandomizeStartAddressCheckBox->setChecked(flag); } void SeerGdbConfigPage::setGdbEnablePrettyPrinting (bool flag) { gdbEnablePrettyPrintingCheckBox->setChecked(flag); } void SeerGdbConfigPage::setGdbRemoteTargetType (const QString& type) { gdbRemoteTargetTypeCombo->setCurrentText(type); } void SeerGdbConfigPage::setGdbArchitectureType (const QString& type) { gdbArchitectureLineEdit->setText(type); } void SeerGdbConfigPage::reset () { #ifdef SEER_GDB_NAME setGdbProgram(STRINGIFY(SEER_GDB_NAME)); #else setGdbProgram("/usr/bin/gdb"); #endif #ifdef SEER_GDB_LAUNCHER setGdbLauncher(STRINGIFY(SEER_GDB_LAUNCHER)); #else setGdbLauncher(""); #endif setGdbArguments("--interpreter=mi"); setGdbAsyncMode(true); setGdbNonStopMode(false); setGdbHandleTerminatingException(true); setGdbRandomizeStartAddress(false); setGdbEnablePrettyPrinting(true); setGdbRemoteTargetType("extended-remote"); setGdbArchitectureType("auto"); } void SeerGdbConfigPage::handleGdbProgramToolButton () { QString program = QFileDialog::getOpenFileName(this, "Select a gdb program to use as the debugger.", gdbProgram(), "", nullptr, QFileDialog::DontUseNativeDialog); if (program != "") { setGdbProgram(program); } } epasveer-seer-97076f1/src/SeerGdbConfigPage.h000066400000000000000000000046521526321767600207710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerGdbConfigPage.h" class SeerGdbConfigPage : public QWidget, protected Ui::SeerGdbConfigPage { Q_OBJECT public: explicit SeerGdbConfigPage (QWidget* parent = 0); ~SeerGdbConfigPage (); QString gdbProgram () const; QString gdbLauncher () const; QString gdbArguments () const; bool gdbAsyncMode () const; bool gdbNonStopMode () const; bool gdbHandleTerminatingException () const; bool gdbRandomizeStartAddress () const; bool gdbEnablePrettyPrinting () const; QString gdbRemoteTargetType () const; QString gdbArchitectureType () const; void setGdbProgram (const QString& program); void setGdbLauncher (const QString& launcher); void setGdbArguments (const QString& arguments); void setGdbAsyncMode (bool flag); void setGdbNonStopMode (bool flag); void setGdbHandleTerminatingException (bool flag); void setGdbRandomizeStartAddress (bool flag); void setGdbEnablePrettyPrinting (bool flag); void setGdbRemoteTargetType (const QString& type); void setGdbArchitectureType (const QString& type); void reset (); protected slots: void handleGdbProgramToolButton (); }; epasveer-seer-97076f1/src/SeerGdbConfigPage.ui000066400000000000000000000373041526321767600211570ustar00rootroot00000000000000 SeerGdbConfigPage 0 0 788 881 SeerGdbConfigPage Gdb Settings GDB program Specify the path and name of the gdb debugger. true Open a file dialog to locate the gdb debugger. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg GDB arguments Arguments to pass to the gdb debugger. true GDB launcher The program, if needed, to launch the gdb binary. false If needed, program and arguments to launch gdb. true Turn gdb 'async' mode on or off. Async mode Allow other threads to continue if any thread reaches a breakpoint. Non-stop mode Randomize the process start address. Randomize start address Handle terminating exceptions when calling functions. Handle terminating-exception Show variables with gdb's 'pretty-printing' system. Enable pretty-printing Remote target type Select the type of remote target connection. remote extended-remote Qt::Horizontal 385 20 Architecture type Executable architecture type. true Qt::Horizontal 385 20 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Specify an alternate gdb program and alternate gdb flags. </span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Changing many of these require saving the new configuration and restarting Seer to take effect</span>.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Note, Seer relies on the &quot;mi&quot; interpreter that is built into gdb. If a different debugger is used, it must provide that. So, usually, the &quot;--interpreter=mi&quot; argument is a must.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sometimes gdb needs to be launched by another program. For example, under flatpak, gdb needs to be launched by flatpak-spawn. This can be defined when compiling Seer. See the CMakefile.txt file. Or manually set here. Normally, this does not need to be set. This launcher is also used for launching RR.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Async mode allows all gdb actions to happen in the background. This allows interrupting of a running program possible. Note, this is disabled for 'connect' mode as background commands may overwhelm the gdbserver.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Non-stop mode, when turned on, will allow other threads to continue to run while another thread reaches a breakpoint.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The gdb debugger normally starts the process at the same address each time. The program's start address can be randomized.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A terminating-exception can happen when gdb is asked to call a function in your program. Like printing the return value from a function. If the function throws an exception, gdb can handle it by suppressing the exception or allowing the program to terminate. See:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace'; color:#24292f; background-color:transparent;"> unwind-on-terminating-exception on|off</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enabling pretty-printing allows gdb to present certain variables (like std::string) in a pleasing way. Otherwise, the contents of the variables are presented in their full description. (See gdb 'pretty-printing'). Once enabled, it can not be turned off for the Seer session.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When connecting to a gdbserver (or the like), you can set gdb's remote target type to:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">* remote</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">* extended-remote</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Extended remote is generally suggested but may not be supported by all gdbserver programs. If you experience a slowness starting Seer, try &quot;remote&quot;.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Architecture Type sets the target's architecture type. The value can be &quot;auto&quot;, in addition of one of the support architectures your version of gdb supports.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Run this command in gdb to see a full list of architectures supported by your version of gdb.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> (gdb) set architecture</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> epasveer-seer-97076f1/src/SeerGdbLogWidget.cpp000066400000000000000000000034341526321767600212040ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerGdbLogWidget.h" #include "SeerUtl.h" #include #include #include #include SeerGdbLogWidget::SeerGdbLogWidget (QWidget* parent) : SeerLogWidget(parent) { } SeerGdbLogWidget::~SeerGdbLogWidget () { } void SeerGdbLogWidget::processText (const QString& text) { QString str; // Remove leading "~" // Remove leading "&" // Remove leading "@" switch (text.front().unicode()) { case QChar('~').unicode(): case QChar('&').unicode(): case QChar('@').unicode(): str = text.mid(1); // Remove leading """ if (str.front() == '"') { str = str.mid(1); } // Remove trailing """ if (str.back() == '"') { str.chop(1); } break; default: str = text; } // https://github.com/epasveer/seer/issues/238 str = Seer::unescape(str); // Add timestamp. if (isTimeStampEnabled()) { QString text = QString("[") + QTime::currentTime().toString("hh:mm:ss.zz") + QString("] ") + str; // Write the string to the log. textEdit->insertPlainText(text); }else{ // Write the string to the log. textEdit->insertPlainText(str); } // If there is breakpoint message (via a manual command), ask // for the breakpoint list to be refreshed. // // Breakpoint 2 at 0x403a40: file explorer.cpp, line 78. // if (str.contains(QRegularExpression("^Breakpoint ([0-9]+) at (0[xX][0-9a-fA-F]+): file (.*\\,) (line) ([0-9]+)"))) { emit refreshBreakpointsList(); } } epasveer-seer-97076f1/src/SeerGdbLogWidget.h000066400000000000000000000007331526321767600206500ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerLogWidget.h" class SeerGdbLogWidget : public SeerLogWidget { Q_OBJECT public: explicit SeerGdbLogWidget (QWidget* parent = 0); ~SeerGdbLogWidget (); void processText (const QString& text); signals: void refreshBreakpointsList (); }; epasveer-seer-97076f1/src/SeerGdbMonitorWidget.cpp000066400000000000000000000154641526321767600221200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerGdbMonitorWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include SeerGdbMonitorWidget::SeerGdbMonitorWidget (QWidget* parent) : QWidget(parent) { // Init variables. _monitorId = Seer::createID(); // Create id for gdb monitor messages. // Set up UI. setupUi(this); // Setup the widgets setWindowTitle("Seer - GDB Monitor"); setAttribute(Qt::WA_DeleteOnClose); m1ToolButton->setMacroName("M1", "gdbmonitor"); m2ToolButton->setMacroName("M2", "gdbmonitor"); m3ToolButton->setMacroName("M3", "gdbmonitor"); m4ToolButton->setMacroName("M4", "gdbmonitor"); m5ToolButton->setMacroName("M5", "gdbmonitor"); m6ToolButton->setMacroName("M6", "gdbmonitor"); m7ToolButton->setMacroName("M7", "gdbmonitor"); m8ToolButton->setMacroName("M8", "gdbmonitor"); m9ToolButton->setMacroName("M9", "gdbmonitor"); m0ToolButton->setMacroName("M0", "gdbmonitor"); // Default font. QFont font; font.setFamily("monospace"); font.setStyleHint(QFont::Monospace); font.setFixedPitch(true); // Set the widget's font. QTextCharFormat format = textEdit->currentCharFormat(); format.setFont(font); textEdit->setCurrentCharFormat(format); textEdit->setFont(font); // Connect things. QObject::connect(monitorCommandLineEdit, &QLineEdit::returnPressed, this, &SeerGdbMonitorWidget::handleCommandLineEdit); QObject::connect(clearToolButton, &QToolButton::clicked, this, &SeerGdbMonitorWidget::handleClearButton); QObject::connect(saveToolButton, &QToolButton::clicked, this, &SeerGdbMonitorWidget::handleSaveButton); QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerGdbMonitorWidget::handlePrintButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerGdbMonitorWidget::handleHelpButton); QObject::connect(macroButtonGroup, &QButtonGroup::buttonClicked, this, &SeerGdbMonitorWidget::handleMacroToolButtonClicked); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerGdbMonitorWidget::handleThemeChanged); #endif // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); // Restore window settings. readSettings(); } SeerGdbMonitorWidget::~SeerGdbMonitorWidget () { } void SeerGdbMonitorWidget::handleText (const QString& text) { // qDebug() << text; if (text.contains(QRegularExpression("^([0-9]+)\\^done,monitor-output="))) { // 13^done,monitor-output=\"The following monitor command\\n\" // 13^done,monitor-output=\"\" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _monitorId) { QString output_text = Seer::parseFirst(text, "monitor-output=", '"', '"', false); textEdit->appendPlainText(Seer::unescape(output_text)); textEdit->moveCursor(QTextCursor::End); } } } void SeerGdbMonitorWidget::handleCommandLineEdit () { QString command = monitorCommandLineEdit->text(); monitorCommandLineEdit->clear(); textEdit->appendPlainText("(monitor) " + command); textEdit->moveCursor(QTextCursor::End); emit executeGdbMonitorCommand(_monitorId, command); } void SeerGdbMonitorWidget::handleClearButton () { textEdit->clear(); } void SeerGdbMonitorWidget::handlePrintButton () { QPrinter printer; QPrintDialog* dlg = new QPrintDialog(&printer, this); if (dlg->exec() != QDialog::Accepted) { return; } QTextDocument* document = textEdit->document(); document->print(&printer); } void SeerGdbMonitorWidget::handleSaveButton () { QFileDialog dialog(this, "Seer log file", "./", "Logs (*.log);;Text files (*.txt);;All files (*.*)"); dialog.setOptions(QFileDialog::DontUseNativeDialog); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("log"); dialog.selectFile("gdbmonitor.log"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } QFile file(files[0]); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); stream << textEdit->toPlainText(); file.flush(); file.close(); }else{ QMessageBox::critical(this, tr("Error"), tr("Cannot save log to file.")); return; } } void SeerGdbMonitorWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/GdbMonitor.md"); help->show(); help->raise(); } void SeerGdbMonitorWidget::handleMacroToolButtonClicked (QAbstractButton* button) { if (button == nullptr) { return; } SeerMacroToolButton* tb = qobject_cast(button); for (auto& command : tb->commands()) { if (command == "") { continue; } textEdit->appendPlainText("(monitor) " + command); textEdit->moveCursor(QTextCursor::End); emit executeGdbMonitorCommand(_monitorId, command); } } void SeerGdbMonitorWidget::handleThemeChanged () { // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); } void SeerGdbMonitorWidget::writeSettings() { QSettings settings; settings.beginGroup("gdbmonitorvisualizerwindow"); { settings.setValue("size", size()); } settings.endGroup(); } void SeerGdbMonitorWidget::readSettings() { QSettings settings; settings.beginGroup("gdbmonitorvisualizerwindow"); { resize(settings.value("size", QSize(800, 400)).toSize()); } settings.endGroup(); } void SeerGdbMonitorWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } epasveer-seer-97076f1/src/SeerGdbMonitorWidget.h000066400000000000000000000026361526321767600215620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerGdbMonitorWidget.h" class SeerGdbMonitorWidget : public QWidget, protected Ui::SeerGdbMonitorWidgetForm { Q_OBJECT public: explicit SeerGdbMonitorWidget (QWidget* parent = 0); ~SeerGdbMonitorWidget (); signals: void executeGdbMonitorCommand (int monitorid, QString command); public slots: void handleText (const QString& text); protected slots: void handleCommandLineEdit (); void handleClearButton (); void handleSaveButton (); void handlePrintButton (); void handleHelpButton (); void handleMacroToolButtonClicked (QAbstractButton* button); void handleThemeChanged (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: int _monitorId; }; epasveer-seer-97076f1/src/SeerGdbMonitorWidget.ui000066400000000000000000000174201526321767600217450ustar00rootroot00000000000000 SeerGdbMonitorWidgetForm 0 0 823 634 Seer - Gdb Monitor true [output from gdb monitor] M1 macroButtonGroup M2 macroButtonGroup M3 macroButtonGroup M4 macroButtonGroup M5 macroButtonGroup M6 macroButtonGroup M7 macroButtonGroup M8 macroButtonGroup M9 macroButtonGroup M0 macroButtonGroup Qt::Horizontal 40 20 Monitor Command: 100 0 Enter a GDB monitor command. true Clear monitor output. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Print the monitor contents. ... :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Save the monitor contents. ... :/seer/resources/RelaxLightIcons/document-save-as.svg:/seer/resources/RelaxLightIcons/document-save-as.svg Help for the GDB monitor. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg SeerMacroToolButton QToolButton
SeerMacroToolButton.h
QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
monitorCommandLineEdit m1ToolButton m2ToolButton m3ToolButton m4ToolButton m5ToolButton m6ToolButton m7ToolButton m8ToolButton m9ToolButton m0ToolButton clearToolButton printToolButton helpToolButton textEdit
epasveer-seer-97076f1/src/SeerGdbWidget.cpp000066400000000000000000005335671526321767600205610ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerGdbWidget.h" #include "SeerLogWidget.h" #include "SeerMemoryVisualizerWidget.h" #include "SeerArrayVisualizerWidget.h" #include "SeerMatrixVisualizerWidget.h" #include "SeerStructVisualizerWidget.h" #include "SeerVarVisualizerWidget.h" #include "SeerImageVisualizerWidget.h" #include "SeerParallelStacksVisualizerWidget.h" #include "SeerGdbMonitorWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static QLoggingCategory LC("seer.gdbwidget"); SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) { _executableName = ""; _executableArguments = ""; _executableWorkingDirectory = ""; _executableBreakpointsFilename = ""; _executableBreakpointFunctionName = ""; _executableBreakpointFirstInstruction = false; _executableConnectHostPort = ""; _executableRRTraceDirectory = ""; _executableCoreFilename = ""; _executablePid = 0; _gdbMonitor = 0; _gdbProcess = 0; #ifdef SEER_GDB_NAME _gdbProgram = STRINGIFY(SEER_GDB_NAME); #else _gdbProgram = "/usr/bin/gdb"; #endif #ifdef SEER_GDB_LAUNCHER _gdbLauncher = STRINGIFY(SEER_GDB_LAUNCHER); #else _gdbLauncher = ""; #endif _gdbArguments = "--interpreter=mi"; _gdbASyncMode = true; _gdbNonStopMode = false; _gdbServerDebug = false; _assemblyDisassemblyFlavor = "att"; _gdbHandleTerminatingException = true; _gdbRandomizeStartAddress = false; _gdbEnablePrettyPrinting = true; _gdbRemoteTargetType = "extended-remote"; _gdbRecordMode = ""; _gdbRecordDirection = ""; setIsQuitting(false); setNewExecutableFlag(true); setupUi(this); // Create the gdb process. _gdbProcess = new QProcess(this); // Create the gdb monitor. _gdbMonitor = new GdbMonitor(this); _gdbMonitor->setProcess(_gdbProcess); // Handle the app's 'quit' event, in case we want to do things before exiting. QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &SeerGdbWidget::handleAboutToQuit); // Connect things. QObject::connect(commandLogsWidget, &SeerCommandLogsWidget::executeGdbCommand, this, &SeerGdbWidget::handleManualCommandExecute); QObject::connect(_gdbProcess, &QProcess::readyReadStandardOutput, _gdbMonitor, &GdbMonitor::handleReadyReadStandardOutput); QObject::connect(_gdbProcess, &QProcess::readyReadStandardError, _gdbMonitor, &GdbMonitor::handleReadyReadStandardError); QObject::connect(_gdbProcess, static_cast(&QProcess::finished), this, &SeerGdbWidget::handleGdbProcessFinished); // ??? Do we care about the gdb process ending? For now, terminate Seer. QObject::connect(_gdbProcess, static_cast(&QProcess::errorOccurred), this, &SeerGdbWidget::handleGdbProcessErrored); QObject::connect(_gdbMonitor, &GdbMonitor::tildeTextOutput, commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::ampersandTextOutput, commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::atsignTextOutput, commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, commandLogsWidget->seerOutputLog(), &SeerSeerLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->seerOutputLog(), &SeerSeerLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, commandLogsWidget->seerOutputLog(), &SeerSeerLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, editorManagerWidget, &SeerEditorManagerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, editorManagerWidget, &SeerEditorManagerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->sourceBrowserWidget(), &SeerSourceBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->typeBrowserWidget(), &SeerTypeBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->staticBrowserWidget(), &SeerStaticBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->libraryBrowserWidget(), &SeerLibraryBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->adaExceptionsBrowserWidget(), &SeerAdaExceptionsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget, &SeerStackManagerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, variableManagerWidget->signalValuesBrowserWidget(), &SeerSignalValuesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, this, &SeerGdbWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, this, &SeerGdbWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::tildeTextOutput, this, &SeerGdbWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::handleText); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshBreakpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshStackFrames, this, &SeerGdbWidget::handleGdbStackListFrames); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::insertBreakpoint, this, &SeerGdbWidget::handleGdbBreakpointInsert); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::insertPrintpoint, this, &SeerGdbWidget::handleGdbPrintpointInsert); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::deleteBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDelete); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::enableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointEnable); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::disableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDisable); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::infoBreakpoint, this, &SeerGdbWidget::handleGdbBreakpointInfo); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::runToLine, this, &SeerGdbWidget::handleGdbRunToLine); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::runToAddress, this, &SeerGdbWidget::handleGdbRunToAddress); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addVariableLoggerExpression, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addVariableExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addVariableTrackerExpression, this, &SeerGdbWidget::handleGdbDataAddExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshVariableTrackerValues, this, &SeerGdbWidget::handleGdbDataListValues); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::evaluateVariableExpression, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::handleEvaluateVariableExpression); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::requestAssembly, this, &SeerGdbWidget::handleGdbGetAssembly); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::requestSourceAndAssembly, this, &SeerGdbWidget::handleGdbGetSourceAndAssembly); QObject::connect(sourceLibraryManagerWidget->sourceBrowserWidget(), &SeerSourceBrowserWidget::refreshSourceList, this, &SeerGdbWidget::handleGdbExecutableSources); QObject::connect(sourceLibraryManagerWidget->sourceBrowserWidget(), &SeerSourceBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::refreshFunctionList, this, &SeerGdbWidget::handleGdbExecutableFunctions); QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::insertBreakpoint, this, &SeerGdbWidget::handleGdbBreakpointInsert); QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::addSkip, this, &SeerGdbWidget::handleGdbSkipAdd); QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(sourceLibraryManagerWidget->typeBrowserWidget(), &SeerTypeBrowserWidget::refreshTypeList, this, &SeerGdbWidget::handleGdbExecutableTypes); QObject::connect(sourceLibraryManagerWidget->typeBrowserWidget(), &SeerTypeBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(sourceLibraryManagerWidget->staticBrowserWidget(), &SeerStaticBrowserWidget::refreshVariableList, this, &SeerGdbWidget::handleGdbExecutableVariables); QObject::connect(sourceLibraryManagerWidget->staticBrowserWidget(), &SeerStaticBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(sourceLibraryManagerWidget->libraryBrowserWidget(), &SeerLibraryBrowserWidget::refreshLibraryList, this, &SeerGdbWidget::handleGdbExecutableLibraries); QObject::connect(sourceLibraryManagerWidget->adaExceptionsBrowserWidget(), &SeerAdaExceptionsBrowserWidget::refreshAdaExceptions, this, &SeerGdbWidget::handleGdbAdaListExceptions); QObject::connect(sourceLibraryManagerWidget->adaExceptionsBrowserWidget(), &SeerAdaExceptionsBrowserWidget::insertCatchpoint, this, &SeerGdbWidget::handleGdbCatchpointInsert); QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::refreshSkipList, this, &SeerGdbWidget::handleGdbSkipList); QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::addSkip, this, &SeerGdbWidget::handleGdbSkipAdd); QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::deleteSkips, this, &SeerGdbWidget::handleGdbSkipDelete); QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::enableSkips, this, &SeerGdbWidget::handleGdbSkipEnable); QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::disableSkips, this, &SeerGdbWidget::handleGdbSkipDisable); QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::refreshStackFrames, this, &SeerGdbWidget::handleGdbStackListFrames); QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::selectedFrame, this, &SeerGdbWidget::handleGdbStackSelectFrame); QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::selectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleOpenAddress); QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::maybeSelectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleMaybeOpenAddress); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::refreshStackArguments, this, &SeerGdbWidget::handleGdbStackListArguments); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addVariableLoggerExpression, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addVariableExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addVariableTrackerExpression, this, &SeerGdbWidget::handleGdbDataAddExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::refreshVariableTrackerValues, this, &SeerGdbWidget::handleGdbDataListExpressions); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::refreshStackLocals, this, &SeerGdbWidget::handleGdbStackListLocals); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addVariableLoggerExpression, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addVariableExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addVariableTrackerExpression, this, &SeerGdbWidget::handleGdbDataAddExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::refreshVariableTrackerValues, this, &SeerGdbWidget::handleGdbDataListExpressions); QObject::connect(stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::refreshStackPointer, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::refreshStackDump, this, QOverload::of(&SeerGdbWidget::handleGdbMemoryEvaluateExpression)); QObject::connect(stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(stackManagerWidget, &SeerStackManagerWidget::refreshThreadFrames, this, &SeerGdbWidget::handleGdbThreadListFrames); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::refreshVariableTrackerNames, this, &SeerGdbWidget::handleGdbDataListExpressions); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::refreshVariableTrackerValues, this, &SeerGdbWidget::handleGdbDataListValues); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::addVariableExpression, this, &SeerGdbWidget::handleGdbDataAddExpression); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::deleteVariableExpressions, this, &SeerGdbWidget::handleGdbDataDeleteExpressions); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); QObject::connect(variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::refreshRegisterNames, this, &SeerGdbWidget::handleGdbRegisterListNames); QObject::connect(variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::refreshRegisterValues, this, &SeerGdbWidget::handleGdbRegisterListValues); QObject::connect(variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::setRegisterValue, this, &SeerGdbWidget::handleGdbRegisterSetValue); QObject::connect(variableManagerWidget->signalValuesBrowserWidget(), &SeerSignalValuesBrowserWidget::refreshSignalNames, this, &SeerGdbWidget::handleGdbSignalListNames); QObject::connect(variableManagerWidget->signalValuesBrowserWidget(), &SeerSignalValuesBrowserWidget::refreshSignalValues, this, &SeerGdbWidget::handleGdbSignalListValues); QObject::connect(variableManagerWidget->signalValuesBrowserWidget(), &SeerSignalValuesBrowserWidget::setSignalValue, this, &SeerGdbWidget::handleGdbSignalSetValue); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::refreshThreadIds, this, &SeerGdbWidget::handleGdbThreadListIds); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::refreshThreadFrames, this, &SeerGdbWidget::handleGdbThreadListFrames); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::selectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleOpenAddress); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::maybeSelectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleMaybeOpenAddress); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::selectedThread, this, &SeerGdbWidget::handleGdbThreadSelectId); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::nextThreadId, this, &SeerGdbWidget::handleGdbNextThreadId); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::stepThreadId, this, &SeerGdbWidget::handleGdbStepThreadId); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::finishThreadId, this, &SeerGdbWidget::handleGdbFinishThreadId); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::continueThreadId, this, &SeerGdbWidget::handleGdbContinueThreadId); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::interruptThreadId, this, &SeerGdbWidget::handleGdbInterruptThreadId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::refreshThreadIds, this, &SeerGdbWidget::handleGdbThreadListIds); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::selectedThread, this, &SeerGdbWidget::handleGdbThreadSelectId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::nextThreadId, this, &SeerGdbWidget::handleGdbNextThreadId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::stepThreadId, this, &SeerGdbWidget::handleGdbStepThreadId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::finishThreadId, this, &SeerGdbWidget::handleGdbFinishThreadId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::continueThreadId, this, &SeerGdbWidget::handleGdbContinueThreadId); QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::interruptThreadId, this, &SeerGdbWidget::handleGdbInterruptThreadId); QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::refreshThreadGroups, this, &SeerGdbWidget::handleGdbThreadListGroups); QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::runThreadGroup, this, &SeerGdbWidget::handleGdbRunThreadGroup); QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::startThreadGroup, this, &SeerGdbWidget::handleGdbStartThreadGroup); QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::continueThreadGroup, this, &SeerGdbWidget::handleGdbContinueThreadGroup); QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::interruptThreadGroup, this, &SeerGdbWidget::handleGdbInterruptThreadGroup); QObject::connect(threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::refreshAdaTasks, this, &SeerGdbWidget::handleGdbAdaListTasks); QObject::connect(threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::selectedThread, this, &SeerGdbWidget::handleGdbThreadSelectId); QObject::connect(threadManagerWidget, &SeerThreadManagerWidget::schedulerLockingModeChanged, this, &SeerGdbWidget::handleGdbSchedulerLockingMode); QObject::connect(threadManagerWidget, &SeerThreadManagerWidget::scheduleMultipleModeChanged, this, &SeerGdbWidget::handleGdbScheduleMultipleMode); QObject::connect(threadManagerWidget, &SeerThreadManagerWidget::forkFollowsModeChanged, this, &SeerGdbWidget::handleGdbForkFollowMode); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::refreshBreakpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::deleteBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDelete); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::enableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointEnable); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::disableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDisable); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::insertBreakpoint, this, &SeerGdbWidget::handleGdbBreakpointInsert); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::addBreakpointCondition, this, &SeerGdbWidget::handleGdbBreakpointCondition); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::addBreakpointIgnore, this, &SeerGdbWidget::handleGdbBreakpointIgnore); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::addBreakpointCommands, this, &SeerGdbWidget::handleGdbBreakpointCommands); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::selectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleOpenAddress); QObject::connect(commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::maybeSelectedAddress, editorManagerWidget, &SeerEditorManagerWidget::handleMaybeOpenAddress); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::refreshWatchpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::deleteWatchpoints, this, &SeerGdbWidget::handleGdbWatchpointDelete); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::enableWatchpoints, this, &SeerGdbWidget::handleGdbWatchpointEnable); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::disableWatchpoints, this, &SeerGdbWidget::handleGdbWatchpointDisable); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::insertWatchpoint, this, &SeerGdbWidget::handleGdbWatchpointInsert); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::addBreakpointCondition, this, &SeerGdbWidget::handleGdbBreakpointCondition); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::addBreakpointIgnore, this, &SeerGdbWidget::handleGdbBreakpointIgnore); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::addBreakpointCommands, this, &SeerGdbWidget::handleGdbBreakpointCommands); QObject::connect(commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::refreshCatchpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::deleteCatchpoints, this, &SeerGdbWidget::handleGdbCatchpointDelete); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::enableCatchpoints, this, &SeerGdbWidget::handleGdbCatchpointEnable); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::disableCatchpoints, this, &SeerGdbWidget::handleGdbCatchpointDisable); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::insertCatchpoint, this, &SeerGdbWidget::handleGdbCatchpointInsert); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::addBreakpointCondition, this, &SeerGdbWidget::handleGdbBreakpointCondition); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::addBreakpointIgnore, this, &SeerGdbWidget::handleGdbBreakpointIgnore); QObject::connect(commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::addBreakpointCommands, this, &SeerGdbWidget::handleGdbBreakpointCommands); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::refreshPrintpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::deletePrintpoints, this, &SeerGdbWidget::handleGdbPrintpointDelete); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::enablePrintpoints, this, &SeerGdbWidget::handleGdbPrintpointEnable); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::disablePrintpoints, this, &SeerGdbWidget::handleGdbPrintpointDisable); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::insertPrintpoint, this, &SeerGdbWidget::handleGdbPrintpointInsert); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::addBreakpointCondition, this, &SeerGdbWidget::handleGdbBreakpointCondition); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::addBreakpointIgnore, this, &SeerGdbWidget::handleGdbBreakpointIgnore); QObject::connect(commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::addBreakpointCommand, this, &SeerGdbWidget::handleGdbBreakpointCommand); QObject::connect(commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::refreshCheckpointsList, this, &SeerGdbWidget::handleGdbCheckpointList); QObject::connect(commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::insertCheckpoint, this, &SeerGdbWidget::handleGdbCheckpointInsert); QObject::connect(commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::selectCheckpoint, this, &SeerGdbWidget::handleGdbCheckpointSelect); QObject::connect(commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::deleteCheckpoints, this, &SeerGdbWidget::handleGdbCheckpointDelete); QObject::connect(this, &SeerGdbWidget::assemblyConfigChanged, editorManagerWidget, &SeerEditorManagerWidget::handleAssemblyConfigChanged); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget, &SeerStackManagerWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, variableManagerWidget->signalValuesBrowserWidget(), &SeerSignalValuesBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::stoppingPointReached, commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::handleStoppingPointReached); QObject::connect(this, &SeerGdbWidget::sessionTerminated, editorManagerWidget, &SeerEditorManagerWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->sourceBrowserWidget(), &SeerSourceBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->functionBrowserWidget(), &SeerFunctionBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->staticBrowserWidget(), &SeerStaticBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->libraryBrowserWidget(), &SeerLibraryBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->adaExceptionsBrowserWidget(), &SeerAdaExceptionsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, sourceLibraryManagerWidget->skipBrowserWidget(), &SeerSkipBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, stackManagerWidget, &SeerStackManagerWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, stackManagerWidget->stackDumpBrowserWidget(), &SeerStackDumpBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, threadManagerWidget->threadGroupsBrowserWidget(), &SeerThreadGroupsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, threadManagerWidget->adaTasksBrowserWidget(), &SeerAdaTasksBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, commandLogsWidget->breakpointsBrowser(), &SeerBreakpointsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, commandLogsWidget->watchpointsBrowser(), &SeerWatchpointsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, commandLogsWidget->catchpointsBrowser(), &SeerCatchpointsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, commandLogsWidget->printpointsBrowser(), &SeerPrintpointsBrowserWidget::handleSessionTerminated); QObject::connect(this, &SeerGdbWidget::sessionTerminated, commandLogsWidget->checkpointsBrowser(), &SeerCheckpointsBrowserWidget::handleSessionTerminated); QObject::connect(leftCenterRightSplitter, &QSplitter::splitterMoved, this, &SeerGdbWidget::handleSplitterMoved); QObject::connect(sourceLibraryVariableManagerSplitter, &QSplitter::splitterMoved, this, &SeerGdbWidget::handleSplitterMoved); QObject::connect(sourceCommandLogsSplitter, &QSplitter::splitterMoved, this, &SeerGdbWidget::handleSplitterMoved); QObject::connect(stackThreadManagerSplitter, &QSplitter::splitterMoved, this, &SeerGdbWidget::handleSplitterMoved); QObject::connect(commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::refreshBreakpointsList, this, &SeerGdbWidget::handleGdbGenericpointList); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshFunctionList, this, &SeerGdbWidget::handleGdbExecutableFunctions); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshVariableList, this, &SeerGdbWidget::handleGdbExecutableVariables); QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshTypeList, this, &SeerGdbWidget::handleGdbExecutableTypes); #if SEER_GDB_LOGOUT == 1 // Direct all GdbWidget and GdbMonitor log to GDB Log, for debugging QObject::connect(this, &SeerGdbWidget::gdbCommandLogout, commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::allTextOutput, commandLogsWidget->gdbOutputLog(), &SeerGdbLogWidget::handleText); #endif QObject::connect(this, &SeerGdbWidget::stateChanged, editorManagerWidget, &SeerEditorManagerWidget::handleGdbStateChanged); // Restore window settings. readSettings(); } SeerGdbWidget::~SeerGdbWidget () { commandLogsWidget->deleteConsole(); if (_gdbMonitor) { delete _gdbMonitor; } if (_gdbProcess) { _gdbProcess->kill(); _gdbProcess->waitForFinished(); delete _gdbProcess; } } GdbMonitor* SeerGdbWidget::gdbMonitor () { return _gdbMonitor; } QProcess* SeerGdbWidget::gdbProcess () { return _gdbProcess; } void SeerGdbWidget::setExecutableName (const QString& executableName) { _executableName = executableName; setNewExecutableFlag(true); } const QString& SeerGdbWidget::executableName () const { return _executableName; } void SeerGdbWidget::setExecutableSymbolName (const QString& executableSymbolName) { _executableSymbolName = executableSymbolName; setNewExecutableFlag(true); } const QString& SeerGdbWidget::executableSymbolName () const { return _executableSymbolName; } void SeerGdbWidget::setNewExecutableFlag (bool flag) { _newExecutableFlag = flag; } bool SeerGdbWidget::newExecutableFlag () const { return _newExecutableFlag; } void SeerGdbWidget::setExecutableArguments (const QString& executableArguments) { _executableArguments = executableArguments; } const QString& SeerGdbWidget::executableArguments () const { return _executableArguments; } void SeerGdbWidget::setExecutableWorkingDirectory (const QString& executableWorkingDirectory) { _executableWorkingDirectory = executableWorkingDirectory; } const QString& SeerGdbWidget::executableWorkingDirectory () const { return _executableWorkingDirectory; } void SeerGdbWidget::setExecutableBreakpointsFilename (const QString& breakpointsFilename) { _executableBreakpointsFilename = breakpointsFilename; } const QString& SeerGdbWidget::executableBreakpointsFilename () const { return _executableBreakpointsFilename; } void SeerGdbWidget::setExecutableBreakpointFunctionName (const QString& nameoraddress) { _executableBreakpointFunctionName = nameoraddress; } const QString& SeerGdbWidget::executableBreakpointFunctionName () const { return _executableBreakpointFunctionName; } void SeerGdbWidget::setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno) { _executableBreakpointSourceName = sourceFilenameAndLineno; } const QString& SeerGdbWidget::executableBreakpointSourceName () const { return _executableBreakpointSourceName; } void SeerGdbWidget::setExecutableBreakpointFirstInstruction (bool flag) { _executableBreakpointFirstInstruction = flag; } bool SeerGdbWidget::executableBreakpointFirstInstruction () const { return _executableBreakpointFirstInstruction; } void SeerGdbWidget::setExecutablePid (int pid) { _executablePid = pid; } int SeerGdbWidget::executablePid () const { return _executablePid; } void SeerGdbWidget::setExecutableConnectHostPort (const QString& connectHostPort) { _executableConnectHostPort = connectHostPort; } const QString& SeerGdbWidget::executableConnectHostPort () const { return _executableConnectHostPort; } void SeerGdbWidget::setExecutableRRTraceDirectory (const QString& rrTraceDirectory) { _executableRRTraceDirectory = rrTraceDirectory; } const QString& SeerGdbWidget::executableRRTraceDirectory () const { return _executableRRTraceDirectory; } void SeerGdbWidget::setExecutableCoreFilename (const QString& coreFilename) { _executableCoreFilename = coreFilename; } const QString& SeerGdbWidget::executableCoreFilename () const { return _executableCoreFilename; } void SeerGdbWidget::setExecutablePreGdbCommands (const QStringList& preGdbCommands) { _executablePreGdbCommands = preGdbCommands; } const QStringList& SeerGdbWidget::executablePreGdbCommands () const { return _executablePreGdbCommands; } void SeerGdbWidget::setExecutablePostGdbCommands (const QStringList& postGdbCommands) { _executablePostGdbCommands = postGdbCommands; } const QStringList& SeerGdbWidget::executablePostGdbCommands () const { return _executablePostGdbCommands; } void SeerGdbWidget::setExecutableLaunchMode (const QString& launchMode) { _executableLaunchMode = launchMode; } const QString& SeerGdbWidget::executableLaunchMode () const { return _executableLaunchMode; } const QString& SeerGdbWidget::executableBreakMode () const { return _executableBreakMode; } void SeerGdbWidget::saveLaunchMode() { _executableLaunchModeBackup = _executableLaunchMode; _executableBreakModeBackup = _executableBreakMode; } void SeerGdbWidget::restoreLaunchMode() { _executableLaunchMode = _executableLaunchModeBackup; _executableBreakMode = _executableBreakModeBackup; } bool SeerGdbWidget::hasBackupLaunchMode () const { if (_executableLaunchModeBackup == "") { return false; } return true; } void SeerGdbWidget::clearBackupLaunchMode () { _executableLaunchModeBackup = ""; _executableBreakModeBackup = ""; } const QString& SeerGdbWidget::backupLaunchMode () const { return _executableLaunchModeBackup; } void SeerGdbWidget::setGdbProgram (const QString& program) { _gdbProgram = program; } QString SeerGdbWidget::gdbProgram () const { return _gdbProgram; } void SeerGdbWidget::setGdbLauncher (const QString& launchProgram) { _gdbLauncher = launchProgram; } QString SeerGdbWidget::gdbLauncher () const { return _gdbLauncher; } void SeerGdbWidget::setGdbArguments (const QString& arguments) { _gdbArguments = arguments; } QString SeerGdbWidget::gdbArguments () const { return _gdbArguments; } void SeerGdbWidget::setGdbProgramOverride (const QString& program) { _gdbProgramOverride = program; } QString SeerGdbWidget::gdbProgramOverride () const { return _gdbProgramOverride; } void SeerGdbWidget::setGdbArgumentsOverride (const QString& arguments) { _gdbArgumentsOverride = arguments; } QString SeerGdbWidget::gdbArgumentsOverride () const { return _gdbArgumentsOverride; } void SeerGdbWidget::setRRProgram (const QString& program) { _gdbRRProgram = program; } QString SeerGdbWidget::rrProgram () const { return _gdbRRProgram; } void SeerGdbWidget::setRRArguments (const QString& arguments) { _gdbRRArguments = arguments; } QString SeerGdbWidget::rrArguments () const { return _gdbRRArguments; } void SeerGdbWidget::setRRGdbArguments (const QString& arguments) { _gdbRRGdbArguments = arguments; } QString SeerGdbWidget::rrGdbArguments () const { return _gdbRRGdbArguments; } void SeerGdbWidget::setGdbAsyncMode (bool flag) { _gdbASyncMode = flag; } bool SeerGdbWidget::gdbAsyncMode () const { return _gdbASyncMode; } void SeerGdbWidget::setGdbNonStopMode (bool flag) { _gdbNonStopMode = flag; } bool SeerGdbWidget::gdbNonStopMode () const { return _gdbNonStopMode; } void SeerGdbWidget::setGdbServerDebug (bool flag) { _gdbServerDebug = flag; } bool SeerGdbWidget::gdbServerDebug () const { return _gdbServerDebug; } void SeerGdbWidget::setGdbHandleTerminatingException (bool flag) { _gdbHandleTerminatingException = flag; } bool SeerGdbWidget::gdbHandleTerminatingException () const { return _gdbHandleTerminatingException; } void SeerGdbWidget::setGdbRandomizeStartAddress (bool flag) { _gdbRandomizeStartAddress = flag; } bool SeerGdbWidget::gdbRandomizeStartAddress () const { return _gdbRandomizeStartAddress; } void SeerGdbWidget::setGdbEnablePrettyPrinting (bool flag) { _gdbEnablePrettyPrinting = flag; } bool SeerGdbWidget::gdbEnablePrettyPrinting () const { return _gdbEnablePrettyPrinting; } void SeerGdbWidget::setGdbRemoteTargetType (const QString& type) { _gdbRemoteTargetType = type; } QString SeerGdbWidget::gdbRemoteTargetType () const { return _gdbRemoteTargetType; } void SeerGdbWidget::setGdbArchitectureType (const QString& type) { _gdbArchitectureType = type; } QString SeerGdbWidget::gdbArchitectureType () const { return _gdbArchitectureType; } void SeerGdbWidget::setGdbRecordMode(const QString& mode) { if (mode == "auto") { if (gdbProgram().contains("udb")) { _gdbRecordMode = "udb"; }else{ _gdbRecordMode = ""; } }else{ _gdbRecordMode = mode; } if (_gdbRecordMode != "rr" && _gdbRecordMode != "udb" && _gdbRecordMode != "") { handleGdbCommand("record " + _gdbRecordMode); } emit recordSettingsChanged(); } QString SeerGdbWidget::gdbRecordMode () const { return _gdbRecordMode; } void SeerGdbWidget::setGdbRecordDirection (const QString& direction) { _gdbRecordDirection = direction; emit recordSettingsChanged(); } QString SeerGdbWidget::gdbRecordDirection () const { return _gdbRecordDirection; } SeerEditorManagerWidget* SeerGdbWidget::editorManager () { return editorManagerWidget; } const SeerEditorManagerWidget* SeerGdbWidget::editorManager () const { return editorManagerWidget; } void SeerGdbWidget::addMessage (const QString& message, QMessageBox::Icon messageType) { commandLogsWidget->messagesBrowser()->addMessage(message, messageType); } void SeerGdbWidget::handleText (const QString& text) { if (text.startsWith("*running,thread-id=\"all\"")) { // Probably a better way to handle all these types of stops. }else if (text.startsWith("*stopped")) { emit stoppingPointReached(); }else if (text.startsWith("=breakpoint-created,")) { handleGdbGenericpointList(); }else if (text.startsWith("=thread-group-started,")) { // =thread-group-started,id="i1",pid="30916" QString pid_text = Seer::parseFirst(text, "pid=", '"', '"', false); //qDebug() << "Inferior pid = " << pid_text; setExecutablePid(pid_text.toLong()); }else if (text.startsWith("=thread-group-exited,")) { handleGdbTerminateExecutable(false); // Scan the output for magic text to refresh the Signal tab. }else if (text.startsWith("~\"@refresh-signal-values\"")) { handleGdbSignalListValues("all"); }else{ // All other text is ignored by this widget. } } void SeerGdbWidget::handleManualCommandExecute (QString command) { // Do nothing if it is blank. if (command == "") { return; } // Execute it. handleGdbCommand(command); } void SeerGdbWidget::handleGdbCommand (const QString& command, bool ignoreErrors) { qCDebug(LC) << "Command=" << command; if (_gdbProcess->state() == QProcess::NotRunning) { if (ignoreErrors == false) { QMessageBox::warning(this, "Seer", QString("The executable has not been started yet or has already exited.\n\n") + "(" + command + ")", QMessageBox::Ok); } return; } QString str = command + "\n"; // Ensure there's a trailing RETURN. QByteArray bytes = str.toUtf8(); // 8-bit Unicode Transformation Format #if SEER_GDB_LOGOUT == 1 // Broadcast this log. For debugging emit gdbCommandLogout("From Widget:" + str); #endif _gdbProcess->write(bytes); // Send the data into the stdin stream of the bash child process } void SeerGdbWidget::handleGdbCommands (const QStringList& commands) { // This may not be as good as using "source file.gdb" because it doesn't // stop on errors. But "source" doesn't support running mi commands. // // Leaving it here, though. QString c = commands.join('\n'); handleGdbCommand(c, true); } void SeerGdbWidget::handleGdbMonitorCommand (int id, const QString& command) { handleGdbCommand(QString::number(id)+"-monitor-exec " + command); } void SeerGdbWidget::handleGdbExit () { handleGdbCommand("-gdb-exit"); } void SeerGdbWidget::handleGdbRunExecutable (const QString& breakMode, bool loadSessionBreakpoints) { qCDebug(LC) << "Starting 'gdb run/start':" << breakMode; QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { // Has a executable name been provided? if (executableName() == "") { QMessageBox::warning(this, "Seer", QString("The executable name has not been provided.\n\nUse File->Debug..."), QMessageBox::Ok); break; } _executableBreakMode = breakMode; // Always say a new executable. // This causes a new gdb each time. The same console, though. setNewExecutableFlag(true); // Delete the old gdb if there is a new executable. if (newExecutableFlag() == true) { killGdb(); } // If gdb isn't running, start it. if (isGdbRuning() == false) { // Connect the terminal to the console. console()->resetTerminal(); console()->connectTerminal(); // Start gdb. bool f = startGdb(); if (f == false) { QMessageBox::critical(this, tr("Error"), tr("Can't start gdb.")); break; } if (gdbAsyncMode()) { handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen. } if (gdbNonStopMode()) { handleGdbCommand("-gdb-set pagination off"); handleGdbCommand("-gdb-set non-stop on"); }else{ handleGdbCommand("-gdb-set non-stop off"); } handleGdbLoadMICommands(); handleGdbSourceScripts(); handleGdbLoadSkips(); } // Set the program's tty device for stdin and stdout. handleGdbTerminalDeviceName(); setExecutableLaunchMode("run"); saveLaunchMode(); setGdbRecordMode("auto"); setExecutablePid(0); // Load the executable, if needed. if (newExecutableFlag() == true) { handleGdbSetArchitectureType(); handleGdbExecutablePreCommands(); // Run any 'pre' commands before program is loaded. handleGdbExecutableName(); // Load the program into the gdb process. handleGdbExecutableSources(); // Load the program source files. handleGdbExecutableLoadBreakpoints(); // Set the program's breakpoints (if any) before running. if (loadSessionBreakpoints) { handleGdbSessionLoadBreakpoints(); } setNewExecutableFlag(false); } // Set or reset some things. handleGdbExecutableWorkingDirectory(); // Set the program's working directory before running. handleGdbAssemblyDisassemblyFlavor(); // Set the disassembly flavor to use. handleGdbAssemblySymbolDemangling(); // Set the symbol demangling. editorManager()->maybeShowAssembly(); if (gdbHandleTerminatingException()) { handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions. }else{ handleGdbCommand("-gdb-set unwind-on-terminating-exception off"); } if (gdbRandomizeStartAddress()) { handleGdbCommand("-gdb-set disable-randomization off"); // Turn on randomization of starting address for process. } if (gdbEnablePrettyPrinting()) { handleGdbCommand("-enable-pretty-printing"); // Turn on pretty-printing. Can not be turned off. } // Set the program's arguments before running. handleGdbExecutableArguments(); // Set a breakpoint for start up if "infunction". if (_executableBreakMode == "infunction" && executableBreakpointFunctionName() != "") { if (executableBreakpointFunctionName().contains(QRegularExpression("^0[xX][0-9a-fA-F]+"))) { handleGdbBreakpointInsert("*" + executableBreakpointFunctionName()); }else{ handleGdbBreakpointInsert("-f --function " + executableBreakpointFunctionName()); } } // Set breakpoints for start up if "insource". if (_executableBreakMode == "insource" && executableBreakpointSourceName() != "") { handleGdbBreakpointsInsert(executableBreakpointSourceName()); } // Elaborate gdb variable output handleGdbCommand("set print repeats unlimited"); // Run any 'post' commands after program is loaded. handleGdbExecutablePostCommands(); // Run the executable. if (_executableBreakMode == "inmain") { handleGdbCommand("-exec-run --all --start"); // Stop in main. }else if (_executableBreakMode == "firstinstruction") { handleGdbCommand("-exec-starti"); // Stop at first instruction. }else{ handleGdbCommand("-exec-run --all"); // Do not stop in main. But honor other breakpoints that may have been previously set. } // Set window titles with name of program. emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableName()).arg(QGuiApplication::applicationPid())); // Notify the state of the GdbWidget has changed. emit stateChanged(); break; } QApplication::restoreOverrideCursor(); qCDebug(LC) << "Finishing 'gdb run/start'."; } void SeerGdbWidget::handleGdbAttachExecutable (bool loadSessionBreakpoints) { qCDebug(LC) << "Starting 'gdb attach'."; QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { // Has a executable name been provided? if (executableName() == "") { QMessageBox::warning(this, "Seer", QString("The executable name has not been provided.\n\nUse File->Debug..."), QMessageBox::Ok); break; } _executableBreakMode = ""; // Always say a new executable. // This causes a new gdb each time. The same console, though. setNewExecutableFlag(true); // Delete the old gdb if there is a new executable. if (newExecutableFlag() == true) { killGdb(); } // If gdb isn't running, start it. // No need to connect to the console in this mode. if (isGdbRuning() == false) { // Connect the terminal to the console. console()->resetTerminal(); console()->connectTerminal(); // Start gdb. bool f = startGdb(); if (f == false) { QMessageBox::critical(this, tr("Error"), tr("Can't start gdb.")); break; } if (gdbAsyncMode()) { handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen. } handleGdbLoadMICommands(); handleGdbSourceScripts(); handleGdbLoadSkips(); } // Set the program's tty device for stdin and stdout. // Not really needed for 'attach' mode, but do it anyway. handleGdbTerminalDeviceName(); // No console for 'attach' mode but make sure it's reattached. setExecutableLaunchMode("attach"); saveLaunchMode(); setGdbRecordMode("auto"); commandLogsWidget->reattachConsole(); // Load the executable, if needed. if (newExecutableFlag() == true) { handleGdbSetArchitectureType(); handleGdbExecutablePreCommands(); // Run any 'pre' commands before program is loaded. handleGdbExecutableName(); // Load the program into the gdb process. handleGdbExecutableSources(); // Load the program source files. handleGdbExecutableLoadBreakpoints(); // Set the program's breakpoints (if any) before running. if (loadSessionBreakpoints) { handleGdbSessionLoadBreakpoints(); } setNewExecutableFlag(false); } // Set or reset some things. handleGdbExecutableWorkingDirectory(); // Set the program's working directory before running. handleGdbAssemblyDisassemblyFlavor(); // Set the disassembly flavor to use. handleGdbAssemblySymbolDemangling(); // Set the symbol demangling. editorManager()->maybeShowAssembly(); if (gdbHandleTerminatingException()) { handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions. }else{ handleGdbCommand("-gdb-set unwind-on-terminating-exception off"); } // Attach to the executable's pid. handleGdbCommand(QString("-target-attach %1").arg(executablePid())); // Set breakpoints for start up if "insource". if (executableBreakpointSourceName() != "") { handleGdbBreakpointsInsert(executableBreakpointSourceName()); } // Elaborate gdb variable output handleGdbCommand("set print repeats unlimited"); // Run any 'post' commands after program is loaded. handleGdbExecutablePostCommands(); // Set window titles with name of program. emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableName()).arg(QGuiApplication::applicationPid())); // Notify the state of the GdbWidget has changed. emit stateChanged(); break; } QApplication::restoreOverrideCursor(); qCDebug(LC) << "Finishing 'gdb attach'."; } void SeerGdbWidget::handleGdbConnectExecutable (bool loadSessionBreakpoints) { qCDebug(LC) << "Starting 'gdb connect'."; QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { _executableBreakMode = ""; // Always say a new executable. // This causes a new gdb each time. The same console, though. setNewExecutableFlag(true); // Disconnect from the terminal and delete the old gdb if there is a new executable. if (newExecutableFlag() == true) { killGdb(); } // If gdb isn't running, start it. if (isGdbRuning() == false) { // Connect the terminal to the console. console()->resetTerminal(); console()->connectTerminal(); // Start gdb. bool f = startGdb(); if (f == false) { QMessageBox::critical(this, tr("Error"), tr("Can't start gdb.")); break; } handleGdbLoadMICommands(); handleGdbSourceScripts(); handleGdbLoadSkips(); } // Set the program's tty device for stdin and stdout. // Not really needed for 'connect' mode, but do it anyway. handleGdbTerminalDeviceName(); // No console for 'connect' mode but make sure it's reattached. setExecutableLaunchMode("connect"); saveLaunchMode(); setGdbRecordMode("auto"); setExecutablePid(0); commandLogsWidget->reattachConsole(); // Load any 'pre' commands. if (newExecutableFlag() == true) { if (gdbServerDebug()) { handleGdbCommand("-gdb-set debug remote 1"); // Turn on gdbserver debug }else{ handleGdbCommand("-gdb-set debug remote 0"); } handleGdbExecutablePreCommands(); // Run any 'pre' commands before program is loaded. } // Connect to the remote gdbserver using the proper remote type. handleGdbCommand(QString("-target-select %1 %2").arg(gdbRemoteTargetType()).arg(executableConnectHostPort())); // Load the executable, if needed. if (newExecutableFlag() == true) { handleGdbSetArchitectureType(); handleGdbExecutableName(); // Load the program into the gdb process. handleGdbExecutableSources(); // Load the program source files. handleGdbExecutableLoadBreakpoints(); // Set the program's breakpoints (if any) before running. if (loadSessionBreakpoints) { handleGdbSessionLoadBreakpoints(); } setNewExecutableFlag(false); } // Set or reset some things. handleGdbExecutableWorkingDirectory(); // Set the program's working directory before running. handleGdbAssemblyDisassemblyFlavor(); // Set the disassembly flavor to use. handleGdbAssemblySymbolDemangling(); // Set the symbol demangling. editorManager()->maybeShowAssembly(); if (gdbHandleTerminatingException()) { handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions. }else{ handleGdbCommand("-gdb-set unwind-on-terminating-exception off"); } // Set breakpoints for start up if "insource". if (executableBreakpointSourceName() != "") { handleGdbBreakpointsInsert(executableBreakpointSourceName()); } // Elaborate gdb variable output handleGdbCommand("set print repeats unlimited"); // Run any 'post' commands after program is loaded. handleGdbExecutablePostCommands(); // Set window titles with name of program. emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableConnectHostPort()).arg(QGuiApplication::applicationPid())); // Notify the state of the GdbWidget has changed. emit stateChanged(); break; } QApplication::restoreOverrideCursor(); qCDebug(LC) << "Finishing 'gdb connect'."; } void SeerGdbWidget::handleGdbRRExecutable (bool loadSessionBreakpoints) { qCDebug(LC) << "Starting 'gdb direct rr'."; QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { // Has a executable name been provided? if (executableName() != "") { QMessageBox::warning(this, "Seer", QString("The executable name can't be provided for 'rr' mode."), QMessageBox::Ok); break; } _executableBreakMode = ""; // Always say a new executable. // This causes a new gdb each time. The same console, though. setNewExecutableFlag(true); // Disconnect from the console and delete the old gdb, then reconnect. if (newExecutableFlag() == true) { killGdb(); } // If gdb isn't running, start it. if (isGdbRuning() == false) { // Connect the terminal to the console. console()->resetTerminal(); console()->connectTerminal(); // Start gdb. bool f = startGdbRR(); if (f == false) { QMessageBox::critical(this, tr("Error"), tr("Can't start gdb.")); break; } handleGdbLoadMICommands(); handleGdbSourceScripts(); handleGdbLoadSkips(); } // Set the program's tty device for stdin and stdout. handleGdbTerminalDeviceName(); // Set the launch mode. setExecutableLaunchMode("rr"); saveLaunchMode(); setGdbRecordMode("rr"); setGdbRecordDirection(""); setExecutablePid(0); // Load the executable, if needed. // For RR, this will start it. if (newExecutableFlag() == true) { handleGdbSetArchitectureType(); handleGdbExecutablePreCommands(); // Run any 'pre' commands before program is loaded. handleGdbExecutableName(); // Load the program into the gdb process. handleGdbExecutableSources(); // Load the program source files. handleGdbExecutableLoadBreakpoints(); // Set the program's breakpoints (if any) before running. if (loadSessionBreakpoints) { handleGdbSessionLoadBreakpoints(); } setNewExecutableFlag(false); } // Set or reset some things. handleGdbExecutableWorkingDirectory(); // Set the program's working directory before running. handleGdbAssemblyDisassemblyFlavor(); // Set the disassembly flavor to use. handleGdbAssemblySymbolDemangling(); // Set the symbol demangling. editorManager()->maybeShowAssembly(); if (gdbHandleTerminatingException()) { handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions. }else{ handleGdbCommand("-gdb-set unwind-on-terminating-exception off"); } if (gdbEnablePrettyPrinting()) { handleGdbCommand("-enable-pretty-printing"); // Turn on pretty-printing. Can not be turned off. } // Set breakpoints for start up if "insource". if (executableBreakpointSourceName() != "") { handleGdbBreakpointsInsert(executableBreakpointSourceName()); } // Elaborate gdb variable output handleGdbCommand("set print repeats unlimited"); // Run any 'post' commands after program is loaded. handleGdbExecutablePostCommands(); // Set window titles with name of program. emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableRRTraceDirectory()).arg(QGuiApplication::applicationPid())); // Notify the state of the GdbWidget has changed. emit stateChanged(); break; } QApplication::restoreOverrideCursor(); qCDebug(LC) << "Finishing 'gdb rr'."; } void SeerGdbWidget::handleGdbCoreFileExecutable () { qCDebug(LC) << "Starting 'gdb corefile'."; QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { // Has a executable name been provided? if (executableName() == "") { QMessageBox::warning(this, "Seer", QString("The executable name has not been provided.\n\nUse File->Debug..."), QMessageBox::Ok); break; } _executableBreakMode = ""; // Always say a new executable. // This causes a new gdb each time. The same console, though. setNewExecutableFlag(true); // Disconnect from the console and delete the old gdb. No need to reconnect. if (newExecutableFlag() == true) { killGdb(); } // If gdb isn't running, start it. // No need to connect to the console in this mode. if (isGdbRuning() == false) { // Connect the terminal to the console. console()->resetTerminal(); console()->connectTerminal(); // Start gdb. bool f = startGdb(); if (f == false) { QMessageBox::critical(this, tr("Error"), tr("Can't start gdb.")); break; } if (gdbAsyncMode()) { handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen. } handleGdbLoadMICommands(); handleGdbSourceScripts(); handleGdbLoadSkips(); } // Set the program's tty device for stdin and stdout. // Not really needed for 'core' mode, but do it anyway. handleGdbTerminalDeviceName(); // No console for 'core' mode but make sure it's reattached. setExecutableLaunchMode("corefile"); saveLaunchMode(); setGdbRecordMode("auto"); setExecutablePid(0); commandLogsWidget->reattachConsole(); if (newExecutableFlag() == true) { handleGdbSetArchitectureType(); handleGdbExecutablePreCommands(); // Run any 'pre' commands before program is loaded. handleGdbExecutableName(); // Load the program into the gdb process. handleGdbExecutableSources(); // Load the program source files. handleGdbAssemblyDisassemblyFlavor(); // Set the disassembly flavor to use. handleGdbAssemblySymbolDemangling(); // Set the symbol demangling. editorManager()->maybeShowAssembly(); } setNewExecutableFlag(false); // Load the executable's core file. handleGdbCommand(QString("-target-select core %1").arg(executableCoreFilename())); // Elaborate gdb variable output handleGdbCommand("set print repeats unlimited"); // Run any 'post' commands after program is loaded. handleGdbExecutablePostCommands(); // This is needed for 'core' mode to refresh the stack frame, for some reason. handleGdbStackListFrames(); // Set window titles with name of program. emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableName()).arg(QGuiApplication::applicationPid())); // Notify the state of the GdbWidget has changed. emit stateChanged(); break; } QApplication::restoreOverrideCursor(); qCDebug(LC) << "Finishing 'gdb corefile'."; } void SeerGdbWidget::handleGdbTerminateExecutable (bool confirm) { while (1) { // Do you really want to restart? if (isGdbRuning() == true) { if (confirm) { int result = QMessageBox::warning(this, "Seer", QString("Terminate current session?"), QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel); if (result == QMessageBox::Cancel) { break; } } handleGdbCommand(QString("save breakpoints /tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid()), true); delay(2); // Give the gdb and 'exit' command. // This should handle detaching from an attached pid. handleGdbCommand("-exec-kill", true); // Kill the gdb. killGdb(); // Print a message. addMessage("Program terminated.", QMessageBox::Warning); // Alert listeners the session has been terminated. emit sessionTerminated(); // Notify the state of the GdbWidget has changed. emit stateChanged(); } break; } } void SeerGdbWidget::handleGdbShutdown () { // Remove session breakpoint file, if any. QFile::remove(QString("/tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid())); // Do nothing if there's not gdb running. if (isGdbRuning() == false) { return; } // We are in no mode now. setExecutableLaunchMode(""); setGdbRecordMode(""); // Give the gdb and 'exit' command. // This should handle detaching from an attached pid. handleGdbExit(); // Kill the gdb. killGdb(); } void SeerGdbWidget::handleGdbRunToLine (QString fullname, int lineno) { if (executableLaunchMode() == "") { return; } QString command = "-exec-until " + fullname + ":" + QString::number(lineno); handleGdbCommand(command); } void SeerGdbWidget::handleGdbRunToAddress (QString address) { if (executableLaunchMode() == "") { return; } QString command = "-exec-until *" +address; handleGdbCommand(command); } void SeerGdbWidget::handleGdbNext () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-next %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbNexti () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-next-instruction %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbStep () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-step %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbStepi () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-step-instruction %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbFinish () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-finish %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbContinue () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-continue %1").arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbReverseNext () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-next --reverse"); } void SeerGdbWidget::handleGdbReverseNexti () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-next-instruction --reverse"); } void SeerGdbWidget::handleGdbReverseStep () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-step --reverse"); } void SeerGdbWidget::handleGdbReverseStepi () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-step-instruction --reverse"); } void SeerGdbWidget::handleGdbReverseFinish () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-finish --reverse"); } void SeerGdbWidget::handleGdbReverseContinue () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-exec-continue --reverse"); } void SeerGdbWidget::handleGdbRecordStart () { if (executableLaunchMode() == "") { return; } if (executableLaunchMode() == "rr" || executableLaunchMode() == "udb") { QMessageBox::warning(this, "Seer", QString("Record 'Start' not available in RR or UDB mode."), QMessageBox::Ok); return; } setGdbRecordMode("full"); setGdbRecordDirection(""); } void SeerGdbWidget::handleGdbRecordStop () { if (executableLaunchMode() == "") { return; } if (executableLaunchMode() == "rr" || executableLaunchMode() == "udb") { QMessageBox::warning(this, "Seer", QString("Record 'Stop' not available in RR or UDB mode."), QMessageBox::Ok); return; } setGdbRecordMode("stop"); setGdbRecordDirection(""); } void SeerGdbWidget::handleGdbRecordForward () { setGdbRecordDirection(""); } void SeerGdbWidget::handleGdbRecordReverse () { setGdbRecordDirection("--reverse"); } void SeerGdbWidget::handleGdbRecordStartStopToggle () { if (gdbRecordMode() == "stop" || gdbRecordMode() == "") { setGdbRecordMode("full"); setGdbRecordDirection(""); }else if (gdbRecordMode() == "full") { setGdbRecordMode("stop"); setGdbRecordDirection(""); }else if (gdbRecordMode() == "rr") { // Don't do anthing. }else if (gdbRecordMode() == "udb") { // Don't do anthing. }else{ setGdbRecordMode("stop"); setGdbRecordDirection(""); } } void SeerGdbWidget::handleGdbRecordDirectionToggle () { if (gdbRecordDirection() == "") { setGdbRecordDirection("--reverse"); }else if (gdbRecordDirection() == "--reverse") { setGdbRecordDirection(""); }else{ setGdbRecordDirection(""); } } void SeerGdbWidget::handleGdbInterrupt () { sendGdbInterrupt(-1); } void SeerGdbWidget::handleGdbInterruptSIGINT () { sendGdbInterrupt(SIGINT); } void SeerGdbWidget::handleGdbInterruptSIGKILL () { sendGdbInterrupt(SIGKILL); } void SeerGdbWidget::handleGdbInterruptSIGFPE () { sendGdbInterrupt(SIGFPE); } void SeerGdbWidget::handleGdbInterruptSIGSEGV () { sendGdbInterrupt(SIGSEGV); } void SeerGdbWidget::handleGdbInterruptSIGUSR1 () { sendGdbInterrupt(SIGUSR1); } void SeerGdbWidget::handleGdbInterruptSIGUSR2 () { sendGdbInterrupt(SIGUSR2); } void SeerGdbWidget::handleGdbRunThreadGroup (QString threadGroup) { if (executableLaunchMode() == "") { return; } if (threadGroup == "") { return; } handleGdbCommand(QString("-exec-run --thread-group %1").arg(threadGroup)); } void SeerGdbWidget::handleGdbStartThreadGroup (QString threadGroup) { if (executableLaunchMode() == "") { return; } if (threadGroup == "") { return; } handleGdbCommand(QString("-exec-run --thread-group %1 --start").arg(threadGroup)); } void SeerGdbWidget::handleGdbContinueThreadGroup (QString threadGroup) { if (executableLaunchMode() == "") { return; } if (threadGroup == "") { return; } handleGdbCommand(QString("-exec-continue %1 --thread-group %2").arg(gdbRecordDirection()).arg(threadGroup)); } void SeerGdbWidget::handleGdbInterruptThreadGroup (QString threadGroup) { if (executableLaunchMode() == "") { return; } if (threadGroup == "") { return; } handleGdbCommand(QString("-exec-interrupt --thread-group %1").arg(threadGroup)); } void SeerGdbWidget::handleGdbNextThreadId (int threadid) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-next --thread %1 %2").arg(threadid).arg(gdbRecordDirection())); } void SeerGdbWidget::handleGdbStepThreadId (int threadid) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-step %1 --thread %2").arg(gdbRecordDirection()).arg(threadid)); } void SeerGdbWidget::handleGdbFinishThreadId (int threadid) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-finish %1 --thread %2").arg(gdbRecordDirection()).arg(threadid)); } void SeerGdbWidget::handleGdbContinueThreadId (int threadid) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-continue %1 --thread %2").arg(gdbRecordDirection()).arg(threadid)); } void SeerGdbWidget::handleGdbInterruptThreadId (int threadid) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-interrupt --thread %1").arg(threadid)); } void SeerGdbWidget::handleGdbExecutableSources () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-file-list-exec-source-files"); } void SeerGdbWidget::handleGdbExecutableFunctions (int id, const QString& functionRegex) { if (executableLaunchMode() == "") { return; } if (id <= 0) { return; } if (functionRegex == "") { return; } QApplication::setOverrideCursor(Qt::BusyCursor); handleGdbCommand(QString("%1-symbol-info-functions --include-nondebug --name %2").arg(id).arg(functionRegex)); QApplication::restoreOverrideCursor(); } void SeerGdbWidget::handleGdbExecutableTypes (int id, const QString& typeRegex) { if (executableLaunchMode() == "") { return; } if (id <= 0) { return; } if (typeRegex == "") { return; } //qDebug() << id << typeRegex; handleGdbCommand(QString("%1-symbol-info-types --name %2").arg(id).arg(typeRegex)); } void SeerGdbWidget::handleGdbExecutableVariables (int id, const QString& variableNameRegex, const QString& variableTypeRegex) { if (executableLaunchMode() == "") { return; } if (id <= 0) { return; } if (variableNameRegex == "" && variableTypeRegex == "") { return; } QString command = QString("%1-symbol-info-variables").arg(id); if (variableNameRegex != "") { command += QString(" --name %1").arg(variableNameRegex); } if (variableTypeRegex != "") { command += QString(" --type %1").arg(variableTypeRegex); } handleGdbCommand(command); } void SeerGdbWidget::handleGdbExecutableLibraries () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-file-list-shared-libraries"); } void SeerGdbWidget::handleGdbExecutableName () { if (executableLaunchMode() == "") { return; } //qDebug() << executableName(); //qDebug() << executableSymbolName(); // executableName() is expected to be non-blank. // An executable and no symbol file? Symbols are expected in the executable. if (executableName() != "" && executableSymbolName() == "") { handleGdbCommand(QString("-file-exec-and-symbols \"") + executableName() + "\""); // An executable and a symbol file? Open the executable and symbol files separately. }else if (executableName() != "" && executableSymbolName() != "") { handleGdbCommand(QString("-file-exec-file \"") + executableName() + "\""); handleGdbCommand(QString("-file-symbol-file \"") + executableSymbolName() + "\""); // No executable and a symbol file? Open the symbol files only. }else if (executableName() == "" && executableSymbolName() != "") { handleGdbCommand(QString("-file-symbol-file \"") + executableSymbolName() + "\""); } } void SeerGdbWidget::handleGdbExecutableArguments () { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-exec-arguments ") + executableArguments()); } void SeerGdbWidget::handleGdbExecutableWorkingDirectory () { if (executableLaunchMode() == "") { return; } if (executableWorkingDirectory() != "") { handleGdbCommand(QString("-environment-cd \"") + executableWorkingDirectory() + "\""); } } void SeerGdbWidget::handleGdbExecutableLoadBreakpoints () { if (executableBreakpointsFilename() == "") { return; } handleGdbCommand("source -v " + executableBreakpointsFilename()); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbExecutablePreCommands () { for (const auto& i : _executablePreGdbCommands) { handleGdbCommand(i); } } void SeerGdbWidget::handleGdbExecutablePostCommands () { for (const auto& i : _executablePostGdbCommands) { handleGdbCommand(i); } } void SeerGdbWidget::handleGdbSessionLoadBreakpoints () { QString filename = QString("/tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid()); if (QFile::exists(filename) == false) { return; } handleGdbCommand(QString("source -v %1").arg(filename)); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbSessionSaveBreakpoints () { handleGdbCommand(QString("source -v /tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid())); } void SeerGdbWidget::handleGdbTerminalDeviceName () { if (commandLogsWidget->console()->terminalDeviceName() != "") { handleGdbCommand(QString("-inferior-tty-set ") + commandLogsWidget->console()->terminalDeviceName()); }else{ qWarning() << "Can't set TTY name because the name is blank."; } } void SeerGdbWidget::handleGdbStackListFrames () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-stack-list-frames"); } void SeerGdbWidget::handleGdbStackSelectFrame (int frameno) { if (executableLaunchMode() == "") { return; } // This is not supported anymore with gdbmi. // handleGdbCommand(QString("-stack-select-frame %1").arg(frameno)); // So resort to calling the non-gdbmi version. handleGdbCommand(QString("frame %1").arg(frameno)); emit stoppingPointReached(); } void SeerGdbWidget::handleGdbStackListLocals () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-stack-list-variables --all-values"); } void SeerGdbWidget::handleGdbStackListArguments () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-stack-list-arguments --all-values"); } void SeerGdbWidget::handleGdbGenericpointList () { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-list"); } void SeerGdbWidget::handleGdbBreakpointDelete (QString breakpoints) { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-delete " + breakpoints); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointEnable (QString breakpoints) { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-enable " + breakpoints); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointDisable (QString breakpoints) { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-disable " + breakpoints); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointInfo (int breakpointid, QString breakpoint) { if (executableLaunchMode() == "") { return; } QString str = QString("%1-break-info %2").arg(breakpointid).arg(breakpoint); handleGdbCommand(str); } void SeerGdbWidget::handleGdbBreakpointsInsert (QString breakpoints) { if (executableLaunchMode() == "") { return; } QStringList breakpointlist = breakpoints.split(','); for (const QString& breakpoint : breakpointlist) { handleGdbBreakpointInsert(breakpoint); } handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointInsert (QString breakpoint) { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-insert " + breakpoint); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointCondition (QString breakpoint, QString condition) { if (executableLaunchMode() == "") { return; } QString str = condition.replace('"', "\\\""); // Quote " characters. handleGdbCommand("-break-condition " + breakpoint + " \"" + condition + "\""); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointIgnore (QString breakpoint, QString count) { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-after " + breakpoint + " " + count); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointCommand (QString breakpoint, QString command) { if (executableLaunchMode() == "") { return; } handleGdbCommand("-break-commands " + breakpoint + " \"" + command + "\""); handleGdbGenericpointList(); } void SeerGdbWidget::handleGdbBreakpointCommands (QString breakpoint, QStringList commands) { if (executableLaunchMode() == "") { return; } QString commandstext; for (int i=0; ihandleTextOutput(text); } void SeerGdbWidget::handleGdbDataAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } // Is this one already present? // ??? Emit an error? if (_dataExpressionName.indexOf(expression) >= 0) { return; } // Add it to our list of variables. _dataExpressionName.push_back(expression); _dataExpressionId.push_back(Seer::createID()); // ^done,DataExpressionAdded={ // id="2", // expression="a" // } QString text = QString("^done,DataExpressionAdded={id=\"%1\",expression=\"%2\"}").arg(_dataExpressionId.back()).arg(_dataExpressionName.back()); //qDebug() << text; gdbMonitor()->handleTextOutput(text); } void SeerGdbWidget::handleGdbDataDeleteExpressions (QString expressionids) { if (executableLaunchMode() == "") { // Clear expression list. _dataExpressionId.clear(); _dataExpressionName.clear(); return; } // ^done,DataExpressionDeleted={ // entry={id="2", expression="a"}, // entry={id="3", expression="a"} // } QString text; text += "^done,DataExpressionDeleted={"; if (expressionids == "*") { bool first = true; for (int i=0; i<_dataExpressionId.size(); i++) { if (first == false) { text += ","; } text += "entry={id=\"" + QString::number(_dataExpressionId[i]) + "\",expression=\"" + _dataExpressionName[i] + "\"}"; first = false; } _dataExpressionId.clear(); _dataExpressionName.clear(); }else{ QStringList ids = expressionids.split(' ', Qt::SkipEmptyParts); bool first = true; for (int i=0; ihandleTextOutput(text); } void SeerGdbWidget::handleGdbMemoryAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerMemoryVisualizerWidget* w = new SeerMemoryVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerMemoryVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerMemoryVisualizerWidget::handleText); QObject::connect(w, &SeerMemoryVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(w, &SeerMemoryVisualizerWidget::evaluateMemoryExpression, this, QOverload::of(&SeerGdbWidget::handleGdbMemoryEvaluateExpression)); QObject::connect(w, &SeerMemoryVisualizerWidget::evaluateAsmExpression, this, &SeerGdbWidget::handleGdbAsmEvaluateExpression); // Tell the visualizer what variable to use. w->setVariableName(expression); } void SeerGdbWidget::handleGdbArrayAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerArrayVisualizerWidget* w = new SeerArrayVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerArrayVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerArrayVisualizerWidget::handleText); QObject::connect(w, &SeerArrayVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(w, &SeerArrayVisualizerWidget::evaluateMemoryExpression, this, &SeerGdbWidget::handleGdbArrayEvaluateExpression); // Tell the visualizer what variable to use. w->setAVariableName(expression); } void SeerGdbWidget::handleGdbMatrixAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerMatrixVisualizerWidget* w = new SeerMatrixVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerMatrixVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerMatrixVisualizerWidget::handleText); QObject::connect(w, &SeerMatrixVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(w, &SeerMatrixVisualizerWidget::evaluateMemoryExpression, this, &SeerGdbWidget::handleGdbArrayEvaluateExpression); // Tell the visualizer what variable to use. w->setVariableName(expression); } void SeerGdbWidget::handleGdbStructAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerStructVisualizerWidget* w = new SeerStructVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerStructVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerStructVisualizerWidget::handleText); QObject::connect(w, &SeerStructVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(w, &SeerStructVisualizerWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(w, &SeerStructVisualizerWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(w, &SeerStructVisualizerWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(w, &SeerStructVisualizerWidget::addStructVisualizer, this, &SeerGdbWidget::handleGdbStructAddExpression); // Tell the visualizer what variable to use. w->setVariableName(expression); } void SeerGdbWidget::handleGdbVarAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerVarVisualizerWidget* w = new SeerVarVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerVarVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerVarVisualizerWidget::handleText); QObject::connect(w, &SeerVarVisualizerWidget::varObjCreate, this, &SeerGdbWidget::handleGdbVarObjCreate); QObject::connect(w, &SeerVarVisualizerWidget::varObjListChildren, this, &SeerGdbWidget::handleGdbVarObjListChildren); QObject::connect(w, &SeerVarVisualizerWidget::varObjUpdate, this, &SeerGdbWidget::handleGdbVarObjUpdate); QObject::connect(w, &SeerVarVisualizerWidget::varObjAssign, this, &SeerGdbWidget::handleGdbVarObjAssign); QObject::connect(w, &SeerVarVisualizerWidget::varObjDelete, this, &SeerGdbWidget::handleGdbVarObjDelete); QObject::connect(w, &SeerVarVisualizerWidget::varObjAttributes, this, &SeerGdbWidget::handleGdbVarObjAttributes); QObject::connect(w, &SeerVarVisualizerWidget::addMemoryVisualizer, this, &SeerGdbWidget::handleGdbMemoryAddExpression); QObject::connect(w, &SeerVarVisualizerWidget::addArrayVisualizer, this, &SeerGdbWidget::handleGdbArrayAddExpression); QObject::connect(w, &SeerVarVisualizerWidget::addMatrixVisualizer, this, &SeerGdbWidget::handleGdbMatrixAddExpression); QObject::connect(w, &SeerVarVisualizerWidget::addVarVisualizer, this, &SeerGdbWidget::handleGdbVarAddExpression); // Tell the visualizer what variable to use. w->setVariableName(expression); } void SeerGdbWidget::handleGdbImageAddExpression (QString expression) { if (executableLaunchMode() == "") { return; } SeerImageVisualizerWidget* w = new SeerImageVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerImageVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerImageVisualizerWidget::handleText); QObject::connect(w, &SeerImageVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); QObject::connect(w, &SeerImageVisualizerWidget::evaluateMemoryExpression, this, QOverload::of(&SeerGdbWidget::handleGdbMemoryEvaluateExpression)); // Tell the visualizer what variable to use. w->setVariableName(expression); } void SeerGdbWidget::handleGdbMemoryEvaluateExpression (int expressionid, QString address, int count) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString::number(expressionid) + "-data-read-memory-bytes " + address + " " + QString::number(count)); } void SeerGdbWidget::handleGdbMemoryEvaluateExpression (int expressionid, QString address, int offset, int count) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString::number(expressionid) + "-data-read-memory-bytes -o " + QString::number(offset) + " " + address + " " + QString::number(count)); } void SeerGdbWidget::handleGdbAsmEvaluateExpression (int expressionid, QString address, int count, int mode) { // -data-disassemble -s $pc -e "$pc + 96" -- 2 if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("%1-data-disassemble -s \"%2 - %3\" -e \"%4 + %5\" -- %6").arg(expressionid).arg(address).arg(0).arg(address).arg(count).arg(mode)); } void SeerGdbWidget::handleGdbArrayEvaluateExpression (int expressionid, QString address, int count) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString::number(expressionid) + "-data-read-memory-bytes " + address + " " + QString::number(count)); } void SeerGdbWidget::handleGdbGetAssembly (QString address) { if (executableLaunchMode() == "") { return; } //qDebug() << "Getting assembly for address" << address << "for mode" << assemblyDisassemblyMode(); QString command; if (assemblyDisassemblyMode() == "length") { command = QString("-data-disassemble -s \"%1\" -e \"%1 + %2\" -- 2").arg(address).arg(assemblyDisassemblyBytes()); }else if (assemblyDisassemblyMode() == "function") { command = QString("-data-disassemble -a \"%1\" -- 2").arg(address); }else{ command = QString("-data-disassemble -a \"%1\" -- 2").arg(address); } //qDebug() << command; handleGdbCommand(command); } void SeerGdbWidget::handleGdbGetSourceAndAssembly (QString address) { if (executableLaunchMode() == "") { return; } //qDebug() << "Getting source and assembly for address" << address << "for mode" << assemblyDisassemblyMode(); QString command; if (assemblyDisassemblyMode() == "length") { command = QString("-data-disassemble -s \"%1\" -e \"%1 + %2\" -- 5").arg(address).arg(assemblyDisassemblyBytes()); }else if (assemblyDisassemblyMode() == "function") { command = QString("-data-disassemble -a \"%1\" -- 5").arg(address); }else{ command = QString("-data-disassemble -a \"%1\" -- 5").arg(address); } //qDebug() << command; handleGdbCommand(command); } void SeerGdbWidget::handleGdbParallelStackFrames (int expressionid) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString::number(expressionid) + "-frames-list"); } void SeerGdbWidget::handleGdbMemoryVisualizer () { handleGdbMemoryAddExpression(""); } void SeerGdbWidget::handleGdbArrayVisualizer () { handleGdbArrayAddExpression(""); } void SeerGdbWidget::handleGdbMatrixVisualizer () { handleGdbMatrixAddExpression(""); } void SeerGdbWidget::handleGdbStructVisualizer () { handleGdbStructAddExpression(""); } void SeerGdbWidget::handleGdbVarVisualizer () { handleGdbVarAddExpression(""); } void SeerGdbWidget::handleGdbImageVisualizer () { handleGdbImageAddExpression(""); } void SeerGdbWidget::handleGdbParallelStacksVisualizer () { if (executableLaunchMode() == "") { return; } SeerParallelStacksVisualizerWidget* w = new SeerParallelStacksVisualizerWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerParallelStacksVisualizerWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerParallelStacksVisualizerWidget::handleText); QObject::connect(w, &SeerParallelStacksVisualizerWidget::refreshParallelStackFrames, this, &SeerGdbWidget::handleGdbParallelStackFrames); QObject::connect(w, &SeerParallelStacksVisualizerWidget::selectedThread, this, &SeerGdbWidget::handleGdbThreadSelectId); QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::selectedThread, w, &SeerParallelStacksVisualizerWidget::highlightSelectedThread); QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::selectedFrame, w, &SeerParallelStacksVisualizerWidget::highlightSelectedFrame); // Force a inital refresh. w->refresh(); } void SeerGdbWidget::handleGdbMonitor () { if (executableLaunchMode() == "") { return; } SeerGdbMonitorWidget* w = new SeerGdbMonitorWidget(0); w->show(); // Connect things. QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerGdbMonitorWidget::handleText); QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerGdbMonitorWidget::handleText); QObject::connect(w, &SeerGdbMonitorWidget::executeGdbMonitorCommand, this, &SeerGdbWidget::handleGdbMonitorCommand); } void SeerGdbWidget::handleSplitterMoved (int pos, int index) { Q_UNUSED(pos); Q_UNUSED(index); //qDebug() << "Splitter moved to " << pos << index; writeSettings(); } void SeerGdbWidget::handleGdbAssemblyDisassemblyFlavor () { if (_assemblyDisassemblyFlavor != "") { handleGdbCommand(QString("-gdb-set disassembly-flavor ") + _assemblyDisassemblyFlavor); } } void SeerGdbWidget::handleGdbAssemblySymbolDemangling () { if (_assemblySymbolDemangling != "") { handleGdbCommand(QString("-gdb-set print asm-demangle ") + _assemblySymbolDemangling); } } void SeerGdbWidget::handleGdbProcessFinished (int exitCode, QProcess::ExitStatus exitStatus) { //qDebug() << "Gdb process finished. Exit code =" << exitCode << "Exit status =" << exitStatus; // Warn if gdb exits only if we are in some kind of run mode. if (executableLaunchMode() != "") { QMessageBox::warning(this, "Seer", QString("The GDB program exited unexpectedly.\n\n") + QString("Exit code=%1 Exit status=%2").arg(exitCode).arg(exitStatus) + "\n\n" + QString("'%1 %2'").arg(_gdbProcess->program()).arg(_gdbProcess->arguments().join(' ')) + "\n\n" + QString("Please restart Seer."), QMessageBox::Ok); } } void SeerGdbWidget::handleGdbProcessErrored (QProcess::ProcessError errorStatus) { //qDebug() << "Error launching gdb process. Error =" << errorStatus; if (errorStatus == QProcess::FailedToStart) { QMessageBox::warning(this, "Seer", QString("Unable to launch the GDB program.\n\n") + QString("'%1 %2'").arg(_gdbProcess->program()).arg(_gdbProcess->arguments().join(' ')) + "\n\n" + QString("Error status=%1").arg(errorStatus), QMessageBox::Ok); } } void SeerGdbWidget::handleAboutToQuit () { // Detect if we're exiting Seer. setIsQuitting(true); } void SeerGdbWidget::writeSettings () { //qDebug() << "Write Settings"; QSettings settings; settings.beginGroup("mainwindowsplitters"); { settings.setValue("leftCenterRightSplitter", leftCenterRightSplitter->saveState()); settings.setValue("sourceCommandLogsSplitter", sourceCommandLogsSplitter->saveState()); settings.setValue("sourceLibraryVariableManagerSplitter", sourceLibraryVariableManagerSplitter->saveState()); settings.setValue("stackThreadManagerSplitter", stackThreadManagerSplitter->saveState()); } settings.endGroup(); settings.beginGroup("consolewindow"); { settings.setValue("mode", consoleMode()); settings.setValue("scrolllines", consoleScrollLines()); }settings.endGroup(); settings.beginWriteArray("sourcealternatedirectories"); { QStringList directories = sourceAlternateDirectories(); for (int i = 0; i < directories.size(); ++i) { settings.setArrayIndex(i); settings.setValue("directory", directories[i]); } } settings.endArray(); settings.beginWriteArray("sourceignorefilepatters"); { QStringList patterns = sourceIgnoreFilePatterns(); for (int i = 0; i < patterns.size(); ++i) { settings.setArrayIndex(i); settings.setValue("pattern", patterns[i]); } } settings.endArray(); settings.beginWriteArray("sourcemiscfilepatterns"); { QStringList patterns = sourceMiscFilePatterns(); for (int i = 0; i < patterns.size(); ++i) { settings.setArrayIndex(i); settings.setValue("pattern", patterns[i]); } } settings.endArray(); settings.beginWriteArray("sourcesourcefilepatterns"); { QStringList patterns = sourceSourceFilePatterns(); for (int i = 0; i < patterns.size(); ++i) { settings.setArrayIndex(i); settings.setValue("pattern", patterns[i]); } } settings.endArray(); settings.beginWriteArray("sourceheaderfilepatterns"); { QStringList patterns = sourceHeaderFilePatterns(); for (int i = 0; i < patterns.size(); ++i) { settings.setArrayIndex(i); settings.setValue("pattern", patterns[i]); } } settings.endArray(); settings.beginGroup("assembly"); { settings.setValue("showassemblytabonstartupmode", assemblyShowAssemblyTabOnStartupMode()); settings.setValue("keepassemblytabontop", assemblyKeepAssemblyTabOnTop()); settings.setValue("assemblydisassemblyflavor", assemblyDisassemblyFlavor()); settings.setValue("assemblysymboldemagling", assemblySymbolDemagling()); settings.setValue("assemblyregisterformat", assemblyRegisterFormat()); settings.setValue("assemblyshowaddresscolumn", assemblyShowAddressColumn()); settings.setValue("assemblyshowoffsetcolumn", assemblyShowOffsetColumn()); settings.setValue("assemblyshowopcodecolumn", assemblyShowOpcodeColumn()); settings.setValue("assemblyshowsourcelines", assemblyShowSourceLines()); settings.setValue("assemblydisassemblymode", assemblyDisassemblyMode()); settings.setValue("assemblydisassemblybytes", assemblyDisassemblyBytes()); } settings.endGroup(); } void SeerGdbWidget::readSettings () { QSettings settings; int size; settings.beginGroup("mainwindowsplitters"); { leftCenterRightSplitter->restoreState(settings.value("leftCenterRightSplitter").toByteArray()); sourceCommandLogsSplitter->restoreState(settings.value("sourceCommandLogsSplitter").toByteArray()); sourceLibraryVariableManagerSplitter->restoreState(settings.value("sourceLibraryVariableManagerSplitter").toByteArray()); stackThreadManagerSplitter->restoreState(settings.value("stackThreadManagerSplitter").toByteArray()); } settings.endGroup(); settings.beginGroup("consolewindow"); { setConsoleMode(settings.value("mode", "attached").toString()); setConsoleScrollLines(settings.value("scrolllines", 1000).toInt()); } settings.endGroup(); size = settings.beginReadArray("sourcealternatedirectories"); { QStringList directories; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); directories << settings.value("directory").toString(); } setSourceAlternateDirectories(directories); } settings.endArray(); size = settings.beginReadArray("sourceignorefilepatters"); { QStringList patterns; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); patterns << settings.value("pattern").toString(); } setSourceIgnoreFilePatterns(patterns); } settings.endArray(); if (settings.childGroups().contains("sourcemiscfilepatterns")) { size = settings.beginReadArray("sourcemiscfilepatterns"); { QStringList patterns; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); patterns << settings.value("pattern").toString(); } setSourceMiscFilePatterns(patterns); } settings.endArray(); } if (settings.childGroups().contains("sourcesourcefilepatterns")) { size = settings.beginReadArray("sourcesourcefilepatterns"); { QStringList patterns; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); patterns << settings.value("pattern").toString(); } setSourceSourceFilePatterns(patterns); } settings.endArray(); } if (settings.childGroups().contains("sourceheaderfilepatterns")) { size = settings.beginReadArray("sourceheaderfilepatterns"); { QStringList patterns; for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); patterns << settings.value("pattern").toString(); } setSourceHeaderFilePatterns(patterns); } settings.endArray(); } settings.beginGroup("assembly"); { setAssemblyShowAssemblyTabOnStartupMode( settings.value("showassemblytabonstartupmode", "never").toString()); setAssemblyKeepAssemblyTabOnTop( settings.value("keepassemblytabontop", true).toBool()); setAssemblyDisassemblyFlavor( settings.value("assemblydisassemblyflavor", "att").toString()); setAssemblySymbolDemagling( settings.value("assemblysymboldemagling", "on").toString()); setAssemblyRegisterFormat( settings.value("assemblyregisterformat", "Natural").toString()); setAssemblyShowAddressColumn( settings.value("assemblyshowaddresscolumn", true).toBool()); setAssemblyShowOffsetColumn( settings.value("assemblyshowoffsetcolumn", false).toBool()); setAssemblyShowOpcodeColumn( settings.value("assemblyshowopcodecolumn", false).toBool()); setAssemblyShowSourceLines( settings.value("assemblyshowsourcelines", false).toBool()); setAssemblyDisassemblyMode( settings.value("assemblydisassemblymode", "function").toString(), settings.value("assemblydisassemblybytes", "256").toInt()); } settings.endGroup(); } bool SeerGdbWidget::isQuitting () const { return _isQuitting; } void SeerGdbWidget::setIsQuitting (bool f) { _isQuitting = f; } bool SeerGdbWidget::isGdbRuning () const { if (_gdbProcess->state() == QProcess::NotRunning) { return false; } return true; } bool SeerGdbWidget::startGdb () { // Don't do anything, if already running. if (isGdbRuning()) { qWarning() << "Already running"; return false; } // Build the raw command to launch the gdb program. // Later the raw command will be broken into individual strings (via ' ') // that the QProcess object expects. QString rawcommand; // Is a 'launcher' being used? Like 'flatpak-spawn'. if (gdbLauncher() != "") { rawcommand += gdbLauncher() + " "; } // Set the gdb program name to use. if (gdbProgramOverride() != "") { rawcommand += gdbProgramOverride() + " "; }else{ rawcommand += gdbProgram() + " "; } // Build the gdb argument list. if (gdbArgumentsOverride() != "") { rawcommand += gdbArgumentsOverride() + " "; }else{ rawcommand += gdbArguments() + " "; } // Now expand any $VAR environment variables. bool ok; QString expandedcommand = Seer::expandEnv(rawcommand, &ok); //qDebug() << "Raw command : " << rawcommand; //qDebug() << "Expanded command: " << expandedcommand; if (ok == false) { QMessageBox::critical(this, "Error", QString("Can't resolve all environment variables in command to launch gdb:\n'%1'").arg(rawcommand)); return false; } // Split string into words, handling "double quoted" words. QStringList args = Seer::split(expandedcommand); // Extract the program name and create a list of arguments. QString program = args.front(); args.pop_front(); // Give the gdb process the program and the argument list. _gdbProcess->setProgram(program); _gdbProcess->setArguments(args); // We need to set the C language, otherwise the MI interface is translated and our message // filters will not work. QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("LANG", "C"); _gdbProcess->setProcessEnvironment(env); // Start the gdb process. _gdbProcess->start(); //qDebug() << _gdbProcess->state(); return true; } bool SeerGdbWidget::startGdbRR () { // Don't do anything, if already running. if (isGdbRuning()) { qWarning() << "Already running"; return false; } // Does the RR trace directory exist? if (QFile::exists(executableRRTraceDirectory()) == false) { QMessageBox::critical(this, "Seer", QString("The RR trace-directory '" + executableRRTraceDirectory() + "' doesn't exist."), QMessageBox::Ok); return false; } // Build the raw command to launch the RR program. // Later the raw command will be broken into individual strings (via ' ') // that the QProcess object expects. QString rawcommand; // Is a 'launcher' being used? Like 'flatpak-spawn'. if (gdbLauncher() != "") { rawcommand += gdbLauncher() + " "; } // Set the RR program name to use. rawcommand += rrProgram() + " "; rawcommand += rrArguments() + " --tty " + commandLogsWidget->console()->terminalDeviceName() + " " + executableRRTraceDirectory() + " "; // Set any extra gdb arguments that RR may want. if (rrGdbArguments() != "") { rawcommand += "-- " + rrGdbArguments() + " "; } // Now expand any $VAR environment variables. bool ok; QString expandedcommand = Seer::expandEnv(rawcommand, &ok); //qDebug() << "Raw command : " << rawcommand; //qDebug() << "Expanded command: " << expandedcommand; if (ok == false) { QMessageBox::critical(this, "Error", QString("Can't resolve all environment variables in command to launch RR:\n'%1'").arg(rawcommand)); return false; } // Split string into words, handling "double quoted" words. QStringList args = Seer::split(expandedcommand); // Extract the program name and create a list of arguments. QString program = args.front(); args.pop_front(); // Give the gdb process the program and the argument list. _gdbProcess->setProgram(program); _gdbProcess->setArguments(args); // We need to set the C language, otherwise the MI interface is translated and our message // filters will not work. QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("LANG", "C"); _gdbProcess->setProcessEnvironment(env); // Start the gdb process. _gdbProcess->start(); //qDebug() << _gdbProcess->state(); return true; } void SeerGdbWidget::killGdb () { // Don't do anything, if isn't running. if (isGdbRuning() == false) { return; } // Clear the launch mode. setExecutableLaunchMode(""); setGdbRecordMode(""); // Kill the process. _gdbProcess->kill(); // Wait for it to end. _gdbProcess->waitForFinished(); // Sanity check. if (isGdbRuning()) { qWarning() << "Is running but shouldn't be."; } } SeerConsoleWidget* SeerGdbWidget::console () { return commandLogsWidget->console(); } void SeerGdbWidget::setConsoleMode (const QString& mode) { commandLogsWidget->setConsoleMode(mode); } QString SeerGdbWidget::consoleMode () const { return commandLogsWidget->consoleMode(); } void SeerGdbWidget::setConsoleScrollLines (int count) { commandLogsWidget->setConsoleScrollLines(count); } int SeerGdbWidget::consoleScrollLines () const { return commandLogsWidget->consoleScrollLines(); } void SeerGdbWidget::setRememberManualCommandCount (int count) { commandLogsWidget->setRememberManualCommandCount(count); } int SeerGdbWidget::rememberManualCommandCount () const { return commandLogsWidget->rememberManualCommandCount(); } void SeerGdbWidget::clearManualCommandHistory () { commandLogsWidget->clearManualCommandHistory(); } const QStringList& SeerGdbWidget::sourceAlternateDirectories() const { return editorManager()->editorAlternateDirectories(); } void SeerGdbWidget::setSourceAlternateDirectories (const QStringList& alternateDirectories) { editorManager()->setEditorAlternateDirectories(alternateDirectories); } void SeerGdbWidget::setSourceMiscFilePatterns (const QStringList& filePatterns) { sourceLibraryManagerWidget->sourceBrowserWidget()->setMiscFilePatterns(filePatterns); } const QStringList& SeerGdbWidget::sourceMiscFilePatterns () const { return sourceLibraryManagerWidget->sourceBrowserWidget()->miscFilePatterns(); } void SeerGdbWidget::setSourceSourceFilePatterns (const QStringList& filePatterns) { sourceLibraryManagerWidget->sourceBrowserWidget()->setSourceFilePatterns(filePatterns); } const QStringList& SeerGdbWidget::sourceSourceFilePatterns () const { return sourceLibraryManagerWidget->sourceBrowserWidget()->sourceFilePatterns(); } void SeerGdbWidget::setSourceHeaderFilePatterns (const QStringList& filePatterns) { sourceLibraryManagerWidget->sourceBrowserWidget()->setHeaderFilePatterns(filePatterns); } const QStringList& SeerGdbWidget::sourceHeaderFilePatterns () const { return sourceLibraryManagerWidget->sourceBrowserWidget()->headerFilePatterns(); } void SeerGdbWidget::setSourceIgnoreFilePatterns (const QStringList& filePatterns) { _ignoreFilePatterns = filePatterns; sourceLibraryManagerWidget->sourceBrowserWidget()->setIgnoreFilePatterns(sourceIgnoreFilePatterns()); editorManager()->setEditorIgnoreDirectories(sourceIgnoreFilePatterns()); } const QStringList& SeerGdbWidget::sourceIgnoreFilePatterns () const { return _ignoreFilePatterns; } void SeerGdbWidget::setAssemblyShowAssemblyTabOnStartupMode (const QString& mode) { editorManager()->setShowAssemblyTabOnStartupMode(mode); } QString SeerGdbWidget::assemblyShowAssemblyTabOnStartupMode () const { return editorManager()->showAssemblyTabOnStartupMode(); } void SeerGdbWidget::setAssemblyKeepAssemblyTabOnTop (bool flag) { editorManager()->setKeepAssemblyTabOnTop(flag); } bool SeerGdbWidget::assemblyKeepAssemblyTabOnTop () const { return editorManager()->keepAssemblyTabOnTop(); } void SeerGdbWidget::setAssemblyDisassemblyFlavor (const QString& flavor) { _assemblyDisassemblyFlavor = flavor; if (isGdbRuning()) { handleGdbAssemblyDisassemblyFlavor(); emit assemblyConfigChanged(); } } QString SeerGdbWidget::assemblyDisassemblyFlavor () const { return _assemblyDisassemblyFlavor; } void SeerGdbWidget::setAssemblySymbolDemagling (const QString& onoff) { _assemblySymbolDemangling = onoff; if (isGdbRuning()) { handleGdbAssemblySymbolDemangling(); emit assemblyConfigChanged(); } } void SeerGdbWidget::handleGdbSchedulerLockingMode (QString mode) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-gdb-set scheduler-locking %1").arg(mode)); } void SeerGdbWidget::handleGdbScheduleMultipleMode (QString mode) { if (executableLaunchMode() == "") { return; } handleGdbCommand(QString("-gdb-set schedule-multiple %1").arg(mode)); } void SeerGdbWidget::handleGdbForkFollowMode (QString mode) { if (executableLaunchMode() == "") { return; } if (mode == "parent") { handleGdbCommand("-gdb-set follow-fork-mode parent"); handleGdbCommand("-gdb-set detach-on-fork on"); }else if (mode == "child") { handleGdbCommand("-gdb-set follow-fork-mode child"); handleGdbCommand("-gdb-set detach-on-fork on"); }else if (mode == "both") { handleGdbCommand("-gdb-set follow-fork-mode parent"); handleGdbCommand("-gdb-set detach-on-fork off"); }else{ qWarning() << "Invalid 'ForkFollowMode' of '" << mode << "'"; } } void SeerGdbWidget::handleGdbLoadMICommands () { // Don't do anything, if isn't running. if (isGdbRuning() == false) { return; } // Path the MI files in the resources. QString miPath = ":/seer/resources/mi-python/"; // Resource file path QDir miDirectory(miPath); if (!miDirectory.exists()) { qDebug() << "Directory does not exist:" << miPath; return; } // Get list of MI files. QFileInfoList miList = miDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries); // Print the list. qDebug() << "Sourcing scripts from:" << miPath; foreach (QFileInfo miInfo, miList) { // Open the source file from resources. QFile miFile(miInfo.absoluteFilePath()); if (!miFile.exists()) { qDebug().nospace().noquote() << "Resource file '" << miInfo << "' does not exist!"; continue; } // Destination file path in /tmp. QString destinationPath = "/tmp/" + miInfo.fileName(); // Delete possible old temp version, if it exists. if (QFile::exists(destinationPath)) { bool f = QFile::remove(destinationPath); if (f == false) { qDebug().nospace().noquote() << "Old temp Resource file '" << destinationPath << "' can not be deleted!"; continue; } } // Copy to temp. bool f = miFile.copy(destinationPath); if (f == false) { qDebug().nospace().noquote() << "Resource file '" << miInfo << "' can not be copied to '" << destinationPath << "'!"; continue; } // Source it. if (QFile::exists(destinationPath) == false) { qDebug().nospace().noquote() << "Temp Resource file '" << destinationPath << "' does not exist!"; continue; } qDebug() << "source " + miInfo.absoluteFilePath(); QString command = "source " + destinationPath; handleGdbCommand(command); } qDebug() << "Done."; } void SeerGdbWidget::handleGdbSourceScripts () { // Don't do anything, if isn't running. if (isGdbRuning() == false) { return; } // Get setting's config path. QSettings settings; QString configFile = settings.fileName(); if (configFile == "") { return; } QFileInfo configFileInfo(configFile); QString configDirectory = configFileInfo.absolutePath(); // Get a list of files in the "scripts" folder. QString scriptsDirectory = configDirectory + "/scripts"; QDir dir(scriptsDirectory); QStringList scripts = dir.entryList(QDir::Files, QDir::Name); // Source each one. qDebug() << "Sourcing scripts from:" << scriptsDirectory; for (const QString& script : scripts) { QString command = "source " + scriptsDirectory + "/" + script; qDebug() << command; handleGdbCommand(command); } qDebug() << "Done."; } void SeerGdbWidget::handleGdbLoadSkips () { // Don't do anything, if isn't running. if (isGdbRuning() == false) { return; } // Guard agains the remote possibility of no Skip browser if (sourceLibraryManagerWidget->skipBrowserWidget() == nullptr) { return; } sourceLibraryManagerWidget->skipBrowserWidget()->loadSkips(); } void SeerGdbWidget::handleGdbSetArchitectureType () { if (gdbArchitectureType() != "") { handleGdbCommand(QString("set architecture ") + gdbArchitectureType()); } } QString SeerGdbWidget::assemblySymbolDemagling () const { return _assemblySymbolDemangling; } void SeerGdbWidget::setAssemblyShowAddressColumn (bool flag) { editorManager()->setAssemblyShowAddressColumn(flag); } bool SeerGdbWidget::assemblyShowAddressColumn () const { return editorManager()->assemblyShowAddressColumn(); } void SeerGdbWidget::setAssemblyShowOffsetColumn (bool flag) { editorManager()->setAssemblyShowOffsetColumn(flag); } bool SeerGdbWidget::assemblyShowOffsetColumn () const { return editorManager()->assemblyShowOffsetColumn(); } void SeerGdbWidget::setAssemblyShowOpcodeColumn (bool flag) { editorManager()->setAssemblyShowOpcodeColumn(flag); } bool SeerGdbWidget::assemblyShowOpcodeColumn () const { return editorManager()->assemblyShowOpcodeColumn(); } void SeerGdbWidget::setAssemblyShowSourceLines (bool flag) { editorManager()->setAssemblyShowSourceLines(flag); } bool SeerGdbWidget::assemblyShowSourceLines () const { return editorManager()->assemblyShowSourceLines(); } void SeerGdbWidget::setAssemblyRegisterFormat (const QString& format) { _assemblyRegisterFormat = format; variableManagerWidget->registerValuesBrowserWidget()->setRegisterFormat(_assemblyRegisterFormat); } QString SeerGdbWidget::assemblyRegisterFormat () const { return _assemblyRegisterFormat; } void SeerGdbWidget::setAssemblyDisassemblyMode (const QString& mode, int bytes) { _assemblyDisassemblyMode = mode; _assemblyDisassemblyBytes = bytes; } QString SeerGdbWidget::assemblyDisassemblyMode () const { return _assemblyDisassemblyMode; } int SeerGdbWidget::assemblyDisassemblyBytes () const { return _assemblyDisassemblyBytes; } void SeerGdbWidget::sendGdbInterrupt (int signal) { //qDebug() << "Sending an interrupt to the program. Signal =" << signal; if (executableLaunchMode() == "") { return; } if (executablePid() < 1) { QMessageBox::warning(this, "Seer", QString("No executable is running or I don't know the PID of the process."), QMessageBox::Ok); return; } // Use kill() to send the signal to the inferior. // -exec-interrupt does not work for -exec-until when the line // number is not in the current function. In this case, -exec-until // behaves like -exec-continue but -exec-interrupt has no effect. :^( // We do have the ability to use a different signal, though. :^) if (signal < 0) { handleGdbCommand("-exec-interrupt"); }else{ int stat = kill(executablePid(), signal); if (stat < 0) { QMessageBox::warning(this, "Seer", QString("Unable to send signal '%1' to pid %2.\nError = '%3'").arg(strsignal(signal)).arg(executablePid()).arg(strerror(errno)), QMessageBox::Ok); } } } // Deleay N seconds by executing Qt's even loop a bunch of times. // This gives time for certain gdb commands to finish. Like saving the breakpoints before exit. void SeerGdbWidget::delay (int seconds) { QTime dieTime = QTime::currentTime().addSecs(seconds); while (QTime::currentTime() < dieTime) { QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } } epasveer-seer-97076f1/src/SeerGdbWidget.h000066400000000000000000001045701526321767600202120ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerConsoleWidget.h" #include "SeerEditorWidgetSource.h" #include "SeerGdbLogWidget.h" #include "SeerSeerLogWidget.h" #include "SeerMessagesBrowserWidget.h" #include "SeerBreakpointsBrowserWidget.h" #include "SeerWatchpointsBrowserWidget.h" #include "SeerCatchpointsBrowserWidget.h" #include "SeerPrintpointsBrowserWidget.h" #include "SeerCheckpointsBrowserWidget.h" #include "GdbMonitor.h" #include #include #include #include "ui_SeerGdbWidget.h" class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm { Q_OBJECT public: explicit SeerGdbWidget (QWidget* parent = 0); ~SeerGdbWidget (); GdbMonitor* gdbMonitor (); QProcess* gdbProcess (); void setExecutableName (const QString& executableName); const QString& executableName () const; void setExecutableSymbolName (const QString& executableSymbolName); const QString& executableSymbolName () const; void setNewExecutableFlag (bool flag); bool newExecutableFlag () const; void setExecutableArguments (const QString& executableArguments); const QString& executableArguments () const; void setExecutableWorkingDirectory (const QString& executableWorkingDirectory); const QString& executableWorkingDirectory () const; void setExecutableBreakpointsFilename (const QString& breakpointsFilename); const QString& executableBreakpointsFilename () const; void setExecutableBreakpointFunctionName (const QString& nameoraddress); const QString& executableBreakpointFunctionName () const; void setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno); const QString& executableBreakpointSourceName () const; void setExecutableBreakpointFirstInstruction (bool flag); bool executableBreakpointFirstInstruction () const; void setExecutablePid (int pid); int executablePid () const; void setExecutableConnectHostPort (const QString& connectHostPort); const QString& executableConnectHostPort () const; void setExecutableRRTraceDirectory (const QString& rrTraceDirectory); const QString& executableRRTraceDirectory () const; void setExecutableCoreFilename (const QString& coreFilename); const QString& executableCoreFilename () const; void setExecutablePreGdbCommands (const QStringList& preGdbCommands); const QStringList& executablePreGdbCommands () const; void setExecutablePostGdbCommands (const QStringList& postGdbCommands); const QStringList& executablePostGdbCommands () const; void setExecutableLaunchMode (const QString& launchMode); const QString& executableLaunchMode () const; const QString& executableBreakMode () const; // Gdb settings. void setGdbLauncher (const QString& launchProgram); QString gdbLauncher () const; void setGdbProgram (const QString& program); QString gdbProgram () const; void setGdbArguments (const QString& arguments); QString gdbArguments () const; void setGdbProgramOverride (const QString& program); QString gdbProgramOverride () const; void setGdbArgumentsOverride (const QString& arguments); QString gdbArgumentsOverride () const; void setGdbAsyncMode (bool flag); bool gdbAsyncMode () const; void setGdbNonStopMode (bool flag); bool gdbNonStopMode () const; void setGdbServerDebug (bool flag); bool gdbServerDebug () const; void setGdbHandleTerminatingException (bool flag); bool gdbHandleTerminatingException () const; void setGdbRandomizeStartAddress (bool flag); bool gdbRandomizeStartAddress () const; void setGdbEnablePrettyPrinting (bool flag); bool gdbEnablePrettyPrinting () const; void setGdbRemoteTargetType (const QString& type); QString gdbRemoteTargetType () const; void setGdbArchitectureType (const QString& type); QString gdbArchitectureType () const; void setGdbRecordMode (const QString& mode); QString gdbRecordMode () const; void setGdbRecordDirection (const QString& direction); QString gdbRecordDirection () const; SeerConsoleWidget* console (); void setConsoleMode (const QString& mode); QString consoleMode () const; void setConsoleScrollLines (int count); int consoleScrollLines () const; void setRememberManualCommandCount (int count); int rememberManualCommandCount () const; void clearManualCommandHistory (); void setSourceAlternateDirectories (const QStringList& alternateDirectories); const QStringList& sourceAlternateDirectories () const; void setSourceMiscFilePatterns (const QStringList& filePatterns); const QStringList& sourceMiscFilePatterns () const; void setSourceSourceFilePatterns (const QStringList& filePatterns); const QStringList& sourceSourceFilePatterns () const; void setSourceHeaderFilePatterns (const QStringList& filePatterns); const QStringList& sourceHeaderFilePatterns () const; void setSourceIgnoreFilePatterns (const QStringList& filePatterns); const QStringList& sourceIgnoreFilePatterns () const; void setAssemblyShowAssemblyTabOnStartupMode (const QString& mode); QString assemblyShowAssemblyTabOnStartupMode () const; void setAssemblyKeepAssemblyTabOnTop (bool flag); bool assemblyKeepAssemblyTabOnTop () const; void setAssemblyDisassemblyFlavor (const QString& flavor); QString assemblyDisassemblyFlavor () const; void setAssemblySymbolDemagling (const QString& onoff); QString assemblySymbolDemagling () const; void setAssemblyShowAddressColumn (bool flag); bool assemblyShowAddressColumn () const; void setAssemblyShowOffsetColumn (bool flag); bool assemblyShowOffsetColumn () const; void setAssemblyShowOpcodeColumn (bool flag); bool assemblyShowOpcodeColumn () const; void setAssemblyShowSourceLines (bool flag); bool assemblyShowSourceLines () const; void setAssemblyRegisterFormat (const QString& format); QString assemblyRegisterFormat () const; void setAssemblyDisassemblyMode (const QString& mode, int bytes); QString assemblyDisassemblyMode () const; int assemblyDisassemblyBytes () const; // RR settings. void setRRProgram (const QString& program); QString rrProgram () const; void setRRArguments (const QString& arguments); QString rrArguments () const; void setRRGdbArguments (const QString& arguments); QString rrGdbArguments () const; // Editor manager. SeerEditorManagerWidget* editorManager (); const SeerEditorManagerWidget* editorManager () const; // Messages void addMessage (const QString& message, QMessageBox::Icon messageType); // Settings void writeSettings (); void readSettings (); // Gdb bool isGdbRuning () const; void restoreLaunchMode (); void saveLaunchMode (); bool hasBackupLaunchMode () const; void clearBackupLaunchMode (); const QString& backupLaunchMode () const; public slots: void handleText (const QString& text); void handleManualCommandExecute (QString command); void handleGdbCommand (const QString& command, bool ignoreErrors=false); void handleGdbCommands (const QStringList& commands); void handleGdbMonitorCommand (int id, const QString& command); void handleGdbExit (); void handleGdbRunExecutable (const QString& breakMode, bool loadSessionBreakpoints); void handleGdbAttachExecutable (bool loadSessionBreakpoints); void handleGdbConnectExecutable (bool loadSessionBreakpoints); void handleGdbRRExecutable (bool loadSessionBreakpoints); void handleGdbCoreFileExecutable (); void handleGdbTerminateExecutable (bool confirm=true); void handleGdbShutdown (); void handleGdbRunToLine (QString fullname, int lineno); void handleGdbRunToAddress (QString address); void handleGdbNext (); void handleGdbNexti (); void handleGdbStep (); void handleGdbStepi (); void handleGdbFinish (); void handleGdbContinue (); void handleGdbReverseNext (); void handleGdbReverseNexti (); void handleGdbReverseStep (); void handleGdbReverseStepi (); void handleGdbReverseFinish (); void handleGdbReverseContinue (); void handleGdbRecordStart (); void handleGdbRecordStop (); void handleGdbRecordForward (); void handleGdbRecordReverse (); void handleGdbRecordStartStopToggle (); void handleGdbRecordDirectionToggle (); void handleGdbInterrupt (); void handleGdbInterruptSIGINT (); void handleGdbInterruptSIGKILL (); void handleGdbInterruptSIGFPE (); void handleGdbInterruptSIGSEGV (); void handleGdbInterruptSIGUSR1 (); void handleGdbInterruptSIGUSR2 (); void handleGdbRunThreadGroup (QString threadGroup); void handleGdbStartThreadGroup (QString threadGroup); void handleGdbContinueThreadGroup (QString threadGroup); void handleGdbInterruptThreadGroup (QString threadGroup); void handleGdbNextThreadId (int threadid); void handleGdbStepThreadId (int threadid); void handleGdbFinishThreadId (int threadid); void handleGdbContinueThreadId (int threadid); void handleGdbInterruptThreadId (int threadid); void handleGdbExecutableSources (); void handleGdbExecutableFunctions (int id, const QString& functionRegex); void handleGdbExecutableTypes (int id, const QString& typeRegex); void handleGdbExecutableVariables (int id, const QString& variableNameRegex, const QString& variableTypeRegex); void handleGdbExecutableLibraries (); void handleGdbExecutableName (); void handleGdbExecutableArguments (); void handleGdbExecutableWorkingDirectory (); void handleGdbExecutableLoadBreakpoints (); void handleGdbExecutablePreCommands (); void handleGdbExecutablePostCommands (); void handleGdbSessionLoadBreakpoints (); void handleGdbSessionSaveBreakpoints (); void handleGdbTerminalDeviceName (); void handleGdbStackListFrames (); void handleGdbStackSelectFrame (int frameno); void handleGdbStackListLocals (); void handleGdbStackListArguments (); void handleGdbGenericpointList (); void handleGdbBreakpointDelete (QString breakpoints); void handleGdbBreakpointEnable (QString breakpoints); void handleGdbBreakpointDisable (QString breakpoints); void handleGdbBreakpointInfo (int breakpointid, QString breakpoint); void handleGdbBreakpointsInsert (QString breakpoints); void handleGdbBreakpointInsert (QString breakpoint); void handleGdbBreakpointCondition (QString breakpoint, QString condition); void handleGdbBreakpointIgnore (QString breakpoint, QString count); void handleGdbBreakpointCommand (QString breakpoint, QString commands); void handleGdbBreakpointCommands (QString breakpoint, QStringList commands); void handleGdbBreakpointReload (QStringList breakpointsText); void handleGdbWatchpointReload (QStringList watchpointsText); void handleGdbCatchpointReload (QStringList catchpointsText); void handleGdbWatchpointDelete (QString watchpoints); void handleGdbWatchpointEnable (QString watchpoints); void handleGdbWatchpointDisable (QString watchpoints); void handleGdbWatchpointInsert (QString watchpoint); void handleGdbCatchpointDelete (QString catchpoints); void handleGdbCatchpointEnable (QString catchpoints); void handleGdbCatchpointDisable (QString catchpoints); void handleGdbCatchpointInsert (QString catchpoint); void handleGdbPrintpointDelete (QString breakpoints); void handleGdbPrintpointEnable (QString breakpoints); void handleGdbPrintpointDisable (QString breakpoints); void handleGdbPrintpointInsert (QString type, QString function, QString channel, QString parameters); void handleGdbThreadListFrames (); void handleGdbThreadListIds (); void handleGdbThreadListGroups (); void handleGdbThreadSelectId (int threadid); void handleGdbAdaListTasks (); void handleGdbAdaListExceptions (); void handleGdbSkipList (); void handleGdbSkipAdd (QString skipmode, QString skipparameters); void handleGdbSkipDelete (QString skipids); void handleGdbSkipEnable (QString skipids); void handleGdbSkipDisable (QString skipids); void handleGdbCheckpointList (); void handleGdbCheckpointInsert (); void handleGdbCheckpointSelect (QString id); void handleGdbCheckpointDelete (QString ids); void handleGdbRegisterListNames (); void handleGdbRegisterListValues (QString fmt); void handleGdbRegisterSetValue (QString fmt, QString name, QString value); void handleGdbSignalListNames (); void handleGdbSignalListValues (QString names); void handleGdbSignalSetValue (QString name, QString stop, QString print, QString pass); void handleGdbDataEvaluateExpression (int expressionid, QString expression); void handleGdbVarObjCreate (int expressionid, QString expression); void handleGdbVarObjListChildren (int expressionid, QString objname); void handleGdbVarObjUpdate (int expressionid, QString objname); void handleGdbVarObjAssign (int expressionid, QString objname, QString value); void handleGdbVarObjDelete (int expressionid, QString objname); void handleGdbVarObjAttributes (int objid, QString objname); void handleGdbDataListValues (); void handleGdbDataListExpressions (); void handleGdbDataAddExpression (QString expression); void handleGdbDataDeleteExpressions (QString expressionids); void handleGdbMemoryAddExpression (QString expression); void handleGdbArrayAddExpression (QString expression); void handleGdbMatrixAddExpression (QString expression); void handleGdbStructAddExpression (QString expression); void handleGdbVarAddExpression (QString expression); void handleGdbImageAddExpression (QString expression); void handleGdbMemoryEvaluateExpression (int expressionid, QString address, int count); void handleGdbMemoryEvaluateExpression (int expressionid, QString address, int offset, int count); void handleGdbAsmEvaluateExpression (int expressionid, QString address, int count, int mode); void handleGdbArrayEvaluateExpression (int expressionid, QString address, int count); void handleGdbGetAssembly (QString address); void handleGdbGetSourceAndAssembly (QString address); void handleGdbParallelStackFrames (int expressionid); void handleGdbMemoryVisualizer (); void handleGdbArrayVisualizer (); void handleGdbMatrixVisualizer (); void handleGdbStructVisualizer (); void handleGdbVarVisualizer (); void handleGdbImageVisualizer (); void handleGdbParallelStacksVisualizer (); void handleGdbMonitor (); void handleSplitterMoved (int pos, int index); void handleGdbAssemblyDisassemblyFlavor (); void handleGdbAssemblySymbolDemangling (); void handleGdbSchedulerLockingMode (QString mode); void handleGdbScheduleMultipleMode (QString mode); void handleGdbForkFollowMode (QString mode); void handleGdbLoadMICommands (); void handleGdbSourceScripts (); void handleGdbLoadSkips (); void handleGdbSetArchitectureType (); void handleGdbProcessFinished (int exitCode, QProcess::ExitStatus exitStatus); void handleGdbProcessErrored (QProcess::ProcessError errorStatus); void handleAboutToQuit (); signals: void stoppingPointReached (); void sessionTerminated (); void changeWindowTitle (QString title); void assemblyConfigChanged (); void recordSettingsChanged (); void stateChanged (); void gdbCommandLogout (const QString& text); protected: private: bool isQuitting () const; void setIsQuitting (bool f); bool startGdb (); bool startGdbRR (); void killGdb (); void sendGdbInterrupt (int signal); void delay (int seconds); bool _isQuitting; QString _gdbLauncher; QString _gdbProgram; QString _gdbArguments; QString _gdbProgramOverride; QString _gdbArgumentsOverride; QString _gdbRRProgram; QString _gdbRRArguments; QString _gdbRRGdbArguments; bool _gdbASyncMode; bool _gdbNonStopMode; bool _gdbServerDebug; bool _gdbHandleTerminatingException; bool _gdbRandomizeStartAddress; bool _gdbEnablePrettyPrinting; QString _gdbRecordMode; QString _gdbRecordDirection; QString _gdbRemoteTargetType; QString _gdbArchitectureType; QString _assemblyDisassemblyFlavor; QString _assemblySymbolDemangling; QString _assemblyRegisterFormat; QString _assemblyDisassemblyMode; int _assemblyDisassemblyBytes; QString _executableName; QString _executableSymbolName; QString _executableArguments; QString _executableWorkingDirectory; QString _executableBreakpointsFilename; QString _executableBreakpointFunctionName; QString _executableBreakpointSourceName; bool _executableBreakpointFirstInstruction; int _executablePid; QString _executableConnectHostPort; QString _executableRRTraceDirectory; QString _executableCoreFilename; QString _executableLaunchMode; QString _executableBreakMode; QString _executableLaunchModeBackup; QString _executableBreakModeBackup; QStringList _executablePreGdbCommands; QStringList _executablePostGdbCommands; bool _newExecutableFlag; GdbMonitor* _gdbMonitor; QProcess* _gdbProcess; QVector _dataExpressionId; QVector _dataExpressionName; QStringList _ignoreFilePatterns; }; epasveer-seer-97076f1/src/SeerGdbWidget.ui000066400000000000000000000114241526321767600203730ustar00rootroot00000000000000 SeerGdbWidgetForm 0 0 997 567 Form Qt::Horizontal false 10 0 Qt::Vertical false 50 50 50 50 Qt::Vertical false 20 75 30 0 Qt::Vertical false 50 50 50 50 SeerEditorManagerWidget QWidget
SeerEditorManagerWidget.h
1
SeerSourceSymbolLibraryManagerWidget QWidget
SeerSourceSymbolLibraryManagerWidget.h
1
SeerStackManagerWidget QWidget
SeerStackManagerWidget.h
1
SeerThreadManagerWidget QWidget
SeerThreadManagerWidget.h
1
SeerVariableManagerWidget QWidget
SeerVariableManagerWidget.h
1
SeerCommandLogsWidget QWidget
SeerCommandLogsWidget.h
1
epasveer-seer-97076f1/src/SeerHelpPageDialog.cpp000066400000000000000000000047561526321767600215170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerHelpPageDialog::SeerHelpPageDialog(QDialog* parent) : QDialog(parent) { // Construct the UI. setupUi(this); // Setup the widgets setWindowTitle("Seer Help"); textBrowser->setOpenExternalLinks(true); // Connect things. QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerHelpPageDialog::handlePrintToolButton); QObject::connect(okPushButton, &QPushButton::clicked, this, &SeerHelpPageDialog::handleOkPushButton); // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); // Restore window settings. readSettings(); } SeerHelpPageDialog::~SeerHelpPageDialog() { } void SeerHelpPageDialog::loadFile (const QString& filename) { // Get the Help text from the file. QFile file(filename); bool f = file.open(QFile::ReadOnly|QFile::Text); if (f == false) { return; } QTextStream stream(&file); QString text = stream.readAll(); // Load it into the browser. loadText(text); } void SeerHelpPageDialog::loadText (const QString& text) { // Put the Help text in as markdown. Move back to the begining. textBrowser->setMarkdown(text); textBrowser->moveCursor(QTextCursor::Start); } void SeerHelpPageDialog::handlePrintToolButton () { QPrinter printer; QPrintDialog* dlg = new QPrintDialog(&printer, this); if (dlg->exec() != QDialog::Accepted) { return; } QTextDocument* document = textBrowser->document(); document->print(&printer); } void SeerHelpPageDialog::handleOkPushButton () { done(QDialog::Accepted); } void SeerHelpPageDialog::writeSettings() { QSettings settings; settings.beginGroup("helpwindow"); { settings.setValue("size", size()); }settings.endGroup(); } void SeerHelpPageDialog::readSettings() { QSettings settings; settings.beginGroup("helpwindow"); { resize(settings.value("size", QSize(600, 600)).toSize()); }settings.endGroup(); } void SeerHelpPageDialog::resizeEvent (QResizeEvent* event) { // Write window settings. writeSettings(); QDialog::resizeEvent(event); } epasveer-seer-97076f1/src/SeerHelpPageDialog.h000066400000000000000000000020111526321767600211420ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "ui_SeerHelpPageDialog.h" class SeerHelpPageDialog: public QDialog, protected Ui::SeerHelpPageDialogForm { Q_OBJECT public: SeerHelpPageDialog(QDialog* parent = 0); ~SeerHelpPageDialog(); void loadFile (const QString& filename); void loadText (const QString& text); signals: public slots: protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); protected slots: void handlePrintToolButton (); void handleOkPushButton (); private: }; epasveer-seer-97076f1/src/SeerHelpPageDialog.ui000066400000000000000000000042201526321767600213340ustar00rootroot00000000000000 SeerHelpPageDialogForm 0 0 592 352 Dialog 0 100 Print Help page. :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Qt::Horizontal 40 20 Dismiss Help page. OK epasveer-seer-97076f1/src/SeerHexWidget.cpp000066400000000000000000000630041526321767600205710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerHexWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #define byteArrayToType( data, order, precision, type ) \ QDataStream stream( data ); \ stream.setByteOrder( order ); \ stream.setFloatingPointPrecision( precision ); \ type t; \ stream >> t; \ return t; qint8 toQInt8 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, qint8) } quint8 toQUInt8 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, quint8) } qint16 toQInt16 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, qint16) } quint16 toQUInt16 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, quint16) } qint32 toQInt32 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, qint32) } quint32 toQUInt32 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, quint32) } qint64 toQInt64 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, qint64) } quint64 toQUInt64 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, quint64) } float toQFloat32 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::SinglePrecision, float) } double toQFloat64 (const QByteArray& data, const QDataStream::ByteOrder order=QDataStream::BigEndian) { byteArrayToType(data, order, QDataStream::DoublePrecision, double) } SeerHexWidget::SeerHexWidget(QWidget* parent) : QWidget(parent), _pdata(nullptr), _pdataPrevious(nullptr) { // Construct the UI. setupUi(this); // Setup the widgets QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); plainTextEdit->setFont(font); plainTextEdit->setFocusPolicy(Qt::StrongFocus); plainTextEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse); plainTextEdit->setWordWrapMode(QTextOption::NoWrap); _memoryMode = SeerHexWidget::HexMemoryMode; _charMode = SeerHexWidget::AsciiCharMode; _addressOffset = 0; _charWidth = plainTextEdit->fontMetrics().horizontalAdvance(QLatin1Char('9')); _charHeight = plainTextEdit->fontMetrics().height(); _gapAddrHex = 10; // Gap between address and hex fields. _gapHexAscii = 16; // Gap between hex and ascii fields. _highlightByte = -1; setBytesPerLine(16); // Connect things. QObject::connect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(showAsLittleEndianCheckBox, &QCheckBox::clicked, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(showUnsignedFloatAsHexCheckBox, &QCheckBox::clicked, this, &SeerHexWidget::handleCursorPositionChanged); QObject::connect(this, &SeerHexWidget::byteOffsetChanged, this, &SeerHexWidget::handleByteOffsetChanged); } SeerHexWidget::~SeerHexWidget() { if (_pdata) { delete _pdata; _pdata = nullptr; } if (_pdataPrevious) { delete _pdataPrevious; _pdataPrevious = nullptr; } } void SeerHexWidget::setBytesPerLine (int count) { // 3 = 'a0 ' // 4 = '007 ' // 9 = '00011010 ' // 4 = ' 10 ' if (memoryMode() == SeerHexWidget::HexMemoryMode) { _hexCharsPerByte = 3; }else if (memoryMode() == SeerHexWidget::OctalMemoryMode) { _hexCharsPerByte = 4; }else if (memoryMode() == SeerHexWidget::BinaryMemoryMode) { _hexCharsPerByte = 9; }else if (memoryMode() == SeerHexWidget::DecimalMemoryMode) { _hexCharsPerByte = 4; }else{ _hexCharsPerByte = 3; } _bytesPerLine = count; _hexCharsPerLine = _bytesPerLine * _hexCharsPerByte - 1; int posHex = SeerHexWidget::HexFieldWidth * _charWidth + gapAddrHex(); // x position of hex field. int posAscii = posHex + hexCharsPerLine() * _charWidth + gapHexAscii(); // x position of ascii field. setMinimumWidth(posAscii + (bytesPerLine() * _charWidth)); // x position after the ascii field. // Repaint the widget. create(); } int SeerHexWidget::bytesPerLine () const { return _bytesPerLine; } int SeerHexWidget::hexCharsPerLine () const { return _hexCharsPerLine; } int SeerHexWidget::hexCharsPerByte () const { return _hexCharsPerByte; } int SeerHexWidget::nLines () const { return plainTextEdit->blockCount(); } int SeerHexWidget::gapAddrHex () const { return _gapAddrHex; } int SeerHexWidget::gapHexAscii () const { return _gapHexAscii; } void SeerHexWidget::setAddressOffset (unsigned long offset) { _addressOffset = offset; // Repaint the widget. create(); } unsigned long SeerHexWidget::addressOffset () const { return _addressOffset; } unsigned long SeerHexWidget::size () const { if (_pdata) { return _pdata->size(); } return 0; } void SeerHexWidget::setMemoryMode (SeerHexWidget::MemoryMode memoryMode) { _memoryMode = memoryMode; // This repaints the widget with the new memory mode setBytesPerLine(bytesPerLine()); } SeerHexWidget::MemoryMode SeerHexWidget::memoryMode () const { return _memoryMode; } QString SeerHexWidget::memoryModeString () const { if (memoryMode() == SeerHexWidget::HexMemoryMode) { return "hex"; }else if (memoryMode() == SeerHexWidget::OctalMemoryMode) { return "octal"; }else if (memoryMode() == SeerHexWidget::BinaryMemoryMode) { return "binary"; }else if (memoryMode() == SeerHexWidget::DecimalMemoryMode) { return "decimal"; } return "???"; } void SeerHexWidget::setCharMode (SeerHexWidget::CharMode charMode) { _charMode = charMode; // Repaint the widget. create(); } SeerHexWidget::CharMode SeerHexWidget::charMode() const { return _charMode; } QString SeerHexWidget::charModeString () const { if (charMode() == SeerHexWidget::AsciiCharMode) { return "ascii"; }else if (charMode() == SeerHexWidget::Utf8Mode) { return "utf8"; }else if (charMode() == SeerHexWidget::Utf16Mode) { return "utf16"; }else if (charMode() == SeerHexWidget::Utf32Mode) { return "utf32"; }else if (charMode() == SeerHexWidget::EbcdicCharMode) { return "ebcdic"; } return "???"; } QTextDocument* SeerHexWidget::document () { return plainTextEdit->document(); } QString SeerHexWidget::toPlainText () { return plainTextEdit->toPlainText(); } void SeerHexWidget::setData(SeerHexWidget::DataStorage* pData) { // Delete previous data, if any. if (_pdataPrevious) { delete _pdataPrevious; _pdataPrevious = nullptr; } // Save away the current data as the previous so we can use it for comparisons. _pdataPrevious = _pdata; _pdata = nullptr; // Save the current data; _pdata = pData; // Repaint the widget. create(); } void SeerHexWidget::handleCursorPositionChanged () { // Get the current cursor position. QTextCursor cursor = plainTextEdit->textCursor(); // Is it before the hex values? (address region) if (cursor.positionInBlock() < SeerHexWidget::HexFieldWidth) { emit byteOffsetChanged(-1); return; } // Is is after the hex values? (ascii/utf/ebcdic region) if (cursor.positionInBlock() > SeerHexWidget::HexFieldWidth + hexCharsPerLine()) { emit byteOffsetChanged(-1); return; } int line = cursor.blockNumber(); int col = cursor.positionInBlock() - SeerHexWidget::HexFieldWidth; int byte = (col / hexCharsPerByte()) + (line * bytesPerLine()); _highlightByte = byte; emit byteOffsetChanged(byte); } void SeerHexWidget::handleByteOffsetChanged (int byte) { // Clear all fields. lineEdit_1->setText(""); lineEdit_2->setText(""); lineEdit_3->setText(""); lineEdit_4->setText(""); lineEdit_5->setText(""); lineEdit_6->setText(""); lineEdit_7->setText(""); lineEdit_8->setText(""); lineEdit_9->setText(""); lineEdit_10->setText(""); lineEdit_11->setText(""); lineEdit_12->setText(""); lineEdit_13->setText(""); lineEdit_14->setText(""); // Remove previous highlight. plainTextEdit->setExtraSelections(QList()); // Invalid byte number, do nothing. if (byte < 0) { return; } // If there's no data, do nothing. if (!_pdata) { return; } // Byte past the end, do nothing. if ((unsigned int)byte >= size()) { return; } // Calculate line and position in line. int line = (byte / bytesPerLine()); int pos = byte - (line * bytesPerLine()); int pos_s = SeerHexWidget::HexFieldWidth + (pos * hexCharsPerByte()); int pos_e = pos_s + hexCharsPerByte() - 1; int pos_a = SeerHexWidget::HexFieldWidth + hexCharsPerLine() + pos + 4; // 4 == ' ' .... ' | ' // Highlight the text in the hex region and the ascii region. QList extraSelections; { // Get a cursor to the current line. QTextBlock block = plainTextEdit->document()->findBlockByLineNumber(line); QTextCursor cursor = QTextCursor(block); // Highlight the current hex value. cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor); cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, pos_s); cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, pos_e - pos_s + 1); // Add it to the extra selections. QTextEdit::ExtraSelection extra_byte; extra_byte.format.setBackground(plainTextEdit->palette().highlight().color()); extra_byte.cursor = cursor; extraSelections.append(extra_byte); // Highlight the current ascii value. // For Ascii and Ebcdic only. No UTF as it can be variable length encoding. if (charMode() == SeerHexWidget::AsciiCharMode || charMode() == SeerHexWidget::EbcdicCharMode) { cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor); cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, pos_a); cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1); // Add it to the extra selections. QTextEdit::ExtraSelection extra_ascii; extra_ascii.format.setBackground(plainTextEdit->palette().highlight().color()); extra_ascii.cursor = cursor; extraSelections.append(extra_ascii); } } plainTextEdit->setExtraSelections(extraSelections); // Set the endian default. QDataStream::ByteOrder byteOrder = QDataStream::BigEndian; if (showAsLittleEndianCheckBox->isChecked()) { byteOrder = QDataStream::LittleEndian; } // Set the 'AsHex' default. bool unsignedAndFloatAsHex = false; if (showUnsignedFloatAsHexCheckBox->isChecked()) { unsignedAndFloatAsHex = true; } // Go through each one and display the value. { QByteArray arr = _pdata->getData(byte, sizeof(char)); // Extract a bytearray from the data for the size of the value we are after. if (arr.size() == sizeof(char)) { // If not the right size, skip it. Near the end of the data. lineEdit_1->setText(QString::number(toQInt8(arr, byteOrder))); // Fill in the signed value. if (unsignedAndFloatAsHex) { // Show unsigned value as hex? if (byteOrder == QDataStream::LittleEndian) { // Swap bytes to handle endianess. std::reverse(arr.begin(), arr.end()); } lineEdit_2->setText("0x"+QString(arr.toHex())); // Print value as hex. }else{ lineEdit_2->setText(QString::number(toQUInt8(arr, byteOrder))); // Print value as a value. } } } { QByteArray arr = _pdata->getData(byte, sizeof(short)); if (arr.size() == sizeof(short)) { lineEdit_3->setText(QString::number(toQInt16(arr, byteOrder))); if (unsignedAndFloatAsHex) { if (byteOrder == QDataStream::LittleEndian) { std::reverse(arr.begin(), arr.end()); } lineEdit_4->setText("0x"+QString(arr.toHex())); }else{ lineEdit_4->setText(QString::number(toQUInt16(arr, byteOrder))); } } } { QByteArray arr = _pdata->getData(byte, sizeof(float)); if (arr.size() == sizeof(float)) { if (unsignedAndFloatAsHex) { if (byteOrder == QDataStream::LittleEndian) { std::reverse(arr.begin(), arr.end()); } lineEdit_5->setText("0x"+QString(arr.toHex())); }else{ lineEdit_5->setText(QString::number(toQFloat32(arr, byteOrder))); } } } { QByteArray arr = _pdata->getData(byte, sizeof(int)); if (arr.size() == sizeof(int)) { lineEdit_6->setText(QString::number(toQInt32(arr, byteOrder))); if (unsignedAndFloatAsHex) { if (byteOrder == QDataStream::LittleEndian) { std::reverse(arr.begin(), arr.end()); } lineEdit_7->setText("0x"+QString(arr.toHex())); }else{ lineEdit_7->setText(QString::number(toQUInt32(arr, byteOrder))); } } } { QByteArray arr = _pdata->getData(byte, sizeof(long int)); if (arr.size() == sizeof(long int)) { lineEdit_8->setText(QString::number(toQInt64(arr, byteOrder))); if (unsignedAndFloatAsHex) { if (byteOrder == QDataStream::LittleEndian) { std::reverse(arr.begin(), arr.end()); } lineEdit_9->setText("0x"+QString(arr.toHex())); }else{ lineEdit_9->setText(QString::number(toQUInt64(arr, byteOrder))); } } } { QByteArray arr = _pdata->getData(byte, sizeof(double)); if (arr.size() == sizeof(double)) { if (unsignedAndFloatAsHex) { if (byteOrder == QDataStream::LittleEndian) { std::reverse(arr.begin(), arr.end()); } lineEdit_10->setText("0x"+QString(arr.toHex())); }else{ lineEdit_10->setText(QString::number(toQFloat64(arr, byteOrder))); } } } { QString val; QByteArray arr = _pdata->getData(byte, 4); for (int i=0; isetText(val); } { QString val; QByteArray arr = _pdata->getData(byte, 4); for (int i=0; isetText(val); } { QString val; QByteArray arr = _pdata->getData(byte, 4); for (int i=0; isetText(val); } { QString val; QByteArray arr = _pdata->getData(byte, 4); // Print N bytes in their char value. if (charMode() == SeerHexWidget::AsciiCharMode) { for (int i=0; isetText(val); } } void SeerHexWidget::create () { createDiffMap(); // Ignore changing of cursor positions. QObject::disconnect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged, this, &SeerHexWidget::handleCursorPositionChanged); // Clear the current document. We're going to recreate it. plainTextEdit->clear(); // Clear the checksum. lineEdit_15->setText(""); // If there's no data, do nothing. if (!_pdata) { // Re-enable notification of changing of cursor positions. QObject::connect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged, this, &SeerHexWidget::handleCursorPositionChanged); return; } // Convert the data to a 'text' string. QString textString = ""; QByteArray data = _pdata->getData(); if (charMode() == SeerHexWidget::AsciiCharMode) { for (int b=0; bcurrentCharFormat(); QTextCharFormat grayFormat = defaultFormat; grayFormat.setBackground(QBrush(Qt::lightGray)); QTextCharFormat underlineFormat = defaultFormat; underlineFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); // Get a cursor QTextCursor cursor(plainTextEdit->textCursor()); cursor.movePosition(QTextCursor::Start); // Go through the data, one byte at a time. for (int i=0; isetText(crc16str); } handleByteOffsetChanged(_highlightByte); // Re-enable notification of changing of cursor positions. QObject::connect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged, this, &SeerHexWidget::handleCursorPositionChanged); } void SeerHexWidget::createDiffMap() { qsizetype pdata_size = 0; qsizetype pdataPrevious_size = 0; qsizetype len = 0; if (_pdata) { pdata_size = _pdata->getData().size(); } if (_pdataPrevious) { pdataPrevious_size = _pdataPrevious->getData().size(); } // Allocate diff map. Set it to zeros. len = qMax(pdata_size, pdataPrevious_size); _diffMap.fill(0, len); // Create diff map if we can. if (_pdata && _pdataPrevious) { for (qsizetype i = 0; i < len; ++i) { // Positions beyond the shorter array always differ bool outOfBounds; bool bytesDiffer; outOfBounds = (i >= _pdata->getData().size()) || (i >= _pdataPrevious->getData().size()); if (outOfBounds) { bytesDiffer = true; }else{ bytesDiffer = _pdata->getData()[i] != _pdataPrevious->getData()[i]; } _diffMap[i] = bytesDiffer; } } } SeerHexWidget::DataStorageArray::DataStorageArray(const QByteArray& arr) { _data = arr; } QByteArray SeerHexWidget::DataStorageArray::getData(int position, int length) { return _data.mid(position, length); } QByteArray SeerHexWidget::DataStorageArray::getData() { return _data; } int SeerHexWidget::DataStorageArray::size() { return _data.size(); } epasveer-seer-97076f1/src/SeerHexWidget.h000066400000000000000000000105711526321767600202370ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerHexWidget.h" // // Hex Memory viewer widget. // Based on virinext/ QHexView // https://github.com/virinext/QHexView // // MIT License. // class SeerHexWidget: public QWidget, protected Ui::SeerHexWidgetForm { Q_OBJECT public: class DataStorage { public: virtual ~DataStorage() {}; virtual QByteArray getData(int position, int length) = 0; virtual QByteArray getData() = 0; virtual int size() = 0; }; class DataStorageArray: public DataStorage { public: DataStorageArray(const QByteArray& arr); virtual QByteArray getData(int position, int length); virtual QByteArray getData(); virtual int size(); private: QByteArray _data; }; enum MemoryMode { UnknownMemoryMode = 0, HexMemoryMode = 1, OctalMemoryMode = 2, BinaryMemoryMode = 3, DecimalMemoryMode = 4, }; enum CharMode { UnknownCharMode = 0, AsciiCharMode = 1, Utf8Mode = 2, Utf16Mode = 3, Utf32Mode = 4, EbcdicCharMode = 5 }; enum MagicNumbers { HexFieldWidth = 18 }; SeerHexWidget(QWidget* parent = 0); ~SeerHexWidget(); void setBytesPerLine (int count); int bytesPerLine () const; int hexCharsPerLine () const; int hexCharsPerByte () const; int nLines () const; int gapAddrHex () const; int gapHexAscii () const; void setAddressOffset (unsigned long offset); unsigned long addressOffset () const; unsigned long size () const; void setMemoryMode (SeerHexWidget::MemoryMode memoryMode); SeerHexWidget::MemoryMode memoryMode () const; QString memoryModeString () const; void setCharMode (SeerHexWidget::CharMode charMode); SeerHexWidget::CharMode charMode () const; QString charModeString () const; QTextDocument* document (); QString toPlainText (); signals: void byteOffsetChanged (int byte); public slots: void setData (DataStorage* pData); protected: protected slots: void handleCursorPositionChanged (); void handleByteOffsetChanged (int byte); private: void create (); void createDiffMap (); DataStorage* _pdata; DataStorage* _pdataPrevious; QByteArray _diffMap; int _charWidth; int _charHeight; int _highlightByte; int _bytesPerLine; int _hexCharsPerLine; int _hexCharsPerByte; int _gapAddrHex; int _gapHexAscii; unsigned long _addressOffset; SeerHexWidget::MemoryMode _memoryMode; SeerHexWidget::CharMode _charMode; }; epasveer-seer-97076f1/src/SeerHexWidget.ui000066400000000000000000000231531526321767600204250ustar00rootroot00000000000000 SeerHexWidgetForm 0 0 907 643 Form 0 100 true Qt::NoTextInteraction Signed 8 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Signed 32 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Hexadecimal Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Unsigned 8 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Unsigned 32 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Octal Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Signed 16 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Signed 64 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Binary Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Unsigned 16 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Unsigned 64 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Text Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Float 32 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Float 64 bit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true CRC16 Sum Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Show Little Endian Decoding true Show Unsigned and Float as Hexidecimal epasveer-seer-97076f1/src/SeerHighlighterSettings.cpp000066400000000000000000000233441526321767600226630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerHighlighterSettings.h" #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif SeerHighlighterSettings::SeerHighlighterSettings () { } SeerHighlighterSettings::SeerHighlighterSettings (const SeerHighlighterSettings& other) { *this = other; } SeerHighlighterSettings::~SeerHighlighterSettings () { } SeerHighlighterSettings& SeerHighlighterSettings::operator= (const SeerHighlighterSettings& rhs) { _keys = rhs._keys; _formats = rhs._formats; _adaSourceSuffixes = rhs._adaSourceSuffixes; _cppSourceSuffixes = rhs._cppSourceSuffixes; _fortranSourceSuffixes = rhs._fortranSourceSuffixes; _rustSourceSuffixes = rhs._rustSourceSuffixes; _odinSourceSuffixes = rhs._odinSourceSuffixes; return *this; } QStringList SeerHighlighterSettings::keys () const { return _keys; } bool SeerHighlighterSettings::has (const QString& name) const { int i = _keys.indexOf(name); if (i < 0) { return false; } return true; } QTextCharFormat SeerHighlighterSettings::get (const QString& name) const { int i = _keys.indexOf(name); if (i < 0) { return QTextCharFormat(); } return _formats[i]; } void SeerHighlighterSettings::add (const QString& name, QTextCharFormat& format) { int i = _keys.indexOf(name); if (i < 0) { _keys.append(name); _formats.append(format); return; } _formats[i] = format; } int SeerHighlighterSettings::count () const { return _keys.size(); } void SeerHighlighterSettings::setAdaSourceSuffixes (const QString& suffixes) { _adaSourceSuffixes = suffixes; } void SeerHighlighterSettings::setCppSourceSuffixes (const QString& suffixes) { _cppSourceSuffixes = suffixes; } void SeerHighlighterSettings::setFortranSourceSuffixes (const QString& suffixes) { _fortranSourceSuffixes = suffixes; } void SeerHighlighterSettings::setOdinSourceSuffixes (const QString& suffixes) { _odinSourceSuffixes = suffixes; } void SeerHighlighterSettings::setRustSourceSuffixes (const QString& suffixes) { _rustSourceSuffixes = suffixes; } const QString& SeerHighlighterSettings::cppSourceSuffixes () { return _cppSourceSuffixes; } const QString& SeerHighlighterSettings::fortranSourceSuffixes () { return _fortranSourceSuffixes; } const QString& SeerHighlighterSettings::odinSourceSuffixes () { return _odinSourceSuffixes; } const QString& SeerHighlighterSettings::rustSourceSuffixes () { return _rustSourceSuffixes; } const QString& SeerHighlighterSettings::adaSourceSuffixes () { return _adaSourceSuffixes; } QStringList SeerHighlighterSettings::themeNames() { QStringList names; names << "auto" << "light" << "dark"; return names; } SeerHighlighterSettings SeerHighlighterSettings::populate (const QString& themeName) { if (themeName == "auto") { #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) // Get the current color scheme Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); if (colorScheme == Qt::ColorScheme::Dark) { return SeerHighlighterSettings::populate_dark(); }else{ return SeerHighlighterSettings::populate_light(); } #else return SeerHighlighterSettings::populate_light(); #endif }else if (themeName == "light") { return SeerHighlighterSettings::populate_light(); }else if (themeName == "dark") { return SeerHighlighterSettings::populate_dark(); } return SeerHighlighterSettings::populate_light(); } SeerHighlighterSettings SeerHighlighterSettings::populate_light () { SeerHighlighterSettings languageSettings; QTextCharFormat f; f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#ffffff")); languageSettings.add("Text", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#c0c0c0")); f.setBackground(QColor("#ffffff")); languageSettings.add("Assembly Text", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#c0c0c0")); languageSettings.add("Margin", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#ffff99")); languageSettings.add("Current Line", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#c0c0c0")); languageSettings.add("Calling Line", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#c0c0c0")); languageSettings.add("Match", f); f = QTextCharFormat(); f.setFontWeight(QFont::Bold); f.setFontItalic(false); f.setForeground(QColor("#800080")); f.setBackground(QColor("#ffffff")); languageSettings.add("Class", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#008000")); f.setBackground(QColor("#ffffff")); languageSettings.add("Quotation", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(true); f.setForeground(QColor("#0000ff")); f.setBackground(QColor("#ffffff")); languageSettings.add("Function", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#ff0000")); f.setBackground(QColor("#ffffff")); languageSettings.add("Comment", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#ff0000")); f.setBackground(QColor("#ffffff")); languageSettings.add("Multiline Comment", f); f = QTextCharFormat(); f.setFontWeight(QFont::Bold); f.setFontItalic(false); f.setForeground(QColor("#000080")); f.setBackground(QColor("#ffffff")); languageSettings.add("Keyword", f); languageSettings.setAdaSourceSuffixes(".ada|.adb|.ads"); languageSettings.setCppSourceSuffixes(".c|.C|.cpp|.CPP|.cxx|.CXX|.h|.H|.hpp|.hxx|.Hxx|.HXX"); languageSettings.setFortranSourceSuffixes(".f90|.F90|.f95|.F95|.f03|.F03|.f08|.F08"); languageSettings.setOdinSourceSuffixes(".odin"); languageSettings.setRustSourceSuffixes(".rs"); return languageSettings; } SeerHighlighterSettings SeerHighlighterSettings::populate_dark () { SeerHighlighterSettings languageSettings; QTextCharFormat f; f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#b2b2b2")); f.setBackground(QColor("#232629")); languageSettings.add("Text", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#32ae48")); f.setBackground(QColor("#232629")); languageSettings.add("Assembly Text", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#7c7f81")); f.setBackground(QColor("#31363b")); languageSettings.add("Margin", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#c7fa54")); f.setBackground(QColor("#8ea82f")); languageSettings.add("Current Line", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#c7fa54")); f.setBackground(QColor("#737373")); languageSettings.add("Calling Line", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#000000")); f.setBackground(QColor("#737373")); languageSettings.add("Match", f); f = QTextCharFormat(); f.setFontWeight(QFont::Bold); f.setFontItalic(false); f.setForeground(QColor("#32ae48")); f.setBackground(QColor("#232629")); languageSettings.add("Class", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#f453de")); f.setBackground(QColor("#232629")); languageSettings.add("Quotation", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(true); f.setForeground(QColor("#736a59")); f.setBackground(QColor("#232629")); languageSettings.add("Function", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#52f8f8")); f.setBackground(QColor("#232629")); languageSettings.add("Comment", f); f = QTextCharFormat(); f.setFontWeight(QFont::Normal); f.setFontItalic(false); f.setForeground(QColor("#52f8f8")); f.setBackground(QColor("#232629")); languageSettings.add("Multiline Comment", f); f = QTextCharFormat(); f.setFontWeight(QFont::Bold); f.setFontItalic(false); f.setForeground(QColor("#d9f743")); f.setBackground(QColor("#232629")); languageSettings.add("Keyword", f); languageSettings.setAdaSourceSuffixes(".ada|.adb|.ads"); languageSettings.setCppSourceSuffixes(".c|.C|.cpp|.CPP|.cxx|.CXX|.h|.H|.hpp|.hxx|.Hxx|.HXX"); languageSettings.setFortranSourceSuffixes(".f90|.F90|.f95|.F95|.f03|.F03|.f08|.F08"); languageSettings.setOdinSourceSuffixes(".odin"); languageSettings.setRustSourceSuffixes(".rs"); return languageSettings; } epasveer-seer-97076f1/src/SeerHighlighterSettings.h000066400000000000000000000051711526321767600223260ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include class SeerHighlighterSettings { public: SeerHighlighterSettings (); SeerHighlighterSettings (const SeerHighlighterSettings& other); ~SeerHighlighterSettings (); SeerHighlighterSettings& operator= (const SeerHighlighterSettings& rhs); QStringList keys () const; bool has (const QString& name) const; QTextCharFormat get (const QString& name) const; void add (const QString& name, QTextCharFormat& format); int count () const; void setAdaSourceSuffixes (const QString& suffixes); void setCppSourceSuffixes (const QString& suffixes); void setFortranSourceSuffixes(const QString& suffixes); void setOdinSourceSuffixes (const QString& suffixes); void setRustSourceSuffixes (const QString& suffixes); const QString& adaSourceSuffixes (); const QString& cppSourceSuffixes (); const QString& fortranSourceSuffixes (); const QString& odinSourceSuffixes (); const QString& rustSourceSuffixes (); static QStringList themeNames (); static SeerHighlighterSettings populate (const QString& themeName); static SeerHighlighterSettings populate_light (); static SeerHighlighterSettings populate_dark (); private: QList _keys; QList _formats; QString _adaSourceSuffixes; QString _cppSourceSuffixes; QString _fortranSourceSuffixes; QString _odinSourceSuffixes; QString _rustSourceSuffixes; }; epasveer-seer-97076f1/src/SeerHistoryLineEdit.cpp000066400000000000000000000010631526321767600217550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerHistoryLineEdit.h" SeerHistoryLineEdit::SeerHistoryLineEdit (const QString& contents, QWidget* parent) : QHistoryLineEdit(contents, parent) { QObject::connect(this, &QHistoryLineEdit::lostFocus, this, &QHistoryLineEdit::execute); } SeerHistoryLineEdit::SeerHistoryLineEdit (QWidget* parent) : QHistoryLineEdit(parent) { QObject::connect(this, &QHistoryLineEdit::lostFocus, this, &QHistoryLineEdit::execute); } epasveer-seer-97076f1/src/SeerHistoryLineEdit.h000066400000000000000000000010231526321767600214160ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "QHistoryLineEdit.h" // // Extends QHistoryLineEdit to connect the 'lostFocus' signal with the // 'execute' slot. This adds the current text to the history when // focus is lost. // class SeerHistoryLineEdit : public QHistoryLineEdit { Q_OBJECT public: SeerHistoryLineEdit(const QString& contents, QWidget* parent = 0); SeerHistoryLineEdit(QWidget* parent = 0); }; epasveer-seer-97076f1/src/SeerImageVisualizerWidget.cpp000066400000000000000000000330061526321767600231440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerImageVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include SeerImageVisualizerWidget::SeerImageVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _variableId = Seer::createID(); // Create two id's for queries. _memoryId = Seer::createID(); _imageWidthId = Seer::createID(); _imageHeightId = Seer::createID(); _formatName = ""; _format = QImage::Format_Invalid; _width = 0; _height = 0; _bytes = 0; // Set up UI. setupUi(this); // Setup the widgets setWindowTitle("Seer Image Visualizer"); setAttribute(Qt::WA_DeleteOnClose); // Connect things. QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleHelpButton); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleVariableNameLineEdit); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerImageVisualizerWidget::handleVariableNameLineEdit); QObject::connect(widthLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleRefreshButton); QObject::connect(widthLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerImageVisualizerWidget::handleWidthLineEdit); QObject::connect(heightLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleRefreshButton); QObject::connect(heightLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerImageVisualizerWidget::handleHeightLineEdit); QObject::connect(formatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerImageVisualizerWidget::handleFormatComboBox); QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handlePrintButton); QObject::connect(saveToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleSaveButton); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerImageVisualizerWidget::handleThemeChanged); #endif // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); // Restore window settings. readSettings(); } SeerImageVisualizerWidget::~SeerImageVisualizerWidget () { } void SeerImageVisualizerWidget::setVariableName (const QString& name) { setWindowTitle("Seer Image Visualizer - '" + name + "'"); variableNameLineEdit->setText(name); setVariableAddress(""); if (variableNameLineEdit->text() == "") { return; } // Clear old contents. QByteArray array; imageViewer->setImage(QImage()); // Send signal to get variable address. emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); } QString SeerImageVisualizerWidget::variableName () const { return variableNameLineEdit->text(); } void SeerImageVisualizerWidget::setVariableAddress (const QString& address) { unsigned long offset = 0; bool ok = false; bool refresh = false; if (address == "") { variableAddressLineEdit->setText(""); offset = 0; }else{ // Test for base10 if (ok == false) { offset = address.toULong(&ok, 10); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); refresh = true; } } // Test for base16 if (ok == false) { offset = address.toULong(&ok, 16); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); refresh = true; } } if (ok == false) { variableAddressLineEdit->setText("not an address"); offset = 0; } } imageViewer->setImage(QImage()); // Show results immediately. if (refresh) { handleRefreshButton(); } } QString SeerImageVisualizerWidget::variableAddress () const { return variableAddressLineEdit->text(); } void SeerImageVisualizerWidget::setImageWidth (const QString& width) { widthLineEdit->setText(width); } QString SeerImageVisualizerWidget::imageWidth () const { return widthLineEdit->text(); } void SeerImageVisualizerWidget::setImageHeight (const QString& height) { heightLineEdit->setText(height); } QString SeerImageVisualizerWidget::imageHeight () const { return heightLineEdit->text(); } void SeerImageVisualizerWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); //qDebug() << text; if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // 10^done,value="1" // 11^done,value="0x7fffffffd538" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { QStringList words = Seer::filterEscapes(Seer::parseFirst(text, "value=", '"', '"', false)).split(' ', Qt::SkipEmptyParts); setVariableAddress(words.first()); }else if (id_text.toInt() == _imageWidthId) { // Set the image width. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setImageWidth(value_text); handleRefreshButton(); }else if (id_text.toInt() == _imageHeightId) { // Set the image height. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setImageHeight(value_text); handleRefreshButton(); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) { // 3^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613e71",contents="00"}] // 4^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613ed4",contents="000000000000000000000000"}] QString id_text = text.section('^', 0,0); if (id_text.toInt() == _memoryId) { //qDebug() << text; QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); // Loop through the memory ranges. for ( const auto& range_text : range_list ) { QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); // Convert hex string to byte array. QByteArray array; for (int i = 0; isetText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) ); } if (id_text.toInt() == _memoryId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); if (msg_text != "") { QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); } } // At a stopping point, refresh. }else if (text.startsWith("*stopped,reason=\"")) { if (autoRefreshCheckBox->isChecked()) { handleRefreshButton(); } }else{ // Ignore anything else. } QApplication::restoreOverrideCursor(); } void SeerImageVisualizerWidget::handleRefreshButton () { // Clear the status. messageLineEdit->setText(""); if (variableNameLineEdit->text() == "") { return; } if (variableAddressLineEdit->text() == "") { return; } if (variableAddressLineEdit->text() == "not an address") { return; } if (widthLineEdit->text() == "") { return; } if (heightLineEdit->text() == "") { return; } // Get image dimensions. int w = widthLineEdit->text().toInt(); int h = heightLineEdit->text().toInt(); if (w < 1 || h < 1) { return; } // Get image format. QString format = formatComboBox->currentText(); // Validate the image dimensions vs. the data size. _formatName = ""; _format = QImage::Format_Invalid; _width = w; _height = h; _bytes = 0; if (format == "RGBA8888") { _formatName = format; _format = QImage::Format_RGBA8888; _bytes = _width * _height * 4; }else if (format == "RGB888") { _formatName = format; _format = QImage::Format_RGB888; _bytes = _width * _height * 3; } // Unknown format. if (_bytes <= 0) { _formatName = ""; _format = QImage::Format_Invalid; _width = w; _height = h; _bytes = 0; messageLineEdit->setText("Unknown image format of '" + format + "."); return; } emit evaluateMemoryExpression(_memoryId, variableAddressLineEdit->text(), _bytes); } void SeerImageVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/ImageVisualizer.md"); help->show(); help->raise(); } void SeerImageVisualizerWidget::handleVariableNameLineEdit () { setVariableName (variableNameLineEdit->text()); } void SeerImageVisualizerWidget::handleWidthLineEdit () { if (widthLineEdit->text() == "") { return; } emit evaluateVariableExpression(_imageWidthId, widthLineEdit->text()); } void SeerImageVisualizerWidget::handleHeightLineEdit () { if (heightLineEdit->text() == "") { return; } emit evaluateVariableExpression(_imageHeightId, heightLineEdit->text()); } void SeerImageVisualizerWidget::handleFormatComboBox (int index) { Q_UNUSED(index); handleRefreshButton(); } void SeerImageVisualizerWidget::handlePrintButton () { imageViewer->print(); } void SeerImageVisualizerWidget::handleSaveButton () { imageViewer->saveFileDialog(variableNameLineEdit->text() + ".png"); } void SeerImageVisualizerWidget::handleCreateImage (const QByteArray& array) { // Clear the status. messageLineEdit->setText(""); // Nothing to do? if (_bytes == 0) { return; } if (_format == QImage::Format_Invalid) { return; } // Data is not large enough for requested image dimensions. if (_bytes > array.size()) { messageLineEdit->setText(QString("%1 memory bytes is not enough for the '%2' image (%3x%4). Need at least %5 bytes.").arg(array.size()) .arg(_formatName) .arg(_width) .arg(_height) .arg(_bytes)); return; } // Construct image. QImage image = QImage((const uchar*)array.data(), _width, _height, _format); imageViewer->setImage(image); } void SeerImageVisualizerWidget::handleThemeChanged () { // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); } void SeerImageVisualizerWidget::writeSettings() { QSettings settings; settings.beginGroup("imagevisualizerwindow"); settings.setValue("size", size()); settings.endGroup(); } void SeerImageVisualizerWidget::readSettings() { QSettings settings; settings.beginGroup("imagevisualizerwindow"); resize(settings.value("size", QSize(800, 400)).toSize()); settings.endGroup(); } void SeerImageVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } epasveer-seer-97076f1/src/SeerImageVisualizerWidget.h000066400000000000000000000053101526321767600226060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerImageVisualizerWidget.h" class SeerImageVisualizerWidget : public QWidget, protected Ui::SeerImageVisualizerWidgetForm { Q_OBJECT public: explicit SeerImageVisualizerWidget (QWidget* parent = 0); ~SeerImageVisualizerWidget (); void setVariableName (const QString& name); QString variableName () const; void setVariableAddress (const QString& address); QString variableAddress () const; void setImageWidth (const QString& width); QString imageWidth () const; void setImageHeight (const QString& height); QString imageHeight () const; signals: void evaluateVariableExpression (int expressionid, QString expression); void evaluateMemoryExpression (int expressionid, QString address, int count); public slots: void handleText (const QString& text); protected slots: void handleRefreshButton (); void handleHelpButton (); void handleVariableNameLineEdit (); void handleWidthLineEdit (); void handleHeightLineEdit (); void handleFormatComboBox (int index); void handlePrintButton (); void handleSaveButton (); void handleCreateImage (const QByteArray& array); void handleThemeChanged (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: int _variableId; int _memoryId; int _imageWidthId; int _imageHeightId; QString _formatName; QImage::Format _format; int _width; int _height; int _bytes; }; epasveer-seer-97076f1/src/SeerImageVisualizerWidget.ui000066400000000000000000000145171526321767600230050ustar00rootroot00000000000000 SeerImageVisualizerWidgetForm 0 0 899 683 Seer Image Visualizer Variable expression resulting in an address. Starting address true Memory address. true Memory address Qt::Vertical RGBA8888 RGB888 The image width (pixels) width true The image height (pixels) height true Qt::Vertical Print the display. ... :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Save the display to a file. ... :/seer/resources/RelaxLightIcons/document-save-as.svg:/seer/resources/RelaxLightIcons/document-save-as.svg Qt::Vertical Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Automatically refresh after each stopping point. Auto Qt::Vertical Help on Image Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg 0 100 true true SeerHistoryLineEdit QLineEdit
SeerHistoryLineEdit.h
QImageViewer QWidget
QImageViewer.h
1
epasveer-seer-97076f1/src/SeerKeySettings.cpp000066400000000000000000000144301526321767600211510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerKeySettings.h" #include SeerKeySettings::SeerKeySettings () { } SeerKeySettings::SeerKeySettings (const SeerKeySettings& other) { *this = other; } SeerKeySettings::~SeerKeySettings () { } SeerKeySettings& SeerKeySettings::operator= (const SeerKeySettings& rhs) { _keys = rhs._keys; return *this; } QStringList SeerKeySettings::keys () const { QList keylist = _keys.keys(); QStringList keys; for (int i=0; i // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include struct SeerKeySetting { SeerKeySetting(QString action, QKeySequence sequence, QString description) : _action(action), _sequence(sequence), _description(description) {} SeerKeySetting() {}; QString _action; QKeySequence _sequence; QString _description; }; class SeerKeySettings { public: SeerKeySettings (); SeerKeySettings (const SeerKeySettings& other); ~SeerKeySettings (); SeerKeySettings& operator= (const SeerKeySettings& rhs); QStringList keys () const; bool has (const QString& action) const; SeerKeySetting get (const QString& action) const; void add (const QString& action, const SeerKeySetting& setting); int count () const; static SeerKeySettings populate (); private: QMap _keys; }; epasveer-seer-97076f1/src/SeerKeysConfigPage.cpp000066400000000000000000000053131526321767600215360ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerKeysConfigPage.h" #include #include #include #include SeerKeysConfigPage::SeerKeysConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Connect things. // Setup the widgets reset(); } SeerKeysConfigPage::~SeerKeysConfigPage() { } void SeerKeysConfigPage::setKeySettings (const SeerKeySettings& settings) { // Clear the table contents. keysTableWidget->setRowCount(0); // Get a list of keys from the highlighter. QStringList keys = settings.keys(); // Loop through each key and get its info. // Construct a table entry. for (int r=0; rinsertRow(r); // Insert the KeySequence editor. QKeySequenceEdit* keySequenceEdit = new QKeySequenceEdit; keySequenceEdit->setKeySequence(setting._sequence); keysTableWidget->setCellWidget(r, 0, keySequenceEdit); // Insert the Description. QLabel* descriptionLabel = new QLabel(setting._description); keysTableWidget->setCellWidget(r, 1, descriptionLabel); } keysTableWidget->setVerticalHeaderLabels(keys); keysTableWidget->resizeColumnToContents(0); // KeySequence keysTableWidget->resizeColumnToContents(1); // Description } SeerKeySettings SeerKeysConfigPage::keySettings() const { SeerKeySettings settings; for (int r=0; rrowCount(); r++) { // Get the key (label) for this row. QString key = keysTableWidget->verticalHeaderItem(r)->text(); // Get widgets for this row. QKeySequenceEdit* keySequenceEdit = dynamic_cast(keysTableWidget->cellWidget(r,0)); QLabel* descriptionLabel = dynamic_cast(keysTableWidget->cellWidget(r,1)); // Create key setting. if (keySequenceEdit != 0 && descriptionLabel != 0) { SeerKeySetting setting(key, keySequenceEdit->keySequence(), descriptionLabel->text()); // Add the setting to our settings. settings.add(key, setting); }else{ if (keySequenceEdit == 0) { qDebug() << "QKeySequenceEdit for row" << r << "is null!"; } if (descriptionLabel == 0) { qDebug() << "QLabel for row" << r << "is null!"; } } } return settings; } void SeerKeysConfigPage::reset () { setKeySettings(SeerKeySettings::populate()); } epasveer-seer-97076f1/src/SeerKeysConfigPage.h000066400000000000000000000012751526321767600212060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerKeySettings.h" #include #include "ui_SeerKeysConfigPage.h" class SeerKeysConfigPage : public QWidget, protected Ui::SeerKeysConfigPage { Q_OBJECT public: explicit SeerKeysConfigPage (QWidget* parent = 0); ~SeerKeysConfigPage (); void setKeySettings (const SeerKeySettings& settings); SeerKeySettings keySettings () const; void reset (); protected slots: private: }; epasveer-seer-97076f1/src/SeerKeysConfigPage.ui000066400000000000000000000070141526321767600213710ustar00rootroot00000000000000 SeerKeysConfigPage 0 0 901 652 SeerKeysConfigPage 0 0 0 25 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Specify key bindings for important Seer operations.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click on the shortcut cell for the key operation you want to change. Then enter the new key sequence.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> 0 75 Gdb and Editor Keys Shortcut Description epasveer-seer-97076f1/src/SeerLibraryBrowserWidget.cpp000066400000000000000000000142161526321767600230160ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerLibraryBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerLibraryBrowserWidget::SeerLibraryBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets librarySearchLineEdit->setPlaceholderText("Search regex..."); librarySearchLineEdit->setClearButtonEnabled(true); libraryTreeWidget->resizeColumnToContents(0); libraryTreeWidget->resizeColumnToContents(1); libraryTreeWidget->resizeColumnToContents(2); libraryTreeWidget->resizeColumnToContents(3); libraryTreeWidget->resizeColumnToContents(4); libraryTreeWidget->resizeColumnToContents(5); libraryTreeWidget->clear(); libraryTreeWidget->setSortingEnabled(false); // Connect things. QObject::connect(librarySearchLineEdit, &QLineEdit::textChanged, this, &SeerLibraryBrowserWidget::handleSearchLineEdit); } SeerLibraryBrowserWidget::~SeerLibraryBrowserWidget () { } void SeerLibraryBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,shared-libraries=[") && text.endsWith("]")) { libraryTreeWidget->clear(); libraryTreeWidget->setSortingEnabled(false); libraryTreeWidget->sortByColumn(-1, Qt::AscendingOrder); // -file-list-shared-libraries // ^done,shared-libraries=[ // {id="/lib/libfoo.so",target-name="/lib/libfoo.so",host-name="/lib/libfoo.so",symbols-loaded="1",thread-group="i1",ranges=[{from="0x72815989",to="0x728162c0"}]}, // {id="/lib/libbar.so",target-name="/lib/libbar.so",host-name="/lib/libbar.so",symbols-loaded="1",thread-group="i1",ranges=[{from="0x76ee48c0",to="0x76ee9160"}]} // ] QString libraries_text = Seer::parseFirst(text, "shared-libraries=", '[', ']', false); //qDebug() << libraries_text; QStringList libraries_list = Seer::parse(libraries_text, "", '{', '}', false); for ( const auto& entry_text : libraries_list ) { QString id_text = Seer::parseFirst(entry_text, "id=", '"', '"', false); QString target_name_text = Seer::parseFirst(entry_text, "target-name=", '"', '"', false); QString host_name_text = Seer::parseFirst(entry_text, "host-name=", '"', '"', false); QString symbols_loaded_text = Seer::parseFirst(entry_text, "symbols-loaded=", '"', '"', false); QString thread_group_text = Seer::parseFirst(entry_text, "thread-group=", '"', '"', false); QString ranges_text = Seer::parseFirst(entry_text, "ranges=", '[', ']', false); // Add the file to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, id_text); item->setText(1, target_name_text); item->setText(2, host_name_text); item->setText(3, symbols_loaded_text); item->setText(4, thread_group_text); item->setText(5, ranges_text); libraryTreeWidget->addTopLevelItem(item); } }else{ // Ignore others. } libraryTreeWidget->resizeColumnToContents(0); libraryTreeWidget->resizeColumnToContents(1); libraryTreeWidget->resizeColumnToContents(2); libraryTreeWidget->resizeColumnToContents(3); libraryTreeWidget->resizeColumnToContents(4); libraryTreeWidget->resizeColumnToContents(5); libraryTreeWidget->sortByColumn(0, Qt::AscendingOrder); libraryTreeWidget->setSortingEnabled(true); librarySearchLineEdit->clear(); QApplication::restoreOverrideCursor(); } void SeerLibraryBrowserWidget::handleSessionTerminated () { // Delete previous contents. libraryTreeWidget->clear(); } void SeerLibraryBrowserWidget::handleSearchLineEdit (const QString& text) { // Set everything to a normal font. If there is no search text, unhide everything. // If there is search text, hide everything so the matching ones can be unhidden later on. QTreeWidgetItemIterator it(libraryTreeWidget); if (*it) { QFont f0 = (*it)->font(0); f0.setBold(false); if (text == "") { while (*it) { (*it)->setHidden(false); // No search text, unhide everything. (*it)->setFont(0,f0); ++it; } }else{ while (*it) { (*it)->setHidden(true); // Has search text, hide everything. Matching items to be unhidden below. (*it)->setFont(0,f0); ++it; } } } // Set selected items to a bold font and unhidden. Move to the first match. if (text != "") { QList matches; matches = libraryTreeWidget->findItems(text, Qt::MatchRegularExpression | Qt::MatchRecursive, 0); QList::const_iterator it = matches.begin(); QList::const_iterator e = matches.end(); if (it != e) { libraryTreeWidget->setCurrentItem(*it); QFont f0 = (*it)->font(0); f0.setBold(true); while (it != e) { (*it)->setHidden(false); (*it)->setFont(0,f0); it++; } } //qDebug() << text << matches.size(); } libraryTreeWidget->resizeColumnToContents(0); libraryTreeWidget->resizeColumnToContents(1); libraryTreeWidget->resizeColumnToContents(2); libraryTreeWidget->resizeColumnToContents(3); libraryTreeWidget->resizeColumnToContents(4); libraryTreeWidget->resizeColumnToContents(5); } void SeerLibraryBrowserWidget::refresh () { emit refreshLibraryList(); } void SeerLibraryBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } epasveer-seer-97076f1/src/SeerLibraryBrowserWidget.h000066400000000000000000000016701526321767600224630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerLibraryBrowserWidget.h" class SeerLibraryBrowserWidget : public QWidget, protected Ui::SeerLibraryBrowserWidgetForm { Q_OBJECT public: explicit SeerLibraryBrowserWidget (QWidget* parent = 0); ~SeerLibraryBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (const QString& text); signals: void refreshLibraryList (); protected: void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerLibraryBrowserWidget.ui000066400000000000000000000035251526321767600226520ustar00rootroot00000000000000 SeerLibraryBrowserWidgetForm 0 0 730 698 Library Browser 6 Id Target-Name Host-Name Symbols Loaded Thread Group Ranges Search in the list of libraries. "*" is allowed. QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
epasveer-seer-97076f1/src/SeerLogWidget.cpp000066400000000000000000000106351526321767600205700ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerLogWidget.h" #include #include #include #include #include #include #include #include #include #include #include SeerLogWidget::SeerLogWidget (QWidget* parent) : QWidget(parent) { setupUi(this); // Setup the widgets QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); textEdit->setReadOnly(true); textEdit->setFont(font); textEdit->setLineWrapMode(QTextEdit::NoWrap); // No wrap wrapTextCheckBox->setCheckState(Qt::Unchecked); // No wrap // Connect things. QObject::connect(clearButton, &QPushButton::clicked, this, &SeerLogWidget::handleClearButton); QObject::connect(printButton, &QPushButton::clicked, this, &SeerLogWidget::handlePrintButton); QObject::connect(saveButton, &QPushButton::clicked, this, &SeerLogWidget::handleSaveButton); QObject::connect(wrapTextCheckBox, &QCheckBox::clicked, this, &SeerLogWidget::handleWrapTextCheckBox); QObject::connect(enableCheckBox, &QCheckBox::clicked, this, &SeerLogWidget::handleEnableCheckBox); QObject::connect(timeStampCheckBox, &QCheckBox::clicked, this, &SeerLogWidget::handleTimeStampCheckBox); } SeerLogWidget::~SeerLogWidget () { } void SeerLogWidget::processText (const QString& text) { // Add text to the end of the document. textEdit->append(text); } bool SeerLogWidget::isLogEnabled () const { return enableCheckBox->isChecked(); } void SeerLogWidget::setLogEnabled (bool flag) { enableCheckBox->setChecked(flag); } bool SeerLogWidget::isTimeStampEnabled () const { return timeStampCheckBox->isChecked(); } void SeerLogWidget::setTimeStampEnabled (bool flag) { timeStampCheckBox->setChecked(flag); } void SeerLogWidget::moveToEnd () { textEdit->verticalScrollBar()->setValue(textEdit->verticalScrollBar()->maximum()); } void SeerLogWidget::setPlaceholderText (const QString& text) { textEdit->setPlaceholderText(text); } void SeerLogWidget::handleText (const QString& text) { // Don't do anything if we're not enabled. if (isLogEnabled() == false) { return; } // Process the text. processText(text); // Move to the end of the document. moveToEnd(); } void SeerLogWidget::handleClearButton () { textEdit->clear(); } void SeerLogWidget::handlePrintButton () { QPrinter printer; QPrintDialog* dlg = new QPrintDialog(&printer, this); if (dlg->exec() != QDialog::Accepted) { return; } QTextDocument* document = textEdit->document(); document->print(&printer); } void SeerLogWidget::handleSaveButton () { QFileDialog dialog(this, "Seer log file", "./", "Logs (*.log);;Text files (*.txt);;All files (*.*)"); dialog.setOptions(QFileDialog::DontUseNativeDialog); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("log"); dialog.selectFile("gdboutput.log"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } QFile file(files[0]); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); stream << textEdit->toPlainText(); file.flush(); file.close(); }else{ QMessageBox::critical(this, tr("Error"), tr("Cannot save log to file.")); return; } } void SeerLogWidget::handleWrapTextCheckBox () { if (wrapTextCheckBox->checkState() == Qt::Unchecked) { textEdit->setLineWrapMode(QTextEdit::NoWrap); // No wrap }else{ textEdit->setLineWrapMode(QTextEdit::WidgetWidth); // Wrap at end of widget } } void SeerLogWidget::handleEnableCheckBox () { emit logEnabledChanged(enableCheckBox->isChecked()); } void SeerLogWidget::handleTimeStampCheckBox () { emit logTimeStampChanged(timeStampCheckBox->isChecked()); } epasveer-seer-97076f1/src/SeerLogWidget.h000066400000000000000000000027511526321767600202350ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerLogWidget.h" class SeerLogWidget : public QWidget, protected Ui::SeerLogWidgetForm { Q_OBJECT public: explicit SeerLogWidget (QWidget* parent = 0); ~SeerLogWidget (); virtual void processText (const QString& text); bool isLogEnabled () const; void setLogEnabled (bool flag); bool isTimeStampEnabled () const; void setTimeStampEnabled (bool flag); void moveToEnd (); void setPlaceholderText (const QString& text); signals: void logEnabledChanged (bool flag); void logTimeStampChanged (bool flag); public slots: void handleText (const QString& text); void handleClearButton (); void handlePrintButton (); void handleSaveButton (); void handleWrapTextCheckBox (); void handleTimeStampCheckBox (); void handleEnableCheckBox (); protected: }; epasveer-seer-97076f1/src/SeerLogWidget.ui000066400000000000000000000135561526321767600204300ustar00rootroot00000000000000 SeerLogWidgetForm 0 0 615 361 Seer Log 100 0 QTextEdit::NoWrap false [gdb output] 0 Print the log output. :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Save the log output to a file. :/seer/resources/RelaxLightIcons/document-save-as.svg:/seer/resources/RelaxLightIcons/document-save-as.svg Qt::Horizontal 0 20 0 Clear the log output. :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 0 20 Enable/Disable output to this log. Enable true 0 0 Wrap long lines to the next line. Wrap Add a timestamp to each line. TStamp Qt::Vertical 28 28 epasveer-seer-97076f1/src/SeerMacroEditorDialog.cpp000066400000000000000000000022221526321767600222240ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMacroEditorDialog.h" #include SeerMacroEditorDialog::SeerMacroEditorDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets setWindowFlags(Qt::Tool); // lightweight tool window setModal(false); // Connect things. } SeerMacroEditorDialog::~SeerMacroEditorDialog () { } void SeerMacroEditorDialog::setMacroName (const QString& name) { setWindowTitle("Seer - Macro Editor for '" + name + "'"); } void SeerMacroEditorDialog::setMacroNickname (const QString& nickname) { nicknameLineEdit->setText(nickname); } QString SeerMacroEditorDialog::macroNickname () const { return nicknameLineEdit->text(); } void SeerMacroEditorDialog::setCommands (const QStringList& commands) { textEditor->clear(); textEditor->setPlainText(commands.join('\n')); textEditor->moveCursor(QTextCursor::Start); textEditor->setFocus(); } QStringList SeerMacroEditorDialog::commands () const { return textEditor->toPlainText().split('\n'); } epasveer-seer-97076f1/src/SeerMacroEditorDialog.h000066400000000000000000000015231526321767600216740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerMacroEditorDialog.h" class SeerMacroEditorDialog : public QDialog, protected Ui::SeerMacroEditorDialog { Q_OBJECT public: explicit SeerMacroEditorDialog (QWidget* parent = 0); ~SeerMacroEditorDialog (); void setMacroName (const QString& name); void setMacroNickname (const QString& nickname); QString macroNickname () const; void setCommands (const QStringList& commands); QStringList commands () const; public slots: private: }; epasveer-seer-97076f1/src/SeerMacroEditorDialog.ui000066400000000000000000000043511526321767600220640ustar00rootroot00000000000000 SeerMacroEditorDialog 0 0 400 300 Seer - Macro Editor Nickname Macro nickname true Insert commands on multiple lines Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerMacroEditorDialog accept() 248 254 157 274 buttonBox rejected() SeerMacroEditorDialog reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerMacroToolButton.cpp000066400000000000000000000121241526321767600217710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMacroToolButton.h" #include "SeerMacroEditorDialog.h" #include #include #include #include #include #include #include #include #include #include SeerMacroToolButton::SeerMacroToolButton(QWidget* parent) : QToolButton(parent) { _holdTimer = new QTimer(this); _holdTimer->setSingleShot(true); _holdTimer->setInterval(500); // 500ms hold time // Create the menu _menu = new QMenu(this); _menu->addAction("Edit Macro", this, &SeerMacroToolButton::handleEditMacro); connect(_holdTimer, &QTimer::timeout, this, &SeerMacroToolButton::handleHoldTriggered); updateToolTip(); } void SeerMacroToolButton::setMacroName (const QString& name, const QString& context) { // Set the macro name. If it's "", nullify our state. _macroName = name; _macroContext = context; if (_macroName == "") { _macroContext = ""; _macroFileName = ""; return; } // Add combination shortcut for re-open closed file (Ctrl + Shift + T) if (macroContext() == "") { QShortcut* shortcut = new QShortcut(QKeySequence(QString("Ctrl+Shift+")+_macroName[1]), this); QObject::connect(shortcut, &QShortcut::activated, this, &QToolButton::click); } // Create the macro filename where the macro is to be written. QSettings settings; QFileInfo fileInfo(settings.fileName()); _macroFileName = fileInfo.absolutePath() + "/macros/" + macroContext() + "/" + _macroName + ".macro"; // Read settings now we have a proper macro name. readMacro(); } const QString& SeerMacroToolButton::macroName () const { return _macroName; } const QString& SeerMacroToolButton::macroContext () const { return _macroContext; } const QString& SeerMacroToolButton::macroFileName () const { return _macroFileName; } void SeerMacroToolButton::setMacroNickname (const QString& nickname) { _macroNickname = nickname; } const QString& SeerMacroToolButton::macroNickname () const { return _macroNickname; } void SeerMacroToolButton::setCommands (const QStringList& commands) { _commands = commands; updateToolTip(); } const QStringList& SeerMacroToolButton::commands () const { return _commands; } void SeerMacroToolButton::writeMacro () { // No macro filename, don't save. if (macroFileName() == "") { return; } // Get the absolute path of the filename. QFileInfo fileInfo(macroFileName()); QString path = fileInfo.absolutePath(); // Create the directory. QDir().mkpath(path); // Create the macro file and write the lines to it. QFile file(macroFileName()); if (file.open(QFile::WriteOnly|QFile::Text|QFile::Truncate)) { QTextStream out(&file); for (const QString& line : commands()) { out << line << "\n"; } file.close(); } // Write macro settings. QSettings settings; settings.beginGroup("macrogdbcommands"); { settings.setValue(macroName()+"_nickname", macroNickname()); settings.setValue(macroName()+"_filename", macroFileName()); } settings.endGroup(); // Update the tooltip. updateToolTip(); } void SeerMacroToolButton::readMacro () { updateToolTip(); if (macroFileName() == "") { return; } QFile file(macroFileName()); if (file.open(QFile::ReadOnly|QFile::Text)) { QStringList lines; QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); lines.append(line); } file.close(); setCommands(lines); // Will update tooltip, too. } } void SeerMacroToolButton::updateToolTip () { QString tip; if (macroName() == "") { tip += "Macro. "; }else{ tip += macroName() + " macro. "; } tip += "Click to execute. Hold down to edit."; if (commands().count() > 0) { tip += "\n\nPreview:\n\n"; tip += commands().join("\n"); } setToolTip(tip); } void SeerMacroToolButton::mousePressEvent (QMouseEvent* event) { QToolButton::mousePressEvent(event); _pressPos = event->pos(); _holdTimer->start(); } void SeerMacroToolButton::mouseReleaseEvent (QMouseEvent* event) { QToolButton::mouseReleaseEvent(event); _holdTimer->stop(); } void SeerMacroToolButton::handleHoldTriggered () { // Show menu at button position QPoint globalPos = mapToGlobal(QPoint(0, height())); _menu->exec(globalPos); // Reset button to unpressed state setDown(false); } void SeerMacroToolButton::handleEditMacro () { SeerMacroEditorDialog dlg; dlg.setMacroName(macroName()); dlg.setMacroNickname(macroNickname()); dlg.setCommands(commands()); if (dlg.exec()) { setMacroNickname(dlg.macroNickname()); setCommands(dlg.commands()); writeMacro(); } } epasveer-seer-97076f1/src/SeerMacroToolButton.h000066400000000000000000000035151526321767600214420ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerMacroToolButton : public QToolButton { Q_OBJECT public: explicit SeerMacroToolButton(QWidget* parent = nullptr); void setMacroName (const QString& name, const QString& context = ""); const QString& macroName () const; const QString& macroContext () const; const QString& macroFileName () const; void setMacroNickname (const QString& nickname); const QString& macroNickname () const; void setCommands (const QStringList& commands); const QStringList& commands () const; protected: void writeMacro (); void readMacro (); void updateToolTip (); void mousePressEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; signals: private slots: void handleHoldTriggered (); void handleEditMacro (); private: QTimer* _holdTimer; QMenu* _menu; QPoint _pressPos; QString _macroContext; QString _macroName; QString _macroFileName; QString _macroNickname; QStringList _commands; }; epasveer-seer-97076f1/src/SeerMainWindow.cpp000066400000000000000000002656761526321767600210000ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMainWindow.h" #include "SeerDebugDialog.h" #include "SeerConfigDialog.h" #include "SeerArgumentsDialog.h" #include "SeerAboutDialog.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include #include SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) { // // Set up UI. // setupUi(this); // // Set up other parts of the UI. // // Add status bar indicator. SeerRunStatusIndicator* runStatus = new SeerRunStatusIndicator(this); statusBar()->addPermanentWidget(runStatus); // Add progress spin widget. QWidget* spacerWidget = new QWidget(this); spacerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); spacerWidget->setStyleSheet("background-color:transparent"); // Need this for QToolBar StyleSheets to work. toolBar->addWidget(spacerWidget); _progressIndicator = new SeerProgressIndicator(this); _progressIndicator->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); _progressIndicator->setFixedWidth(96); _progressIndicator->setColor(palette().color(QPalette::WindowText)); toolBar->addWidget(_progressIndicator); // Add help button. QToolButton* helpToolButton = new QToolButton(this); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on Seer main window."); toolBar->addWidget(helpToolButton); // Set up ThemeStyle menu. _themeStyleMenuActionGroup = new QActionGroup(this); _themeStyleMenuActionGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::Exclusive); _themeStyleMenuActionGroup->setEnabled(true); _themeStyleMenuActionGroup->setVisible(true); QAction* lightStyleAction = menuThemeStyle->addAction("light"); lightStyleAction->setCheckable(true); _themeStyleMenuActionGroup->addAction(lightStyleAction); QAction* darkStyleAction = menuThemeStyle->addAction("dark"); darkStyleAction->setCheckable(true); _themeStyleMenuActionGroup->addAction(darkStyleAction); QStringList styles = QStyleFactory::keys(); for (int i = 0; i < styles.size(); i++) { QAction* styleAction = menuThemeStyle->addAction(styles.at(i)); styleAction->setCheckable(true); _themeStyleMenuActionGroup->addAction(styleAction); } // Set up IconColor menu. _iconColorMenuActionGroup = new QActionGroup(this); _iconColorMenuActionGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::Exclusive); _iconColorMenuActionGroup->setEnabled(true); _iconColorMenuActionGroup->setVisible(true); QAction* autoIconColorAction = menuIconColor->addAction("auto"); autoIconColorAction->setCheckable(true); _iconColorMenuActionGroup->addAction(autoIconColorAction); QAction* lightIconColorAction = menuIconColor->addAction("light"); lightIconColorAction->setCheckable(true); _iconColorMenuActionGroup->addAction(lightIconColorAction); QAction* darkIconColorAction = menuIconColor->addAction("dark"); darkIconColorAction->setCheckable(true); _iconColorMenuActionGroup->addAction(darkIconColorAction); // Hide Nexti and Stepi. Enabled/disabled by SeerEditorManagerWidget. actionGdbNext->setVisible(true); actionGdbNexti->setVisible(false); actionGdbStep->setVisible(true); actionGdbStepi->setVisible(false); actionGdbFinish->setVisible(true); // Set up Interrupt menu. QMenu* menuInterrupt = new QMenu(this); _interruptAction = menuInterrupt->addAction("Interrupt"); menuInterrupt->addSeparator(); QAction* interruptActionSIGINT = menuInterrupt->addAction("SIGINT"); QAction* interruptActionSIGKILL = menuInterrupt->addAction("SIGKILL"); QAction* interruptActionSIGFPE = menuInterrupt->addAction("SIGFPE"); QAction* interruptActionSIGSEGV = menuInterrupt->addAction("SIGSEGV"); QAction* interruptActionSIGUSR1 = menuInterrupt->addAction("SIGUSR1"); QAction* interruptActionSIGUSR2 = menuInterrupt->addAction("SIGUSR2"); actionInterruptProcess->setMenu(menuInterrupt); // Set up Visualizer menu. QMenu* menuVisualizer = new QMenu(this); QAction* visualizerMemoryAction = menuVisualizer->addAction("Memory"); menuVisualizer->addSeparator(); QAction* visualizerArrayAction = menuVisualizer->addAction("Array"); QAction* visualizerMatrixAction = menuVisualizer->addAction("Matrix"); QAction* visualizerVarAction = menuVisualizer->addAction("Struct"); QAction* visualizerStructAction = menuVisualizer->addAction("BasicStruct"); QAction* visualizerImageAction = menuVisualizer->addAction("Image"); QAction* visualizerParallelStacksAction = menuVisualizer->addAction("ParallelStacks"); QAction* visualizerGdbMonitorAction = menuVisualizer->addAction("GDB Monitor"); actionVisualizers->setMenu(menuVisualizer); // Set up control menu for recording. QActionGroup* recordDirectionActionGroup = new QActionGroup(this); recordDirectionActionGroup->addAction(actionControlRecordForward); recordDirectionActionGroup->addAction(actionControlRecordReverse); // Set the inital key settings. setKeySettings(SeerKeySettings::populate()); setProjectFilename(""); // Set the default shotcut key to toggle record direction. actionRecordDirection->setShortcut(QKeySequence::fromString("Ctrl+D")); // // Set up signals/slots. // QObject::connect(actionFileDebug, &QAction::triggered, this, &SeerMainWindow::handleFileDebugWithOutDefaultProject); QObject::connect(actionFileArguments, &QAction::triggered, this, &SeerMainWindow::handleFileArguments); QObject::connect(actionFileQuit, &QAction::triggered, this, &SeerMainWindow::handleFileQuit); QObject::connect(actionViewMemoryVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewMemoryVisualizer); QObject::connect(actionViewArrayVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewArrayVisualizer); QObject::connect(actionViewMatrixVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewMatrixVisualizer); QObject::connect(actionViewStructVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewVarVisualizer); QObject::connect(actionViewBasicStructVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewStructVisualizer); QObject::connect(actionViewImageVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewImageVisualizer); QObject::connect(actionViewParallelStacksVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewParallelStacksVisualizer); QObject::connect(actionViewGdbMonitor, &QAction::triggered, this, &SeerMainWindow::handleViewGdbMonitor); QObject::connect(actionViewAssembly, &QAction::triggered, this, &SeerMainWindow::handleViewAssembly); QObject::connect(actionConsoleAttached, &QAction::triggered, this, &SeerMainWindow::handleViewConsoleAttached); QObject::connect(actionConsoleDetached, &QAction::triggered, this, &SeerMainWindow::handleViewConsoleDetached); QObject::connect(actionConsoleDetachedMinimized, &QAction::triggered, this, &SeerMainWindow::handleViewConsoleDetachedMinimized); QObject::connect(actionHelpAbout, &QAction::triggered, this, &SeerMainWindow::handleHelpAbout); QObject::connect(actionControlRestart, &QAction::triggered, this, &SeerMainWindow::handleRestartExecutable); QObject::connect(actionControlTerminate, &QAction::triggered, this, &SeerMainWindow::handleTerminateExecutable); QObject::connect(actionControlContinue, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbContinue); QObject::connect(actionControlNext, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbNext); QObject::connect(actionControlStep, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbStep); QObject::connect(actionControlNexti, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbNexti); QObject::connect(actionControlStepi, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbStepi); QObject::connect(actionControlFinish, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbFinish); QObject::connect(actionControlRunToLine, &QAction::triggered, gdbWidget->editorManager(), &SeerEditorManagerWidget::handleRunToSelectedLine); QObject::connect(actionControlReverseContinue, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseContinue); QObject::connect(actionControlReverseNext, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseNext); QObject::connect(actionControlReverseStep, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseStep); QObject::connect(actionControlReverseNexti, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseNexti); QObject::connect(actionControlReverseStepi, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseStepi); QObject::connect(actionControlReverseFinish, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbReverseFinish); QObject::connect(actionControlRecordStart, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordStart); QObject::connect(actionControlRecordForward, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordForward); QObject::connect(actionControlRecordReverse, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordReverse); QObject::connect(actionControlRecordStop, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordStop); QObject::connect(actionControlInterrupt, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterrupt); QObject::connect(actionSettingsConfiguration, &QAction::triggered, this, &SeerMainWindow::handleSettingsConfiguration); QObject::connect(actionSettingsSaveConfiguration, &QAction::triggered, this, &SeerMainWindow::handleSettingsSaveConfiguration); QObject::connect(actionGdbLaunch, &QAction::triggered, this, &SeerMainWindow::handleFileDebugWithOutDefaultProject); QObject::connect(actionGdbTerminate, &QAction::triggered, this, &SeerMainWindow::handleTerminateExecutable); QObject::connect(actionGdbRestart, &QAction::triggered, this, &SeerMainWindow::handleRestartExecutable); QObject::connect(_themeStyleMenuActionGroup, &QActionGroup::triggered, this, &SeerMainWindow::handleThemeStyleMenuChanged); QObject::connect(_iconColorMenuActionGroup, &QActionGroup::triggered, this, &SeerMainWindow::handleIconColorMenuChanged); QObject::connect(actionGdbContinue, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbContinue); QObject::connect(actionGdbNext, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbNext); QObject::connect(actionGdbStep, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbStep); QObject::connect(actionGdbNexti, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbNexti); QObject::connect(actionGdbStepi, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbStepi); QObject::connect(actionGdbFinish, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbFinish); QObject::connect(actionRecordProcess, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordStartStopToggle); QObject::connect(actionRecordDirection, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbRecordDirectionToggle); QObject::connect(actionInterruptProcess, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterrupt); QObject::connect(_interruptAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterrupt); QObject::connect(interruptActionSIGINT, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGINT); QObject::connect(interruptActionSIGKILL, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGKILL); QObject::connect(interruptActionSIGFPE, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGFPE); QObject::connect(interruptActionSIGSEGV, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGSEGV); QObject::connect(interruptActionSIGUSR1, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGUSR1); QObject::connect(interruptActionSIGUSR2, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGUSR2); QObject::connect(actionVisualizers, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbMemoryVisualizer); QObject::connect(visualizerMemoryAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbMemoryVisualizer); QObject::connect(visualizerArrayAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbArrayVisualizer); QObject::connect(visualizerMatrixAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbMatrixVisualizer); QObject::connect(visualizerVarAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbVarVisualizer); QObject::connect(visualizerStructAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbStructVisualizer); QObject::connect(visualizerImageAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbImageVisualizer); QObject::connect(visualizerParallelStacksAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbParallelStacksVisualizer); QObject::connect(visualizerGdbMonitorAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbMonitor); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::astrixTextOutput, runStatus, &SeerRunStatusIndicator::handleText); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::equalTextOutput, runStatus, &SeerRunStatusIndicator::handleText); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::astrixTextOutput, this, &SeerMainWindow::handleText); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::caretTextOutput, this, &SeerMainWindow::handleText); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::equalTextOutput, this, &SeerMainWindow::handleText); QObject::connect(gdbWidget->editorManager(), &SeerEditorManagerWidget::showMessage, this, &SeerMainWindow::handleShowMessage); QObject::connect(gdbWidget->editorManager(), &SeerEditorManagerWidget::assemblyTabShown, this, &SeerMainWindow::handleViewAssemblyShown); QObject::connect(gdbWidget, &SeerGdbWidget::recordSettingsChanged, this, &SeerMainWindow::handleRecordSettingsChanged); QObject::connect(gdbWidget, &SeerGdbWidget::changeWindowTitle, this, &SeerMainWindow::handleChangeWindowTitle); QObject::connect(gdbWidget, &SeerGdbWidget::stateChanged, this, &SeerMainWindow::handleGdbStateChanged); QObject::connect(runStatus, &SeerRunStatusIndicator::statusChanged, this, &SeerMainWindow::handleRunStatusChanged); QObject::connect(qApp, &QApplication::aboutToQuit, gdbWidget, &SeerGdbWidget::handleGdbShutdown); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerMainWindow::handleHelpToolButtonClicked); QObject::connect(gdbWidget, &SeerGdbWidget::sessionTerminated, runStatus, &SeerRunStatusIndicator::handleSessionTerminated); // This handle button state when target state changes QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::astrixTextOutput, this, &SeerMainWindow::handleStatusChanged); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::caretTextOutput, this, &SeerMainWindow::handleStatusChanged); // Handle when theme is changed. Change the color of all icons. #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerMainWindow::handleThemeChanged); #endif // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); handleRecordSettingsChanged(); // // Initialize contents. // // Restore window settings. readSettings(); // Restore configuration settings. readConfigSettings(); // Show the main window. show(); handleShowMessage("Welcome to Seer. The All Knowing...", 3000); } SeerMainWindow::~SeerMainWindow() { } void SeerMainWindow::setExecutableName (const QString& executableName) { gdbWidget->setExecutableName(executableName); } const QString& SeerMainWindow::executableName () const { return gdbWidget->executableName(); } void SeerMainWindow::setExecutableSymbolName (const QString& executableSymbolName) { gdbWidget->setExecutableSymbolName(executableSymbolName); } const QString& SeerMainWindow::executableSymbolName () const { return gdbWidget->executableSymbolName(); } void SeerMainWindow::setExecutableArguments (const QString& executableArguments) { gdbWidget->setExecutableArguments(executableArguments); } void SeerMainWindow::setExecutableArguments (const QStringList& executableArguments) { // // Convert the list of arguments into a single argument string. // Be careful of arguments that contain a space. These need to be surrounded by // a "'" character to retain the argument grouping. // // ie: myprog 42.0 "This is a multi-worded argument" // // Has 2 arguments. Not 6. // QString arguments; for (auto arg : executableArguments) { if (arg.contains(' ')) { arg = "'" + arg + "'"; } if (arguments == "") { arguments = arg; }else{ arguments += " " + arg; } } setExecutableArguments(arguments); } const QString& SeerMainWindow::executableArguments () const { return gdbWidget->executableArguments(); } void SeerMainWindow::setExecutableWorkingDirectory (const QString& executableWorkingDirectory) { gdbWidget->setExecutableWorkingDirectory(executableWorkingDirectory); } const QString& SeerMainWindow::executableWorkingDirectory () const { return gdbWidget->executableWorkingDirectory(); } void SeerMainWindow::setExecutableBreakpointsFilename (const QString& breakpointsFilename) { gdbWidget->setExecutableBreakpointsFilename(breakpointsFilename); } const QString& SeerMainWindow::executableBreakpointsFilename () const { return gdbWidget->executableBreakpointsFilename(); } void SeerMainWindow::setExecutableBreakpointFunctionName (const QString& nameoraddress) { gdbWidget->setExecutableBreakpointFunctionName(nameoraddress); } const QString& SeerMainWindow::executableBreakpointFunctionName () const { return gdbWidget->executableBreakpointFunctionName(); } void SeerMainWindow::setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno) { gdbWidget->setExecutableBreakpointSourceName(sourceFilenameAndLineno); } const QString& SeerMainWindow::executableBreakpointSourceName () const { return gdbWidget->executableBreakpointSourceName(); } void SeerMainWindow::setExecutableBreakpointFirstInstruction (bool flag) { gdbWidget->setExecutableBreakpointFirstInstruction(flag); } bool SeerMainWindow::executableBreakpointFirstInstruction () const { return gdbWidget->executableBreakpointFirstInstruction(); } void SeerMainWindow::setExecutableShowAssemblyTabMode (const QString& mode) { gdbWidget->setAssemblyShowAssemblyTabOnStartupMode(mode); } QString SeerMainWindow::executableShowAssemblyTabMode () const { return gdbWidget->assemblyShowAssemblyTabOnStartupMode(); } void SeerMainWindow::setExecutableRandomizeStartAddress (bool flag) { gdbWidget->setGdbRandomizeStartAddress(flag); } bool SeerMainWindow::executableRandomizeStartAddress () const { return gdbWidget->gdbRandomizeStartAddress(); } void SeerMainWindow::setExecutableNonStopMode (bool flag) { gdbWidget->setGdbNonStopMode(flag); } bool SeerMainWindow::executableNonStopMode () const { return gdbWidget->gdbNonStopMode(); } void SeerMainWindow::setExecutablePid (int pid) { gdbWidget->setExecutablePid(pid); } int SeerMainWindow::executablePid () const { return gdbWidget->executablePid(); } void SeerMainWindow::setExecutableConnectHostPort (const QString& executableConnectHostPort) { gdbWidget->setExecutableConnectHostPort(executableConnectHostPort); } const QString& SeerMainWindow::executableConnectHostPort () const { return gdbWidget->executableConnectHostPort(); } void SeerMainWindow::setExecutableConnectRemoteTargetType (const QString& type) { gdbWidget->setGdbRemoteTargetType(type); } QString SeerMainWindow::executableConnectRemoteTargetType () const { return gdbWidget->gdbRemoteTargetType(); } void SeerMainWindow::setExecutableConnectGdbserverDebug (bool enable) { gdbWidget->setGdbServerDebug(enable); } bool SeerMainWindow::executableConnectGdbserverDebug () const { return gdbWidget->gdbServerDebug(); } void SeerMainWindow::setExecutableRRTraceDirectory (const QString& executableRRTraceDirectory) { gdbWidget->setExecutableRRTraceDirectory(executableRRTraceDirectory); } const QString& SeerMainWindow::executableRRTraceDirectory () const { return gdbWidget->executableRRTraceDirectory(); } void SeerMainWindow::setExecutableCoreFilename (const QString& executableCoreFilename) { gdbWidget->setExecutableCoreFilename(executableCoreFilename); } const QString& SeerMainWindow::executableCoreFilename () const { return gdbWidget->executableCoreFilename(); } void SeerMainWindow::setExecutablePreGdbCommands (const QStringList& preGdbCommands) { gdbWidget->setExecutablePreGdbCommands(preGdbCommands); } const QStringList& SeerMainWindow::executablePreGdbCommands() const { return gdbWidget->executablePreGdbCommands(); } void SeerMainWindow::setExecutablePostGdbCommands (const QStringList& postGdbCommands) { gdbWidget->setExecutablePostGdbCommands(postGdbCommands); } const QStringList& SeerMainWindow::executablePostGdbCommands() const { return gdbWidget->executablePostGdbCommands(); } void SeerMainWindow::setProjectFilename (const QString& projectFilename) { _projectFile = projectFilename; } const QString& SeerMainWindow::projectFilename () const { return _projectFile; } void SeerMainWindow::setGdbProgramOverride (const QString& gdbProgram) { gdbWidget->setGdbProgramOverride(gdbProgram); } QString SeerMainWindow::gdbProgramOverride () const { return gdbWidget->gdbProgramOverride(); } void SeerMainWindow::setGdbArgumentsOverride (const QString& gdbArguments) { gdbWidget->setGdbArgumentsOverride(gdbArguments); } QString SeerMainWindow::gdbArgumentsOverride () const { return gdbWidget->gdbArgumentsOverride(); } void SeerMainWindow::launchExecutable (const QString& launchMode, const QString& breakMode) { // Show all buttons by default. Turn some off depending on debug mode. actionGdbContinue->setVisible(true); actionGdbNext->setVisible(true); actionGdbNexti->setVisible(true); actionGdbStep->setVisible(true); actionGdbStepi->setVisible(true); actionGdbFinish->setVisible(true); actionInterruptProcess->setVisible(true); actionRecordProcess->setVisible(true); actionRecordDirection->setVisible(true); actionGdbRestart->setVisible(false); actionGdbTerminate->setVisible(false); actionGdbLaunch->setVisible(false); actionControlRestart->setVisible(true); actionControlTerminate->setVisible(true); actionControlInterrupt->setVisible(true); if (launchMode == "run") { gdbWidget->handleGdbRunExecutable(breakMode, false); }else if (launchMode == "start") { gdbWidget->handleGdbRunExecutable(breakMode, false); }else if (launchMode == "attach") { gdbWidget->handleGdbAttachExecutable(false); }else if (launchMode == "connect") { gdbWidget->handleGdbConnectExecutable(false); }else if (launchMode == "rr") { gdbWidget->handleGdbRRExecutable(false); }else if (launchMode == "corefile") { actionGdbContinue->setVisible(false); actionGdbNext->setVisible(false); actionGdbNexti->setVisible(false); actionGdbStep->setVisible(false); actionGdbStepi->setVisible(false); actionGdbFinish->setVisible(false); actionInterruptProcess->setVisible(false); actionRecordProcess->setVisible(false); actionRecordDirection->setVisible(false); gdbWidget->handleGdbCoreFileExecutable(); }else if (launchMode == "project") { actionGdbLaunch->setVisible(true); // If no mode, schedule the opening of the debug dialog. QTimer::singleShot(200, this, &SeerMainWindow::handleFileDebugWithDefaultProject); }else if (launchMode == "none") { actionGdbLaunch->setVisible(true); // If no mode, schedule the opening of the debug dialog. QTimer::singleShot(200, this, &SeerMainWindow::handleFileDebugWithDefaultProject); }else if (launchMode == "configdialog") { actionGdbLaunch->setVisible(true); // Launch the config dialog. QTimer::singleShot(200, this, &SeerMainWindow::handleSettingsConfiguration); }else{ qDebug() << "UNKNOWN launch mode:" << launchMode; } } const QString& SeerMainWindow::executableLaunchMode () const { return gdbWidget->executableLaunchMode(); } const QString& SeerMainWindow::executableBreakMode () const { return gdbWidget->executableBreakMode(); } void SeerMainWindow::setStyleName (const QString& name) { // Check for Dark/Light style from Seer's resource tree. if (name == "dark" || name == "light") { QFile s(":qdarkstyle/" + name + "/" + name + "style.qss"); if (s.exists() == false) { qDebug() << "Stylesheet '" + name + "' doesn't exist!"; return; } bool f = s.open(QFile::ReadOnly | QFile::Text); if (f == false) { qDebug() << "Can't open Stylesheet '" + name + "'!"; return; } QTextStream ts(&s); qApp->setStyleSheet(ts.readAll()); _styleName = name; // Otherwise, a system installed one or Qt internal one. }else{ QApplication::setStyle(name); _styleName = name; } } const QString& SeerMainWindow::styleName () { return _styleName; } void SeerMainWindow::setIconColorTheme(const QString& mode) { Seer::setIconColorTheme(mode); handleThemeChanged(); // Will trigger the icon colorization. } const QString& SeerMainWindow::iconColorTheme () { return Seer::iconColorTheme(); } void SeerMainWindow::handleFileDebugWithDefaultProject () { handleFileDebug(true); } void SeerMainWindow::handleFileDebugWithOutDefaultProject () { handleFileDebug(false); } void SeerMainWindow::handleFileDebug (bool loadDefaultProject) { SeerDebugDialog dlg(this); dlg.setExecutableName(executableName()); dlg.setExecutableSymbolName(executableSymbolName()); dlg.setExecutableWorkingDirectory(executableWorkingDirectory()); dlg.setExecutableArguments(executableArguments()); dlg.setLaunchMode(executableLaunchMode()); dlg.setBreakpointMode(executableBreakMode()); dlg.setBreakpointsFilename(executableBreakpointsFilename()); dlg.setBreakpointFunctionName(executableBreakpointFunctionName()); dlg.setBreakpointSourceName(executableBreakpointSourceName()); dlg.setBreakpointFirstInstruction(executableBreakpointFirstInstruction()); dlg.setShowAssemblyTabMode(executableShowAssemblyTabMode()); dlg.setRandomizeStartAddress(executableRandomizeStartAddress()); dlg.setNonStopMode(executableNonStopMode()); dlg.setAttachPid(executablePid()); dlg.setConnectHostPort(executableConnectHostPort()); dlg.setConnectRemoteTargetType(executableConnectRemoteTargetType()); dlg.setConnectGdbserverDebug(executableConnectGdbserverDebug()); dlg.setRRTraceDirectory(executableRRTraceDirectory()); dlg.setCoreFilename(executableCoreFilename()); dlg.setPreGdbCommands(executablePreGdbCommands()); dlg.setPostGdbCommands(executablePostGdbCommands()); // If there's a project, use it. if (projectFilename() != "") { dlg.setProjectFilename(projectFilename()); // Otherwise use the default project, if there is one. }else{ if (loadDefaultProject && executableName() == "") { dlg.loadDefaultProjectSettings(); } } setProjectFilename(""); // Clear project name here. No need to have it anymore. int ret = dlg.exec(); if (ret == 0) { return; } QString launchMode = dlg.launchMode(); QString breakMode = dlg.breakpointMode(); if (launchMode == "") { return; } setExecutableName(dlg.executableName()); setExecutableSymbolName(dlg.executableSymbolName()); setExecutableWorkingDirectory(dlg.executableWorkingDirectory()); setExecutableArguments(dlg.executableArguments()); setExecutableBreakpointsFilename(dlg.breakpointsFilename()); setExecutableBreakpointFunctionName(dlg.breakpointFunctionName()); setExecutableBreakpointSourceName(dlg.breakpointSourceName()); setExecutableBreakpointFirstInstruction(dlg.breakpointFirstInstruction()); setExecutableShowAssemblyTabMode(dlg.showAssemblyTabMode()); setExecutableRandomizeStartAddress(dlg.randomizeStartAddress()); setExecutableNonStopMode(dlg.nonStopMode()); setExecutablePid(dlg.attachPid()); setExecutableConnectHostPort(dlg.connectHostPort()); setExecutableConnectRemoteTargetType(dlg.connectRemoteTargetType()); setExecutableConnectGdbserverDebug(dlg.connectGdbserverDebug()); setExecutableRRTraceDirectory(dlg.rrTraceDirectory()); setExecutableCoreFilename(dlg.coreFilename()); setExecutablePreGdbCommands(dlg.preGdbCommands()); setExecutablePostGdbCommands(dlg.postGdbCommands()); launchExecutable(launchMode, breakMode); } void SeerMainWindow::handleFileArguments () { SeerArgumentsDialog dlg(this); dlg.setExecutableArguments(executableArguments()); int ret = dlg.exec(); if (ret == 0) { return; } setExecutableArguments(dlg.executableArguments()); } void SeerMainWindow::handleFileQuit () { gdbWidget->handleGdbShutdown(); QCoreApplication::exit(0); } void SeerMainWindow::handleViewMemoryVisualizer () { gdbWidget->handleGdbMemoryVisualizer(); } void SeerMainWindow::handleViewArrayVisualizer () { gdbWidget->handleGdbArrayVisualizer(); } void SeerMainWindow::handleViewMatrixVisualizer () { gdbWidget->handleGdbMatrixVisualizer(); } void SeerMainWindow::handleViewStructVisualizer () { gdbWidget->handleGdbStructVisualizer(); } void SeerMainWindow::handleViewVarVisualizer () { gdbWidget->handleGdbVarVisualizer(); } void SeerMainWindow::handleViewImageVisualizer () { gdbWidget->handleGdbImageVisualizer(); } void SeerMainWindow::handleViewParallelStacksVisualizer () { gdbWidget->handleGdbParallelStacksVisualizer(); } void SeerMainWindow::handleViewGdbMonitor() { gdbWidget->handleGdbMonitor(); } void SeerMainWindow::handleViewAssembly () { gdbWidget->editorManager()->showAssembly(); } void SeerMainWindow::handleViewAssemblyShown (bool shown) { // Corefile always have them off. if (executableLaunchMode() == "corefile") { actionGdbNext->setVisible(false); actionGdbNexti->setVisible(false); actionGdbStep->setVisible(false); actionGdbStepi->setVisible(false); actionGdbFinish->setVisible(false); // Toggle regular and instruction buttons. }else{ actionGdbNext->setVisible(!shown); actionGdbNexti->setVisible(shown); actionGdbStep->setVisible(!shown); actionGdbStepi->setVisible(shown); actionGdbFinish->setVisible(!shown); } } void SeerMainWindow::handleViewConsoleAttached () { gdbWidget->setConsoleMode("attached"); } void SeerMainWindow::handleViewConsoleDetached () { gdbWidget->setConsoleMode("detached"); } void SeerMainWindow::handleViewConsoleDetachedMinimized () { gdbWidget->setConsoleMode("detachedminimized"); } void SeerMainWindow::handleSettingsConfiguration () { SeerConfigDialog dlg(this); dlg.setSeerConsoleMode(gdbWidget->consoleMode()); dlg.setSeerConsoleScrollLines(gdbWidget->consoleScrollLines()); dlg.setSeerRememberManualCommandCount(gdbWidget->rememberManualCommandCount()); dlg.setGdbLauncher(gdbWidget->gdbLauncher()); dlg.setGdbProgram(gdbWidget->gdbProgram()); dlg.setGdbArguments(gdbWidget->gdbArguments()); dlg.setGdbAsyncMode(gdbWidget->gdbAsyncMode()); dlg.setGdbNonStopMode(gdbWidget->gdbNonStopMode()); dlg.setGdbHandleTerminatingException(gdbWidget->gdbHandleTerminatingException()); dlg.setGdbRandomizeStartAddress(gdbWidget->gdbRandomizeStartAddress()); dlg.setGdbEnablePrettyPrinting(gdbWidget->gdbEnablePrettyPrinting()); dlg.setGdbRemoteTargetType(gdbWidget->gdbRemoteTargetType()); dlg.setGdbArchitectureType(gdbWidget->gdbArchitectureType()); dlg.setEditorFont(gdbWidget->editorManager()->editorFont()); dlg.setEditorTabSize(gdbWidget->editorManager()->editorTabSize()); dlg.setEditorHighlighterSettings(gdbWidget->editorManager()->editorHighlighterSettings()); dlg.setEditorHighlighterEnabled(gdbWidget->editorManager()->editorHighlighterEnabled()); dlg.setEditorMinimapEnabled(gdbWidget->editorManager()->editorMinimapEnabled()); dlg.setExternalEditorCommand(gdbWidget->editorManager()->editorExternalEditorCommand()); dlg.setEditorAutoSourceReload(gdbWidget->editorManager()->editorAutoSourceReload()); dlg.setSourceAlternateDirectories(gdbWidget->sourceAlternateDirectories()); dlg.setSourceIgnoreFilePatterns(gdbWidget->sourceIgnoreFilePatterns()); dlg.setSourceMiscFilePatterns(gdbWidget->sourceMiscFilePatterns()); dlg.setSourceSourceFilePatterns(gdbWidget->sourceSourceFilePatterns()); dlg.setSourceHeaderFilePatterns(gdbWidget->sourceHeaderFilePatterns()); dlg.setAssemblyShowAssemblyTabOnStartupMode(gdbWidget->assemblyShowAssemblyTabOnStartupMode()); dlg.setAssemblyKeepAssemblyTabOnTop(gdbWidget->assemblyKeepAssemblyTabOnTop()); dlg.setAssemblyDisassemblyFlavor(gdbWidget->assemblyDisassemblyFlavor()); dlg.setAssemblySymbolDemagling(gdbWidget->assemblySymbolDemagling()); dlg.setAssemblyShowAddressColumn(gdbWidget->assemblyShowAddressColumn()); dlg.setAssemblyShowOffsetColumn(gdbWidget->assemblyShowOffsetColumn()); dlg.setAssemblyShowOpcodeColumn(gdbWidget->assemblyShowOpcodeColumn()); dlg.setAssemblyShowSourceLines(gdbWidget->assemblyShowSourceLines()); dlg.setAssemblyRegisterFormat(gdbWidget->assemblyRegisterFormat()); dlg.setAssemblyDisassemblyMode(gdbWidget->assemblyDisassemblyMode(), gdbWidget->assemblyDisassemblyBytes()); dlg.setKeySettings(keySettings()); dlg.setRRProgram(gdbWidget->rrProgram()); dlg.setRRArguments(gdbWidget->rrArguments()); dlg.setRRGdbArguments(gdbWidget->rrGdbArguments()); int ret = dlg.exec(); if (ret == 0) { return; } // Update the GdbWidget with the new settings. gdbWidget->setConsoleMode(dlg.seerConsoleMode()); gdbWidget->setConsoleScrollLines(dlg.seerConsoleScrollLines()); gdbWidget->setRememberManualCommandCount(dlg.seerRememberManualCommandCount()); gdbWidget->setGdbLauncher(dlg.gdbLauncher()); gdbWidget->setGdbProgram(dlg.gdbProgram()); gdbWidget->setGdbArguments(dlg.gdbArguments()); gdbWidget->setGdbAsyncMode(dlg.gdbAsyncMode()); gdbWidget->setGdbNonStopMode(dlg.gdbNonStopMode()); gdbWidget->setGdbHandleTerminatingException(dlg.gdbHandleTerminatingException()); gdbWidget->setGdbRandomizeStartAddress(dlg.gdbRandomizeStartAddress()); gdbWidget->setGdbEnablePrettyPrinting(dlg.gdbEnablePrettyPrinting()); gdbWidget->setGdbRemoteTargetType(dlg.gdbRemoteTargetType()); gdbWidget->setGdbArchitectureType(dlg.gdbArchitectureType()); gdbWidget->editorManager()->setEditorFont(dlg.editorFont()); gdbWidget->editorManager()->setEditorTabSize(dlg.editorTabSize()); gdbWidget->editorManager()->setEditorHighlighterSettings(dlg.editorHighlighterSettings()); gdbWidget->editorManager()->setEditorHighlighterEnabled(dlg.editorHighlighterEnabled()); gdbWidget->editorManager()->setEditorMinimapEnabled(dlg.editorMinimapEnabled()); gdbWidget->editorManager()->setEditorExternalEditorCommand(dlg.externalEditorCommand()); gdbWidget->editorManager()->setEditorAutoSourceReload(dlg.editorAutoSourceReload()); gdbWidget->setSourceAlternateDirectories(dlg.sourceAlternateDirectories()); gdbWidget->setSourceIgnoreFilePatterns(dlg.sourceIgnoreFilePatterns()); gdbWidget->setSourceMiscFilePatterns(dlg.sourceMiscFilePatterns()); gdbWidget->setSourceSourceFilePatterns(dlg.sourceSourceFilePatterns()); gdbWidget->setSourceHeaderFilePatterns(dlg.sourceHeaderFilePatterns()); gdbWidget->setAssemblyShowAssemblyTabOnStartupMode(dlg.assemblyShowAssemblyTabOnStartupMode()); gdbWidget->setAssemblyKeepAssemblyTabOnTop(dlg.assemblyKeepAssemblyTabOnTop()); gdbWidget->setAssemblyDisassemblyFlavor(dlg.assemblyDisassemblyFlavor()); gdbWidget->setAssemblySymbolDemagling(dlg.assemblySymbolDemagling()); gdbWidget->setAssemblyShowAddressColumn(dlg.assemblyShowAddressColumn()); gdbWidget->setAssemblyShowOffsetColumn(dlg.assemblyShowOffsetColumn()); gdbWidget->setAssemblyShowOpcodeColumn(dlg.assemblyShowOpcodeColumn()); gdbWidget->setAssemblyShowSourceLines(dlg.assemblyShowSourceLines()); gdbWidget->setAssemblyRegisterFormat(dlg.assemblyRegisterFormat()); gdbWidget->setAssemblyDisassemblyMode(dlg.assemblyDisassemblyMode(), dlg.assemblyDisassemblyBytes()); gdbWidget->setRRProgram(dlg.rrProgram()); gdbWidget->setRRArguments(dlg.rrArguments()); gdbWidget->setRRGdbArguments(dlg.rrGdbArguments()); // Clear history, if we need to. bool clearManualCommandHistory = dlg.seerClearManualCommandHistory(); if (clearManualCommandHistory) { gdbWidget->clearManualCommandHistory(); } // Set the key shortcuts. setKeySettings(dlg.keySettings()); } void SeerMainWindow::handleSettingsSaveConfiguration () { writeConfigSettings(); gdbWidget->writeSettings(); QMessageBox m(QMessageBox::Information, "Seer", "Configuration saved!"); m.setStandardButtons(QMessageBox::NoButton); QTimer::singleShot(1000, &m, SLOT(hide())); m.exec(); } void SeerMainWindow::handleHelpAbout () { SeerAboutDialog dlg(this); dlg.exec(); } void SeerMainWindow::handleTerminateExecutable () { if (gdbWidget->isGdbRuning() == true) { QSettings settings; bool prompt = true; settings.beginGroup("mainwindow"); { prompt = settings.value("promptterminate", prompt).toBool(); } settings.endGroup(); if (prompt) { QMessageBox msgBox(this); msgBox.setWindowTitle("Seer"); msgBox.setText("Terminate current session?"); msgBox.setIcon(QMessageBox::Question); // Add "Don't ask again" checkbox QCheckBox* dontAskAgainBox = new QCheckBox("Don't ask again", &msgBox); msgBox.setCheckBox(dontAskAgainBox); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Ok); int result = msgBox.exec(); // Save preference if checked if (dontAskAgainBox->isChecked()) { settings.beginGroup("mainwindow"); { settings.setValue("promptterminate", false); } settings.endGroup(); } if (result == QMessageBox::Cancel) { return; } } gdbWidget->handleGdbTerminateExecutable(false); } } void SeerMainWindow::handleRestartExecutable () { // Prompt if there's already a gdb running. if (gdbWidget->isGdbRuning() == true) { QSettings settings; bool prompt = true; settings.beginGroup("mainwindow"); { prompt = settings.value("promptrestart", prompt).toBool(); } settings.endGroup(); if (prompt) { // This QMessageBox with a checkbox and load/save from QSettings // is begging for a helper object! QMessageBox msgBox(this); msgBox.setWindowTitle("Seer"); msgBox.setText("Restart current session?"); msgBox.setIcon(QMessageBox::Question); // Add "Don't ask again" checkbox QCheckBox* dontAskAgainBox = new QCheckBox("Don't ask again", &msgBox); msgBox.setCheckBox(dontAskAgainBox); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Ok); int result = msgBox.exec(); // Save preference if checked if (dontAskAgainBox->isChecked()) { settings.beginGroup("mainwindow"); { settings.setValue("promptrestart", false); } settings.endGroup(); } if (result == QMessageBox::Cancel) { return; } } } if (gdbWidget->isGdbRuning() == true) { gdbWidget->handleGdbTerminateExecutable(false); } if (gdbWidget->isGdbRuning() == false && gdbWidget->hasBackupLaunchMode()) { gdbWidget->restoreLaunchMode(); } if (gdbWidget->executableLaunchMode() == "run" || gdbWidget->executableLaunchMode() == "start") { QString breakfunction = gdbWidget->executableBreakpointFunctionName(); QString breaksource = gdbWidget->executableBreakpointSourceName(); bool firstinstruction = gdbWidget->executableBreakpointFirstInstruction(); // Stop in function? if (breakfunction != "") { gdbWidget->handleGdbRunExecutable("infunction", true); // Stop at source:line? }else if (breaksource != "") { gdbWidget->handleGdbRunExecutable("insource", true); // Stop at first instruction? }else if (firstinstruction == true) { gdbWidget->handleGdbRunExecutable("firstinstruction", true); // Otherwise, attempt to stop in "main". }else{ gdbWidget->handleGdbRunExecutable("inmain", true); } }else if (gdbWidget->executableLaunchMode() == "attach") { gdbWidget->handleGdbAttachExecutable(true); }else if (gdbWidget->executableLaunchMode() == "connect") { gdbWidget->handleGdbConnectExecutable(true); }else if (gdbWidget->executableLaunchMode() == "rr") { gdbWidget->handleGdbRRExecutable(true); }else if (gdbWidget->executableLaunchMode() == "corefile") { gdbWidget->handleGdbCoreFileExecutable(); }else{ qDebug() << "UNKNOWN launch mode:" << gdbWidget->executableLaunchMode(); } } void SeerMainWindow::handleThemeStyleMenuChanged () { QAction* action = _themeStyleMenuActionGroup->checkedAction(); if (action == 0) { return; } setStyleName(action->text()); } void SeerMainWindow::handleIconColorMenuChanged () { QAction* action = _iconColorMenuActionGroup->checkedAction(); if (action == 0) { return; } setIconColorTheme(action->text()); } void SeerMainWindow::handleShowMessage (QString message, int time) { statusBar()->showMessage(message, time); } void SeerMainWindow::handleGdbStateChanged () { // qDebug() << "MODE:" << gdbWidget->executableLaunchMode() << "GDBRUNNING:" << gdbWidget->isGdbRuning() << "HASBACKUPLAUNCH:" << gdbWidget->hasBackupLaunchMode(); // // We are currently debugging a program. Allow for Terminate/Detach/Disconnect... // // mode: "run" gdbrunning: true hasbackuplaunch: false // terminate: show debug: hide retart: hide // // mode: "run" gdbrunning: true hasbackuplaunch: true // terminate: show debug: hide retart: hide // if (gdbWidget->executableLaunchMode() != "" && gdbWidget->isGdbRuning() == true) { // Launch and Restart. Applies to all. actionGdbLaunch->setVisible(false); actionGdbRestart->setVisible(true); actionControlRestart->setVisible(true); actionControlTerminate->setVisible(true); // Get the hotkey for the Terminate button. QString hotkey = ""; if (_keySettings.has("Terminate")) { SeerKeySetting setting = _keySettings.get("Terminate"); hotkey = " (" + setting._sequence.toString() + ")"; } // Run mode if (gdbWidget->executableLaunchMode() == "run" || gdbWidget->executableLaunchMode() == "start" || gdbWidget->executableLaunchMode() == "rr" || gdbWidget->executableLaunchMode() == "corefile") { // Terminate actionGdbTerminate->setVisible(true); actionGdbTerminate->setText("Terminate" + hotkey); actionGdbTerminate->setToolTip("Terminate the current debugging session."); actionControlTerminate->setText("Terminate"); actionControlTerminate->setToolTip("Terminate the current debugging session."); // Attach mode }else if (gdbWidget->executableLaunchMode() == "attach") { // Detach actionGdbTerminate->setVisible(true); actionGdbTerminate->setText("Detach" + hotkey); actionGdbTerminate->setToolTip("Detach from the current debugging session."); actionControlTerminate->setText("Detach"); actionControlTerminate->setToolTip("Detach from the current debugging session."); // Connect mode }else if (gdbWidget->executableLaunchMode() == "connect") { // Disconnect actionGdbTerminate->setVisible(true); actionGdbTerminate->setText("Disconnect" + hotkey); actionGdbTerminate->setToolTip("Disconnect from the current debugging session."); actionControlTerminate->setText("Disconnect"); actionControlTerminate->setToolTip("Disconnect from the current debugging session."); }else{ qDebug() << "UNKNOWN launch mode:" << gdbWidget->executableLaunchMode(); } return; } // // We are debugging a program but gdb has been killed. Allow for Launch and for Restart/Reattach/Reconnect... // // mode: "" gdbrunning: false hasbackuplaunch: true // terminate: hide debug: show retart: show // if (gdbWidget->executableLaunchMode() == "" && gdbWidget->isGdbRuning() == false && gdbWidget->hasBackupLaunchMode() == true) { // Allow a new debugging session. actionGdbLaunch->setVisible(true); actionGdbLaunch->setToolTip("Start a new debugging session."); // Hide terminate. Applies to all. actionGdbTerminate->setVisible(false); actionControlRestart->setVisible(true); actionControlTerminate->setVisible(true); // Get the hotkey for the Restart button. QString hotkey = ""; if (_keySettings.has("Restart")) { SeerKeySetting setting = _keySettings.get("Restart"); hotkey = " (" + setting._sequence.toString() + ")"; } // Run mode if (gdbWidget->backupLaunchMode() == "run" || gdbWidget->backupLaunchMode() == "start" || gdbWidget->backupLaunchMode() == "rr" || gdbWidget->backupLaunchMode() == "corefile") { // Restart actionGdbRestart->setVisible(true); actionGdbRestart->setText("Restart" + hotkey); actionGdbRestart->setToolTip("Restart the current debugging session."); actionControlRestart->setText("Restart"); actionControlRestart->setToolTip("Restart the current debugging session."); // Attach mode }else if (gdbWidget->backupLaunchMode() == "attach") { // Reattach actionGdbRestart->setVisible(true); actionGdbRestart->setText("Reattach" + hotkey); actionGdbRestart->setToolTip("Reattach the current debugging session."); actionControlRestart->setText("Reattach"); actionControlRestart->setToolTip("Reattach the current debugging session."); // Connect mode }else if (gdbWidget->backupLaunchMode() == "connect") { // Reconnect actionGdbRestart->setVisible(true); actionGdbRestart->setText("Reconnect" + hotkey); actionGdbRestart->setToolTip("Reconnect the current debugging session."); actionControlRestart->setText("Reconnect"); actionControlRestart->setToolTip("Reconnect the current debugging session."); }else{ qDebug() << "UNKNOWN launch mode:" << gdbWidget->backupLaunchMode(); } return; } qDebug() << "BAD STATE!"; } void SeerMainWindow::handleText (const QString& text) { if (text.startsWith("^error,msg=") || text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // ^error,msg="The program is not being run." // ^error,msg="ptrace: No such process." // 3^error,msg="Undefined MI command: symbol-info-variables",code="undefined-command" // 5^error,msg="No symbol "delta" in current context." // 5^error,msg="A syntax error in expression, near `'." QString newtext = Seer::filterEscapes(text); // Filter escaped characters. // Filter out less important errors. if (newtext.contains("^error,msg=\"No registers.\"")) { return; } if (newtext.contains("^error,msg=\"Selected thread is running.\"")) { return; } if (newtext.contains("^error,msg=\"Cannot inspect Ada tasks when program is not running\"")) { return; } if (newtext.contains("^error,msg=\"The current thread has terminated\"")) { return; } if (newtext.contains("^error,msg=\"A syntax error in expression, near ")) { return; } if (newtext.contains("^error,msg=\"No symbol \"")) { return; } // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); if (msg_text == "") { return; } // Show error on status bar. handleShowMessage(Seer::filterBookends(msg_text, '"', '"'), 3000); // Break early for certain errors. if (msg_text == "No symbol \"disassembly\" in current context.") { return; } if (msg_text == "\"-data-disassemble: No function contains specified address\"") { return; } if (msg_text == "\"No symbol \"disassembly\" in current context.\"") { return; } if (msg_text.startsWith("\"A syntax error in expression, near")) { return; } if (msg_text.startsWith("\"Invalid character ")) { return; } if (msg_text.startsWith("\"No symbol ")) { return; } if (msg_text.startsWith("\"Problem parsing arguments: data-evaluate-expression")) { return; } if (msg_text == "\"Attempt to use a type name as an expression\"") { return; } gdbWidget->addMessage(Seer::filterEscapes(msg_text), QMessageBox::Warning); return; }else if (text == "^running") { // Swallow this message. return; }else if (text == "^done") { return; }else if (text.startsWith("^done,files=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,shared-libraries=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,stack=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,variables=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,stack-args=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,bkpt={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,hw-awpt={")) { return; }else if (text.startsWith("^done,hw-rwpt={")) { return; }else if (text.startsWith("^done,wpt={")) { return; }else if (text.startsWith("^done,thread-ids={")) { return; }else if (text.startsWith("^done,new-thread-id=")) { return; }else if (text.startsWith("^done,threads=[")) { return; }else if (text.startsWith("^done,groups=[")) { return; }else if (text.startsWith("^done,register-names=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,register-values=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,DataExpressionAdded={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,DataExpressionDeleted={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,DataExpressionTable={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,symbols={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,asm_insns=[")) { return; }else if (text.startsWith("^done,ada-exceptions={") && text.endsWith("}")) { return; }else if (text.startsWith("^done,skips=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,signal-values=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,signal-names=[") && text.endsWith("]")) { return; }else if (text.startsWith("^done,checkpoints=[") && text.endsWith("]")) { return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done"))) { return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { return; }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) { return; }else if (text == "^exit") { return; }else if (text.startsWith("*running,thread-id=\"")) { QString threadid_text = Seer::parseFirst(text, "thread-id=", '"', '"', false); handleShowMessage("Program started. Thread id: " + threadid_text, 3000); return; }else if (text == "^connected") { //^connected return; }else if (text.startsWith("^connected,frame=")) { //^connected,frame={level=\"0\",addr=\"0x00007f48351f80c1\",func=\"read\",args=[],from=\"/lib64/libc.so.6\",arch=\"i386:x86-64\"}" return; }else if (text.startsWith("*stopped")) { QString reason_text = Seer::parseFirst(text, "reason=", '"', '"', false); if (reason_text == "") { reason_text = "unknown"; } handleShowMessage("Program stopped. Reason: " + reason_text, 3000); if (reason_text == "signal-received") { //*stopped,reason="signal-received",signal-name="SIGSEGV",signal-meaning="Segmentation fault", ... QString signalname_text = Seer::parseFirst(text, "signal-name=", '"', '"', false); gdbWidget->addMessage("Program encountered a '" + signalname_text + "' signal.", QMessageBox::Warning); }else if (reason_text == "breakpoint-hit") { QString bkptno_text = Seer::parseFirst(text, "bkptno=", '"', '"', false); QString disp_text = Seer::parseFirst(text, "disp=", '"', '"', false); if (disp_text == "del") { gdbWidget->addMessage("Program reached temporary breakpoint '" + bkptno_text + "'.", QMessageBox::Information); }else{ gdbWidget->addMessage("Program reached breakpoint '" + bkptno_text + "'.", QMessageBox::Information); } }else if (reason_text == "watchpoint-trigger") { //*stopped,reason="watchpoint-trigger",wpt={number="3",exp="i"},value={old="32767",new="42"},frame={addr="0x0000000000400d79",func="function1",args=[{name="text",value="\"Hello, World!\""}],file="function1.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp",line="9",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="0" QString wpt_text = Seer::parseFirst(text, "wpt=", '{', '}', false); QString number_text = Seer::parseFirst(wpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(wpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString old_text = Seer::parseFirst(value_text, "old=", '"', '"', false); QString new_text = Seer::parseFirst(value_text, "new=", '"', '"', false); gdbWidget->addMessage(QString("Watchpoint triggered.\n\nNumber: %1\nExpression: %2\nOld value: %3\nNew value: %4").arg(number_text).arg(exp_text).arg(old_text).arg(new_text), QMessageBox::Information); }else if (reason_text == "read-watchpoint-trigger") { //*stopped,reason="read-watchpoint-trigger",hw-rwpt={number="5",exp="i"},value={value="42"},frame={addr="0x0000000000400d9a",func="function1",args=[{name="text",value="\"Hello, World!\""}],file="function1.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp",line="11",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="4" QString hwwpt_text = Seer::parseFirst(text, "hw-rwpt=", '{', '}', false); QString number_text = Seer::parseFirst(hwwpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(hwwpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString value_text2 = Seer::parseFirst(value_text, "value=", '"', '"', false); gdbWidget->addMessage(QString("Watchpoint triggered.\n\nNumber: %1\nExpression: %2\nValue: %3").arg(number_text).arg(exp_text).arg(value_text2), QMessageBox::Information); }else if (reason_text == "access-watchpoint-trigger") { //*stopped,reason="access-watchpoint-trigger",hw-awpt={number="3",exp="v"},value={old="1",new="11"},frame={addr="0x000000000040059a",func="bar",args=[{name="v",value="11"}],file="helloonefile.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloonefile/helloonefile.cpp",line="15",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="3" QString hwawpt_text = Seer::parseFirst(text, "hw-awpt=", '{', '}', false); QString number_text = Seer::parseFirst(hwawpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(hwawpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString old_text = Seer::parseFirst(value_text, "old=", '"', '"', false); QString new_text = Seer::parseFirst(value_text, "new=", '"', '"', false); gdbWidget->addMessage(QString("Watchpoint triggered.\n\nNumber: %1\nExpression: %2\nOld value: %3\nNew value: %4").arg(number_text).arg(exp_text).arg(old_text).arg(new_text), QMessageBox::Information); }else if (reason_text == "watchpoint-scope") { //*stopped,reason="watchpoint-scope",wpnum="5", frame={func="callee3",args=[{name="strarg", value="0x11940 \"A string argument.\""}], file="../../../devo/gdb/testsuite/gdb.mi/basics.c", fullname="/home/foo/bar/devo/gdb/testsuite/gdb.mi/basics.c",line="18"} QString wpnum_text = Seer::parseFirst(text, "wpnum=", '"', '"', false); gdbWidget->addMessage(QString("Watchpoint went out of scope. Will be deleted.\n\nNumber: %1").arg(wpnum_text), QMessageBox::Information); }else if (reason_text == "exited-normally") { //*stopped,reason="exited-normally" gdbWidget->addMessage("Program exited normally.", QMessageBox::Information); }else if (reason_text == "exited") { //*stopped,reason="exited",exit-code="01" QString exitcode_text = Seer::parseFirst(text, "exit-code=", '"', '"', false); gdbWidget->addMessage("Program exited with code '" + exitcode_text +"'", QMessageBox::Information); }else if (reason_text == "exited-signalled") { //*stopped,reason="exited-signalled",signal-name="SIGSEGV",signal-meaning="Segmentation fault" QString signalname_text = Seer::parseFirst(text, "signal-name=", '"', '"', false); gdbWidget->addMessage("Program exited abnormally.\nIt encountered a '" + signalname_text + "' signal.", QMessageBox::Warning); }else if (reason_text == "unknown") { // Don't bother showing this. // Attaching to a pid will generate an unknown *stopped message that is useless. // qDebug() << "Text=" << text; // qDebug() << "Reason=" << reason_text; // gdbWidget->addMessage("Program encountered an unknown problem. See the Gdb output tab for messages.", QMessageBox::Warning); } return; }else if (text.startsWith("=thread-group-started,")) { // =thread-group-started,id="i1",pid="30916" QString pid_text = Seer::parseFirst(text, "pid=", '"', '"', false); //qDebug() << "Inferior pid = " << pid_text; gdbWidget->addMessage("Program started. (pid=" + pid_text +")", QMessageBox::Information); return; }else if (text.startsWith("=")) { // Suppress all other '=' messages. return; } // Leave in for stray error messages. qDebug() << text; } void SeerMainWindow::handleRunStatusChanged (SeerRunStatusIndicator::RunStatus status) { if (status == SeerRunStatusIndicator::RunStatus::Idle) { _progressIndicator->stop(); }else if (status == SeerRunStatusIndicator::RunStatus::Stopped) { _progressIndicator->stop(); }else if (status == SeerRunStatusIndicator::RunStatus::Running) { _progressIndicator->start(); }else{ _progressIndicator->stop(); } } void SeerMainWindow::handleRecordSettingsChanged () { if (gdbWidget->gdbRecordMode() == "stop" || gdbWidget->gdbRecordMode() == "") { // Menu Control actionControlRecordStart->setEnabled(true); actionControlRecordStop->setEnabled(false); actionControlRecordForward->setEnabled(false); actionControlRecordReverse->setEnabled(false); actionControlRecordForward->setChecked(false); actionControlRecordReverse->setChecked(false); actionControlReverseContinue->setEnabled(false); actionControlReverseNext->setEnabled(false); actionControlReverseStep->setEnabled(false); actionControlReverseFinish->setEnabled(false); actionControlReverseNexti->setEnabled(false); actionControlReverseStepi->setEnabled(false); // Toolbar actionRecordProcess->setText("Record"); actionRecordProcess->setToolTip("Toggle Record mode."); actionRecordProcess->setEnabled(true); actionRecordDirection->setEnabled(false); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); }else if (gdbWidget->gdbRecordMode() == "full") { // Menu Control actionControlRecordStart->setEnabled(false); actionControlRecordStop->setEnabled(true); actionControlRecordForward->setEnabled(true); actionControlRecordReverse->setEnabled(true); actionControlReverseContinue->setEnabled(true); actionControlReverseNext->setEnabled(true); actionControlReverseStep->setEnabled(true); actionControlReverseFinish->setEnabled(true); actionControlReverseNexti->setEnabled(true); actionControlReverseStepi->setEnabled(true); if (gdbWidget->gdbRecordDirection() == "") { actionControlRecordForward->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); }else if (gdbWidget->gdbRecordDirection() == "--reverse") { actionControlRecordReverse->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-previous.svg")); }else{ actionControlRecordForward->setChecked(false); actionControlRecordReverse->setChecked(false); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); qDebug() << "Bad record direction of '" << gdbWidget->gdbRecordDirection() << "'"; } // Toolbar actionRecordProcess->setText("Recording"); actionRecordProcess->setToolTip("Toggle Record mode."); actionRecordProcess->setEnabled(true); actionRecordDirection->setEnabled(true); }else if (gdbWidget->gdbRecordMode() == "rr") { // Menu Control actionControlRecordStart->setEnabled(false); actionControlRecordStop->setEnabled(false); actionControlRecordForward->setEnabled(true); actionControlRecordReverse->setEnabled(true); actionControlReverseContinue->setEnabled(true); actionControlReverseNext->setEnabled(true); actionControlReverseStep->setEnabled(true); actionControlReverseFinish->setEnabled(true); actionControlReverseNexti->setEnabled(true); actionControlReverseStepi->setEnabled(true); if (gdbWidget->gdbRecordDirection() == "") { actionControlRecordForward->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); }else if (gdbWidget->gdbRecordDirection() == "--reverse") { actionControlRecordReverse->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-previous.svg")); }else{ actionControlRecordForward->setChecked(false); actionControlRecordReverse->setChecked(false); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); qDebug() << "Bad record direction of '" << gdbWidget->gdbRecordDirection() << "'"; } // Toolbar actionRecordProcess->setText("RR"); actionRecordProcess->setToolTip("Using RR debugger."); actionRecordProcess->setEnabled(true); actionRecordDirection->setEnabled(true); }else if (gdbWidget->gdbRecordMode() == "udb") { // Menu Control actionControlRecordStart->setEnabled(false); actionControlRecordStop->setEnabled(false); actionControlRecordForward->setEnabled(true); actionControlRecordReverse->setEnabled(true); actionControlReverseContinue->setEnabled(true); actionControlReverseNext->setEnabled(true); actionControlReverseStep->setEnabled(true); actionControlReverseFinish->setEnabled(true); actionControlReverseNexti->setEnabled(true); actionControlReverseStepi->setEnabled(true); if (gdbWidget->gdbRecordDirection() == "") { actionControlRecordForward->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); }else if (gdbWidget->gdbRecordDirection() == "--reverse") { actionControlRecordReverse->setChecked(true); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-previous.svg")); }else{ actionControlRecordForward->setChecked(false); actionControlRecordReverse->setChecked(false); actionRecordDirection->setIcon(QIcon(":/seer/resources/RelaxLightIcons/go-next.svg")); qDebug() << "Bad record direction of '" << gdbWidget->gdbRecordDirection() << "'"; } // Toolbar actionRecordProcess->setText("UDB"); actionRecordProcess->setToolTip("Using UDB debugger."); actionRecordProcess->setEnabled(true); actionRecordDirection->setEnabled(true); }else{ qDebug() << "Bad record mode of:" << gdbWidget->gdbRecordMode(); } } void SeerMainWindow::handleChangeWindowTitle (QString title) { if (title == "") { setWindowTitle("Seer Debugger"); }else{ setWindowTitle("Seer Debugger - '" + title + "'"); } } void SeerMainWindow::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/MainWindow.md"); help->show(); help->raise(); } void SeerMainWindow::writeSettings() { QSettings settings; settings.beginGroup("mainwindow"); { settings.setValue("size", size()); } settings.endGroup(); } void SeerMainWindow::readSettings() { QSettings settings; settings.beginGroup("mainwindow"); { resize(settings.value("size", QSize(1250, 1000)).toSize()); } settings.endGroup(); } void SeerMainWindow::writeConfigSettings () { QSettings settings; settings.beginGroup("mainwindow"); { settings.setValue("qtstyle", styleName()); settings.setValue("iconcolortheme", iconColorTheme()); } settings.endGroup(); settings.beginGroup("gdb"); { settings.setValue("launcher", gdbWidget->gdbLauncher()); settings.setValue("program", gdbWidget->gdbProgram()); settings.setValue("arguments", gdbWidget->gdbArguments()); settings.setValue("asyncmode", gdbWidget->gdbAsyncMode()); settings.setValue("nonstopmode", gdbWidget->gdbNonStopMode()); settings.setValue("handleterminatingexception", gdbWidget->gdbHandleTerminatingException()); settings.setValue("randomizestartaddress", gdbWidget->gdbRandomizeStartAddress()); settings.setValue("enableprettyprinting", gdbWidget->gdbEnablePrettyPrinting()); settings.setValue("remotetargettype", gdbWidget->gdbRemoteTargetType()); settings.setValue("architecturetype", gdbWidget->gdbArchitectureType()); } settings.endGroup(); settings.beginGroup("rr"); { settings.setValue("program", gdbWidget->rrProgram()); settings.setValue("arguments", gdbWidget->rrArguments()); settings.setValue("gdbarguments", gdbWidget->rrGdbArguments()); } settings.endGroup(); settings.beginGroup("editor"); { settings.setValue("font", gdbWidget->editorManager()->editorFont().toString()); settings.setValue("tabsize", gdbWidget->editorManager()->editorTabSize()); settings.setValue("externaleditorcommand", gdbWidget->editorManager()->editorExternalEditorCommand()); settings.setValue("autosourcereload", gdbWidget->editorManager()->editorAutoSourceReload()); settings.setValue("minimapenabled", gdbWidget->editorManager()->editorMinimapEnabled()); settings.beginGroup("highlighter"); { settings.setValue("enabled", gdbWidget->editorManager()->editorHighlighterEnabled()); SeerHighlighterSettings highlighter = gdbWidget->editorManager()->editorHighlighterSettings(); QStringList keys = highlighter.keys(); for (int i=0; irememberManualCommandCount()); } settings.endGroup(); settings.beginWriteArray("shortcuts"); { SeerKeySettings keysettings = keySettings(); QStringList keys = keysettings.keys(); for (int i=0; isetGdbLauncher(settings.value("launcher", STRINGIFY(SEER_GDB_LAUNCHER)).toString()); #else gdbWidget->setGdbLauncher(settings.value("launcher", "").toString()); #endif #ifdef SEER_GDB_NAME gdbWidget->setGdbProgram(settings.value("program", STRINGIFY(SEER_GDB_NAME)).toString()); #else gdbWidget->setGdbProgram(settings.value("program", "/usr/bin/gdb").toString()); #endif gdbWidget->setGdbArguments(settings.value("arguments", "--interpreter=mi").toString()); gdbWidget->setGdbAsyncMode(settings.value("asyncmode", true).toBool()); gdbWidget->setGdbNonStopMode(settings.value("nonstopmode", false).toBool()); gdbWidget->setGdbHandleTerminatingException(settings.value("handleterminatingexception", true).toBool()); gdbWidget->setGdbRandomizeStartAddress(settings.value("randomizestartaddress", false).toBool()); gdbWidget->setGdbEnablePrettyPrinting(settings.value("enableprettyprinting", true).toBool()); gdbWidget->setGdbRemoteTargetType(settings.value("remotetargettype", "extended-remote").toString()); gdbWidget->setGdbArchitectureType(settings.value("architecturetype", "auto").toString()); } settings.endGroup(); settings.beginGroup("rr"); { gdbWidget->setRRProgram(settings.value("program", "/usr/bin/rr").toString()); gdbWidget->setRRArguments(settings.value("arguments", "replay --interpreter=mi").toString()); gdbWidget->setRRGdbArguments(settings.value("gdbarguments", "").toString()); } settings.endGroup(); settings.beginGroup("editor"); { QFont f; if (settings.contains("font")) { f.fromString(settings.value("font").toString()); }else{ f = QFont("monospace", 10); } gdbWidget->editorManager()->setEditorFont(f); gdbWidget->editorManager()->setEditorTabSize(settings.value("tabsize", 4).toInt()); gdbWidget->editorManager()->setEditorExternalEditorCommand(settings.value("externaleditorcommand").toString()); gdbWidget->editorManager()->setEditorAutoSourceReload(settings.value("autosourcereload").toBool()); gdbWidget->editorManager()->setEditorMinimapEnabled(settings.value("minimapenabled",false).toBool()); settings.beginGroup("highlighter"); { gdbWidget->editorManager()->setEditorHighlighterEnabled(settings.value("enabled",true).toBool()); SeerHighlighterSettings highlighter = gdbWidget->editorManager()->editorHighlighterSettings(); QStringList keys = highlighter.keys(); for (int i=0; i()); } if (settings.contains("backgroundcolor")) { f.setBackground(settings.value("backgroundcolor").value()); } highlighter.add(keys[i], f); } settings.endGroup(); } if (settings.contains("cppsuffixes")) highlighter.setCppSourceSuffixes(settings.value("cppsuffixes").toString()); if (settings.contains("odinsuffixes")) highlighter.setOdinSourceSuffixes(settings.value("odinsuffixes").toString()); if (settings.contains("rustsuffixes")) highlighter.setRustSourceSuffixes(settings.value("rustsuffixes").toString()); if (settings.contains("adasuffixes")) highlighter.setAdaSourceSuffixes(settings.value("adasuffixes").toString()); if (settings.contains("fortransuffixes")) highlighter.setFortranSourceSuffixes(settings.value("fortransuffixes").toString()); gdbWidget->editorManager()->setEditorHighlighterSettings(highlighter); } settings.endGroup(); } settings.endGroup(); settings.beginGroup("manualgdbcommands"); { gdbWidget->setRememberManualCommandCount(settings.value("remembercount", 10).toInt()); } settings.endGroup(); int size = settings.beginReadArray("shortcuts"); { SeerKeySettings keysettings = keySettings(); // Start with defaults. The add() will overwrite. for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); QString name = settings.value("action").toString(); QKeySequence key = QKeySequence::fromString(settings.value("key").toString()); QString help = settings.value("help").toString(); keysettings.add(name, SeerKeySetting(name, key, help)); } setKeySettings(keysettings); } settings.endArray(); } void SeerMainWindow::resizeEvent (QResizeEvent* event) { // Write window settings. writeSettings(); QMainWindow::resizeEvent(event); } void SeerMainWindow::closeEvent (QCloseEvent* event) { event->accept(); QCoreApplication::exit(0); } void SeerMainWindow::setKeySettings (const SeerKeySettings& settings) { _keySettings = settings; refreshShortCuts(); } const SeerKeySettings SeerMainWindow::keySettings () const { return _keySettings; } void SeerMainWindow::refreshShortCuts () { // Dynamically change tool tip for 'Restart' depending on debug mode. if (_keySettings.has("Restart")) { SeerKeySetting setting = _keySettings.get("Restart"); actionGdbRestart->setToolTip(setting._description); actionGdbRestart->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlRestart->setShortcut(setting._sequence); } if (_keySettings.has("Terminate")) { SeerKeySetting setting = _keySettings.get("Terminate"); actionGdbTerminate->setToolTip(setting._description); actionGdbTerminate->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlTerminate->setShortcut(setting._sequence); } if (_keySettings.has("Next")) { SeerKeySetting setting = _keySettings.get("Next"); actionGdbNext->setToolTip(setting._description); actionGdbNext->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlNext->setShortcut(setting._sequence); } if (_keySettings.has("Nexti")) { SeerKeySetting setting = _keySettings.get("Nexti"); actionGdbNexti->setToolTip(setting._description); actionGdbNexti->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlNexti->setShortcut(setting._sequence); } if (_keySettings.has("Step")) { SeerKeySetting setting = _keySettings.get("Step"); actionGdbStep->setToolTip(setting._description); actionGdbStep->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlStep->setShortcut(setting._sequence); } if (_keySettings.has("Stepi")) { SeerKeySetting setting = _keySettings.get("Stepi"); actionGdbStepi->setToolTip(setting._description); actionGdbStepi->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlStepi->setShortcut(setting._sequence); } if (_keySettings.has("Finish")) { SeerKeySetting setting = _keySettings.get("Finish"); actionGdbFinish->setToolTip(setting._description); actionGdbFinish->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlFinish->setShortcut(setting._sequence); } if (_keySettings.has("Continue")) { SeerKeySetting setting = _keySettings.get("Continue"); actionGdbContinue->setToolTip(setting._description); actionGdbContinue->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlContinue->setShortcut(setting._sequence); } if (_keySettings.has("ReverseNext")) { SeerKeySetting setting = _keySettings.get("ReverseNext"); actionControlReverseNext->setShortcut(setting._sequence); } if (_keySettings.has("ReverseNexti")) { SeerKeySetting setting = _keySettings.get("ReverseNexti"); actionControlReverseNexti->setShortcut(setting._sequence); } if (_keySettings.has("ReverseStep")) { SeerKeySetting setting = _keySettings.get("ReverseStep"); actionControlReverseStep->setShortcut(setting._sequence); } if (_keySettings.has("ReverseStepi")) { SeerKeySetting setting = _keySettings.get("ReverseStepi"); actionControlReverseStepi->setShortcut(setting._sequence); } if (_keySettings.has("ReverseFinish")) { SeerKeySetting setting = _keySettings.get("ReverseFinish"); actionControlReverseFinish->setShortcut(setting._sequence); } if (_keySettings.has("ReverseContinue")) { SeerKeySetting setting = _keySettings.get("ReverseContinue"); actionControlReverseContinue->setShortcut(setting._sequence); } if (_keySettings.has("Interrupt")) { SeerKeySetting setting = _keySettings.get("Interrupt"); _interruptAction->setText(setting._action + " (" + setting._sequence.toString() + ")"); actionControlInterrupt->setShortcut(setting._sequence); } if (_keySettings.has("Debug")) { SeerKeySetting setting = _keySettings.get("Debug"); actionFileDebug->setShortcut(setting._sequence); } if (_keySettings.has("Arguments")) { SeerKeySetting setting = _keySettings.get("Arguments"); actionFileArguments->setShortcut(setting._sequence); } if (_keySettings.has("Quit")) { SeerKeySetting setting = _keySettings.get("Quit"); actionFileQuit->setShortcut(setting._sequence); } if (_keySettings.has("ToggleRecordDirection")) { SeerKeySetting setting = _keySettings.get("ToggleRecordDirection"); actionRecordDirection->setText(QString("Direction") + " (" + setting._sequence.toString() + ")"); actionRecordDirection->setShortcut(setting._sequence); actionControlDirectionMenu->setTitle(QString("Direction") + " (Toggle " + setting._sequence.toString() + ")"); } if (_keySettings.has("RunToLine")) { SeerKeySetting setting = _keySettings.get("RunToLine"); actionControlRunToLine->setShortcut(setting._sequence); } // Notify the editor manager of changes. gdbWidget->editorManager()->setEditorKeySettings(keySettings()); } /*********************************************************************************************************************** * Change action button availability when status change **********************************************************************************************************************/ void SeerMainWindow::handleStatusChanged(QString message) { // target halt if (message.startsWith("*stopped,reason=") || message.startsWith("^done,stack=[frame=")) { handleGdbTargetInterrupt(); }else if (message.startsWith("*running")) { // target is running handleGdbTargetRunning(); } } // Disable some button while target is running void SeerMainWindow::handleGdbTargetRunning() { // Control Menu actionControlInterrupt->setEnabled(true); actionControlContinue->setEnabled(false); actionControlNext->setEnabled(false); actionControlStep->setEnabled(false); actionControlFinish->setEnabled(false); actionControlNexti->setEnabled(false); actionControlStepi->setEnabled(false); actionControlRunToLine->setEnabled(false); // Action buttons actionInterruptProcess->setEnabled(true); actionGdbContinue->setEnabled(false); actionGdbNext->setEnabled(false); actionGdbStep->setEnabled(false); actionGdbFinish->setEnabled(false); actionGdbNexti->setEnabled(false); actionGdbStepi->setEnabled(false); } // Enable some button while target is interrupted void SeerMainWindow::handleGdbTargetInterrupt() { // Control Menu actionControlInterrupt->setEnabled(false); actionControlContinue->setEnabled(true); actionControlNext->setEnabled(true); actionControlStep->setEnabled(true); actionControlFinish->setEnabled(true); actionControlNexti->setEnabled(true); actionControlStepi->setEnabled(true); actionControlRunToLine->setEnabled(true); // Action buttons actionInterruptProcess->setEnabled(false); actionGdbContinue->setEnabled(true); actionGdbNext->setEnabled(true); actionGdbStep->setEnabled(true); actionGdbFinish->setEnabled(true); actionGdbNexti->setEnabled(true); actionGdbStepi->setEnabled(true); } void SeerMainWindow::handleThemeChanged () { // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); } epasveer-seer-97076f1/src/SeerMainWindow.h000066400000000000000000000232671526321767600204310ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "ui_SeerMainWindow.h" #include "SeerRunStatusIndicator.h" #include "SeerKeySettings.h" #include "SeerProgressIndicator.h" #include #include #include #include #include #include #include class SeerMainWindow : public QMainWindow, protected Ui::SeerMainWindowForm { Q_OBJECT public: SeerMainWindow (QWidget* parent = 0); ~SeerMainWindow (); void setExecutableName (const QString& executableName); const QString& executableName () const; void setExecutableSymbolName (const QString& executableSymbolName); const QString& executableSymbolName () const; void setExecutableArguments (const QString& executableArguments); void setExecutableArguments (const QStringList& executableArguments); const QString& executableArguments () const; void setExecutableWorkingDirectory (const QString& executableWorkingDirectory); const QString& executableWorkingDirectory () const; void setExecutableBreakpointsFilename (const QString& breakpointsFilename); const QString& executableBreakpointsFilename () const; void setExecutableBreakpointFunctionName (const QString& nameoraddress); const QString& executableBreakpointFunctionName () const; void setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno); const QString& executableBreakpointSourceName () const; void setExecutableBreakpointFirstInstruction (bool flag); bool executableBreakpointFirstInstruction () const; void setExecutableShowAssemblyTabMode (const QString& mode); QString executableShowAssemblyTabMode () const; void setExecutableRandomizeStartAddress (bool flag); bool executableRandomizeStartAddress () const; void setExecutableNonStopMode (bool flag); bool executableNonStopMode () const; void setExecutablePid (int pid); int executablePid () const; void setExecutableConnectHostPort (const QString& executableConnectHostPort); const QString& executableConnectHostPort () const; void setExecutableConnectRemoteTargetType (const QString& type); QString executableConnectRemoteTargetType () const; void setExecutableConnectGdbserverDebug (bool enable); bool executableConnectGdbserverDebug () const; void setExecutableRRTraceDirectory (const QString& executableRRTraceDirectory); const QString& executableRRTraceDirectory () const; void setExecutableCoreFilename (const QString& executableCoreFilename); const QString& executableCoreFilename () const; void setExecutablePreGdbCommands (const QStringList& preGdbCommands); const QStringList& executablePreGdbCommands () const; void setExecutablePostGdbCommands (const QStringList& postGdbCommands); const QStringList& executablePostGdbCommands () const; void setProjectFilename (const QString& projectFilename); const QString& projectFilename () const; void setGdbProgramOverride (const QString& gdbProgram); QString gdbProgramOverride () const; void setGdbArgumentsOverride (const QString& gdbProgram); QString gdbArgumentsOverride () const; void launchExecutable (const QString& launchMode, const QString& breakMode); const QString& executableLaunchMode () const; const QString& executableBreakMode () const; void setStyleName (const QString& name); const QString& styleName (); void setIconColorTheme (const QString& theme); const QString& iconColorTheme (); private slots: void handleFileDebugWithDefaultProject (); void handleFileDebugWithOutDefaultProject (); void handleFileDebug (bool loadDefaultProject); void handleFileArguments (); void handleFileQuit (); void handleViewMemoryVisualizer (); void handleViewArrayVisualizer (); void handleViewMatrixVisualizer (); void handleViewStructVisualizer (); void handleViewVarVisualizer (); void handleViewImageVisualizer (); void handleViewParallelStacksVisualizer (); void handleViewGdbMonitor (); void handleViewAssembly (); void handleViewAssemblyShown (bool shown); void handleViewConsoleAttached (); void handleViewConsoleDetached (); void handleViewConsoleDetachedMinimized (); void handleSettingsConfiguration (); void handleSettingsSaveConfiguration (); void handleHelpAbout (); void handleText (const QString& text); void handleRunStatusChanged (SeerRunStatusIndicator::RunStatus status); void handleRecordSettingsChanged (); void handleChangeWindowTitle (QString title); void handleHelpToolButtonClicked (); void handleTerminateExecutable (); void handleRestartExecutable (); void handleThemeStyleMenuChanged (); void handleIconColorMenuChanged (); void handleShowMessage (QString message, int time); void handleGdbStateChanged (); void handleGdbTargetRunning (); void handleGdbTargetInterrupt (); void handleStatusChanged (QString message); void handleThemeChanged (); protected: void writeSettings (); void readSettings (); void writeConfigSettings (); void readConfigSettings (); void resizeEvent (QResizeEvent* event); void closeEvent (QCloseEvent* event); void setKeySettings (const SeerKeySettings& settings); const SeerKeySettings keySettings () const; void refreshShortCuts (); private: QActionGroup* _themeStyleMenuActionGroup; QActionGroup* _iconColorMenuActionGroup; QString _styleName; QAction* _interruptAction; SeerProgressIndicator* _progressIndicator; SeerKeySettings _keySettings; QString _projectFile; }; epasveer-seer-97076f1/src/SeerMainWindow.ui000066400000000000000000000740701526321767600206150ustar00rootroot00000000000000 SeerMainWindowForm 0 0 1206 726 Qt::NoContextMenu Seer Debugger 0 0 1206 23 File Edit View Console :/seer/resources/icons-icons/console.png:/seer/resources/icons-icons/console.png Theme Style :/seer/resources/icons-icons/style.png:/seer/resources/icons-icons/style.png Icon Theme :/seer/resources/icons-icons/style.png:/seer/resources/icons-icons/style.png Settings Help Control Set Record mode. Record :/seer/resources/RelaxLightIcons/tools-media-optical-burn-image.svg:/seer/resources/RelaxLightIcons/tools-media-optical-burn-image.svg Set Playback direction. Direction :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Reverse toolBar Qt::ToolButtonTextBesideIcon TopToolBarArea false :/seer/resources/icons-icons/exit.png:/seer/resources/icons-icons/exit.png Quit Quit Quit the Seer debugger. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg :/seer/resources/RelaxLightIcons/debug-step-over.svg:/seer/resources/RelaxLightIcons/debug-step-over.svg Next :/seer/resources/RelaxLightIcons/debug-step-into.svg:/seer/resources/RelaxLightIcons/debug-step-into.svg Step :/seer/resources/RelaxLightIcons/debug-step-out.svg:/seer/resources/RelaxLightIcons/debug-step-out.svg Finish :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Continue :/seer/resources/thenounproject/fortune-teller.svg:/seer/resources/thenounproject/fortune-teller.svg Debug... Debug Load an executable to debug. :/seer/resources/icons-icons/arguments.png:/seer/resources/icons-icons/arguments.png Arguments... Arguments Specify new arguments to the current executable. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Interrupt Send a 'Terminate' signal to the process.<br/><br/>Hold down for alternate signals. :/seer/resources/icons/hicolor/32x32/seergdb.png:/seer/resources/icons/hicolor/32x32/seergdb.png About Seer About Seer :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Memory Visualizer Launch a blank Memory Visualizer. :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Array Visualizer Launch a blank Array Visualizer. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Restart Restart the debugging session Restart the debugging session. Honor breakpoints, if any. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Continue Continue Continue executing the program. Stop at any breakpoints, or when the program exits. :/seer/resources/RelaxLightIcons/debug-step-over.svg:/seer/resources/RelaxLightIcons/debug-step-over.svg Next Next Execute next step, step over functions. :/seer/resources/RelaxLightIcons/debug-step-into.svg:/seer/resources/RelaxLightIcons/debug-step-into.svg Step Step Execute next step, step into functions. :/seer/resources/RelaxLightIcons/debug-step-out.svg:/seer/resources/RelaxLightIcons/debug-step-out.svg Finish Finish Execute the remaining function, stop after it exits. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Interrupt Interrupt Send a 'Terminate' signal to the process. :/seer/resources/thenounproject/configure.svg:/seer/resources/thenounproject/configure.svg Configuration... Configure Seer. :/seer/resources/RelaxLightIcons/document-save.svg:/seer/resources/RelaxLightIcons/document-save.svg Save Configuration... Save the configurations so future Seer sessions will use them. :/seer/resources/icons-icons/attach.png:/seer/resources/icons-icons/attach.png Attached Show the console window in Seer's tabs. Show the console window in Seer's tabs. :/seer/resources/icons-icons/maximize.png:/seer/resources/icons-icons/maximize.png Detached Detach the console into it's own window. Detach the console into it's own window. :/seer/resources/icons-icons/minimize.png:/seer/resources/icons-icons/minimize.png Detached Minimized Detach the console into it's own minimaize window. Detach the console into it's own minimaize window. :/seer/resources/RelaxLightIcons/debug-step-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-instruction.svg Nexti Execute next instruction, step over functions. :/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg Stepi Execute next instruction, step into functions. :/seer/resources/thenounproject/assembly.svg:/seer/resources/thenounproject/assembly.svg Assembly View View the program's assembly. :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Struct Visualizer Launch a blank Struct Visualizer. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Stop Stop Record mode. true :/seer/resources/RelaxLightIcons/go-previous.svg:/seer/resources/RelaxLightIcons/go-previous.svg Reverse Set Gdb Playback to reverse. :/seer/resources/RelaxLightIcons/tools-media-optical-burn-image.svg:/seer/resources/RelaxLightIcons/tools-media-optical-burn-image.svg Record Toggle Record mode. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Start Start Record mode. true :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Forward Set Gdb Playback to forward. :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Direction Toggle Playback direction. :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Image Visualizer Launch a blank Image Visualizer. :/seer/resources/RelaxLightIcons/debug-step-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-instruction.svg Nexti Nexti :/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg Stepi Stepi :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Visualizers Launch a Memory visualizer.<br/><br/>Hold down for alternate visualizers. :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg BasicStruct Visualizer Launch a blank BasicStruct Visualizer. Execution Messages View the program's execution messages. :/seer/resources/RelaxLightIcons/system-shutdown.svg:/seer/resources/RelaxLightIcons/system-shutdown.svg QAction::NoRole :/seer/resources/thenounproject/fortune-teller.svg:/seer/resources/thenounproject/fortune-teller.svg Debug Launch a debugging session. QAction::NoRole :/seer/resources/RelaxLightIcons/system-shutdown.svg:/seer/resources/RelaxLightIcons/system-shutdown.svg Terminate Terminate the debugging session Terminate the debugging session. QAction::NoRole :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Matrix Visualizer Launch a blank Matrix Visualizer. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Reverse Continue :/seer/resources/RelaxLightIcons/debug-step-over.svg:/seer/resources/RelaxLightIcons/debug-step-over.svg Reverse Next :/seer/resources/RelaxLightIcons/debug-step-into.svg:/seer/resources/RelaxLightIcons/debug-step-into.svg Reverse Step :/seer/resources/RelaxLightIcons/debug-step-out.svg:/seer/resources/RelaxLightIcons/debug-step-out.svg Reverse Finish :/seer/resources/RelaxLightIcons/debug-step-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-instruction.svg Reverse Nexti :/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg:/seer/resources/RelaxLightIcons/debug-step-into-instruction.svg Reverse Stepi :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg ParallelStacks Visualizer :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Run To Line Run to the currently selected line. Stop at any breakpoints, or when the program exits. QAction::NoRole :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg GDB Monitor SeerGdbWidget QWidget
SeerGdbWidget.h
1
epasveer-seer-97076f1/src/SeerMatrixVisualizerWidget.cpp000066400000000000000000000574051526321767600233770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMatrixVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include #include #include #include #include SeerMatrixVisualizerWidget::SeerMatrixVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _variableId = Seer::createID(); // Create id's for queries. _memoryId = Seer::createID(); _rowsId = Seer::createID(); _columnsId = Seer::createID(); _offsetId = Seer::createID(); _strideId = Seer::createID(); // Set up UI. setupUi(this); // Setup the widgets setWindowTitle("Seer Matrix Visualizer"); setAttribute(Qt::WA_DeleteOnClose); matrixDisplayFormatComboBox->setCurrentIndex(0); matrixStorageOrderComboBox->setCurrentIndex(0); handleMatrixDisplayFormatComboBox(0); handleMatrixStorageOrderComboBox(0); variableNameLineEdit->enableReturnPressedOnClear(); // Connect things. QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerMatrixVisualizerWidget::handleRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerMatrixVisualizerWidget::handleHelpButton); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleVariableNameLineEdit); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleVariableNameLineEdit); QObject::connect(matrixRowsLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton); QObject::connect(matrixRowsLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementRowsLineEdit); QObject::connect(matrixColumnsLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton); QObject::connect(matrixColumnsLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementColumnsLineEdit); QObject::connect(matrixOffsetLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton); QObject::connect(matrixOffsetLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementOffsetLineEdit); QObject::connect(matrixStrideLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMatrixVisualizerWidget::handleRefreshButton); QObject::connect(matrixStrideLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMatrixVisualizerWidget::handleElementStrideLineEdit); QObject::connect(matrixDisplayFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerMatrixVisualizerWidget::handleMatrixDisplayFormatComboBox); QObject::connect(matrixStorageOrderComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerMatrixVisualizerWidget::handleMatrixStorageOrderComboBox); QObject::connect(matrixTableWidget, &SeerMatrixWidget::dataChanged, this, &SeerMatrixVisualizerWidget::handleDataChanged); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerMatrixVisualizerWidget::handleThemeChanged); #endif // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); // Restore window settings. readSettings(); } SeerMatrixVisualizerWidget::~SeerMatrixVisualizerWidget () { } void SeerMatrixVisualizerWidget::setVariableName (const QString& name) { setWindowTitle("Seer Matrix Visualizer - '" + name + "'"); variableNameLineEdit->setText(name); if (variableNameLineEdit->text() == "") { variableAddressLineEdit->setText(""); matrixRowsLineEdit->setText(""); matrixColumnsLineEdit->setText(""); matrixOffsetLineEdit->setText(""); matrixStrideLineEdit->setText(""); matrixTableWidget->setData(0); return; } // Coalesce this variable's setup (data reset + offset/stride) into // a single table rebuild; the guard flushes it when it leaves scope. SeerMatrixWidget::BulkUpdate bulk(matrixTableWidget); setVariableAddress(""); // Clear old contents. QByteArray array; bool ok; matrixTableWidget->setData(new SeerMatrixWidget::DataStorageArray(array)); if (matrixOffsetLineEdit->text() != "") { matrixTableWidget->setAddressOffset(matrixOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << matrixOffsetLineEdit->text(); } }else{ matrixTableWidget->setAddressOffset(0); } if (matrixStrideLineEdit->text() != "") { matrixTableWidget->setAddressStride(matrixStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << matrixStrideLineEdit->text(); } }else{ matrixTableWidget->setAddressStride(1); } // Send signal to get variable address. emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); } QString SeerMatrixVisualizerWidget::variableName () const { return variableNameLineEdit->text(); } void SeerMatrixVisualizerWidget::setVariableAddress (const QString& address) { unsigned long offset = 0; bool ok = false; if (address == "") { variableAddressLineEdit->setText(""); offset = 0; }else{ // Test for base10 if (ok == false) { offset = address.toULong(&ok, 10); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } // Test for base16 if (ok == false) { offset = address.toULong(&ok, 16); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); } } if (ok == false) { variableAddressLineEdit->setText("not an address"); offset = 0; } } matrixTableWidget->setAddressOffset(0); } QString SeerMatrixVisualizerWidget::variableAddress () const { return variableAddressLineEdit->text(); } void SeerMatrixVisualizerWidget::setVariableRows (const QString& rows) { matrixRowsLineEdit->setText(rows); } QString SeerMatrixVisualizerWidget::variableRows () const { return matrixRowsLineEdit->text(); } void SeerMatrixVisualizerWidget::setVariableColumns (const QString& columns) { matrixColumnsLineEdit->setText(columns); } QString SeerMatrixVisualizerWidget::variableColumns () const { return matrixColumnsLineEdit->text(); } void SeerMatrixVisualizerWidget::setVariableOffset (const QString& offset) { matrixOffsetLineEdit->setText(offset); } QString SeerMatrixVisualizerWidget::variableOffset () const { return matrixOffsetLineEdit->text(); } void SeerMatrixVisualizerWidget::setVariableStride (const QString& stride) { matrixStrideLineEdit->setText(stride); } QString SeerMatrixVisualizerWidget::variableStride () const { return matrixStrideLineEdit->text(); } void SeerMatrixVisualizerWidget::handleText (const QString& text) { //qDebug() << text; if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // 11^done,value="1" // 11^done,value="0x7fffffffd538" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); QString address = ""; // Look for an address in the value. if (address == "") { QRegularExpression re("0[xX][0-9a-fA-F]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Look for a number in the value. if (address == "") { QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Set the variable address and read the memory there. setVariableAddress(address); readMemory(); } if (id_text.toInt() == _rowsId) { // Set the memory length. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setVariableRows(value_text); handleRefreshButton(); } if (id_text.toInt() == _columnsId) { // Set the memory length. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setVariableColumns(value_text); handleRefreshButton(); } if (id_text.toInt() == _offsetId) { // Set the memory offset. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setVariableOffset(value_text); handleRefreshButton(); } if (id_text.toInt() == _strideId) { // Set the memory stride. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setVariableStride(value_text); handleRefreshButton(); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) { // 3^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613e71",contents="00"}] // 4^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613ed4",contents="000000000000000000000000"}] QString id_text = text.section('^', 0,0); if (id_text.toInt() == _memoryId) { QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); // Loop through the memory ranges. for ( const auto& range_text : range_list ) { QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); // Convert hex string to byte array. QByteArray array; for (int i = 0; isetData(new SeerMatrixWidget::DataStorageArray(array)); if (matrixOffsetLineEdit->text() != "") { matrixTableWidget->setAddressOffset(matrixOffsetLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address offset." << matrixOffsetLineEdit->text(); } }else{ matrixTableWidget->setAddressOffset(0); } if (matrixStrideLineEdit->text() != "") { matrixTableWidget->setAddressStride(matrixStrideLineEdit->text().toULong(&ok)); if (ok == false) { qWarning() << "Invalid string for address stride." << matrixStrideLineEdit->text(); } }else{ matrixTableWidget->setAddressStride(1); } // Set the dimension of the matrix table. if (matrixRowsLineEdit->text() != "" && matrixColumnsLineEdit->text() != "") { int rows = matrixRowsLineEdit->text().toInt(&ok); if (ok == false) { qWarning() << "Invalid string for number of rows." << matrixRowsLineEdit->text(); rows = 0; } int columns = matrixColumnsLineEdit->text().toInt(&ok); if (ok == false) { qWarning() << "Invalid string for number of columns." << matrixColumnsLineEdit->text(); columns = 0; } matrixTableWidget->setDimensions(rows,columns); }else{ matrixTableWidget->setDimensions(0,0); } break; // Take just the first range for now. } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // 12^error,msg="No symbol \"return\" in current context." // 13^error,msg="No symbol \"cout\" in current context." // 3^error,msg="Unable to read memory." QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { variableAddressLineEdit->setText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) ); } if (id_text.toInt() == _memoryId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); if (msg_text != "") { QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); } } if (id_text.toInt() == _rowsId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); matrixRowsLineEdit->setText(""); matrixRowsLineEdit->setFocus(); } if (id_text.toInt() == _columnsId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); matrixColumnsLineEdit->setText(""); matrixColumnsLineEdit->setFocus(); } if (id_text.toInt() == _offsetId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); matrixOffsetLineEdit->setText(""); matrixOffsetLineEdit->setFocus(); } if (id_text.toInt() == _strideId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); matrixStrideLineEdit->setText(""); matrixStrideLineEdit->setFocus(); } // At a stopping point, refresh. Skip the "exited" reasons: the program // is gone and reading the matrix would fail with a memory error. }else if (text.startsWith("*stopped,reason=\"") && text.startsWith("*stopped,reason=\"exited") == false) { if (autoRefreshCheckBox->isChecked()) { handleRefreshButton(); } }else{ // Ignore anything else. } } void SeerMatrixVisualizerWidget::handleRefreshButton () { if (variableNameLineEdit->text() == "") { return; } // Re-evaluate the variable's address first: it may have changed since the // last stop (or the variable may not have existed yet). The answer then // reads the memory at the fresh address. See readMemory(). emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); } void SeerMatrixVisualizerWidget::readMemory () { if (variableAddressLineEdit->text() == "") { return; } if (variableAddressLineEdit->text() == "not an address") { return; } // A null address can't be read (a matrix before its construction, for // example). Keep the "0x0" visible but don't ask gdb. if (variableAddressLineEdit->text() == "0x0") { return; } int bytes = matrixRowsLineEdit->text().toInt() * matrixColumnsLineEdit->text().toInt() * Seer::typeBytes(matrixDisplayFormatComboBox->currentText()); // Nothing to read yet (no rows/columns). if (bytes <= 0) { return; } // qDebug() << "Asking for" << bytes << "bytes of matrix data."; emit evaluateMemoryExpression(_memoryId, variableAddressLineEdit->text(), bytes); } void SeerMatrixVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/MatrixVisualizer.md"); help->show(); help->raise(); } void SeerMatrixVisualizerWidget::handleVariableNameLineEdit () { setVariableName (variableNameLineEdit->text()); } void SeerMatrixVisualizerWidget::handleElementRowsLineEdit () { // Nothing set? Return. if (variableRows() == "") { return; } // A regular integer? Return. QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(variableRows()); if (match.hasMatch()) { return; } // Send for the value of the variable. emit evaluateVariableExpression(_rowsId, variableRows()); } void SeerMatrixVisualizerWidget::handleElementColumnsLineEdit () { // Nothing set? Return. if (variableColumns() == "") { return; } // A regular integer? Return. QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(variableColumns()); if (match.hasMatch()) { return; } // Send for the value of the variable. emit evaluateVariableExpression(_columnsId, variableColumns()); } void SeerMatrixVisualizerWidget::handleElementOffsetLineEdit () { // Nothing set? Return. if (variableOffset() == "") { return; } // A regular integer? Return. QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(variableOffset()); if (match.hasMatch()) { return; } emit evaluateVariableExpression(_offsetId, variableOffset()); } void SeerMatrixVisualizerWidget::handleElementStrideLineEdit () { // Nothing set? Return. if (variableStride() == "") { return; } // A regular integer? Return. QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(variableStride()); if (match.hasMatch()) { return; } // Send for the value of the variable. emit evaluateVariableExpression(_strideId, variableStride()); } void SeerMatrixVisualizerWidget::handleMatrixDisplayFormatComboBox (int index) { //qDebug() << index; if (index == 0) { matrixTableWidget->setDataType(SeerMatrixWidget::Int16MatrixType); }else if (index == 1) { matrixTableWidget->setDataType(SeerMatrixWidget::Int32MatrixType); }else if (index == 2) { matrixTableWidget->setDataType(SeerMatrixWidget::Int64MatrixType); }else if (index == 3) { matrixTableWidget->setDataType(SeerMatrixWidget::UInt16MatrixType); }else if (index == 4) { matrixTableWidget->setDataType(SeerMatrixWidget::UInt32MatrixType); }else if (index == 5) { matrixTableWidget->setDataType(SeerMatrixWidget::UInt64MatrixType); }else if (index == 6) { matrixTableWidget->setDataType(SeerMatrixWidget::Float32MatrixType); }else if (index == 7) { matrixTableWidget->setDataType(SeerMatrixWidget::Float64MatrixType); }else{ // Do nothing. } handleRefreshButton(); } void SeerMatrixVisualizerWidget::handleMatrixStorageOrderComboBox (int index) { // Same bytes, only the cell mapping changes, so no memory re-read is needed. if (index == 1) { matrixTableWidget->setStorageOrder(SeerMatrixWidget::ColumnMajor); }else{ matrixTableWidget->setStorageOrder(SeerMatrixWidget::RowMajor); } } void SeerMatrixVisualizerWidget::handleDataChanged () { // Update the meta information. // Clear everything. countLineEdit->setText(""); rowsLineEdit->setText(""); columnsLineEdit->setText(""); minimumLineEdit->setText(""); maximumLineEdit->setText(""); sumLineEdit->setText(""); averageLineEdit->setText(""); medianLineEdit->setText(""); rmsLineEdit->setText(""); // If there's nothing to show, just return. if (matrixTableWidget->dataCount() <= 0) { return; } if (matrixTableWidget->dataValues().count() <= 0) { return; } // Make a copy of the values for us to play with. QVector values = matrixTableWidget->dataValues(); // Fill in counts. countLineEdit->setText(QString::number(matrixTableWidget->dataCount())); rowsLineEdit->setText(QString::number(matrixTableWidget->dataRows())); columnsLineEdit->setText(QString::number(matrixTableWidget->dataColumns())); // Calculate statistics. double val = 0.0; double min = values[0]; double max = values[0]; double sum = 0.0; double sum2 = 0.0; double avg = 0.0; double med = 0.0; double rms = 0.0; for (int i=0; isetText(QString::number(min)); maximumLineEdit->setText(QString::number(max)); sumLineEdit->setText(QString::number(sum)); averageLineEdit->setText(QString::number(avg)); rmsLineEdit->setText(QString::number(rms)); // For median, we need to sort the values. So do this last. std::sort(values.begin(), values.end()); // If the number of elements is odd, the median is the middle element if (values.size() % 2 != 0) { med = values[values.size() / 2]; }else{ double mid1 = values[values.size() / 2 - 1]; double mid2 = values[values.size() / 2]; med = (mid1 + mid2) / 2.0; } medianLineEdit->setText(QString::number(med)); return; } void SeerMatrixVisualizerWidget::handleThemeChanged () { // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); } void SeerMatrixVisualizerWidget::writeSettings() { QSettings settings; settings.beginGroup("matrixvisualizerwindow"); { settings.setValue("size", size()); } settings.endGroup(); } void SeerMatrixVisualizerWidget::readSettings() { QSettings settings; settings.beginGroup("matrixvisualizerwindow"); { resize(settings.value("size", QSize(800, 400)).toSize()); } settings.endGroup(); } void SeerMatrixVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } epasveer-seer-97076f1/src/SeerMatrixVisualizerWidget.h000066400000000000000000000062541526321767600230400ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerMatrixVisualizerWidget.h" class SeerMatrixVisualizerWidget : public QWidget, protected Ui::SeerMatrixVisualizerWidgetForm { Q_OBJECT public: explicit SeerMatrixVisualizerWidget (QWidget* parent = 0); ~SeerMatrixVisualizerWidget (); void setVariableName (const QString& name); QString variableName () const; void setVariableAddress (const QString& address); QString variableAddress () const; void setVariableRows (const QString& rows); QString variableRows () const; void setVariableColumns (const QString& columns); QString variableColumns () const; void setVariableOffset (const QString& offset); QString variableOffset () const; void setVariableStride (const QString& stride); QString variableStride () const; signals: void evaluateVariableExpression (int expressionid, QString expression); void evaluateMemoryExpression (int expressionid, QString address, int count); public slots: void handleText (const QString& text); protected slots: void handleRefreshButton (); void handleHelpButton (); void handleVariableNameLineEdit (); void handleElementRowsLineEdit (); void handleElementColumnsLineEdit (); void handleElementOffsetLineEdit (); void handleElementStrideLineEdit (); void handleMatrixDisplayFormatComboBox (int index); void handleMatrixStorageOrderComboBox (int index); void handleDataChanged (); void handleThemeChanged (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: void readMemory (); int _variableId; int _memoryId; int _rowsId; int _columnsId; int _offsetId; int _strideId; }; epasveer-seer-97076f1/src/SeerMatrixVisualizerWidget.ui000066400000000000000000000351721526321767600232270ustar00rootroot00000000000000 SeerMatrixVisualizerWidgetForm 0 0 855 622 Form Variable name or expression. Variable name true Variable address. true Variable address false Total number of rows in the matrix. # rows true Total number of columns in the matrix. # columns true Element offset into matrix. (default=0) offset true Element stride between values. (default=1) stride true Matrix data type. int16 int32 int64 uint16 uint32 uint64 float32 float64 How the 2D matrix is laid out in memory: row-major (row by row) or column-major (column by column). row-major column-major Automatically refresh after each stopping point. Auto Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Help on Memory Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg 1 0 Count Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter # values true # values Rows Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter # rows true # rows Columns Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter # columns true # columns Minimum Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Minimum value true Minimum value Maximum Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Maximum value true Maximum value Qt::Horizontal 40 20 Sum Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Sum of values true Sum of values Average Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Average of values true Average of values Median Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Median of values true Median of values RMS Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter RMS of values true RMS of values Qt::Horizontal 40 20 SeerMatrixWidget QTableWidget
SeerMatrixWidget.h
SeerHistoryLineEdit QLineEdit
SeerHistoryLineEdit.h
variableNameLineEdit variableAddressLineEdit matrixRowsLineEdit matrixColumnsLineEdit matrixOffsetLineEdit matrixStrideLineEdit matrixDisplayFormatComboBox matrixStorageOrderComboBox autoRefreshCheckBox refreshToolButton helpToolButton matrixTableWidget countLineEdit rowsLineEdit columnsLineEdit minimumLineEdit maximumLineEdit sumLineEdit averageLineEdit medianLineEdit rmsLineEdit
epasveer-seer-97076f1/src/SeerMatrixWidget.cpp000066400000000000000000000243571526321767600213210ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMatrixWidget.h" #include "SeerUtl.h" #include #include #include SeerMatrixWidget::SeerMatrixWidget(QWidget* parent) : QTableWidget(parent) { QFont font; font.setFamily("monospace [Consolas]"); font.setFixedPitch(true); font.setStyleHint(QFont::TypeWriter); setFont(font); setFocusPolicy(Qt::StrongFocus); setEditTriggers(QAbstractItemView::NoEditTriggers); horizontalHeader()->setDefaultAlignment(Qt::AlignRight); _bulkUpdateDepth = 0; _createPending = false; _data = 0; _dataRows = 0; _dataColumns = 0; _dataType = SeerMatrixWidget::UnknownMatrixType; _storageOrder = SeerMatrixWidget::RowMajor; _addressOffset = 0; _addressStride = 1; setAddressOffset(0); setAddressStride(1); } SeerMatrixWidget::~SeerMatrixWidget() { if (_data) { delete _data; } } void SeerMatrixWidget::setAddressOffset (unsigned long offset) { _addressOffset = offset; // Repaint the widget. create(); } unsigned long SeerMatrixWidget::addressOffset () const { return _addressOffset; } void SeerMatrixWidget::setAddressStride (unsigned long stride) { if (stride < 1) { qWarning() << "Stride is not valid." << stride; stride = 1; } _addressStride = stride; // Repaint the widget. create(); } unsigned long SeerMatrixWidget::addressStride () const { return _addressStride; } int SeerMatrixWidget::dataRows () const { return _dataRows; } int SeerMatrixWidget::dataColumns () const { return _dataColumns; } unsigned long SeerMatrixWidget::dataSize () const { if (_data) { return _data->size(); } return 0; } int SeerMatrixWidget::dataCount () const { if (_data == 0) { return 0; } if (elementSize() < 1) { return 0; } return _data->size() / elementSize(); } unsigned long SeerMatrixWidget::elementSize () const { if (dataType() == SeerMatrixWidget::Int16MatrixType) { return 2; }else if (dataType() == SeerMatrixWidget::UInt16MatrixType) { return 2; }else if (dataType() == SeerMatrixWidget::Int32MatrixType) { return 4; }else if (dataType() == SeerMatrixWidget::UInt32MatrixType) { return 4; }else if (dataType() == SeerMatrixWidget::Int64MatrixType) { return 8; }else if (dataType() == SeerMatrixWidget::UInt64MatrixType) { return 8; }else if (dataType() == SeerMatrixWidget::Float32MatrixType) { return 4; }else if (dataType() == SeerMatrixWidget::Float64MatrixType) { return 8; } return 0; } void SeerMatrixWidget::setDataType (SeerMatrixWidget::MatrixType dataType) { _dataType = dataType; // This repaints the widget with the new matrix mode create(); } SeerMatrixWidget::MatrixType SeerMatrixWidget::dataType () const { return _dataType; } void SeerMatrixWidget::setStorageOrder (SeerMatrixWidget::StorageOrder order) { _storageOrder = order; // This repaints the widget with the new storage order. create(); } SeerMatrixWidget::StorageOrder SeerMatrixWidget::storageOrder () const { return _storageOrder; } QString SeerMatrixWidget::dataTypeString () const { if (dataType() == SeerMatrixWidget::Int16MatrixType) { return "int8"; }else if (dataType() == SeerMatrixWidget::UInt16MatrixType) { return "uint16"; }else if (dataType() == SeerMatrixWidget::Int32MatrixType) { return "int32"; }else if (dataType() == SeerMatrixWidget::UInt32MatrixType) { return "uint32"; }else if (dataType() == SeerMatrixWidget::Int64MatrixType) { return "int64"; }else if (dataType() == SeerMatrixWidget::UInt64MatrixType) { return "uint64"; }else if (dataType() == SeerMatrixWidget::Float32MatrixType) { return "float32"; }else if (dataType() == SeerMatrixWidget::Float64MatrixType) { return "float64"; } return "???"; } const QVector& SeerMatrixWidget::dataValues () const { return _dataValues; } void SeerMatrixWidget::setData(SeerMatrixWidget::DataStorage* pData) { if (_data) { delete _data; } /* if (pData == 0) { qDebug() << "Setting new data with no size. Dimensions are reset. Assign new data and set them again!"; }else{ qDebug() << "Setting new data with size of" << pData->size() << ". Dimensions are reset. Set them again!"; } */ _data = pData; _dataRows = 0; _dataColumns = 0; // Repaint the widget. create(); } void SeerMatrixWidget::setDimensions (int rows, int colums) { // qDebug() << "Setting dimensions to" << rows << "x" << colums; _dataRows = rows; _dataColumns = colums; // Repaint the widget. create(); } void SeerMatrixWidget::create () { // Coalesce a burst of property changes: while a bulk update is active, // defer the (expensive) table rebuild and just record that one is pending. // endBulkUpdate() performs the single rebuild once the burst is complete. if (_bulkUpdateDepth > 0) { _createPending = true; return; } // Clear the table. We're going to recreate it. clear(); setRowCount(0); setColumnCount(0); if (_data) { // qDebug() << "Row:" << dataRows() << "Cols:" << dataColumns(); setRowCount(dataRows()); setColumnCount(dataColumns()); } // If the number of rows/columns have not been assigned, return. if (dataRows() < 1 || dataColumns() < 1) { // qDebug() << "Zero rows or cols. Row:" << dataRows() << "Cols:" << dataColumns(); emit dataChanged(); return; } // Clear the values. _dataValues.resize(0); // If there's no data, do nothing. if (!_data) { // qDebug() << "No _data"; emit dataChanged(); return; } if (elementSize() < 1) { // qDebug() << "Bad element size." << elementSize(); emit dataChanged(); return; } if (_data) { int row = 0; int col = 0; // setHorizontalHeaderItem(_aColumnId, new QTableWidgetItem(QString("%1:%2:%3").arg(aLabel()).arg(aAddressOffset()).arg(aAddressStride()))); // Set the column headers. Set their labels. for (int c=0; c < dataColumns(); c++) { QTableWidgetItem* colHeaderitem = new QTableWidgetItem(QString::number(c)); colHeaderitem->setTextAlignment(Qt::AlignRight|Qt::AlignHCenter); setHorizontalHeaderItem(c, colHeaderitem); } for (int i=elementSize()*addressOffset(); i<_data->size(); i+=elementSize()*addressStride()) { // qDebug() << "Displaying element" << i; // Set row header if we need to. Set its label. if (col == 0) { QTableWidgetItem* rowHeaderitem = new QTableWidgetItem(QString::number(row)); rowHeaderitem->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); setVerticalHeaderItem(row, rowHeaderitem); } // Set cell item. QTableWidgetItem* item = new QTableWidgetItem; item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); QByteArray element = _data->getData(i, elementSize()); double val = 0.0; if (dataType() == SeerMatrixWidget::Int16MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::UInt16MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::Int32MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::UInt32MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::Int64MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::UInt64MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::Float32MatrixType) { val = *reinterpret_cast(element.data()); }else if (dataType() == SeerMatrixWidget::Float64MatrixType) { val = *reinterpret_cast(element.data()); }else{ qWarning() << "Unknown data type."; val = 0.0; } item->setText(QString::number(val)); item->setToolTip(QString("(%1,%2) = %3").arg(row).arg(col).arg(item->text())); setItem(row, col, item); _dataValues.push_back(val); // Advance to the next cell. Row-major fills a row at a time; // column-major fills a column at a time (eg: Fortran, Eigen). if (storageOrder() == SeerMatrixWidget::ColumnMajor) { row++; if (row == dataRows()) { row = 0; col++; } }else{ col++; if (col == dataColumns()) { col = 0; row++; } } } } emit dataChanged(); } void SeerMatrixWidget::beginBulkUpdate () { _bulkUpdateDepth++; } void SeerMatrixWidget::endBulkUpdate () { if (_bulkUpdateDepth > 0) { _bulkUpdateDepth--; } // Once fully unwound, do the single deferred rebuild (if any setter fired). if (_bulkUpdateDepth == 0 && _createPending) { _createPending = false; create(); } } SeerMatrixWidget::BulkUpdate::BulkUpdate (SeerMatrixWidget* widget) : _widget(widget) { _widget->beginBulkUpdate(); } SeerMatrixWidget::BulkUpdate::~BulkUpdate () { _widget->endBulkUpdate(); } SeerMatrixWidget::DataStorageArray::DataStorageArray(const QByteArray& arr) { _data = arr; } QByteArray SeerMatrixWidget::DataStorageArray::getData(int position, int length) { return _data.mid(position, length); } int SeerMatrixWidget::DataStorageArray::size() { return _data.size(); } epasveer-seer-97076f1/src/SeerMatrixWidget.h000066400000000000000000000104441526321767600207560ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerMatrixWidget: public QTableWidget { Q_OBJECT public: class DataStorage { public: virtual ~DataStorage() {}; virtual QByteArray getData(int position, int length) = 0; virtual int size() = 0; }; class DataStorageArray: public DataStorage { public: DataStorageArray(const QByteArray& arr); virtual QByteArray getData(int position, int length); virtual int size(); private: QByteArray _data; }; enum MatrixType { UnknownMatrixType = 0, Int16MatrixType = 1, UInt16MatrixType = 2, Int32MatrixType = 3, UInt32MatrixType = 4, Int64MatrixType = 5, UInt64MatrixType = 6, Float32MatrixType = 7, Float64MatrixType = 8 }; enum StorageOrder { RowMajor = 0, ColumnMajor = 1 }; // RAII guard: coalesces a burst of property changes into a single // rebuild. While a guard is alive create() is deferred; the single // rebuild happens when it goes out of scope. Nesting is supported. // Prefer a guard over the private begin/end pair so the matching end // is guaranteed even on early return or exception. class BulkUpdate { public: explicit BulkUpdate (SeerMatrixWidget* widget); ~BulkUpdate (); BulkUpdate (const BulkUpdate&) = delete; BulkUpdate& operator= (const BulkUpdate&) = delete; private: SeerMatrixWidget* _widget; }; SeerMatrixWidget(QWidget* parent = 0); ~SeerMatrixWidget(); void setAddressOffset (unsigned long offset); unsigned long addressOffset () const; void setAddressStride (unsigned long stride); unsigned long addressStride () const; unsigned long elementSize () const; void setDataType (SeerMatrixWidget::MatrixType dataType); SeerMatrixWidget::MatrixType dataType () const; void setStorageOrder (SeerMatrixWidget::StorageOrder order); SeerMatrixWidget::StorageOrder storageOrder () const; QString dataTypeString () const; const QVector& dataValues () const; int dataRows () const; int dataColumns () const; unsigned long dataSize () const; int dataCount () const; signals: void dataChanged (); public slots: void setData (DataStorage* pData); void setDimensions (int rows, int colums); protected: private: void create (); void beginBulkUpdate (); void endBulkUpdate (); int _bulkUpdateDepth; bool _createPending; unsigned long _addressOffset; unsigned long _addressStride; DataStorage* _data; int _dataRows; int _dataColumns; SeerMatrixWidget::MatrixType _dataType; SeerMatrixWidget::StorageOrder _storageOrder; QVector _dataValues; }; epasveer-seer-97076f1/src/SeerMemoryVisualizerWidget.cpp000066400000000000000000000425651526321767600234040ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMemoryVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include #include #include SeerMemoryVisualizerWidget::SeerMemoryVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _variableId = Seer::createID(); // Create id's for queries. _memoryId = Seer::createID(); _memoryLengthId = Seer::createID(); _asmId = Seer::createID(); // Set up UI. setupUi(this); // Setup the widgets setWindowTitle("Seer Memory Visualizer"); setAttribute(Qt::WA_DeleteOnClose); columnCountSpinBox->setValue(memoryHexEditor->bytesPerLine()); if (memoryHexEditor->memoryMode() == SeerHexWidget::HexMemoryMode) { memoryDisplayFormatComboBox->setCurrentIndex(0); }else if (memoryHexEditor->memoryMode() == SeerHexWidget::OctalMemoryMode) { memoryDisplayFormatComboBox->setCurrentIndex(1); }else if (memoryHexEditor->memoryMode() == SeerHexWidget::BinaryMemoryMode) { memoryDisplayFormatComboBox->setCurrentIndex(2); }else if (memoryHexEditor->memoryMode() == SeerHexWidget::DecimalMemoryMode) { memoryDisplayFormatComboBox->setCurrentIndex(3); }else{ memoryDisplayFormatComboBox->setCurrentIndex(0); } if (memoryHexEditor->charMode() == SeerHexWidget::AsciiCharMode) { charDisplayFormatComboBox->setCurrentIndex(0); }else if (memoryHexEditor->charMode() == SeerHexWidget::Utf8Mode) { charDisplayFormatComboBox->setCurrentIndex(1); }else if (memoryHexEditor->charMode() == SeerHexWidget::Utf16Mode) { charDisplayFormatComboBox->setCurrentIndex(2); }else if (memoryHexEditor->charMode() == SeerHexWidget::Utf32Mode) { charDisplayFormatComboBox->setCurrentIndex(3); }else if (memoryHexEditor->charMode() == SeerHexWidget::EbcdicCharMode) { charDisplayFormatComboBox->setCurrentIndex(4); }else{ charDisplayFormatComboBox->setCurrentIndex(0); } // Connect things. QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerMemoryVisualizerWidget::handleRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerMemoryVisualizerWidget::handleHelpButton); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMemoryVisualizerWidget::handleVariableNameLineEdit); QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMemoryVisualizerWidget::handleVariableNameLineEdit); QObject::connect(memoryLengthLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerMemoryVisualizerWidget::handleRefreshButton); QObject::connect(memoryLengthLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerMemoryVisualizerWidget::handleMemoryLengthLineEdit); QObject::connect(memoryDisplayFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerMemoryVisualizerWidget::handleMemoryDisplayFormatComboBox); QObject::connect(charDisplayFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerMemoryVisualizerWidget::handleCharDisplayFormatComboBox); QObject::connect(columnCountSpinBox, QOverload::of(&QSpinBox::valueChanged), this, &SeerMemoryVisualizerWidget::handleColumnCountSpinBox); QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerMemoryVisualizerWidget::handlePrintButton); QObject::connect(saveToolButton, &QToolButton::clicked, this, &SeerMemoryVisualizerWidget::handleSaveButton); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerMemoryVisualizerWidget::handleThemeChanged); #endif // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); // Restore window settings. readSettings(); } SeerMemoryVisualizerWidget::~SeerMemoryVisualizerWidget () { } void SeerMemoryVisualizerWidget::setVariableName (const QString& name) { setWindowTitle("Seer Memory Visualizer - '" + name + "'"); variableNameLineEdit->setText(name); setVariableAddress(""); // Clear old contents. QByteArray array; memoryHexEditor->setData(new SeerHexWidget::DataStorageArray(array)); memoryAsmEditor->setData(""); // Do nothing if there's no variable name. if (variableNameLineEdit->text() == "") { return; } // Send signal to get variable address. emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); } QString SeerMemoryVisualizerWidget::variableName () const { return variableNameLineEdit->text(); } void SeerMemoryVisualizerWidget::setVariableAddress (const QString& address) { unsigned long offset = 0; bool ok = false; bool refresh = false; if (address == "") { variableAddressLineEdit->setText(""); offset = 0; }else{ // Test for base10 if (ok == false) { offset = address.toULong(&ok, 10); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); refresh = true; } } // Test for base16 if (ok == false) { offset = address.toULong(&ok, 16); if (ok) { variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); refresh = true; } } if (ok == false) { variableAddressLineEdit->setText("not an address"); offset = 0; } } memoryHexEditor->setAddressOffset(offset); // Show results immediately. if (refresh) { handleRefreshButton(); } } QString SeerMemoryVisualizerWidget::variableAddress () const { return variableAddressLineEdit->text(); } void SeerMemoryVisualizerWidget::setMemoryLength (const QString& length) { memoryLengthLineEdit->setText(length); } QString SeerMemoryVisualizerWidget::memoryLength () const { return memoryLengthLineEdit->text(); } void SeerMemoryVisualizerWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // 11^done,value="1" // 11^done,value="0x7fffffffd538" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); QString address = ""; // Look for an address in the value. if (address == "") { QRegularExpression re("0[xX][0-9a-fA-F]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Look for a number in the value. if (address == "") { QRegularExpression re("[0-9]+"); QRegularExpressionMatch match = re.match(value_text); if (match.hasMatch()) { address = match.captured(); } } // Set the variable address. setVariableAddress(address); }else if (id_text.toInt() == _memoryLengthId) { // Set the memory length. QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); setMemoryLength(value_text); handleRefreshButton(); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) { // 3^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613e71",contents="00"}] // 4^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613ed4",contents="000000000000000000000000"}] QString id_text = text.section('^', 0,0); if (id_text.toInt() == _memoryId) { QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); // Loop through the memory ranges. for ( const auto& range_text : range_list ) { QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); // Convert hex string to byte array. QByteArray array; for (int i = 0; isetData(new SeerHexWidget::DataStorageArray(array)); break; // Take just the first range for now. } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,asm_insns="))) { QString id_text = text.section('^', 0,0); if (id_text.toInt() == _asmId) { memoryAsmEditor->setData(text); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // 12^error,msg="No symbol \"return\" in current context." // 13^error,msg="No symbol \"cout\" in current context." // 3^error,msg="Unable to read memory." QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { variableAddressLineEdit->setText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) ); variableAddressLineEdit->setFocus(); } if (id_text.toInt() == _memoryId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); /* XXX if (msg_text != "") { QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); } */ } if (id_text.toInt() == _memoryLengthId) { // Display the error message. QString msg_text = Seer::parseFirst(text, "msg=", false); QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); memoryLengthLineEdit->setText(""); memoryLengthLineEdit->setFocus(); } // At a stopping point, refresh. }else if (text.startsWith("*stopped,reason=\"")) { if (autoRefreshCheckBox->isChecked()) { handleRefreshButton(); } }else{ // Ignore anything else. } QApplication::restoreOverrideCursor(); } void SeerMemoryVisualizerWidget::handleRefreshButton () { if (variableNameLineEdit->text() == "") { return; } if (variableAddressLineEdit->text() == "") { return; } if (variableAddressLineEdit->text() == "not an address") { return; } int nbytes = 256; if (memoryLengthLineEdit->text() != "") { nbytes = memoryLengthLineEdit->text().toInt(); } if (nbytes < 1) { return; } emit evaluateMemoryExpression(_memoryId, variableAddressLineEdit->text(), nbytes); emit evaluateAsmExpression(_asmId, variableAddressLineEdit->text(), nbytes, 2); } void SeerMemoryVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/MemoryVisualizer.md"); help->show(); help->raise(); } void SeerMemoryVisualizerWidget::handleVariableNameLineEdit () { setVariableName (variableNameLineEdit->text()); } void SeerMemoryVisualizerWidget::handleMemoryLengthLineEdit () { if (memoryLengthLineEdit->text() == "") { return; } emit evaluateVariableExpression(_memoryLengthId, memoryLengthLineEdit->text()); } void SeerMemoryVisualizerWidget::handleMemoryDisplayFormatComboBox (int index) { if (index == 0) { memoryHexEditor->setMemoryMode(SeerHexWidget::HexMemoryMode); }else if (index == 1) { memoryHexEditor->setMemoryMode(SeerHexWidget::OctalMemoryMode); }else if (index == 2) { memoryHexEditor->setMemoryMode(SeerHexWidget::BinaryMemoryMode); }else if (index == 3) { memoryHexEditor->setMemoryMode(SeerHexWidget::DecimalMemoryMode); }else{ // Do nothing. } } void SeerMemoryVisualizerWidget::handleCharDisplayFormatComboBox (int index) { if (index == 0) { memoryHexEditor->setCharMode(SeerHexWidget::AsciiCharMode); }else if (index == 1) { memoryHexEditor->setCharMode(SeerHexWidget::Utf8Mode); }else if (index == 2) { memoryHexEditor->setCharMode(SeerHexWidget::Utf16Mode); }else if (index == 3) { memoryHexEditor->setCharMode(SeerHexWidget::Utf32Mode); }else if (index == 4) { memoryHexEditor->setCharMode(SeerHexWidget::EbcdicCharMode); }else{ // Do nothing. } } void SeerMemoryVisualizerWidget::handleColumnCountSpinBox (int value) { memoryHexEditor->setBytesPerLine(value); } void SeerMemoryVisualizerWidget::handlePrintButton () { QPrinter printer; QPrintDialog dialog(&printer, this); if (dialog.exec() != QDialog::Accepted) { return; } // Make a copy so we can temporarily add a header. QTextDocument* clone = 0; if (tabWidget->currentWidget()->objectName() == "hex_tab") { clone = memoryHexEditor->document()->clone(this); }else if (tabWidget->currentWidget()->objectName() == "asm_tab") { clone = memoryAsmEditor->document()->clone(this); }else{ clone = new QTextDocument("NO TAB SELECTED!!!\n"); } QTextCursor cursor(clone); QTextCharFormat format = cursor.charFormat(); format.setBackground(QBrush(Qt::transparent)); cursor.insertText("\n", format); cursor.insertText("name=" + variableName() + " address=" + variableAddress() + " bytesPerLine=" + QString::number(memoryHexEditor->bytesPerLine()) + " bytes=" + QString::number(memoryHexEditor->size()) + " memory=" + memoryHexEditor->memoryModeString() + " char=" + memoryHexEditor->charModeString() + "\n", format); cursor.insertText("\n", format); clone->print(&printer); delete clone; } void SeerMemoryVisualizerWidget::handleSaveButton () { QFileDialog dialog(this, "Seer Visualizer File", "./", "Logs (*.log);;Text files (*.txt);;All files (*.*)"); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("log"); dialog.selectFile("memory.log"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } QFile file(files[0]); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); stream << "\n"; stream << "name=" << variableName() << " address=" << variableAddress() << " bytesPerLine=" << memoryHexEditor->bytesPerLine() << " bytes=" << memoryHexEditor->size() << " memory=" << memoryHexEditor->memoryModeString() << " char=" << memoryHexEditor->charModeString() << "\n"; stream << "\n"; if (tabWidget->currentWidget()->objectName() == "hex_tab") { stream << memoryHexEditor->toPlainText(); }else if (tabWidget->currentWidget()->objectName() == "asm_tab") { stream << memoryAsmEditor->toPlainText(); }else{ stream << "NO TAB SELECTED!!!\n"; } stream << "\n"; file.flush(); file.close(); }else{ QMessageBox::critical(this, tr("Error"), tr("Cannot save display to file.")); return; } } void SeerMemoryVisualizerWidget::handleThemeChanged () { // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); } void SeerMemoryVisualizerWidget::writeSettings() { QSettings settings; settings.beginGroup("memoryvisualizerwindow"); settings.setValue("size", size()); settings.endGroup(); } void SeerMemoryVisualizerWidget::readSettings() { QSettings settings; settings.beginGroup("memoryvisualizerwindow"); resize(settings.value("size", QSize(800, 400)).toSize()); settings.endGroup(); } void SeerMemoryVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } epasveer-seer-97076f1/src/SeerMemoryVisualizerWidget.h000066400000000000000000000047361526321767600230470ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerMemoryVisualizerWidget.h" class SeerMemoryVisualizerWidget : public QWidget, protected Ui::SeerMemoryVisualizerWidgetForm { Q_OBJECT public: explicit SeerMemoryVisualizerWidget (QWidget* parent = 0); ~SeerMemoryVisualizerWidget (); void setVariableName (const QString& name); QString variableName () const; void setVariableAddress (const QString& address); QString variableAddress () const; void setMemoryLength (const QString& length); QString memoryLength () const; signals: void evaluateVariableExpression (int expressionid, QString expression); void evaluateMemoryExpression (int expressionid, QString address, int count); void evaluateAsmExpression (int expressionid, QString address, int count, int mode); public slots: void handleText (const QString& text); protected slots: void handleRefreshButton (); void handleHelpButton (); void handleVariableNameLineEdit (); void handleMemoryLengthLineEdit (); void handleMemoryDisplayFormatComboBox (int index); void handleCharDisplayFormatComboBox (int index); void handleColumnCountSpinBox (int value); void handlePrintButton (); void handleSaveButton (); void handleThemeChanged (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: int _variableId; int _memoryId; int _memoryLengthId; int _asmId; }; epasveer-seer-97076f1/src/SeerMemoryVisualizerWidget.ui000066400000000000000000000202001526321767600232150ustar00rootroot00000000000000 SeerMemoryVisualizerWidgetForm 0 0 899 683 Form Variable expression resulting in an address. Starting address true Memory address. true Memory address Number of bytes to display. # Bytes (default 256) true Memory display format. hex octal binary decimal Character display format. ascii utf8 utf16 utf32 ebcdic Number of columns in display. 1 10 Print the display. ... :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Save the display to a file. ... :/seer/resources/RelaxLightIcons/document-save-as.svg:/seer/resources/RelaxLightIcons/document-save-as.svg Qt::Vertical Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Automatically refresh after each stopping point. Auto Qt::Vertical Help on Memory Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg 0 Memory 0 100 Disassembly 0 100 SeerHexWidget QWidget
SeerHexWidget.h
1
SeerAsmWidget QWidget
SeerAsmWidget.h
1
SeerHistoryLineEdit QLineEdit
SeerHistoryLineEdit.h
epasveer-seer-97076f1/src/SeerMessagesBrowserWidget.cpp000066400000000000000000000132111526321767600231530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMessagesBrowserWidget.h" #include #include #include #include #include SeerMessagesBrowserWidget::SeerMessagesBrowserWidget (QWidget* parent) : QWidget(parent) { _raiseMode = "any"; // Default. Raise message tab on any message. _raiseMenu = 0; // Construct the UI. setupUi(this); // Setup the widgets messagesTreeWidget->setRootIsDecorated(false); messagesTreeWidget->setSortingEnabled(false); messagesTreeWidget->resizeColumnToContents(0); // timestamp messagesTreeWidget->resizeColumnToContents(1); // message type icon messagesTreeWidget->resizeColumnToContents(2); // message _raiseMenu = new QMenu("Raise Messages Tab"); QMenu* menu = new QMenu(); menu->addMenu(_raiseMenu); _anyMessageAction = _raiseMenu->addAction("Any message"); _importanMessagesAction = _raiseMenu->addAction("Important messages"); _neverMessagesAction = _raiseMenu->addAction("Never"); preferencesToolButton->setMenu(menu); preferencesToolButton->setPopupMode(QToolButton::InstantPopup); // Get icons. _informationIcon = QIcon(":/seer/resources/RelaxLightIcons/data-information.svg"); _warningIcon = QIcon(":/seer/resources/RelaxLightIcons/data-warning.svg"); _criticalIcon = QIcon(":/seer/resources/RelaxLightIcons/data-error.svg"); _questionIcon = QIcon(":/seer/resources/RelaxLightIcons/dialog-question.svg"); // Connect things. QObject::connect(deleteMessagesToolButton, &QToolButton::clicked, this, &SeerMessagesBrowserWidget::handleDeleteToolButton); QObject::connect(_raiseMenu, &QMenu::aboutToShow, this, &SeerMessagesBrowserWidget::handleRaiseMenuShow); QObject::connect(_raiseMenu, &QMenu::triggered, this, &SeerMessagesBrowserWidget::handleRaiseMenuTriggered); // Clear messages clearMessages(); // Read the default settings. readSettings(); } SeerMessagesBrowserWidget::~SeerMessagesBrowserWidget () { } void SeerMessagesBrowserWidget::addMessage (const QString& message, QMessageBox::Icon messageType) { // Create an entry with our message. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, QTime::currentTime().toString(Qt::TextDate)); switch (messageType) { case QMessageBox::NoIcon: item->setIcon(1, _noIcon); break; case QMessageBox::Information: item->setIcon(1, _informationIcon); break; case QMessageBox::Warning: item->setIcon(1, _warningIcon); break; case QMessageBox::Critical: item->setIcon(1, _criticalIcon); break; case QMessageBox::Question: item->setIcon(1, _questionIcon); break; default: item->setIcon(1, _noIcon); break; } item->setText(2, message); // Insert the entry (at the end). messagesTreeWidget->addTopLevelItem(item); // Re-adjust column sizes. messagesTreeWidget->resizeColumnToContents(0); messagesTreeWidget->resizeColumnToContents(1); messagesTreeWidget->resizeColumnToContents(2); // Scroll to the bottom. QTreeWidgetItem* lastItem = messagesTreeWidget->topLevelItem(messagesTreeWidget->topLevelItemCount()-1); if (lastItem) { messagesTreeWidget->scrollToItem(lastItem); messagesTreeWidget->clearSelection(); lastItem->setSelected(true); } // Signal that a message was added, depending on the 'raise' mode. if (_raiseMode == "any") { emit showMessages(); }else if (_raiseMode == "important") { if (messageType == QMessageBox::Warning || messageType == QMessageBox::Critical || messageType == QMessageBox::Question) { emit showMessages(); }else if (message.startsWith("Program started")) { emit showMessages(); }else if (message.startsWith("Program exited")) { emit showMessages(); } }else if (_raiseMode == "never") { // Do nothing. } } void SeerMessagesBrowserWidget::clearMessages () { messagesTreeWidget->clear(); } void SeerMessagesBrowserWidget::writeSettings () { QSettings settings; settings.beginGroup("executionmessages"); { settings.setValue("raisetabmode", _raiseMode); }settings.endGroup(); } void SeerMessagesBrowserWidget::readSettings () { QSettings settings; settings.beginGroup("executionmessages"); { _raiseMode = settings.value("raisetabmode", "any").toString(); } settings.endGroup(); } void SeerMessagesBrowserWidget::handleDeleteToolButton () { // Delete all messages. clearMessages(); } void SeerMessagesBrowserWidget::handleRaiseMenuShow () { if (_raiseMode == "any") { _raiseMenu->setDefaultAction(_anyMessageAction); }else if (_raiseMode == "important") { _raiseMenu->setDefaultAction(_importanMessagesAction); }else if (_raiseMode == "never") { _raiseMenu->setDefaultAction(_neverMessagesAction); }else{ _raiseMenu->setDefaultAction(_anyMessageAction); } } void SeerMessagesBrowserWidget::handleRaiseMenuTriggered (QAction* action) { if (action == _anyMessageAction) { _raiseMode = "any"; }else if (action == _importanMessagesAction) { _raiseMode = "important"; }else if (action == _neverMessagesAction) { _raiseMode = "never"; }else{ _raiseMode = "any"; } writeSettings(); } epasveer-seer-97076f1/src/SeerMessagesBrowserWidget.h000066400000000000000000000031371526321767600226260ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include #include "ui_SeerMessagesBrowserWidget.h" class SeerMessagesBrowserWidget : public QWidget, protected Ui::SeerMessagesBrowserWidgetForm { Q_OBJECT public: explicit SeerMessagesBrowserWidget (QWidget* parent = 0); ~SeerMessagesBrowserWidget (); public slots: void addMessage (const QString& message, QMessageBox::Icon messageType); void clearMessages (); private slots: void handleDeleteToolButton (); void handleRaiseMenuShow (); void handleRaiseMenuTriggered (QAction* action); signals: void showMessages (); protected: void writeSettings (); void readSettings (); private: QString _raiseMode; QMenu* _raiseMenu; QAction* _anyMessageAction; QAction* _importanMessagesAction; QAction* _neverMessagesAction; QIcon _noIcon; QIcon _informationIcon; QIcon _warningIcon; QIcon _criticalIcon; QIcon _questionIcon; }; epasveer-seer-97076f1/src/SeerMessagesBrowserWidget.ui000066400000000000000000000054171526321767600230170ustar00rootroot00000000000000 SeerMessagesBrowserWidgetForm 0 0 1162 625 Form QAbstractItemView::NoEditTriggers Timestamp Type AlignLeading|AlignVCenter Message Delete all messages. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Preferences :/seer/resources/RelaxLightIcons/application-menu.svg:/seer/resources/RelaxLightIcons/application-menu.svg Qt::Vertical 20 40 epasveer-seer-97076f1/src/SeerMessagesDialog.cpp000066400000000000000000000115651526321767600215750ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMessagesDialog.h" #include #include #include #include #include #include SeerMessagesDialog::SeerMessagesDialog (QWidget* parent) : QDialog(parent) { _closePushButton = 0; _clearPushButton = 0; // Construct the UI. setupUi(this); setWindowTitle("Seer Execution Messages"); // Setup the widgets. QString style = "QTreeWidget::item:!selected " // Items in tree widget will have a border. "{ " "border: 1px solid gainsboro; " "border-left: none; " "border-top: none; " "}" "QTreeWidget::item:selected {}"; messageTreeWidget->setRootIsDecorated(false); messageTreeWidget->setStyleSheet(style); messageTreeWidget->setSortingEnabled(false); messageTreeWidget->resizeColumnToContents(0); // timestamp messageTreeWidget->resizeColumnToContents(1); // message type icon messageTreeWidget->resizeColumnToContents(2); // message // Add a "CLEAR" button to the dialog's buttonbox. // Make sure the CLOSE has the default action still. QDialogButtonBox* buttonBox = findChild("buttonBox"); if (buttonBox) { _clearPushButton = buttonBox->addButton("Clear", QDialogButtonBox::ActionRole); QObject::connect(_clearPushButton, &QPushButton::clicked, this, &SeerMessagesDialog::clearMessages); _closePushButton = buttonBox->button(QDialogButtonBox::Close); } resetDefaultButton(); // Get icons. _informationIcon = QIcon(":/seer/resources/RelaxLightIcons/data-information.svg"); _warningIcon = QIcon(":/seer/resources/RelaxLightIcons/data-warning.svg"); _criticalIcon = QIcon(":/seer/resources/RelaxLightIcons/data-error.svg"); _questionIcon = QIcon(":/seer/resources/RelaxLightIcons/dialog-question.svg"); // Connect things. // Clear messages clearMessages(); // Restore window settings. readSettings(); // Hide right away. hide(); } SeerMessagesDialog::~SeerMessagesDialog () { } void SeerMessagesDialog::addMessage (const QString& message, QMessageBox::Icon messageType) { // Give this dialog the focus. //setFocus(Qt::OtherFocusReason); // Show messages any time a messaged is added. showMessages(); // Create an entry with our message. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, QTime::currentTime().toString(Qt::TextDate)); switch (messageType) { case QMessageBox::NoIcon: item->setIcon(1, _noIcon); break; case QMessageBox::Information: item->setIcon(1, _informationIcon); break; case QMessageBox::Warning: item->setIcon(1, _warningIcon); break; case QMessageBox::Critical: item->setIcon(1, _criticalIcon); break; case QMessageBox::Question: item->setIcon(1, _questionIcon); break; default: item->setIcon(1, _noIcon); break; } item->setText(2, message); // Insert the entry (at the end). messageTreeWidget->addTopLevelItem(item); // Re-adjust column sizes. messageTreeWidget->resizeColumnToContents(0); messageTreeWidget->resizeColumnToContents(1); messageTreeWidget->resizeColumnToContents(2); // Scroll to the bottom. QTreeWidgetItem* lastItem = messageTreeWidget->topLevelItem(messageTreeWidget->topLevelItemCount()-1); if (lastItem) { messageTreeWidget->scrollToItem(lastItem); messageTreeWidget->clearSelection(); lastItem->setSelected(true); } resetDefaultButton(); } void SeerMessagesDialog::clearMessages () { messageTreeWidget->clear(); resetDefaultButton(); } void SeerMessagesDialog::showMessages () { // Show the dialog. show(); resetDefaultButton(); } void SeerMessagesDialog::writeSettings () { QSettings settings; settings.beginGroup("executionmessagesdialog"); { settings.setValue("size", size()); }settings.endGroup(); } void SeerMessagesDialog::readSettings () { QSettings settings; settings.beginGroup("executionmessagesdialog"); { resize(settings.value("size", QSize(425, 150)).toSize()); } settings.endGroup(); } void SeerMessagesDialog::resizeEvent (QResizeEvent* event) { // Write window settings. writeSettings(); QDialog::resizeEvent(event); } void SeerMessagesDialog::resetDefaultButton () { if (_clearPushButton) { _clearPushButton->setDefault(false); } if (_closePushButton) { _closePushButton->setDefault(true); } } epasveer-seer-97076f1/src/SeerMessagesDialog.h000066400000000000000000000026071526321767600212370ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include "ui_SeerMessagesDialog.h" class SeerMessagesDialog : public QDialog, protected Ui::SeerMessagesDialog { Q_OBJECT public: explicit SeerMessagesDialog (QWidget* parent = 0); ~SeerMessagesDialog (); signals: public slots: void addMessage (const QString& message, QMessageBox::Icon messageType); void clearMessages (); void showMessages (); protected slots: protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); void resetDefaultButton (); private: QIcon _noIcon; QIcon _informationIcon; QIcon _warningIcon; QIcon _criticalIcon; QIcon _questionIcon; QPushButton* _closePushButton; QPushButton* _clearPushButton; }; epasveer-seer-97076f1/src/SeerMessagesDialog.ui000066400000000000000000000040631526321767600214230ustar00rootroot00000000000000 SeerMessagesDialog 0 0 425 150 Seer Execution Messages QAbstractItemView::NoEditTriggers Timestamp Type AlignLeading|AlignVCenter Message Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() SeerMessagesDialog accept() 248 254 157 274 buttonBox rejected() SeerMessagesDialog reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerOdinSourceHighlighter.cpp000066400000000000000000000116341526321767600231340ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerOdinSourceHighlighter.h" SeerOdinSourceHighlighter::SeerOdinSourceHighlighter (QTextDocument* parent) : SeerSourceHighlighter(parent) { // Set to default formats. setHighlighterSettings(SeerHighlighterSettings::populate("")); } void SeerOdinSourceHighlighter::setHighlighterSettings (const SeerHighlighterSettings& settings) { _highlighterSettings = settings; _classFormat = _highlighterSettings.get("Class"); _quotationFormat = _highlighterSettings.get("Quotation"); _functionFormat = _highlighterSettings.get("Function"); _singleLineCommentFormat = _highlighterSettings.get("Comment"); _multiLineCommentFormat = _highlighterSettings.get("Multiline Comment"); _keywordFormat = _highlighterSettings.get("Keyword"); const QString keywordPatterns[] = { QStringLiteral("\\bpackage\\b"), QStringLiteral("\\bimport\\b"), QStringLiteral("\\bforeign\\b"), QStringLiteral("\\bproc\\b"), QStringLiteral("\\breturn\\b"), QStringLiteral("\\bif\\b"), QStringLiteral("\\belse\\b"), QStringLiteral("\\bswitch\\b"), QStringLiteral("\\bcase\\b"), QStringLiteral("\\bbreak\\b"), QStringLiteral("\\bcontinue\\b"), QStringLiteral("\\bfallthrough\\b"), QStringLiteral("\\bfor\\b"), QStringLiteral("\\bdo\\b"), QStringLiteral("\\bin\\b"), QStringLiteral("\\bnot_in\\b"), QStringLiteral("\\bdefer\\b"), QStringLiteral("\\bdynamic\\b"), QStringLiteral("\\bconst\\b"), QStringLiteral("\\bwhere\\b"), QStringLiteral("\\busing\\b"), QStringLiteral("\\bor_else\\b"), QStringLiteral("\\bor_break\\b"), QStringLiteral("\\bor_continue\\b"), QStringLiteral("\\bor_return\\b"), QStringLiteral("\\basm\\b"), QStringLiteral("\\bdistinct\\b"), QStringLiteral("\\bcontext\\b"), QStringLiteral("\\bnil\\b"), QStringLiteral("\\btrue\\b"), QStringLiteral("\\bfalse\\b"), QStringLiteral("\\bstruct\\b"), QStringLiteral("\\benum\\b"), QStringLiteral("\\bunion\\b"), QStringLiteral("\\bmap\\b"), QStringLiteral("\\bbit_set\\b"), QStringLiteral("\\bbit_field\\b"), QStringLiteral("\\bcast\\b"), QStringLiteral("\\btransmute\\b"), QStringLiteral("\\bauto_cast\\b"), QStringLiteral("\\bwhen\\b"), // builtin types QStringLiteral("\\b(i8|i16|i32|i64|i128|int)\\b"), QStringLiteral("\\b(u8|u16|u32|u64|u128|uint|uintptr)\\b"), QStringLiteral("\\b(f16|f32|f64|f128)\\b"), QStringLiteral("\\bf16le|f32le|f64le|f128le\\b"), QStringLiteral("\\b(f16be|f32be|f64be|f128be)\\b"), QStringLiteral("\\b(complex32|complex64|complex128)\\b"), QStringLiteral("\\b(quaternion64|quaternion128|quaternion256)\\b"), QStringLiteral("\\b(bool|b8|b16|b32|b64)\\b"), QStringLiteral("\\b(string|cstring|rune)\\b"), QStringLiteral("\\b(rawptr)\\b"), QStringLiteral("\\b(any|typeid)\\b"), QStringLiteral("\\b(byte)\\b"), QStringLiteral("\\b(u16le|u32le|u64le|u128le|i16le|i32le|i64le|i128le)\\b"), QStringLiteral("\\b(i16be|i32be|i64be|i128be|u16be|u32be|u64be|u128be)\\b"), // matches all the #+ and # compiler directives/builtins QStringLiteral("#([^\\s\\(]+)(\\([^\\)]*\\))?"), // matches all attributes like @(attribute) with optional parentheses QStringLiteral("@(\\([^\\)]*\\)|\\w+)"), }; _highlightingRules.clear(); // Clear old rules. HighlightingRule rule; // Set class format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Z][A-Z0-9_]*\\b")); rule.format = _classFormat; _highlightingRules.append(rule); // Set function format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Za-z0-9_]+(?=\\s*\\()")); rule.format = _functionFormat; _highlightingRules.append(rule); // Set keywords format and expression (must have precedence over functions) for (const QString& pattern : keywordPatterns) { rule.pattern = QRegularExpression(pattern); rule.format = _keywordFormat; _highlightingRules.append(rule); } // Set quote format and expression. This rule must come after the function // and keyword rules so that string contents keep the quote format (same // order as the Ada highlighter). rule.pattern = QRegularExpression(QStringLiteral("\"[^\"]*\"")); rule.format = _quotationFormat; _highlightingRules.append(rule); // Set single line comment format and expression. rule.pattern = QRegularExpression(QStringLiteral("//[^\n]*")); rule.format = _singleLineCommentFormat; _highlightingRules.append(rule); // Set multi-line comment expression. Format is defined later. _commentStartExpression = QRegularExpression(QStringLiteral("/\\*")); _commentEndExpression = QRegularExpression(QStringLiteral("\\*/")); } epasveer-seer-97076f1/src/SeerOdinSourceHighlighter.h000066400000000000000000000007241526321767600225770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerHighlighterSettings.h" #include "SeerSourceHighlighter.h" class SeerOdinSourceHighlighter : public SeerSourceHighlighter { Q_OBJECT public: SeerOdinSourceHighlighter(QTextDocument *parent = 0); virtual void setHighlighterSettings (SeerHighlighterSettings const &settings) override; }; epasveer-seer-97076f1/src/SeerParallelStacksCommon.cpp000066400000000000000000000361301526321767600227570ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerParallelStacksVisualizerWidget.h" #include "SeerUtl.h" #include #include SeerParallelStacksFrame::SeerParallelStacksFrame() { } SeerParallelStacksFrame::SeerParallelStacksFrame(const QString& text) { parse(text); } SeerParallelStacksFrame::~SeerParallelStacksFrame() { } void SeerParallelStacksFrame::parse (const QString& text) { _level = Seer::parseFirst(text, "level=", '"', '"', false).toInt(); _addr = Seer::parseFirst(text, "addr=", '"', '"', false); _function = Seer::parseFirst(text, "func=", '"', '"', false); _arch = Seer::parseFirst(text, "arch=", '"', '"', false); _from = Seer::parseFirst(text, "from=", '"', '"', false); _file = Seer::parseFirst(text, "file=", '"', '"', false); _fullname = Seer::parseFirst(text, "fullname=", '"', '"', false); _line = Seer::parseFirst(text, "line=", '"', '"', false).toInt(); _type = Seer::parseFirst(text, "type=", '"', '"', false); } int SeerParallelStacksFrame::level () const { return _level; } int SeerParallelStacksFrame::depth () const { return _depth; } void SeerParallelStacksFrame::setDepth (int depth) { _depth = depth; } const QString& SeerParallelStacksFrame::addr () const { return _addr; } const QString& SeerParallelStacksFrame::function () const { return _function; } QString SeerParallelStacksFrame::functionOrAddr () const { if (_function == "??") { return _addr; } return _function; } const QString& SeerParallelStacksFrame::arch () const { return _arch; } const QString& SeerParallelStacksFrame::from () const { return _from; } const QString& SeerParallelStacksFrame::file () const { return _file; } const QString& SeerParallelStacksFrame::fullname () const { return _fullname; } int SeerParallelStacksFrame::line () const { return _line; } const QString& SeerParallelStacksFrame::type () const { return _type; } bool SeerParallelStacksFrame::hasDebugInfo () const { return _file.isEmpty() == false || _fullname.isEmpty() == false; } SeerParallelStacksFrame SeerParallelStacksFrame::externalCodeFrame (int level) { SeerParallelStacksFrame frame; frame._level = level; frame._line = 0; frame._function = "[External Code]"; frame._isExternalCode = true; return frame; } bool SeerParallelStacksFrame::isExternalCode () const { return _isExternalCode; } const QStringList& SeerParallelStacksFrame::externalFunctions () const { return _externalFunctions; } void SeerParallelStacksFrame::addExternalFunction (const QString& function) { if (_externalFunctions.contains(function) == false) { _externalFunctions.append(function); } } QString SeerParallelStacksFrame::toString() const { // XXX return QString("level: %1, address: '%2', function: '%3', file: '%4', fullname: '%5'") .arg(_level).arg(_addr).arg(_function).arg(_file).arg(_fullname); return QString("level: %1, address: '%2', file: '%3', fullname: '%4'") .arg(_level).arg(_addr).arg(_file).arg(_fullname); } SeerParallelStacksThread::SeerParallelStacksThread () { } SeerParallelStacksThread::SeerParallelStacksThread (const QString& text) { parse(text); } SeerParallelStacksThread::~SeerParallelStacksThread () { } void SeerParallelStacksThread::parse (const QString& text) { _id = Seer::parseFirst(text, "thread-id=", '"', '"', false).toInt(); _target_id = Seer::parseFirst(text, "target-id=", '"', '"', false); _name = Seer::parseFirst(text, "name=", '"', '"', false); _state = Seer::parseFirst(text, "state=", '"', '"', false); _current = Seer::parseFirst(text, "current=", '"', '"', false).toInt(); QString frames_text = Seer::parseFirst(text, "frames=", '[', ']', false); QStringList frame_list = Seer::parse(frames_text, "", '{', '}', false); // Loop through each thread. for (const auto& frame_text : frame_list) { SeerParallelStacksFrame frame(frame_text); _frames.push_back(frame); } } int SeerParallelStacksThread::id () const { return _id; } const QString& SeerParallelStacksThread::target_id () const { return _target_id; } const QString& SeerParallelStacksThread::name () const { return _name; } const QString& SeerParallelStacksThread::state () const { return _state; } int SeerParallelStacksThread::current () const { return _current; } int SeerParallelStacksThread::frameCount () const { return _frames.size(); } const SeerParallelStacksFrame& SeerParallelStacksThread::frame (int i) const { return _frames[i]; } const SeerParallelStacksFrames& SeerParallelStacksThread::frames () const { return _frames; } SeerParallelStacksThread SeerParallelStacksThread::withFrames (const SeerParallelStacksFrames& frames) const { SeerParallelStacksThread thread = *this; thread._frames = frames; return thread; } int SeerParallelStacksThread::indexOfFunction (const QString& function) const { // Frames are innermost-first, so the first match is the innermost call. for (int i = 0; i < _frames.size(); ++i) { if (_frames[i].functionOrAddr() == function) { return i; } } return -1; } int SeerParallelStacksThread::indexOfLevel (int level) const { // Frames are innermost-first with increasing levels. An "[External Code]" // frame carries the level of the innermost frame it merged, so the // covering frame is the last one whose level is <= level. int index = -1; for (int i = 0; i < _frames.size(); ++i) { if (_frames[i].level() > level) { break; } index = i; } return index; } QString SeerParallelStacksThread::toString() const { QString result = QString("Thread %1: #Frames %2").arg(_id).arg(QString::number(_frames.size())); for (const auto& f : _frames) { result += "\n " + f.toString(); } result += "\n"; return result; } static SeerParallelStacksNode buildImpl(const SeerParallelStacksThreads& threads, const SeerParallelStacksFrame& currentFrame, int depth) { SeerParallelStacksNode node; node.depth = depth; node.function = currentFrame; node.threads = threads; // Group threads by the function at position [-depth-1] (bottom-up). QMap functionFrames; QMap> functionThreads; int level = -depth - 1; for (const SeerParallelStacksThread& t : threads) { int idx = t.frames().size() + level; // convert negative index if (idx < 0 || idx >= t.frames().size()) { continue; } const SeerParallelStacksFrame& frame = t.frame(idx); const QString& fn = frame.function(); if (functionFrames.contains(fn) == false) { functionFrames[fn] = frame; }else if (frame.isExternalCode()) { // Threads sharing this "[External Code]" node may have come // through different external functions. List them all. for (const QString& f : frame.externalFunctions()) { functionFrames[fn].addExternalFunction(f); } } functionThreads[fn].append(t); } for (auto it = functionThreads.begin(); it != functionThreads.end(); ++it) { // Tag the representative frame with the CHILD's own depth (depth+1) // rather than trusting whichever thread it happened to come from: // depth-from-bottom is the same for every thread sharing this // call-tree position (that's the invariant the grouping above // relies on), so it stays correct however "current" is later // redefined by an interactive thread/frame selection — unlike // level(), which is only meaningful relative to whichever thread // this particular frame was sampled from. SeerParallelStacksFrame repFrame = functionFrames[it.key()]; repFrame.setDepth(depth + 1); SeerParallelStacksNode child = buildImpl(it.value(), repFrame, depth + 1); node.children.append(child); } return node; } SeerParallelStacksNode SeerParallelStacksBuildParallelStacks(const SeerParallelStacksThreads& threads) { return buildImpl(threads, SeerParallelStacksFrame(), 0); } // --------------------------------------------------------------- // fillStack — flatten SeerParallelStacksNode tree into Stack tree for graphing // --------------------------------------------------------------- SeerParallelStacksStack SeerParallelStacksFillStack(const SeerParallelStacksNode& node, bool downward) { SeerParallelStacksStack stack; stack.threadCount = node.threads.size(); // Collect thread IDs for this node for (const SeerParallelStacksThread& t : node.threads) { stack.threadIds.append(t.id()); } if (node.children.size() == 1) { // Merge single child into this stack (chain of frames). // Keep the IDs from the leaf (most specific) node. // Normally children are deeper (more toward the top of the call // stack) than this node, so their frames go first — the resulting // list reads top of stack (innermost) to bottom of stack // (outermost). When drawn downward (Method View's callers), the // children are this node's callers instead, so they go last to // keep that same innermost-to-outermost reading order. auto child = SeerParallelStacksFillStack(node.children[0], downward); stack.frames = child.frames; stack.stacks = child.stacks; stack.threadCount = child.threadCount; stack.threadIds = child.threadIds; if (node.function.function().isEmpty() == false) { if (downward) { stack.frames.prepend(node.function); }else{ stack.frames.append(node.function); } } } else { if (node.function.function().isEmpty() == false) { stack.frames.append(node.function); } for (const auto& childNode : node.children) { stack.stacks.append(SeerParallelStacksFillStack(childNode, downward)); } } return stack; } // Re-tags every frame in the tree with a signed distance from Method View's // pivot, in place of buildImpl()'s depth-from-bottom: depth() becomes // sign * (node.depth + offset). static void renumberDepths(SeerParallelStacksNode& node, int offset, int sign) { if (node.function.function().isEmpty() == false) { node.function.setDepth(sign * (node.depth + offset)); } for (auto& child : node.children) { renumberDepths(child, offset, sign); } } // --------------------------------------------------------------- // Method View — split every thread that calls pivotFunction at its // innermost call of it (so, with recursion, the callee half never contains // the pivot again), then build each half with the same buildImpl() the // Threads view uses: // // callees: frames[0..idx] — the pivot is the last (outermost) // frame, so the tree's root has exactly one child: the pivot. // callers: frames[idx+1..], reversed — so the immediate caller is the // outermost frame, and the tree grows from the pivot out // toward each thread's entry point. // --------------------------------------------------------------- SeerParallelStacksMethodStacks SeerParallelStacksBuildMethodStacks(const SeerParallelStacksThreads& threads, const QString& pivotFunction) { SeerParallelStacksMethodStacks result; result.pivotFunction = pivotFunction; SeerParallelStacksThreads calleeThreads; SeerParallelStacksThreads callerThreads; for (const SeerParallelStacksThread& t : threads) { int idx = t.indexOfFunction(pivotFunction); if (idx < 0) { continue; } const SeerParallelStacksFrames& frames = t.frames(); SeerParallelStacksFrames callees = frames.mid(0, idx + 1); SeerParallelStacksFrames callers; for (int i = frames.size() - 1; i > idx; --i) { callers.append(frames[i]); } calleeThreads.append(t.withFrames(callees)); callerThreads.append(t.withFrames(callers)); } result.threadCount = calleeThreads.size(); if (result.threadCount == 0) { return result; } // Callees. The pivot node is at buildImpl() depth 1, so offset -1 makes // it depth 0 and its callees +1, +2, ... SeerParallelStacksNode calleeRoot = buildImpl(calleeThreads, SeerParallelStacksFrame(), 0); renumberDepths(calleeRoot, -1, +1); if (calleeRoot.children.size() == 1) { // Build the pivot's box by hand rather than via FillStack(), which // would merge it into its callee chain whenever there's only one // callee branch — the pivot should always sit in a box of its own. const SeerParallelStacksNode& pivotNode = calleeRoot.children[0]; result.callees.threadCount = pivotNode.threads.size(); for (const SeerParallelStacksThread& t : pivotNode.threads) { result.callees.threadIds.append(t.id()); } result.callees.frames.append(pivotNode.function); for (const auto& childNode : pivotNode.children) { result.callees.stacks.append(SeerParallelStacksFillStack(childNode)); } } // Callers. The immediate caller is at buildImpl() depth 1, so negating // gives -1, -2, ... going outward. SeerParallelStacksNode callerRoot = buildImpl(callerThreads, SeerParallelStacksFrame(), 0); renumberDepths(callerRoot, 0, -1); result.callers = SeerParallelStacksFillStack(callerRoot, true); return result; } // --------------------------------------------------------------- // Merge each run of consecutive frames without debug info into a single // "[External Code]" frame, like Visual Studio's "Show External Code" off. // Done before building the tree, so threads that differ only inside // library code end up sharing a node. // --------------------------------------------------------------- SeerParallelStacksThreads SeerParallelStacksCollapseExternalCode(const SeerParallelStacksThreads& threads, const QString& keepFunction) { SeerParallelStacksThreads result; for (const SeerParallelStacksThread& t : threads) { SeerParallelStacksFrames frames; bool inRun = false; for (const SeerParallelStacksFrame& f : t.frames()) { bool external = f.hasDebugInfo() == false && (keepFunction.isEmpty() || f.functionOrAddr() != keepFunction); if (external == false) { frames.append(f); inRun = false; continue; } if (inRun == false) { frames.append(SeerParallelStacksFrame::externalCodeFrame(f.level())); inRun = true; } frames.last().addExternalFunction(f.functionOrAddr()); } result.append(t.withFrames(frames)); } return result; } epasveer-seer-97076f1/src/SeerParallelStacksCommon.h000066400000000000000000000206451526321767600224300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include // Sentinel for "no frame depth" (no highlight, or a "[...]" placeholder // row). Not -1, since Method View uses negative depths for callers. constexpr int kNoFrameDepth = std::numeric_limits::min(); class SeerParallelStacksFrame { public: SeerParallelStacksFrame (); SeerParallelStacksFrame (const QString& text); ~SeerParallelStacksFrame (); void parse (const QString& text); int level () const; const QString& addr () const; const QString& function () const; QString functionOrAddr () const; const QString& arch () const; const QString& from () const; const QString& file () const; const QString& fullname () const; int line () const; const QString& type () const; QString toString () const; // A frame with no source file — library or system code built // without debug info. bool hasDebugInfo () const; // A run of consecutive frames without debug info, merged into one // "[External Code]" frame (see SeerParallelStacksCollapseExternalCode()). // Its level() is that of the innermost frame in the run, and // externalFunctions() lists the functions it stands in for. When // threads are merged into one node, the node's frame lists those of // every thread. static SeerParallelStacksFrame externalCodeFrame (int level); bool isExternalCode () const; const QStringList& externalFunctions () const; void addExternalFunction (const QString& function); // Distance from the bottom (outermost/root) frame of whichever // thread this frame was sampled from — unlike level() (that // thread's own absolute numbering, which varies with how many // frames that thread has below this point), depth() is the same // for every thread sharing this call-tree position, since it's set // from the tree's own recursion depth, not from any one thread's // frame count. Set by SeerParallelStacksCommon.cpp while building // the tree; kNoFrameDepth until then. // // In Method View the meaning changes to a signed distance from the // pivot frame instead: 0 for the pivot, +1, +2, ... for its callees // (upward) and -1, -2, ... for its callers (downward). Negative // values are therefore legitimate there — use kNoFrameDepth, not -1, // to mean "no frame". int depth () const; void setDepth (int depth); private: int _level; QString _addr; QString _function; QString _arch; QString _from; QString _file; QString _fullname; int _line; QString _type; int _depth = kNoFrameDepth; bool _isExternalCode = false; QStringList _externalFunctions; }; typedef QVector SeerParallelStacksFrames; class SeerParallelStacksThread { public: SeerParallelStacksThread (); SeerParallelStacksThread (const QString& text); ~SeerParallelStacksThread (); void parse (const QString& text); int id () const; const QString& target_id () const; const QString& name () const; const QString& state () const; int current () const; QString toString () const; int frameCount () const; const SeerParallelStacksFrame& frame (int i) const; const SeerParallelStacksFrames& frames () const; // A copy of this thread (same id/name/state) with its frames // replaced — used by Method View to split a stack at the pivot. SeerParallelStacksThread withFrames (const SeerParallelStacksFrames& frames) const; // Index (== level) of the innermost frame whose function() is // function, or -1 if this thread never calls it. int indexOfFunction (const QString& function) const; // Index of the frame covering gdb frame level — the frame itself, // or the "[External Code]" frame it was merged into. -1 if none. int indexOfLevel (int level) const; private: int _id; QString _target_id; QString _name; QString _state; int _current; SeerParallelStacksFrames _frames; }; typedef QVector SeerParallelStacksThreads; struct SeerParallelStacksNode { SeerParallelStacksFrame function; // function().isEmpty() == root int depth = 0; SeerParallelStacksThreads threads; QVector children; }; // Flat "Stack" representation used when building the graph. Purely // structural — which thread/frame is "current" is a separate, dynamic // concern applied afterward (see SeerParallelStacksGraphicsView:: // setCurrentThreadId()/setCurrentFrameDepth()), not baked in here. struct SeerParallelStacksStack { int threadCount = 0; QVector threadIds; // IDs of every thread in this node SeerParallelStacksFrames frames; QVector stacks; }; // Method View: the graph pivots on one function. The pivot sits alone in // the callees root box; its callees branch upward from it and its callers // branch downward, toward each thread's outermost frame. struct SeerParallelStacksMethodStacks { QString pivotFunction; int threadCount = 0; // threads whose stack contains the pivot SeerParallelStacksStack callees; // root = the pivot box itself; children grow upward SeerParallelStacksStack callers; // item-less root; children grow downward }; struct SeerParallelStacksSettings { QString showMinimapMode; QString viewMode; // "Stack" or "Method" bool showFullFunctionName; int functionNameLength; bool showFullStackSize; int stackSize; bool showExternalCode; // false: merge frames without debug info into "[External Code]" }; SeerParallelStacksNode SeerParallelStacksBuildParallelStacks (const SeerParallelStacksThreads& threads); // Build the parallel-stacks tree from a flat list of threads. SeerParallelStacksStack SeerParallelStacksFillStack (const SeerParallelStacksNode& node, bool downward = false); // downward: parent box sits above its children (Method View callers). SeerParallelStacksMethodStacks SeerParallelStacksBuildMethodStacks (const SeerParallelStacksThreads& threads, const QString& pivotFunction); // Build Method View's two halves around pivotFunction. SeerParallelStacksThreads SeerParallelStacksCollapseExternalCode (const SeerParallelStacksThreads& threads, const QString& keepFunction = QString()); // Merge each run of frames without debug info into one "[External Code]" frame. Frames of keepFunction (Method View's pivot) are left alone. epasveer-seer-97076f1/src/SeerParallelStacksFilterWidget.cpp000066400000000000000000000215571526321767600241270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerParallelStacksFilterWidget.h" #include #include #include #include #include #include #include #include // Tree item roles. NameRole holds the library path, function name or // thread id; KindRole says which of the three the item is. static const int NameRole = Qt::UserRole; static const int KindRole = Qt::UserRole + 1; enum FilterItemKind { LibraryKind = 0, FunctionKind = 1, ThreadKind = 2 }; SeerParallelStacksFilterWidget::SeerParallelStacksFilterWidget (QWidget* parent) : QWidget(parent, Qt::Popup) { _searchLineEdit = new QLineEdit(this); _searchLineEdit->setPlaceholderText("Filter list"); _searchLineEdit->setClearButtonEnabled(true); _searchLineEdit->setToolTip("Narrow the list to libraries and functions containing this text (case-insensitive)."); _treeWidget = new QTreeWidget(this); _treeWidget->setColumnCount(1); _treeWidget->setHeaderHidden(true); _treeWidget->setToolTip("Check libraries, functions or threads to show only the threads that pass through them."); _clearButton = new QPushButton("Clear Filters", this); _clearButton->setToolTip("Uncheck everything and show all threads."); QHBoxLayout* searchLayout = new QHBoxLayout; searchLayout->addWidget(_searchLineEdit); searchLayout->addWidget(_clearButton); QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(4, 4, 4, 4); layout->addLayout(searchLayout); layout->addWidget(_treeWidget); resize(400, 450); // Connect things. QObject::connect(_treeWidget, &QTreeWidget::itemChanged, this, &SeerParallelStacksFilterWidget::handleItemChanged); QObject::connect(_searchLineEdit, &QLineEdit::textChanged, this, &SeerParallelStacksFilterWidget::handleSearchTextChanged); QObject::connect(_clearButton, &QPushButton::clicked, this, &SeerParallelStacksFilterWidget::handleClearButton); } SeerParallelStacksFilterWidget::~SeerParallelStacksFilterWidget () { } QString SeerParallelStacksFilterWidget::libraryOf (const SeerParallelStacksFrame& frame) { if (frame.from().isEmpty()) { return "(program)"; } return frame.from(); } void SeerParallelStacksFilterWidget::setThreads (const SeerParallelStacksThreads& threads, const QSet& libraries, const QSet& functions, const QSet& threadIds) { // Collect library -> function -> thread id -> thread name. QMap keeps // each level sorted, and collapses a recursive function's repeats. QMap>> tree; for (const auto& t : threads) { for (const auto& f : t.frames()) { tree[libraryOf(f)][f.functionOrAddr()][t.id()] = t.name(); } } // Rebuilding sets every item's check state, which isn't a user change. QSignalBlocker blocker(_treeWidget); _treeWidget->clear(); for (auto lib = tree.cbegin(); lib != tree.cend(); ++lib) { QTreeWidgetItem* libItem = new QTreeWidgetItem(_treeWidget); libItem->setText(0, lib.key() == "(program)" ? lib.key() : QFileInfo(lib.key()).fileName()); libItem->setToolTip(0, lib.key()); libItem->setData(0, NameRole, lib.key()); libItem->setData(0, KindRole, LibraryKind); libItem->setFlags(libItem->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate); for (auto func = lib.value().cbegin(); func != lib.value().cend(); ++func) { QTreeWidgetItem* funcItem = new QTreeWidgetItem(libItem); funcItem->setText(0, func.key()); funcItem->setToolTip(0, QString("%1\n%2 thread%3").arg(func.key()).arg(func.value().size()).arg(func.value().size() == 1 ? "" : "s")); funcItem->setData(0, NameRole, func.key()); funcItem->setData(0, KindRole, FunctionKind); funcItem->setFlags(funcItem->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate); for (auto thr = func.value().cbegin(); thr != func.value().cend(); ++thr) { QTreeWidgetItem* threadItem = new QTreeWidgetItem(funcItem); threadItem->setText(0, thr.value().isEmpty() ? QString("Thread %1").arg(thr.key()) : QString("Thread %1 (%2)").arg(thr.key()).arg(thr.value())); threadItem->setData(0, NameRole, thr.key()); threadItem->setData(0, KindRole, ThreadKind); threadItem->setFlags(threadItem->flags() | Qt::ItemIsUserCheckable); // Only the leaves are set. Auto-tristate parents derive their // own state from them. bool checked = libraries.contains(lib.key()) || functions.contains(func.key()) || threadIds.contains(thr.key()); threadItem->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked); } } libItem->setExpanded(true); } // Reapply the list's own narrowing to the new items. handleSearchTextChanged(_searchLineEdit->text()); } QSet SeerParallelStacksFilterWidget::libraries () const { QSet set; for (int i = 0; i < _treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem* libItem = _treeWidget->topLevelItem(i); if (libItem->checkState(0) == Qt::Checked) { set.insert(libItem->data(0, NameRole).toString()); } } return set; } QSet SeerParallelStacksFilterWidget::functions () const { QSet set; for (int i = 0; i < _treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem* libItem = _treeWidget->topLevelItem(i); // A fully checked library already covers its functions. if (libItem->checkState(0) != Qt::PartiallyChecked) { continue; } for (int j = 0; j < libItem->childCount(); ++j) { QTreeWidgetItem* funcItem = libItem->child(j); if (funcItem->checkState(0) == Qt::Checked) { set.insert(funcItem->data(0, NameRole).toString()); } } } return set; } QSet SeerParallelStacksFilterWidget::threadIds () const { QSet set; for (int i = 0; i < _treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem* libItem = _treeWidget->topLevelItem(i); if (libItem->checkState(0) != Qt::PartiallyChecked) { continue; } for (int j = 0; j < libItem->childCount(); ++j) { QTreeWidgetItem* funcItem = libItem->child(j); // A fully checked function already covers its threads. if (funcItem->checkState(0) != Qt::PartiallyChecked) { continue; } for (int k = 0; k < funcItem->childCount(); ++k) { QTreeWidgetItem* threadItem = funcItem->child(k); if (threadItem->checkState(0) == Qt::Checked) { set.insert(threadItem->data(0, NameRole).toInt()); } } } } return set; } void SeerParallelStacksFilterWidget::handleItemChanged (QTreeWidgetItem* item, int column) { Q_UNUSED(item); Q_UNUSED(column); emitFilterChanged(); } void SeerParallelStacksFilterWidget::handleSearchTextChanged (const QString& text) { // A library is shown if it, or any of its functions, matches. A // function is shown if it or its library matches. Threads follow their // function. for (int i = 0; i < _treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem* libItem = _treeWidget->topLevelItem(i); bool libMatch = text.isEmpty() || libItem->data(0, NameRole).toString().contains(text, Qt::CaseInsensitive); bool anyFunc = false; for (int j = 0; j < libItem->childCount(); ++j) { QTreeWidgetItem* funcItem = libItem->child(j); bool funcMatch = libMatch || funcItem->text(0).contains(text, Qt::CaseInsensitive); funcItem->setHidden(!funcMatch); anyFunc = anyFunc || funcMatch; } libItem->setHidden(!libMatch && !anyFunc); } } void SeerParallelStacksFilterWidget::handleClearButton () { // Unchecking the libraries cascades to everything under them. for (int i = 0; i < _treeWidget->topLevelItemCount(); ++i) { _treeWidget->topLevelItem(i)->setCheckState(0, Qt::Unchecked); } emitFilterChanged(); } void SeerParallelStacksFilterWidget::emitFilterChanged () { // Checking a parent cascades an itemChanged for every item under it. // Coalesce them into one filterChanged once the cascade is done. if (_changePending) { return; } _changePending = true; QTimer::singleShot(0, this, [this]() { _changePending = false; emit filterChanged(); }); } epasveer-seer-97076f1/src/SeerParallelStacksFilterWidget.h000066400000000000000000000045211526321767600235640ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerParallelStacksCommon.h" #include #include #include #include #include #include // Popup for the ParallelStacks filter (like Visual Studio's). A checkable // tree of library -> function -> thread, built from every frame of every // thread. Checking an item keeps only the threads that pass through it. // // The selection is reported as three sets, so it can be reapplied by name // after a refresh: // // libraries() fully checked libraries. // functions() fully checked functions not covered by a checked library. // threadIds() individually checked threads under a partially checked function. class SeerParallelStacksFilterWidget : public QWidget { Q_OBJECT public: explicit SeerParallelStacksFilterWidget (QWidget* parent = 0); ~SeerParallelStacksFilterWidget (); void setThreads (const SeerParallelStacksThreads& threads, const QSet& libraries, const QSet& functions, const QSet& threadIds); QSet libraries () const; QSet functions () const; QSet threadIds () const; // A frame's library: the 'from' shared object, or "(program)" for // frames that have none (the executable itself). static QString libraryOf (const SeerParallelStacksFrame& frame); signals: void filterChanged (); protected slots: void handleItemChanged (QTreeWidgetItem* item, int column); void handleSearchTextChanged (const QString& text); void handleClearButton (); private: void emitFilterChanged (); QLineEdit* _searchLineEdit; QTreeWidget* _treeWidget; QPushButton* _clearButton; bool _changePending = false; }; epasveer-seer-97076f1/src/SeerParallelStacksGraphicsView.cpp000066400000000000000000001642071526321767600241310ustar00rootroot00000000000000#include "SeerParallelStacksGraphicsView.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include class SeerParallelStacksPopupTableWidget; // ================================================================ // Theme-aware palette. SeerParallelStacksGraphicsView::setColorTheme() // resolves "auto"/"light"/"dark" (mirroring Seer::colorizeChartViewItem()) // and flips g_darkTheme; the box/edge/minimap paint() methods below all // read colors from here so they stay in sync with the app's color scheme. // ================================================================ namespace { struct BoxColors { QColor background; QColor activeBackground; QColor border; QColor headerText; QColor divider; QColor frameText; QColor dragOutline; QColor searchBackground; QColor searchOutline; }; struct MiniMapColors { QColor panelBackground; QColor panelBorder; QColor boxMarker; QColor viewportFill; QColor viewportBorder; QColor searchMarker; }; bool g_darkTheme = false; const BoxColors& boxColors () { static const BoxColors light { QColor(0xFA, 0xFA, 0xFA), QColor(0xFF, 0xF3, 0xC4), QColor(0x88, 0x88, 0x88), QColor(0x22, 0x22, 0x22), QColor(0xCC, 0xCC, 0xCC), QColor(0x00, 0x7A, 0x33), QColor(0x1A, 0x52, 0xA8), QColor(0xFF, 0xC8, 0x8A), QColor(0xE0, 0x6C, 0x00) }; static const BoxColors dark { QColor(0x3A, 0x3A, 0x3A), QColor(0x5A, 0x4A, 0x1A), QColor(0x77, 0x77, 0x77), QColor(0xEE, 0xEE, 0xEE), QColor(0x5A, 0x5A, 0x5A), QColor(0x4C, 0xD9, 0x87), QColor(0x6F, 0xA8, 0xF0), QColor(0x8A, 0x4A, 0x10), QColor(0xFF, 0x9A, 0x3C) }; return g_darkTheme ? dark : light; } QColor edgeColor () { static const QColor light(0x55, 0x55, 0x55); static const QColor dark (0xBB, 0xBB, 0xBB); return g_darkTheme ? dark : light; } const MiniMapColors& miniMapColors () { static const MiniMapColors light { QColor(0xFF, 0xFF, 0xFF, 230), QColor(0x88, 0x88, 0x88), QColor(0x5A, 0x8F, 0xD6), QColor(0x1A, 0x52, 0xA8, 40), QColor(0x1A, 0x52, 0xA8), QColor(0xE0, 0x6C, 0x00) }; static const MiniMapColors dark { QColor(0x2B, 0x2B, 0x2B, 230), QColor(0x77, 0x77, 0x77), QColor(0x6F, 0xA8, 0xF0), QColor(0x6F, 0xA8, 0xF0, 60), QColor(0x6F, 0xA8, 0xF0), QColor(0xFF, 0x9A, 0x3C) }; return g_darkTheme ? dark : light; } QColor viewBackground () { static const QColor light(0xF0, 0xF0, 0xF0); static const QColor dark (0x2B, 0x2B, 0x2B); return g_darkTheme ? dark : light; } // The SeerParallelStacksGraphicsView an item lives in, if any. SeerParallelStacksGraphicsView* viewOf (const QGraphicsItem* item) { if (item && item->scene() && !item->scene()->views().isEmpty()) { return qobject_cast(item->scene()->views().first()); } return nullptr; } } // ================================================================ // SeerParallelStacksStackBoxItem // ================================================================ SeerParallelStacksStackBoxItem::SeerParallelStacksStackBoxItem(const SeerParallelStacksStack& stack, const SeerParallelStacksSettings& settings, QGraphicsItem* parent) : QGraphicsItem(parent) { // Enable geometry-change notifications so itemChange() fires on setPos() setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); setAcceptHoverEvents(true); _hoverTimer = new QTimer(this); _hoverTimer->setSingleShot(true); _hoverTimer->setInterval(_kHoverDelayMs); QObject::connect(_hoverTimer, &QTimer::timeout, this, &SeerParallelStacksStackBoxItem::handleShowPopup); _headerLeft = QString("%1 Thread%2").arg(stack.threadCount).arg(stack.threadCount == 1 ? "" : "s"); _stack = stack; _settings = settings; _threadIds = stack.threadIds; // the header shows only the count; the ids are listed in the hover popup // _isActiveStack starts false; the owning view sets it via // setHighlightedThreadId() right after building the graph. // Precompute the frame rows to draw, honoring the stack-size setting. buildFrameRows(); _frameRowMatches.fill(false, _frameRows.size()); QFont boldFont; boldFont.setBold(true); QFontMetrics boldFm(boldFont); qreal headerW = boldFm.horizontalAdvance(_headerLeft); qreal maxTextW = headerW; // Highlighting is applied later (see setHighlightedFrameDepth()), so any // row could end up bold — always measure with boldFm to leave room for // that, rather than trying to guess which row it'll be. for (const auto& row : _frameRows) { if (_settings.showFullFunctionName) { maxTextW = std::max(maxTextW, (qreal)boldFm.horizontalAdvance(row)); }else{ maxTextW = std::max(maxTextW, (qreal)boldFm.horizontalAdvance(Seer::elideText(row, Qt::ElideMiddle, _settings.functionNameLength))); } } _width = maxTextW + 2 * _kPadX; _height = _kPadY + _kRowH * (1 + (int)_frameRows.size()) + _kPadY; } void SeerParallelStacksStackBoxItem::buildFrameRows() { _frameRows.clear(); _frameRowDepths.clear(); _frameRowHidden.clear(); auto appendFrame = [this](const SeerParallelStacksFrame& frame) { _frameRows.append(frame.functionOrAddr()); _frameRowDepths.append(frame.depth()); _frameRowHidden.append(frame.externalFunctions()); }; const int frameCount = (int)_stack.frames.size(); // Show every frame when asked to, or when the stack is already small // enough, or when the limit isn't a sane positive number. if (_settings.showFullStackSize || _settings.stackSize <= 0 || frameCount <= _settings.stackSize) { for (const auto& frame : _stack.frames) { appendFrame(frame); } return; } // Split the allowed frame count in half: top frames from the front, // the remainder from the back, with a single "[...]" row standing in // for the removed middle frames. const int topCount = _settings.stackSize / 2; const int bottomCount = _settings.stackSize - topCount; for (int i = 0; i < topCount; ++i) { appendFrame(_stack.frames[i]); } QStringList hidden; for (int i = topCount; i < frameCount - bottomCount; ++i) { hidden.append(_stack.frames[i].functionOrAddr()); hidden.append(_stack.frames[i].externalFunctions()); } _frameRows.append("[...]"); _frameRowDepths.append(kNoFrameDepth); _frameRowHidden.append(hidden); for (int i = frameCount - bottomCount; i < frameCount; ++i) { appendFrame(_stack.frames[i]); } } SeerParallelStacksStackBoxItem::~SeerParallelStacksStackBoxItem() { // Tell every edge that still points at us to forget about it. // This must run BEFORE this object's memory is freed, regardless of // whether the scene destroys this box or its edges first — it prevents // the edges' own destructors (and any pending itemChange callbacks) // from dereferencing a dangling pointer back to this item. for (SeerParallelStacksLiveEdge* e : _edges) { e->detachEndpoint(this); } _edges.clear(); // A rebuild (refresh, or a Method View re-pivot) can destroy this box // while its popup is open. The popup is a parentless top-level window, // so it would otherwise stay on screen, orphaned. deleteLater() since // this may run from inside one of the popup's own signals. if (_popup) { _popup->deleteLater(); _popup = nullptr; } } QRectF SeerParallelStacksStackBoxItem::boundingRect() const { return QRectF(0, 0, _width, _height); } void SeerParallelStacksStackBoxItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) { painter->setRenderHint(QPainter::Antialiasing); const BoxColors& colors = boxColors(); painter->setBrush(_isActiveStack ? colors.activeBackground : colors.background); if (_isCurrentSearchMatch) { painter->setPen(QPen(colors.searchOutline, 3.0)); }else{ painter->setPen(_isPivot ? QPen(colors.dragOutline, 3.0) : QPen(colors.border, 1.5)); } painter->drawRoundedRect(boundingRect(), 6, 6); QFont boldFont; boldFont.setBold(true); QFont normFont; const qreal innerW = _width - 2 * _kPadX; qreal y = _kPadY; painter->setFont(boldFont); painter->setPen(colors.headerText); painter->drawText(QRectF(_kPadX, y, innerW, _kRowH), Qt::AlignCenter, _headerLeft); y += _kRowH; painter->setPen(QPen(colors.divider, 1)); painter->drawLine(QPointF(0, y), QPointF(_width, y)); painter->setPen(colors.frameText); for (int i = 0; i < _frameRows.size(); ++i) { const QString& row = _frameRows[i]; // _highlightedFrameDepth is a single value shared by the whole tree, // so gate it on _isActiveStack too — otherwise every box with a // frame at that depth (e.g. depth 1, which nearly all of them have) // would bold a row, not just the debugger's actual current // thread/frame. bool isCurrentFrame = _isActiveStack && _frameRowDepths[i] != kNoFrameDepth && _frameRowDepths[i] == _highlightedFrameDepth; if (_frameRowMatches[i]) { painter->fillRect(QRectF(_kPadX / 2.0, y + 1, _width - _kPadX, _kRowH - 2), colors.searchBackground); } painter->setFont(isCurrentFrame ? boldFont : normFont); if (_settings.showFullFunctionName) { painter->drawText(QRectF(_kPadX, y, innerW, _kRowH), Qt::AlignLeft | Qt::AlignVCenter, row); }else{ painter->drawText(QRectF(_kPadX, y, innerW, _kRowH), Qt::AlignLeft | Qt::AlignVCenter, Seer::elideText(row, Qt::ElideMiddle, _settings.functionNameLength)); } y += _kRowH; } if (_dragging) { painter->setBrush(Qt::NoBrush); painter->setPen(QPen(colors.dragOutline, 2.0, Qt::DashLine)); painter->drawRoundedRect(boundingRect().adjusted(1, 1, -1, -1), 6, 6); } } qreal SeerParallelStacksStackBoxItem::width() const { return _width; } qreal SeerParallelStacksStackBoxItem::height() const { return _height; } void SeerParallelStacksStackBoxItem::registerEdge(SeerParallelStacksLiveEdge* e) { _edges.append(e); } void SeerParallelStacksStackBoxItem::unregisterEdge(SeerParallelStacksLiveEdge* e) { _edges.removeAll(e); } QPointF SeerParallelStacksStackBoxItem::sceneBottom() const { return mapToScene(QPointF(_width / 2.0, _height)); } QPointF SeerParallelStacksStackBoxItem::sceneTop() const { return mapToScene(QPointF(_width / 2.0, 0)); } void SeerParallelStacksStackBoxItem::setHighlightedThreadId(int threadId) { bool active = (threadId >= 0) && _stack.threadIds.contains(threadId); if (active == _isActiveStack) { return; } _isActiveStack = active; update(); } void SeerParallelStacksStackBoxItem::setHighlightedFrameDepth(int frameDepth) { if (frameDepth == _highlightedFrameDepth) { return; } _highlightedFrameDepth = frameDepth; update(); } void SeerParallelStacksStackBoxItem::setPivot(bool flag) { if (flag == _isPivot) { return; } _isPivot = flag; update(); } int SeerParallelStacksStackBoxItem::setSearchExpression(const QRegularExpression& re) { const bool active = re.isValid() && re.pattern().isEmpty() == false; int count = 0; for (int i = 0; i < _frameRows.size(); ++i) { bool match = false; if (active) { // A "[...]" row matches only through the frames it hides. match = _frameRowDepths[i] != kNoFrameDepth && re.match(_frameRows[i]).hasMatch(); for (int h = 0; match == false && h < _frameRowHidden[i].size(); ++h) { match = re.match(_frameRowHidden[i][h]).hasMatch(); } } _frameRowMatches[i] = match; if (match) { count++; } } _isCurrentSearchMatch = false; update(); return count; } bool SeerParallelStacksStackBoxItem::hasSearchMatch() const { return _frameRowMatches.contains(true); } void SeerParallelStacksStackBoxItem::setCurrentSearchMatch(bool flag) { if (flag == _isCurrentSearchMatch) { return; } _isCurrentSearchMatch = flag; update(); } QVariant SeerParallelStacksStackBoxItem::itemChange(GraphicsItemChange change, const QVariant& value) { if (change == ItemPositionHasChanged) { for (SeerParallelStacksLiveEdge* e : _edges) { e->update(); // ask each connected edge to repaint } } return QGraphicsItem::itemChange(change, value); } void SeerParallelStacksStackBoxItem::mousePressEvent(QGraphicsSceneMouseEvent* event) { if (event->button() == Qt::LeftButton && event->modifiers() & Qt::ShiftModifier) { _dragging = true; _dragOffset = event->pos(); // A node being dragged must not show its popup. Cancel any pending // popup and tear down one that's already visible. _hoverTimer->stop(); handleDeletePopup(); setZValue(10); update(); if (auto* v = viewOf(this)) v->beginNodeDragScroll(); event->accept(); return; } QGraphicsItem::mousePressEvent(event); } void SeerParallelStacksStackBoxItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { if (_dragging) { setPos(mapToScene(event->pos() - _dragOffset)); event->accept(); return; } QGraphicsItem::mouseMoveEvent(event); } void SeerParallelStacksStackBoxItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { if (_dragging && event->button() == Qt::LeftButton) { _dragging = false; setZValue(0); update(); if (auto* v = viewOf(this)) v->endDragScroll(); // The drag suppressed the popup and no fresh hoverEnterEvent will // arrive (the mouse never left the node). If it's still hovering, // restart the delay so the popup can appear again. if (isUnderMouse() && _popup == nullptr) { _hoverTimer->start(); } event->accept(); return; } QGraphicsItem::mouseReleaseEvent(event); } void SeerParallelStacksStackBoxItem::hoverEnterEvent(QGraphicsSceneHoverEvent* event) { QGraphicsItem::hoverEnterEvent(event); if (_popup == nullptr) { _hoverTimer->start(); } } void SeerParallelStacksStackBoxItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { QGraphicsItem::hoverLeaveEvent(event); // Cancel a pending popup if the mouse left before the delay elapsed. _hoverTimer->stop(); // A popup that's already showing stays up if the mouse just moved onto // it — give handleMaybeClosePopup() a moment to check for that. handleMaybeClosePopup(); } QRect SeerParallelStacksStackBoxItem::globalRect() const { QGraphicsView* view = scene()->views().first(); // scene() is always valid here QRectF sceneRect = mapToScene(boundingRect()).boundingRect(); QPoint topLeft = view->viewport()->mapToGlobal(view->mapFromScene(sceneRect.topLeft())); QPoint bottomRight = view->viewport()->mapToGlobal(view->mapFromScene(sceneRect.bottomRight())); return QRect(topLeft, bottomRight); } void SeerParallelStacksStackBoxItem::handleShowPopup() { if (_popup != nullptr) { return; } // Don't pop up while the node is being dragged. if (_dragging) { return; } QString frame; if (_stack.frames.size() > 0) { frame = _stack.frames[0].functionOrAddr(); } // Match the graph's current highlighted thread — there's no such thing // as "gdb's real current thread" at this level any more (the stack tree // is now purely structural); the view is the sole source of that. int currentThreadId = -1; if (auto* v = viewOf(this)) { currentThreadId = v->currentThreadId(); } _popup = new SeerParallelStacksPopupTableWidget(); _popup->setCurrentThreadId(currentThreadId); for (const auto& id : _threadIds) { _popup->addRow(id, frame); } // Position below the item, aligned to its left edge _popup->move(globalRect().bottomLeft()); _popup->show(); QObject::connect(_popup, &SeerParallelStacksPopupTableWidget::mouseLeftPopup, this, &SeerParallelStacksStackBoxItem::handleMaybeClosePopup); QObject::connect(_popup, &SeerParallelStacksPopupTableWidget::selectedThread, this, &SeerParallelStacksStackBoxItem::selectedThread); } void SeerParallelStacksStackBoxItem::handleMaybeClosePopup() { if (_popup == nullptr) { return; } // The mouse may have simply crossed from the node onto the popup (or // vice versa) — give that a moment to register before deciding the // mouse has truly left both, then re-check with the cursor's live // position rather than relying on possibly-stale hover state. QTimer::singleShot(_kCloseGraceMs, this, [this]() { if (_popup == nullptr) { return; } bool overNode = globalRect().contains(QCursor::pos()); bool overPopup = _popup->frameGeometry().contains(QCursor::pos()); if (overNode == false && overPopup == false) { handleDeletePopup(); } }); } void SeerParallelStacksStackBoxItem::handleDeletePopup() { if (_popup) { delete _popup; _popup = nullptr; } } // ================================================================ // SeerParallelStacksLiveEdge — redraws itself each paint() from current endpoint positions // ================================================================ SeerParallelStacksLiveEdge::SeerParallelStacksLiveEdge(SeerParallelStacksStackBoxItem* from, SeerParallelStacksStackBoxItem* to, QGraphicsItem* parent) : QGraphicsItem(parent) , _from(from) , _to(to) { setZValue(-1); // Position the edge item at the scene origin; all coordinates are scene-space. setPos(0, 0); // Edges are purely decorative and must never intercept mouse input. // Without this, QGraphicsView::itemAt() / scene hit-testing uses the // default shape() (== boundingRect(), which includes generous padding // for the bezier + arrowhead) and would report a LiveEdge under the // cursor for most clicks near/between boxes — silently swallowing // both box-grab and background-pan attempts before they ever reach // StackBoxItem or the view's own mousePressEvent. setAcceptedMouseButtons(Qt::NoButton); _from->registerEdge(this); _to->registerEdge(this); } SeerParallelStacksLiveEdge::~SeerParallelStacksLiveEdge() { // If our endpoints are still alive, tell them to forget about us so // they don't later call update() on a dangling SeerParallelStacksLiveEdge* during // itemChange(). detachEndpoint() is a no-op if the endpoint has // already nulled itself out via SeerParallelStacksStackBoxItem::~SeerParallelStacksStackBoxItem(). if (_from) _from->unregisterEdge(this); if (_to) _to->unregisterEdge(this); } void SeerParallelStacksLiveEdge::detachEndpoint(SeerParallelStacksStackBoxItem* box) { if (_from == box) _from = nullptr; if (_to == box) _to = nullptr; } QRectF SeerParallelStacksLiveEdge::boundingRect() const { // Return the bounding rect of the two endpoints plus generous padding // so the bezier and arrowhead are never clipped. if (!_from || !_to) return QRectF(); QPointF f = _from->sceneBottom(); QPointF t = _to->sceneTop(); qreal pad = _kArrow + _kVCtrl + 4; return QRectF(f, t).normalized().adjusted(-pad, -pad, pad, pad); } QPainterPath SeerParallelStacksLiveEdge::shape() const { // Empty path == this item is never returned by hit-testing // (QGraphicsScene::itemAt, collidingItems, etc.). boundingRect() // above is intentionally large (it just needs to avoid clipping the // curve/arrowhead during paint), so without this override the edge // would otherwise swallow clicks meant for boxes or the background. return QPainterPath(); } void SeerParallelStacksLiveEdge::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) { if (!_from || !_to) return; painter->setRenderHint(QPainter::Antialiasing); QPointF from = _from->sceneBottom(); QPointF to = _to->sceneTop(); // --- Arrowhead: tip touches the child box bottom (`from`), // base is _kArrow further along toward `to`. // The bezier starts at the base so the line never overlaps the head. QPointF delta = to - from; double len = std::hypot(delta.x(), delta.y()); if (len < 1e-6) return; QPointF dir = delta / len; // unit vector from→to QPointF perp(-dir.y(), dir.x()); // perpendicular QPointF tip = from; // touches child box QPointF base = from + dir * _kArrow; // where the line begins QPointF a1 = base + perp * (_kArrow * 0.5); QPointF a2 = base - perp * (_kArrow * 0.5); // Bezier runs from the arrowhead base to the parent box top. QPainterPath path; path.moveTo(base); path.cubicTo(base + QPointF(0, _kVCtrl), to + QPointF(0, -_kVCtrl), to); const QColor color = edgeColor(); painter->setPen(QPen(color, 1.5)); painter->setBrush(Qt::NoBrush); painter->drawPath(path); QPolygonF arrowHead; arrowHead << tip << a1 << a2; painter->setPen(Qt::NoPen); painter->setBrush(color); painter->drawPolygon(arrowHead); } // ================================================================ // SeerParallelStacksMiniMapWidget // ================================================================ SeerParallelStacksMiniMapWidget::SeerParallelStacksMiniMapWidget(SeerParallelStacksGraphicsView* view, QWidget* parent) : QWidget(parent) , _view(view) { setAttribute(Qt::WA_NoSystemBackground, false); setCursor(Qt::PointingHandCursor); setToolTip(QStringLiteral("Click or drag to jump around the graph.\nShift + drag to move the minimap.")); resize(sizeHint()); } QRectF SeerParallelStacksMiniMapWidget::contentRect() const { // Inset by a small margin so the border isn't drawn flush against // the widget edge. return QRectF(rect()).adjusted(2, 2, -2, -2); } void SeerParallelStacksMiniMapWidget::refresh() { update(); } QRectF SeerParallelStacksMiniMapWidget::overviewSceneRect() const { if (!_view || !_view->scene()) { return QRectF(); } QRectF r; for (QGraphicsItem* item : _view->scene()->items()) { if (dynamic_cast(item)) { r = r.united(item->sceneBoundingRect()); } } // Always keep the current visible region in frame so the viewport marker // stays inside the overview. r = r.united(_view->mapToScene(_view->viewport()->rect()).boundingRect()); if (r.isEmpty()) { r = _view->sceneRect(); } return r.adjusted(-20, -20, 20, 20); } void SeerParallelStacksMiniMapWidget::paintEvent(QPaintEvent* ) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); const MiniMapColors& colors = miniMapColors(); // Panel background painter.setBrush(colors.panelBackground); painter.setPen(QPen(colors.panelBorder, 1.5)); painter.drawRoundedRect(rect().adjusted(0, 0, -1, -1), 6, 6); if (!_view || !_view->scene()) { return; } const QRectF sceneRect = overviewSceneRect(); if (sceneRect.isEmpty()) { return; } const QRectF avail = contentRect(); // Compute a uniform scale that fits the whole scene into the // available area while preserving aspect ratio, then centre it. const qreal sx = avail.width() / sceneRect.width(); const qreal sy = avail.height() / sceneRect.height(); const qreal s = std::min(sx, sy); const qreal drawW = sceneRect.width() * s; const qreal drawH = sceneRect.height() * s; const QPointF origin(avail.left() + (avail.width() - drawW) / 2.0, avail.top() + (avail.height() - drawH) / 2.0); auto sceneToWidget = [&](const QPointF& p) -> QPointF { return origin + QPointF((p.x() - sceneRect.left()) * s, (p.y() - sceneRect.top()) * s); }; // Draw a small marker for every SeerParallelStacksStackBoxItem so the overall shape // of the graph is recognisable at a glance. painter.setPen(Qt::NoPen); // Boxes holding a search match stand out in their own color. for (QGraphicsItem* item : _view->scene()->items()) { if (auto* box = dynamic_cast(item)) { QRectF r(sceneToWidget(box->sceneBoundingRect().topLeft()), sceneToWidget(box->sceneBoundingRect().bottomRight())); if (r.width() < 2) r.setWidth(2); if (r.height() < 2) r.setHeight(2); painter.setBrush(box->hasSearchMatch() ? colors.searchMarker : colors.boxMarker); painter.drawRoundedRect(r, 1, 1); } } // Draw the main view's current visible region as an outlined box. const QRectF visibleScene = _view->mapToScene(_view->viewport()->rect()).boundingRect(); QRectF viewportMarker(sceneToWidget(visibleScene.topLeft()), sceneToWidget(visibleScene.bottomRight())); painter.setBrush(colors.viewportFill); painter.setPen(QPen(colors.viewportBorder, 1.5)); painter.drawRect(viewportMarker); } void SeerParallelStacksMiniMapWidget::jumpToWidgetPos(const QPoint& widgetPos) { if (!_view || !_view->scene()) return; const QRectF sceneRect = overviewSceneRect(); if (sceneRect.isEmpty()) return; const QRectF avail = contentRect(); const qreal sx = avail.width() / sceneRect.width(); const qreal sy = avail.height() / sceneRect.height(); const qreal s = std::min(sx, sy); const qreal drawW = sceneRect.width() * s; const qreal drawH = sceneRect.height() * s; const QPointF origin(avail.left() + (avail.width() - drawW) / 2.0, avail.top() + (avail.height() - drawH) / 2.0); // Inverse of sceneToWidget() const QPointF scenePos( sceneRect.left() + (widgetPos.x() - origin.x()) / s, sceneRect.top() + (widgetPos.y() - origin.y()) / s); // An anchored (Shift-dragged) minimap travels with the graph, so // centering the view would scroll it out from under the cursor. // Re-anchor it at its current on-screen spot so it stays put while // being used to navigate. const QPoint before = pos(); _view->centerOn(scenePos); if (_view->_miniMapAnchored) { _view->placeMiniMapAt(before); } refresh(); } void SeerParallelStacksMiniMapWidget::mousePressEvent(QMouseEvent* event) { // Shift + left-drag repositions the minimap widget itself. if (event->button() == Qt::LeftButton && (event->modifiers() & Qt::ShiftModifier)) { _moving = true; _moveGrabOffset = event->pos(); setCursor(Qt::ClosedHandCursor); if (_view) _view->beginMiniMapDragScroll(); event->accept(); return; } if (event->button() == Qt::LeftButton) { _dragging = true; jumpToWidgetPos(event->pos()); event->accept(); return; } QWidget::mousePressEvent(event); } void SeerParallelStacksMiniMapWidget::mouseMoveEvent(QMouseEvent* event) { if (_moving) { const QPoint topLeft = mapToParent(event->pos()) - _moveGrabOffset; if (_view) { _view->placeMiniMapAt(topLeft); _view->updateDragScroll(_view->viewport()->mapFromGlobal(mapToGlobal(event->pos()))); }else{ move(topLeft); } event->accept(); return; } if (_dragging) { jumpToWidgetPos(event->pos()); event->accept(); return; } QWidget::mouseMoveEvent(event); } void SeerParallelStacksMiniMapWidget::mouseReleaseEvent(QMouseEvent* event) { if (_moving && event->button() == Qt::LeftButton) { _moving = false; setCursor(Qt::PointingHandCursor); if (_view) _view->endDragScroll(); event->accept(); return; } if (_dragging && event->button() == Qt::LeftButton) { _dragging = false; event->accept(); return; } QWidget::mouseReleaseEvent(event); } // ================================================================ // SeerParallelStacksPopupTableWidget // ================================================================ SeerParallelStacksPopupTableWidget::SeerParallelStacksPopupTableWidget(QWidget* parent) : QFrame(parent) { // Frameless, no taskbar entry. Using Qt::Window instead of Qt::Popup // here because Qt::Popup grabs the mouse and can interfere with // leaveEvent delivery on some platforms. setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); // Visible frame around the table setCurrentThreadId(0); setFrameShape(QFrame::Box); setFrameShadow(QFrame::Plain); setLineWidth(1); setStyleSheet( "SeerParallelStacksPopupTableWidget {" " background-color: palette(window);" " border: 1px solid #888;" " border-radius: 4px;" "}" ); // Ensure leaveEvent fires reliably even without buttons held setMouseTracking(true); _table = new QTableWidget(this); _table->setRowCount(0); _table->setColumnCount(2); _table->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); _table->setHorizontalHeaderLabels({"ThreadID","Function"}); _table->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); _table->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); _table->horizontalScrollBar()->setSingleStep(5); _table->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); _table->setMouseTracking(true); _table->viewport()->setMouseTracking(true); _table->horizontalHeader()->setStretchLastSection(true); _table->verticalHeader()->setVisible(false); _table->setEditTriggers(QAbstractItemView::NoEditTriggers); _table->setSelectionBehavior(QAbstractItemView::SelectRows); _table->setSelectionMode(QAbstractItemView::SingleSelection); _table->setFrameShape(QFrame::NoFrame); // outer QFrame provides the border _table->resizeColumnToContents(0); _table->resizeColumnToContents(1); QObject::connect(_table, &QTableWidget::itemSelectionChanged, this, &SeerParallelStacksPopupTableWidget::handleSelectionChanged); // Small padding between the outer frame border and the table itself QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(6, 6, 6, 6); layout->addWidget(_table); } void SeerParallelStacksPopupTableWidget::addRow (int threadId, const QString& frame) { int nrows = _table->rowCount(); _table->setRowCount(nrows+1); QTableWidgetItem* item0 = new QTableWidgetItem(QString::number(threadId)); item0->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); item0->setFlags(item0->flags()|Qt::ItemIsEditable); item0->setData(Qt::UserRole, threadId); QTableWidgetItem* item1 = new QTableWidgetItem(frame); item1->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter); item1->setFlags(item1->flags()|Qt::ItemIsEditable); _table->setItem(nrows, 0, item0); _table->setItem(nrows, 1, item1); _table->resizeColumnToContents(0); _table->resizeColumnToContents(1); refreshRowHighlights(); } void SeerParallelStacksPopupTableWidget::setCurrentThreadId (int threadId) { _currentThreadId = threadId; refreshRowHighlights(); } void SeerParallelStacksPopupTableWidget::refreshRowHighlights () { if (!_table) { return; } const QBrush highlight(boxColors().activeBackground); for (int row = 0; row < _table->rowCount(); ++row) { int rowThreadId = _table->item(row, 0)->data(Qt::UserRole).toInt(); const QBrush background = (rowThreadId == _currentThreadId) ? highlight : QBrush(); _table->item(row, 0)->setBackground(background); _table->item(row, 1)->setBackground(background); } } void SeerParallelStacksPopupTableWidget::handleSelectionChanged () { const auto selectedRows = _table->selectionModel()->selectedRows(); if (selectedRows.isEmpty()) { return; } int threadId = _table->item(selectedRows.first().row(), 0)->data(Qt::UserRole).toInt(); setCurrentThreadId(threadId); emit selectedThread(threadId); } void SeerParallelStacksPopupTableWidget::leaveEvent(QEvent* event) { QFrame::leaveEvent(event); emit mouseLeftPopup(); } // ================================================================ // SeerParallelStacksPopupTableWidget // ================================================================ constexpr qreal kHGap = 30.0; constexpr qreal kVGap = 60.0; SeerParallelStacksGraphicsView::SeerParallelStacksGraphicsView(QWidget* parent) : QGraphicsView(parent), _scene(new QGraphicsScene(this)) { setScene(_scene); setRenderHint(QPainter::Antialiasing); setDragMode(QGraphicsView::NoDrag); setTransformationAnchor(QGraphicsView::AnchorUnderMouse); setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); _miniMap = new SeerParallelStacksMiniMapWidget(this, this); _miniMap->raise(); updateMiniMapVisibility(); _autoScrollTimer.setInterval(16); // Connect things. QObject::connect(_scene, &QGraphicsScene::changed, this, &SeerParallelStacksGraphicsView::handleGrowSceneRectToFitItems); QObject::connect(_scene, &QGraphicsScene::changed, _miniMap, &SeerParallelStacksMiniMapWidget::refresh); QObject::connect(&_autoScrollTimer, &QTimer::timeout, this, &SeerParallelStacksGraphicsView::handleAutoScrollTick); } void SeerParallelStacksGraphicsView::setColorTheme (const QString& colorTheme) { bool dark = false; if (colorTheme == "auto") { #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); if (colorScheme == Qt::ColorScheme::Dark) { dark = true; }else if (colorScheme != Qt::ColorScheme::Light) { qDebug() << "Bad colorScheme of: " << colorScheme; } #endif }else if (colorTheme == "dark") { dark = true; }else if (colorTheme != "light") { qDebug() << "Bad colorTheme of: " << colorTheme; } g_darkTheme = dark; setBackgroundBrush(viewBackground()); if (_scene) { _scene->update(); } if (_miniMap) { _miniMap->update(); } } void SeerParallelStacksGraphicsView::setShowMinimapMode (const QString& mode) { if (mode == "Always" || mode == "Never" || mode == "Auto") { _showMinimapMode = mode; }else{ _showMinimapMode = "Auto"; } updateMiniMapVisibility(); } void SeerParallelStacksGraphicsView::updateMiniMapVisibility () { if (!_miniMap) { return; } bool visible = false; if (_showMinimapMode == "Always") { visible = true; }else if (_showMinimapMode == "Never") { visible = false; }else{ // "Auto" — show only when a scrollbar is active, meaning the scene // doesn't fully fit in the viewport. visible = (horizontalScrollBar()->minimum() != horizontalScrollBar()->maximum()) || (verticalScrollBar()->minimum() != verticalScrollBar()->maximum()); } _miniMap->setVisible(visible); if (visible) { _miniMap->raise(); repositionMiniMap(); growSceneForMiniMap(); } } void SeerParallelStacksGraphicsView::zoomBy(double factor, QGraphicsView::ViewportAnchor anchor) { const QGraphicsView::ViewportAnchor prev = transformationAnchor(); setTransformationAnchor(anchor); scale(factor, factor); setTransformationAnchor(prev); repositionMiniMap(); growSceneForMiniMap(); updateMiniMapVisibility(); if (_miniMap) _miniMap->refresh(); } void SeerParallelStacksGraphicsView::resetZoom() { const QRectF bounds = _scene->itemsBoundingRect(); if (bounds.isEmpty()) { resetTransform(); }else{ fitInView(bounds.adjusted(-40, -40, 40, 40), Qt::KeepAspectRatio); } repositionMiniMap(); growSceneForMiniMap(); updateMiniMapVisibility(); if (_miniMap) _miniMap->refresh(); } void SeerParallelStacksGraphicsView::wheelEvent(QWheelEvent* event) { zoomBy(event->angleDelta().y() > 0 ? 1.15 : 1.0 / 1.15, QGraphicsView::AnchorUnderMouse); } void SeerParallelStacksGraphicsView::keyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Shift) { setDragMode(QGraphicsView::ScrollHandDrag); } switch (event->key()) { case Qt::Key_Plus: case Qt::Key_Equal: // so '+' works without needing Shift zoomBy(1.15, QGraphicsView::AnchorViewCenter); event->accept(); return; case Qt::Key_Minus: case Qt::Key_Underscore: zoomBy(1.0 / 1.15, QGraphicsView::AnchorViewCenter); event->accept(); return; case Qt::Key_Escape: resetZoom(); event->accept(); return; default: break; } QGraphicsView::keyPressEvent(event); } void SeerParallelStacksGraphicsView::keyReleaseEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Shift) { setDragMode(QGraphicsView::NoDrag); } QGraphicsView::keyReleaseEvent(event); } void SeerParallelStacksGraphicsView::resizeEvent(QResizeEvent* event) { QGraphicsView::resizeEvent(event); repositionMiniMap(); updateMiniMapVisibility(); } void SeerParallelStacksGraphicsView::scrollContentsBy(int dx, int dy) { QGraphicsView::scrollContentsBy(dx, dy); // An anchored minimap travels with the graph, so re-place it on every scroll. repositionMiniMap(); updateMiniMapVisibility(); if (_miniMap) _miniMap->refresh(); } void SeerParallelStacksGraphicsView::placeMiniMapAt(const QPoint& viewTopLeft) { if (!_miniMap) return; // Turn the widget position into a scene anchor so, from now on, the // minimap travels with the graph exactly like a dragged node. const QPoint vpTopLeft = viewTopLeft - viewport()->pos(); _miniMapAnchor = mapToScene(vpTopLeft); _miniMapAnchored = true; growSceneForMiniMap(); repositionMiniMap(); } QRectF SeerParallelStacksGraphicsView::miniMapSceneRect() const { if (!_miniMap) return QRectF(); // The scene area the minimap widget currently covers (its pixel size // mapped back through the view transform). const QRect vp(mapFromScene(_miniMapAnchor), _miniMap->sizeHint()); return mapToScene(vp).boundingRect(); } void SeerParallelStacksGraphicsView::growSceneForMiniMap() { if (!_miniMap || !_miniMapAnchored || !_miniMap->isVisible()) return; // Keep the scene rect big enough to hold the minimap plus the same 40px // margin handleGrowSceneRectToFitItems() keeps around the nodes — this is // what "makes room" for it as it's dragged toward an edge. Grow only. const QRectF needed = miniMapSceneRect().adjusted(-40, -40, 40, 40); const QRectF current = _scene->sceneRect(); if (!current.contains(needed)) { _scene->setSceneRect(current.united(needed)); } } void SeerParallelStacksGraphicsView::repositionMiniMap() { if (!_miniMap) return; const QSize s = _miniMap->sizeHint(); // Until the user Shift-drags it, the minimap is pinned to the bottom-right // corner of the viewport. if (!_miniMapAnchored) { const int margin = 10; _miniMap->setGeometry(width() - s.width() - margin, height() - s.height() - margin, s.width(), s.height()); return; } // Anchored: derive the widget position from the scene anchor so it scrolls // and zooms with the graph. _miniMap->setGeometry(QRect(viewport()->pos() + mapFromScene(_miniMapAnchor), s)); } // ================================================================ // Drag-autoscroll // ================================================================ void SeerParallelStacksGraphicsView::beginNodeDragScroll() { _nodeDragScroll = true; } void SeerParallelStacksGraphicsView::beginMiniMapDragScroll() { _miniMapDragScroll = true; } void SeerParallelStacksGraphicsView::endDragScroll() { _nodeDragScroll = false; _miniMapDragScroll = false; _autoScrollVelocity = QPoint(); _autoScrollTimer.stop(); } void SeerParallelStacksGraphicsView::updateDragScroll(const QPoint& viewportPos) { if (!_nodeDragScroll && !_miniMapDragScroll) return; const QRect r = viewport()->rect(); const int band = 28; // start scrolling when the cursor is this close to an edge const int maxV = 24; // fastest scroll, px per tick // depth: how far the cursor is past the band's inner edge (>0 => push). auto push = [maxV](int depth) -> int { if (depth <= 0) return 0; return qBound(3, depth / 2 + 3, maxV); }; int vx = 0, vy = 0; vx -= push((r.left() + band) - viewportPos.x()); vx += push(viewportPos.x() - (r.right() - band)); vy -= push((r.top() + band) - viewportPos.y()); vy += push(viewportPos.y() - (r.bottom() - band)); _autoScrollVelocity = QPoint(vx, vy); if (_autoScrollVelocity.isNull()) { _autoScrollTimer.stop(); }else if (!_autoScrollTimer.isActive()) { _autoScrollTimer.start(); } } void SeerParallelStacksGraphicsView::handleAutoScrollTick() { if (_autoScrollVelocity.isNull()) { _autoScrollTimer.stop(); return; } const qreal m11 = transform().m11(); const qreal m22 = transform().m22(); const qreal sx = (m11 != 0.0) ? _autoScrollVelocity.x() / m11 : 0.0; const qreal sy = (m22 != 0.0) ? _autoScrollVelocity.y() / m22 : 0.0; // Move the dragged object in the scroll direction so, once we scroll, it // stays put under the cursor — and grow the scene to its new extent so the // scrollbars actually have somewhere to go. if (_miniMapDragScroll) { _miniMapAnchor += QPointF(sx, sy); growSceneForMiniMap(); }else if (auto* box = dynamic_cast(_scene->mouseGrabberItem())) { box->moveBy(sx, sy); handleGrowSceneRectToFitItems(); }else{ endDragScroll(); return; } horizontalScrollBar()->setValue(horizontalScrollBar()->value() + _autoScrollVelocity.x()); verticalScrollBar()->setValue(verticalScrollBar()->value() + _autoScrollVelocity.y()); if (_miniMapDragScroll) { repositionMiniMap(); } } void SeerParallelStacksGraphicsView::mousePressEvent(QMouseEvent* event) { // Background panning only kicks in for Ctrl+LMB on empty space. // If the click landed on an item (e.g. a SeerParallelStacksStackBoxItem), let the base // class dispatch it to that item — SeerParallelStacksStackBoxItem handles its own // Ctrl+LMB grab-and-move behavior. if (event->button() == Qt::LeftButton && event->modifiers() & Qt::ControlModifier && itemAt(event->pos()) == nullptr) { _panning = true; _panStartPos = event->pos(); setCursor(Qt::ClosedHandCursor); event->accept(); return; } QGraphicsView::mousePressEvent(event); } void SeerParallelStacksGraphicsView::mouseMoveEvent(QMouseEvent* event) { if (_panning) { const QPoint delta = event->pos() - _panStartPos; _panStartPos = event->pos(); horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x()); verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y()); event->accept(); return; } // Keep the autoscroll in step with a node being Shift-dragged (the minimap // widget feeds updateDragScroll() itself). if (_nodeDragScroll) { updateDragScroll(event->pos()); } QGraphicsView::mouseMoveEvent(event); } void SeerParallelStacksGraphicsView::mouseReleaseEvent(QMouseEvent* event) { if (_panning && event->button() == Qt::LeftButton) { _panning = false; setCursor(Qt::ArrowCursor); event->accept(); return; } if (event->button() == Qt::LeftButton) { endDragScroll(); } QGraphicsView::mouseReleaseEvent(event); } void SeerParallelStacksGraphicsView::setStack(const SeerParallelStacksStack& root, const SeerParallelStacksSettings& settings) { setShowMinimapMode(settings.showMinimapMode); endDragScroll(); // a rebuild invalidates any in-progress drag // Building the graph is purely structural — it doesn't touch // _currentThreadId/_currentFrameDepth or highlight anything. The caller // (SeerParallelStacksVisualizerWidget::highlightDirectedGraph()) is // responsible for re-applying the highlight afterward. _scene->clear(); if (root.threadCount == 0) { return; } auto* rootPN = new PlacedNode; buildPlacedTree(rootPN, root, settings, nullptr); // Every box on the same level (row) shares a vertical center. Level 0 // (the outermost frames) is the bottom row; callees stack upward. QVector rowH; collectRowHeights(rootPN, 0, rowH); qreal xCursor = 0; layoutTree(rootPN, xCursor, 0, rowTops(rowH, true), rowH); addEdges(rootPN); deleteTree(rootPN); fitSceneToItems(); // Boxes start unhighlighted — the caller re-applies the highlight // afterward (see SeerParallelStacksVisualizerWidget::highlightDirectedGraph()). } void SeerParallelStacksGraphicsView::setMethodStacks(const SeerParallelStacksMethodStacks& method, const SeerParallelStacksSettings& settings) { setShowMinimapMode(settings.showMinimapMode); endDragScroll(); // a rebuild invalidates any in-progress drag // Purely structural, like setStack() — highlighting is re-applied by // the caller afterward. _scene->clear(); if (method.threadCount == 0 || method.callees.frames.isEmpty()) { return; } // --- Callees: the pivot box is this tree's root, so the regular // layout leaves it at the bottom with its callees branching above. auto* calleePN = new PlacedNode; buildPlacedTree(calleePN, method.callees, settings, nullptr); SeerParallelStacksStackBoxItem* pivotItem = calleePN->item; pivotItem->setPivot(true); QVector calleeRowH; collectRowHeights(calleePN, 0, calleeRowH); qreal xCursor = 0; layoutTree(calleePN, xCursor, 0, rowTops(calleeRowH, true), calleeRowH); addEdges(calleePN); // --- Callers: laid out downward on their own, then moved so they hang // centered under the pivot. The two halves occupy separate vertical // bands, so they can't collide. auto* callerPN = new PlacedNode; buildPlacedTree(callerPN, method.callers, settings, nullptr); if (callerPN->item || callerPN->children.isEmpty() == false) { QVector callerRowH; collectRowHeights(callerPN, 0, callerRowH); qreal callerX = 0; layoutTreeDown(callerPN, callerX, 0, rowTops(callerRowH, false), callerRowH); qreal dx = calleePN->cx - callerPN->cx; qreal dy = pivotItem->y() + pivotItem->height() + kVGap; translateTree(callerPN, dx, dy); addEdgesDown(callerPN, pivotItem); } deleteTree(calleePN); deleteTree(callerPN); fitSceneToItems(); } void SeerParallelStacksGraphicsView::fitSceneToItems() { // Let the scene rect track item bounds dynamically (Qt recomputes it // automatically as items move/grow). A fixed rect set once here would // go stale once items are dragged via Ctrl+LMB, leaving the scrollbar // range clamped to the original extents at the original zoom level. _scene->setSceneRect(QRectF()); // Fit the (current) scene contents into the viewport once, then capture // that as the explicit scene rect with some padding so scrollbars have // a stable, generously-sized range to work with at any zoom level. QRectF bounds = _scene->itemsBoundingRect().adjusted(-40, -40, 40, 40); _scene->setSceneRect(bounds); fitInView(bounds, Qt::KeepAspectRatio); // Re-place the minimap for the new graph and, if it's been dragged out, // grow the scene back so it stays reachable. repositionMiniMap(); growSceneForMiniMap(); updateMiniMapVisibility(); if (_miniMap) _miniMap->refresh(); } // Record the tallest box on each level (row) of the tree. A node with a box // is on `level` and its children on `level+1`. An item-less node (only ever // the root) passes `level` straight through, so its children are level 0. void SeerParallelStacksGraphicsView::collectRowHeights(PlacedNode* pn, int level, QVector& rowH) { int childLevel = level; if (pn->item) { if (rowH.size() <= level) { rowH.resize(level + 1, 0); } rowH[level] = std::max(rowH[level], pn->item->height()); childLevel = level + 1; } for (auto* child : pn->children) { collectRowHeights(child, childLevel, rowH); } } // Top y of each row. Upward trees put level 0 at the bottom with deeper // levels stacked above it; downward trees put level 0 at the top. QVector SeerParallelStacksGraphicsView::rowTops(const QVector& rowH, bool upward) const { QVector rowTop(rowH.size(), 0); if (upward) { for (int l = rowH.size() - 2; l >= 0; --l) { rowTop[l] = rowTop[l+1] + rowH[l+1] + kVGap; } }else{ for (int l = 1; l < rowH.size(); ++l) { rowTop[l] = rowTop[l-1] + rowH[l-1] + kVGap; } } return rowTop; } void SeerParallelStacksGraphicsView::buildPlacedTree(PlacedNode* pn, const SeerParallelStacksStack& stack, const SeerParallelStacksSettings& settings, PlacedNode* parentPN) { pn->stack = stack; pn->parent = parentPN; if (!stack.frames.isEmpty()) { pn->item = new SeerParallelStacksStackBoxItem(stack, settings); _scene->addItem(pn->item); QObject::connect(pn->item, &SeerParallelStacksStackBoxItem::selectedThread, this, &SeerParallelStacksGraphicsView::handleThreadSelected); } for (const auto& child : stack.stacks) { auto* childPN = new PlacedNode; buildPlacedTree(childPN, child, settings, pn); pn->children.append(childPN); } // Order siblings from most frames to least (then most threads), left to right. std::stable_sort(pn->children.begin(), pn->children.end(), [](const PlacedNode* a, const PlacedNode* b) { if (a->stack.frames.size() != b->stack.frames.size()) { return a->stack.frames.size() > b->stack.frames.size(); } return a->stack.threadCount > b->stack.threadCount; }); } // Children sit above their parent, which is centered over them. Leaves // advance xCursor left to right. Each box is vertically centered in its // level's row (rowTop/rowH, from collectRowHeights()/rowTops()). Sets cx // (center x) and cy (bottom y). void SeerParallelStacksGraphicsView::layoutTree(PlacedNode* pn, qreal& xCursor, int level, const QVector& rowTop, const QVector& rowH) { qreal itemW = pn->item ? pn->item->width() : 0; qreal itemH = pn->item ? pn->item->height() : 0; int childLevel = pn->item ? level + 1 : level; if (pn->children.isEmpty()) { pn->cx = xCursor + itemW / 2.0; xCursor += itemW + kHGap; }else{ qreal firstCx = -1, lastCx = -1; for (auto* child : pn->children) { layoutTree(child, xCursor, childLevel, rowTop, rowH); if (firstCx < 0) firstCx = child->cx; lastCx = child->cx; } pn->cx = (firstCx + lastCx) / 2.0; } if (pn->item) { qreal y = rowTop[level] + (rowH[level] - itemH) / 2.0; pn->item->setPos(pn->cx - itemW / 2.0, y); pn->cy = y + itemH; } } // Mirror of layoutTree(): a parent sits above its children, centered over // them, and level 0 is the top row. Leaves still advance xCursor left to // right. Sets cx (center x) and cy (bottom y) the same way layoutTree() does. void SeerParallelStacksGraphicsView::layoutTreeDown(PlacedNode* pn, qreal& xCursor, int level, const QVector& rowTop, const QVector& rowH) { qreal itemW = pn->item ? pn->item->width() : 0; qreal itemH = pn->item ? pn->item->height() : 0; int childLevel = pn->item ? level + 1 : level; if (pn->children.isEmpty()) { pn->cx = xCursor + itemW / 2.0; xCursor += itemW + kHGap; }else{ qreal firstCx = -1, lastCx = -1; for (auto* child : pn->children) { layoutTreeDown(child, xCursor, childLevel, rowTop, rowH); if (firstCx < 0) firstCx = child->cx; lastCx = child->cx; } pn->cx = (firstCx + lastCx) / 2.0; // A single child that's narrower than this box would otherwise // leave the box hanging off the left of xCursor's column. xCursor = std::max(xCursor, pn->cx + itemW / 2.0 + kHGap); } if (pn->item) { qreal y = rowTop[level] + (rowH[level] - itemH) / 2.0; pn->item->setPos(pn->cx - itemW / 2.0, y); pn->cy = y + itemH; } } void SeerParallelStacksGraphicsView::translateTree(PlacedNode* pn, qreal dx, qreal dy) { pn->cx += dx; pn->cy += dy; if (pn->item) { pn->item->setPos(pn->item->x() + dx, pn->item->y() + dy); } for (auto* child : pn->children) { translateTree(child, dx, dy); } } void SeerParallelStacksGraphicsView::addEdgesDown(PlacedNode* pn, SeerParallelStacksStackBoxItem* above) { // Same direction as the Threads view: from the callee (upper box) to // its caller (lower box). An item-less node passes `above` through to // its children, so they all connect to it directly. if (pn->item && above) { _scene->addItem(new SeerParallelStacksLiveEdge(above, pn->item)); } SeerParallelStacksStackBoxItem* anchor = pn->item ? pn->item : above; for (auto* child : pn->children) { addEdgesDown(child, anchor); } } void SeerParallelStacksGraphicsView::addEdges(PlacedNode* pn) { for (auto* child : pn->children) { if (pn->item && child->item) { // SeerParallelStacksLiveEdge registers itself with both endpoints on construction. // The scene takes ownership via addItem. auto* edge = new SeerParallelStacksLiveEdge(child->item, pn->item); _scene->addItem(edge); } addEdges(child); } } void SeerParallelStacksGraphicsView::deleteTree(PlacedNode* pn) { for (auto* child : pn->children) { deleteTree(child); } delete pn; } void SeerParallelStacksGraphicsView::handleGrowSceneRectToFitItems() { if (_scene->items().isEmpty()) { return; } const QRectF current = _scene->sceneRect(); const QRectF needed = _scene->itemsBoundingRect().adjusted(-40, -40, 40, 40); // Only grow — never shrink on every change, to avoid jitter — and only // when the items actually fall outside the current rect. if (!current.contains(needed)) { _scene->setSceneRect(current.united(needed)); } updateMiniMapVisibility(); } int SeerParallelStacksGraphicsView::currentThreadId() const { return _currentThreadId; } void SeerParallelStacksGraphicsView::setCurrentThreadId(int threadId) { _currentThreadId = threadId; applyCurrentHighlight(); } void SeerParallelStacksGraphicsView::setCurrentFrameDepth(int frameDepth) { _currentFrameDepth = frameDepth; applyCurrentHighlight(); } void SeerParallelStacksGraphicsView::setCurrentHighlight(int threadId, int frameDepth) { _currentThreadId = threadId; _currentFrameDepth = frameDepth; applyCurrentHighlight(); } void SeerParallelStacksGraphicsView::handleThreadSelected(int threadId) { setCurrentThreadId(threadId); emit selectedThread(threadId); } void SeerParallelStacksGraphicsView::applyCurrentHighlight() { // Highlight every box holding the current thread — including a shared // ancestor (branch-point) box, since the thread genuinely does pass // through it too. Each box gates its own frame-depth bolding on also // being the active-thread box (see StackBoxItem::paint()). for (QGraphicsItem* item : _scene->items()) { if (auto* box = dynamic_cast(item)) { box->setHighlightedThreadId(_currentThreadId); box->setHighlightedFrameDepth(_currentFrameDepth); } } } void SeerParallelStacksGraphicsView::setSearchExpression(const QRegularExpression& re) { _searchExpression = re; _searchMatchCount = 0; _searchIndex = -1; _searchBoxes.clear(); for (QGraphicsItem* item : _scene->items()) { if (auto* box = dynamic_cast(item)) { int count = box->setSearchExpression(re); if (count > 0) { _searchMatchCount += count; _searchBoxes.append(box); } } } // Visit matches in reading order: top-to-bottom, then left-to-right. std::sort(_searchBoxes.begin(), _searchBoxes.end(), [](const QPointer& a, const QPointer& b) { const QPointF pa = a->scenePos(); const QPointF pb = b->scenePos(); return pa.y() != pb.y() ? pa.y() < pb.y() : pa.x() < pb.x(); }); if (_miniMap) _miniMap->refresh(); } int SeerParallelStacksGraphicsView::searchMatchCount() const { return _searchMatchCount; } int SeerParallelStacksGraphicsView::searchBoxCount() const { return _searchBoxes.size(); } int SeerParallelStacksGraphicsView::searchCurrentIndex() const { return _searchIndex; } void SeerParallelStacksGraphicsView::findNextSearchMatch(bool backward) { const int n = _searchBoxes.size(); if (n == 0) { return; } if (_searchIndex >= 0 && _searchIndex < n && _searchBoxes[_searchIndex]) { _searchBoxes[_searchIndex]->setCurrentSearchMatch(false); } if (_searchIndex < 0) { _searchIndex = backward ? n - 1 : 0; }else{ _searchIndex = (_searchIndex + (backward ? n - 1 : 1)) % n; } // The boxes are gone if the scene was cleared behind our back. SeerParallelStacksStackBoxItem* box = _searchBoxes[_searchIndex]; if (box == nullptr) { return; } box->setCurrentSearchMatch(true); centerOn(box); } epasveer-seer-97076f1/src/SeerParallelStacksGraphicsView.h000066400000000000000000000562151526321767600235750ustar00rootroot00000000000000#pragma once #include "SeerParallelStacksCommon.h" #include #include #include #include #include #include #include #include #include #include #include class SeerParallelStacksPopupTableWidget; class SeerParallelStacksLiveEdge; // --------------------------------------------------------------- // A single box in the graph: shows thread count + IDs + call frames. // Ctrl+LMB grabs and moves the item freely within the scene. // Moving the item automatically redraws all connected LiveEdges. // --------------------------------------------------------------- class SeerParallelStacksStackBoxItem : public QObject, public QGraphicsItem { Q_OBJECT Q_INTERFACES(QGraphicsItem) public: explicit SeerParallelStacksStackBoxItem(const SeerParallelStacksStack& stack, const SeerParallelStacksSettings& settings, QGraphicsItem* parent = nullptr); ~SeerParallelStacksStackBoxItem() override; QRectF boundingRect () const override; void paint (QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override; qreal width () const; qreal height () const; // Edge registry — called by LiveEdge on construction/destruction void registerEdge (SeerParallelStacksLiveEdge* e); void unregisterEdge (SeerParallelStacksLiveEdge* e); // Bottom-centre and top-centre in scene coordinates (edge attach points) QPointF sceneBottom () const; QPointF sceneTop () const; // Highlights this box iff its stack holds threadId (-1 clears it). // This is THE current thread for the whole graph — either gdb's real // current thread or one the user picked in a popup table — so there // is only ever one highlight, not two independent ones. void setHighlightedThreadId (int threadId); // Sets which frame depth to bold (kNoFrameDepth clears it) — depth-from-bottom // (SeerParallelStacksFrame::depth()), not the thread-relative // level() number, so this stays correct no matter which thread the // caller means by "current" (see SeerParallelStacksCommon.cpp). // Only takes visible effect when this box is also the active-thread // box (see paint()) — depth is a single value shared by the whole // tree, so without that gate nearly every box would bold a // same-depth row. void setHighlightedFrameDepth (int frameDepth); // Marks this box as Method View's pivot (drawn with a heavier, // accent-colored border). void setPivot (bool flag); // Marks every frame row whose function matches re (an empty or // invalid re clears them). A "[...]" or "[External Code]" row // matches if any of the frames it stands in for does. Returns the // number of matching rows. int setSearchExpression (const QRegularExpression& re); bool hasSearchMatch () const; // Marks this box as the search match the view last jumped to // (drawn with a search-colored border). void setCurrentSearchMatch (bool flag); signals: // Forwarded from this box's popup table when a row is selected there. void selectedThread (int threadId); protected: QVariant itemChange (GraphicsItemChange change, const QVariant& value) override; void mousePressEvent (QGraphicsSceneMouseEvent* event) override; void mouseMoveEvent (QGraphicsSceneMouseEvent* event) override; void mouseReleaseEvent (QGraphicsSceneMouseEvent* event) override; void hoverEnterEvent (QGraphicsSceneHoverEvent* event) override; void hoverLeaveEvent (QGraphicsSceneHoverEvent* event) override; private slots: void handleDeletePopup (); void handleShowPopup (); void handleMaybeClosePopup (); private: // Global (screen) rect this box occupies, used to test whether the // cursor is still over the node. QRect globalRect () const; // Fills _frameRows (and the parallel _frameRowDepths) with the // frame-row texts to draw. Honors the showFullStackSize / stackSize // settings: when the full stack is hidden, only the top and bottom // stackSize frames are shown and the removed middle ones are // replaced by a single "[...]" row. The underlying _stack.frames is // left untouched. void buildFrameRows (); QVector _edges; // non-owning QVector _threadIds; SeerParallelStacksStack _stack; QStringList _frameRows; QVector _frameRowDepths; // parallel to _frameRows; each row's frame depth() (kNoFrameDepth for a "[...]" placeholder row) QVector _frameRowMatches; // parallel to _frameRows; row matches the search expression QVector _frameRowHidden; // parallel to _frameRows; the functions a "[...]" or "[External Code]" row stands in for SeerParallelStacksSettings _settings; bool _isActiveStack = false; // holds the graph's current thread int _highlightedFrameDepth = kNoFrameDepth; // bolded iff _isActiveStack is also true bool _isPivot = false; // Method View's pivot box bool _isCurrentSearchMatch = false; // the search match last jumped to QString _headerLeft; qreal _width = 0; qreal _height = 0; SeerParallelStacksPopupTableWidget* _popup = 0; QTimer* _hoverTimer = 0; static constexpr int _kHoverDelayMs = 1000; static constexpr int _kCloseGraceMs = 150; bool _dragging = false; QPointF _dragOffset; static constexpr qreal _kPadX = 12; static constexpr qreal _kPadY = 8; static constexpr qreal _kRowH = 20; }; // --------------------------------------------------------------- // A live bezier edge between two StackBoxItems. // It redraws itself whenever either endpoint moves. // --------------------------------------------------------------- class SeerParallelStacksLiveEdge : public QGraphicsItem { public: SeerParallelStacksLiveEdge(SeerParallelStacksStackBoxItem* from, SeerParallelStacksStackBoxItem* to, QGraphicsItem* parent = nullptr); ~SeerParallelStacksLiveEdge() override; QRectF boundingRect () const override; QPainterPath shape () const override; void paint (QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override; // Called by StackBoxItem's destructor so this edge stops referencing // an endpoint that is about to be (or has been) destroyed. After this, // the edge renders nothing and its own destructor won't touch `box`. void detachEndpoint (SeerParallelStacksStackBoxItem* box); private: SeerParallelStacksStackBoxItem* _from; // child (bottom anchor) SeerParallelStacksStackBoxItem* _to; // parent (top anchor) static constexpr qreal _kArrow = 8.0; static constexpr qreal _kVCtrl = 60.0 * 0.4; // bezier control-point stretch }; class SeerParallelStacksGraphicsView; // --------------------------------------------------------------- // Small overlay widget showing the entire scene at a glance, with a // rectangle marking the main view's current visible region. Click or // drag inside it to jump/pan the main view there. Shift + left-drag // moves the minimap widget itself to a new spot in the view. // --------------------------------------------------------------- class SeerParallelStacksMiniMapWidget : public QWidget { Q_OBJECT public: explicit SeerParallelStacksMiniMapWidget(SeerParallelStacksGraphicsView* view, QWidget* parent = nullptr); QSize sizeHint () const override { return QSize(180, 140); } public slots: void refresh (); // call whenever the scene or the main view's viewport changes protected: void paintEvent (QPaintEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; private: // Maps a point in this widget to a scene position, and centers the // main view there. void jumpToWidgetPos (const QPoint& widgetPos); // The scaled rect (within this widget) that the minimap content is // drawn into, preserving the scene's aspect ratio. QRectF contentRect () const; // The scene region the overview frames: the graph's nodes plus the // current visible region (so the viewport marker is always shown), // independent of where the minimap itself has been parked. QRectF overviewSceneRect () const; SeerParallelStacksGraphicsView* _view; bool _dragging = false; // plain left-drag: navigating the graph bool _moving = false; // shift + left-drag: repositioning this widget QPoint _moveGrabOffset; // cursor offset within the widget at move start }; // A frameless popup window that wraps a QTableWidget inside a small // bordered frame. Its lifetime is owned by the SeerParallelStacksStackBoxItem // that created it — it stays up for as long as the mouse is in that node. class SeerParallelStacksPopupTableWidget : public QFrame { Q_OBJECT public: explicit SeerParallelStacksPopupTableWidget(QWidget* parent = nullptr); void addRow (int threadId, const QString& function); // Sets which row (by threadId) shows the "current thread" highlight // and restyles the rows already in the table to match. void setCurrentThreadId (int threadId); protected: void leaveEvent (QEvent* event) override; signals: void mouseLeftPopup (); void selectedThread (int threadId); private slots: void handleSelectionChanged (); private: // Recolors every row's background: highlighted iff its threadId // equals _currentThreadId. Called whenever a row is added or // _currentThreadId changes. void refreshRowHighlights (); QTableWidget* _table = nullptr; int _currentThreadId; }; class SeerParallelStacksGraphicsView : public QGraphicsView { Q_OBJECT public: explicit SeerParallelStacksGraphicsView(QWidget* parent = nullptr); void setStack (const SeerParallelStacksStack& root, const SeerParallelStacksSettings& settings); // Method View counterpart to setStack(): the pivot box in the // middle, its callees above it (laid out like the Threads view) and // its callers below it (mirrored, growing downward). void setMethodStacks (const SeerParallelStacksMethodStacks& method, const SeerParallelStacksSettings& settings); void setColorTheme (const QString& colorTheme); void setShowMinimapMode (const QString& mode); // "Always", "Never", or "Auto" // Drag-autoscroll hooks. While a node or the minimap is being dragged // near a viewport edge, the view scrolls (and grows the scene) to keep // the dragged object under the cursor. Driven by the node item and the // minimap widget. void beginNodeDragScroll (); void beginMiniMapDragScroll (); void updateDragScroll (const QPoint& viewportPos); void endDragScroll (); // The thread currently highlighted across the whole graph — gdb's // real current thread by default, or whichever one the user last // picked in a popup table. Read by a box when it opens its popup, so // the popup's own row highlighting matches the graph. int currentThreadId () const; // Restyles the graph to highlight threadId, without emitting // selectedThread() — for a caller (e.g. some other widget's own // thread selection) that already knows and doesn't need telling // back. handleThreadSelected() is the popup-driven counterpart that // does emit it. void setCurrentThreadId (int threadId); // Restyles the graph's frame bolding to frameDepth — a depth-from- // bottom value (SeerParallelStacksFrame::depth()), not a raw // thread-relative frame level; the caller (e.g. // SeerParallelStacksVisualizerWidget::handleFrameSelected(), for a // frame picked in the external stack frames browser) is responsible // for converting a level to a depth using that thread's own frame // count, since only it knows which thread the level came from. The // graph has no frame-selection UI of its own, so there's no // popup-driven counterpart to this one. void setCurrentFrameDepth (int frameDepth); // Sets both at once, restyling the graph in a single pass instead of // two — the counterpart SeerParallelStacksVisualizerWidget:: // highlightDirectedGraph() uses, since it always knows both together. void setCurrentHighlight (int threadId, int frameDepth); // Highlights every frame row, in every box, whose function matches // re (an empty or invalid re clears it). Not kept across rebuilds — // the caller re-applies it after setStack()/setMethodStacks(). void setSearchExpression (const QRegularExpression& re); int searchMatchCount () const; // matching frame rows int searchBoxCount () const; // boxes holding at least one int searchCurrentIndex () const; // index of the box last jumped to, -1 if none // Centers the view on the next (or previous) box holding a match, // wrapping around. Boxes are visited top-to-bottom, left-to-right. void findNextSearchMatch (bool backward = false); signals: // Forwarded from whichever StackBoxItem's popup table had a row selected. void selectedThread (int threadId); protected: void wheelEvent (QWheelEvent* event) override; void keyPressEvent (QKeyEvent* event) override; void keyReleaseEvent (QKeyEvent* event) override; void mousePressEvent (QMouseEvent* event) override; void mouseMoveEvent (QMouseEvent* event) override; void mouseReleaseEvent (QMouseEvent* event) override; void resizeEvent (QResizeEvent* event) override; void scrollContentsBy (int dx, int dy) override; private slots: // Grows the scene rect (and thus the scrollbar range) if items have // been dragged outside the current bounds. Connected to // QGraphicsScene::changed, which fires on item moves/repaints. void handleGrowSceneRectToFitItems (); // Fires while a drag sits near a viewport edge: nudges the scrollbars // (and the dragged object) so it keeps following the cursor. void handleAutoScrollTick (); // A thread was selected in some box's popup table. Makes it the // graph's current thread, restyles every box that holds it, and // forwards the selection on via the selectedThread signal. void handleThreadSelected (int threadId); private: struct PlacedNode { SeerParallelStacksStack stack; SeerParallelStacksStackBoxItem* item = nullptr; PlacedNode* parent = nullptr; QVector children; qreal cx = 0; qreal cy = 0; }; void buildPlacedTree (PlacedNode* pn, const SeerParallelStacksStack& stack, const SeerParallelStacksSettings& settings, PlacedNode* parentPN); void collectRowHeights (PlacedNode* pn, int level, QVector& rowH); QVector rowTops (const QVector& rowH, bool upward) const; void layoutTree (PlacedNode* pn, qreal& xCursor, int level, const QVector& rowTop, const QVector& rowH); void layoutTreeDown (PlacedNode* pn, qreal& xCursor, int level, const QVector& rowTop, const QVector& rowH); // mirror of layoutTree(): children below their parent void translateTree (PlacedNode* pn, qreal dx, qreal dy); void addEdges (PlacedNode* pn); void addEdgesDown (PlacedNode* pn, SeerParallelStacksStackBoxItem* above); // edges for a layoutTreeDown() tree hanging below `above` // Shared tail of setStack()/setMethodStacks(): sizes the scene rect // to the laid-out items, fits it into the viewport, and re-places // the minimap. void fitSceneToItems (); void deleteTree (PlacedNode* pn); // Zoom: '+'/'-' step (keyboard, centered), mouse wheel (under cursor). void zoomBy (double factor, QGraphicsView::ViewportAnchor anchor); // 'Esc' — refit the whole graph to the viewport (normal zoom level). void resetZoom (); // Places the minimap widget. Until the user Shift-drags it, this pins // it to the bottom-right corner of the viewport. Once dragged, the // minimap is anchored to a scene position and travels with the graph — // like a node — and this re-derives its widget geometry. void repositionMiniMap (); // Anchors the minimap at the scene point currently under viewTopLeft // (view coordinates). Called by the minimap widget while it is being // Shift-dragged. void placeMiniMapAt (const QPoint& viewTopLeft); // Scene rectangle the minimap widget currently covers. QRectF miniMapSceneRect () const; // Grows the scene rect so it always contains the (Shift-dragged) // minimap plus padding — the "make room for it" behavior nodes get // from handleGrowSceneRectToFitItems(). void growSceneForMiniMap (); // Shows or hides the minimap according to _showMinimapMode. In "Auto" // mode the minimap is shown only while one of the view's scrollbars is // active (i.e. the scene doesn't fully fit in the viewport). void updateMiniMapVisibility (); // Reapplies _currentThreadId's and _currentFrameDepth's highlight to // every box currently in the scene. Called after a setStack() // rebuild and whenever either is set. void applyCurrentHighlight (); QGraphicsScene* _scene; SeerParallelStacksMiniMapWidget* _miniMap; QString _showMinimapMode = "Auto"; bool _miniMapAnchored = false; // true once the user has Shift-dragged it QPointF _miniMapAnchor; // scene coords of the minimap's top-left bool _panning = false; QPoint _panStartPos; // viewport coords at pan start QTimer _autoScrollTimer; QPoint _autoScrollVelocity; // px/tick, from cursor proximity to the edges bool _nodeDragScroll = false; bool _miniMapDragScroll = false; int _currentThreadId = -1; // the graph's current thread; reset from gdb's real one on every setStack() refresh int _currentFrameDepth = kNoFrameDepth; // the graph's current frame depth(); reset from gdb's real one on every setStack() refresh QRegularExpression _searchExpression; QVector> _searchBoxes; // boxes holding a match; QPointer since a scene clear deletes them int _searchMatchCount = 0; int _searchIndex = -1; friend class SeerParallelStacksMiniMapWidget; // needs sceneRect()/mapToScene()/centerOn() access }; epasveer-seer-97076f1/src/SeerParallelStacksSettingsDialog.cpp000066400000000000000000000114541526321767600244510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerParallelStacksSettingsDialog.h" #include #include #include SeerParallelStacksSettingsDialog::SeerParallelStacksSettingsDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets setShowMinimap("Auto"); setShowFullFunctionName(true); setFunctionNameLength(64); setShowFullStackSize(true); setStackSize(20); setShowExternalCode(false); // Connect things. QObject::connect(functionNameLengthAllCheckBox, &QCheckBox::clicked, this, &SeerParallelStacksSettingsDialog::handleFunctionNameLengthClicked); QObject::connect(stackFrameSizeAllCheckBox, &QCheckBox::clicked, this, &SeerParallelStacksSettingsDialog::handleStackFrameSizeClicked); // Set UI for click buttons. handleFunctionNameLengthClicked(); handleStackFrameSizeClicked(); // Restore window settings. readSettings(); } SeerParallelStacksSettingsDialog::~SeerParallelStacksSettingsDialog () { } void SeerParallelStacksSettingsDialog::setSettings (const SeerParallelStacksSettings& settings) { setShowMinimap(settings.showMinimapMode); setShowFullFunctionName(settings.showFullFunctionName); setFunctionNameLength(settings.functionNameLength); setShowFullStackSize(settings.showFullStackSize); setStackSize(settings.stackSize); setShowExternalCode(settings.showExternalCode); handleFunctionNameLengthClicked(); handleStackFrameSizeClicked(); } SeerParallelStacksSettings SeerParallelStacksSettingsDialog::settings () const { SeerParallelStacksSettings settings; settings.showMinimapMode = showMinimap(); settings.showFullFunctionName = showFullFunctionName(); settings.functionNameLength = functionNameLength(); settings.showFullStackSize = showFullStackSize(); settings.stackSize = stackSize(); settings.showExternalCode = showExternalCode(); return settings; } void SeerParallelStacksSettingsDialog::setShowMinimap (const QString& when) { if (when == "Auto" || when == "Always" || when == "Never") { showMinimapComboBox->setCurrentText(when); }else{ showMinimapComboBox->setCurrentText("Auto"); } } QString SeerParallelStacksSettingsDialog::showMinimap () const { return showMinimapComboBox->currentText(); } void SeerParallelStacksSettingsDialog::setShowFullFunctionName (bool flag) { functionNameLengthAllCheckBox->setChecked(flag); } bool SeerParallelStacksSettingsDialog::showFullFunctionName () const { return functionNameLengthAllCheckBox->isChecked(); } void SeerParallelStacksSettingsDialog::setFunctionNameLength (int length) { functionNameLengthSpinBox->setValue(length); } int SeerParallelStacksSettingsDialog::functionNameLength () const { return functionNameLengthSpinBox->value(); } void SeerParallelStacksSettingsDialog::setShowFullStackSize (bool flag) { stackFrameSizeAllCheckBox->setChecked(flag); } bool SeerParallelStacksSettingsDialog::showFullStackSize () const { return stackFrameSizeAllCheckBox->isChecked(); } void SeerParallelStacksSettingsDialog::setStackSize (int size) { stackFrameSizeSpinBox->setValue(size); } int SeerParallelStacksSettingsDialog::stackSize () const { return stackFrameSizeSpinBox->value(); } void SeerParallelStacksSettingsDialog::setShowExternalCode (bool flag) { showExternalCodeCheckBox->setChecked(flag); } bool SeerParallelStacksSettingsDialog::showExternalCode () const { return showExternalCodeCheckBox->isChecked(); } void SeerParallelStacksSettingsDialog::handleFunctionNameLengthClicked () { if (functionNameLengthAllCheckBox->isChecked()) { functionNameLengthSpinBox->setEnabled(false); }else{ functionNameLengthSpinBox->setEnabled(true); } } void SeerParallelStacksSettingsDialog::handleStackFrameSizeClicked () { if (stackFrameSizeAllCheckBox->isChecked()) { stackFrameSizeSpinBox->setEnabled(false); }else{ stackFrameSizeSpinBox->setEnabled(true); } } void SeerParallelStacksSettingsDialog::writeSettings() { QSettings settings; settings.beginGroup("parallelstackssettingsdialog"); { settings.setValue("size", size()); }settings.endGroup(); } void SeerParallelStacksSettingsDialog::readSettings() { QSettings settings; settings.beginGroup("parallelstackssettingsdialog"); { if (settings.contains("size")) { resize(settings.value("size", QSize(400, 225)).toSize()); } } settings.endGroup(); } void SeerParallelStacksSettingsDialog::resizeEvent (QResizeEvent* event) { // Write window settings. writeSettings(); QWidget::resizeEvent(event); } epasveer-seer-97076f1/src/SeerParallelStacksSettingsDialog.h000066400000000000000000000043021526321767600241100ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerParallelStacksCommon.h" #include #include #include #include "ui_SeerParallelStacksSettingsDialog.h" class SeerParallelStacksSettingsDialog : public QDialog, protected Ui::SeerParallelStacksSettingsDialogForm { Q_OBJECT public: explicit SeerParallelStacksSettingsDialog (QWidget* parent = 0); ~SeerParallelStacksSettingsDialog (); void setSettings (const SeerParallelStacksSettings& settings); SeerParallelStacksSettings settings () const; void setShowMinimap (const QString& when); QString showMinimap () const; void setShowFullFunctionName (bool flag); bool showFullFunctionName () const; void setFunctionNameLength (int length); int functionNameLength () const; void setShowFullStackSize (bool flag); bool showFullStackSize () const; void setStackSize (int size); int stackSize () const; void setShowExternalCode (bool flag); bool showExternalCode () const; public slots: private slots: void handleFunctionNameLengthClicked (); void handleStackFrameSizeClicked (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: }; epasveer-seer-97076f1/src/SeerParallelStacksSettingsDialog.ui000066400000000000000000000146431526321767600243070ustar00rootroot00000000000000 SeerParallelStacksSettingsDialogForm 0 0 373 225 Seer - ParallelStacks Settings ParallelStacks Settings Show Minimap Keep N frames of the stack. Omit the middle frames. 1 999 5 10 Function Name Length Stack Frame Size Keep N characters of the function name. Omit the middle characters. 1 999 5 10 Keep the full length of function names. Full Keep all frames of the stack. All Show External Code Show every frame without debug info. Unchecked, each run of them is merged into a single '[External Code]' frame. Show Show the Minimap when needed, always, or never. Auto Always Never Qt::Vertical 20 4 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok groupBox buttonBox verticalSpacer showMinimapComboBox functionNameLengthAllCheckBox functionNameLengthSpinBox stackFrameSizeAllCheckBox stackFrameSizeSpinBox showExternalCodeCheckBox buttonBox accepted() SeerParallelStacksSettingsDialogForm accept() 227 179 157 199 buttonBox rejected() SeerParallelStacksSettingsDialogForm reject() 295 185 286 199 epasveer-seer-97076f1/src/SeerParallelStacksVisualizerWidget.cpp000066400000000000000000000643601526321767600250360ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerParallelStacksVisualizerWidget.h" #include "SeerParallelStacksSettingsDialog.h" #include "SeerParallelStacksFilterWidget.h" #include "SeerParallelStacksCommon.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include #include #include #include #include #include #include SeerParallelStacksVisualizerWidget::SeerParallelStacksVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _id = Seer::createID(); // ID for parallelstacks command. _settings = {"Auto", "Stack", true, 64, true, 20, false}; // Set up UI. setupUi(this); // Setup the widgets setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); setWindowTitle("Seer ParallelStacks Visualizer (BETA - please report bugs/features)"); setAttribute(Qt::WA_DeleteOnClose); // Connect things. QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerParallelStacksVisualizerWidget::handleRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerParallelStacksVisualizerWidget::handleHelpButton); QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerParallelStacksVisualizerWidget::handlePrintButton); QObject::connect(saveToolButton, &QToolButton::clicked, this, &SeerParallelStacksVisualizerWidget::handleSaveButton); QObject::connect(settingsToolButton, &QToolButton::clicked, this, &SeerParallelStacksVisualizerWidget::handleSettingsButton); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerParallelStacksVisualizerWidget::handleThemeChanged); #endif QObject::connect(graphicsView, &SeerParallelStacksGraphicsView::selectedThread, this, &SeerParallelStacksVisualizerWidget::handleGraphThreadSelected); QObject::connect(viewModeComboBox, &QComboBox::currentTextChanged, this, &SeerParallelStacksVisualizerWidget::handleViewModeChanged); QObject::connect(autoRefreshCheckBox, &QCheckBox::toggled, this, &SeerParallelStacksVisualizerWidget::writeSettings); QObject::connect(searchLineEdit, &QLineEdit::textChanged, this, &SeerParallelStacksVisualizerWidget::handleSearchTextChanged); QObject::connect(searchLineEdit, &QLineEdit::returnPressed, this, &SeerParallelStacksVisualizerWidget::handleSearchReturnPressed); QObject::connect(searchRegexCheckBox, &QCheckBox::toggled, this, &SeerParallelStacksVisualizerWidget::handleSearchRegexToggled); QObject::connect(filterToolButton, &QToolButton::clicked, this, &SeerParallelStacksVisualizerWidget::handleFilterButton); // Same search keys as the source editor. QShortcut* searchShortcut = new QShortcut(QKeySequence(tr("Ctrl+F")), this); QShortcut* searchNextShortcut = new QShortcut(QKeySequence(tr("Ctrl+G")), this); QShortcut* searchPrevShortcut = new QShortcut(QKeySequence(tr("Ctrl+Shift+G")), this); QObject::connect(searchShortcut, &QShortcut::activated, this, &SeerParallelStacksVisualizerWidget::handleSearchShortcut); QObject::connect(searchNextShortcut, &QShortcut::activated, this, &SeerParallelStacksVisualizerWidget::handleSearchNext); QObject::connect(searchPrevShortcut, &QShortcut::activated, this, &SeerParallelStacksVisualizerWidget::handleSearchPrevious); // Colorize icons and the graph for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); graphicsView->setColorTheme(Seer::iconColorTheme()); // Restore window settings. readSettings(); updateFilterButton(); } SeerParallelStacksVisualizerWidget::~SeerParallelStacksVisualizerWidget () { if (QGraphicsScene* scene = graphicsView->scene()) { scene->clear(); } } void SeerParallelStacksVisualizerWidget::setSettings (const SeerParallelStacksSettings& settings) { _settings = settings; writeSettings(); } SeerParallelStacksSettings SeerParallelStacksVisualizerWidget::settings () const { return _settings; } void SeerParallelStacksVisualizerWidget::setShowFullFunctionName (bool flag) { _settings.showFullFunctionName = flag; writeSettings(); // Redraw scene with new settings. createDirectedGraph(); highlightDirectedGraph(_currentThreadId, _currentFrameLevel); } bool SeerParallelStacksVisualizerWidget::showFullFunctionName () const { return _settings.showFullFunctionName; } void SeerParallelStacksVisualizerWidget::setFunctionNameLength (int length) { _settings.functionNameLength = length; writeSettings(); // Redraw scene with new settings. createDirectedGraph(); highlightDirectedGraph(_currentThreadId, _currentFrameLevel); } int SeerParallelStacksVisualizerWidget::functionNameLength () const { return _settings.functionNameLength; } void SeerParallelStacksVisualizerWidget::setShowMinimapMode (const QString& mode) { _settings.showMinimapMode = mode; writeSettings(); // Redraw scene with new settings. createDirectedGraph(); highlightDirectedGraph(_currentThreadId, _currentFrameLevel); } const QString& SeerParallelStacksVisualizerWidget::showMinimapMode () const { return _settings.showMinimapMode; } void SeerParallelStacksVisualizerWidget::refresh () { handleRefreshButton(); } void SeerParallelStacksVisualizerWidget::highlightDirectedGraph (int threadId, int frameLevel) { // frameLevel is relative to threadId's own numbering. Convert it to a // depth-from-bottom value using that thread's own frame count, since // that's what the graph's boxes compare against (see // SeerParallelStacksFrame::depth()) — a raw level is only meaningful // relative to the thread it came from. depth() starts at 1 for the // outermost frame, so the conversion is frameCount - level, not // frameCount - 1 - level. // // In Method View, depth is instead the signed distance from the pivot // (see SeerParallelStacksFrame::depth()): pivot index - level. If this // thread never calls the pivot, it isn't in the graph, so no frame is. // // The graph's threads may have runs of frames merged into one // "[External Code]" frame, so frameLevel is first mapped to the index of // the frame covering it — a frame inside external code highlights its // "[External Code]" row. int frameDepth = kNoFrameDepth; for (const auto& t : _graphThreads) { if (t.id() == threadId) { int frameIdx = t.indexOfLevel(frameLevel); if (frameIdx < 0) { break; } if (isMethodView()) { int pivotIdx = t.indexOfFunction(_methodPivot); if (pivotIdx >= 0) { frameDepth = pivotIdx - frameIdx; } }else{ frameDepth = t.frameCount() - frameIdx; } break; } } graphicsView->setCurrentHighlight(threadId, frameDepth); } void SeerParallelStacksVisualizerWidget::highlightSelectedThread (int threadId) { // Switching threads selects that thread's innermost frame, so the old // frame level (from some other thread) no longer applies. _currentThreadId = threadId; _currentFrameLevel = 0; updateForSelection(); } void SeerParallelStacksVisualizerWidget::highlightSelectedFrame (int frameLevel) { _currentFrameLevel = frameLevel; updateForSelection(); } void SeerParallelStacksVisualizerWidget::handleGraphThreadSelected (int threadId) { // The graph has already highlighted threadId itself. Track it here too, // so a later frame selection (or Method View rebuild) uses it rather // than a stale thread. _currentThreadId = threadId; _currentFrameLevel = 0; emit selectedThread(threadId); // This is reached from inside a box's popup-table signal, and a rebuild // clears the scene — deleting that box. Defer it until the signal has // unwound. if (isMethodView()) { QTimer::singleShot(0, this, [this]() { updateForSelection(); }); } } void SeerParallelStacksVisualizerWidget::updateForSelection () { if (isMethodView() && currentPivotFunction() != _methodPivot) { createDirectedGraph(); } highlightDirectedGraph(_currentThreadId, _currentFrameLevel); } void SeerParallelStacksVisualizerWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.contains(QRegularExpression("^([0-9]+)\\^done,frames="))) { // 4^done,frames=[ // {thread-id="10",target-id="(26131, 26146, 0)",name="hellothreads5",state="stopped",current="0", // frames=[ // {level="0",addr="0x7ffff78a3c1e",func="__futex_abstimed_wait_common",arch="i386:x86-64",from="/lib64/libc.so.6",type="normal"}, // {level="1",addr="0x7ffff78a6548",func="pthread_cond_wait@@GLIBC_2.3.2",arch="i386:x86-64",from="/lib64/libc.so.6",type="normal"}, // {level="2",addr="0x404357",func="w2",arch="i386:x86-64",file="hellothreads5.cpp",fullname="/nas/erniep/Development/seer/tests/hellothreads5/hellothreads5.cpp",line="22",type="normal"}, // ] // }, // ], // current_thread_id="1",current_frame_level="0",total_threads="11",total_frames="128" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _id) { _threads.clear(); QString result_text = Seer::parseFirst(text, "frames=", '[', ']', false); QStringList thread_list = Seer::parse(result_text, "", '{', '}', false); // Loop through each thread. for (const auto& thread_text : thread_list) { SeerParallelStacksThread thread(thread_text); _threads.push_back(thread); } QString current_thread_id_text = Seer::parseFirst(text, "current_thread_id=", '"', '"', false); QString current_frame_level_text = Seer::parseFirst(text, "current_frame_level=", '"', '"', false); _currentThreadId = current_thread_id_text.toInt(); _currentFrameLevel = current_frame_level_text.toInt(); createDirectedGraph(); highlightDirectedGraph(_currentThreadId, _currentFrameLevel); updateFilterButton(); } }else if (text.startsWith("^error,msg=\"No registers.\"")) { _graphThreads.clear(); // Clear old scene. if (QGraphicsScene* scene = graphicsView->scene()) { scene->clear(); } applySearch(false); // At a stopping point, refresh. }else if (text.startsWith("*stopped,reason=\"")) { if (autoRefreshCheckBox->isChecked()) { handleRefreshButton(); } }else{ // Ignore anything else. } QApplication::restoreOverrideCursor(); } void SeerParallelStacksVisualizerWidget::handleRefreshButton () { emit refreshParallelStackFrames(_id); } void SeerParallelStacksVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/ParallelStacksVisualizer.md"); help->show(); help->raise(); } void SeerParallelStacksVisualizerWidget::handlePrintButton () { QGraphicsScene* scene = graphicsView->scene(); if (scene == nullptr) { return; } QPrinter printer(QPrinter::HighResolution); printer.setPageOrientation(QPageLayout::Landscape); QPrintDialog dialog(&printer, this); dialog.setWindowTitle("Seer - Print ParallelStacks"); if (dialog.exec() != QDialog::Accepted) { return; } QRectF sceneRect = scene->sceneRect(); // Render the scene to a high-resolution image first. // Use a decent multiplier so text/shapes stay crisp when scaled up to page size. const qreal renderScale = 4.0; // tweak for quality vs memory/time QSize imageSize = (sceneRect.size() * renderScale).toSize(); QImage image(imageSize, QImage::Format_ARGB32); image.fill(Qt::white); QPainter imagePainter(&image); imagePainter.setRenderHint(QPainter::Antialiasing); imagePainter.setRenderHint(QPainter::TextAntialiasing); imagePainter.setRenderHint(QPainter::SmoothPixmapTransform); scene->render(&imagePainter, QRectF(QPointF(0, 0), image.size()), sceneRect); imagePainter.end(); // Now print the rasterized image, scaled to fit the page. QPainter printPainter(&printer); printPainter.setRenderHint(QPainter::SmoothPixmapTransform); QRectF pageRect = printer.pageRect(QPrinter::DevicePixel); QRectF target(QPointF(0, 0), image.size()); target.setSize(target.size().scaled(pageRect.size(), Qt::KeepAspectRatio)); target.moveCenter(pageRect.center()); printPainter.drawImage(target, image, image.rect()); printPainter.end(); QMessageBox::information(this, "Done", "Scene sent to printer."); } void SeerParallelStacksVisualizerWidget::handleSaveButton () { QGraphicsScene* scene = graphicsView->scene(); if (scene == nullptr) { return; } QString fileName = QFileDialog::getSaveFileName(this, "Seer - Save ParallelStacks As Image", "parallelstacks.png", "PNG Image (*.png)"); if (fileName.isEmpty()) { return; } // Make sure the file has a .png extension, in case the user typed one without it. if (!fileName.endsWith(".png", Qt::CaseInsensitive)) { fileName += ".png"; } QRectF sceneRect = scene->sceneRect(); // Render at a higher resolution than the scene's native size for crisper output. const qreal renderScale = 4.0; // tweak for quality vs file size QSize imageSize = (sceneRect.size() * renderScale).toSize(); QImage image(imageSize, QImage::Format_ARGB32); image.fill(Qt::white); // use Qt::transparent if you want a transparent background QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::TextAntialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); scene->render(&painter, QRectF(QPointF(0, 0), image.size()), sceneRect); painter.end(); if (!image.save(fileName, "PNG")) { QMessageBox::warning(this, "Save Failed", "Could not save the image to:\n" + fileName); return; } QMessageBox::information(this, "Done", "Scene saved to:\n" + fileName); } void SeerParallelStacksVisualizerWidget::handleSettingsButton () { // Bring up the settings dialog. SeerParallelStacksSettingsDialog dialog(this); // Set dialog things. dialog.setSettings(_settings); // Execute the dialog. if (dialog.exec()) { // Set things. The dialog doesn't know about the view mode (that's // the toolbar's toggle), so carry it across. SeerParallelStacksSettings settings = dialog.settings(); settings.viewMode = _settings.viewMode; setSettings(settings); // Redraw scene with new settings. createDirectedGraph(); highlightDirectedGraph(_currentThreadId, _currentFrameLevel); } } void SeerParallelStacksVisualizerWidget::handleThemeChanged () { // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); // And the graph. graphicsView->setColorTheme(Seer::iconColorTheme()); } void SeerParallelStacksVisualizerWidget::handleViewModeChanged (const QString& mode) { _settings.viewMode = mode; writeSettings(); // Redraw scene in the new mode. createDirectedGraph(); highlightDirectedGraph(_currentThreadId, _currentFrameLevel); } void SeerParallelStacksVisualizerWidget::handleSearchTextChanged () { applySearch(true); } void SeerParallelStacksVisualizerWidget::handleSearchRegexToggled () { writeSettings(); applySearch(true); } void SeerParallelStacksVisualizerWidget::handleSearchReturnPressed () { // returnPressed carries no modifiers, so ask for them. if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { handleSearchPrevious(); }else{ handleSearchNext(); } } void SeerParallelStacksVisualizerWidget::handleSearchShortcut () { searchLineEdit->setFocus(Qt::ShortcutFocusReason); searchLineEdit->selectAll(); } void SeerParallelStacksVisualizerWidget::handleSearchNext () { graphicsView->findNextSearchMatch(false); updateSearchStatus(); } void SeerParallelStacksVisualizerWidget::handleSearchPrevious () { graphicsView->findNextSearchMatch(true); updateSearchStatus(); } void SeerParallelStacksVisualizerWidget::applySearch (bool jumpToFirst) { const QString text = searchLineEdit->text(); // Plain text is escaped so characters like '(' or '*' match literally. const QString pattern = searchRegexCheckBox->isChecked() ? text : QRegularExpression::escape(text); QRegularExpression re(pattern, QRegularExpression::CaseInsensitiveOption); // Highlight nothing until the expression is complete. if (re.isValid() == false) { graphicsView->setSearchExpression(QRegularExpression()); searchStatusLabel->setText("Bad expression"); searchStatusLabel->setToolTip(re.errorString()); return; } graphicsView->setSearchExpression(re); if (jumpToFirst) { graphicsView->findNextSearchMatch(false); } updateSearchStatus(); } void SeerParallelStacksVisualizerWidget::updateSearchStatus () { if (searchLineEdit->text().isEmpty()) { searchStatusLabel->setText(""); searchStatusLabel->setToolTip(""); return; } const int boxes = graphicsView->searchBoxCount(); const int frames = graphicsView->searchMatchCount(); const int index = graphicsView->searchCurrentIndex(); if (boxes == 0) { searchStatusLabel->setText("No matches"); }else if (index < 0) { searchStatusLabel->setText(QString("%1 node%2").arg(boxes).arg(boxes == 1 ? "" : "s")); }else{ searchStatusLabel->setText(QString("%1 of %2").arg(index + 1).arg(boxes)); } searchStatusLabel->setToolTip(QString("%1 matching frame%2 in %3 node%4.").arg(frames).arg(frames == 1 ? "" : "s").arg(boxes).arg(boxes == 1 ? "" : "s")); } void SeerParallelStacksVisualizerWidget::handleFilterButton () { // The button only opens the popup. Its checked state reflects whether a // filter is active, so undo the click's own toggle. updateFilterButton(); if (_filterPopup == nullptr) { _filterPopup = new SeerParallelStacksFilterWidget(this); QObject::connect(_filterPopup, &SeerParallelStacksFilterWidget::filterChanged, this, &SeerParallelStacksVisualizerWidget::handleFilterChanged); } _filterPopup->setThreads(_threads, _filterLibraries, _filterFunctions, _filterThreadIds); // Place it like a menu: below the button, or above it if there's no room // (the toolbar sits at the bottom of the window). QPoint below = filterToolButton->mapToGlobal(QPoint(0, filterToolButton->height())); QPoint above = filterToolButton->mapToGlobal(QPoint(0, -_filterPopup->height())); QScreen* screen = filterToolButton->screen(); if (screen != nullptr && below.y() + _filterPopup->height() > screen->availableGeometry().bottom()) { _filterPopup->move(above); }else{ _filterPopup->move(below); } _filterPopup->show(); _filterPopup->raise(); } void SeerParallelStacksVisualizerWidget::handleFilterChanged () { _filterLibraries = _filterPopup->libraries(); _filterFunctions = _filterPopup->functions(); _filterThreadIds = _filterPopup->threadIds(); // Redraw scene with the new filter. createDirectedGraph(); highlightDirectedGraph(_currentThreadId, _currentFrameLevel); updateFilterButton(); } bool SeerParallelStacksVisualizerWidget::isFiltered () const { return !_filterLibraries.isEmpty() || !_filterFunctions.isEmpty() || !_filterThreadIds.isEmpty(); } SeerParallelStacksThreads SeerParallelStacksVisualizerWidget::filteredThreads () const { if (isFiltered() == false) { return _threads; } SeerParallelStacksThreads threads; for (const auto& t : _threads) { bool keep = _filterThreadIds.contains(t.id()); for (int i = 0; keep == false && i < t.frameCount(); ++i) { const SeerParallelStacksFrame& f = t.frame(i); keep = _filterFunctions.contains(f.functionOrAddr()) || _filterLibraries.contains(SeerParallelStacksFilterWidget::libraryOf(f)); } if (keep) { threads.push_back(t); } } return threads; } SeerParallelStacksThreads SeerParallelStacksVisualizerWidget::graphThreads (const QString& pivot) const { if (_settings.showExternalCode) { return filteredThreads(); } return SeerParallelStacksCollapseExternalCode(filteredThreads(), pivot); } void SeerParallelStacksVisualizerWidget::updateFilterButton () { const QString tooltip = "Show only the threads that pass through the selected libraries, functions or threads."; filterToolButton->setChecked(isFiltered()); if (isFiltered()) { filterToolButton->setToolTip(tooltip + QString("\n\n%1 of %2 threads shown.").arg(filteredThreads().size()).arg(_threads.size())); }else{ filterToolButton->setToolTip(tooltip); } } void SeerParallelStacksVisualizerWidget::writeSettings() { QSettings settings; settings.beginGroup("parallelstacksvisualizerwindow"); { settings.setValue("size", size()); settings.setValue("functionnamelength", _settings.functionNameLength); settings.setValue("showfullfunctionname", _settings.showFullFunctionName); settings.setValue("showfullstacksize", _settings.showFullStackSize); settings.setValue("stacksize", _settings.stackSize); settings.setValue("showexternalcode", _settings.showExternalCode); settings.setValue("showminimapmode", _settings.showMinimapMode); settings.setValue("viewmode", _settings.viewMode); settings.setValue("autorefresh", autoRefreshCheckBox->isChecked()); settings.setValue("searchregex", searchRegexCheckBox->isChecked()); } settings.endGroup(); } void SeerParallelStacksVisualizerWidget::readSettings() { QSettings settings; settings.beginGroup("parallelstacksvisualizerwindow"); { resize(settings.value("size", QSize(800, 400)).toSize()); _settings.showFullFunctionName = settings.value("showfullfunctionname", true).toBool(); _settings.functionNameLength = settings.value("functionnamelength", 64).toInt(); _settings.showFullStackSize = settings.value("showfullstacksize", true).toBool(); _settings.stackSize = settings.value("stacksize", 20).toInt(); _settings.showExternalCode = settings.value("showexternalcode", false).toBool(); _settings.showMinimapMode = settings.value("showminimapmode", "Auto").toString(); _settings.viewMode = settings.value("viewmode", "Stack").toString(); // Unknown (or older "Threads") values fall back to Stack. if (viewModeComboBox->findText(_settings.viewMode) < 0) { _settings.viewMode = "Stack"; } // No graph to redraw yet, so don't let the change trigger one. QSignalBlocker blocker(viewModeComboBox); viewModeComboBox->setCurrentText(_settings.viewMode); autoRefreshCheckBox->setChecked(settings.value("autorefresh", false).toBool()); // No graph to search yet, so don't let the change trigger one. QSignalBlocker regexBlocker(searchRegexCheckBox); searchRegexCheckBox->setChecked(settings.value("searchregex", true).toBool()); } settings.endGroup(); } void SeerParallelStacksVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } void SeerParallelStacksVisualizerWidget::createDirectedGraph() { // Clear old scene. if (QGraphicsScene* scene = graphicsView->scene()) { scene->clear(); } // Method View: pivot on the current thread's current function. if (isMethodView()) { _methodPivot = currentPivotFunction(); _graphThreads = graphThreads(_methodPivot); SeerParallelStacksMethodStacks method = SeerParallelStacksBuildMethodStacks(_graphThreads, _methodPivot); graphicsView->setMethodStacks(method, settings()); applySearch(false); return; } _methodPivot.clear(); // Build parallel-stacks tree. Purely structural — no highlighting here; // see highlightDirectedGraph(). _graphThreads = graphThreads(QString()); SeerParallelStacksNode root = SeerParallelStacksBuildParallelStacks(_graphThreads); SeerParallelStacksStack stack = SeerParallelStacksFillStack(root); graphicsView->setStack(stack, settings()); applySearch(false); } bool SeerParallelStacksVisualizerWidget::isMethodView () const { return _settings.viewMode == "Method"; } QString SeerParallelStacksVisualizerWidget::currentPivotFunction () const { for (const auto& t : _threads) { if (t.id() == _currentThreadId) { if (_currentFrameLevel >= 0 && _currentFrameLevel < t.frameCount()) { return t.frame(_currentFrameLevel).functionOrAddr(); } break; } } return ""; } epasveer-seer-97076f1/src/SeerParallelStacksVisualizerWidget.h000066400000000000000000000162721526321767600245020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerParallelStacksCommon.h" #include #include #include #include "ui_SeerParallelStacksVisualizerWidget.h" class SeerParallelStacksFilterWidget; class SeerParallelStacksVisualizerWidget : public QWidget, protected Ui::SeerParallelStacksVisualizerWidgetForm { Q_OBJECT public: explicit SeerParallelStacksVisualizerWidget (QWidget* parent = 0); ~SeerParallelStacksVisualizerWidget (); void setSettings (const SeerParallelStacksSettings& settings); SeerParallelStacksSettings settings () const; void setShowFullFunctionName (bool flag); bool showFullFunctionName () const; void setFunctionNameLength (int length); int functionNameLength () const; void setShowMinimapMode (const QString& mode); const QString& showMinimapMode () const; signals: void refreshParallelStackFrames (int id); void selectedThread (int threadId); public slots: void refresh (); void handleText (const QString& text); // Highlights threadId/frameLevel in the already-built graph — the // counterpart to createDirectedGraph(), which only builds and // deliberately leaves highlighting alone. Called internally right // after every createDirectedGraph() call (using _currentThreadId/ // _currentFrameLevel), and exposed as a slot so another widget could // drive it directly if it ever has both values to give at once. void highlightDirectedGraph (int threadId, int frameLevel); // Another widget (e.g. the thread frames browser) selected a // thread — reflect it in the graph without re-announcing it via // selectedThread(), since that widget already told gdb itself. Just // a thin wrapper around highlightDirectedGraph() using the // last-known frame level, since this signal only carries a thread id. void highlightSelectedThread (int threadId); // Another widget (e.g. the stack frames browser) selected a frame — // reflect it in the graph the same way. The graph has no // frame-selection UI of its own, so there's no outgoing signal to // avoid re-announcing here. A thin wrapper around // highlightDirectedGraph() using the last-known thread id. void highlightSelectedFrame (int frameLevel); protected slots: void handleRefreshButton (); void handleHelpButton (); void handlePrintButton (); void handleSaveButton (); void handleSettingsButton (); void handleThemeChanged (); void handleViewModeChanged (const QString& mode); void handleSearchTextChanged (); void handleSearchRegexToggled (); void handleSearchReturnPressed (); void handleSearchShortcut (); void handleSearchNext (); void handleSearchPrevious (); void handleFilterButton (); void handleFilterChanged (); // A thread was picked in one of the graph's popup tables. void handleGraphThreadSelected (int threadId); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: void createDirectedGraph (); bool isMethodView () const; // Method View's pivot: the function in the current thread's current // frame, or "" if that frame can't be found. QString currentPivotFunction () const; // Selecting a different thread/frame re-pivots Method View (like // Visual Studio), so the graph has to be rebuilt, not just // re-highlighted. Threads view only needs the re-highlight. void updateForSelection (); // Re-runs the search field's expression against the current graph // (a rebuild discards the old highlights), optionally jumping to the // first match, and refreshes the match-count label. void applySearch (bool jumpToFirst); void updateSearchStatus (); // _threads narrowed by the filter: every thread when no filter is // set, otherwise those passing through a checked library, a checked // function, or that are checked themselves. SeerParallelStacksThreads filteredThreads () const; bool isFiltered () const; // filteredThreads() as drawn: with frames lacking debug info merged // into "[External Code]" unless showExternalCode is set. In Method // View, pivot's own frames are kept so it can still be found. SeerParallelStacksThreads graphThreads (const QString& pivot) const; void updateFilterButton (); int _id; SeerParallelStacksThreads _threads; SeerParallelStacksThreads _graphThreads; // the threads the current graph was built from (see graphThreads()) int _currentThreadId = -1; int _currentFrameLevel = 0; QString _methodPivot; // the pivot the current Method View graph was built on SeerParallelStacksSettings _settings; // The filter, by name/id so it survives a refresh. SeerParallelStacksFilterWidget* _filterPopup = nullptr; QSet _filterLibraries; QSet _filterFunctions; QSet _filterThreadIds; }; epasveer-seer-97076f1/src/SeerParallelStacksVisualizerWidget.ui000066400000000000000000000161301526321767600246610ustar00rootroot00000000000000 SeerParallelStacksVisualizerWidgetForm 0 0 899 683 Seer ParallelStacks Visualizer :/seer/resources/icons/hicolor/32x32/seergdb.png:/seer/resources/icons/hicolor/32x32/seergdb.png 200 0 Highlight every frame in the graph whose function matches this text (case-insensitive). Enter or Ctrl+G jumps to the next matching node. Shift+Enter or Ctrl+Shift+G to the previous one. Ctrl+F to focus. Search functions true Treat the search text as a regular expression. Unchecked, it's matched as plain text. Regex true Show only the threads that pass through the selected libraries, functions or threads. :/seer/resources/RelaxLightIcons/view-filter.svg:/seer/resources/RelaxLightIcons/view-filter.svg true Qt::Vertical Select the view mode. Stack shows all threads' merged call stacks. Method pivots the graph on the current frame's function, showing its callers below and its callees above. Stack Method Settings. :/seer/resources/RelaxLightIcons/application-menu.svg:/seer/resources/RelaxLightIcons/application-menu.svg Qt::Vertical Print the display. ... :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg Save the display to a file. ... :/seer/resources/RelaxLightIcons/document-save-as.svg:/seer/resources/RelaxLightIcons/document-save-as.svg Qt::Vertical Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Automatically refresh after each stopping point. Auto Qt::Vertical Help on ParallelStacks Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg SeerParallelStacksGraphicsView QGraphicsView
SeerParallelStacksGraphicsView.h
epasveer-seer-97076f1/src/SeerPlainTextEdit.cpp000066400000000000000000000267421526321767600214270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include #include "SeerPlainTextEdit.h" #include #include #include #include #include #include #include #include #include #include #include #include SeerPlainTextEdit::SeerPlainTextEdit(const QString& text, QWidget* parent) : QPlainTextEdit(text, parent) { // Turn off the widget's cursor. We'll do our own in the paintEvent. setCursorWidth(0); _cursorVisible = true; _cursorTimer = new QTimer(this); QObject::connect(_cursorTimer, &QTimer::timeout, this, &SeerPlainTextEdit::blinkCursor); QObject::connect(this, &QPlainTextEdit::cursorPositionChanged, this, &SeerPlainTextEdit::handleCursorPositionChanged); _cursorTimer->start(500); } SeerPlainTextEdit::SeerPlainTextEdit(QWidget* parent) : QPlainTextEdit(parent) { // Turn off the widget's cursor. We'll do our own in the paintEvent. setCursorWidth(0); _cursorVisible = true; _cursorTimer = new QTimer(this); QObject::connect(_cursorTimer, &QTimer::timeout, this, &SeerPlainTextEdit::blinkCursor); QObject::connect(this, &QPlainTextEdit::cursorPositionChanged, this, &SeerPlainTextEdit::handleCursorPositionChanged); _cursorTimer->start(500); } SeerPlainTextEdit::~SeerPlainTextEdit () { } void SeerPlainTextEdit::forwardViewportEvent(QEvent* event) { viewportEvent(event); } void SeerPlainTextEdit::blinkCursor() { _cursorVisible = !_cursorVisible; viewport()->update(); // Trigger a repaint of the viewport } void SeerPlainTextEdit::paintEvent(QPaintEvent* event) { // First, let the standard QPlainTextEdit handle its painting. QPlainTextEdit::paintEvent(event); // Get our painter. QPainter painter(viewport()); // Draw the cursor manually. if (_cursorVisible) { QRect r = cursorRect(); r.setWidth(CURSOR_WIDTH); painter.fillRect(r, palette().text().color()); } // Add margin highlight for current line QTextCursor cursor = textCursor(); QTextBlock block = cursor.block(); // Get the rectangle of the current line (block) QRectF rect = blockBoundingGeometry(block).translated(contentOffset()); // Optional: add a few pixels margin around the block rect.adjust(-2, 0, 2, 0); // Draw a visible border QPen pen(QColor(200, 200, 200), 0.5); painter.setPen(pen); painter.drawRect(rect); } // Add margin highlight for current line void SeerPlainTextEdit::handleCursorPositionChanged() { viewport()->update(); } // // // SeerPlainTextWheelEventForwarder::SeerPlainTextWheelEventForwarder (SeerPlainTextEdit* target ) : QObject(), _target(target) { } SeerPlainTextWheelEventForwarder::~SeerPlainTextWheelEventForwarder() { _target = NULL; } bool SeerPlainTextWheelEventForwarder::eventFilter (QObject* obj, QEvent* event) { Q_UNUSED(obj); if (_target == 0) { return false; } if (event->type() == QEvent::Wheel) { _target->forwardViewportEvent(event); } // do not filter the event return false; } // // // qreal SeerPlainTextMiniMap::pixelsPerLine (const QPlainTextEdit* editor, int height) { int totalLines = qMax(1, editor->document()->blockCount()); return qMin(qreal(LINE_PITCH), qreal(qMax(1, height)) / qreal(totalLines)); } int SeerPlainTextMiniMap::lineAt (const QPlainTextEdit* editor, int height, int y) { int totalLines = qMax(1, editor->document()->blockCount()); return qBound(0, int(y / pixelsPerLine(editor, height)), totalLines - 1); } QRectF SeerPlainTextMiniMap::overlayRect (const QPlainTextEdit* editor, int width, int height) { const QScrollBar* scrollBar = editor->verticalScrollBar(); qreal ppl = pixelsPerLine(editor, height); qreal y = scrollBar->value() * ppl; qreal h = qMax(4.0, qMax(1, scrollBar->pageStep()) * ppl); return QRectF(0, y, width, h); } int SeerPlainTextMiniMap::dragValue (const QPlainTextEdit* editor, int height, int startValue, int dy) { const QScrollBar* scrollBar = editor->verticalScrollBar(); // Keep the overlay under the mouse. int value = startValue + qRound(qreal(dy) / pixelsPerLine(editor, height)); return qBound(scrollBar->minimum(), value, scrollBar->maximum()); } void SeerPlainTextMiniMap::render (QPixmap& pixmap, const QTextDocument* document, const QColor& background, const QColor& foreground) { pixmap.fill(background); QPainter painter(&pixmap); int totalLines = qMax(1, document->blockCount()); int width = pixmap.width(); qreal pixelsPerLine = qMin(qreal(LINE_PITCH), qreal(qMax(1, pixmap.height())) / qreal(totalLines)); int blockHeight = qMax(1, qRound(pixelsPerLine * LINE_HEIGHT / LINE_PITCH)); int lastY = -1; for (QTextBlock block = document->firstBlock(); block.isValid(); block = block.next()) { int y = int(block.blockNumber() * pixelsPerLine); // Only the first line that falls on a pixel row is drawn. if (y == lastY) { continue; } lastY = y; QString text = block.text(); // Per-character colors from the syntax highlighter, if there is one. QVector colors(text.length(), foreground); const auto formats = block.layout()->formats(); for (const QTextLayout::FormatRange& range : formats) { if (range.format.hasProperty(QTextFormat::ForegroundBrush) == false) { continue; } QColor color = range.format.foreground().color(); for (int i = qMax(0, range.start); i < qMin(text.length(), range.start + range.length); i++) { colors[i] = color; } } // Draw each character as a one pixel wide mark, whose opacity follows // how much "ink" the character has. Rows of marks then read like tiny // text rather than solid blocks. int column = 0; for (int i = 0; i < text.length() && column < width; i++) { QChar ch = text.at(i); if (ch == QLatin1Char('\t')) { column = (column / TAB_WIDTH + 1) * TAB_WIDTH; continue; } if (ch.isSpace() == false) { QColor color = colors[i]; color.setAlpha(characterOpacity(ch)); painter.fillRect(column, y, 1, blockHeight, color); } column++; } } } void SeerPlainTextMiniMap::showVisibleLinesTip (const QPlainTextEdit* editor, QWidget* miniMap, const QPoint& globalPos) { // Like Kate, show the range of lines visible in the editor while scrolling with the mini-map. const QScrollBar* scrollBar = editor->verticalScrollBar(); int totalLines = qMax(1, editor->document()->blockCount()); int firstLine = scrollBar->value() + 1; int lastLine = qMin(totalLines, scrollBar->value() + qMax(1, scrollBar->pageStep())); QToolTip::showText(globalPos, QString("Lines %1 - %2 of %3").arg(firstLine).arg(lastLine).arg(totalLines), miniMap); } int SeerPlainTextMiniMap::characterOpacity (QChar ch) { // Light punctuation. if (QStringLiteral(".,:;'`\"-_^~").contains(ch)) { return 70; } // Other punctuation and brackets. if (ch.isPunct() || ch.isSymbol()) { return 130; } // Lowercase letters. if (ch.isLower()) { return 170; } // Uppercase letters, digits, and anything else dense. return 220; } // // // SeerPlainTextMiniMapPreview::SeerPlainTextMiniMapPreview (QWidget* parent) : QWidget(parent, Qt::ToolTip | Qt::FramelessWindowHint) { setAttribute(Qt::WA_ShowWithoutActivating); setAttribute(Qt::WA_TransparentForMouseEvents); _editor = 0; _lineno = 0; } SeerPlainTextMiniMapPreview::~SeerPlainTextMiniMapPreview () { } void SeerPlainTextMiniMapPreview::showPreview (QPlainTextEdit* editor, int lineno, const QRect& globalMiniMapRect, int globalY, const QColor& background, const QColor& foreground, const QColor& highlight) { _editor = editor; _lineno = lineno; _background = background; _foreground = foreground; _highlight = highlight; QFontMetricsF fm(editor->font()); qreal scale = previewScale(); int w = qMin(qRound(PREVIEW_COLUMNS * fm.horizontalAdvance(QLatin1Char('9')) * scale) + 2 * PREVIEW_PADDING, editor->viewport()->width()); int h = qRound(PREVIEW_LINES * fm.lineSpacing() * scale) + 2 * PREVIEW_PADDING; // To the left of the mini-map, centered on the mouse, kept on the screen. int x = globalMiniMapRect.left() - w - 4; int y = globalY - h / 2; QScreen* screen = QGuiApplication::screenAt(QPoint(globalMiniMapRect.left(), globalY)); if (screen) { QRect avail = screen->availableGeometry(); x = qMax(avail.left(), x); y = qBound(avail.top(), y, qMax(avail.top(), avail.bottom() - h + 1)); } resize(w, h); move(x, y); show(); update(); } qreal SeerPlainTextMiniMapPreview::previewScale () const { if (_editor == 0) { return 1.0; } // A couple of points smaller than the editor's font. QFont font = _editor->font(); qreal size = font.pointSizeF() > 0 ? font.pointSizeF() : qreal(font.pixelSize()); if (size <= 0) { return 1.0; } return qMax(qreal(1), size - PREVIEW_SMALLER_POINTS) / size; } void SeerPlainTextMiniMapPreview::paintEvent (QPaintEvent* event) { Q_UNUSED(event); QPainter painter(this); painter.fillRect(rect(), _background); if (_editor) { const QTextDocument* document = _editor->document(); QAbstractTextDocumentLayout* layout = document->documentLayout(); painter.setClipRect(rect().adjusted(1, 1, -1, -1)); painter.save(); // Draw the code a little smaller than the editor's. Scale the painter rather // than shrinking the font, which is known to break tab-stop rendering (see // setEditorFont()'s comments), and lets the editor's own layouts be reused. qreal scale = previewScale(); painter.translate(PREVIEW_PADDING, PREVIEW_PADDING); painter.scale(scale, scale); painter.setFont(_editor->font()); qreal y = 0; qreal bottom = (height() - PREVIEW_PADDING) / scale; qreal right = width() / scale; for (QTextBlock block = document->findBlockByNumber(qMax(0, _lineno - PREVIEW_LINES / 2)); block.isValid() && y < bottom; block = block.next()) { QRectF bounds = layout->blockBoundingRect(block); // also forces the block's layout if (block.blockNumber() == _lineno) { painter.fillRect(QRectF(-PREVIEW_PADDING / scale, y, right, bounds.height()), _highlight); } // Draw the block's layout directly so the syntax highlighter's colors are honored. QTextLayout* textLayout = block.layout(); QPointF origin(0, y); if (textLayout->lineCount() > 0) { origin -= textLayout->lineAt(0).position(); } painter.setPen(_foreground); textLayout->draw(&painter, origin); y += bounds.height(); } painter.restore(); painter.setClipping(false); } painter.setPen(_foreground); painter.drawRect(rect().adjusted(0, 0, -1, -1)); } epasveer-seer-97076f1/src/SeerPlainTextEdit.h000066400000000000000000000102161526321767600210610ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include #include #include #include #include #include class SeerPlainTextEdit : public QPlainTextEdit { Q_OBJECT public: explicit SeerPlainTextEdit (const QString& text, QWidget* parent = 0); explicit SeerPlainTextEdit (QWidget* parent = 0); ~SeerPlainTextEdit (); void forwardViewportEvent (QEvent* event); protected: void paintEvent (QPaintEvent* event); private slots: void blinkCursor (); void handleCursorPositionChanged (); private: constexpr static int CURSOR_WIDTH = 2; QTimer* _cursorTimer; bool _cursorVisible; }; class SeerPlainTextWheelEventForwarder : public QObject { Q_OBJECT public: explicit SeerPlainTextWheelEventForwarder (SeerPlainTextEdit* target); ~SeerPlainTextWheelEventForwarder(); bool eventFilter (QObject* obj, QEvent* event); private: SeerPlainTextEdit* _target; }; // // Shared mini-map support for the Source and Assembly editors. // // Like Kate, the mini-map always shows the whole document. Each character is drawn as a one pixel // wide mark in its syntax color, faded by how dense the character is, rather than as shrunken text. Lines are LINE_PITCH pixels apart when the document fits; // otherwise they're squeezed together. When several lines fall on the same pixel row, only the // first of them is drawn, rather than drawing them on top of each other. // class SeerPlainTextMiniMap { public: constexpr static int LINE_PITCH = 3; // Maximum pixels from one line to the next. constexpr static int LINE_HEIGHT = 2; // Pixels high of each line's marks, at LINE_PITCH. constexpr static int TAB_WIDTH = 4; // Columns per tab stop. static qreal pixelsPerLine (const QPlainTextEdit* editor, int height); static int lineAt (const QPlainTextEdit* editor, int height, int y); static QRectF overlayRect (const QPlainTextEdit* editor, int width, int height); static int dragValue (const QPlainTextEdit* editor, int height, int startValue, int dy); static void render (QPixmap& pixmap, const QTextDocument* document, const QColor& background, const QColor& foreground); static void showVisibleLinesTip (const QPlainTextEdit* editor, QWidget* miniMap, const QPoint& globalPos); private: static int characterOpacity (QChar ch); }; class SeerPlainTextMiniMapPreview : public QWidget { Q_OBJECT public: explicit SeerPlainTextMiniMapPreview (QWidget* parent = 0); ~SeerPlainTextMiniMapPreview (); void showPreview (QPlainTextEdit* editor, int lineno, const QRect& globalMiniMapRect, int globalY, const QColor& background, const QColor& foreground, const QColor& highlight); protected: void paintEvent (QPaintEvent* event) override; private: qreal previewScale () const; constexpr static int PREVIEW_LINES = 15; constexpr static int PREVIEW_COLUMNS = 80; constexpr static int PREVIEW_PADDING = 4; constexpr static int PREVIEW_SMALLER_POINTS = 2; // Points smaller than the editor's font. QPlainTextEdit* _editor; int _lineno; QColor _background; QColor _foreground; QColor _highlight; }; epasveer-seer-97076f1/src/SeerPrintpointCreateDialog.cpp000066400000000000000000000214671526321767600233220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerPrintpointCreateDialog.h" #include "SeerHelpPageDialog.h" #include SeerPrintpointCreateDialog::SeerPrintpointCreateDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets setFilename(""); setFunctionName(""); setLabelName(""); setLineNumber(""); setTemporaryEnabled (false); setPendingEnabled (false); setDisabledEnabled (false); setConditionalEnabled (false); setIgnoreCountEnabled (false); setThreadIdEnabled (false); setConditionalText (""); setIgnoreCountText (""); setThreadIdText (""); setFormat(""); setArguments(""); setDPrintfType ("gdb"); setDPrintfFunction (""); setDPrintfChannel (""); filenameLineEdit->setFocus(); // Connect things. QObject::connect(conditionalCheckBox, &QCheckBox::clicked, conditionalLineEdit, &QLineEdit::setEnabled); QObject::connect(ignoreCountCheckBox, &QCheckBox::clicked, ignoreCountLineEdit, &QLineEdit::setEnabled); QObject::connect(threadIdCheckBox, &QCheckBox::clicked, threadIdLineEdit, &QLineEdit::setEnabled); QObject::connect(typeButtonGroup, &QButtonGroup::buttonClicked, this, &SeerPrintpointCreateDialog::handleDprintfTypeChanged); QObject::connect(typeHelpToolButton, &QToolButton::clicked, this, &SeerPrintpointCreateDialog::handleHelpToolButtonClicked); } SeerPrintpointCreateDialog::~SeerPrintpointCreateDialog () { } void SeerPrintpointCreateDialog::setFilename (const QString& text) { filenameLineEdit->setText(text); } void SeerPrintpointCreateDialog::setFunctionName (const QString& text) { functionLineEdit->setText(text); } void SeerPrintpointCreateDialog::setLabelName (const QString& text) { labelLineEdit->setText(text); } void SeerPrintpointCreateDialog::setLineNumber (const QString& text) { lineNumberLineEdit->setText(text); } QString SeerPrintpointCreateDialog::filenameText () const { return filenameLineEdit->text(); } QString SeerPrintpointCreateDialog::functionNameText () const { return functionLineEdit->text(); } QString SeerPrintpointCreateDialog::labelNameText () const { return labelLineEdit->text(); } QString SeerPrintpointCreateDialog::lineNumberText () const { return lineNumberLineEdit->text(); } void SeerPrintpointCreateDialog::setTemporaryEnabled (bool flag) { temporaryCheckBox->setChecked(flag); } void SeerPrintpointCreateDialog::setPendingEnabled (bool flag) { pendingCheckBox->setChecked(flag); } void SeerPrintpointCreateDialog::setDisabledEnabled (bool flag) { disabledCheckBox->setChecked(flag); } void SeerPrintpointCreateDialog::setConditionalEnabled (bool flag) { conditionalCheckBox->setChecked(flag); conditionalLineEdit->setEnabled(flag); } void SeerPrintpointCreateDialog::setIgnoreCountEnabled (bool flag) { ignoreCountCheckBox->setChecked(flag); ignoreCountLineEdit->setEnabled(flag); } void SeerPrintpointCreateDialog::setThreadIdEnabled (bool flag) { threadIdCheckBox->setChecked(flag); threadIdLineEdit->setEnabled(flag); } void SeerPrintpointCreateDialog::setConditionalText (const QString& text) { conditionalLineEdit->setText(text); } void SeerPrintpointCreateDialog::setIgnoreCountText (const QString& text) { ignoreCountLineEdit->setText(text); } void SeerPrintpointCreateDialog::setThreadIdText (const QString& text) { threadIdLineEdit->setText(text); } bool SeerPrintpointCreateDialog::temporaryEnabled () const { return temporaryCheckBox->isChecked(); } bool SeerPrintpointCreateDialog::pendingEnabled () const { return pendingCheckBox->isChecked(); } bool SeerPrintpointCreateDialog::disabledEnabled () const { return disabledCheckBox->isChecked(); } bool SeerPrintpointCreateDialog::conditionalEnabled () const { return conditionalCheckBox->isChecked(); } bool SeerPrintpointCreateDialog::ignoreCountEnabled () const { return ignoreCountCheckBox->isChecked(); } bool SeerPrintpointCreateDialog::threadIdEnabled () const { return threadIdCheckBox->isChecked(); } QString SeerPrintpointCreateDialog::conditionalText () const { return conditionalLineEdit->text(); } QString SeerPrintpointCreateDialog::ignoreCountText () const { return ignoreCountLineEdit->text(); } QString SeerPrintpointCreateDialog::threadIdText () const { return threadIdLineEdit->text(); } void SeerPrintpointCreateDialog::setFormat (const QString& text) { formatLineEdit->setText(text); } void SeerPrintpointCreateDialog::setArguments (const QString& text) { argumentsLineEdit->setText(text); } QString SeerPrintpointCreateDialog::format () const { return formatLineEdit->text(); } QString SeerPrintpointCreateDialog::arguments () const { return argumentsLineEdit->text(); } QString SeerPrintpointCreateDialog::dprintfType () const { if (typeGdbRadioButton->isChecked()) { return "gdb"; }else if (typeCallRadioButton->isChecked()) { return "call"; }else if (typeAgentRadioButton->isChecked()) { return "agent"; } // Default. return "gdb"; } QString SeerPrintpointCreateDialog::dprintfFunction () const { if (dprintfType() == "gdb") { return ""; } return dprintfFunctionLineEdit->text(); } QString SeerPrintpointCreateDialog::dprintfChannel () const { if (dprintfType() == "gdb") { return ""; } return dprintfChannelLineEdit->text(); } void SeerPrintpointCreateDialog::setDPrintfType (const QString& text) { if (text == "gdb") { typeGdbRadioButton->setChecked(true); dprintfFunctionLineEdit->setEnabled(false); dprintfChannelLineEdit->setEnabled(false); return; }else if (text == "call") { typeCallRadioButton->setChecked(true); dprintfFunctionLineEdit->setEnabled(true); dprintfChannelLineEdit->setEnabled(true); return; }else if (text == "agent") { typeAgentRadioButton->setChecked(true); dprintfFunctionLineEdit->setEnabled(false); dprintfChannelLineEdit->setEnabled(false); return; } // Default. typeGdbRadioButton->setChecked(true); dprintfFunctionLineEdit->setEnabled(false); dprintfChannelLineEdit->setEnabled(false); } void SeerPrintpointCreateDialog::setDPrintfFunction (const QString& text) { dprintfFunctionLineEdit->setText(text); } void SeerPrintpointCreateDialog::setDPrintfChannel (const QString& text) { dprintfChannelLineEdit->setText(text); } QString SeerPrintpointCreateDialog::printpointParameters () const { // Build a printpoint specification. // // -dprintf-insert [ -t ] [ -f ] [ -d ] [ --qualified ] // [ -c condition ] [--force-condition] [ -i ignore-count ] // [ -p thread-id ] [ location ] // [ format ] [ argument ] QString printpointParameters; if (temporaryEnabled()) { printpointParameters += " -t"; } if (pendingEnabled()) { printpointParameters += " -f"; } if (disabledEnabled()) { printpointParameters += " -d"; } if (conditionalEnabled()) { if (conditionalText() != "") { printpointParameters += " -c \"" + conditionalText() + "\""; } } if (ignoreCountEnabled()) { if (ignoreCountText() != "") { printpointParameters += " -i " + ignoreCountText(); } } if (threadIdEnabled()) { if (threadIdText() != "") { printpointParameters += " -p " + threadIdText(); } } if (filenameText() != "") { printpointParameters += " --source \"" + filenameText() +"\""; } if (functionNameText() != "") { printpointParameters += " --function " + functionNameText(); } if (labelNameText() != "") { printpointParameters += " --label " + labelNameText(); } if (lineNumberText() != "") { printpointParameters += " --line " + lineNumberText(); } // Build the format string, ensuring a \" at the beginning and end of the string. printpointParameters += " "; if (format().front() != QString("\"")) { printpointParameters += "\""; } printpointParameters += format(); if (format().back() != QString("\"")) { printpointParameters += "\""; } // Add the arguments to the string. printpointParameters += " " + arguments(); return printpointParameters; } void SeerPrintpointCreateDialog::handleDprintfTypeChanged () { setDPrintfType(dprintfType()); } void SeerPrintpointCreateDialog::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/Printpoints.md"); help->show(); help->raise(); } epasveer-seer-97076f1/src/SeerPrintpointCreateDialog.h000066400000000000000000000061411526321767600227570ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerPrintpointCreateDialog.h" class SeerPrintpointCreateDialog : public QDialog, protected Ui::SeerPrintpointCreateDialogForm { Q_OBJECT public: explicit SeerPrintpointCreateDialog (QWidget* parent = 0); ~SeerPrintpointCreateDialog (); void setFilename (const QString& text); void setFunctionName (const QString& text); void setLabelName (const QString& text); void setLineNumber (const QString& text); QString filenameText () const; QString functionNameText () const; QString labelNameText () const; QString lineNumberText () const; void setTemporaryEnabled (bool flag); void setPendingEnabled (bool flag); void setDisabledEnabled (bool flag); void setConditionalEnabled (bool flag); void setIgnoreCountEnabled (bool flag); void setThreadIdEnabled (bool flag); void setConditionalText (const QString& text); void setIgnoreCountText (const QString& text); void setThreadIdText (const QString& text); bool temporaryEnabled () const; bool hardwareEnabled () const; bool pendingEnabled () const; bool disabledEnabled () const; bool conditionalEnabled () const; bool ignoreCountEnabled () const; bool threadIdEnabled () const; QString conditionalText () const; QString ignoreCountText () const; QString threadIdText () const; void setFormat (const QString& text); void setArguments (const QString& text); QString format () const; QString arguments () const; QString dprintfType () const; QString dprintfFunction () const; QString dprintfChannel () const; void setDPrintfType (const QString& text); void setDPrintfFunction (const QString& text); void setDPrintfChannel (const QString& text); QString printpointParameters () const; public slots: void handleDprintfTypeChanged (); private slots: void handleHelpToolButtonClicked (); private: }; epasveer-seer-97076f1/src/SeerPrintpointCreateDialog.ui000066400000000000000000000324201526321767600231440ustar00rootroot00000000000000 SeerPrintpointCreateDialogForm 0 0 607 635 Create a Printpoint Printpoint Location Filename true Line number true Qt::Horizontal 40 20 Function true Label true Qt::Horizontal 40 20 Printpoint Conditions Temporary Qt::Horizontal 40 20 Conditional true Pending Qt::Horizontal 40 20 Ignore Count true Thread Id true Disabled Qt::Horizontal 40 20 Printpoint Parameters Format A printf() style format string. Don't forget the '\n'. true Arguments List of variables to print, separated by a space. true Printpoint Type Type Printpoint output goes the Gdb Ouput tab. gdb typeButtonGroup Printpoint output goes to the Seer Console. call typeButtonGroup Printpoint output is handled by the gdbserver. agent typeButtonGroup Qt::Horizontal 561 20 Help about Printpoints. ... :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Function The name of a function in your program to use. true Channel The channel variable, if required by the function. true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok filenameLineEdit lineNumberLineEdit functionLineEdit labelLineEdit temporaryCheckBox conditionalCheckBox conditionalLineEdit pendingCheckBox ignoreCountCheckBox ignoreCountLineEdit disabledCheckBox threadIdCheckBox threadIdLineEdit formatLineEdit argumentsLineEdit typeGdbRadioButton typeCallRadioButton typeAgentRadioButton typeHelpToolButton dprintfFunctionLineEdit dprintfChannelLineEdit buttonBox accepted() SeerPrintpointCreateDialogForm accept() 248 254 157 274 buttonBox rejected() SeerPrintpointCreateDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerPrintpointsBrowserWidget.cpp000066400000000000000000000372761526321767600237560ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerPrintpointsBrowserWidget.h" #include "SeerPrintpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerPrintpointsBrowserWidget::SeerPrintpointsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets printpointsTreeWidget->clear(); printpointsTreeWidget->setSortingEnabled(false); printpointsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); printpointsTreeWidget->resizeColumnToContents(0); // number printpointsTreeWidget->resizeColumnToContents(1); // type printpointsTreeWidget->resizeColumnToContents(2); // disp printpointsTreeWidget->resizeColumnToContents(3); // enabled printpointsTreeWidget->resizeColumnToContents(4); // addr //printpointsTreeWidget->resizeColumnToContents(5); // func Too long to show printpointsTreeWidget->resizeColumnToContents(6); // file //printpointsTreeWidget->resizeColumnToContents(7); // fullname Too long to show printpointsTreeWidget->resizeColumnToContents(8); // line //printpointsTreeWidget->resizeColumnToContents(9); // script Too long to show printpointsTreeWidget->resizeColumnToContents(10); // thread-groups printpointsTreeWidget->resizeColumnToContents(11); // cond printpointsTreeWidget->resizeColumnToContents(12); // times printpointsTreeWidget->resizeColumnToContents(13); // ignore printpointsTreeWidget->resizeColumnToContents(14); // original-location /* printpointsTreeWidget->setColumnHidden(1, true); // ??? Hide or have a config to hide/show columns. printpointsTreeWidget->setColumnHidden(6, true); */ // Connect things. QObject::connect(printpointsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerPrintpointsBrowserWidget::handleItemDoubleClicked); QObject::connect(refreshPrintpointsToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleRefreshToolButton); QObject::connect(addPrintpointToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleAddToolButton); QObject::connect(deletePrintpointsToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleDeleteToolButton); QObject::connect(enablePrintpointsToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleEnableToolButton); QObject::connect(disablePrintpointsToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleDisableToolButton); QObject::connect(conditionBreakpointToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleConditionToolButton); QObject::connect(ignoreBreakpointToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleIgnoreToolButton); QObject::connect(commandBreakpointToolButton, &QToolButton::clicked, this, &SeerPrintpointsBrowserWidget::handleCommandToolButton); } SeerPrintpointsBrowserWidget::~SeerPrintpointsBrowserWidget () { } bool SeerPrintpointsBrowserWidget::isEmpty() const { return (printpointsTreeWidget->topLevelItemCount() == 0); } QStringList SeerPrintpointsBrowserWidget::breakpoints () const { return QStringList(); } void SeerPrintpointsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { printpointsTreeWidget->clear(); // // ^done,BreakpointTable={ // nr_rows="1",nr_cols="6", // // hdr=[ // {width="7",alignment="-1",col_name="number",colhdr="Num"}, // {width="14",alignment="-1",col_name="type",colhdr="Type"}, // {width="4",alignment="-1",col_name="disp",colhdr="Disp"}, // {width="3",alignment="-1",col_name="enabled",colhdr="Enb"}, // {width="18",alignment="-1",col_name="addr",colhdr="Address"}, // {width="40",alignment="2",col_name="what",colhdr="What"} // ], // // body=[ // bkpt={number="3", // type="dprintf", // disp="keep", // enabled="y", // addr="0x0000000000403a78", // func="main(int, char**)", // file="explorer.cpp", // fullname="/home/erniep/Development/Peak/src/Apps/Explorer/explorer.cpp", // line="84", // thread-groups=["i1"], // times="0", // script={"printf "i=%d argc=%d\n",i,argc"}, // original-location="-source /home/erniep/Development/Peak/src/Apps/Explorer/explorer.cpp -line 84"} // ] // } // Don't filter characters. It messes up \n in the the dprintf_text. // QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString body_text = Seer::parseFirst(text, "body=", '[', ']', false); if (body_text != "") { QStringList bkpt_list = Seer::parse(text, "bkpt=", '{', '}', false); for ( const auto& bkpt_text : bkpt_list ) { QString number_text = Seer::parseFirst(bkpt_text, "number=", '"', '"', false); QString type_text = Seer::parseFirst(bkpt_text, "type=", '"', '"', false); QString disp_text = Seer::parseFirst(bkpt_text, "disp=", '"', '"', false); QString enabled_text = Seer::parseFirst(bkpt_text, "enabled=", '"', '"', false); QString addr_text = Seer::parseFirst(bkpt_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(bkpt_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(bkpt_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(bkpt_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(bkpt_text, "line=", '"', '"', false); QString script_text = Seer::parseFirst(bkpt_text, "script=", '[', ']', false); QString thread_groups_text = Seer::parseFirst(bkpt_text, "thread-groups=", '[', ']', false); QString cond_text = Seer::parseFirst(bkpt_text, "cond=", '"', '"', false); QString times_text = Seer::parseFirst(bkpt_text, "times=", '"', '"', false); QString ignore_text = Seer::parseFirst(bkpt_text, "ignore=", '"', '"', false); QString original_location_text = Seer::parseFirst(bkpt_text, "original-location=", '"', '"', false); // Only look for 'breakpoint' type dprintf points. if (type_text != "dprintf") { continue; } // Remove '"' bookends and then remove one level of escapes. script_text = Seer::filterBookends (script_text, '"', '"'); script_text = Seer::filterEscapes(script_text); // Add the level to the tree. QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, number_text); topItem->setText(1, type_text); topItem->setText(2, disp_text); topItem->setText(3, enabled_text); topItem->setText(4, addr_text); topItem->setText(5, func_text); topItem->setText(6, QFileInfo(file_text).fileName()); topItem->setText(7, fullname_text); topItem->setText(8, line_text); topItem->setText(9, script_text); topItem->setText(10, thread_groups_text); topItem->setText(11, cond_text); topItem->setText(12, times_text); topItem->setText(13, ignore_text); topItem->setText(14, original_location_text); for (int i=0; icolumnCount(); i++) { topItem->setTextAlignment(i, Qt::AlignLeft|Qt::AlignTop); } printpointsTreeWidget->addTopLevelItem(topItem); } } }else{ // Ignore others. } printpointsTreeWidget->resizeColumnToContents(0); printpointsTreeWidget->resizeColumnToContents(1); printpointsTreeWidget->resizeColumnToContents(2); printpointsTreeWidget->resizeColumnToContents(3); printpointsTreeWidget->resizeColumnToContents(4); //printpointsTreeWidget->resizeColumnToContents(5); printpointsTreeWidget->resizeColumnToContents(6); //printpointsTreeWidget->resizeColumnToContents(7); printpointsTreeWidget->resizeColumnToContents(8); printpointsTreeWidget->resizeColumnToContents(9); printpointsTreeWidget->resizeColumnToContents(10); printpointsTreeWidget->resizeColumnToContents(11); printpointsTreeWidget->resizeColumnToContents(12); printpointsTreeWidget->resizeColumnToContents(13); printpointsTreeWidget->resizeColumnToContents(14); QApplication::restoreOverrideCursor(); } void SeerPrintpointsBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshPrintpointsList(); } void SeerPrintpointsBrowserWidget::handleSessionTerminated () { // Delete previous contents. printpointsTreeWidget->clear(); } void SeerPrintpointsBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); int lineno = item->text(8).toInt(); emit selectedFile(item->text(6), item->text(7), lineno); } void SeerPrintpointsBrowserWidget::handleRefreshToolButton () { emit refreshPrintpointsList(); } void SeerPrintpointsBrowserWidget::handleAddToolButton () { SeerPrintpointCreateDialog dlg(this); int ret = dlg.exec(); if (ret == 0) { return; } // Build a printpoint specification. QString type = dlg.dprintfType(); QString function = dlg.dprintfFunction(); QString channel = dlg.dprintfChannel(); QString parameters = dlg.printpointParameters(); // If nothing, just return. if (parameters == "" || type == "") { return; } // Otherwise send the command to create the printpoint. emit insertPrintpoint(type, function, channel, parameters); } void SeerPrintpointsBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = printpointsTreeWidget->selectedItems(); // Build a string that is a list of printpoints. QString printpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { printpoints += " "; } printpoints += (*i)->text(0); } // Don't do anything if the list of printpoints is empty. if (printpoints == "") { return; } // Send the signal. emit deletePrintpoints(printpoints); } void SeerPrintpointsBrowserWidget::handleEnableToolButton () { // Get selected tree items. QList items = printpointsTreeWidget->selectedItems(); // Build a string that is a list of printpoints. QString printpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { printpoints += " "; } printpoints += (*i)->text(0); } // Don't do anything if the list of printpoints is empty. if (printpoints == "") { return; } // Send the signal. emit enablePrintpoints(printpoints); } void SeerPrintpointsBrowserWidget::handleDisableToolButton () { // Get selected tree items. QList items = printpointsTreeWidget->selectedItems(); // Build a string that is a list of printpoints. QString printpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { printpoints += " "; } printpoints += (*i)->text(0); } // Don't do anything if the list of printpoints is empty. if (printpoints == "") { return; } // Send the signal. emit disablePrintpoints(printpoints); } void SeerPrintpointsBrowserWidget::handleConditionToolButton () { // Get selected tree items. Only allow one. QList items = printpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one printpoint when adding a condition.", QMessageBox::Ok); return; } // Get the condition text. bool ok; QString condition = QInputDialog::getText(this, "Seer", "Enter the condition for this printpoint.\nA blank condition will remove an existing one.", QLineEdit::Normal, items.front()->text(11), &ok); if (ok == false) { return; } // Get the selected printpoint number. QString printpoint = items.front()->text(0); // Send the signal. emit addBreakpointCondition(printpoint, condition); } void SeerPrintpointsBrowserWidget::handleIgnoreToolButton () { // Get selected tree items. Only allow one. QList items = printpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one printpoint when adding an ignore count.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; int count = QInputDialog::getInt(this, "Seer", "Enter the ignore count for this printpoint.\nA count of 0 will remove an existing one.", items.front()->text(13).toInt(), 0, 2147483647, 1, &ok); if (ok == false) { return; } // Get the selected printpoint number. QString printpoint = items.front()->text(0); // Send the signal. emit addBreakpointIgnore(printpoint, QString::number(count)); } void SeerPrintpointsBrowserWidget::handleCommandToolButton () { // Get selected tree items. Only allow one. QList items = printpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one printpoint when editing the command.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; QString command = QInputDialog::getText(this, "Seer", "Enter the command to execute for this printpoint.", QLineEdit::Normal, items.front()->text(9), &ok); if (ok == false) { return; } // Get the selected breakpoint number. QString breakpoint = items.front()->text(0); // Send the signal. emit addBreakpointCommand(breakpoint, command); } void SeerPrintpointsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); emit refreshPrintpointsList(); } epasveer-seer-97076f1/src/SeerPrintpointsBrowserWidget.h000066400000000000000000000045121526321767600234060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerPrintpointsBrowserWidget.h" class SeerPrintpointsBrowserWidget : public QWidget, protected Ui::SeerPrintpointsBrowserWidgetForm { Q_OBJECT public: explicit SeerPrintpointsBrowserWidget (QWidget* parent = 0); ~SeerPrintpointsBrowserWidget (); bool isEmpty () const; QStringList breakpoints () const; public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); private slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleRefreshToolButton (); void handleAddToolButton (); void handleDeleteToolButton (); void handleEnableToolButton (); void handleDisableToolButton (); void handleConditionToolButton (); void handleIgnoreToolButton (); void handleCommandToolButton (); signals: void refreshPrintpointsList (); void deletePrintpoints (QString printpoints); void enablePrintpoints (QString printpoints); void disablePrintpoints (QString printpoints); void addBreakpointCondition (QString printpoint, QString condition); void addBreakpointIgnore (QString printpoint, QString count); void addBreakpointCommand (QString breakpoint, QString command); void insertPrintpoint (QString type, QString function, QString channel, QString parameters); void selectedFile (QString file, QString fullname, int lineno); protected: void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerPrintpointsBrowserWidget.ui000066400000000000000000000160621526321767600235770ustar00rootroot00000000000000 SeerPrintpointsBrowserWidgetForm 0 0 1173 528 Form 100 100 15 Number Type Disposition Enabled Address Function File Fullname Line Command Thread Groups Condition Times Ignore Original Location Add a new printpoint. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Refresh the list of printpoints. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Enable selected printpoints. ... :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Disable selected printpoints. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Add condition to selected breakpoint. ? Add ignore count to selected breakpoint. # Edit command to selected breakpoint. ... :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Delete selected printpoints. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Vertical 20 40 Qt::Vertical 20 40 epasveer-seer-97076f1/src/SeerProgressIndicator.cpp000066400000000000000000000033171526321767600223430ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerProgressIndicator.h" #include #include #include #include #include SeerProgressIndicator::SeerProgressIndicator(QWidget* parent) : QProgressIndicator(parent) { setContextMenuPolicy(Qt::CustomContextMenu); QObject::connect(this, &SeerProgressIndicator::customContextMenuRequested, this, &SeerProgressIndicator::handleShowContextMenu); // Read settings. readSettings(); } SeerProgressIndicator::~SeerProgressIndicator() { } void SeerProgressIndicator::writeSettings () { QSettings settings; settings.beginGroup("progressindicator"); { settings.setValue("type", typeName()); } settings.endGroup(); } void SeerProgressIndicator::readSettings () { QSettings settings; settings.beginGroup("progressindicator"); { setType(settings.value("type", QString("BallRotate")).toString()); } settings.endGroup(); } void SeerProgressIndicator::handleShowContextMenu (const QPoint& point) { // Don't do anything. if (point.isNull()) { return; } // Possible indicator types. QStringList typeList = types(); if (typeList.size() == 0) { return; } // Build up menu. QMenu menu("Progress Indicators", this); for (int i=0; itext()); // Save it for next time. writeSettings(); } epasveer-seer-97076f1/src/SeerProgressIndicator.h000066400000000000000000000011421526321767600220020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "QProgressIndicator.h" class SeerProgressIndicator : public QProgressIndicator { Q_OBJECT public: SeerProgressIndicator(QWidget* parent = 0); ~SeerProgressIndicator(); protected: void writeSettings (); void readSettings (); protected slots: void handleShowContextMenu (const QPoint& point); private: }; epasveer-seer-97076f1/src/SeerRRConfigPage.cpp000066400000000000000000000031151526321767600211440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRRConfigPage.h" #include #include #include SeerRRConfigPage::SeerRRConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Connect things. QObject::connect(rrProgramToolButton, &QToolButton::clicked, this, &SeerRRConfigPage::handleRRProgramToolButton); // Setup the defaults. reset(); } SeerRRConfigPage::~SeerRRConfigPage() { } QString SeerRRConfigPage::rrProgram () const { return rrProgramLineEdit->text(); } QString SeerRRConfigPage::rrArguments () const { return rrArgumentsLineEdit->text(); } QString SeerRRConfigPage::gdbArguments () const { return gdbArgumentsLineEdit->text(); } void SeerRRConfigPage::setRRProgram (const QString& program) { rrProgramLineEdit->setText(program); } void SeerRRConfigPage::setRRArguments (const QString& arguments) { rrArgumentsLineEdit->setText(arguments); } void SeerRRConfigPage::setGdbArguments (const QString& arguments) { gdbArgumentsLineEdit->setText(arguments); } void SeerRRConfigPage::reset () { setRRProgram("/usr/bin/rr"); setRRArguments("replay --interpreter=mi"); setGdbArguments(""); } void SeerRRConfigPage::handleRRProgramToolButton () { QString program = QFileDialog::getOpenFileName(this, "Select a RR program to use.", rrProgram(), "", nullptr, QFileDialog::DontUseNativeDialog); if (program != "") { setRRProgram(program); } } epasveer-seer-97076f1/src/SeerRRConfigPage.h000066400000000000000000000022171526321767600206130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerRRConfigPage.h" class SeerRRConfigPage : public QWidget, protected Ui::SeerRRConfigPage { Q_OBJECT public: explicit SeerRRConfigPage (QWidget* parent = 0); ~SeerRRConfigPage (); QString rrProgram () const; QString rrArguments () const; QString gdbArguments () const; void setRRProgram (const QString& program); void setRRArguments (const QString& arguments); void setGdbArguments (const QString& arguments); void reset (); protected slots: void handleRRProgramToolButton (); }; epasveer-seer-97076f1/src/SeerRRConfigPage.ui000066400000000000000000000171111526321767600210000ustar00rootroot00000000000000 SeerRRConfigPage 0 0 794 920 SeerRRConfigPage RR Settings Specify the path and name of the RR debugger. true RR program RR arguments Any extra arguments to pass to the gdb debugger. true Open a file dialog to locate the RR debugger. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg Arguments to pass to the RR debugger. true GDB arguments <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Specify the RR program and location, as well as the RR arguments. </span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Changing many of these require saving the new configuration and restarting Seer to take effect</span>.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';"><br />&quot;RR program&quot; points to the path and name of the RR program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">&quot;RR arguments&quot; specifies the arguments to pass to RR. It must minimally have 'replay --interpreter=mi'. And other arguments you may need for RR.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">&quot;GDB arguments&quot; specified the arguments to pass on to gdb. Usually not needed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">RR will be started by the launcher specified in the GDB config tab.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">Between these input fields, Seer forms the command:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';"> $ /usr/bin/rr replay --interpreter=mi [RR-arguments] [trace-directory] [--tty /dev/pts] [-- gdb-arguments] </span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';"><br /></span>Note, Seer relies on the &quot;mi&quot; interpreter that is built into gdb. So, the &quot;--interpreter=mi&quot; argument is a must. This is specified in the &quot;RR arguments&quot; field.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';"><br />The &quot;trace-directory&quot; argument is given when you run Seer in the RR mode.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">The &quot;--tty&quot; device is handled automatically by Seer.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';"><br />Here's the RR Wiki page for more info on arguments.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">https://github.com/rr-debugger/rr/wiki/Usage<br /><br /></span></p></body></html> epasveer-seer-97076f1/src/SeerRegisterEditValueDialog.cpp000066400000000000000000000015101526321767600234020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRegisterEditValueDialog.h" #include SeerRegisterEditValueDialog::SeerRegisterEditValueDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets set("",""); // Connect things. } SeerRegisterEditValueDialog::~SeerRegisterEditValueDialog () { } void SeerRegisterEditValueDialog::set (const QString& regname, const QString& regvalue) { registerNameLineEdit->setText(regname); registerValueLineEdit->setText(regvalue); } QString SeerRegisterEditValueDialog::nameText () const { return registerNameLineEdit->text(); } QString SeerRegisterEditValueDialog::valueText () const { return registerValueLineEdit->text(); } epasveer-seer-97076f1/src/SeerRegisterEditValueDialog.h000066400000000000000000000013311526321767600230500ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerRegisterEditValueDialog.h" class SeerRegisterEditValueDialog : public QDialog, protected Ui::SeerRegisterEditValueDialogForm { Q_OBJECT public: explicit SeerRegisterEditValueDialog (QWidget* parent = 0); ~SeerRegisterEditValueDialog (); void set (const QString& regname, const QString& regvalue); QString nameText () const; QString valueText () const; public slots: private: }; epasveer-seer-97076f1/src/SeerRegisterEditValueDialog.ui000066400000000000000000000054211526321767600232420ustar00rootroot00000000000000 SeerRegisterEditValueDialogForm 0 0 322 164 Seer - Edit a Register Value Register Edit Name The name of the register to edit. true Value The register's new value. true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerRegisterEditValueDialogForm accept() 248 254 157 274 buttonBox rejected() SeerRegisterEditValueDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerRegisterProfileDialog.cpp000066400000000000000000000216501526321767600231270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRegisterProfileDialog.h" #include "SeerRegisterTreeWidgetItem.h" #include #include #include #include #include #include #include SeerRegisterProfileDialog::SeerRegisterProfileDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); registersTreeWidget->setSortingEnabled(true); // We can sort on columns. registersTreeWidget->sortByColumn(0, Qt::AscendingOrder); registersTreeWidget->resizeColumnToContents(0); // index registersTreeWidget->resizeColumnToContents(1); // name registersTreeWidget->resizeColumnToContents(2); // checkbox registersTreeWidget->clear(); // Letters, numbers, space, period, hypen, underscore. QRegularExpressionValidator* validator = new QRegularExpressionValidator(QRegularExpression("[a-zA-Z0-9\\ \\.\\-\\_]+")); profileNameLineEdit->setValidator(validator); // Setup the widgets setRegisters(QStringList(), QVector()); // Connect things. QObject::connect(enablePushButton, &QPushButton::clicked, this, &SeerRegisterProfileDialog::handleEnableSelected); QObject::connect(disablePushButton, &QPushButton::clicked, this, &SeerRegisterProfileDialog::handleDisableSelected); QObject::connect(importPushButton, &QPushButton::clicked, this, &SeerRegisterProfileDialog::handleImportFile); QObject::connect(exportPushButton, &QPushButton::clicked, this, &SeerRegisterProfileDialog::handleExportFile); // Restore window settings. readSettings(); } SeerRegisterProfileDialog::~SeerRegisterProfileDialog () { } void SeerRegisterProfileDialog::setRegisters (const QStringList& registerNames, const QVector& registerEnabled) { registersTreeWidget->clear(); for (int i=0; isetText(0, QString::number(i)); topItem->setText(1, registerNames[i]); if (registerEnabled[i] == true) { topItem->setCheckState(2, Qt::Checked); }else{ topItem->setCheckState(2, Qt::Unchecked); } registersTreeWidget->addTopLevelItem(topItem); } registersTreeWidget->resizeColumnToContents(0); registersTreeWidget->resizeColumnToContents(1); registersTreeWidget->resizeColumnToContents(2); } QStringList SeerRegisterProfileDialog::registerNames () const { QStringList registerNames; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = registersTreeWidget->topLevelItem(i); registerNames.push_back(topItem->text(1)); } return registerNames; } QVector SeerRegisterProfileDialog::registerEnabled () const { QVector registerEnabled; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = registersTreeWidget->topLevelItem(i); if (topItem->checkState(2) == Qt::Checked) { registerEnabled.push_back(true); }else{ registerEnabled.push_back(false); } } return registerEnabled; } void SeerRegisterProfileDialog::setProfileName (const QString& profileName) { profileNameLineEdit->setText(profileName); } QString SeerRegisterProfileDialog::profileName () const { return profileNameLineEdit->text(); } void SeerRegisterProfileDialog::accept () { if (profileNameLineEdit->text() == "") { QMessageBox::warning(this, "Seer", "The register profile name is blank.", QMessageBox::Ok); return; } if (profileNameLineEdit->text() == "allregisters") { QMessageBox::warning(this, "Seer", "The register profile name of 'allregisters' is reserved.\n\nChoose a different name.", QMessageBox::Ok); return; } QDialog::accept(); } void SeerRegisterProfileDialog::handleEnableSelected () { QList selected = registersTreeWidget->selectedItems(); foreach (QTreeWidgetItem* item, selected) { item->setCheckState(2, Qt::Checked); } } void SeerRegisterProfileDialog::handleDisableSelected () { QList selected = registersTreeWidget->selectedItems(); foreach (QTreeWidgetItem* item, selected) { item->setCheckState(2, Qt::Unchecked); } } void SeerRegisterProfileDialog::handleImportFile () { // // Get the name of the file to import. // QFileDialog dialog(this, "Seer Register Profile File", "./", "Text files (*.txt);;All files (*.*)"); dialog.setAcceptMode(QFileDialog::AcceptOpen); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("txt"); dialog.selectFile("registerprofile.txt"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } // // Open the file and read from it. // A simple format of: // // QFile file(files[0]); if (file.open(QIODevice::ReadOnly)) { QStringList registerNames; QVector registerEnabled; QTextStream stream(&file); while (stream.atEnd() == false) { QString line = stream.readLine(); QStringList words = line.split(QRegularExpression("\\s+")); // Ignore empty lines. if (words.count() == 0) { continue; } // Ignore null lines. if (words.count() == 1 && words[0] == "") { continue; } // There should be only two words on each line. if (words.count() != 2) { QMessageBox::critical(this, tr("Error"), tr("Can't load register profile file.\nEncountered a line not the form of:\n\n ")); return; } // The second word must be 'enabled' or 'disabled'. if (words[1] != "enabled" && words[1] != "disabled") { QMessageBox::critical(this, tr("Error"), tr("Can't load register profile file.\nEncountered a line not the form of:\n\n ")); return; } registerNames.push_back(words[0]); registerEnabled.push_back(words[1] == "enabled" ? true : false); } // Populate the list with the imported values. setRegisters (registerNames, registerEnabled); QMessageBox::information(this, "Seer", "Loaded."); }else{ QMessageBox::critical(this, tr("Error"), tr("Can't open register profile file.")); return; } } void SeerRegisterProfileDialog::handleExportFile () { // // Get the name of the file to export. // QFileDialog dialog(this, "Seer Register Profile File", "./", "Text files (*.txt);;All files (*.*)"); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("txt"); dialog.selectFile("registerprofile.txt"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } // // Create the file and write to it. // A simple format of: // // QFile file(files[0]); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); QStringList names = registerNames(); QVector enabled = registerEnabled(); for (int i=0; i // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerRegisterProfileDialog.h" class SeerRegisterProfileDialog : public QDialog, protected Ui::SeerRegisterProfileDialogForm { Q_OBJECT public: explicit SeerRegisterProfileDialog (QWidget* parent = 0); ~SeerRegisterProfileDialog (); void setRegisters (const QStringList& registerNames, const QVector& registerEnabled); QStringList registerNames () const; QVector registerEnabled () const; void setProfileName (const QString& profileName); QString profileName () const; public slots: void accept (); private slots: void handleEnableSelected (); void handleDisableSelected (); void handleImportFile (); void handleExportFile (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: }; epasveer-seer-97076f1/src/SeerRegisterProfileDialog.ui000066400000000000000000000121171526321767600227600ustar00rootroot00000000000000 SeerRegisterProfileDialogForm 0 0 600 601 Seer - Register Profile Editor 100 0 QAbstractItemView::ExtendedSelection true # Name Enabled Profile name (lowercase letters and numbers). Profile name true Enable selected items. Enable Selected Disable selected items. Disable Selected Qt::Vertical QSizePolicy::Fixed 20 40 Import items from a file. Import Export items to a file. Export Qt::Vertical QSizePolicy::Expanding 20 318 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerRegisterProfileDialogForm accept() 248 254 157 274 buttonBox rejected() SeerRegisterProfileDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerRegisterTreeWidgetItem.cpp000066400000000000000000000014101526321767600232610ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRegisterTreeWidgetItem.h" #include #include #include // // SeerRegisterTreeWidgetItem // bool SeerRegisterTreeWidgetItem::operator< (const QTreeWidgetItem& other) const { int column = treeWidget()->sortColumn(); // If no sort column set, then default to ascending order. if (column < 0) { return true; } // If sort on column 0, then compare numerically. if (column == 0) { return text(column).toInt() < other.text(column).toInt(); } // Otherwise, all other columns are textual. return text(column) < other.text(column); } epasveer-seer-97076f1/src/SeerRegisterTreeWidgetItem.h000066400000000000000000000020611526321767600227310ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include class SeerRegisterTreeWidgetItem : public QTreeWidgetItem { public: /* Do we need to specify the base constructors? QTreeWidgetItem(const QTreeWidgetItem &other) QTreeWidgetItem(QTreeWidgetItem *parent, QTreeWidgetItem *preceding, int type = Type) QTreeWidgetItem(QTreeWidgetItem *parent, const QStringList &strings, int type = Type) QTreeWidgetItem(QTreeWidgetItem *parent, int type = Type) QTreeWidgetItem(QTreeWidget *parent, QTreeWidgetItem *preceding, int type = Type) QTreeWidgetItem(QTreeWidget *parent, const QStringList &strings, int type = Type) QTreeWidgetItem(QTreeWidget *parent, int type = Type) QTreeWidgetItem(const QStringList &strings, int type = Type) QTreeWidgetItem(int type = Type) */ virtual bool operator< (const QTreeWidgetItem& other) const; }; epasveer-seer-97076f1/src/SeerRegisterValuesBrowserWidget.cpp000066400000000000000000000564151526321767600243650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRegisterValuesBrowserWidget.h" #include "SeerRegisterEditValueDialog.h" #include "SeerRegisterProfileDialog.h" #include "SeerRegisterTreeWidgetItem.h" #include "SeerUtl.h" #include "QEditDelegate.h" #include #include #include #include #include #include #include #include #include #include SeerRegisterValuesBrowserWidget::SeerRegisterValuesBrowserWidget (QWidget* parent) : QWidget(parent) { _newProfileAction = 0; _deleteProfileAction = 0; // Construct the UI. setupUi(this); // Setup the widgets registersTreeWidget->setMouseTracking(true); registersTreeWidget->sortByColumn(0, Qt::AscendingOrder); registersTreeWidget->setSortingEnabled(true); // We can sort on columns. registersTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); registersTreeWidget->resizeColumnToContents(0); // number registersTreeWidget->resizeColumnToContents(1); // name registersTreeWidget->resizeColumnToContents(2); // value registersTreeWidget->resizeColumnToContents(3); // used registersTreeWidget->setColumnHidden(3, true); // Hide the 'used' column. registersTreeWidget->clear(); registerFormatComboBox->addItem("Natural", QVariant("N")); registerFormatComboBox->addItem("Hex", QVariant("x")); registerFormatComboBox->addItem("Octal", QVariant("o")); registerFormatComboBox->addItem("Binary", QVariant("t")); registerFormatComboBox->addItem("Decimal", QVariant("d")); registerFormatComboBox->addItem("Raw", QVariant("r")); registerProfileComboBox->addItem("allregisters"); _needsRegisterNames = true; // Create edit delegate. QAllowEditDelegate* editDelegate = new QAllowEditDelegate(this); registersTreeWidget->setItemDelegateForColumn(0, new QNoEditDelegate(this)); registersTreeWidget->setItemDelegateForColumn(1, new QNoEditDelegate(this)); registersTreeWidget->setItemDelegateForColumn(2, editDelegate); registersTreeWidget->setItemDelegateForColumn(3, new QNoEditDelegate(this)); // Preference menu. QMenu* menu = new QMenu(); _newProfileAction = menu->addAction("New profile"); _modifyProfileAction = menu->addAction("Modify current profile"); _deleteProfileAction = menu->addAction("Delete current profile"); preferencesToolButton->setMenu(menu); preferencesToolButton->setPopupMode(QToolButton::InstantPopup); // Connect things. QObject::connect(registersTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerRegisterValuesBrowserWidget::handleItemDoubleClicked); QObject::connect(registersTreeWidget, &QTreeWidget::itemEntered, this, &SeerRegisterValuesBrowserWidget::handleItemEntered); QObject::connect(registersTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerRegisterValuesBrowserWidget::handleContextMenu); QObject::connect(editDelegate, &QAllowEditDelegate::editingFinished, this, &SeerRegisterValuesBrowserWidget::handleIndexEditingFinished); QObject::connect(registerFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerRegisterValuesBrowserWidget::handleFormatChanged); QObject::connect(registersTreeWidget->header(), &QHeaderView::sectionClicked, this, &SeerRegisterValuesBrowserWidget::handleColumnSelected); QObject::connect(_newProfileAction, &QAction::triggered, this, &SeerRegisterValuesBrowserWidget::handleNewProfile); QObject::connect(_modifyProfileAction, &QAction::triggered, this, &SeerRegisterValuesBrowserWidget::handleModifyProfile); QObject::connect(_deleteProfileAction, &QAction::triggered, this, &SeerRegisterValuesBrowserWidget::handleDeleteProfile); QObject::connect(registerProfileComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerRegisterValuesBrowserWidget::handleProfileChanged); // Restore settings. readSettings(); } SeerRegisterValuesBrowserWidget::~SeerRegisterValuesBrowserWidget () { } void SeerRegisterValuesBrowserWidget::setRegisterFormat (QString fmt) { registerFormatComboBox->setCurrentText(fmt); } void SeerRegisterValuesBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,register-names=[") && text.endsWith("]")) { // "^done,register-names=[\"rax\",\"rbx\",\"rcx\",\"rdx\",\"rsi\",\"rdi\",\"rbp\",\"rsp\", // \"r8\",\"r9\",\"r10\",\"r11\",\"r12\",\"r13\",\"r14\",\"r15\", // \"rip\",\"eflags\",\"cs\",\"ss\",\"ds\",\"es\",\"fs\",\"gs\", // This recreates the tree. registersTreeWidget->clear(); QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "register-names=", '[', ']', false); QStringList name_list = Seer::parse(frame_text, "", '"', '"', false); int i = 0; for ( const auto& name_text : name_list ) { // Some register names come back as "". Not sure why or how. // We'll skip them but we need to still increment the // register id number. Otherwise we may update the wrong // register because we search for the register by its id. if (name_text != "") { QTreeWidgetItem* topItem = new SeerRegisterTreeWidgetItem; topItem->setFlags(topItem->flags() | Qt::ItemIsEditable); topItem->setText(0, QString::number(i)); topItem->setText(1, name_text); topItem->setText(2, ""); topItem->setText(3, "new"); topItem->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); registersTreeWidget->addTopLevelItem(topItem); } i++; } handleShowHideRegisters(); _needsRegisterNames = false; }else if (text.startsWith("^done,register-values=[") && text.endsWith("]")) { // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(registersTreeWidget); while (*it) { (*it)->setText(3, "unused"); ++it; } // "^done,register-values=[{number=\"0\",value=\"0x4005e7\"},{number=\"1\",value=\"0x0\"},{number=\"2\",value=\"0x100\"}, // {number=\"3\",value=\"0x7fffffffd548\"},{number=\"4\",value=\"0x7fffffffd538\"},{number=\"5\",value=\"0x1\"},... // {number=\"205\",value=\"0x0\"},{number=\"206\",value=\"0x0\"}]" QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "register-values=", '[', ']', false); QStringList registers_list = Seer::parse(frame_text, "", '{', '}', false); for ( const auto& register_text : registers_list ) { QString number_text = Seer::parseFirst(register_text, "number=", '"', '"', false); QString value_text = Seer::parseFirst(register_text, "value=", '"', '"', false); // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. QList matches = registersTreeWidget->findItems(number_text, Qt::MatchExactly, 0); // Found a match. Reuse it. Set the value. // If no matches, do not add this entry. if (matches.size() > 0) { QTreeWidgetItem* item = matches.takeFirst(); bool isDifferent = false; // Flag it as different of the new value is different than the old version _AND_ // the old one isn't "" (like after a refresh). if (item->text(2) != "" && item->text(2) != value_text) { isDifferent = true; } item->setText(2, value_text); item->setText(3, "reused"); QFont f1 = item->font(1); QFont f2 = item->font(2); f1.setBold(isDifferent); f2.setBold(isDifferent); item->setFont(1, f1); item->setFont(2, f2); } } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. QList matches = registersTreeWidget->findItems("unused", Qt::MatchExactly, 3); qDeleteAll(matches); }else{ // Ignore others. } registersTreeWidget->resizeColumnToContents(0); registersTreeWidget->resizeColumnToContents(1); registersTreeWidget->resizeColumnToContents(2); registersTreeWidget->resizeColumnToContents(3); QApplication::restoreOverrideCursor(); } void SeerRegisterValuesBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } if (_needsRegisterNames) { emit refreshRegisterNames(); _needsRegisterNames = false; } // Get the format. QString fmt = registerFormatComboBox->currentData().toString(); // refresh(); // If a stopping point is reached, just refresh the values. // The register names should already be there. emit refreshRegisterValues(fmt); } void SeerRegisterValuesBrowserWidget::handleSessionTerminated () { // Delete previous contents. registersTreeWidget->clear(); _needsRegisterNames = true; } void SeerRegisterValuesBrowserWidget::refresh () { // Force new names. _needsRegisterNames = true; // Get the format. QString fmt = registerFormatComboBox->currentData().toString(); emit refreshRegisterNames(); emit refreshRegisterValues(fmt); } void SeerRegisterValuesBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); _editItem(item); } void SeerRegisterValuesBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(1) + " : " + item->text(2)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerRegisterValuesBrowserWidget::handleContextMenu (const QPoint& pos) { // Get the item at the cursor. QTreeWidgetItem* item = registersTreeWidget->itemAt(pos); // Construct the menu. QMenu* menu = new QMenu("Options", this); QAction* editAction = menu->addAction("Edit selected"); QAction* copyAction = menu->addAction("Copy selected"); QAction* copyAllAction = menu->addAction("Copy all"); // If no selected item, disable 'selected' copy but allow 'all'. if (item == 0) { editAction->setEnabled(false); copyAction->setEnabled(false); } // Execute the menu. Return if nothing. QAction* action = menu->exec(registersTreeWidget->mapToGlobal(pos)); if (action == 0) { return; } // Do register edit. if (action == editAction) { _editItem(item); } // Get selected tree items. QList items; // Get list of 'select' items. if (action == copyAction) { items = registersTreeWidget->selectedItems(); } // Get list of 'all' items. if (action == copyAllAction) { items = registersTreeWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard); } // Populate the clipboard. if (items.size() == 0) { return; } QClipboard* clipboard = QGuiApplication::clipboard(); QString text; for (int i=0; iisHidden() == true) { continue; } text += items[i]->text(1) + ":" + items[i]->text(2) + '\n'; } clipboard->setText(text, QClipboard::Clipboard); clipboard->setText(text, QClipboard::Selection); } void SeerRegisterValuesBrowserWidget::handleIndexEditingFinished (const QModelIndex& index) { QTreeWidgetItem* item = registersTreeWidget->getItemFromIndex(index); if (item == 0) { return; } // Get the format. QString fmt = registerFormatComboBox->currentData().toString(); // Get the new value; QString value = item->text(2); // Emit the signal to change the register to the new value. emit setRegisterValue(fmt, item->text(1), value); } void SeerRegisterValuesBrowserWidget::handleFormatChanged (int index) { // Get the format. QString fmt = registerFormatComboBox->itemData(index).toString(); // Refresh the register values. emit refreshRegisterValues(fmt); } void SeerRegisterValuesBrowserWidget::handleColumnSelected (int logicalIndex) { Q_UNUSED(logicalIndex); writeSettings(); } void SeerRegisterValuesBrowserWidget::handleNewProfile () { if (registersTreeWidget->topLevelItemCount() == 0) { QMessageBox::warning(this, "Seer", "When creating a profile, Seer needs to be debugging a program.", QMessageBox::Ok); return; } // Build a list of registers. QStringList registerNames; QVector registerEnabled; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* item = registersTreeWidget->topLevelItem(i); registerNames.push_back(item->text(1)); registerEnabled.push_back(true); } // Bring up the register profile dialog. SeerRegisterProfileDialog dlg(this); dlg.setRegisters(registerNames, registerEnabled); if (dlg.exec()) { QString profileName = dlg.profileName(); if (profileName == "") { return; } registerNames = dlg.registerNames(); registerEnabled = dlg.registerEnabled(); registerProfileComboBox->addItem(profileName); registerProfileComboBox->setCurrentText(profileName); writeProfileSettings(profileName, registerNames, registerEnabled); writeSettings(); // Use them. _registerNames = registerNames; _registerEnabled = registerEnabled; handleShowHideRegisters(); } } void SeerRegisterValuesBrowserWidget::handleModifyProfile () { QString profileName = registerProfileComboBox->currentText(); if (profileName == "allregisters") { QMessageBox::warning(this, "Seer", "The profile 'allregisters' is reserved.\n\nIt can't be modified.", QMessageBox::Ok); return; } // Build a list of registers. QStringList registerNames = _registerNames; QVector registerEnabled = _registerEnabled; // Bring up the register profile dialog. SeerRegisterProfileDialog dlg(this); dlg.setProfileName(profileName); dlg.setRegisters(registerNames, registerEnabled); if (dlg.exec()) { // Get the (potenially new) profile name. QString newProfileName = dlg.profileName(); if (newProfileName == "") { return; } registerNames = dlg.registerNames(); registerEnabled = dlg.registerEnabled(); // If it's a new name, add it to the list and switch to it. if (newProfileName != profileName) { registerProfileComboBox->addItem(newProfileName); registerProfileComboBox->setCurrentText(newProfileName); } // Write out the setting changes. writeProfileSettings(newProfileName, registerNames, registerEnabled); writeSettings(); // Use them. _registerNames = registerNames; _registerEnabled = registerEnabled; handleShowHideRegisters(); } } void SeerRegisterValuesBrowserWidget::handleDeleteProfile () { int index = registerProfileComboBox->currentIndex(); if (index < 0) { return; } QString profileName = registerProfileComboBox->itemText(index); if (profileName == "") { return; } if (profileName == "allregisters") { QMessageBox::warning(this, "Seer", "The profile 'allregisters' is reserved.\n\nIt can't be deleted.", QMessageBox::Ok); return; } QMessageBox::StandardButton ans = QMessageBox::question(this, "Seer", "Delete profile '" + profileName + "'?"); if (ans != QMessageBox::Yes) { return; } // Delete the profile from the settings. deleteProfileSettings(profileName); // Delete the profile from the list of profiles. registerProfileComboBox->removeItem(index); // Write the current settings. writeSettings(); // Switch to the next profile in the list of profiles. index = registerProfileComboBox->currentIndex(); if (index < 0) { return; } handleProfileChanged (index); } void SeerRegisterValuesBrowserWidget::handleShowHideRegisters () { // If the list is empty, show all. if (_registerNames.count() == 0 || _registerEnabled.count() == 0) { for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = registersTreeWidget->topLevelItem(i); topItem->setHidden(false); } return; } // There is a list. Hide all, then show which ones are enabled. for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = registersTreeWidget->topLevelItem(i); topItem->setHidden(true); } for (int i=0; i<_registerNames.count(); i++) { if (_registerEnabled[i] == false) { continue; } QString registerName = _registerNames[i]; QList matches = registersTreeWidget->findItems(registerName, Qt::MatchExactly, 1); for (int i=0; isetHidden(false); } } } void SeerRegisterValuesBrowserWidget::handleProfileChanged (int index) { // Get the profile. QString profileName = registerProfileComboBox->itemText(index); // Build a list of registers. QStringList registerNames; QVector registerEnabled; bool f = readProfileSettings(profileName, registerNames, registerEnabled); if (f == false) { return; } // Use them. _registerNames = registerNames; _registerEnabled = registerEnabled; handleShowHideRegisters(); writeSettings(); } void SeerRegisterValuesBrowserWidget::writeSettings () { QSettings settings; QStringList registerprofiles; for (int i=0; icount(); i++) { if (registerProfileComboBox->itemText(i) == "allregisters") { continue; } registerprofiles.push_back(registerProfileComboBox->itemText(i)); } settings.beginGroup("registerwindow"); { settings.setValue("sortcolumn", registersTreeWidget->header()->sortIndicatorSection()); settings.setValue("sortorder", registersTreeWidget->header()->sortIndicatorOrder()); settings.setValue("registerprofile", registerProfileComboBox->currentText()); settings.setValue("registerprofiles", registerprofiles); } settings.endGroup(); } void SeerRegisterValuesBrowserWidget::readSettings () { QSettings settings; settings.beginGroup("registerwindow"); { int column = settings.value("sortcolumn", 0).toInt(); int order = settings.value("sortorder", Qt::AscendingOrder).toInt(); registersTreeWidget->header()->setSortIndicator(column, (Qt::SortOrder)order); QString registerProfileName = settings.value("registerprofile").toString(); QStringList registerProfiles = settings.value("registerprofiles").toStringList(); registerProfileComboBox->addItems(registerProfiles); registerProfileComboBox->setCurrentText(registerProfileName); } settings.endGroup(); } void SeerRegisterValuesBrowserWidget::writeProfileSettings (const QString& profileName, const QStringList& registerNames, const QVector& registerEnabled) { QSettings settings; QStringList registerEnabledFlags; for (int i=0; i& registerEnabled) { if (profileName == "" || profileName == "allregisters") { registerNames.resize(0); registerEnabled.resize(0); return true; } QSettings settings; settings.beginGroup("registerprofile_" + profileName); { QVariant registerNamesVariant = settings.value("registernames"); QVariant registerEnabledVariant = settings.value("registerenabled"); QStringList registerEnabledFlags; // Not found? Return with error. if (registerNamesVariant == QVariant() || registerEnabledVariant == QVariant()) { return false; } // Okay, we found it. Populate the containters. registerNames = registerNamesVariant.toStringList(); registerEnabledFlags = registerEnabledVariant.toStringList(); registerEnabled.resize(0); for (int i=0; itext(1), item->text(2)); int ret = dlg.exec(); if (ret == 0) { return; } // The register name could be changed, as well as the value. QString name = dlg.nameText(); QString value = dlg.valueText(); if (name == "") { return; } if (value == "") { return; } // Get the format. QString fmt = registerFormatComboBox->currentData().toString(); // Emit the signal to change the register to the new value. emit setRegisterValue(fmt, name, value); return; } epasveer-seer-97076f1/src/SeerRegisterValuesBrowserWidget.h000066400000000000000000000067711526321767600240320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "ui_SeerRegisterValuesBrowserWidget.h" #include #include #include #include #include #include class SeerRegisterValuesBrowserWidget : public QWidget, protected Ui::SeerRegisterValuesBrowserWidgetForm { Q_OBJECT public: explicit SeerRegisterValuesBrowserWidget (QWidget* parent = 0); ~SeerRegisterValuesBrowserWidget (); public: void setRegisterFormat (QString fmt); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); void handleContextMenu (const QPoint& pos); void handleIndexEditingFinished (const QModelIndex& index); void handleFormatChanged (int index); void handleColumnSelected (int logicalIndex); void handleNewProfile (); void handleModifyProfile (); void handleDeleteProfile (); void handleShowHideRegisters (); void handleProfileChanged (int index); signals: void refreshRegisterNames (); void refreshRegisterValues (QString fmt); void setRegisterValue (QString fmt, QString name, QString value); protected: void showEvent (QShowEvent* event); void readSettings (); void writeSettings (); bool readProfileSettings (const QString& profileName, QStringList& registerNames, QVector& registerEnabled); void writeProfileSettings (const QString& profileName, const QStringList& registerNames, const QVector& registerEnabled); void deleteProfileSettings (const QString& profileName); private: void _editItem (QTreeWidgetItem* item); bool _needsRegisterNames; QStringList _registerNames; QVector _registerEnabled; QAction* _newProfileAction; QAction* _modifyProfileAction; QAction* _deleteProfileAction; }; epasveer-seer-97076f1/src/SeerRegisterValuesBrowserWidget.ui000066400000000000000000000103641526321767600242110ustar00rootroot00000000000000 SeerRegisterValuesBrowserWidgetForm 0 0 733 528 Form Format 0 0 Register Value Format. Qt::Horizontal 508 23 Preferences :/seer/resources/RelaxLightIcons/application-menu.svg:/seer/resources/RelaxLightIcons/application-menu.svg Profile 50 0 Register Profile Selection. QComboBox::AdjustToContentsOnFirstShow Qt::Horizontal 538 23 4 true # Name Value Used QIndexTreeWidget QTreeWidget
QIndexTreeWidget.h
registerFormatComboBox registerProfileComboBox preferencesToolButton registersTreeWidget
epasveer-seer-97076f1/src/SeerRunStatusIndicator.cpp000066400000000000000000000056641526321767600225160ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRunStatusIndicator.h" #include #include #include SeerRunStatusIndicator::SeerRunStatusIndicator(QWidget* parent) : QLabel(parent) { QSize size = fontMetrics().size(Qt::TextSingleLine, "XXXXXXXXXXXXXXXXXX"); setAlignment(Qt::AlignCenter); setFixedWidth(size.width()); setText("Status"); setStyleSheet("background-color: lightgray; color: black; font-weight: bold;"); } SeerRunStatusIndicator::~SeerRunStatusIndicator() { } void SeerRunStatusIndicator::setRunStatus (SeerRunStatusIndicator::RunStatus status) { if (status == RunStatus::Idle) { setText("Session Terminated"); setStyleSheet("background-color: lightgray; color: black; font-weight: bold;"); }else if (status == RunStatus::Stopped) { setText("Stopped"); setStyleSheet("background-color: red; color: black; font-weight: bold;"); }else if (status == RunStatus::Stop_By_Breakpoint) { setText("Stop by breakpoint"); setStyleSheet("background-color: yellow; color: black; font-weight: bold;"); }else if (status == RunStatus::Running) { setText("Running"); setStyleSheet("background-color: green; color: black; font-weight: bold;"); }else{ setText("Unknown"); } emit statusChanged(status); } void SeerRunStatusIndicator::handleText (const QString& text) { if (text.startsWith("*running,thread-id=\"")) { // *running,thread-id="all" // *running,thread-id="2" setRunStatus(SeerRunStatusIndicator::Running); }else if (text.startsWith("*stopped")) { if (text.startsWith("*stopped,reason=\"breakpoint-hit\"")) setRunStatus(SeerRunStatusIndicator::Stop_By_Breakpoint); else //^connected,frame={level=\"0\",addr=\"0x00007f48351f80c1\",func=\"read\",args=[],from=\"/lib64/libc.so.6\",arch=\"i386:x86-64\"}" setRunStatus(SeerRunStatusIndicator::Stopped); }else if (text.startsWith("=thread-exited")) { //=thread-exited,id="1",group-id="i1" setRunStatus(SeerRunStatusIndicator::Stopped); }else if (text.startsWith("=thread-group-exited")) { //=thread-group-exited,id="i1" setRunStatus(SeerRunStatusIndicator::Stopped); } else if (text.startsWith("^done,stack")) { // When finish command is invoked setRunStatus(SeerRunStatusIndicator::Stopped); } else{ // All other text is ignored by this widget. // qDebug() << text; } } // handle when program stop/ killed void SeerRunStatusIndicator::handleSessionTerminated() { setText("Session Terminated"); setStyleSheet("background-color: lightgray; color: black; font-weight: bold;"); // also tell SeerProgressIndicator to stop spinning setRunStatus(SeerRunStatusIndicator::Idle); } epasveer-seer-97076f1/src/SeerRunStatusIndicator.h000066400000000000000000000020611526321767600221470ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include class SeerRunStatusIndicator : public QLabel { Q_OBJECT public: enum RunStatus { Idle = 0, Stopped = 1, Stop_By_Breakpoint = 2, Running = 3, }; explicit SeerRunStatusIndicator(QWidget* parent = 0); ~SeerRunStatusIndicator (); void setRunStatus (SeerRunStatusIndicator::RunStatus status); SeerRunStatusIndicator::RunStatus runStatus () const; signals: void statusChanged (SeerRunStatusIndicator::RunStatus status); public slots: void handleText (const QString& text); void handleSessionTerminated (); protected: private: }; epasveer-seer-97076f1/src/SeerRustSourceHighlighter.cpp000066400000000000000000000104661526321767600232020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerRustSourceHighlighter.h" SeerRustSourceHighlighter::SeerRustSourceHighlighter(QTextDocument *parent) : SeerSourceHighlighter(parent) { // Set to default formats. setHighlighterSettings(SeerHighlighterSettings::populate("")); } void SeerRustSourceHighlighter::setHighlighterSettings(const SeerHighlighterSettings &settings) { _highlighterSettings = settings; _classFormat = _highlighterSettings.get("Class"); _quotationFormat = _highlighterSettings.get("Quotation"); _functionFormat = _highlighterSettings.get("Function"); _singleLineCommentFormat = _highlighterSettings.get("Comment"); _multiLineCommentFormat = _highlighterSettings.get("Multiline Comment"); _keywordFormat = _highlighterSettings.get("Keyword"); const QString keywordPatterns[] = { QStringLiteral("\\bas\\b"), QStringLiteral("\\bbreak\\b"), QStringLiteral("\\bconst\\b"), QStringLiteral("\\bcontinue\\b"), QStringLiteral("\\bcrate\\b"), QStringLiteral("\\belse\\b"), QStringLiteral("\\benum\\b"), QStringLiteral("\\bextern\\b"), QStringLiteral("\\bfalse\\b"), QStringLiteral("\\bfn\\b"), QStringLiteral("\\bfor\\b"), QStringLiteral("\\bif\\b"), QStringLiteral("\\bimpl\\b"), QStringLiteral("\\bin\\b"), QStringLiteral("\\blet\\b"), QStringLiteral("\\bloop\\b"), QStringLiteral("\\bmatch\\b"), QStringLiteral("\\bmod\\b"), QStringLiteral("\\bmove\\b"), QStringLiteral("\\bmut\\b"), QStringLiteral("\\bpub\\b"), QStringLiteral("\\bref\\b"), QStringLiteral("\\breturn\\b"), QStringLiteral("\\bself\\b"), QStringLiteral("\\bSelf\\b"), QStringLiteral("\\bstatic\\b"), QStringLiteral("\\bstruct\\b"), QStringLiteral("\\bsuper\\b"), QStringLiteral("\\btrait\\b"), QStringLiteral("\\btrue\\b"), QStringLiteral("\\btype\\b"), QStringLiteral("\\bunsafe\\b"), QStringLiteral("\\buse\\b"), QStringLiteral("\\bwhere\\b"), QStringLiteral("\\bwhile\\b"), QStringLiteral("\\basync\\b"), QStringLiteral("\\bawait\\b"), QStringLiteral("\\bdyn\\b"), QStringLiteral("\\babstract\\b"), QStringLiteral("\\bbecome\\b"), QStringLiteral("\\bbox\\b"), QStringLiteral("\\bdo\\b"), QStringLiteral("\\bfinal\\b"), QStringLiteral("\\bmacro\\b"), QStringLiteral("\\boverride\\b"), QStringLiteral("\\bpriv\\b"), QStringLiteral("\\btypeof\\b"), QStringLiteral("\\bunsized\\b"), QStringLiteral("\\bvirtual\\b"), QStringLiteral("\\byield\\b"), QStringLiteral("\\btry\\b"), QStringLiteral("\\bgen\\b"), QStringLiteral("#!?\\[.*\\]"), }; _highlightingRules.clear(); // Clear old rules. HighlightingRule rule; // Set class format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Z][A-Za-z0-9_]*\\b")); rule.format = _classFormat; _highlightingRules.append(rule); // Set function format and expression. rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Za-z0-9_!]+(?=\\s*\\()")); rule.format = _functionFormat; _highlightingRules.append(rule); // Set keywords format and expression (must have precedence over functions) for (const QString &pattern : keywordPatterns) { rule.pattern = QRegularExpression(pattern); rule.format = _keywordFormat; _highlightingRules.append(rule); } // Set quote format and expression. This rule must come after the function // and keyword rules so that string contents keep the quote format (same // order as the Ada highlighter). rule.pattern = QRegularExpression(QStringLiteral("\"[^\"]*\"")); rule.format = _quotationFormat; _highlightingRules.append(rule); // Set single line comment format and expression. rule.pattern = QRegularExpression(QStringLiteral("//[^\n]*")); rule.format = _singleLineCommentFormat; _highlightingRules.append(rule); // Set multi-line comment expression. Format is defined later. _commentStartExpression = QRegularExpression(QStringLiteral("/\\*")); _commentEndExpression = QRegularExpression(QStringLiteral("\\*/")); } epasveer-seer-97076f1/src/SeerRustSourceHighlighter.h000066400000000000000000000007241526321767600226430ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerHighlighterSettings.h" #include "SeerSourceHighlighter.h" class SeerRustSourceHighlighter : public SeerSourceHighlighter { Q_OBJECT public: SeerRustSourceHighlighter(QTextDocument *parent = 0); virtual void setHighlighterSettings (const SeerHighlighterSettings &settings) override; }; epasveer-seer-97076f1/src/SeerSeerConfigPage.cpp000066400000000000000000000043351526321767600215240ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSeerConfigPage.h" #include SeerSeerConfigPage::SeerSeerConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Connect things. // Setup the defaults. reset(); } SeerSeerConfigPage::~SeerSeerConfigPage() { } void SeerSeerConfigPage::setConsoleMode (const QString& mode) { if (mode == "attached") { attachedRadioButton->setChecked(true); }else if (mode == "detached") { detachedRadioButton->setChecked(true); }else if (mode == "detachedminimized") { detachedMinimizedRadioButton->setChecked(true); }else{ attachedRadioButton->setChecked(true); } } QString SeerSeerConfigPage::consoleMode () const { if (attachedRadioButton->isChecked()) { return "attached"; }else if (detachedRadioButton->isChecked()) { return "detached"; }else if (detachedMinimizedRadioButton->isChecked()) { return "detachedminimized"; }else{ return "attached"; } } void SeerSeerConfigPage::setConsoleScrollLines (int count) { consoleScrollLinesSpinBox->setValue(count); } int SeerSeerConfigPage::consoleScrollLines () const { return consoleScrollLinesSpinBox->value(); } void SeerSeerConfigPage::setRememberWindowSizes (bool flag) { rememberSizescheckBox->setChecked(flag); } bool SeerSeerConfigPage::rememberWindowSizes () const { return rememberSizescheckBox->isChecked(); } void SeerSeerConfigPage::setRememberManualCommandCount (int count) { rememberGdbCommandsSpinBox->setValue(count); } int SeerSeerConfigPage::rememberManualCommandCount () const { return rememberGdbCommandsSpinBox->value(); } void SeerSeerConfigPage::setClearManualCommandHistory (bool flag) { clearHistoryCheckBox->setChecked(flag); } bool SeerSeerConfigPage::clearManualCommandHistory () const { return clearHistoryCheckBox->isChecked(); } void SeerSeerConfigPage::reset () { setConsoleMode("attached"); setConsoleScrollLines(1000); setRememberWindowSizes(true); setRememberManualCommandCount(10); setClearManualCommandHistory(false); } epasveer-seer-97076f1/src/SeerSeerConfigPage.h000066400000000000000000000025751526321767600211750ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerSeerConfigPage.h" class SeerSeerConfigPage : public QWidget, public Ui::SeerSeerConfigPage { Q_OBJECT public: explicit SeerSeerConfigPage (QWidget* parent = 0); ~SeerSeerConfigPage (); void setConsoleMode (const QString& mode); QString consoleMode () const; void setConsoleScrollLines (int count); int consoleScrollLines () const; void setRememberWindowSizes (bool flag); bool rememberWindowSizes () const; void setRememberManualCommandCount (int count); int rememberManualCommandCount () const; void setClearManualCommandHistory (bool flag); bool clearManualCommandHistory () const; void reset (); }; epasveer-seer-97076f1/src/SeerSeerConfigPage.ui000066400000000000000000000205431526321767600213560ustar00rootroot00000000000000 SeerSeerConfigPage 0 0 671 611 SeerSeerConfigPage 0 0 Manual Gdb commands Number of manual commands to rememvber. 0 means all. Clear all manual gdb commands. Clear history Number of manual gdb/mi commands to remember Qt::Horizontal 40 20 Window sizes Remember window sizes. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Specify general settings for the Seer program itself.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Console is where the output for the program being debugged goes to. On startup, the Console can be shown attached inside Seer's tab windows; detached as a normal window; or detached as a minimized window. Also, the console can limit the number of lines in its scroll history. 0 means all lines.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The window sizes can be remembered if they get changed. On startup, Seer will start with the remembered sizes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Also, 'N' of the most recent manually entered gdb/mi commands will be remembered. 0 means all.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Console mode on startup The console is shown as a normal detached window. Detached modeButtonGroup Qt::Horizontal 218 20 The console is shown attached inside Seer's tabs. Attached modeButtonGroup The console is shown as a normal detached window that is minimize. Detached Minimized modeButtonGroup Maximum number of scroll lines. 0 means unlimited. 99999 1000 Qt::Horizontal 40 20 Number of scroll lines windowSizesGroupBox textBrowser consoleModeGroupBox manualGdbCommandsGroupBox epasveer-seer-97076f1/src/SeerSeerLogWidget.cpp000066400000000000000000000026621526321767600214100ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSeerLogWidget.h" #include "SeerUtl.h" #include #include #include #include SeerSeerLogWidget::SeerSeerLogWidget (QWidget* parent) : SeerLogWidget(parent) { } SeerSeerLogWidget::~SeerSeerLogWidget () { } void SeerSeerLogWidget::processText (const QString& text) { // Only log '^', '*', and '=' records. bool selected = false; if (selected == false && text.front() == '^') { selected = true; } if (selected == false && text.front() == '*') { selected = true; } if (selected == false && text.front() == '=') { selected = true; } if (selected == false && text.contains(QRegularExpression("^([0-9]+)\\^")) == true) { selected = true; } if (selected == false && text.contains(QRegularExpression("^([0-9]+)\\*")) == true) { selected = true; } if (selected == false && text.contains(QRegularExpression("^([0-9]+)\\=")) == true) { selected = true; } if (selected == false) { return; } // No filtering. QString str = text; if (isTimeStampEnabled()) { str = QString("[") + QTime::currentTime().toString("hh:mm:ss.zz") + QString("] ") + str; } // Write the string to the log. textEdit->append(str); } epasveer-seer-97076f1/src/SeerSeerLogWidget.h000066400000000000000000000006241526321767600210510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerLogWidget.h" class SeerSeerLogWidget : public SeerLogWidget { Q_OBJECT public: explicit SeerSeerLogWidget (QWidget* parent = 0); ~SeerSeerLogWidget (); void processText (const QString& text); }; epasveer-seer-97076f1/src/SeerSignalEditValueDialog.cpp000066400000000000000000000037261526321767600230460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSignalEditValueDialog.h" #include SeerSignalEditValueDialog::SeerSignalEditValueDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets set("","","","",""); // Connect things. } SeerSignalEditValueDialog::~SeerSignalEditValueDialog () { } void SeerSignalEditValueDialog::set (const QString& signame, const QString& stopvalue, const QString& printvalue, const QString& passvalue, const QString& description) { signalNameLineEdit->setText(signame); signalDescriptionLineEdit->setText(description); signalStopCheckBox->setCheckState(Qt::Unchecked); signalPrintCheckBox->setCheckState(Qt::Unchecked); signalPassCheckBox->setCheckState(Qt::Unchecked); if (stopvalue == "stop" || stopvalue.compare("Yes", Qt::CaseInsensitive) == 0) { signalStopCheckBox->setCheckState(Qt::Checked); } if (printvalue == "print" || printvalue.compare("Yes", Qt::CaseInsensitive) == 0) { signalPrintCheckBox->setCheckState(Qt::Checked); } if (passvalue == "pass" || passvalue.compare("Yes", Qt::CaseInsensitive) == 0) { signalPassCheckBox->setCheckState(Qt::Checked); } } QString SeerSignalEditValueDialog::nameText () const { return signalNameLineEdit->text(); } QString SeerSignalEditValueDialog::stopText () const { if (signalStopCheckBox->isChecked()) { return "stop"; } return "nostop"; } QString SeerSignalEditValueDialog::printText () const { if (signalPrintCheckBox->isChecked()) { return "print"; } return "noprint"; } QString SeerSignalEditValueDialog::passText () const { if (signalPassCheckBox->isChecked()) { return "pass"; } return "nopass"; } QString SeerSignalEditValueDialog::descriptionText () const { return signalDescriptionLineEdit->text(); } epasveer-seer-97076f1/src/SeerSignalEditValueDialog.h000066400000000000000000000017331526321767600225070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerSignalEditValueDialog.h" class SeerSignalEditValueDialog : public QDialog, protected Ui::SeerSignalEditValueDialogForm { Q_OBJECT public: explicit SeerSignalEditValueDialog (QWidget* parent = 0); ~SeerSignalEditValueDialog (); void set (const QString& signame, const QString& stopvalue, const QString& printvalue, const QString& passvalue, const QString& description); QString nameText () const; QString stopText () const; QString printText () const; QString passText () const; QString descriptionText () const; public slots: private: }; epasveer-seer-97076f1/src/SeerSignalEditValueDialog.ui000066400000000000000000000122461526321767600226760ustar00rootroot00000000000000 SeerSignalEditValueDialogForm 0 0 523 173 Seer - Edit a Signal Value Signal Edit Name 100 0 The name of the signal to edit. true false Stop your program if GDB sees this signal. Stop Print a message to the "GDB output" tab if GDB sees this signal. Print Pass this signal to your program if GDB sees this signal. Pass Qt::Horizontal QSizePolicy::Preferred 60 20 Description 50 0 The description of the signal. true false Qt::Vertical 20 11 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerSignalEditValueDialogForm accept() 248 254 157 274 buttonBox rejected() SeerSignalEditValueDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerSignalProfileDialog.cpp000066400000000000000000000206531526321767600225620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSignalProfileDialog.h" #include #include #include #include #include #include #include SeerSignalProfileDialog::SeerSignalProfileDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); signalsTreeWidget->resizeColumnToContents(0); // name signalsTreeWidget->resizeColumnToContents(1); // checkbox signalsTreeWidget->clear(); // Letters, numbers, space, period, hypen, underscore. QRegularExpressionValidator* validator = new QRegularExpressionValidator(QRegularExpression("[a-zA-Z0-9\\ \\.\\-\\_]+")); profileNameLineEdit->setValidator(validator); // Setup the widgets setSignals(QStringList(), QVector()); // Connect things. QObject::connect(enablePushButton, &QPushButton::clicked, this, &SeerSignalProfileDialog::handleEnableSelected); QObject::connect(disablePushButton, &QPushButton::clicked, this, &SeerSignalProfileDialog::handleDisableSelected); QObject::connect(importPushButton, &QPushButton::clicked, this, &SeerSignalProfileDialog::handleImportFile); QObject::connect(exportPushButton, &QPushButton::clicked, this, &SeerSignalProfileDialog::handleExportFile); // Restore window settings. readSettings(); } SeerSignalProfileDialog::~SeerSignalProfileDialog () { } void SeerSignalProfileDialog::setSignals (const QStringList& signalNames, const QVector& signalEnabled) { signalsTreeWidget->clear(); for (int i=0; isetText(0, signalNames[i]); if (signalEnabled[i] == true) { topItem->setCheckState(1, Qt::Checked); }else{ topItem->setCheckState(1, Qt::Unchecked); } signalsTreeWidget->addTopLevelItem(topItem); } signalsTreeWidget->resizeColumnToContents(0); signalsTreeWidget->resizeColumnToContents(1); } QStringList SeerSignalProfileDialog::signalNames () const { QStringList signalNames; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = signalsTreeWidget->topLevelItem(i); signalNames.push_back(topItem->text(0)); } return signalNames; } QVector SeerSignalProfileDialog::signalEnabled () const { QVector signalEnabled; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = signalsTreeWidget->topLevelItem(i); if (topItem->checkState(1) == Qt::Checked) { signalEnabled.push_back(true); }else{ signalEnabled.push_back(false); } } return signalEnabled; } void SeerSignalProfileDialog::setProfileName (const QString& profileName) { profileNameLineEdit->setText(profileName); } QString SeerSignalProfileDialog::profileName () const { return profileNameLineEdit->text(); } void SeerSignalProfileDialog::accept () { if (profileNameLineEdit->text() == "") { QMessageBox::warning(this, "Seer", "The signal profile name is blank.", QMessageBox::Ok); return; } if (profileNameLineEdit->text() == "allsignals") { QMessageBox::warning(this, "Seer", "The signal profile name of 'allsignals' is reserved.\n\nChoose a different name.", QMessageBox::Ok); return; } QDialog::accept(); } void SeerSignalProfileDialog::handleEnableSelected () { QList selected = signalsTreeWidget->selectedItems(); foreach (QTreeWidgetItem* item, selected) { item->setCheckState(1, Qt::Checked); } } void SeerSignalProfileDialog::handleDisableSelected () { QList selected = signalsTreeWidget->selectedItems(); foreach (QTreeWidgetItem* item, selected) { item->setCheckState(1, Qt::Unchecked); } } void SeerSignalProfileDialog::handleImportFile () { // // Get the name of the file to import. // QFileDialog dialog(this, "Seer Signal Profile File", "./", "Text files (*.txt);;All files (*.*)"); dialog.setAcceptMode(QFileDialog::AcceptOpen); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("txt"); dialog.selectFile("signalprofile.txt"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } // // Open the file and read from it. // A simple format of: // // QFile file(files[0]); if (file.open(QIODevice::ReadOnly)) { QStringList signalNames; QVector signalEnabled; QTextStream stream(&file); while (stream.atEnd() == false) { QString line = stream.readLine(); QStringList words = line.split(QRegularExpression("\\s+")); // Ignore empty lines. if (words.count() == 0) { continue; } // Ignore null lines. if (words.count() == 1 && words[0] == "") { continue; } // There should be only two words on each line. if (words.count() != 2) { QMessageBox::critical(this, tr("Error"), tr("Can't load signal profile file.\nEncountered a line not the form of:\n\n ")); return; } // The second word must be 'enabled' or 'disabled'. if (words[1] != "enabled" && words[1] != "disabled") { QMessageBox::critical(this, tr("Error"), tr("Can't load signal profile file.\nEncountered a line not the form of:\n\n ")); return; } signalNames.push_back(words[0]); signalEnabled.push_back(words[1] == "enabled" ? true : false); } // Populate the list with the imported values. setSignals (signalNames, signalEnabled); QMessageBox::information(this, "Seer", "Loaded."); }else{ QMessageBox::critical(this, tr("Error"), tr("Can't open signal profile file.")); return; } } void SeerSignalProfileDialog::handleExportFile () { // // Get the name of the file to export. // QFileDialog dialog(this, "Seer Signal Profile File", "./", "Text files (*.txt);;All files (*.*)"); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setDefaultSuffix("txt"); dialog.selectFile("signalprofile.txt"); if (dialog.exec() != QDialog::Accepted) { return; } QStringList files = dialog.selectedFiles(); if (files.size() == 0) { return; } if (files.size() > 1) { QMessageBox::critical(this, tr("Error"), tr("Select only 1 file.")); return; } // // Create the file and write to it. // A simple format of: // // QFile file(files[0]); if (file.open(QIODevice::ReadWrite)) { QTextStream stream(&file); QStringList names = signalNames(); QVector enabled = signalEnabled(); for (int i=0; i // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerSignalProfileDialog.h" class SeerSignalProfileDialog : public QDialog, protected Ui::SeerSignalProfileDialogForm { Q_OBJECT public: explicit SeerSignalProfileDialog (QWidget* parent = 0); ~SeerSignalProfileDialog (); void setSignals (const QStringList& signalNames, const QVector& signalEnabled); QStringList signalNames () const; QVector signalEnabled () const; void setProfileName (const QString& profileName); QString profileName () const; public slots: void accept (); private slots: void handleEnableSelected (); void handleDisableSelected (); void handleImportFile (); void handleExportFile (); protected: void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: }; epasveer-seer-97076f1/src/SeerSignalProfileDialog.ui000066400000000000000000000117361526321767600224170ustar00rootroot00000000000000 SeerSignalProfileDialogForm 0 0 600 601 Seer - Signal Profile Editor 100 0 QAbstractItemView::ExtendedSelection false Name Enabled Profile name (lowercase letters and numbers). Profile name true Enable selected items. Enable Selected Disable selected items. Disable Selected Qt::Vertical QSizePolicy::Fixed 20 40 Import items from a file. Import Export items to a file. Export Qt::Vertical QSizePolicy::Expanding 20 318 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerSignalProfileDialogForm accept() 248 254 157 274 buttonBox rejected() SeerSignalProfileDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerSignalValuesBrowserWidget.cpp000066400000000000000000000471601526321767600240130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSignalValuesBrowserWidget.h" #include "SeerSignalEditValueDialog.h" #include "SeerSignalProfileDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include SeerSignalValuesBrowserWidget::SeerSignalValuesBrowserWidget (QWidget* parent) : QWidget(parent) { _newProfileAction = 0; _deleteProfileAction = 0; // Construct the UI. setupUi(this); // Setup the widgets signalsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); signalsTreeWidget->resizeColumnToContents(0); // name signalsTreeWidget->resizeColumnToContents(1); // stop signalsTreeWidget->resizeColumnToContents(2); // print signalsTreeWidget->resizeColumnToContents(3); // pass signalsTreeWidget->resizeColumnToContents(4); // description signalsTreeWidget->resizeColumnToContents(5); // used signalsTreeWidget->setColumnHidden(5, true); // Hide the 'used' column. signalsTreeWidget->clear(); signalProfileComboBox->addItem("allsignals"); _needsSignalNames = true; // Preference menu. QMenu* menu = new QMenu(); _newProfileAction = menu->addAction("New profile"); _modifyProfileAction = menu->addAction("Modify current profile"); _deleteProfileAction = menu->addAction("Delete current profile"); preferencesToolButton->setMenu(menu); preferencesToolButton->setPopupMode(QToolButton::InstantPopup); // Connect things. QObject::connect(signalsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerSignalValuesBrowserWidget::handleItemDoubleClicked); QObject::connect(signalsTreeWidget, &QTreeWidget::itemEntered, this, &SeerSignalValuesBrowserWidget::handleItemEntered); QObject::connect(signalsTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerSignalValuesBrowserWidget::handleContextMenu); QObject::connect(_newProfileAction, &QAction::triggered, this, &SeerSignalValuesBrowserWidget::handleNewProfile); QObject::connect(_modifyProfileAction, &QAction::triggered, this, &SeerSignalValuesBrowserWidget::handleModifyProfile); QObject::connect(_deleteProfileAction, &QAction::triggered, this, &SeerSignalValuesBrowserWidget::handleDeleteProfile); QObject::connect(signalProfileComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerSignalValuesBrowserWidget::handleProfileChanged); // Restore settings. readSettings(); } SeerSignalValuesBrowserWidget::~SeerSignalValuesBrowserWidget () { } void SeerSignalValuesBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,signal-names=[") && text.endsWith("]")) { // ^done,signal-names=[ // "SIGHUP","SIGINT","SIGQUIT","SIGILL","SIGTRAP","SIGABRT","SIGEMT","SIGFPE","SIGKILL","SIGBUS","SIGSEGV" // ] // This recreates the tree. signalsTreeWidget->clear(); QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString frame_text = Seer::parseFirst(newtext, "signal-names=", '[', ']', false); QStringList name_list = Seer::parse(frame_text, "", '"', '"', false); for ( const auto& name_text : name_list ) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, name_text); topItem->setText(5, "new"); signalsTreeWidget->addTopLevelItem(topItem); } handleShowHideSignals(); _needsSignalNames = false; } else if (text.startsWith("^done,signal-values=[") && text.endsWith("]")) { // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(signalsTreeWidget); while (*it) { (*it)->setText(5, "unused"); ++it; } // ^done,signal-values=[ // {name="SIGHUP",stop="Yes",print="Yes",pass="Yes",description="Hangup"}, // {name="SIGINT",stop="Yes",print="Yes",pass="No",description="Interrupt"}, // {name="SIGQUIT",stop="Yes",print="Yes",pass="Yes",description="Quit"}, // {name="SIGILL",stop="Yes",print="Yes",pass="Yes",description="Illegal instruction"}, // {name="EXC_EMULATION",stop="Yes",print="Yes",pass="Yes",description="Emulation instruction"}, // {name="EXC_SOFTWARE",stop="Yes",print="Yes",pass="Yes",description="Software generated exception"}, // {name="EXC_BREAKPOINT",stop="Yes",print="Yes",pass="Yes",description="Breakpoint"}, // {name="SIGLIBRT",stop="No",print="No",pass="Yes",description="librt internal signal"} // ] QString signals_text = Seer::parseFirst(text, "signal-values=", '[', ']', false); QStringList signals_list = Seer::parse(signals_text, "", '{', '}', false); for (const auto& signal_entry : signals_list) { QString name_text = Seer::parseFirst(signal_entry, "name=", '"', '"', false); QString stop_text = Seer::parseFirst(signal_entry, "stop=", '"', '"', false); QString print_text = Seer::parseFirst(signal_entry, "print=", '"', '"', false); QString pass_text = Seer::parseFirst(signal_entry, "pass=", '"', '"', false); QString description_text = Seer::parseFirst(signal_entry, "description=", '"', '"', false); // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. QList matches = signalsTreeWidget->findItems(name_text, Qt::MatchExactly, 0); // Found a match. Reuse it. Set the value. // If no matches, do not add this entry. if (matches.size() > 0) { QTreeWidgetItem* item = matches.takeFirst(); item->setText(0, name_text); item->setText(1, stop_text); item->setText(2, print_text); item->setText(3, pass_text); item->setText(4, description_text); item->setText(5, "reused"); } } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. QList matches = signalsTreeWidget->findItems("unused", Qt::MatchExactly, 5); qDeleteAll(matches); }else{ // Ignore others. } signalsTreeWidget->resizeColumnToContents(0); signalsTreeWidget->resizeColumnToContents(1); signalsTreeWidget->resizeColumnToContents(2); signalsTreeWidget->resizeColumnToContents(3); signalsTreeWidget->resizeColumnToContents(4); signalsTreeWidget->resizeColumnToContents(5); QApplication::restoreOverrideCursor(); } void SeerSignalValuesBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } if (_needsSignalNames) { emit refreshSignalNames(); _needsSignalNames = false; } // refresh(); // If a stopping point is reached, just refresh the values. // The signal names should already be there. emit refreshSignalValues("all"); } void SeerSignalValuesBrowserWidget::handleSessionTerminated () { // Delete previous contents. signalsTreeWidget->clear(); _needsSignalNames = true; } void SeerSignalValuesBrowserWidget::refresh () { _needsSignalNames = true; emit refreshSignalNames(); emit refreshSignalValues("all"); } void SeerSignalValuesBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); _editItem(item); } void SeerSignalValuesBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + item->text(4)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerSignalValuesBrowserWidget::handleContextMenu (const QPoint& pos) { // Get the item at the cursor. QTreeWidgetItem* item = signalsTreeWidget->itemAt(pos); // Construct the menu. QMenu* menu = new QMenu("Options", this); QAction* editAction = menu->addAction("Edit selected"); QAction* copyAction = menu->addAction("Copy selected"); QAction* copyAllAction = menu->addAction("Copy all"); // If no selected item, disable 'selected' copy but allow 'all'. if (item == 0) { editAction->setEnabled(false); copyAction->setEnabled(false); } // Execute the menu. Return if nothing. QAction* action = menu->exec(signalsTreeWidget->mapToGlobal(pos)); if (action == 0) { return; } // Do signal edit. if (action == editAction) { _editItem(item); } // Get selected tree items. QList items; // Get list of 'select' items. if (action == copyAction) { items = signalsTreeWidget->selectedItems(); } // Get list of 'all' items. if (action == copyAllAction) { items = signalsTreeWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard); } // Populate the clipboard. if (items.size() == 0) { return; } QClipboard* clipboard = QGuiApplication::clipboard(); QString text; text += QString("name") + " : " + "stop" + " " + "print" + " " + "pass" + '\n'; for (int i=0; iisHidden() == true) { continue; } text += items[i]->text(0) + " : " + items[i]->text(1) + " " + items[i]->text(2) + " " + items[i] ->text(3) + '\n'; } clipboard->setText(text, QClipboard::Clipboard); clipboard->setText(text, QClipboard::Selection); } void SeerSignalValuesBrowserWidget::handleNewProfile () { if (signalsTreeWidget->topLevelItemCount() == 0) { QMessageBox::warning(this, "Seer", "When creating a profile, Seer needs to be debugging a program.", QMessageBox::Ok); return; } // Build a list of signals. QStringList signalNames; QVector signalEnabled; for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* item = signalsTreeWidget->topLevelItem(i); signalNames.push_back(item->text(0)); signalEnabled.push_back(true); } // Bring up the signal profile dialog. SeerSignalProfileDialog dlg(this); dlg.setSignals(signalNames, signalEnabled); if (dlg.exec()) { QString profileName = dlg.profileName(); if (profileName == "") { return; } signalNames = dlg.signalNames(); signalEnabled = dlg.signalEnabled(); signalProfileComboBox->addItem(profileName); signalProfileComboBox->setCurrentText(profileName); writeProfileSettings(profileName, signalNames, signalEnabled); writeSettings(); // Use them. _signalNames = signalNames; _signalEnabled = signalEnabled; handleShowHideSignals(); } } void SeerSignalValuesBrowserWidget::handleModifyProfile () { QString profileName = signalProfileComboBox->currentText(); if (profileName == "allsignals") { QMessageBox::warning(this, "Seer", "The profile 'allsignals' is reserved.\n\nIt can't be modified.", QMessageBox::Ok); return; } // Build a list of signals. QStringList signalNames = _signalNames; QVector signalEnabled = _signalEnabled; // Bring up the signal profile dialog. SeerSignalProfileDialog dlg(this); dlg.setProfileName(profileName); dlg.setSignals(signalNames, signalEnabled); if (dlg.exec()) { // Get the (potenially new) profile name. QString newProfileName = dlg.profileName(); if (newProfileName == "") { return; } signalNames = dlg.signalNames(); signalEnabled = dlg.signalEnabled(); // If it's a new name, add it to the list and switch to it. if (newProfileName != profileName) { signalProfileComboBox->addItem(newProfileName); signalProfileComboBox->setCurrentText(newProfileName); } // Write out the setting changes. writeProfileSettings(newProfileName, signalNames, signalEnabled); writeSettings(); // Use them. _signalNames = signalNames; _signalEnabled = signalEnabled; handleShowHideSignals(); } } void SeerSignalValuesBrowserWidget::handleDeleteProfile () { int index = signalProfileComboBox->currentIndex(); if (index < 0) { return; } QString profileName = signalProfileComboBox->itemText(index); if (profileName == "") { return; } if (profileName == "allsignals") { QMessageBox::warning(this, "Seer", "The profile 'allsignals' is reserved.\n\nIt can't be deleted.", QMessageBox::Ok); return; } QMessageBox::StandardButton ans = QMessageBox::question(this, "Seer", "Delete profile '" + profileName + "'?"); if (ans != QMessageBox::Yes) { return; } // Delete the profile from the settings. deleteProfileSettings(profileName); // Delete the profile from the list of profiles. signalProfileComboBox->removeItem(index); // Write the current settings. writeSettings(); // Switch to the next profile in the list of profiles. index = signalProfileComboBox->currentIndex(); if (index < 0) { return; } handleProfileChanged (index); } void SeerSignalValuesBrowserWidget::handleShowHideSignals () { // If the list is empty, show all. if (_signalNames.count() == 0 || _signalEnabled.count() == 0) { for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = signalsTreeWidget->topLevelItem(i); topItem->setHidden(false); } return; } // There is a list. Hide all, then show which ones are enabled. for (int i=0; itopLevelItemCount(); i++) { QTreeWidgetItem* topItem = signalsTreeWidget->topLevelItem(i); topItem->setHidden(true); } for (int i=0; i<_signalNames.count(); i++) { if (_signalEnabled[i] == false) { continue; } QString signalName = _signalNames[i]; QList matches = signalsTreeWidget->findItems(signalName, Qt::MatchExactly, 0); for (int i=0; isetHidden(false); } } } void SeerSignalValuesBrowserWidget::handleProfileChanged (int index) { // Get the profile. QString profileName = signalProfileComboBox->itemText(index); // Build a list of signals. QStringList signalNames; QVector signalEnabled; bool f = readProfileSettings(profileName, signalNames, signalEnabled); if (f == false) { return; } // Use them. _signalNames = signalNames; _signalEnabled = signalEnabled; handleShowHideSignals(); writeSettings(); } void SeerSignalValuesBrowserWidget::writeSettings () { QSettings settings; QStringList signalprofiles; for (int i=0; icount(); i++) { if (signalProfileComboBox->itemText(i) == "allsignals") { continue; } signalprofiles.push_back(signalProfileComboBox->itemText(i)); } settings.beginGroup("signalwindow"); { settings.setValue("signalprofile", signalProfileComboBox->currentText()); settings.setValue("signalprofiles", signalprofiles); } settings.endGroup(); } void SeerSignalValuesBrowserWidget::readSettings () { QSettings settings; settings.beginGroup("signalwindow"); { QString signalProfileName = settings.value("signalprofile").toString(); QStringList signalProfiles = settings.value("signalprofiles").toStringList(); signalProfileComboBox->addItems(signalProfiles); signalProfileComboBox->setCurrentText(signalProfileName); } settings.endGroup(); } void SeerSignalValuesBrowserWidget::writeProfileSettings (const QString& profileName, const QStringList& signalNames, const QVector& signalEnabled) { QSettings settings; QStringList signalEnabledFlags; for (int i=0; i& signalEnabled) { if (profileName == "" || profileName == "allsignals") { signalNames.resize(0); signalEnabled.resize(0); return true; } QSettings settings; settings.beginGroup("signalprofile_" + profileName); { QVariant signalNamesVariant = settings.value("signalnames"); QVariant signalEnabledVariant = settings.value("signalenabled"); QStringList signalEnabledFlags; // Not found? Return with error. if (signalNamesVariant == QVariant() || signalEnabledVariant == QVariant()) { return false; } // Okay, we found it. Populate the containters. signalNames = signalNamesVariant.toStringList(); signalEnabledFlags = signalEnabledVariant.toStringList(); signalEnabled.resize(0); for (int i=0; itext(0), item->text(1), item->text(2), item->text(3), item->text(4)); int ret = dlg.exec(); if (ret == 0) { return; } // The register name could be changed, as well as the value. QString name = dlg.nameText(); QString stop = dlg.stopText(); QString print = dlg.printText(); QString pass = dlg.passText(); if (name == "" || stop == "" || print == "" || pass == "") { return; } // Emit the signal to change the register to the new value. emit setSignalValue(name, stop, print, pass); return; } epasveer-seer-97076f1/src/SeerSignalValuesBrowserWidget.h000066400000000000000000000061661526321767600234610ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2026 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "ui_SeerSignalValuesBrowserWidget.h" #include #include #include #include #include #include class SeerSignalValuesBrowserWidget : public QWidget, protected Ui::SeerSignalValuesBrowserWidgetForm { Q_OBJECT public: explicit SeerSignalValuesBrowserWidget (QWidget* parent = 0); ~SeerSignalValuesBrowserWidget (); public: public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); void handleContextMenu (const QPoint& pos); void handleNewProfile (); void handleModifyProfile (); void handleDeleteProfile (); void handleShowHideSignals (); void handleProfileChanged (int index); signals: void refreshSignalNames (); void refreshSignalValues (QString names); void setSignalValue (QString name, QString stop, QString print, QString pass); protected: void showEvent (QShowEvent* event); void readSettings (); void writeSettings (); bool readProfileSettings (const QString& profileName, QStringList& signalNames, QVector& signalEnabled); void writeProfileSettings (const QString& profileName, const QStringList& signalNames, const QVector& signalEnabled); void deleteProfileSettings (const QString& profileName); private: void _editItem (QTreeWidgetItem* item); bool _needsSignalNames; QStringList _signalNames; QVector _signalEnabled; QAction* _newProfileAction; QAction* _modifyProfileAction; QAction* _deleteProfileAction; }; epasveer-seer-97076f1/src/SeerSignalValuesBrowserWidget.ui000066400000000000000000000064721526321767600236470ustar00rootroot00000000000000 SeerSignalValuesBrowserWidgetForm 0 0 733 528 Form 0 0 Signal Profile Name. Qt::Horizontal 508 23 Preferences :/seer/resources/RelaxLightIcons/application-menu.svg:/seer/resources/RelaxLightIcons/application-menu.svg Profile 6 false Name Stop Print Pass Description Used QIndexTreeWidget QTreeWidget
QIndexTreeWidget.h
signalProfileComboBox preferencesToolButton signalsTreeWidget
epasveer-seer-97076f1/src/SeerSkipBrowserWidget.cpp000066400000000000000000000216611526321767600223220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSkipBrowserWidget.h" #include "SeerSkipCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include SeerSkipBrowserWidget::SeerSkipBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets skipTreeWidget->setMouseTracking(true); skipTreeWidget->resizeColumnToContents(0); skipTreeWidget->resizeColumnToContents(1); skipTreeWidget->resizeColumnToContents(2); skipTreeWidget->resizeColumnToContents(3); skipTreeWidget->resizeColumnToContents(4); skipTreeWidget->resizeColumnToContents(5); skipTreeWidget->clear(); skipTreeWidget->setSortingEnabled(false); // Connect things. QObject::connect(skipAddToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleAddToolButton); QObject::connect(skipDeleteToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleDeleteToolButton); QObject::connect(skipEnableToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleEnableToolButton); QObject::connect(skipDisableToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleDisableToolButton); QObject::connect(skipSaveToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleSaveToolButton); QObject::connect(skipLoadToolButton, &QToolButton::clicked, this, &SeerSkipBrowserWidget::handleLoadToolButton); } SeerSkipBrowserWidget::~SeerSkipBrowserWidget () { } void SeerSkipBrowserWidget::loadSkips () { handleLoadToolButton(false); } void SeerSkipBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,skips=[") && text.endsWith("]")) { skipTreeWidget->clear(); skipTreeWidget->setSortingEnabled(false); skipTreeWidget->sortByColumn(-1, Qt::AscendingOrder); // ^done,skips=[ // {number="1",enable="y",glob="n",file="",re="n",function="std::vector >::back()"}, // {number="2",enable="y",glob="n",file="",re="n",function="std::unique_ptr >::operator*() const"} // ] QString skips_text = Seer::parseFirst(text, "skips=", '[', ']', false); QStringList skips_list = Seer::parse(skips_text, "", '{', '}', false); for (const auto& skip_entry : skips_list) { QString number_text = Seer::parseFirst(skip_entry, "number=", '"', '"', false); QString enable_text = Seer::parseFirst(skip_entry, "enable=", '"', '"', false); QString glob_text = Seer::parseFirst(skip_entry, "glob=", '"', '"', false); QString file_text = Seer::parseFirst(skip_entry, "file=", '"', '"', false); QString re_text = Seer::parseFirst(skip_entry, "re=", '"', '"', false); QString function_text = Seer::parseFirst(skip_entry, "function=", '"', '"', false); // Add the function to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, number_text); item->setText(1, enable_text); item->setText(2, glob_text); item->setText(3, file_text); item->setText(4, re_text); item->setText(5, function_text); skipTreeWidget->addTopLevelItem(item); } }else{ // Ignore others. } skipTreeWidget->resizeColumnToContents(0); skipTreeWidget->resizeColumnToContents(1); skipTreeWidget->resizeColumnToContents(2); skipTreeWidget->resizeColumnToContents(3); skipTreeWidget->resizeColumnToContents(4); skipTreeWidget->resizeColumnToContents(5); QApplication::restoreOverrideCursor(); } void SeerSkipBrowserWidget::handleSessionTerminated () { // Delete previous contents. skipTreeWidget->clear(); } void SeerSkipBrowserWidget::handleAddToolButton () { // Create the dialog. SeerSkipCreateDialog dialog(this); // Execute it. if (dialog.exec() != QDialog::Accepted) { return; } // Get result. QString mode = dialog.skipMode(); QString parameters = dialog.skipParameters(); if (mode == "" || parameters == "") { return; } // Send the 'add skip' command. emit addSkip(mode, parameters); } void SeerSkipBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = skipTreeWidget->selectedItems(); // Build ID list. QString ids; for (int i=0; itext(0); } // Send the list of ID's to delete. emit deleteSkips(ids); } void SeerSkipBrowserWidget::handleEnableToolButton () { // Get selected tree items. QList items = skipTreeWidget->selectedItems(); // Build ID list. QString ids; for (int i=0; itext(0); } // Send the list of ID's to enable. emit enableSkips(ids); } void SeerSkipBrowserWidget::handleDisableToolButton () { // Get selected tree items. QList items = skipTreeWidget->selectedItems(); // Build ID list. QString ids; for (int i=0; itext(0); } // Send the list of ID's to disable. emit disableSkips(ids); } void SeerSkipBrowserWidget::handleSaveToolButton () { int result = QMessageBox::warning(this, "Seer", QString("Save the skips in the view?\n\nPreviously saved skips will be deleted first."), QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel); if (result == QMessageBox::Cancel) return; QSettings settings; settings.beginWriteArray("gdbskips"); { int i=0; QTreeWidgetItemIterator it(skipTreeWidget); while (*it) { settings.setArrayIndex(i); settings.setValue("number", (*it)->text(0)); settings.setValue("enable", (*it)->text(1)); settings.setValue("glob", (*it)->text(2)); settings.setValue("file", (*it)->text(3)); settings.setValue("re", (*it)->text(4)); settings.setValue("function", (*it)->text(5)); ++i; ++it; } } settings.endArray(); } void SeerSkipBrowserWidget::handleLoadToolButton (bool askIfAlreadyLoaded) { // Warn only if there are existing skips in the view. if (askIfAlreadyLoaded == true && skipTreeWidget->topLevelItemCount() > 0) { int result = QMessageBox::warning(this, "Seer", QString("Load the previously saved skips from settings?\n\nThe existing skips in the view will be deleted first."), QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel); if (result == QMessageBox::Cancel) return; } QSettings settings; if (settings.childGroups().contains("gdbskips")) { emit deleteSkips(""); // Tell gdb to delete all skips. This will update the view. int size = settings.beginReadArray("gdbskips"); for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); QString number = settings.value("number").toString(); QString enable = settings.value("enable").toString(); QString glob = settings.value("glob").toString(); QString file = settings.value("file").toString(); QString re = settings.value("re").toString(); QString function = settings.value("function").toString(); QString mode; QString parameters; // Work on file mode. if (file != "") { if (glob == "y") { parameters = file; mode = "gfile"; }else if (glob == "n") { parameters = file; mode = "file"; } // Work on function mode. } else if (function != "") { if (re == "y") { parameters = function; mode = "rfunction"; }else if (re == "n") { parameters = function; mode = "function"; }else{ continue; } } if (mode == "" || parameters == "") continue; emit addSkip(mode, parameters); } settings.endArray(); } } void SeerSkipBrowserWidget::refresh () { emit refreshSkipList(); } epasveer-seer-97076f1/src/SeerSkipBrowserWidget.h000066400000000000000000000030571526321767600217660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerSkipBrowserWidget.h" class SeerSkipBrowserWidget : public QWidget, protected Ui::SeerSkipBrowserWidgetForm { Q_OBJECT public: explicit SeerSkipBrowserWidget (QWidget* parent = 0); ~SeerSkipBrowserWidget (); void loadSkips (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleAddToolButton (); void handleDeleteToolButton (); void handleEnableToolButton (); void handleDisableToolButton (); void handleSaveToolButton (); void handleLoadToolButton (bool askIfAlreadyLoaded=true); signals: void refreshSkipList (); void addSkip (const QString& skipMode, const QString& skipParameters); void deleteSkips (const QString& skips); void enableSkips (const QString& skips); void disableSkips (const QString& skips); protected: private: }; epasveer-seer-97076f1/src/SeerSkipBrowserWidget.ui000066400000000000000000000116601526321767600221530ustar00rootroot00000000000000 SeerSkipBrowserWidgetForm 0 0 794 528 Form QAbstractItemView::ExtendedSelection 6 Num Enb Glob File RE Function true Add a new skip. :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg true Enable selected skips. :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Disable selected skips. :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Delete selected skips. :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 Save skips. ... :/seer/resources/RelaxLightIcons/document-save.svg:/seer/resources/RelaxLightIcons/document-save.svg Load skips. ... :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg epasveer-seer-97076f1/src/SeerSkipCreateDialog.cpp000066400000000000000000000061171526321767600220550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSkipCreateDialog.h" #include "SeerHelpPageDialog.h" #include SeerSkipCreateDialog::SeerSkipCreateDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets fileRadioButton->setChecked(true); fileRadioButton->setFocus(); // Connect things. QObject::connect(modeButtonGroup, QOverload::of(&QButtonGroup::idClicked), this, &SeerSkipCreateDialog::handleModeButtonGroup); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerSkipCreateDialog::handleHelpToolButton); handleModeButtonGroup(); } SeerSkipCreateDialog::~SeerSkipCreateDialog () { } void SeerSkipCreateDialog::handleModeButtonGroup () { // Disable all text fields. We'll enable one later. fileLineEdit->setEnabled(false); fileGlobLineEdit->setEnabled(false); functionLineEdit->setEnabled(false); functionRegexLineEdit->setEnabled(false); // Enable the one that is selected. QAbstractButton* button = modeButtonGroup->checkedButton(); if (button == dynamic_cast(fileRadioButton)) { fileLineEdit->setEnabled(true); fileLineEdit->setFocus(); } else if (button == dynamic_cast(fileGlobRadioButton)) { fileGlobLineEdit->setEnabled(true); fileGlobLineEdit->setFocus(); } else if (button == dynamic_cast(functionRadioButton)) { functionLineEdit->setEnabled(true); functionLineEdit->setFocus(); } else if (button == dynamic_cast(functionRegexRadioButton)) { functionRegexLineEdit->setEnabled(true); functionRegexLineEdit->setFocus(); } } void SeerSkipCreateDialog::handleHelpToolButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog(this); help->loadFile(":/seer/resources/help/Skips.md"); help->show(); help->raise(); } QString SeerSkipCreateDialog::skipMode () const { // Build a catchpoint specification. QString skipMode; if (fileRadioButton->isChecked()) { skipMode = "file"; }else if (fileGlobRadioButton->isChecked()) { skipMode = "gfile"; }else if (functionRadioButton->isChecked()) { skipMode = "function"; }else if (functionRegexRadioButton->isChecked()) { skipMode = "rfunction"; } qDebug() << skipMode; return skipMode; } QString SeerSkipCreateDialog::skipParameters () const { // Build a catchpoint specification. QString skipParameters; if (fileRadioButton->isChecked()) { skipParameters = fileLineEdit->text(); }else if (fileGlobRadioButton->isChecked()) { skipParameters = fileGlobLineEdit->text(); }else if (functionRadioButton->isChecked()) { skipParameters = functionLineEdit->text(); }else if (functionRegexRadioButton->isChecked()) { skipParameters = functionRegexLineEdit->text(); } qDebug() << skipParameters; return skipParameters; } epasveer-seer-97076f1/src/SeerSkipCreateDialog.h000066400000000000000000000013221526321767600215130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerSkipCreateDialog.h" class SeerSkipCreateDialog : public QDialog, protected Ui::SeerSkipCreateDialogForm { Q_OBJECT public: explicit SeerSkipCreateDialog (QWidget* parent = 0); ~SeerSkipCreateDialog (); QString skipMode () const; QString skipParameters () const; public slots: private slots: void handleModeButtonGroup (); void handleHelpToolButton (); private: }; epasveer-seer-97076f1/src/SeerSkipCreateDialog.ui000066400000000000000000000126561526321767600217150ustar00rootroot00000000000000 SeerSkipCreateDialogForm 0 0 471 253 Create a Skip Specify Skip details. Qt::Horizontal 348 20 :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Filename modeButtonGroup filename Filename (glob) modeButtonGroup filename glob-pattern Function modeButtonGroup function name Function (regex) modeButtonGroup function regex Qt::Vertical 20 17 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok fileRadioButton fileGlobRadioButton functionRadioButton functionRegexRadioButton fileLineEdit fileGlobLineEdit functionLineEdit functionRegexLineEdit helpToolButton buttonBox accepted() SeerSkipCreateDialogForm accept() 248 254 157 274 buttonBox rejected() SeerSkipCreateDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerSlashProcDialog.cpp000066400000000000000000000017601526321767600217200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSlashProcDialog.h" SeerSlashProcDialog::SeerSlashProcDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); // Setup the widgets // Connect things. QObject::connect(processInfoWidget, &QProcessInfoWidget::pidSelected, this, &SeerSlashProcDialog::handlePidSelected); } SeerSlashProcDialog::~SeerSlashProcDialog () { } int SeerSlashProcDialog::selectedPid () const { return processInfoWidget->selectedPid(); } QString SeerSlashProcDialog::selectedName () const { return processInfoWidget->selectedName(); } QString SeerSlashProcDialog::selectedFullname () const { return processInfoWidget->selectedFullname(); } QString SeerSlashProcDialog::selectedCommandLine () const { return processInfoWidget->selectedCommandLine(); } void SeerSlashProcDialog::handlePidSelected() { done(QDialog::Accepted); } epasveer-seer-97076f1/src/SeerSlashProcDialog.h000066400000000000000000000014451526321767600213650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerSlashProcDialog.h" class SeerSlashProcDialog : public QDialog, protected Ui::SeerSlashProcDialogForm { Q_OBJECT public: explicit SeerSlashProcDialog (QWidget* parent = 0); ~SeerSlashProcDialog (); int selectedPid () const; QString selectedName () const; QString selectedFullname () const; QString selectedCommandLine () const; public slots: private slots: void handlePidSelected (); private: }; epasveer-seer-97076f1/src/SeerSlashProcDialog.ui000066400000000000000000000036521526321767600215550ustar00rootroot00000000000000 SeerSlashProcDialogForm 0 0 589 562 Seer - System Processes Select a process pid. Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok QProcessInfoWidget QWidget
QProcessInfoWidget.h
1
buttonBox accepted() SeerSlashProcDialogForm accept() 248 254 157 274 buttonBox rejected() SeerSlashProcDialogForm reject() 316 260 286 274
epasveer-seer-97076f1/src/SeerSourceBrowserWidget.cpp000066400000000000000000000225101526321767600226460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSourceBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include SeerSourceBrowserWidget::SeerSourceBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets sourceSearchLineEdit->setPlaceholderText("Search regex..."); sourceSearchLineEdit->setClearButtonEnabled(true); _sourceFilesItems = new QTreeWidgetItem; _sourceFilesItems->setText(0, "Source files"); _headerFilesItems = new QTreeWidgetItem; _headerFilesItems->setText(0, "Header files"); _miscFilesItems = new QTreeWidgetItem; _miscFilesItems->setText(0, "Misc files"); sourceTreeWidget->setMouseTracking(true); sourceTreeWidget->addTopLevelItem(_sourceFilesItems); sourceTreeWidget->addTopLevelItem(_headerFilesItems); sourceTreeWidget->addTopLevelItem(_miscFilesItems); sourceTreeWidget->resizeColumnToContents(0); sourceTreeWidget->resizeColumnToContents(1); _sourceFilePatterns = QStringList( {"*.cpp", "*.c", "*.C", "*.f", "*.f90", ".F90", "*.rs", "*.go", "*.ada", "*.adb", "*.s", "*.S"} ); // Default settings. _headerFilePatterns = QStringList( {"*.hpp", "*.h", "*.ads"} ); _miscFilePatterns = QStringList( {"/usr/include/"} ); // Connect things. QObject::connect(sourceTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerSourceBrowserWidget::handleItemDoubleClicked); QObject::connect(sourceTreeWidget, &QTreeWidget::itemEntered, this, &SeerSourceBrowserWidget::handleItemEntered); QObject::connect(sourceSearchLineEdit, &QLineEdit::textChanged, this, &SeerSourceBrowserWidget::handleSearchLineEdit); } SeerSourceBrowserWidget::~SeerSourceBrowserWidget () { } void SeerSourceBrowserWidget::setMiscFilePatterns (const QStringList& patterns) { _miscFilePatterns = patterns; } const QStringList& SeerSourceBrowserWidget::miscFilePatterns () const { return _miscFilePatterns; } void SeerSourceBrowserWidget::setSourceFilePatterns (const QStringList& patterns) { _sourceFilePatterns = patterns; } const QStringList& SeerSourceBrowserWidget::sourceFilePatterns () const { return _sourceFilePatterns; } void SeerSourceBrowserWidget::setHeaderFilePatterns (const QStringList& patterns) { _headerFilePatterns = patterns; } const QStringList& SeerSourceBrowserWidget::headerFilePatterns () const { return _headerFilePatterns; } void SeerSourceBrowserWidget::setIgnoreFilePatterns (const QStringList& patterns) { _ignoreFilePatterns = patterns; } const QStringList& SeerSourceBrowserWidget::ignoreFilePatterns () const { return _ignoreFilePatterns; } void SeerSourceBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,files=[") && text.endsWith("]")) { // ^done,files=[ // {file=\"../sysdeps/x86_64/start.S\",fullname=\"/home/abuild/rpmbuild/BUILD/glibc-2.26/csu/../sysdeps/x86_64/start.S\"}, // {file=\"helloworld.cpp\",fullname=\"/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp\"} // ] // Delete previous files. deleteChildItems(); QString files_text = Seer::parseFirst(text, "files=", '[', ']', false); QStringList files_list = Seer::parse(files_text, "", '{', '}', false); // Set up a map to look for duplicate entries. QMap QMap files; for (const auto& entry_text : files_list) { QString file_text = Seer::parseFirst(entry_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(entry_text, "fullname=", '"', '"', false); //qDebug() << file_text << fullname_text; // Skip duplicates if (files.contains(fullname_text)) { continue; } files.insert(fullname_text, file_text); // Add the file to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, QFileInfo(file_text).fileName()); item->setText(1, fullname_text); // See which pattern the file matches. Put the file under that folder. // If no match, put it in 'misc'. if (Seer::matchesWildcard(ignoreFilePatterns(), fullname_text)) { continue; }else if (Seer::matchesWildcard(miscFilePatterns(), fullname_text)) { _miscFilesItems->addChild(item); }else if (Seer::matchesWildcard(sourceFilePatterns(), fullname_text)) { _sourceFilesItems->addChild(item); }else if (Seer::matchesWildcard(headerFilePatterns(), fullname_text)) { _headerFilesItems->addChild(item); }else{ _miscFilesItems->addChild(item); } } // Always expand the source items. Expanding the other // items are under the user's control. _sourceFilesItems->setExpanded(true); }else{ // Ignore others. } // Sort each item separately. _sourceFilesItems->sortChildren(0, Qt::AscendingOrder); _headerFilesItems->sortChildren(0, Qt::AscendingOrder); _miscFilesItems->sortChildren(0, Qt::AscendingOrder); sourceTreeWidget->resizeColumnToContents(0); sourceTreeWidget->resizeColumnToContents(1); sourceSearchLineEdit->clear(); QApplication::restoreOverrideCursor(); } void SeerSourceBrowserWidget::handleSessionTerminated () { // Delete previous files. deleteChildItems(); } void SeerSourceBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedFile(item->text(0), item->text(1), 0); } void SeerSourceBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); //qDebug() << item->text(0) << column; if (item->text(1) == "") { // Look at the FullName. for (int i=0; icolumnCount(); i++) { // The top-level items do not have a tooltip. item->setToolTip(i, ""); } }else{ item->setToolTip(0, item->text(0) + " : " + item->text(1)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } } void SeerSourceBrowserWidget::handleSearchLineEdit (const QString& text) { // Set everything to a normal font. If there is no search text, unhide everything. // If there is search text, hide everything so the matching ones can be unhidden later on. QTreeWidgetItemIterator it(sourceTreeWidget); if (*it) { QFont f0 = (*it)->font(0); QFont f1 = (*it)->font(1); f0.setBold(false); f1.setBold(false); if (text == "") { while (*it) { (*it)->setHidden(false); // No search text, unhide everything. (*it)->setFont(0,f0); (*it)->setFont(1,f1); ++it; } }else{ while (*it) { (*it)->setHidden(true); // Has serach text, hide everything. Matching items to be unhidden below. (*it)->setFont(0,f0); (*it)->setFont(1,f1); ++it; } } } // Set selected items to a bold font and unhidden. Move to the first match. if (text != "") { _sourceFilesItems->setHidden(false); _headerFilesItems->setHidden(false); _miscFilesItems->setHidden(false); QList matches; matches = sourceTreeWidget->findItems(text, Qt::MatchRegularExpression | Qt::MatchRecursive, 0); QList::const_iterator it = matches.begin(); QList::const_iterator e = matches.end(); if (it != e) { sourceTreeWidget->setCurrentItem(*it); QFont f0 = (*it)->font(0); QFont f1 = (*it)->font(1); f0.setBold(true); f1.setBold(true); while (it != e) { if (*it != _sourceFilesItems && *it != _headerFilesItems && *it != _miscFilesItems) { (*it)->setHidden(false); (*it)->setFont(0,f0); (*it)->setFont(1,f1); } it++; } } // Always expand the source items. Expanding the other // items are under the user's control. _sourceFilesItems->setExpanded(true); //qDebug() << text << matches.size(); } sourceTreeWidget->resizeColumnToContents(0); sourceTreeWidget->resizeColumnToContents(1); } void SeerSourceBrowserWidget::refresh () { emit refreshSourceList(); } void SeerSourceBrowserWidget::deleteChildItems () { // Delete child items. Leave top-level 'Source', 'Header', and 'Misc'. foreach (auto i, _sourceFilesItems->takeChildren()) { delete i; } foreach (auto i, _headerFilesItems->takeChildren()) { delete i; } foreach (auto i, _miscFilesItems->takeChildren()) { delete i; } } epasveer-seer-97076f1/src/SeerSourceBrowserWidget.h000066400000000000000000000045251526321767600223210ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerSourceBrowserWidget.h" class SeerSourceBrowserWidget : public QWidget, protected Ui::SeerSourceBrowserWidgetForm { Q_OBJECT public: explicit SeerSourceBrowserWidget (QWidget* parent = 0); ~SeerSourceBrowserWidget (); void setMiscFilePatterns (const QStringList& patterns); const QStringList& miscFilePatterns () const; void setSourceFilePatterns (const QStringList& patterns); const QStringList& sourceFilePatterns () const; void setHeaderFilePatterns (const QStringList& patterns); const QStringList& headerFilePatterns () const; void setIgnoreFilePatterns (const QStringList& patterns); const QStringList& ignoreFilePatterns () const; public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (const QString& text); void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshSourceList (); void selectedFile (QString file, QString fullname, int lineno); protected: void deleteChildItems (); private: QTreeWidgetItem* _sourceFilesItems; QTreeWidgetItem* _headerFilesItems; QTreeWidgetItem* _miscFilesItems; QStringList _sourceFilePatterns; QStringList _headerFilePatterns; QStringList _miscFilePatterns; QStringList _ignoreFilePatterns; }; epasveer-seer-97076f1/src/SeerSourceBrowserWidget.ui000066400000000000000000000026171526321767600225070ustar00rootroot00000000000000 SeerSourceBrowserWidgetForm 0 0 730 698 Source Browser 2 File Full Name Search in the list of files. "*" is allowed. QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
epasveer-seer-97076f1/src/SeerSourceConfigPage.cpp000066400000000000000000000355431526321767600220730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSourceConfigPage.h" #include #include #include #include #include SeerSourceConfigPage::SeerSourceConfigPage(QWidget* parent) : QWidget(parent) { // Set up the UI. setupUi(this); // Setup the widgets alternateDirectoriesTreeWidget->clear(); alternateDirectoriesTreeWidget->setSortingEnabled(false); alternateDirectoriesTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); alternateDirectoriesTreeWidget->resizeColumnToContents(0); // directory ignoreFilePatternsTreeWidget->clear(); ignoreFilePatternsTreeWidget->setSortingEnabled(false); ignoreFilePatternsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); ignoreFilePatternsTreeWidget->resizeColumnToContents(0); // file pattern miscFilePatternsTreeWidget->clear(); miscFilePatternsTreeWidget->setSortingEnabled(false); miscFilePatternsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); miscFilePatternsTreeWidget->resizeColumnToContents(0); // file pattern sourceFilePatternsTreeWidget->clear(); sourceFilePatternsTreeWidget->setSortingEnabled(false); sourceFilePatternsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); sourceFilePatternsTreeWidget->resizeColumnToContents(0); // file pattern headerFilePatternsTreeWidget->clear(); headerFilePatternsTreeWidget->setSortingEnabled(false); headerFilePatternsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); headerFilePatternsTreeWidget->resizeColumnToContents(0); // file pattern // Connect things. QObject::connect(addAlternateDirectoryToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleAddAlternateButtonClicked); QObject::connect(moveUpAlternateDirectoriesToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleUpAlternateButtonClicked); QObject::connect(moveDownAlternateDirectoriesToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDownAlternateButtonClicked); QObject::connect(deleteAlternateDirectoriesToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDeleteAlternateButtonClicked); QObject::connect(addIgnoreFilePatternToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleAddIgnorePatternButtonClicked); QObject::connect(deleteIgnoreFilePatternesToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDeleteIgnorePatternButtonClicked); QObject::connect(addMiscFilePatternToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleAddMiscPatternButtonClicked); QObject::connect(deleteMiscFilePatternsToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDeleteMiscPatternButtonClicked); QObject::connect(addSourceFilePatternToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleAddSourcePatternButtonClicked); QObject::connect(deleteSourceFilePatternsToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDeleteSourcePatternButtonClicked); QObject::connect(addHeaderFilePatternToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleAddHeaderPatternButtonClicked); QObject::connect(deleteHeaderFilePatternsToolButton, &QToolButton::clicked, this, &SeerSourceConfigPage::handleDeleteHeaderPatternButtonClicked); // Setup the defaults. reset(); } SeerSourceConfigPage::~SeerSourceConfigPage() { } void SeerSourceConfigPage::setAlternateDirectories (const QStringList& alternateDirectories) { alternateDirectoriesTreeWidget->clear(); QStringListIterator iter(alternateDirectories); while (iter.hasNext()) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, iter.next()); alternateDirectoriesTreeWidget->addTopLevelItem(topItem); } alternateDirectoriesTreeWidget->resizeColumnToContents(0); } QStringList SeerSourceConfigPage::alternateDirectories () const { QStringList list; QTreeWidgetItemIterator iter(alternateDirectoriesTreeWidget); while (*iter) { list << (*iter)->text(0); ++iter; } return list; } void SeerSourceConfigPage::setIgnoreFilePatterns (const QStringList& filePatterns) { ignoreFilePatternsTreeWidget->clear(); QStringListIterator iter(filePatterns); while (iter.hasNext()) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, iter.next()); ignoreFilePatternsTreeWidget->addTopLevelItem(topItem); } ignoreFilePatternsTreeWidget->resizeColumnToContents(0); } QStringList SeerSourceConfigPage::ignoreFilePatterns () const { QStringList list; QTreeWidgetItemIterator iter(ignoreFilePatternsTreeWidget); while (*iter) { list << (*iter)->text(0); ++iter; } return list; } void SeerSourceConfigPage::setMiscFilePatterns (const QStringList& filePatterns) { miscFilePatternsTreeWidget->clear(); QStringListIterator iter(filePatterns); while (iter.hasNext()) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, iter.next()); miscFilePatternsTreeWidget->addTopLevelItem(topItem); } miscFilePatternsTreeWidget->resizeColumnToContents(0); } QStringList SeerSourceConfigPage::miscFilePatterns () const { QStringList list; QTreeWidgetItemIterator iter(miscFilePatternsTreeWidget); while (*iter) { list << (*iter)->text(0); ++iter; } return list; } void SeerSourceConfigPage::setSourceFilePatterns (const QStringList& filePatterns) { sourceFilePatternsTreeWidget->clear(); QStringListIterator iter(filePatterns); while (iter.hasNext()) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, iter.next()); sourceFilePatternsTreeWidget->addTopLevelItem(topItem); } sourceFilePatternsTreeWidget->resizeColumnToContents(0); } QStringList SeerSourceConfigPage::sourceFilePatterns () const { QStringList list; QTreeWidgetItemIterator iter(sourceFilePatternsTreeWidget); while (*iter) { list << (*iter)->text(0); ++iter; } return list; } void SeerSourceConfigPage::setHeaderFilePatterns (const QStringList& filePatterns) { headerFilePatternsTreeWidget->clear(); QStringListIterator iter(filePatterns); while (iter.hasNext()) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, iter.next()); headerFilePatternsTreeWidget->addTopLevelItem(topItem); } headerFilePatternsTreeWidget->resizeColumnToContents(0); } QStringList SeerSourceConfigPage::headerFilePatterns () const { QStringList list; QTreeWidgetItemIterator iter(headerFilePatternsTreeWidget); while (*iter) { list << (*iter)->text(0); ++iter; } return list; } void SeerSourceConfigPage::reset () { QStringList alternateDirectories; alternateDirectories << "./"; setAlternateDirectories(alternateDirectories); setIgnoreFilePatterns(QStringList()); setMiscFilePatterns( {"/usr/include/*"} ); setSourceFilePatterns( {"*.cpp", "*.c", "*.C", "*.f", "*.f90", "*.F90", "*.rs", "*.go", "*.ada", "*.adb"} ); setHeaderFilePatterns( {"*.hpp", "*.h", "*.ads"} ); } void SeerSourceConfigPage::handleAddAlternateButtonClicked () { // Ask for the alternate directory to add to the list. QString directory = QFileDialog::getExistingDirectory(this, "Seer - Enter an alternate directory", QString(), QFileDialog::ShowDirsOnly|QFileDialog::DontUseNativeDialog); if (directory == "") { return; } // Get the selected items, if any. QList matches = alternateDirectoriesTreeWidget->selectedItems(); // Create the new item QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, directory); // If there is something selected, add the new item before the first selected item. if (matches.count() > 0) { int index = alternateDirectoriesTreeWidget->indexOfTopLevelItem(matches[0]); alternateDirectoriesTreeWidget->insertTopLevelItem(index, topItem); // Otherwise, just add it to the end of the list. }else{ alternateDirectoriesTreeWidget->addTopLevelItem(topItem); } // Resize the columns and select the item we just added. alternateDirectoriesTreeWidget->resizeColumnToContents(0); alternateDirectoriesTreeWidget->setCurrentItem(topItem, 0); } void SeerSourceConfigPage::handleUpAlternateButtonClicked () { // Get the selected items. QList matches = alternateDirectoriesTreeWidget->selectedItems(); // Loop through them from low to high. for (int i=0; iindexOfTopLevelItem(matches[i]); // Stop if the item is at the top of the list. if (index <= 0) { break; } // Steel it from the treeWidget. QTreeWidgetItem* topItem = alternateDirectoriesTreeWidget->takeTopLevelItem(index); // Re-add it to the moved up position. alternateDirectoriesTreeWidget->insertTopLevelItem(index-1, topItem); } // Re-selected the items. alternateDirectoriesTreeWidget->clearSelection(); for (int i=0; isetSelected(true); } // Resize the columns. alternateDirectoriesTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleDownAlternateButtonClicked () { // Get the selected items. QList matches = alternateDirectoriesTreeWidget->selectedItems(); // Loop through them from high to low. for (int i=matches.count()-1; i>=0; i--) { int index = alternateDirectoriesTreeWidget->indexOfTopLevelItem(matches[i]); // Stop if the item is at the bottom of the list. if (index >= alternateDirectoriesTreeWidget->topLevelItemCount()-1) { break; } // Steel it from the treeWidget. QTreeWidgetItem* topItem = alternateDirectoriesTreeWidget->takeTopLevelItem(index); // Re-add it to the moved down position. alternateDirectoriesTreeWidget->insertTopLevelItem(index+1, topItem); } // Re-selected the items. alternateDirectoriesTreeWidget->clearSelection(); for (int i=0; isetSelected(true); } // Resize the columns. alternateDirectoriesTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleDeleteAlternateButtonClicked () { QList matches = alternateDirectoriesTreeWidget->selectedItems(); qDeleteAll(matches); // Resize the columns and select the items we just deleted. alternateDirectoriesTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleAddIgnorePatternButtonClicked () { // Ask for the ignore directory to add to the list. QString directory = QInputDialog::getText(this, "Seer - Enter a directory to ignore", "Ignore directory:"); if (directory == "") { return; } // Create the new item QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, directory); // Just add it to the end of the list. ignoreFilePatternsTreeWidget->addTopLevelItem(topItem); // Resize the columns and select the item we just added. ignoreFilePatternsTreeWidget->resizeColumnToContents(0); ignoreFilePatternsTreeWidget->setCurrentItem(topItem, 0); } void SeerSourceConfigPage::handleDeleteIgnorePatternButtonClicked () { QList matches = ignoreFilePatternsTreeWidget->selectedItems(); qDeleteAll(matches); // Resize the columns and select the items we just deleted. ignoreFilePatternsTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleAddMiscPatternButtonClicked () { // Ask for the pattern to add to the list. QString pattern = QInputDialog::getText(this, "Seer - Enter a file pattern", "Misc file pattern:"); if (pattern == "") { return; } // Create the new item QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, pattern); // Just add it to the end of the list. miscFilePatternsTreeWidget->addTopLevelItem(topItem); // Resize the columns and select the item we just added. miscFilePatternsTreeWidget->resizeColumnToContents(0); miscFilePatternsTreeWidget->setCurrentItem(topItem, 0); } void SeerSourceConfigPage::handleDeleteMiscPatternButtonClicked () { QList matches = miscFilePatternsTreeWidget->selectedItems(); qDeleteAll(matches); // Resize the columns and select the items we just deleted. miscFilePatternsTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleAddSourcePatternButtonClicked () { // Ask for the pattern to add to the list. QString pattern = QInputDialog::getText(this, "Seer - Enter a file pattern", "Source file pattern:"); if (pattern == "") { return; } // Create the new item QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, pattern); // Just add it to the end of the list. sourceFilePatternsTreeWidget->addTopLevelItem(topItem); // Resize the columns and select the item we just added. sourceFilePatternsTreeWidget->resizeColumnToContents(0); sourceFilePatternsTreeWidget->setCurrentItem(topItem, 0); } void SeerSourceConfigPage::handleDeleteSourcePatternButtonClicked () { QList matches = sourceFilePatternsTreeWidget->selectedItems(); qDeleteAll(matches); // Resize the columns and select the items we just deleted. sourceFilePatternsTreeWidget->resizeColumnToContents(0); } void SeerSourceConfigPage::handleAddHeaderPatternButtonClicked () { // Ask for the pattern to add to the list. QString pattern = QInputDialog::getText(this, "Seer - Enter a file pattern", "Header file pattern:"); if (pattern == "") { return; } // Create the new item QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, pattern); // Just add it to the end of the list. headerFilePatternsTreeWidget->addTopLevelItem(topItem); // Resize the columns and select the item we just added. headerFilePatternsTreeWidget->resizeColumnToContents(0); headerFilePatternsTreeWidget->setCurrentItem(topItem, 0); } void SeerSourceConfigPage::handleDeleteHeaderPatternButtonClicked () { QList matches = headerFilePatternsTreeWidget->selectedItems(); qDeleteAll(matches); // Resize the columns and select the items we just deleted. headerFilePatternsTreeWidget->resizeColumnToContents(0); } epasveer-seer-97076f1/src/SeerSourceConfigPage.h000066400000000000000000000052341526321767600215320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerSourceConfigPage.h" class SeerSourceConfigPage : public QWidget, public Ui::SeerSourceConfigPage { Q_OBJECT public: explicit SeerSourceConfigPage (QWidget* parent = 0); ~SeerSourceConfigPage (); void setAlternateDirectories (const QStringList& alternateDirectories); QStringList alternateDirectories () const; void setIgnoreFilePatterns (const QStringList& filePatterns); QStringList ignoreFilePatterns () const; void setMiscFilePatterns (const QStringList& filePatterns); QStringList miscFilePatterns () const; void setSourceFilePatterns (const QStringList& filePatterns); QStringList sourceFilePatterns () const; void setHeaderFilePatterns (const QStringList& filePatterns); QStringList headerFilePatterns () const; void reset (); protected slots: void handleAddAlternateButtonClicked (); void handleUpAlternateButtonClicked (); void handleDownAlternateButtonClicked (); void handleDeleteAlternateButtonClicked (); void handleAddIgnorePatternButtonClicked (); void handleDeleteIgnorePatternButtonClicked (); void handleAddMiscPatternButtonClicked (); void handleDeleteMiscPatternButtonClicked (); void handleAddSourcePatternButtonClicked (); void handleDeleteSourcePatternButtonClicked (); void handleAddHeaderPatternButtonClicked (); void handleDeleteHeaderPatternButtonClicked (); private: }; epasveer-seer-97076f1/src/SeerSourceConfigPage.ui000066400000000000000000000577401526321767600217310ustar00rootroot00000000000000 SeerSourceConfigPage 0 0 804 852 SeerSourceConfigPage Source Lookup 0 0 false Alternate Directories Add a new directory. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Move up selected directories. ... :/seer/resources/RelaxLightIcons/go-up.svg:/seer/resources/RelaxLightIcons/go-up.svg Move down selected directories. ... :/seer/resources/RelaxLightIcons/go-down.svg:/seer/resources/RelaxLightIcons/go-down.svg Delete selected directories. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 0 0 false Ignore Directories/Files Add a new directory. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Delete selected directories. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 Source Browser Filtering 0 0 false Misc Directories/Files Add a new file pattern. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Delete selected file patterns. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 0 0 false Source Directories/Files Add a new file pattern. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Delete selected file patterns. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 0 0 false Header Directories/Files Add a new file pattern. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Delete selected file patterns. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Horizontal 40 20 0 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Source Lookup.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If Seer can't find the source file in the directory that gdb knows of, then Seer will look in these <span style=" text-decoration: underline;">Alternate</span> directories in the order they appear. If Seer still can't find the source file, it will prompt you to enter the location. If you don't want to be prompted, add the directory path to the list of <span style=" text-decoration: underline;">Ignore</span> directories. Wildcarding is allowed when adding an ignore entry.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Source Browser Filtering.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">These settings affect how Seer sorts all the source and include filenames that a program references. These files appear in the Source Browser in one of three catagegories: <span style=" text-decoration: underline;">Source</span>, <span style=" text-decoration: underline;">Header</span>, or <span style=" text-decoration: underline;">Misc</span>.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Files that match the <span style=" text-decoration: underline;">Ignore</span> list will not be sorted into any catagegory.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">An entry can be a directory path, filename, or filename extension. Wildcarding is allowed and is encouraged for fine control. A directory path must end with &quot;/*&quot;.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Seer looks at the debug information for the program to create a list of all files the program references. Some are applicable to the the program, others are not.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ones that are not, should be sorted into <span style=" text-decoration: underline;">Misc</span>. These can be system header files or system source files. The ones that are, are sorted into <span style=" text-decoration: underline;">Source</span> or <span style=" text-decoration: underline;">Header</span>, depending on the sorting settings.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For each file, it is compared to the sort patterns in the <span style=" text-decoration: underline;">Misc</span> category, then the <span style=" text-decoration: underline;">Source</span>, then the <span style=" text-decoration: underline;">Header</span> category. It is put into the first one that matches. If it doesn't match any, it is put into the <span style=" text-decoration: underline;">Misc</span> category.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For example, <span style=" text-decoration: underline;">Source</span> should have entries like:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> *.cpp</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> *.c</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> *.go</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> *.asm</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline;">Header</span> should have entries like:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> *.h</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline;">Misc</span> should have entries like:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> /usr/include/*</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline;">Ignore</span> should have entries like:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> /home/abuild/*</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> epasveer-seer-97076f1/src/SeerSourceHighlighter.cpp000066400000000000000000000052701526321767600223210ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSourceHighlighter.h" #include "SeerAdaSourceHighlighter.h" #include "SeerOdinSourceHighlighter.h" #include "SeerCppSourceHighlighter.h" #include "SeerFortranSourceHighlighter.h" #include "SeerRustSourceHighlighter.h" SeerSourceHighlighter::SeerSourceHighlighter (QTextDocument* parent) : QSyntaxHighlighter(parent) {} const SeerHighlighterSettings& SeerSourceHighlighter::highlighterSettings() { return _highlighterSettings; } SeerSourceHighlighter* SeerSourceHighlighter::getSourceHighlighter(QString const& file, SeerHighlighterSettings settings) { QRegularExpression ada_re("(?:" + settings.adaSourceSuffixes() + ")$"); if (file.contains(ada_re)) { return new SeerAdaSourceHighlighter(0); } QRegularExpression cpp_re("(?:" + settings.cppSourceSuffixes() + ")$"); if (file.contains(cpp_re)) { return new SeerCppSourceHighlighter(0); } QRegularExpression fortran_re("(?:" + settings.fortranSourceSuffixes() + ")$"); if (file.contains(fortran_re)) { return new SeerFortranSourceHighlighter(0); } QRegularExpression odin_re("(?:" + settings.odinSourceSuffixes() + ")$"); if (file.contains(odin_re)) { return new SeerOdinSourceHighlighter(0); } QRegularExpression rust_re("(?:" + settings.rustSourceSuffixes() + ")$"); if (file.contains(rust_re)) { return new SeerRustSourceHighlighter(0); } return nullptr; } void SeerSourceHighlighter::highlightBlock (const QString& text) { for (const HighlightingRule& rule : std::as_const(_highlightingRules)) { QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text); while (matchIterator.hasNext()) { QRegularExpressionMatch match = matchIterator.next(); setFormat(match.capturedStart(), match.capturedLength(), rule.format); } } setCurrentBlockState(0); int startIndex = 0; if (previousBlockState() != 1) { startIndex = text.indexOf(_commentStartExpression); } while (startIndex >= 0) { QRegularExpressionMatch match = _commentEndExpression.match(text, startIndex); int endIndex = match.capturedStart(); int commentLength = 0; if (endIndex == -1) { setCurrentBlockState(1); commentLength = text.length() - startIndex; }else{ commentLength = endIndex - startIndex + match.capturedLength(); } setFormat(startIndex, commentLength, _multiLineCommentFormat); startIndex = text.indexOf(_commentStartExpression, startIndex + commentLength); } } epasveer-seer-97076f1/src/SeerSourceHighlighter.h000066400000000000000000000030111526321767600217550ustar00rootroot00000000000000/* ## Syntax highlighting To add syntax highlighting to a language. Subclass `SeerSourceHighlighter` and then instatiate your highlighter by matching the filename in the `getSourceHighlighter` function. */ #pragma once #include "SeerHighlighterSettings.h" #include #include class SeerSourceHighlighter : public QSyntaxHighlighter { Q_OBJECT public: SeerSourceHighlighter(QTextDocument *parent = 0); const SeerHighlighterSettings& highlighterSettings (); virtual void setHighlighterSettings (SeerHighlighterSettings const& settings) = 0; static SeerSourceHighlighter* getSourceHighlighter (QString const& file, SeerHighlighterSettings settings); protected: virtual void highlightBlock (const QString &text); SeerHighlighterSettings _highlighterSettings; QTextCharFormat _singleLineCommentFormat; QTextCharFormat _multiLineCommentFormat; QRegularExpression _commentStartExpression; QRegularExpression _commentEndExpression; QTextCharFormat _keywordFormat; QTextCharFormat _classFormat; QTextCharFormat _quotationFormat; QTextCharFormat _functionFormat; struct HighlightingRule { QRegularExpression pattern; QTextCharFormat format; }; QVector _highlightingRules{}; }; epasveer-seer-97076f1/src/SeerSourceLoadErrorDialog.ui000066400000000000000000000104501526321767600227230ustar00rootroot00000000000000 Dialog 0 0 638 322 Dialog Error Could not find: /path/to/some/sourcefile. Its location may have changed. How would you like to handle this? :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/HighContrast/document-open.svg For this file, enter an alternate directory to look in. :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/HighContrast/document-open.svg /path/that/seer/is/expecting /path/to/an/alternate/directory /path/to/actual/directory For this file and future files, enter a directory mapping between expected and actual. QFrame::Sunken Qt::Horizontal Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() Dialog accept() 248 254 157 274 buttonBox rejected() Dialog reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerSourceSymbolLibraryManagerWidget.cpp000066400000000000000000000231301526321767600253070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerSourceSymbolLibraryManagerWidget.h" #include "SeerHelpPageDialog.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include SeerSourceSymbolLibraryManagerWidget::SeerSourceSymbolLibraryManagerWidget (QWidget* parent) : QWidget(parent) { // Initialize private data // Setup UI setupUi(this); // Setup the widgets tabWidget->setMovable(true); tabWidget->setTabsClosable(false); _sourceBrowserWidget = new SeerSourceBrowserWidget(this); _functionBrowserWidget = new SeerFunctionBrowserWidget(this); _typeBrowserWidget = new SeerTypeBrowserWidget(this); _staticBrowserWidget = new SeerStaticBrowserWidget(this); _libraryBrowserWidget = new SeerLibraryBrowserWidget(this); _adaExceptionsBrowserWidget = new SeerAdaExceptionsBrowserWidget(this); _skipBrowserWidget = new SeerSkipBrowserWidget(this); tabWidget->addTab(_sourceBrowserWidget, "Source"); tabWidget->addTab(_functionBrowserWidget, "Functions"); tabWidget->addTab(_typeBrowserWidget, "Types"); tabWidget->addTab(_staticBrowserWidget, "Statics"); tabWidget->addTab(_libraryBrowserWidget, "Libraries"); tabWidget->addTab(_adaExceptionsBrowserWidget, "AdaExceptions"); tabWidget->addTab(_skipBrowserWidget, "Skips"); QToolButton* tabsContextMenuButton = new QToolButton(tabWidget); tabsContextMenuButton->setIcon(QIcon(":/seer/resources/thenounproject/preferences.svg")); tabsContextMenuButton->setToolTip("Show/Hide tabs."); tabsContextMenuButton->setContextMenuPolicy(Qt::CustomContextMenu); QToolButton* refreshToolButton = new QToolButton(tabWidget); refreshToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/view-refresh.svg")); refreshToolButton->setToolTip("Refresh the source/symbol/library information."); QToolButton* helpToolButton = new QToolButton(tabWidget); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on source/symbol/library information."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(tabsContextMenuButton); hcontainer->addWidget(refreshToolButton); hcontainer->addWidget(helpToolButton); tabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Restore tab ordering. readSettings(); // Connect things. QObject::connect(tabsContextMenuButton, &QToolButton::clicked, this, &SeerSourceSymbolLibraryManagerWidget::handleTabsContextMenuButtonClicked); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerSourceSymbolLibraryManagerWidget::handleRefreshToolButtonClicked); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerSourceSymbolLibraryManagerWidget::handleHelpToolButtonClicked); QObject::connect(tabWidget->tabBar(), &QTabBar::tabMoved, this, &SeerSourceSymbolLibraryManagerWidget::handleTabMoved); QObject::connect(tabWidget->tabBar(), &QTabBar::currentChanged, this, &SeerSourceSymbolLibraryManagerWidget::handleTabChanged); } SeerSourceSymbolLibraryManagerWidget::~SeerSourceSymbolLibraryManagerWidget () { } SeerSourceBrowserWidget* SeerSourceSymbolLibraryManagerWidget::sourceBrowserWidget () { return _sourceBrowserWidget; } SeerFunctionBrowserWidget* SeerSourceSymbolLibraryManagerWidget::functionBrowserWidget () { return _functionBrowserWidget; } SeerTypeBrowserWidget* SeerSourceSymbolLibraryManagerWidget::typeBrowserWidget () { return _typeBrowserWidget; } SeerStaticBrowserWidget* SeerSourceSymbolLibraryManagerWidget::staticBrowserWidget () { return _staticBrowserWidget; } SeerLibraryBrowserWidget* SeerSourceSymbolLibraryManagerWidget::libraryBrowserWidget () { return _libraryBrowserWidget; } SeerAdaExceptionsBrowserWidget* SeerSourceSymbolLibraryManagerWidget::adaExceptionsBrowserWidget () { return _adaExceptionsBrowserWidget; } SeerSkipBrowserWidget* SeerSourceSymbolLibraryManagerWidget::skipBrowserWidget () { return _skipBrowserWidget; } void SeerSourceSymbolLibraryManagerWidget::handleRefreshToolButtonClicked () { sourceBrowserWidget()->refresh(); functionBrowserWidget()->refresh(); typeBrowserWidget()->refresh(); staticBrowserWidget()->refresh(); libraryBrowserWidget()->refresh(); adaExceptionsBrowserWidget()->refresh(); skipBrowserWidget()->refresh(); } void SeerSourceSymbolLibraryManagerWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/SourceSymbolLibraryInfoBrowser.md"); help->show(); help->raise(); } void SeerSourceSymbolLibraryManagerWidget::handleTabMoved (int from, int to) { Q_UNUSED(from); Q_UNUSED(to); writeSettings(); } void SeerSourceSymbolLibraryManagerWidget::handleTabChanged (int index) { Q_UNUSED(index); writeSettings(); } void SeerSourceSymbolLibraryManagerWidget::writeSettings () { // Build up visible list. QStringList visible; for (int i=0; itabBar()->count(); i++) { visible.append(tabWidget->isTabVisible(i) ? "true" : "false"); } // Build up tab order. QStringList tabs; for (int i=0; itabBar()->count(); i++) { tabs.append(tabWidget->tabBar()->tabText(i)); } // Build up current tab. QString current = tabWidget->tabBar()->tabText(tabWidget->tabBar()->currentIndex()); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Write settings. QSettings settings; settings.beginGroup("sourcemanagerwindow"); { settings.setValue("taborder", tabs.join(',')); settings.setValue("tabvisible", visible.join(',')); settings.setValue("tabcurrent", current); } settings.endGroup(); } void SeerSourceSymbolLibraryManagerWidget::readSettings () { // Can't move things? if (tabWidget->tabBar()->isMovable() == false) { return; } // Read tab order from settings. QSettings settings; QStringList tabs; QStringList visible; QString current; settings.beginGroup("sourcemanagerwindow"); { tabs = settings.value("taborder").toString().split(','); visible = settings.value("tabvisible").toString().split(','); current = settings.value("tabcurrent").toString(); } settings.endGroup(); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Move tabs to the requested order. for (int i=0; itabBar()->count(); j++) { if (tabWidget->tabBar()->tabText(j) == tab) { tb = j; break; } } if (tb != -1) { tabWidget->tabBar()->moveTab(tb, i); } } // Show/Hide tabs. for (int i=0; isetTabVisible(i,true); }else if (flag == "false") { tabWidget->setTabVisible(i,false); }else{ tabWidget->setTabVisible(i,true); } } // Make a tab current. if (current != "") { for (int i=0; itabBar()->count(); i++) { if (tabWidget->tabBar()->tabText(i) == current) { tabWidget->setCurrentIndex(i); break; } } }else{ tabWidget->setCurrentIndex(0); } } void SeerSourceSymbolLibraryManagerWidget::handleTabsContextMenuButtonClicked() { // Build the menu and execute it. QMenu contextMenu; QWidget* container = new QWidget(&contextMenu); QVBoxLayout* layout = new QVBoxLayout(container); for (int i = 0; i < tabWidget->count(); i++) { QString title = tabWidget->tabText(i); QCheckBox* showTabCheckBox = new QCheckBox(title, container); showTabCheckBox->setChecked(tabWidget->isTabVisible(i)); layout->addWidget(showTabCheckBox); QObject::connect(showTabCheckBox, &QCheckBox::toggled, [this, showTabCheckBox, i](bool checked) { // Count visible tabs. int count=0; for (int x=0; xcount(); x++) { if (tabWidget->isTabVisible(x)) { count++; } } // Adjust the count. The 'checked' is made before the UI is updated. if (checked == true) { count++; }else{ count--; } // Reset the checkbox UI if the last visible tab was clicked. if (checked == false and count == 0) { showTabCheckBox->setChecked(true); // Don't hide last visible tab. }else if (checked == false and count > 1) { tabWidget->setTabVisible(i, checked); // Always show tabs when asked. }else{ tabWidget->setTabVisible(i, checked); } writeSettings(); }); } container->setLayout(layout); QWidgetAction* action = new QWidgetAction(&contextMenu); action->setDefaultWidget(container); contextMenu.addAction(action); contextMenu.exec(QCursor::pos()); } epasveer-seer-97076f1/src/SeerSourceSymbolLibraryManagerWidget.h000066400000000000000000000054371526321767600247660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerSourceBrowserWidget.h" #include "SeerFunctionBrowserWidget.h" #include "SeerTypeBrowserWidget.h" #include "SeerStaticBrowserWidget.h" #include "SeerLibraryBrowserWidget.h" #include "SeerAdaExceptionsBrowserWidget.h" #include "SeerSkipBrowserWidget.h" #include #include "ui_SeerSourceSymbolLibraryManagerWidget.h" class SeerSourceSymbolLibraryManagerWidget : public QWidget, protected Ui::SeerSourceSymbolLibraryManagerWidgetForm { Q_OBJECT public: explicit SeerSourceSymbolLibraryManagerWidget (QWidget* parent = 0); ~SeerSourceSymbolLibraryManagerWidget (); SeerSourceBrowserWidget* sourceBrowserWidget (); SeerFunctionBrowserWidget* functionBrowserWidget (); SeerTypeBrowserWidget* typeBrowserWidget (); SeerStaticBrowserWidget* staticBrowserWidget (); SeerLibraryBrowserWidget* libraryBrowserWidget (); SeerAdaExceptionsBrowserWidget* adaExceptionsBrowserWidget (); SeerSkipBrowserWidget* skipBrowserWidget (); protected: void writeSettings (); void readSettings (); private slots: void handleRefreshToolButtonClicked (); void handleHelpToolButtonClicked (); void handleTabMoved (int from, int to); void handleTabChanged (int index); void handleTabsContextMenuButtonClicked (); private: SeerSourceBrowserWidget* _sourceBrowserWidget; SeerFunctionBrowserWidget* _functionBrowserWidget; SeerTypeBrowserWidget* _typeBrowserWidget; SeerStaticBrowserWidget* _staticBrowserWidget; SeerLibraryBrowserWidget* _libraryBrowserWidget; SeerAdaExceptionsBrowserWidget* _adaExceptionsBrowserWidget; SeerSkipBrowserWidget* _skipBrowserWidget; QTabWidget* _dumpTab; }; epasveer-seer-97076f1/src/SeerSourceSymbolLibraryManagerWidget.ui000066400000000000000000000031651526321767600251500ustar00rootroot00000000000000 SeerSourceSymbolLibraryManagerWidgetForm 0 0 771 479 Form 0 0 0 0 3 font-weight: bold; Source/Symbol/Library Info Qt::PlainText -1 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
epasveer-seer-97076f1/src/SeerStackArgumentsBrowserWidget.cpp000066400000000000000000000572231526321767600243520ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackArgumentsBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerStackArgumentsBrowserWidget::SeerStackArgumentsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets argumentsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); argumentsTreeWidget->setMouseTracking(true); argumentsTreeWidget->setSortingEnabled(false); argumentsTreeWidget->resizeColumnToContents(0); // level argumentsTreeWidget->resizeColumnToContents(1); // Name argumentsTreeWidget->resizeColumnToContents(2); // Value argumentsTreeWidget->resizeColumnToContents(3); // used argumentsTreeWidget->setColumnHidden(3, true); // Hide the 'used' column. argumentsTreeWidget->clear(); // Connect things. QObject::connect(argumentsTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerStackArgumentsBrowserWidget::handleContextMenu); QObject::connect(argumentsTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerStackArgumentsBrowserWidget::handleItemCollapsed); QObject::connect(argumentsTreeWidget, &QTreeWidget::itemExpanded, this, &SeerStackArgumentsBrowserWidget::handleItemExpanded); QObject::connect(argumentsTreeWidget, &QTreeWidget::itemEntered, this, &SeerStackArgumentsBrowserWidget::handleItemEntered); } SeerStackArgumentsBrowserWidget::~SeerStackArgumentsBrowserWidget () { } void SeerStackArgumentsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,stack-args=[") && text.endsWith("]")) { //argumentsTreeWidget->clear(); // ^done,stack-args=[ // frame={level="0",args=[ // {name="message",value="\"Hello, World!\""} // ]}, // frame={level="1",args=[ // {name="argc",value="1"}, // {name="argv",value="0x7fffffffd5b8"} // ]} // ] // "level=\"0\",args=[{name=\"message\",value=\"\\\"Hello, World!\\\"\"}]", // "level=\"1\",args=[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\"0x7fffffffd5b8\"}]" QStringList frame_list = Seer::parse(text, "frame=", '{', '}', false); // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(argumentsTreeWidget); while (*it) { (*it)->setText(3, "unused"); ++it; } for ( const auto& frame_text : frame_list ) { QString level_text = Seer::parseFirst(frame_text, "level=", '"', '"', false); QString args_text = Seer::parseFirst(frame_text, "args=", '[', ']', false); QStringList namevalue_list = Seer::parse(args_text, "", '{', '}', false); QList matches = argumentsTreeWidget->findItems(level_text, Qt::MatchExactly, 0); QTreeWidgetItem* topItem = 0; // Use an existing level. if (matches.count() > 0) { topItem = matches[0]; topItem->setText(3, "reused"); // Add the new level to the tree. }else{ topItem = new QTreeWidgetItem; topItem->setText(0, level_text); topItem->setText(3, "new"); argumentsTreeWidget->addTopLevelItem(topItem); } // Get the argument names and values for the level. for ( const auto& namevalue_text : namevalue_list ) { QString name_text = Seer::parseFirst(namevalue_text, "name=", '"', '"', false); QString value_text = Seer::parseFirst(namevalue_text, "value=", '"', '"', false); // Populate the tree. handleItemCreate(topItem, "", name_text, value_text); } // Expand all items for the level. argumentsTreeWidget->expandItem(topItem); } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. // Don't use qDeleteAll() here. It doesn't work as expected for items that are "found". // Instead, get a list of matches and delete them from the bottom up. QList matches = argumentsTreeWidget->findItems("unused", Qt::MatchExactly|Qt::MatchRecursive, 3); while (matches.isEmpty() == false) { foreach (QTreeWidgetItem* item, matches) { if (item->childCount() == 0) { QTreeWidgetItem* parent = item->parent(); if (parent) { parent->removeChild(item); } bool f = matches.removeOne(item); Q_ASSERT(f != false); delete item; break; } } } }else{ // Ignore others. } argumentsTreeWidget->resizeColumnToContents(0); argumentsTreeWidget->resizeColumnToContents(1); argumentsTreeWidget->resizeColumnToContents(2); argumentsTreeWidget->resizeColumnToContents(3); QApplication::restoreOverrideCursor(); } void SeerStackArgumentsBrowserWidget::handleStoppingPointReached () { refresh(); } void SeerStackArgumentsBrowserWidget::handleSessionTerminated () { // Delete previous contents. argumentsTreeWidget->clear(); } void SeerStackArgumentsBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshStackArguments(); } void SeerStackArgumentsBrowserWidget::handleContextMenu (const QPoint& pos) { QTreeWidgetItem* item = argumentsTreeWidget->itemAt(pos); if (item == 0) { return; } if (item->text(1) == "") { return; } QAction* addVariableLoggerExpressionAction; QAction* addVariableLoggerAsteriskExpressionAction; QAction* addVariableLoggerAmpersandExpressionAction; QAction* addVariableLoggerAsteriskAmpersandExpressionAction; QAction* addVariableLoggerObjcExpressionAction; QAction* addVariableTrackerExpressionAction; QAction* addVariableTrackerAsteriskExpressionAction; QAction* addVariableTrackerAmpersandExpressionAction; QAction* addVariableTrackerAsteriskAmpersandExpressionAction; QAction* addVariableTrackerObjcExpressionAction; QAction* addMemoryVisualizerAction; QAction* addMemoryAsteriskVisualizerAction; QAction* addMemoryAmpersandVisualizerAction; QAction* addArrayVisualizerAction; QAction* addArrayAsteriskVisualizerAction; QAction* addArrayAmpersandVisualizerAction; QAction* addMatrixVisualizerAction; QAction* addMatrixAsteriskVisualizerAction; QAction* addMatrixAmpersandVisualizerAction; QAction* addStructVisualizerAction; QAction* addStructAsteriskVisualizerAction; QAction* addStructAmpersandVisualizerAction; addVariableLoggerExpressionAction = new QAction(QString("%1").arg(item->text(1))); addVariableLoggerAsteriskExpressionAction = new QAction(QString("*%1").arg(item->text(1))); addVariableLoggerAmpersandExpressionAction = new QAction(QString("&&%1").arg(item->text(1))); addVariableLoggerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(item->text(1))); addVariableLoggerObjcExpressionAction = new QAction(QString("(objc)%1").arg(item->text(0))); addVariableTrackerExpressionAction = new QAction(QString("%1").arg(item->text(1))); addVariableTrackerAsteriskExpressionAction = new QAction(QString("*%1").arg(item->text(1))); addVariableTrackerAmpersandExpressionAction = new QAction(QString("&&%1").arg(item->text(1))); addVariableTrackerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(item->text(1))); addVariableTrackerObjcExpressionAction = new QAction(QString("(objc)%1").arg(item->text(0))); addMemoryVisualizerAction = new QAction(QString("%1").arg(item->text(1))); addMemoryAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(1))); addMemoryAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(1))); addArrayVisualizerAction = new QAction(QString("%1").arg(item->text(1))); addArrayAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(1))); addArrayAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(1))); addMatrixVisualizerAction = new QAction(QString("%1").arg(item->text(1))); addMatrixAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(1))); addMatrixAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(1))); addStructVisualizerAction = new QAction(QString("%1").arg(item->text(1))); addStructAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(1))); addStructAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(1))); QMenu menu("Visualizers", this); menu.setTitle("Visualizers"); QMenu loggerMenu("Add variable to Logger"); loggerMenu.addAction(addVariableLoggerExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskExpressionAction); loggerMenu.addAction(addVariableLoggerAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerObjcExpressionAction); menu.addMenu(&loggerMenu); QMenu trackerMenu("Add variable to Tracker"); trackerMenu.addAction(addVariableTrackerExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskExpressionAction); trackerMenu.addAction(addVariableTrackerAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerObjcExpressionAction); menu.addMenu(&trackerMenu); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); // Launch the menu. Get the response. QAction* action = menu.exec(argumentsTreeWidget->viewport()->mapToGlobal(pos)); // Do nothing. if (action == 0) { return; } // Handle adding a variable to log. if (action == addVariableLoggerExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableLoggerExpression(item->text(1)); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableLoggerExpression(QString("*") + item->text(1)); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAmpersandExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableLoggerExpression(QString("&") + item->text(1)); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskAmpersandExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableLoggerExpression(QString("*&") + item->text(1)); } return; } // Handle adding a variable to log. if (action == addVariableLoggerObjcExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableLoggerExpression(QString("(objc)") + item->text(1)); } return; } // Handle adding a variable to track. if (action == addVariableTrackerExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableTrackerExpression(item->text(1)); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableTrackerExpression(QString("*") + item->text(1)); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAmpersandExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableTrackerExpression(QString("&") + item->text(1)); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskAmpersandExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableTrackerExpression(QString("*&") + item->text(1)); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerObjcExpressionAction) { // Emit the signals. if (item->text(1) != "") { emit addVariableTrackerExpression(QString("(objc)") + item->text(1)); emit refreshVariableTrackerValues(); } return; } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMemoryVisualizer(item->text(1)); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMemoryVisualizer(QString("*") + item->text(1)); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMemoryVisualizer(QString("&") + item->text(1)); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addArrayVisualizer(item->text(1)); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addArrayVisualizer(QString("*") + item->text(1)); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addArrayVisualizer(QString("&") + item->text(1)); } return; } // Handle adding matrix to visualize. if (action == addMatrixVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMatrixVisualizer(item->text(1)); } return; } // Handle adding matrix to visualize. if (action == addMatrixAsteriskVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMatrixVisualizer(QString("*") + item->text(1)); } return; } // Handle adding matrix to visualize. if (action == addMatrixAmpersandVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addMatrixVisualizer(QString("&") + item->text(1)); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addStructVisualizer(item->text(1)); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addStructVisualizer(QString("*") + item->text(1)); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { // Emit the signals. if (item->text(1) != "") { emit addStructVisualizer(QString("&") + item->text(1)); } return; } } void SeerStackArgumentsBrowserWidget::handleItemExpanded (QTreeWidgetItem* item) { Q_UNUSED(item); argumentsTreeWidget->resizeColumnToContents(0); argumentsTreeWidget->resizeColumnToContents(1); argumentsTreeWidget->resizeColumnToContents(2); argumentsTreeWidget->resizeColumnToContents(3); } void SeerStackArgumentsBrowserWidget::handleItemCollapsed (QTreeWidgetItem* item) { Q_UNUSED(item); argumentsTreeWidget->resizeColumnToContents(0); argumentsTreeWidget->resizeColumnToContents(1); argumentsTreeWidget->resizeColumnToContents(2); argumentsTreeWidget->resizeColumnToContents(3); } void SeerStackArgumentsBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); if (item->text(0) != "") { for (int i=0; icolumnCount(); i++) { // The "level" item does not have a tooltip. item->setToolTip(i, ""); } }else{ QTreeWidgetItem* parent = item->parent(); // Get parent item, which is the level. item->setToolTip(0, parent->text(0) + " : " + item->text(1) + " : " + Seer::elideText(item->text(2), Qt::ElideRight, 100)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } } void SeerStackArgumentsBrowserWidget::handleItemCreate (QTreeWidgetItem* parentItem, const QString& level_text, const QString& name_text, const QString& value_text) { // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. We start by looking for matches that // may already be there. If there are matches, the code will reuse it. If not, a new item // is created by the code. Note, when searching, we only look at the current level. Not any // children. QList matches; if (parentItem == 0) { Q_ASSERT(parentItem != NULL); return; }else{ for (int i=0; ichildCount(); i++) { if (parentItem->child(i)->text(1) == name_text) { matches.append(parentItem->child(i)); } } } // Parse bookmarks. QString capture0; // With const address. QString capture1; // Without. QRegularExpression withaddress_re("^@0[xX][0-9a-fA-F]+: \\{(.*?)\\}$"); QRegularExpressionMatch withaddress_match = withaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (withaddress_match.hasMatch()) { capture0 = withaddress_match.captured(0); capture1 = withaddress_match.captured(1); }else{ QRegularExpression noaddress_re("^\\{(.*?)\\}$"); QRegularExpressionMatch noaddress_match = noaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (noaddress_match.hasMatch()) { capture0 = noaddress_match.captured(0); capture1 = noaddress_match.captured(1); } } // Add the complex entry to the tree. Reuse, if possible. if (capture0 != "" && capture1 != "") { // Remove bookends QString text = capture1; QTreeWidgetItem* item = 0; // Use the privously created item. Or create a new one. if (matches.size() > 0) { item = matches[0]; item->setText(3, "reused"); }else{ item = new QTreeWidgetItem; item->setText(3, "new"); // If we're dealing with a top-level item, attach it to the tree. // Otherwise, attach it to the parent. if (parentItem) { parentItem->addChild(item); }else{ argumentsTreeWidget->addTopLevelItem(item); } } // Set the flatvalue text. item->setText(0, level_text); item->setText(1, name_text); item->setText(2, Seer::filterEscapes(text)); item->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); // Convert to a list of name/value pairs. QStringList nv_pairs = Seer::parseCommaList(text, '{', '}'); // Go through each pair and add the name and its value to the tree. for (const auto& nv : nv_pairs) { QStringPair pair = Seer::parseNameValue(nv, '='); handleItemCreate(item, level_text, pair.first, pair.second); } // Add the simple entry to the tree. Reuse, if possible. }else{ QTreeWidgetItem* item = 0; // Use the privously created item. Or create a new one. if (matches.size() > 0) { item = matches[0]; item->setText(3, "reused"); }else{ item = new QTreeWidgetItem; item->setText(3, "new"); // If we're dealing with a top-level item, attach it to the tree. // Otherwise, attach it to the parent. if (parentItem) { parentItem->addChild(item); }else{ argumentsTreeWidget->addTopLevelItem(item); } } // Simple entries don't have children. Delete them. QList children = item->takeChildren(); if (matches.size() > 0) { qDeleteAll(children); } // Populate the item. item->setText(0, level_text); item->setText(1, name_text); item->setText(2, Seer::filterEscapes(value_text)); item->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); } } void SeerStackArgumentsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } epasveer-seer-97076f1/src/SeerStackArgumentsBrowserWidget.h000066400000000000000000000041331526321767600240070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerStackArgumentsBrowserWidget.h" class SeerStackArgumentsBrowserWidget : public QWidget, protected Ui::SeerStackArgumentsBrowserWidgetForm { Q_OBJECT public: explicit SeerStackArgumentsBrowserWidget (QWidget* parent = 0); ~SeerStackArgumentsBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleContextMenu (const QPoint& pos); void handleItemExpanded (QTreeWidgetItem* item); void handleItemCollapsed (QTreeWidgetItem* item); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshStackArguments (); void addVariableLoggerExpression (QString expression); void addVariableTrackerExpression (QString expression); void refreshVariableTrackerValues (); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); protected: void handleItemCreate (QTreeWidgetItem* parentItem, const QString& level_text, const QString& name_text, const QString& value_text); void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerStackArgumentsBrowserWidget.ui000066400000000000000000000021411526321767600241720ustar00rootroot00000000000000 SeerStackArgumentsBrowserWidgetForm 0 0 794 528 Form 4 Level Name Value Used epasveer-seer-97076f1/src/SeerStackDumpBrowserWidget.cpp000066400000000000000000000315271526321767600233110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackDumpBrowserWidget.h" #include "SeerStackDumpSettingsDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include SeerStackDumpBrowserWidget::SeerStackDumpBrowserWidget (QWidget* parent) : QWidget(parent) { _spExpressionId = Seer::createID(); _dumpExpressionId = Seer::createID(); // Construct the UI. setupUi(this); // Setup the widgets stackTableWidget->setMouseTracking(true); stackTableWidget->setSortingEnabled(false); stackTableWidget->resizeColumnToContents(0); // 2 byte address stackTableWidget->resizeColumnToContents(1); // 2 byte value stackTableWidget->resizeColumnToContents(2); // 4 byte value stackTableWidget->resizeColumnToContents(3); // 8 byte value stackTableWidget->resizeColumnToContents(4); // N byte ascii stackTableWidget->resizeRowsToContents(); stackTableWidget->clearContents(); // Connect things. QObject::connect(formatComboBox, &QComboBox::currentTextChanged, this, &SeerStackDumpBrowserWidget::handleFormatComboBox); QObject::connect(visualizerToolButton, &QToolButton::clicked, this, &SeerStackDumpBrowserWidget::handleVisualizerToolButton); QObject::connect(preferencesToolButton, &QToolButton::clicked, this, &SeerStackDumpBrowserWidget::handlePreferencesToolButton); QObject::connect(stackTableWidget, &QTableWidget::cellDoubleClicked, this, &SeerStackDumpBrowserWidget::handleCellDoubleClicked); setStackPointerExpression("$sp"); setStackPointerColor(QColor("lightGray")); setBytesBeforeSP(16); setBytesAfterSP(16); setAsciiBytes(8); // Restore settings. readSettings(); } SeerStackDumpBrowserWidget::~SeerStackDumpBrowserWidget () { } void SeerStackDumpBrowserWidget::setStackPointerExpression (const QString& expression) { _stackPointerExpression = expression; spExpressionLabel->setText(_stackPointerExpression); } QString SeerStackDumpBrowserWidget::stackPointerExpression () const { return _stackPointerExpression; } void SeerStackDumpBrowserWidget::setBytesBeforeSP (int nbytes) { _bytesBeforeSP = ceil(nbytes / 8.0) * 8; // Round to 8. } int SeerStackDumpBrowserWidget::bytesBeforeSP () const { return _bytesBeforeSP; } void SeerStackDumpBrowserWidget::setBytesAfterSP (int nbytes) { _bytesAfterSP = ceil(nbytes / 8.0) * 8; // Round to 8. } int SeerStackDumpBrowserWidget::bytesAfterSP () const { return _bytesAfterSP; } void SeerStackDumpBrowserWidget::setAsciiBytes (int nbytes) { _asciiBytes = nbytes; } int SeerStackDumpBrowserWidget::asciiBytes () const { return _asciiBytes; } void SeerStackDumpBrowserWidget::setStackPointerColor (const QColor& color) { _stackPointerColor = color; } QColor SeerStackDumpBrowserWidget::stackPointerColor () const { return _stackPointerColor; } void SeerStackDumpBrowserWidget::handleText (const QString& text) { // -data-read-memory-bytes -o 16 $sp 32 // ^done,memory=[ // { // begin="0x00007fffffffda80", // offset="0x0000000000000000", // end="0x00007fffffffdaa0", // contents="0000000000000000e80300000000000098dcffffff7f0000e803000001000000" // } // ] // // // -data-evaluate-expression $sp // ^done,value="0x7fffffffda90" QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // ^done,value="0x7fffffffda90" QString id_text = text.section('^', 0,0); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); if (id_text.toInt() != _spExpressionId) { break; } addressLineEdit->setText(value_text); emit refreshStackDump(_dumpExpressionId, value_text, -bytesBeforeSP(), bytesBeforeSP()+bytesAfterSP()+2); }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,memory="))) { QString id_text = text.section('^', 0,0); if (id_text.toInt() != _dumpExpressionId) { break; } QString begin_text = Seer::parseFirst(text, "begin=", '"', '"', false); QString contents_text = Seer::parseFirst(text, "contents=", '"', '"', false); _populateTable(begin_text, contents_text); }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg=\"No registers.\""))) { addressLineEdit->setText(""); }else{ // Ignore others. } break; } stackTableWidget->resizeColumnToContents(0); stackTableWidget->resizeColumnToContents(1); stackTableWidget->resizeColumnToContents(2); stackTableWidget->resizeColumnToContents(3); stackTableWidget->resizeColumnToContents(4); stackTableWidget->resizeRowsToContents(); QApplication::restoreOverrideCursor(); } void SeerStackDumpBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } refresh(); } void SeerStackDumpBrowserWidget::handleSessionTerminated () { // Delete previous contents. stackTableWidget->clearContents(); } void SeerStackDumpBrowserWidget::handleFormatComboBox (const QString& text) { Q_UNUSED(text); refresh(); } void SeerStackDumpBrowserWidget::handleVisualizerToolButton () { emit addMemoryVisualizer(addressLineEdit->text()); } void SeerStackDumpBrowserWidget::handlePreferencesToolButton () { // Bring up the register edit dialog. SeerStackDumpSettingsDialog dlg(this); dlg.setStackPointerExpression(stackPointerExpression()); dlg.setStackPointerColor(stackPointerColor()); dlg.setBytesBeforeSP(bytesBeforeSP()); dlg.setBytesAfterSP(bytesAfterSP()); dlg.setAsciiBytes(asciiBytes()); //dlg.set(item->text(1), item->text(2)); int ret = dlg.exec(); if (ret == 0) { return; } setStackPointerExpression(dlg.stackPointerExpression()); setStackPointerColor(dlg.stackPointerColor()); setBytesBeforeSP(dlg.bytesBeforeSP()); setBytesAfterSP(dlg.bytesAfterSP()); setAsciiBytes(dlg.asciiBytes()); writeSettings(); refresh(); } void SeerStackDumpBrowserWidget::handleCellDoubleClicked (int row, int col) { Q_UNUSED(col); QTableWidgetItem* item = stackTableWidget->item(row, 0); if (item == 0) { return; } QString address = item->text(); if (address.mid(0,2) != "0x") { address.insert(0,"0x"); } emit addMemoryVisualizer(address); } void SeerStackDumpBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshStackPointer(_spExpressionId, stackPointerExpression()); } void SeerStackDumpBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } void SeerStackDumpBrowserWidget::_populateTable (QString address, QString contents) { QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); // Loop off '0x'. if (address.mid(0,2) == "0x") { address = address.mid(2); } bool ok; quint64 address64 = address.toULongLong(&ok, 16); quint64 pos64 = address64; int nrows = contents.length()/2/2; // Divide by 2 for a "FF" character, then again for 2 bytes per row. // Convert the contents to raw bytes. QVector bytes; for (int pos=0; posclearContents(); stackTableWidget->setRowCount(nrows); int spRow = -1; // Fill in the address column. for (int i=0,r=0; i < contents.length()/2; i+=2,pos64+=2,r++) { QString str = QString::number(pos64, 16); QTableWidgetItem* item = new QTableWidgetItem; item->setText(str); item->setFont(fixedFont); if (addressLineEdit->text().contains(str)) { item->setBackground(QBrush(stackPointerColor())); spRow = r; } stackTableWidget->setItem(r,0,item); } // Fill in the 2byte column. for (int i=0,r=0; icurrentText() == "hex") { str = Seer::ucharToHex(bytes, i, 2); }else if (formatComboBox->currentText() == "octal") { str = Seer::ucharToOctal(bytes, i, 2); }else if (formatComboBox->currentText() == "uint") { str = Seer::ucharToUShort(bytes, i, 1); }else if (formatComboBox->currentText() == "int") { str = Seer::ucharToShort(bytes, i, 1); } QTableWidgetItem* item = new QTableWidgetItem; item->setText(str); item->setFont(fixedFont); if (r == spRow) { item->setBackground(QBrush(stackPointerColor())); } stackTableWidget->setItem(r,1,item); } // Fill in the 4byte column. for (int i=0,r=0; i < bytes.size(); i+=2,r++) { QString str; if (formatComboBox->currentText() == "hex") { str = Seer::ucharToHex(bytes, i, 4); }else if (formatComboBox->currentText() == "octal") { str = Seer::ucharToOctal(bytes, i, 4); }else if (formatComboBox->currentText() == "uint") { str = Seer::ucharToUInt(bytes, i, 1); }else if (formatComboBox->currentText() == "int") { str = Seer::ucharToInt(bytes, i, 1); }else if (formatComboBox->currentText() == "float") { str = Seer::ucharToFloat(bytes, i, 1); } QTableWidgetItem* item = new QTableWidgetItem; item->setText(str); item->setFont(fixedFont); if (r == spRow) { item->setBackground(QBrush(stackPointerColor())); } stackTableWidget->setItem(r,2,item); } // Fill in the 8byte column. for (int i=0,r=0; i < bytes.size(); i+=2,r++) { QString str; if (formatComboBox->currentText() == "hex") { str = Seer::ucharToHex(bytes, i, 8); }else if (formatComboBox->currentText() == "octal") { str = Seer::ucharToOctal(bytes, i, 8); }else if (formatComboBox->currentText() == "uint") { str = Seer::ucharToULong(bytes, i, 1); }else if (formatComboBox->currentText() == "int") { str = Seer::ucharToLong(bytes, i, 1); }else if (formatComboBox->currentText() == "float") { str = Seer::ucharToDouble(bytes, i, 1); } QTableWidgetItem* item = new QTableWidgetItem; item->setText(str); item->setFont(fixedFont); if (r == spRow) { item->setBackground(QBrush(stackPointerColor())); } stackTableWidget->setItem(r,3,item); } // Fill in the Nbyte ascii column. for (int i=0,r=0; i < bytes.size(); i+=2,r++) { QString str = Seer::ucharToAscii(bytes, i, asciiBytes()); QTableWidgetItem* item = new QTableWidgetItem; item->setText(str); item->setFont(fixedFont); if (r == spRow) { item->setBackground(QBrush(stackPointerColor())); } stackTableWidget->setItem(r,4,item); } } void SeerStackDumpBrowserWidget::writeSettings () { QSettings settings; settings.beginGroup("stackdumpwindow"); { settings.setValue("stackpointerexpression", stackPointerExpression()); settings.setValue("stackpointercolor", stackPointerColor()); settings.setValue("bytesbeforesp", bytesBeforeSP()); settings.setValue("bytesaftersp", bytesAfterSP()); settings.setValue("asciibytes", asciiBytes()); } settings.endGroup(); } void SeerStackDumpBrowserWidget::readSettings () { QSettings settings; settings.beginGroup("stackdumpwindow"); { setStackPointerExpression(settings.value("stackpointerexpression", "$sp").toString()); QVariant variant = settings.value("stackpointercolor", "lightGray"); QColor color = variant.value(); setStackPointerColor(color); setBytesBeforeSP(settings.value("bytesbeforesp", 32).toInt()); setBytesAfterSP(settings.value("bytesaftersp", 32).toInt()); setAsciiBytes(settings.value("asciibytes", 8).toInt()); } settings.endGroup(); } epasveer-seer-97076f1/src/SeerStackDumpBrowserWidget.h000066400000000000000000000052071526321767600227520ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerStackDumpBrowserWidget.h" class SeerStackDumpBrowserWidget : public QWidget, protected Ui::SeerStackDumpBrowserWidgetForm { Q_OBJECT public: explicit SeerStackDumpBrowserWidget (QWidget* parent = 0); ~SeerStackDumpBrowserWidget (); void setStackPointerExpression (const QString& expression); QString stackPointerExpression () const; void setBytesBeforeSP (int nbytes); int bytesBeforeSP () const; void setBytesAfterSP (int nbytes); int bytesAfterSP () const; void setAsciiBytes (int nbytes); int asciiBytes () const; void setStackPointerColor (const QColor& color); QColor stackPointerColor () const; public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleFormatComboBox (const QString& text); void handleVisualizerToolButton (); void handlePreferencesToolButton (); void handleCellDoubleClicked (int row, int col); signals: void refreshStackPointer (int id, QString expression); void refreshStackDump (int id, QString address, int offset, int count); void addMemoryVisualizer (QString expression); protected: void showEvent (QShowEvent* event); void readSettings (); void writeSettings (); private: void _populateTable (QString address, QString contents); int _spExpressionId; int _dumpExpressionId; QString _stackPointerExpression; int _bytesBeforeSP; int _bytesAfterSP; int _asciiBytes; QColor _stackPointerColor; }; epasveer-seer-97076f1/src/SeerStackDumpBrowserWidget.ui000066400000000000000000000131771526321767600231450ustar00rootroot00000000000000 SeerStackDumpBrowserWidgetForm 0 0 794 528 Seer Stack Dump 0 0 $sp 0 0 true address Format 0 0 hex octal int uint float Launch Memory Visualizer :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg Preferences :/seer/resources/RelaxLightIcons/application-menu.svg:/seer/resources/RelaxLightIcons/application-menu.svg Qt::Horizontal QSizePolicy::Expanding 40 20 QAbstractItemView::NoEditTriggers true Qt::SolidLine true false Address AlignLeading|AlignVCenter 2 Byte AlignLeading|AlignVCenter 4 Byte AlignLeading|AlignVCenter 8 Byte AlignLeading|AlignVCenter String AlignLeading|AlignVCenter addressLineEdit formatComboBox stackTableWidget epasveer-seer-97076f1/src/SeerStackDumpSettingsDialog.cpp000066400000000000000000000040151526321767600234320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackDumpSettingsDialog.h" #include "SeerRegisterTreeWidgetItem.h" #include #include #include #include #include #include #include SeerStackDumpSettingsDialog::SeerStackDumpSettingsDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); spHighLightColorButton->setFrameStyle(QFrame::Box|QFrame::Plain); spHighLightColorButton->setLineWidth(1); // Setup the widgets setStackPointerExpression("$sp"); setStackPointerColor(QColor("lightGray")); setBytesBeforeSP(16); setBytesAfterSP(16); setAsciiBytes(8); // Connect things. } SeerStackDumpSettingsDialog::~SeerStackDumpSettingsDialog () { } void SeerStackDumpSettingsDialog::setStackPointerExpression (const QString& expression) { spExpressionLineEdit->setText(expression); } void SeerStackDumpSettingsDialog::setStackPointerColor (const QColor& color) { spHighLightColorButton->setColor(color); } QColor SeerStackDumpSettingsDialog::stackPointerColor () const { return spHighLightColorButton->color(); } QString SeerStackDumpSettingsDialog::stackPointerExpression () const { return spExpressionLineEdit->text(); } void SeerStackDumpSettingsDialog::setBytesBeforeSP (int nbytes) { preBytesSpinBox->setValue(nbytes); } int SeerStackDumpSettingsDialog::bytesBeforeSP () const { return preBytesSpinBox->value(); } void SeerStackDumpSettingsDialog::setBytesAfterSP (int nbytes) { postBytesSpinBox->setValue(nbytes); } int SeerStackDumpSettingsDialog::bytesAfterSP () const { return postBytesSpinBox->value(); } void SeerStackDumpSettingsDialog::setAsciiBytes (int nbytes) { asciiBytesSpinBox->setValue(nbytes); } int SeerStackDumpSettingsDialog::asciiBytes () const { return asciiBytesSpinBox->value(); } epasveer-seer-97076f1/src/SeerStackDumpSettingsDialog.h000066400000000000000000000025061526321767600231020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerStackDumpSettingsDialog.h" class SeerStackDumpSettingsDialog : public QDialog, protected Ui::SeerStackDumpSettingsDialogForm { Q_OBJECT public: explicit SeerStackDumpSettingsDialog (QWidget* parent = 0); ~SeerStackDumpSettingsDialog (); void setStackPointerExpression (const QString& expression); QString stackPointerExpression () const; void setStackPointerColor (const QColor& color); QColor stackPointerColor () const; void setBytesBeforeSP (int nbytes); int bytesBeforeSP () const; void setBytesAfterSP (int nbytes); int bytesAfterSP () const; void setAsciiBytes (int nbytes); int asciiBytes () const; public slots: private slots: protected: private: }; epasveer-seer-97076f1/src/SeerStackDumpSettingsDialog.ui000066400000000000000000000224551526321767600232750ustar00rootroot00000000000000 SeerStackDumpSettingsDialogForm 0 0 699 502 Seer - Stack Dump Settings Stack pointer expression Gdb expression to get the stack pointer. SP expression true Highlight color 0 0 40 0 Select color to highlight SP row. Qt::Horizontal 218 20 Bytes shown before SP Number of bytes shown before the SP. 96 8 16 Qt::Horizontal 448 20 Bytes shown after SP Number of bytes shown after the SP. 96 8 16 Qt::Horizontal 448 20 Ascii bytes shown Number of ascii bytes to show. 96 1 8 Qt::Horizontal 448 20 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The stack pointer (SP) points to where in the stack memory the program is currently at. The settings here control how the memory around the SP is displayed.<br /><br />GDB has the virtual variable called &quot;$sp&quot;, which contains the SP address. It is typical to use this as the SP expression. Some might prefer &quot;$ss*16+$sp&quot;, which is for X86 real mode. Either way, enter a gdb expression that results in an address. In most cases, $sp is enough.<br /><br />Seer can show N bytes before and N bytes after the SP, thus forming a window of bytes. N is rounded up to the next count of 8.<br /><br />The bytes are shown as 2, 4, and 8 byte version of: hex, octal, int, uint, and float values.</p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Also, Seer will attempt to show the bytes as Ascii characters. The number of Ascii characters to show can be set.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Double clicking on a row will bring up a separate Memory Visualizer for that address.</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br />Highlight color is used to highlight the row that contains $SP. Double click on it to bring up a color chooser.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok QColorButton QWidget
QColorButton.h
1
buttonBox accepted() SeerStackDumpSettingsDialogForm accept() 248 254 157 274 buttonBox rejected() SeerStackDumpSettingsDialogForm reject() 316 260 286 274
epasveer-seer-97076f1/src/SeerStackFramesBrowserWidget.cpp000066400000000000000000000214411526321767600236130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackFramesBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerStackFramesBrowserWidget::SeerStackFramesBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); _previousStackFrameText = ""; // Setup the widgets stackTreeWidget->setMouseTracking(true); stackTreeWidget->setSortingEnabled(false); stackTreeWidget->resizeColumnToContents(0); // level stackTreeWidget->resizeColumnToContents(1); // func stackTreeWidget->resizeColumnToContents(2); // file stackTreeWidget->resizeColumnToContents(3); // line stackTreeWidget->resizeColumnToContents(4); // fullname stackTreeWidget->resizeColumnToContents(5); // addr stackTreeWidget->resizeColumnToContents(6); // arch stackTreeWidget->clear(); // Connect things. QObject::connect(stackTreeWidget, &QTreeWidget::itemClicked, this, &SeerStackFramesBrowserWidget::handleItemClicked); QObject::connect(stackTreeWidget, &QTreeWidget::itemEntered, this, &SeerStackFramesBrowserWidget::handleItemEntered); } SeerStackFramesBrowserWidget::~SeerStackFramesBrowserWidget () { } void SeerStackFramesBrowserWidget::handleText (const QString& text) { // Stackframes is important. Always do it. // // Don't do any work if the widget is hidden. // if (isHidden()) { // return; // } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,stack=[") && text.endsWith("]")) { // ^done,stack=[ // frame={level=\"0\",addr=\"0x0000000000400d72\",func=\"function1\",file=\"function1.cpp\",fullname=\"/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp\",line=\"7\",arch=\"i386:x86-64\"}, // frame={level=\"1\",addr=\"0x0000000000400cc3\",func=\"main\",file=\"helloworld.cpp\",fullname=\"/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp\",line=\"14\",arch=\"i386:x86-64\"} // ] // If we are simply moving up and down the stack (via frame-select) then the text won't change. // If it is different, reconstruct the tree. Select the first frame. if (text != _previousStackFrameText) { _previousStackFrameText = text; stackTreeWidget->clear(); QString stack_text = Seer::parseFirst(text, "stack=", '[', ']', false); if (stack_text != "") { // Parse through the frame list and set the current lines that are in the frame list. QStringList frame_list = Seer::parse(text, "frame=", '{', '}', false); QString firstLiveFrameLevel = ""; QString firstLiveFrameFile = ""; QString firstLiveFrameFullname = ""; QString firstLiveFrameLine = ""; QString firstFrameLevel = ""; QString firstFrameAddr = ""; for ( const auto& frame_text : frame_list ) { QString level_text = Seer::parseFirst(frame_text, "level=", '"', '"', false); QString addr_text = Seer::parseFirst(frame_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(frame_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); QString arch_text = Seer::parseFirst(frame_text, "arch=", '"', '"', false); // Create the item. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, level_text); item->setText(1, func_text); item->setText(2, QFileInfo(file_text).fileName()); item->setText(3, line_text); item->setText(4, fullname_text); item->setText(5, addr_text); item->setText(6, arch_text); // Enable/disable interaction with this row depending if there is a valid file and line number. if (file_text != "" && fullname_text != "" && line_text != "") { item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); // Save the first live frame (that has a valid file and lineno) so we can select it automatically. // This only happens if the stack text is different (a stop point is reached). if (firstLiveFrameLevel == "") { firstLiveFrameLevel = level_text; firstLiveFrameFile = QFileInfo(file_text).fileName(); firstLiveFrameFullname = fullname_text; firstLiveFrameLine = line_text; } }else{ item->setFlags(Qt::NoItemFlags); } // Get the address of the first entry of the frame. if (addr_text != "") { if (firstFrameLevel == "") { firstFrameLevel = level_text; firstFrameAddr = addr_text; } } // Add the frame to the tree. stackTreeWidget->addTopLevelItem(item); } // Automatically bring up the file for the first live frame. if (firstLiveFrameLevel != "") { if (firstLiveFrameFile != "" && firstLiveFrameFullname != "") { emit selectedFile(firstLiveFrameFile, firstLiveFrameFullname, firstLiveFrameLine.toInt()); } } // Automatically bring up the assembly for the first frame. emit maybeSelectedAddress(firstLiveFrameFile, firstLiveFrameFullname, firstFrameAddr); } // Select the first frame level. // ??? Perhaps show the current frame level somehow. stackTreeWidget->clearSelection(); QList matches = stackTreeWidget->findItems("0", Qt::MatchExactly, 0); if (matches.size() > 0) { stackTreeWidget->setCurrentItem(matches.first()); } } }else{ // Ignore others. } stackTreeWidget->resizeColumnToContents(0); stackTreeWidget->resizeColumnToContents(1); stackTreeWidget->resizeColumnToContents(2); stackTreeWidget->resizeColumnToContents(3); stackTreeWidget->resizeColumnToContents(4); stackTreeWidget->resizeColumnToContents(5); stackTreeWidget->resizeColumnToContents(6); QApplication::restoreOverrideCursor(); } void SeerStackFramesBrowserWidget::handleStoppingPointReached () { // Stackframes is important. Always do it. // // Don't do any work if the widget is hidden. // if (isHidden()) { // return; // } refresh(); } void SeerStackFramesBrowserWidget::handleSessionTerminated () { // Delete previous contents and remembered state. stackTreeWidget->clear(); _previousStackFrameText = ""; } void SeerStackFramesBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshStackFrames(); } void SeerStackFramesBrowserWidget::handleItemClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); int lineno = item->text(3).toInt(); // Select frame. emit selectedFrame(item->text(0).toInt()); // Select file if we can. if (item->text(2) != "" && item->text(4) != "") { emit selectedFile(item->text(2), item->text(4), lineno); } // Select address if we can. if (item->text(5) != "") { emit maybeSelectedAddress(item->text(2), item->text(4), item->text(5)); } } void SeerStackFramesBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + item->text(1) + " : " + item->text(2) + " : " + item->text(3)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerStackFramesBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } epasveer-seer-97076f1/src/SeerStackFramesBrowserWidget.h000066400000000000000000000030131526321767600232530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerStackFramesBrowserWidget.h" class SeerStackFramesBrowserWidget : public QWidget, protected Ui::SeerStackFramesBrowserWidgetForm { Q_OBJECT public: explicit SeerStackFramesBrowserWidget (QWidget* parent = 0); ~SeerStackFramesBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshStackFrames (); void selectedFile (QString file, QString fullname, int lineno); void selectedAddress (QString address); void maybeSelectedAddress (QString file, QString fullname, QString address); void selectedFrame (int frameno); protected: void showEvent (QShowEvent* event); private: QString _previousStackFrameText; }; epasveer-seer-97076f1/src/SeerStackFramesBrowserWidget.ui000066400000000000000000000026201526321767600234440ustar00rootroot00000000000000 SeerStackFramesBrowserWidgetForm 0 0 600 700 Form 7 Level Function File Line Fullname Address Arch epasveer-seer-97076f1/src/SeerStackLocalsBrowserWidget.cpp000066400000000000000000000541041526321767600236150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackLocalsBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include SeerStackLocalsBrowserWidget::SeerStackLocalsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets localsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); localsTreeWidget->setMouseTracking(true); localsTreeWidget->setSortingEnabled(false); localsTreeWidget->resizeColumnToContents(0); // name localsTreeWidget->resizeColumnToContents(1); // arg localsTreeWidget->resizeColumnToContents(2); // value localsTreeWidget->resizeColumnToContents(3); // used localsTreeWidget->setColumnHidden(3, true); // Hide the 'used' column. localsTreeWidget->clear(); _frameNumber = 0; // Connect things. QObject::connect(localsTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerStackLocalsBrowserWidget::handleContextMenu); QObject::connect(localsTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerStackLocalsBrowserWidget::handleItemCollapsed); QObject::connect(localsTreeWidget, &QTreeWidget::itemExpanded, this, &SeerStackLocalsBrowserWidget::handleItemExpanded); QObject::connect(localsTreeWidget, &QTreeWidget::itemEntered, this, &SeerStackLocalsBrowserWidget::handleItemEntered); } SeerStackLocalsBrowserWidget::~SeerStackLocalsBrowserWidget () { } void SeerStackLocalsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,variables=[") && text.endsWith("]")) { // ^done,variables=[ // {name=\"message\",arg=\"1\",value=\"\\\"Hello, World!\\\"\"}, // {name=\"something\",arg=\"1\",value=\"\\\"Hello, World!\\\"\"} // ] // Parse the text. Create a list of variables. QString frame_text = Seer::parseFirst(text, "variables=", '[', ']', false); QStringList variable_list = Seer::parse(frame_text, "", '{', '}', false); // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(localsTreeWidget); while (*it) { (*it)->setText(3, "unused"); ++it; } // Loop through each variable. for (const auto& variable_text : variable_list) { QString name_text = Seer::parseFirst(variable_text, "name=", '"', '"', false); QString arg_text = Seer::parseFirst(variable_text, "arg=", '"', '"', false); QString value_text = Seer::parseFirst(variable_text, "value=", '"', '"', false); // Morph 'is function argument' from a '1' to 'yes'. arg_text = (arg_text == "1" ? "yes" : ""); // Populate the tree. handleItemCreate(0, name_text, arg_text, value_text); } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. // Don't use qDeleteAll() here. It doesn't work as expected for items that are "found". // Instead, get a list of matches and delete them from the bottom up. QList matches = localsTreeWidget->findItems("unused", Qt::MatchExactly|Qt::MatchRecursive, 3); while (matches.isEmpty() == false) { foreach (QTreeWidgetItem* item, matches) { if (item->childCount() == 0) { QTreeWidgetItem* parent = item->parent(); if (parent) { parent->removeChild(item); } bool f = matches.removeOne(item); Q_ASSERT(f != false); delete item; break; } } } }else{ // Ignore others. } localsTreeWidget->resizeColumnToContents(0); localsTreeWidget->resizeColumnToContents(1); localsTreeWidget->resizeColumnToContents(2); localsTreeWidget->resizeColumnToContents(3); QApplication::restoreOverrideCursor(); } void SeerStackLocalsBrowserWidget::handleStoppingPointReached () { refresh(); } void SeerStackLocalsBrowserWidget::handleSessionTerminated () { // Delete previous contents. localsTreeWidget->clear(); } void SeerStackLocalsBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshStackLocals(); } void SeerStackLocalsBrowserWidget::handleContextMenu (const QPoint& pos) { QTreeWidgetItem* item = localsTreeWidget->itemAt(pos); if (item == 0) { return; } QAction* addVariableLoggerExpressionAction; QAction* addVariableLoggerAsteriskExpressionAction; QAction* addVariableLoggerAmpersandExpressionAction; QAction* addVariableLoggerAsteriskAmpersandExpressionAction; QAction* addVariableLoggerObjcExpressionAction; QAction* addVariableTrackerExpressionAction; QAction* addVariableTrackerAsteriskExpressionAction; QAction* addVariableTrackerAmpersandExpressionAction; QAction* addVariableTrackerAsteriskAmpersandExpressionAction; QAction* addVariableTrackerObjcExpressionAction; QAction* addMemoryVisualizerAction; QAction* addMemoryAsteriskVisualizerAction; QAction* addMemoryAmpersandVisualizerAction; QAction* addArrayVisualizerAction; QAction* addArrayAsteriskVisualizerAction; QAction* addArrayAmpersandVisualizerAction; QAction* addMatrixVisualizerAction; QAction* addMatrixAsteriskVisualizerAction; QAction* addMatrixAmpersandVisualizerAction; QAction* addStructVisualizerAction; QAction* addStructAsteriskVisualizerAction; QAction* addStructAmpersandVisualizerAction; addVariableLoggerExpressionAction = new QAction(QString("%1").arg(item->text(0))); addVariableLoggerAsteriskExpressionAction = new QAction(QString("*%1").arg(item->text(0))); addVariableLoggerAmpersandExpressionAction = new QAction(QString("&&%1").arg(item->text(0))); addVariableLoggerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(item->text(0))); addVariableLoggerObjcExpressionAction = new QAction(QString("(objc)%1").arg(item->text(0))); addVariableTrackerExpressionAction = new QAction(QString("%1").arg(item->text(0))); addVariableTrackerAsteriskExpressionAction = new QAction(QString("*%1").arg(item->text(0))); addVariableTrackerAmpersandExpressionAction = new QAction(QString("&&%1").arg(item->text(0))); addVariableTrackerAsteriskAmpersandExpressionAction = new QAction(QString("*&&%1").arg(item->text(0))); addVariableTrackerObjcExpressionAction = new QAction(QString("(objc)%1").arg(item->text(0))); addMemoryVisualizerAction = new QAction(QString("%1").arg(item->text(0))); addMemoryAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(0))); addMemoryAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(0))); addArrayVisualizerAction = new QAction(QString("%1").arg(item->text(0))); addArrayAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(0))); addArrayAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(0))); addMatrixVisualizerAction = new QAction(QString("%1").arg(item->text(0))); addMatrixAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(0))); addMatrixAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(0))); addStructVisualizerAction = new QAction(QString("%1").arg(item->text(0))); addStructAsteriskVisualizerAction = new QAction(QString("*%1").arg(item->text(0))); addStructAmpersandVisualizerAction = new QAction(QString("&&%1").arg(item->text(0))); QMenu menu("Visualizers", this); menu.setTitle("Visualizers"); QMenu loggerMenu("Add variable to Logger"); loggerMenu.addAction(addVariableLoggerExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskExpressionAction); loggerMenu.addAction(addVariableLoggerAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerAsteriskAmpersandExpressionAction); loggerMenu.addAction(addVariableLoggerObjcExpressionAction); menu.addMenu(&loggerMenu); QMenu trackerMenu("Add variable to Tracker"); trackerMenu.addAction(addVariableTrackerExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskExpressionAction); trackerMenu.addAction(addVariableTrackerAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerAsteriskAmpersandExpressionAction); trackerMenu.addAction(addVariableTrackerObjcExpressionAction); menu.addMenu(&trackerMenu); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); // Launch the menu. Get the response. QAction* action = menu.exec(localsTreeWidget->viewport()->mapToGlobal(pos)); // Do nothing. if (action == 0) { return; } // Build up a variable string, incase it is a nested struct. QTreeWidgetItem* i = item; QString variable = item->text(0); while (i->parent() != 0) { variable = i->parent()->text(0) + "." + variable; i = i->parent(); } // Handle adding a variable to log. if (action == addVariableLoggerExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableLoggerExpression(variable); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableLoggerExpression(QString("*") + variable); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAmpersandExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableLoggerExpression(QString("&") + variable); } return; } // Handle adding a variable to log. if (action == addVariableLoggerAsteriskAmpersandExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableLoggerExpression(QString("*&") + variable); } return; } // Handle adding a variable to log. if (action == addVariableLoggerObjcExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableLoggerExpression(QString("(objc)") + variable); } return; } // Handle adding a variable to track. if (action == addVariableTrackerExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableTrackerExpression(variable); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableTrackerExpression(QString("*") + variable); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAmpersandExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableTrackerExpression(QString("&") + variable); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerAsteriskAmpersandExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableTrackerExpression(QString("*&") + variable); emit refreshVariableTrackerValues(); } return; } // Handle adding a variable to track. if (action == addVariableTrackerObjcExpressionAction) { // Emit the signals. if (variable != "") { emit addVariableTrackerExpression(QString("(objc)") + variable); emit refreshVariableTrackerValues(); } return; } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("*") + variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("&") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("*") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("&") + variable); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(variable); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("*") + variable); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("&") + variable); } return; } } void SeerStackLocalsBrowserWidget::handleItemExpanded (QTreeWidgetItem* item) { Q_UNUSED(item); localsTreeWidget->resizeColumnToContents(0); localsTreeWidget->resizeColumnToContents(1); localsTreeWidget->resizeColumnToContents(2); localsTreeWidget->resizeColumnToContents(3); } void SeerStackLocalsBrowserWidget::handleItemCollapsed (QTreeWidgetItem* item) { Q_UNUSED(item); localsTreeWidget->resizeColumnToContents(0); localsTreeWidget->resizeColumnToContents(1); localsTreeWidget->resizeColumnToContents(2); localsTreeWidget->resizeColumnToContents(3); } void SeerStackLocalsBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + Seer::elideText(item->text(2), Qt::ElideRight, 100)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerStackLocalsBrowserWidget::handleItemCreate (QTreeWidgetItem* parentItem, const QString& name_text, const QString& arg_text, const QString& value_text) { // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. We start by looking for matches that // may already be there. If there are matches, the code will reuse it. If not, a new item // is created by the code. Note, when searching, we only look at the current level. Not any // children. QList matches; if (parentItem == 0) { matches = localsTreeWidget->findItems(name_text, Qt::MatchExactly, 0); }else{ for (int i=0; ichildCount(); i++) { if (parentItem->child(i)->text(0) == name_text) { matches.append(parentItem->child(i)); } } } // Parse bookmarks. QString capture0; // With bookends. QString capture1; // Without. QRegularExpression withaddress_re("^@0[xX][0-9a-fA-F]+: \\{(.*?)\\}$"); QRegularExpressionMatch withaddress_match = withaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (withaddress_match.hasMatch()) { capture0 = withaddress_match.captured(0); capture1 = withaddress_match.captured(1); }else{ QRegularExpression noaddress_re("^\\{(.*?)\\}$"); QRegularExpressionMatch noaddress_match = noaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (noaddress_match.hasMatch()) { capture0 = noaddress_match.captured(0); capture1 = noaddress_match.captured(1); } } // Add the complex entry to the tree. Reuse, if possible. if (capture0 != "" && capture1 != "") { // Remove bookends QString text = capture1; QTreeWidgetItem* item = 0; // Use the privously created item. Or create a new one. if (matches.size() > 0) { item = matches[0]; item->setText(3, "reused"); }else{ item = new QTreeWidgetItem; item->setText(3, "new"); // If we're dealing with a top-level item, attach it to the tree. // Otherwise, attach it to the parent. if (parentItem) { parentItem->addChild(item); }else{ localsTreeWidget->addTopLevelItem(item); } } // Set the flatvalue text. item->setText(0, name_text); item->setText(1, arg_text); item->setText(2, Seer::filterEscapes(text)); item->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); // Convert to a list of name/value pairs. QStringList nv_pairs = Seer::parseCommaList(text, '{', '}'); // Go through each pair and add the name and its value to the tree. for (const auto& nv : nv_pairs) { QStringPair pair = Seer::parseNameValue(nv, '='); handleItemCreate(item, pair.first, arg_text, pair.second); } // Add the simple entry to the tree. Reuse, if possible. }else{ QTreeWidgetItem* item = 0; // Use the privously created item. Or create a new one. if (matches.size() > 0) { item = matches[0]; item->setText(3, "reused"); }else{ item = new QTreeWidgetItem; item->setText(3, "new"); // If we're dealing with a top-level item, attach it to the tree. // Otherwise, attach it to the parent. if (parentItem) { parentItem->addChild(item); }else{ localsTreeWidget->addTopLevelItem(item); } } // Simple entries don't have children. Delete them. QList children = item->takeChildren(); if (matches.size() > 0) { qDeleteAll(children); } // Populate the item. item->setText(0, name_text); item->setText(1, arg_text); item->setText(2, Seer::filterEscapes(value_text)); item->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); } } void SeerStackLocalsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } epasveer-seer-97076f1/src/SeerStackLocalsBrowserWidget.h000066400000000000000000000041671526321767600232660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerStackLocalsBrowserWidget.h" class SeerStackLocalsBrowserWidget : public QWidget, protected Ui::SeerStackLocalsBrowserWidgetForm { Q_OBJECT public: explicit SeerStackLocalsBrowserWidget (QWidget* parent = 0); ~SeerStackLocalsBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleContextMenu (const QPoint& pos); void handleItemExpanded (QTreeWidgetItem* item); void handleItemCollapsed (QTreeWidgetItem* item); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshStackLocals (); void addVariableLoggerExpression (QString expression); void addVariableTrackerExpression (QString expression); void refreshVariableTrackerValues (); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); protected: void handleItemCreate (QTreeWidgetItem* parentItem, const QString& name_text, const QString& arg_text, const QString& value_text); void showEvent (QShowEvent* event); private: int _frameNumber; }; epasveer-seer-97076f1/src/SeerStackLocalsBrowserWidget.ui000066400000000000000000000021261526321767600234450ustar00rootroot00000000000000 SeerStackLocalsBrowserWidgetForm 0 0 794 528 Form 4 Name Arg Value Used epasveer-seer-97076f1/src/SeerStackManagerWidget.cpp000066400000000000000000000237101526321767600224050ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStackManagerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include SeerStackManagerWidget::SeerStackManagerWidget (QWidget* parent) : QWidget(parent) { // Initialize private data // Setup UI setupUi(this); // Setup the widgets tabWidget->setMovable(true); tabWidget->setTabsClosable(false); _stackFramesBrowserWidget = new SeerStackFramesBrowserWidget(this); _stackArgumentsBrowserWidget = new SeerStackArgumentsBrowserWidget(this); _stackLocalsBrowserWidget = new SeerStackLocalsBrowserWidget(this); _stackDumpBrowserWidget = new SeerStackDumpBrowserWidget(this); tabWidget->addTab(_stackFramesBrowserWidget, "Frames"); tabWidget->addTab(_stackArgumentsBrowserWidget, "Arguments"); tabWidget->addTab(_stackLocalsBrowserWidget, "Locals"); tabWidget->addTab(_stackDumpBrowserWidget, "Stack"); QToolButton* tabsContextMenuButton = new QToolButton(tabWidget); tabsContextMenuButton->setIcon(QIcon(":/seer/resources/thenounproject/preferences.svg")); tabsContextMenuButton->setToolTip("Show/Hide tabs."); tabsContextMenuButton->setContextMenuPolicy(Qt::CustomContextMenu); QToolButton* refreshToolButton = new QToolButton(tabWidget); refreshToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/view-refresh.svg")); refreshToolButton->setToolTip("Refresh the stack information."); QToolButton* helpToolButton = new QToolButton(tabWidget); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on stack information."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(tabsContextMenuButton); hcontainer->addWidget(refreshToolButton); hcontainer->addWidget(helpToolButton); tabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Restore tab ordering. readSettings(); // Connect things. QObject::connect(tabsContextMenuButton, &QToolButton::clicked, this, &SeerStackManagerWidget::handleTabsContextMenuButtonClicked); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerStackManagerWidget::handleRefreshToolButtonClicked); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerStackManagerWidget::handleHelpToolButtonClicked); QObject::connect(tabWidget->tabBar(), &QTabBar::tabMoved, this, &SeerStackManagerWidget::handleTabMoved); QObject::connect(tabWidget->tabBar(), &QTabBar::currentChanged, this, &SeerStackManagerWidget::handleTabChanged); } SeerStackManagerWidget::~SeerStackManagerWidget () { } SeerStackFramesBrowserWidget* SeerStackManagerWidget::stackFramesBrowserWidget () { return _stackFramesBrowserWidget; } SeerStackArgumentsBrowserWidget* SeerStackManagerWidget::stackArgumentsBrowserWidget () { return _stackArgumentsBrowserWidget; } SeerStackLocalsBrowserWidget* SeerStackManagerWidget::stackLocalsBrowserWidget () { return _stackLocalsBrowserWidget; } SeerStackDumpBrowserWidget* SeerStackManagerWidget::stackDumpBrowserWidget () { return _stackDumpBrowserWidget; } void SeerStackManagerWidget::handleRefreshToolButtonClicked () { stackFramesBrowserWidget()->refresh(); stackArgumentsBrowserWidget()->refresh(); stackLocalsBrowserWidget()->refresh(); stackDumpBrowserWidget()->refresh(); refresh(); } void SeerStackManagerWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/StackInfoBrowser.md"); help->show(); help->raise(); } void SeerStackManagerWidget::handleTabMoved (int from, int to) { Q_UNUSED(from); Q_UNUSED(to); writeSettings(); } void SeerStackManagerWidget::handleTabChanged (int index) { Q_UNUSED(index); writeSettings(); } void SeerStackManagerWidget::writeSettings () { // Build up visible list. QStringList visible; for (int i=0; itabBar()->count(); i++) { visible.append(tabWidget->isTabVisible(i) ? "true" : "false"); } // Build up tab order. QStringList tabs; for (int i=0; itabBar()->count(); i++) { tabs.append(tabWidget->tabBar()->tabText(i)); } // Build up current tab. QString current = tabWidget->tabBar()->tabText(tabWidget->tabBar()->currentIndex()); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; QSettings settings; settings.beginGroup("stackmanagerwindow"); { settings.setValue("taborder", tabs.join(',')); settings.setValue("tabvisible", visible.join(',')); settings.setValue("tabcurrent", current); } settings.endGroup(); } void SeerStackManagerWidget::readSettings () { // Can't move things? if (tabWidget->tabBar()->isMovable() == false) { return; } // Read tab order from settings. QSettings settings; QStringList tabs; QStringList visible; QString current; settings.beginGroup("stackmanagerwindow"); { tabs = settings.value("taborder").toString().split(','); visible = settings.value("tabvisible").toString().split(','); current = settings.value("tabcurrent").toString(); } settings.endGroup(); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Move tabs to the requested order. for (int i=0; itabBar()->count(); j++) { if (tabWidget->tabBar()->tabText(j) == tab) { tb = j; break; } } if (tb != -1) { tabWidget->tabBar()->moveTab(tb, i); } } // Show/Hide tabs. for (int i=0; isetTabVisible(i,true); }else if (flag == "false") { tabWidget->setTabVisible(i,false); }else{ tabWidget->setTabVisible(i,true); } } // Make a tab current. if (current != "") { for (int i=0; itabBar()->count(); i++) { if (tabWidget->tabBar()->tabText(i) == current) { tabWidget->setCurrentIndex(i); break; } } }else{ tabWidget->setCurrentIndex(0); } } void SeerStackManagerWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,thread-ids={")) { QString newtext = Seer::filterEscapes(text); // Filter escaped characters. // ^done,thread-ids={ // thread-id=\"1\", // thread-id=\"2\" // }, // current-thread-id=\"1\", // number-of-threads=\"2\" QString currentthreadid_text = Seer::parseFirst(newtext, "current-thread-id=", '"', '"', false); if (currentthreadid_text == "") { label->setText("Stack Info - No Thread Selected"); }else{ label->setText("Stack Info - Thread Id " + currentthreadid_text); } stackFramesBrowserWidget()->refresh(); stackArgumentsBrowserWidget()->refresh(); stackLocalsBrowserWidget()->refresh(); stackDumpBrowserWidget()->refresh(); }else{ // Ignore others. } QApplication::restoreOverrideCursor(); } void SeerStackManagerWidget::handleSessionTerminated () { label->setText("Stack Info"); } void SeerStackManagerWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } refresh(); } void SeerStackManagerWidget::refresh () { emit refreshThreadFrames(); } void SeerStackManagerWidget::handleTabsContextMenuButtonClicked() { // Build the menu and execute it. QMenu contextMenu; QWidget* container = new QWidget(&contextMenu); QVBoxLayout* layout = new QVBoxLayout(container); for (int i = 0; i < tabWidget->count(); i++) { QString title = tabWidget->tabText(i); QCheckBox* showTabCheckBox = new QCheckBox(title, container); showTabCheckBox->setChecked(tabWidget->isTabVisible(i)); layout->addWidget(showTabCheckBox); QObject::connect(showTabCheckBox, &QCheckBox::toggled, [this, showTabCheckBox, i](bool checked) { // Count visible tabs. int count=0; for (int x=0; xcount(); x++) { if (tabWidget->isTabVisible(x)) { count++; } } // Adjust the count. The 'checked' is made before the UI is updated. if (checked == true) { count++; }else{ count--; } // Reset the checkbox UI if the last visible tab was clicked. if (checked == false and count == 0) { showTabCheckBox->setChecked(true); // Don't hide last visible tab. }else if (checked == false and count > 1) { tabWidget->setTabVisible(i, checked); // Always show tabs when asked. }else{ tabWidget->setTabVisible(i, checked); } writeSettings(); }); } container->setLayout(layout); QWidgetAction* action = new QWidgetAction(&contextMenu); action->setDefaultWidget(container); contextMenu.addAction(action); contextMenu.exec(QCursor::pos()); } epasveer-seer-97076f1/src/SeerStackManagerWidget.h000066400000000000000000000050301526321767600220450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerStackFramesBrowserWidget.h" #include "SeerStackArgumentsBrowserWidget.h" #include "SeerStackLocalsBrowserWidget.h" #include "SeerStackDumpBrowserWidget.h" #include #include "ui_SeerStackManagerWidget.h" class SeerStackManagerWidget : public QWidget, protected Ui::SeerStackManagerWidgetForm { Q_OBJECT public: explicit SeerStackManagerWidget (QWidget* parent = 0); ~SeerStackManagerWidget (); SeerStackFramesBrowserWidget* stackFramesBrowserWidget (); SeerStackArgumentsBrowserWidget* stackArgumentsBrowserWidget (); SeerStackLocalsBrowserWidget* stackLocalsBrowserWidget (); SeerStackDumpBrowserWidget* stackDumpBrowserWidget (); signals: void refreshThreadFrames (); protected: void writeSettings (); void readSettings (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); private slots: void handleRefreshToolButtonClicked (); void handleHelpToolButtonClicked (); void handleTabMoved (int from, int to); void handleTabChanged (int index); void handleTabsContextMenuButtonClicked (); private: SeerStackFramesBrowserWidget* _stackFramesBrowserWidget; SeerStackArgumentsBrowserWidget* _stackArgumentsBrowserWidget; SeerStackLocalsBrowserWidget* _stackLocalsBrowserWidget; SeerStackDumpBrowserWidget* _stackDumpBrowserWidget; }; epasveer-seer-97076f1/src/SeerStackManagerWidget.ui000066400000000000000000000031131526321767600222330ustar00rootroot00000000000000 SeerStackManagerWidgetForm 0 0 773 494 Form 0 0 0 0 3 font-weight: bold; Stack Info Qt::PlainText -1 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
epasveer-seer-97076f1/src/SeerStaticBrowserWidget.cpp000066400000000000000000000167031526321767600226440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStaticBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include SeerStaticBrowserWidget::SeerStaticBrowserWidget (QWidget* parent) : QWidget(parent) { // Set the state. _id = Seer::createID(); // Construct the UI. setupUi(this); // Setup the widgets staticNameSearchLineEdit->setPlaceholderText("Static name regex..."); staticNameSearchLineEdit->setClearButtonEnabled(true); staticTypeSearchLineEdit->setPlaceholderText("Static type regex..."); staticTypeSearchLineEdit->setClearButtonEnabled(true); staticTreeWidget->setMouseTracking(true); //staticTreeWidget->resizeColumnToContents(0); //staticTreeWidget->resizeColumnToContents(1); staticTreeWidget->resizeColumnToContents(2); staticTreeWidget->resizeColumnToContents(3); staticTreeWidget->resizeColumnToContents(4); staticTreeWidget->resizeColumnToContents(5); staticTreeWidget->clear(); staticTreeWidget->setSortingEnabled(false); // Connect things. QObject::connect(staticTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerStaticBrowserWidget::handleItemDoubleClicked); QObject::connect(staticTreeWidget, &QTreeWidget::itemEntered, this, &SeerStaticBrowserWidget::handleItemEntered); QObject::connect(staticNameSearchLineEdit, &QLineEdit::returnPressed, this, &SeerStaticBrowserWidget::handleSearchLineEdit); QObject::connect(staticTypeSearchLineEdit, &QLineEdit::returnPressed, this, &SeerStaticBrowserWidget::handleSearchLineEdit); } SeerStaticBrowserWidget::~SeerStaticBrowserWidget () { } void SeerStaticBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith(QString::number(_id) + "^done,symbols={") && text.endsWith("}")) { staticTreeWidget->clear(); staticTreeWidget->setSortingEnabled(false); staticTreeWidget->sortByColumn(-1, Qt::AscendingOrder); // -symbol-info-variables // ^done,symbols={ // debug=[ // { // filename="elf-init.c", // fullname="/home/abuild/rpmbuild/BUILD/glibc-2.31/csu/elf-init.c", // symbols=[ // { // line="95", // name="__libc_csu_fini", // type="void (void)", // description="void __libc_csu_fini(void);" // }, // { // line="67", // name="__libc_csu_init", // type="void (int, char **, char **)", // description="void __libc_csu_init(int, char **, char **);" // } // ] // }, // ... // ] // } QString debug_text = Seer::parseFirst(text, "debug=", '[', ']', false); QStringList filenames_list = Seer::parse(debug_text, "", '{', '}', false); for (const auto& filename_entry : filenames_list) { QString filename_text = Seer::parseFirst(filename_entry, "filename=", '"', '"', false); QString fullname_text = Seer::parseFirst(filename_entry, "fullname=", '"', '"', false); QString symbols_text = Seer::parseFirst(filename_entry, "symbols=", '[', ']', false); QStringList symbols_list = Seer::parse(symbols_text, "", '{', '}', false); for (const auto& symbol_entry : symbols_list) { QString line_text = Seer::parseFirst(symbol_entry, "line=", '"', '"', false); QString name_text = Seer::parseFirst(symbol_entry, "name=", '"', '"', false); QString type_text = Seer::parseFirst(symbol_entry, "type=", '"', '"', false); QString description_text = Seer::parseFirst(symbol_entry, "type=", '"', '"', false); // Skip variable entries that have no line number. if (line_text == "") { continue; } // Add the variable to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; QFont f0 = item->font(0); f0.setBold(true); item->setFont(0,f0); item->setFont(1,f0); item->setText(0, name_text); item->setText(1, type_text); item->setText(2, filename_text); item->setText(3, line_text); item->setText(4, fullname_text); item->setText(5, description_text); staticTreeWidget->addTopLevelItem(item); } } }else{ // Ignore others. } //staticTreeWidget->resizeColumnToContents(0); // Name //staticTreeWidget->resizeColumnToContents(1); // Type staticTreeWidget->resizeColumnToContents(2); // Filename staticTreeWidget->resizeColumnToContents(3); // Line staticTreeWidget->resizeColumnToContents(4); // Fullname staticTreeWidget->resizeColumnToContents(5); // Description staticTreeWidget->sortByColumn(0, Qt::AscendingOrder); staticTreeWidget->setSortingEnabled(true); QApplication::restoreOverrideCursor(); } void SeerStaticBrowserWidget::handleSessionTerminated () { // Delete previous contents. staticTreeWidget->clear(); } void SeerStaticBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedFile(item->text(2), item->text(4), item->text(3).toInt()); } void SeerStaticBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); QString tip = QString("Variable: %1\nType: %2\nFile: %3\nLine: %4\nFullname: %5\nDescription: %6").arg(item->text(0)).arg(item->text(1)).arg(item->text(2)).arg(item->text(3)).arg(item->text(4)).arg(item->text(5)); item->setToolTip(0, tip); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerStaticBrowserWidget::handleSearchLineEdit () { staticTreeWidget->clear(); staticTreeWidget->setSortingEnabled(false); staticTreeWidget->sortByColumn(-1, Qt::AscendingOrder); //staticTreeWidget->resizeColumnToContents(0); //staticTreeWidget->resizeColumnToContents(1); staticTreeWidget->resizeColumnToContents(2); staticTreeWidget->resizeColumnToContents(3); staticTreeWidget->resizeColumnToContents(4); staticTreeWidget->resizeColumnToContents(5); if (staticNameSearchLineEdit->text() != "" || staticTypeSearchLineEdit->text() != "") { emit refreshVariableList(_id, staticNameSearchLineEdit->text(), staticTypeSearchLineEdit->text()); } } void SeerStaticBrowserWidget::refresh () { handleSearchLineEdit(); } epasveer-seer-97076f1/src/SeerStaticBrowserWidget.h000066400000000000000000000023311526321767600223010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerStaticBrowserWidget.h" class SeerStaticBrowserWidget : public QWidget, protected Ui::SeerStaticBrowserWidgetForm { Q_OBJECT public: explicit SeerStaticBrowserWidget (QWidget* parent = 0); ~SeerStaticBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (); void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshVariableList (int id, const QString& staticNameRegex, const QString& staticTypeRegex); void selectedFile (QString file, QString fullname, int lineno); protected: private: int _id; }; epasveer-seer-97076f1/src/SeerStaticBrowserWidget.ui000066400000000000000000000047321526321767600224760ustar00rootroot00000000000000 SeerStaticBrowserWidgetForm 0 0 730 698 Static Browser Search for static variable names. "*" is allowed. Static names true Search for static variable types. "*" is allowed. Static types true 6 Variable Type File Line Full Name Description QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
epasveer-seer-97076f1/src/SeerStructVisualizerWidget.cpp000066400000000000000000000412331526321767600234070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerStructVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include SeerStructVisualizerWidget::SeerStructVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _variableId = Seer::createID(); // Create id for queries. // Set up UI. setupUi(this); // Setup the widgets setWindowTitle("Seer BasicStruct Visualizer"); setAttribute(Qt::WA_DeleteOnClose); variableTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); variableTreeWidget->setMouseTracking(true); variableTreeWidget->setSortingEnabled(false); variableTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); variableTreeWidget->setRootIsDecorated(true); variableTreeWidget->setItemsExpandable(true); variableTreeWidget->resizeColumnToContents(0); // name variableTreeWidget->resizeColumnToContents(1); // value variableTreeWidget->clear(); // Connect things. QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerStructVisualizerWidget::handleRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerStructVisualizerWidget::handleHelpButton); QObject::connect(variableNameLineEdit, &QLineEdit::returnPressed, this, &SeerStructVisualizerWidget::handleVariableNameLineEdit); QObject::connect(variableTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerStructVisualizerWidget::handleContextMenu); QObject::connect(variableTreeWidget, &QTreeWidget::itemEntered, this, &SeerStructVisualizerWidget::handleItemEntered); QObject::connect(variableTreeWidget, &QTreeWidget::itemExpanded, this, &SeerStructVisualizerWidget::handleItemExpanded); QObject::connect(variableTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerStructVisualizerWidget::handleItemExpanded); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerStructVisualizerWidget::handleThemeChanged); #endif // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); // Restore window settings. readSettings(); } SeerStructVisualizerWidget::~SeerStructVisualizerWidget () { } void SeerStructVisualizerWidget::setVariableName (const QString& name) { setWindowTitle("Seer BasicStruct Visualizer - '" + name + "'"); variableNameLineEdit->setText(name); // Create the initial variable in the tree. variableTreeWidget->clear(); if (variableNameLineEdit->text() != "") { QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, name); item->setText(1, ""); variableTreeWidget->addTopLevelItem(item); } // Resize columns. variableTreeWidget->resizeColumnToContents(0); variableTreeWidget->resizeColumnToContents(1); // Send signal to get variable result. if (variableNameLineEdit->text() != "") { emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); } } QString SeerStructVisualizerWidget::variableName () const { return variableNameLineEdit->text(); } void SeerStructVisualizerWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { QString id_text = text.section('^', 0,0); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); if (id_text.toInt() == _variableId) { QTreeWidgetItem* topItem = variableTreeWidget->topLevelItem(0); if (topItem == 0) { return; } // Delete all subitems of the toplevel item. foreach (auto item, topItem->takeChildren()) delete item; // Populate the tree. handleItemCreate(topItem, value_text); // Expand everything if there are children. if (topItem->childCount() > 0) { variableTreeWidget->expandAll(); } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { QString id_text = text.section('^', 0,0); QString msg_text = Seer::parseFirst(text, "msg=", '"', '"', false); if (id_text.toInt() == _variableId) { QTreeWidgetItem* topItem = variableTreeWidget->topLevelItem(0); if (topItem == 0) { return; } // Delete all subitems of the toplevel item. foreach (auto item, topItem->takeChildren()) delete item; // Set the error text. topItem->setText(1, Seer::filterEscapes(msg_text)); } }else if (text.startsWith("^error,msg=\"No registers.\"")) { variableTreeWidget->clear(); // At a stopping point, refresh. }else if (text.startsWith("*stopped,reason=\"")) { if (autoRefreshCheckBox->isChecked()) { handleRefreshButton(); } }else{ // Ignore anything else. } // Resize columns. variableTreeWidget->resizeColumnToContents(0); variableTreeWidget->resizeColumnToContents(1); // Set the cursor back. QApplication::restoreOverrideCursor(); } void SeerStructVisualizerWidget::handleItemCreate (QTreeWidgetItem* parentItem, const QString& value_text) { if (Seer::hasBookends(value_text, '{', '}')) { // Remove bookends QString text = Seer::filterBookends(value_text, '{', '}'); // Set the flatvalue text. parentItem->setText(1, Seer::filterEscapes(text)); // Convert to a list of name/value pairs. QStringList nv_pairs = Seer::parseCommaList(text, '{', '}'); // Go through each pair and add the name and its value to the tree. QTreeWidgetItem* prevItem = 0; for (const auto& nv : nv_pairs) { QStringPair pair = Seer::parseNameValue(nv, '='); // Handle "name = "xxxx", '\\000' , "yyyy" ..., age = 0, salary = 0" // There is a 'first' value but no 'second'. So just concatenate unto the previous item. if (pair.second == "") { if (prevItem) { prevItem->setText(0, prevItem->text(0) + pair.first); prevItem->setText(1, ""); } // Normal case of "name = value". }else{ QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, pair.first); item->setText(1, ""); parentItem->addChild(item); // Handle recursion if value has bookends. if (Seer::hasBookends(pair.second, '{', '}')) { handleItemCreate(item, pair.second); }else{ item->setText(1, Seer::filterEscapes(pair.second)); } prevItem = item; } } parentItem->setExpanded(true); }else{ parentItem->setText(1, Seer::filterEscapes(value_text)); } } void SeerStructVisualizerWidget::handleContextMenu (const QPoint& pos) { QTreeWidgetItem* item = variableTreeWidget->itemAt(pos); if (item == 0) { return; } // Create the variable name. // It's a struct so include its parent names. QString variable; while (item) { if (variable == "") { variable = item->text(0); }else{ variable = item->text(0) + "." + variable; } item = item->parent(); } // Create the menus. QAction* addMemoryVisualizerAction; QAction* addMemoryAsteriskVisualizerAction; QAction* addMemoryAmpersandVisualizerAction; QAction* addArrayVisualizerAction; QAction* addArrayAsteriskVisualizerAction; QAction* addArrayAmpersandVisualizerAction; QAction* addMatrixVisualizerAction; QAction* addMatrixAsteriskVisualizerAction; QAction* addMatrixAmpersandVisualizerAction; QAction* addStructVisualizerAction; QAction* addStructAsteriskVisualizerAction; QAction* addStructAmpersandVisualizerAction; addMemoryVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); addMemoryAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); addMemoryAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); addArrayVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); addArrayAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); addArrayAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); addMatrixVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); addMatrixAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); addMatrixAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); addStructVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); addStructAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); addStructAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); QMenu menu("Visualizers", this); menu.setTitle("Visualizers"); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to an Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); // Launch the menu. Get the response. QAction* action = menu.exec(variableTreeWidget->viewport()->mapToGlobal(pos)); // Do nothing. if (action == 0) { return; } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { //qDebug() << "addMemoryVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { //qDebug() << "addMemoryAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("*") + variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { //qDebug() << "addMemoryAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { //qDebug() << "addArrayVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { //qDebug() << "addArrayAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { //qDebug() << "addArrayAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addMatrixVisualizerAction) { //qDebug() << "addMatrixVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addMatrixAsteriskVisualizerAction) { //qDebug() << "addMatrixAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addMatrixAmpersandVisualizerAction) { //qDebug() << "addMatrixAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("&") + variable); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { //qDebug() << "addStructVisualizer" << variable; // Emit the signals. if (variable != "") { emit addStructVisualizer(variable); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { //qDebug() << "addStructAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("*") + variable); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { //qDebug() << "addStructAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("&") + variable); } return; } } void SeerStructVisualizerWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + item->text(1)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerStructVisualizerWidget::handleItemExpanded (QTreeWidgetItem* item) { Q_UNUSED(item); // Resize columns. variableTreeWidget->resizeColumnToContents(0); variableTreeWidget->resizeColumnToContents(1); } void SeerStructVisualizerWidget::handleRefreshButton () { if (variableNameLineEdit->text() == "") { return; } // Send signal to get variable result. emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); } void SeerStructVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/BasicStructVisualizer.md"); help->show(); help->raise(); } void SeerStructVisualizerWidget::handleVariableNameLineEdit () { if (variableNameLineEdit->text() == "") { return; } setVariableName (variableNameLineEdit->text()); } void SeerStructVisualizerWidget::handleThemeChanged () { // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); } void SeerStructVisualizerWidget::writeSettings () { QSettings settings; settings.beginGroup("structvisualizerwindow"); settings.setValue("size", size()); settings.endGroup(); } void SeerStructVisualizerWidget::readSettings () { QSettings settings; settings.beginGroup("structvisualizerwindow"); resize(settings.value("size", QSize(800, 400)).toSize()); settings.endGroup(); } void SeerStructVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } epasveer-seer-97076f1/src/SeerStructVisualizerWidget.h000066400000000000000000000041521526321767600230530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include "ui_SeerStructVisualizerWidget.h" class SeerStructVisualizerWidget : public QWidget, protected Ui::SeerStructVisualizerWidgetForm { Q_OBJECT public: explicit SeerStructVisualizerWidget (QWidget* parent = 0); ~SeerStructVisualizerWidget (); void setVariableName (const QString& name); QString variableName () const; signals: void evaluateVariableExpression (int expressionid, QString expression); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); public slots: void handleText (const QString& text); protected slots: void handleRefreshButton (); void handleHelpButton (); void handleVariableNameLineEdit (); void handleContextMenu (const QPoint& pos); void handleItemEntered (QTreeWidgetItem* item, int column); void handleItemExpanded (QTreeWidgetItem* item); void handleThemeChanged (); protected: void handleItemCreate (QTreeWidgetItem* parentItem, const QString& value_text); void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: int _variableId; }; epasveer-seer-97076f1/src/SeerStructVisualizerWidget.ui000066400000000000000000000063001526321767600232360ustar00rootroot00000000000000 SeerStructVisualizerWidgetForm 0 0 807 683 Form Enter a variable to visualize. Variable name true Qt::Vertical Refresh the display. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Automatically refresh after each stopping point. Auto Qt::Vertical Help on Struct Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Variable Value QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
epasveer-seer-97076f1/src/SeerThreadFramesBrowserWidget.cpp000066400000000000000000000275241526321767600237650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerThreadFramesBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerThreadFramesBrowserWidget::SeerThreadFramesBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets threadTreeWidget->setMouseTracking(true); threadTreeWidget->setSortingEnabled(false); threadTreeWidget->resizeColumnToContents(0); // active threadTreeWidget->resizeColumnToContents(1); // id threadTreeWidget->resizeColumnToContents(2); // state threadTreeWidget->resizeColumnToContents(3); // target-id threadTreeWidget->resizeColumnToContents(4); // func threadTreeWidget->resizeColumnToContents(5); // file threadTreeWidget->resizeColumnToContents(6); // line threadTreeWidget->resizeColumnToContents(7); // fullname threadTreeWidget->resizeColumnToContents(8); // args threadTreeWidget->resizeColumnToContents(9); // name threadTreeWidget->resizeColumnToContents(10); // level threadTreeWidget->resizeColumnToContents(11); // addr threadTreeWidget->resizeColumnToContents(12); // arch threadTreeWidget->resizeColumnToContents(13); // core threadTreeWidget->clear(); // Connect things. QObject::connect(threadTreeWidget, &QTreeWidget::itemClicked, this, &SeerThreadFramesBrowserWidget::handleItemClicked); QObject::connect(threadTreeWidget, &QTreeWidget::itemEntered, this, &SeerThreadFramesBrowserWidget::handleItemEntered); QObject::connect(gdbNextToolButton, &QToolButton::clicked, this, &SeerThreadFramesBrowserWidget::handleGdbNextToolButton); QObject::connect(gdbStepToolButton, &QToolButton::clicked, this, &SeerThreadFramesBrowserWidget::handleGdbStepToolButton); QObject::connect(gdbFinishToolButton, &QToolButton::clicked, this, &SeerThreadFramesBrowserWidget::handleGdbFinishToolButton); QObject::connect(gdbContinueToolButton, &QToolButton::clicked, this, &SeerThreadFramesBrowserWidget::handleGdbContinueToolButton); QObject::connect(gdbInterruptToolButton, &QToolButton::clicked, this, &SeerThreadFramesBrowserWidget::handleGdbInterruptToolButton); } SeerThreadFramesBrowserWidget::~SeerThreadFramesBrowserWidget () { } void SeerThreadFramesBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,threads=[")) { // // ^done,threads=[ // { // id=\"1\", // target-id=\"Thread 0x7ffff7fbd740 (LWP 22356)\", // name=\"hellothreads\", // thread={ // level=\"0\", // addr=\"0x00000000004006bf\", // func=\"main\", // args=[], // file=\"hellothreads.cpp\", // fullname=\"/home/erniep/Development/Peak/src/Seer/hellothreads/hellothreads.cpp\", // line=\"27\", // arch=\"i386:x86-64\" // }, // state=\"stopped\", // core=\"0\" // }, // // { // id=\"2\", // target-id=\"Thread 0x7ffff6ed1700 (LWP 22370)\", // details=\"Exiting\", // name=\"hellothreads\", // frame={ // level=\"0\", // addr=\"0x00007ffff6f0b1c3\", // func=\"__longjmp\", // args=[], // from=\"/lib64/libc.so.6\", // arch=\"i386:x86-64\" // }, // state=\"stopped\", // core=\"6\" // } // ], // current-thread-id=\"1\" // //qDebug() << text; threadTreeWidget->clear(); QString threads_text = Seer::parseFirst(text, "threads=", '[', ']', false); QString currentthreadid_text = Seer::parseFirst(text, "current-thread-id=", '"', '"', false); //qDebug() << threads_text; if (threads_text != "") { QStringList threads_list = Seer::parse(threads_text, "", '{', '}', false); for ( const auto& thread_text : threads_list ) { QString id_text = Seer::parseFirst(thread_text, "id=", '"', '"', false); QString targetid_text = Seer::parseFirst(thread_text, "target-id=", '"', '"', false); QString name_text = Seer::parseFirst(thread_text, "name=", '"', '"', false); QString frame_text = Seer::parseFirst(thread_text, "frame=", '{', '}', false); QString level_text = Seer::parseFirst(frame_text, "level=", '"', '"', false); QString addr_text = Seer::parseFirst(frame_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(frame_text, "func=", '"', '"', false); QString args_text = Seer::parseFirst(frame_text, "args=", '[', ']', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); QString arch_text = Seer::parseFirst(frame_text, "arch=", '"', '"', false); QString state_text = Seer::parseFirst(thread_text, "state=", '"', '"', false); QString core_text = Seer::parseFirst(thread_text, "core=", '"', '"', false); //qDebug() << file_text << fullname_text; // Create the item. QTreeWidgetItem* item = new QTreeWidgetItem; if (id_text == currentthreadid_text) { item->setText(0, "*"); }else{ item->setText(0, " "); } item->setText(1, id_text); item->setText(2, state_text); item->setText(3, targetid_text); item->setText(4, func_text); item->setText(5, QFileInfo(file_text).fileName()); item->setText(6, line_text); item->setText(7, fullname_text); item->setText(8, args_text); item->setText(9, name_text); item->setText(10, level_text); item->setText(11, addr_text); item->setText(12, arch_text); item->setText(13, core_text); // Add the frame to the tree. threadTreeWidget->addTopLevelItem(item); } // Select the current thread id. threadTreeWidget->clearSelection(); QList matches = threadTreeWidget->findItems(currentthreadid_text, Qt::MatchExactly, 1); if (matches.size() > 0) { threadTreeWidget->setCurrentItem(matches.first()); } } }else if (text.startsWith("*running,thread-id=")) { refresh(); }else if (text.startsWith("=thread-created,id=")) { // =thread-created,id="2",group-id="i2" refresh(); }else if (text.startsWith("=thread-exited,id=")) { // =thread-exited,id="2",group-id="i2" refresh(); }else{ // Ignore others. } threadTreeWidget->resizeColumnToContents(0); threadTreeWidget->resizeColumnToContents(1); threadTreeWidget->resizeColumnToContents(2); threadTreeWidget->resizeColumnToContents(3); //threadTreeWidget->resizeColumnToContents(4); // Don't resize. //threadTreeWidget->resizeColumnToContents(5); // Don't resize. threadTreeWidget->resizeColumnToContents(6); //threadTreeWidget->resizeColumnToContents(7); // Don't resize. //threadTreeWidget->resizeColumnToContents(8); // Don't resize. threadTreeWidget->resizeColumnToContents(9); threadTreeWidget->resizeColumnToContents(10); threadTreeWidget->resizeColumnToContents(11); threadTreeWidget->resizeColumnToContents(12); threadTreeWidget->resizeColumnToContents(13); QApplication::restoreOverrideCursor(); } void SeerThreadFramesBrowserWidget::handleStoppingPointReached () { refresh(); } void SeerThreadFramesBrowserWidget::handleSessionTerminated () { // Delete previous contents. threadTreeWidget->clear(); } void SeerThreadFramesBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshThreadIds(); emit refreshThreadFrames(); } void SeerThreadFramesBrowserWidget::handleItemClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); QList items = threadTreeWidget->selectedItems(); if (items.count() == 1) { int lineno = item->text(6).toInt(); // Select thread. emit selectedThread(item->text(1).toInt()); // Select file if we can. if (item->text(5) != "" && item->text(7) != "") { emit selectedFile(item->text(5), item->text(7), lineno); } // Select address if we can. if (item->text(11) != "") { emit maybeSelectedAddress(item->text(5), item->text(7), item->text(11)); } } } void SeerThreadFramesBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); //qDebug() << item->text(1) << column; item->setToolTip(0, item->text(1) + " : " + item->text(2) + " : " + item->text(3) + " : " + item->text(5) + " : " + item->text(6)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerThreadFramesBrowserWidget::handleGdbNextToolButton () { QList items = threadTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit nextThreadId(threadid); } } void SeerThreadFramesBrowserWidget::handleGdbStepToolButton () { QList items = threadTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit stepThreadId(threadid); } } void SeerThreadFramesBrowserWidget::handleGdbFinishToolButton () { QList items = threadTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit finishThreadId(threadid); } } void SeerThreadFramesBrowserWidget::handleGdbContinueToolButton () { QList items = threadTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit continueThreadId(threadid); } } void SeerThreadFramesBrowserWidget::handleGdbInterruptToolButton () { QList items = threadTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit interruptThreadId(threadid); } } void SeerThreadFramesBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } epasveer-seer-97076f1/src/SeerThreadFramesBrowserWidget.h000066400000000000000000000045231526321767600234240ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerThreadFramesBrowserWidget.h" class SeerThreadFramesBrowserWidget : public QWidget, protected Ui::SeerThreadFramesBrowserWidgetForm { Q_OBJECT public: explicit SeerThreadFramesBrowserWidget (QWidget* parent = 0); ~SeerThreadFramesBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); void handleGdbNextToolButton (); void handleGdbStepToolButton (); void handleGdbFinishToolButton (); void handleGdbContinueToolButton (); void handleGdbInterruptToolButton (); signals: void refreshThreadFrames (); void refreshThreadIds (); void selectedFile (QString file, QString fullname, int lineno); void selectedAddress (QString address); void maybeSelectedAddress (QString file, QString fullname, QString address); void selectedFrame (int frameno); void selectedThread (int threadid); void nextThreadId (int threadid); void stepThreadId (int threadid); void finishThreadId (int threadid); void continueThreadId (int threadid); void interruptThreadId (int threadid); protected: void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerThreadFramesBrowserWidget.ui000066400000000000000000000125201526321767600236060ustar00rootroot00000000000000 SeerThreadFramesBrowserWidgetForm 0 0 794 528 Form Execute the next line for selected threads. Step over functions. :/seer/resources/RelaxLightIcons/debug-step-over.svg:/seer/resources/RelaxLightIcons/debug-step-over.svg Execute the next line for selected threads. Step into functions. :/seer/resources/RelaxLightIcons/debug-step-into.svg:/seer/resources/RelaxLightIcons/debug-step-into.svg Finish the current function for selected threads. :/seer/resources/RelaxLightIcons/debug-step-out.svg:/seer/resources/RelaxLightIcons/debug-step-out.svg Continue execution of selected threads. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Interrupt execution of selected threads. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Qt::Horizontal 40 20 QAbstractItemView::ExtendedSelection 14 Active Thread Id State Target Id Function File Line Fullname Arguments Name Level Address Arch Core epasveer-seer-97076f1/src/SeerThreadGroupsBrowserWidget.cpp000066400000000000000000000152561526321767600240260ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerThreadGroupsBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerThreadGroupsBrowserWidget::SeerThreadGroupsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets groupTreeWidget->setMouseTracking(true); groupTreeWidget->setSortingEnabled(false); groupTreeWidget->resizeColumnToContents(0); // id groupTreeWidget->resizeColumnToContents(1); // type groupTreeWidget->resizeColumnToContents(2); // pid groupTreeWidget->resizeColumnToContents(3); // executable groupTreeWidget->resizeColumnToContents(4); // cores groupTreeWidget->clear(); // Connect things. QObject::connect(groupTreeWidget, &QTreeWidget::itemEntered, this, &SeerThreadGroupsBrowserWidget::handleItemEntered); QObject::connect(gdbRunToolButton, &QToolButton::clicked, this, &SeerThreadGroupsBrowserWidget::handleGdbRunToolButton); QObject::connect(gdbStartToolButton, &QToolButton::clicked, this, &SeerThreadGroupsBrowserWidget::handleGdbStartToolButton); QObject::connect(gdbContinueToolButton, &QToolButton::clicked, this, &SeerThreadGroupsBrowserWidget::handleGdbContinueToolButton); QObject::connect(gdbInterruptToolButton, &QToolButton::clicked, this, &SeerThreadGroupsBrowserWidget::handleGdbInterruptToolButton); } SeerThreadGroupsBrowserWidget::~SeerThreadGroupsBrowserWidget () { } void SeerThreadGroupsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,groups=[")) { // ^done,groups=[ // { // id="i1", // type="process", // pid="5424", // executable="/home/erniep/Development/Peak/src/seer/tests/helloinferior/helloinferior", // cores=["0"] // }, // { id="i2", // type="process", // pid="5432", // executable="/home/erniep/Development/Peak/src/seer/tests/helloinferior/helloinferior", // cores=["5"] // } // ] //qDebug() << text; groupTreeWidget->clear(); QString groups_text = Seer::parseFirst(text, "groups=", '[', ']', false); //qDebug() << groups_text; if (groups_text != "") { QStringList groups_list = Seer::parse(groups_text, "", '{', '}', false); for ( const auto& group_text : groups_list ) { QString id_text = Seer::parseFirst(group_text, "id=", '"', '"', false); QString type_text = Seer::parseFirst(group_text, "type=", '"', '"', false); QString pid_text = Seer::parseFirst(group_text, "pid=", '"', '"', false); QString exe_text = Seer::parseFirst(group_text, "executable=", '"', '"', false); QString cores_text = Seer::parseFirst(group_text, "cores=", '[', ']', false); // Create the item. QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, id_text); item->setText(1, type_text); item->setText(2, pid_text); item->setText(3, exe_text); item->setText(4, cores_text); // Add the frame to the tree. groupTreeWidget->addTopLevelItem(item); } } }else if (text.startsWith("=thread-created,id=")) { // =thread-created,id="2",group-id="i2" refresh(); }else if (text.startsWith("=thread-exited,id=")) { // =thread-exited,id="2",group-id="i2" refresh(); }else{ // Ignore others. } groupTreeWidget->resizeColumnToContents(0); groupTreeWidget->resizeColumnToContents(1); groupTreeWidget->resizeColumnToContents(2); //groupTreeWidget->resizeColumnToContents(3); // Don't resize. groupTreeWidget->resizeColumnToContents(4); QApplication::restoreOverrideCursor(); } void SeerThreadGroupsBrowserWidget::handleSessionTerminated () { // Delete previous contents. groupTreeWidget->clear(); } void SeerThreadGroupsBrowserWidget::refresh () { emit refreshThreadIds(); emit refreshThreadGroups(); } void SeerThreadGroupsBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); //qDebug() << item->text(0) << column; item->setToolTip(0, item->text(0) + " : " + item->text(1) + " : " + item->text(2) + " : " + item->text(3) + " : " + item->text(4)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerThreadGroupsBrowserWidget::handleGdbRunToolButton () { QList items = groupTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { QString groupid = (*i)->text(0); emit runThreadGroup(groupid); } } void SeerThreadGroupsBrowserWidget::handleGdbStartToolButton () { QList items = groupTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { QString groupid = (*i)->text(0); emit startThreadGroup(groupid); } } void SeerThreadGroupsBrowserWidget::handleGdbContinueToolButton () { QList items = groupTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { QString groupid = (*i)->text(0); emit continueThreadGroup(groupid); } } void SeerThreadGroupsBrowserWidget::handleGdbInterruptToolButton () { QList items = groupTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { QString groupid = (*i)->text(0); emit interruptThreadGroup(groupid); } } void SeerThreadGroupsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } epasveer-seer-97076f1/src/SeerThreadGroupsBrowserWidget.h000066400000000000000000000032031526321767600234600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerThreadGroupsBrowserWidget.h" class SeerThreadGroupsBrowserWidget : public QWidget, protected Ui::SeerThreadGroupsBrowserWidgetForm { Q_OBJECT public: explicit SeerThreadGroupsBrowserWidget (QWidget* parent = 0); ~SeerThreadGroupsBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleItemEntered (QTreeWidgetItem* item, int column); void handleGdbRunToolButton (); void handleGdbStartToolButton (); void handleGdbContinueToolButton (); void handleGdbInterruptToolButton (); signals: void refreshThreadGroups (); void refreshThreadIds (); void runThreadGroup (QString threadGroup); void startThreadGroup (QString threadGroup); void continueThreadGroup (QString threadGroup); void interruptThreadGroup (QString threadGroup); protected: void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerThreadGroupsBrowserWidget.ui000066400000000000000000000077741526321767600236670ustar00rootroot00000000000000 SeerThreadGroupsBrowserWidgetForm 0 0 794 528 Form false Run selected inferiors again. Do not break in "main". :/seer/resources/RelaxLightIcons/debug-run.svg:/seer/resources/RelaxLightIcons/debug-run.svg false Run selected inferiors again. Break in "main". :/seer/resources/RelaxLightIcons/debug-run.svg:/seer/resources/RelaxLightIcons/debug-run.svg Continue execution of selected inferiors. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Interrupt execution of selected inferiors. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Qt::Horizontal 40 20 QAbstractItemView::ExtendedSelection 5 Thread Group Id Type Pid Executable Cores epasveer-seer-97076f1/src/SeerThreadIdsBrowserWidget.cpp000066400000000000000000000143441526321767600232630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerThreadIdsBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include SeerThreadIdsBrowserWidget::SeerThreadIdsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets idsTreeWidget->setSortingEnabled(false); idsTreeWidget->resizeColumnToContents(0); // state idsTreeWidget->resizeColumnToContents(1); // id idsTreeWidget->clear(); // Connect things. QObject::connect(idsTreeWidget, &QTreeWidget::itemClicked, this, &SeerThreadIdsBrowserWidget::handleItemClicked); QObject::connect(gdbNextToolButton, &QToolButton::clicked, this, &SeerThreadIdsBrowserWidget::handleGdbNextToolButton); QObject::connect(gdbStepToolButton, &QToolButton::clicked, this, &SeerThreadIdsBrowserWidget::handleGdbStepToolButton); QObject::connect(gdbFinishToolButton, &QToolButton::clicked, this, &SeerThreadIdsBrowserWidget::handleGdbFinishToolButton); QObject::connect(gdbContinueToolButton, &QToolButton::clicked, this, &SeerThreadIdsBrowserWidget::handleGdbContinueToolButton); QObject::connect(gdbInterruptToolButton, &QToolButton::clicked, this, &SeerThreadIdsBrowserWidget::handleGdbInterruptToolButton); } SeerThreadIdsBrowserWidget::~SeerThreadIdsBrowserWidget () { } void SeerThreadIdsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,thread-ids={")) { QString newtext = Seer::filterEscapes(text); // Filter escaped characters. // ^done,thread-ids={ // thread-id=\"1\", // thread-id=\"2\" // }, // current-thread-id=\"1\", // number-of-threads=\"2\" idsTreeWidget->clear(); QString threadids_text = Seer::parseFirst(newtext, "thread-ids=", '{', '}', false); QStringList threadids_list = Seer::parse(threadids_text, "thread-id=", '"', '"', false); QString currentthreadid_text = Seer::parseFirst(newtext, "current-thread-id=", '"', '"', false); // Add the thread-ids. for ( const auto& threadid_text : threadids_list ) { //qDebug() << threadid_text; // Construct the item QTreeWidgetItem* item = new QTreeWidgetItem; if (threadid_text == currentthreadid_text) { item->setText(0, "*"); }else{ item->setText(0, " "); } item->setText(1, threadid_text); // Set the text to bold if the ID is the same as the CURRENT ID. QFont fnormal = item->font(0); fnormal.setBold(false); QFont fbold = item->font(0); fbold.setBold(true); if (threadid_text == currentthreadid_text) { item->setFont(0, fbold); item->setFont(1, fbold); }else{ item->setFont(0, fnormal); item->setFont(1, fnormal); } // Add the frame to the tree. idsTreeWidget->addTopLevelItem(item); } // Clear the selection and select the one for the current thread-id. idsTreeWidget->clearSelection(); QList matches = idsTreeWidget->findItems(currentthreadid_text, Qt::MatchExactly, 1); if (matches.size() > 0) { idsTreeWidget->setCurrentItem(matches.first()); } }else{ // Ignore others. } idsTreeWidget->resizeColumnToContents(0); idsTreeWidget->resizeColumnToContents(1); QApplication::restoreOverrideCursor(); } void SeerThreadIdsBrowserWidget::handleStoppingPointReached () { refresh(); } void SeerThreadIdsBrowserWidget::handleSessionTerminated () { // Delete previous contents. idsTreeWidget->clear(); } void SeerThreadIdsBrowserWidget::handleItemClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedThread(item->text(1).toInt()); } void SeerThreadIdsBrowserWidget::refresh () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshThreadIds(); } void SeerThreadIdsBrowserWidget::handleGdbNextToolButton () { QList items = idsTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit nextThreadId(threadid); } } void SeerThreadIdsBrowserWidget::handleGdbStepToolButton () { QList items = idsTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit stepThreadId(threadid); } } void SeerThreadIdsBrowserWidget::handleGdbFinishToolButton () { QList items = idsTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit finishThreadId(threadid); } } void SeerThreadIdsBrowserWidget::handleGdbContinueToolButton () { QList items = idsTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit continueThreadId(threadid); } } void SeerThreadIdsBrowserWidget::handleGdbInterruptToolButton () { QList items = idsTreeWidget->selectedItems(); QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { int threadid = (*i)->text(1).toInt(); emit interruptThreadId(threadid); } } void SeerThreadIdsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } epasveer-seer-97076f1/src/SeerThreadIdsBrowserWidget.h000066400000000000000000000034601526321767600227250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerThreadIdsBrowserWidget.h" class SeerThreadIdsBrowserWidget : public QWidget, protected Ui::SeerThreadIdsBrowserWidgetForm { Q_OBJECT public: explicit SeerThreadIdsBrowserWidget (QWidget* parent = 0); ~SeerThreadIdsBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); protected slots: void handleItemClicked (QTreeWidgetItem* item, int column); void handleGdbNextToolButton (); void handleGdbStepToolButton (); void handleGdbFinishToolButton (); void handleGdbContinueToolButton (); void handleGdbInterruptToolButton (); signals: void refreshThreadIds (); void selectedThread (int threadid); void nextThreadId (int threadid); void stepThreadId (int threadid); void finishThreadId (int threadid); void continueThreadId (int threadid); void interruptThreadId (int threadid); protected: void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerThreadIdsBrowserWidget.ui000066400000000000000000000077251526321767600231230ustar00rootroot00000000000000 SeerThreadIdsBrowserWidgetForm 0 0 794 528 Form Execute the next line for selected threads. Step over functions. :/seer/resources/RelaxLightIcons/debug-step-over.svg:/seer/resources/RelaxLightIcons/debug-step-over.svg Execute the next line for selected threads. Step into functions. :/seer/resources/RelaxLightIcons/debug-step-into.svg:/seer/resources/RelaxLightIcons/debug-step-into.svg Finish the current function for selected threads. :/seer/resources/RelaxLightIcons/debug-step-out.svg:/seer/resources/RelaxLightIcons/debug-step-out.svg Continue execution of selected threads. :/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg:/seer/resources/RelaxLightIcons/debug-execute-from-cursor.svg Interrupt execution of selected threads. :/seer/resources/thenounproject/stop.svg:/seer/resources/thenounproject/stop.svg Qt::Horizontal 40 20 2 Active Thread Id epasveer-seer-97076f1/src/SeerThreadManagerWidget.cpp000066400000000000000000000246021526321767600225500ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerThreadManagerWidget.h" #include "SeerHelpPageDialog.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include #include #include SeerThreadManagerWidget::SeerThreadManagerWidget (QWidget* parent) : QWidget(parent) { // Initialize private data // Setup UI setupUi(this); // Setup the widgets tabWidget->setMovable(true); tabWidget->setTabsClosable(false); _threadFramesBrowserWidget = new SeerThreadFramesBrowserWidget(this); _threadIdsBrowserWidget = new SeerThreadIdsBrowserWidget(this); _threadGroupsBrowserWidget = new SeerThreadGroupsBrowserWidget(this); _adaTasksBrowserWidget = new SeerAdaTasksBrowserWidget(this); tabWidget->addTab(_threadFramesBrowserWidget, "Frames"); tabWidget->addTab(_threadIdsBrowserWidget, "Ids"); tabWidget->addTab(_threadGroupsBrowserWidget, "Groups"); tabWidget->addTab(_adaTasksBrowserWidget, "AdaTasks"); QToolButton* tabsContextMenuButton = new QToolButton(tabWidget); tabsContextMenuButton->setIcon(QIcon(":/seer/resources/thenounproject/preferences.svg")); tabsContextMenuButton->setToolTip("Show/Hide tabs."); tabsContextMenuButton->setContextMenuPolicy(Qt::CustomContextMenu); QToolButton* refreshToolButton = new QToolButton(tabWidget); refreshToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/view-refresh.svg")); refreshToolButton->setToolTip("Refresh the thread information."); QToolButton* helpToolButton = new QToolButton(tabWidget); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on thread information."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(tabsContextMenuButton); hcontainer->addWidget(refreshToolButton); hcontainer->addWidget(helpToolButton); tabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Restore tab ordering. readSettings(); // Connect things. QObject::connect(tabsContextMenuButton, &QToolButton::clicked, this, &SeerThreadManagerWidget::handleTabsContextMenuButtonClicked); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerThreadManagerWidget::handleRefreshToolButtonClicked); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerThreadManagerWidget::handleHelpToolButtonClicked); QObject::connect(schedulerLockingComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerThreadManagerWidget::handleSchedulerLockingComboBox); QObject::connect(scheduleMultipleComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerThreadManagerWidget::handleScheduleMultipleComboBox); QObject::connect(forkFollowsComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerThreadManagerWidget::handleForkFollowComboBox); QObject::connect(tabWidget->tabBar(), &QTabBar::tabMoved, this, &SeerThreadManagerWidget::handleTabMoved); QObject::connect(tabWidget->tabBar(), &QTabBar::currentChanged, this, &SeerThreadManagerWidget::handleTabChanged); } SeerThreadManagerWidget::~SeerThreadManagerWidget () { } SeerThreadFramesBrowserWidget* SeerThreadManagerWidget::threadFramesBrowserWidget () { return _threadFramesBrowserWidget; } SeerThreadIdsBrowserWidget* SeerThreadManagerWidget::threadIdsBrowserWidget () { return _threadIdsBrowserWidget; } SeerThreadGroupsBrowserWidget* SeerThreadManagerWidget::threadGroupsBrowserWidget () { return _threadGroupsBrowserWidget; } SeerAdaTasksBrowserWidget* SeerThreadManagerWidget::adaTasksBrowserWidget () { return _adaTasksBrowserWidget; } void SeerThreadManagerWidget::setSchedulerLockingMode (const QString& mode) { schedulerLockingComboBox->setCurrentText(mode); } QString SeerThreadManagerWidget::schedulerLockingMode () const { return schedulerLockingComboBox->currentText(); } void SeerThreadManagerWidget::setScheduleMultipleMode (const QString& mode) { scheduleMultipleComboBox->setCurrentText(mode); } QString SeerThreadManagerWidget::scheduleMultipleMode () const { return scheduleMultipleComboBox->currentText(); } void SeerThreadManagerWidget::setForkFollowsMode (const QString& mode) { forkFollowsComboBox->setCurrentText(mode); } QString SeerThreadManagerWidget::forkFollowsMode () const { return forkFollowsComboBox->currentText(); } void SeerThreadManagerWidget::handleRefreshToolButtonClicked () { threadFramesBrowserWidget()->refresh(); threadIdsBrowserWidget()->refresh(); threadGroupsBrowserWidget()->refresh(); adaTasksBrowserWidget()->refresh(); } void SeerThreadManagerWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/ThreadProcessInfoBrowser.md"); help->show(); help->raise(); } void SeerThreadManagerWidget::handleSchedulerLockingComboBox (int index) { Q_UNUSED(index); emit schedulerLockingModeChanged(schedulerLockingComboBox->currentText()); } void SeerThreadManagerWidget::handleScheduleMultipleComboBox (int index) { Q_UNUSED(index); emit scheduleMultipleModeChanged(scheduleMultipleComboBox->currentText()); } void SeerThreadManagerWidget::handleForkFollowComboBox (int index) { Q_UNUSED(index); emit forkFollowsModeChanged(forkFollowsComboBox->currentText()); } void SeerThreadManagerWidget::handleTabMoved (int from, int to) { Q_UNUSED(from); Q_UNUSED(to); writeSettings(); } void SeerThreadManagerWidget::handleTabChanged (int index) { Q_UNUSED(index); writeSettings(); } void SeerThreadManagerWidget::writeSettings () { // Build up visible list. QStringList visible; for (int i=0; itabBar()->count(); i++) { visible.append(tabWidget->isTabVisible(i) ? "true" : "false"); } // Build up tab order. QStringList tabs; for (int i=0; itabBar()->count(); i++) { tabs.append(tabWidget->tabBar()->tabText(i)); } // Build up current tab. QString current = tabWidget->tabBar()->tabText(tabWidget->tabBar()->currentIndex()); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; QSettings settings; settings.beginGroup("threadmanagerwindow"); { settings.setValue("taborder", tabs.join(',')); settings.setValue("tabvisible", visible.join(',')); settings.setValue("tabcurrent", current); } settings.endGroup(); } void SeerThreadManagerWidget::readSettings () { // Can't move things? if (tabWidget->tabBar()->isMovable() == false) { return; } // Read tab order from settings. QSettings settings; QStringList tabs; QStringList visible; QString current; settings.beginGroup("threadmanagerwindow"); { tabs = settings.value("taborder").toString().split(','); visible = settings.value("tabvisible").toString().split(','); current = settings.value("tabcurrent").toString(); } settings.endGroup(); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Move tabs to the requested order. for (int i=0; itabBar()->count(); j++) { if (tabWidget->tabBar()->tabText(j) == tab) { tb = j; break; } } if (tb != -1) { tabWidget->tabBar()->moveTab(tb, i); } } // Show/Hide tabs. for (int i=0; isetTabVisible(i,true); }else if (flag == "false") { tabWidget->setTabVisible(i,false); }else{ tabWidget->setTabVisible(i,true); } } // Make a tab current. if (current != "") { for (int i=0; itabBar()->count(); i++) { if (tabWidget->tabBar()->tabText(i) == current) { tabWidget->setCurrentIndex(i); break; } } }else{ tabWidget->setCurrentIndex(0); } } void SeerThreadManagerWidget::handleTabsContextMenuButtonClicked() { // Build the menu and execute it. QMenu contextMenu; QWidget* container = new QWidget(&contextMenu); QVBoxLayout* layout = new QVBoxLayout(container); for (int i = 0; i < tabWidget->count(); i++) { QString title = tabWidget->tabText(i); QCheckBox* showTabCheckBox = new QCheckBox(title, container); showTabCheckBox->setChecked(tabWidget->isTabVisible(i)); layout->addWidget(showTabCheckBox); QObject::connect(showTabCheckBox, &QCheckBox::toggled, [this, showTabCheckBox, i](bool checked) { // Count visible tabs. int count=0; for (int x=0; xcount(); x++) { if (tabWidget->isTabVisible(x)) { count++; } } // Adjust the count. The 'checked' is made before the UI is updated. if (checked == true) { count++; }else{ count--; } // Reset the checkbox UI if the last visible tab was clicked. if (checked == false and count == 0) { showTabCheckBox->setChecked(true); // Don't hide last visible tab. }else if (checked == false and count > 1) { tabWidget->setTabVisible(i, checked); // Always show tabs when asked. }else{ tabWidget->setTabVisible(i, checked); } writeSettings(); }); } container->setLayout(layout); QWidgetAction* action = new QWidgetAction(&contextMenu); action->setDefaultWidget(container); contextMenu.addAction(action); contextMenu.exec(QCursor::pos()); } epasveer-seer-97076f1/src/SeerThreadManagerWidget.h000066400000000000000000000065031526321767600222150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerThreadFramesBrowserWidget.h" #include "SeerThreadIdsBrowserWidget.h" #include "SeerThreadGroupsBrowserWidget.h" #include "SeerAdaTasksBrowserWidget.h" #include #include "ui_SeerThreadManagerWidget.h" class SeerThreadManagerWidget : public QWidget, protected Ui::SeerThreadManagerWidgetForm { Q_OBJECT public: explicit SeerThreadManagerWidget (QWidget* parent = 0); ~SeerThreadManagerWidget (); SeerThreadFramesBrowserWidget* threadFramesBrowserWidget (); SeerThreadIdsBrowserWidget* threadIdsBrowserWidget (); SeerThreadGroupsBrowserWidget* threadGroupsBrowserWidget (); SeerAdaTasksBrowserWidget* adaTasksBrowserWidget (); signals: void schedulerLockingModeChanged (const QString& mode); void scheduleMultipleModeChanged (const QString& mode); void forkFollowsModeChanged (const QString& mode); protected: void writeSettings (); void readSettings (); public slots: void setSchedulerLockingMode (const QString& mode); QString schedulerLockingMode () const; void setScheduleMultipleMode (const QString& mode); QString scheduleMultipleMode () const; void setForkFollowsMode (const QString& mode); QString forkFollowsMode () const; private slots: void handleRefreshToolButtonClicked (); void handleHelpToolButtonClicked (); void handleSchedulerLockingComboBox (int index); void handleScheduleMultipleComboBox (int index); void handleForkFollowComboBox (int index); void handleTabMoved (int from, int to); void handleTabChanged (int index); void handleTabsContextMenuButtonClicked (); private: SeerThreadFramesBrowserWidget* _threadFramesBrowserWidget; SeerThreadIdsBrowserWidget* _threadIdsBrowserWidget; SeerThreadGroupsBrowserWidget* _threadGroupsBrowserWidget; SeerAdaTasksBrowserWidget* _adaTasksBrowserWidget; }; epasveer-seer-97076f1/src/SeerThreadManagerWidget.ui000066400000000000000000000126751526321767600224120ustar00rootroot00000000000000 SeerThreadManagerWidgetForm 0 0 398 520 Form 0 0 0 0 3 font-weight: bold; Thread/Process Info Qt::PlainText -1 50 0 Scheduler locking: 50 0 Schedule multiple: Qt::Vertical 50 0 Fork follows: Qt::Horizontal QSizePolicy::Ignored 0 20 Set the scheduler locking mode. replay off on step Set the mode for allowing threads of multiple processes to be resumed when an execution command is issued. off on Set the debugger response to a program call of fork or vfork. parent child both Qt::Horizontal QSizePolicy::Ignored 0 20 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
epasveer-seer-97076f1/src/SeerTildeLogWidget.cpp000066400000000000000000000012631526321767600215470ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerTildeLogWidget.h" #include "SeerUtl.h" #include SeerTildeLogWidget::SeerTildeLogWidget (QWidget* parent) : SeerLogWidget(parent) { } SeerTildeLogWidget::~SeerTildeLogWidget () { } void SeerTildeLogWidget::processText (const QString& text) { QString str = text.mid(1); // Remove leading "~" if (str.front() == '"') { // Remove leading """ str = str.mid(1); } if (str.back() == '"') { // Remove trailing """ str.chop(1); } str = Seer::filterEscapes(str); textEdit->insertPlainText(str); } epasveer-seer-97076f1/src/SeerTildeLogWidget.h000066400000000000000000000006271526321767600212170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerLogWidget.h" class SeerTildeLogWidget : public SeerLogWidget { Q_OBJECT public: explicit SeerTildeLogWidget (QWidget* parent = 0); ~SeerTildeLogWidget (); void processText (const QString& text); }; epasveer-seer-97076f1/src/SeerTypeBrowserWidget.cpp000066400000000000000000000132771526321767600223410ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerTypeBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include SeerTypeBrowserWidget::SeerTypeBrowserWidget (QWidget* parent) : QWidget(parent) { // Set the state. _id = Seer::createID(); // Construct the UI. setupUi(this); // Setup the widgets typeSearchLineEdit->setPlaceholderText("Search regex..."); typeSearchLineEdit->setClearButtonEnabled(true); typeTreeWidget->setMouseTracking(true); //typeTreeWidget->resizeColumnToContents(0); typeTreeWidget->resizeColumnToContents(1); typeTreeWidget->resizeColumnToContents(2); typeTreeWidget->resizeColumnToContents(3); typeTreeWidget->clear(); typeTreeWidget->setSortingEnabled(false); // Connect things. QObject::connect(typeTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerTypeBrowserWidget::handleItemDoubleClicked); QObject::connect(typeTreeWidget, &QTreeWidget::itemEntered, this, &SeerTypeBrowserWidget::handleItemEntered); QObject::connect(typeSearchLineEdit, &QLineEdit::returnPressed, this, &SeerTypeBrowserWidget::handleSearchLineEdit); } SeerTypeBrowserWidget::~SeerTypeBrowserWidget () { } void SeerTypeBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith(QString::number(_id) + "^done,symbols={") && text.endsWith("}")) { typeTreeWidget->clear(); typeTreeWidget->setSortingEnabled(false); typeTreeWidget->sortByColumn(-1, Qt::AscendingOrder); // -symbol-info-types [--name name_regexp] // [--max-results limit] // // ^done,symbols={ // debug=[ // { // filename="/peak/rel/include/CnvLib.h",fullname="/home/erniep/Development/Peak/rel/include/CnvLib.h", // symbols=[ // { // line="8", // name="Cnv" // } // ] // }, // ... // ] // } QString debug_text = Seer::parseFirst(text, "debug=", '[', ']', false); QStringList filenames_list = Seer::parse(debug_text, "", '{', '}', false); for (const auto& filename_entry : filenames_list) { QString filename_text = Seer::parseFirst(filename_entry, "filename=", '"', '"', false); QString fullname_text = Seer::parseFirst(filename_entry, "fullname=", '"', '"', false); QString symbols_text = Seer::parseFirst(filename_entry, "symbols=", '[', ']', false); QStringList symbols_list = Seer::parse(symbols_text, "", '{', '}', false); for (const auto& symbol_entry : symbols_list) { QString line_text = Seer::parseFirst(symbol_entry, "line=", '"', '"', false); QString name_text = Seer::parseFirst(symbol_entry, "name=", '"', '"', false); // Skip type entries that have no line number. if (line_text == "") { continue; } // Add the type to the tree. QTreeWidgetItem* item = new QTreeWidgetItem; QFont f0 = item->font(0); f0.setBold(true); item->setFont(0,f0); item->setText(0, name_text); item->setText(1, filename_text); item->setText(2, line_text); item->setText(3, fullname_text); typeTreeWidget->addTopLevelItem(item); } } }else{ // Ignore others. } //typeTreeWidget->resizeColumnToContents(0); typeTreeWidget->resizeColumnToContents(1); typeTreeWidget->resizeColumnToContents(2); typeTreeWidget->resizeColumnToContents(3); typeTreeWidget->sortByColumn(0, Qt::AscendingOrder); typeTreeWidget->setSortingEnabled(true); QApplication::restoreOverrideCursor(); } void SeerTypeBrowserWidget::handleSessionTerminated () { // Delete previous contents. typeTreeWidget->clear(); } void SeerTypeBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); emit selectedFile(item->text(1), item->text(3), item->text(2).toInt()); } void SeerTypeBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); QString tip = QString("Type: %1\nFile: %2\nLine: %3\nFullname: %4").arg(item->text(0)).arg(item->text(1)).arg(item->text(2)).arg(item->text(3)); item->setToolTip(0, tip); for (int i=1; icolumnCount(); i++) { // Copy tooltip to the other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerTypeBrowserWidget::handleSearchLineEdit () { typeTreeWidget->clear(); typeTreeWidget->setSortingEnabled(false); typeTreeWidget->sortByColumn(-1, Qt::AscendingOrder); //typeTreeWidget->resizeColumnToContents(0); typeTreeWidget->resizeColumnToContents(1); typeTreeWidget->resizeColumnToContents(2); typeTreeWidget->resizeColumnToContents(3); if (typeSearchLineEdit->text() != "") { emit refreshTypeList(_id, typeSearchLineEdit->text()); } } void SeerTypeBrowserWidget::refresh () { handleSearchLineEdit(); } epasveer-seer-97076f1/src/SeerTypeBrowserWidget.h000066400000000000000000000022511526321767600217740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerTypeBrowserWidget.h" class SeerTypeBrowserWidget : public QWidget, protected Ui::SeerTypeBrowserWidgetForm { Q_OBJECT public: explicit SeerTypeBrowserWidget (QWidget* parent = 0); ~SeerTypeBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void refresh (); protected slots: void handleSearchLineEdit (); void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleItemEntered (QTreeWidgetItem* item, int column); signals: void refreshTypeList (int id, const QString& typeRegex); void selectedFile (QString file, QString fullname, int lineno); protected: private: int _id; }; epasveer-seer-97076f1/src/SeerTypeBrowserWidget.ui000066400000000000000000000031271526321767600221650ustar00rootroot00000000000000 SeerTypeBrowserWidgetForm 0 0 730 698 Type Browser 4 Type File Line Full Name Search in the list of types. "*" is allowed. QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
epasveer-seer-97076f1/src/SeerUtl.cpp000066400000000000000000001372601526321767600174530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include #include #include #include // Comment out for now. I don't want to include boost because // that would impact people try to compile Seer. Qt6 offer // a 'stacktrace' function. OpenSuse may be slow in adoption. // For now, comment it out and use when needed. // #include #include #include // // Increment this with every release on GitHub. // See scripts/change_versionnumber // #define SEER_VERSION "2.8.1" namespace Seer { QString version () { return SEER_VERSION + QString(" (Qt") + QT_VERSION_STR + ")"; } QString filterBareNewLines (const QString& str) { // Remove bare (not inside quotes) '\n' substrings. // Maybe extra spaces after '\n'. // "{\n B = 1,\n C = 0,\n D = \"asd\",\n E = std::vector of length 1, capacity 64 = {true}\n}" // "{B = 1, C = 0, D = \"asd\", E = std::vector of length 1, capacity 64 = {true}}" QString tmp; qsizetype anchor=0; qsizetype curr=0; qsizetype end=str.length(); // Loop through string a character at a time. while (curr < end) { // Found a '\n' substring. Deal with it. if (str.mid(curr,2) == "\\n") { // Append the good bits before the '\n'. tmp.append(str.mid(anchor,curr-anchor)); curr += 2; // Skip trailing spaces, if any, after '\n'. while (curr < end) { if (str.at(curr) == ' ') { curr++; }else{ break; } } anchor = curr; // Other character. Skip it. }else{ curr++; } } // Anything left to deal with? if (curr > anchor) { tmp.append(str.mid(anchor,curr-anchor)); anchor = curr; } return tmp; } QString filterEscapes (const QString& str) { // Remove one level of '\'. // value="\"'Treasure' by Lucillius\\n\\n\\tbut theirs.\\n\"" QString tmp; bool escaped = false; for (int i=0; i 0) { r.remove(i, len); r.insert(i, value); }else{ f = false; // Not expanded. break; } } while (true) { QRegularExpressionMatch match = env_re2.match(r); if (match.hasMatch() == false) { break; } qsizetype i = match.capturedStart(); qsizetype len = match.capturedLength(); QString capstr = match.captured(); QString envstr = capstr.mid(1,capstr.length()-1); QByteArray value(qgetenv(envstr.toLatin1().data())); if (value.size() > 0) { r.remove(i, len); r.insert(i, value); }else{ f = false; // Not expanded. break; } } if (ok) { *ok = f; } return r; } QStringList parse (const QString& str, const QString& search, QChar startBracket, QChar endBracket, bool includeSearchString) { // // str = "^done,stack-args=[frame={level=\"0\",args=[{name=\"message\",value=\"\\\"Hello, World!\\\"\"}]},frame={level=\"1\",args=[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\"0x7fffffffd5b8\"}]}]" // search = "frame=" // startBracket = '{' // endBracket = '}' // QStringList list; QString searchWord = search + startBracket; // 'frame={' int from = 0; while (1) { // Look for the next occurance of the search word. int index = str.indexOf(searchWord,from); if (index < 0) { // If not found, we're done. break; } // Set things up to look for the matching end bracket. int start = index + search.size() + 1; // Positioned after 'frame={' int end = start + 1; int bracketLevel = 1; // Start with one start bracket already encountered. for (end=start; end= 0) { if (str[end-1] == '\\') { escaped = true; } } if (startBracket != endBracket) { // Do this test if brackets are not the same character. if (str[end] == startBracket && escaped == false) { // Encountered another start bracket, increment the level. bracketLevel++; } } if (str[end] == endBracket && escaped == false) { // Encountered an end bracket, decrement the level. bracketLevel--; if (bracketLevel == 0) { // If the level is 0, we're done. break; } } } // Are things valid? if (bracketLevel != 0) { // No matching bracket. break; } if (end > str.size()) { // The end is past the end of the string. break; } // Build the string. QString tmp; if (includeSearchString) { tmp = search + startBracket + str.mid(start, end-start) + endBracket; }else{ tmp = str.mid(start, end-start); } // Add it to the list. list.append(tmp); // Go back for more from = end + 1; } // Return the list. return list; } QString parseFirst (const QString& str, const QString& search, QChar startBracket, QChar endBracket, bool includeSearchString) { QStringList list = Seer::parse(str, search, startBracket, endBracket, includeSearchString); if (list.size() == 0) { return QString(); } return list.front(); } QString parseFirst (const QString& str, const QString& search, bool includeSearchString) { QString match; // Look for the next occurance of the search word. int index = str.indexOf(search,0); if (index < 0) { // If not found, we're done. return match; } // Set things up to look for the matching end bracket. int start = index + search.size() + 0; // Position after 'msg=' int end = str.size(); if (includeSearchString) { match = search + str.mid(start, end-start); }else{ match = str.mid(start, end-start); } return match; } bool hasBookends (const QString& str, QChar startBracket, QChar endBracket) { if (str.startsWith(startBracket) && str.endsWith(endBracket)) { return true; } return false; } QString filterBookends (const QString& str, QChar startBracket, QChar endBracket) { // If the string starts with and ends with the bracket characters, then return // the text between the brackets. if (str.startsWith(startBracket) && str.endsWith(endBracket)) { return str.mid(1,str.size()-2); } // Otherwise, return the orginal string. return str; } QStringList filterBookends (const QStringList& strings, QChar startBracket, QChar endBracket) { QStringList list; // For a list of strings, remove the bookends, if possible. for (int i=0; i, \"hildTest 2000-", '0' , "1", '0' , "330324377377377177000000004", '0' , "test\", '000' , \"325377377\", child = {childId = -9864, childString = \"\"}} enum STATE{ START = 0, SCANNING = 1, FOUND = 2, IGNORE = 3, }; QStringList list; int index = 0; int start = 0; int end = 0; int previousComma= 0; STATE state = START; while (index < str.length()) { // Handle "=" if (str[index] == '=') { if (state == SCANNING) // looking for 2nd '=' { // state = FOUND; end = previousComma; QString field = str.mid(start, end-start); list.append(field.trimmed()); start = previousComma + 1; } if (state == START) // looking for 2nd '=' { state = SCANNING; } } if (str[index] == startBracket) { state = IGNORE; } if (str[index] == endBracket) { state = SCANNING; } if (str[index] == ',' && state != IGNORE) { previousComma = index; } // The last if (index == str.length() - 1) { QString field = str.mid(start, index); list.append(field.trimmed()); } index++; } return list; } // // Parse an array, turn it to QList // QStringList parseArray (const QString& parentName, const QString& str) { // Input: {age = 1, name = "1st_child"}, {age = 2, name = "2nd_child"} // Output: QStringList : parentName[0] = {age = 1, name = "1st_child"}, parentName[1] = {age = 1, name = "1st_child"} QStringList list; int index = 0; int cntStartBracket = 0; int cntEndBracket = 0; int start = 0; int cnt = 0; while (index < str.length()) { if (str[index] == '{') { if (cntStartBracket == cntEndBracket) start = index; cntStartBracket++; } if (str[index] == '}') { // Check to see if character after it is ",". Otherwise, it probably trash character. if (index + 1 < str.length()) { if (str[index + 1] == '}' || str[index + 1] == ',' || index + 1 == str.length() ) { cntEndBracket++; if (cntStartBracket == cntEndBracket) { QString field = str.mid(start, index + 1 - start); field = parentName + "[" + QString::number(cnt) + "] = " + field; list.append(field.trimmed()); cntStartBracket = 0; cntEndBracket = 0; cnt++; } } } else if (index + 1 == str.length()) { // The last element cntEndBracket++; if (cntStartBracket == cntEndBracket) { QString field = str.mid(start, index + 1 - start); field = parentName + "[" + QString::number(cnt) + "] = " + field; list.append(field.trimmed()); cntStartBracket = 0; cntEndBracket = 0; cnt++; } } } index ++; } return list; } QMap createKeyValueMap (const QStringList& list, QChar separator) { QMap map; for (const auto& i : list) { QStringPair pair = parseNameValue(i, separator); map[pair.first] = pair.second; } return map; } // // // QStringPair parseNameValue (const QString& str, QChar separator) { // name = "Pasveer, Ernie" // // pair.first = name // pair.second = "Pasveer, Ernie" // QStringPair pair; int index = 0; int state = 0; int start = 0; int end = 0; bool inquotes = false; while (index < str.length()) { // Handle start of field. if (state == 0) { // Start of field. start = index; end = index; state = 1; // Look for end of field (a command or eol). continue; } // Handle end of field. if (state == 1) { // Handle """ if (str[index] == '"') { if (inquotes == false) { inquotes = true; }else{ inquotes = false; } index++; continue; } // Handle "=" separator. if (str[index] == separator) { if (inquotes) { index++; continue; } // Extract the two fields. index is at the "=". end = index; QString one = str.mid(start, end-start); QString two = str.mid(end+1); pair = QStringPair(one.trimmed(),two.trimmed()); state = 0; // Look for the next field. break; } // Handle any other character. index++; continue; } qDebug() << "Bad state!"; index++; continue; } // Handle if no "=" separator. if (state == 1) { pair = QStringPair(str.trimmed(),QString()); } return pair; } // // Quote certain characters in a string. // // "hello" => \"hello\" // QString quoteChars (const QString& str, const QString& chars) { QString string; for (int i=0; i= 0x060000 QRegularExpression re = QRegularExpression::fromWildcard(pattern, Qt::CaseInsensitive, QRegularExpression::UnanchoredWildcardConversion); #else // With Qt5, 'wildcardToRegularExpression' needs a "/*" at the start of 'pattern' // if 'string' start with a "/". //if (string[0] == '/') { // if (pattern[0] != '/') { // pattern = "/*/" + pattern; // } //} // This pattern needs to be converted from a glob to a regex. // All '*' are replaced with '.*' // The pattern is terminated with a '$', if it doesn't have one. pattern.replace("*", ".*"); //if (string[0] != '/') { // if (pattern.back() != '$') { // pattern += '$'; // } //} // qDebug() << pattern << string; // QRegularExpression re = QRegularExpression(QRegularExpression::wildcardToRegularExpression(pattern)); QRegularExpression re = QRegularExpression(pattern); #endif if (re.match(string).hasMatch()) { return true; } } return false; } bool hasWildcards (const QString& str) { return (str.indexOf('*') >= 0) || (str.indexOf('?') >= 0); } QString elideText (const QString& str, Qt::TextElideMode mode, int length) { QString leftElide("... "); QString middleElide(" ... "); QString rightElide(" ..."); // The string is fine. Just return it. if (str.length() <= length) { return str; } // The string is too long but don't add elide. if (mode == Qt::ElideNone) { return str.left(length); } // The string is too long. Add elilde on the left. if (mode == Qt::ElideLeft) { return leftElide + str.right(length); } // The string is too long. Add elilde on the right. if (mode == Qt::ElideRight) { return str.left(length) + rightElide; } // The string is too long. Add elilde in the middle. if (mode == Qt::ElideMiddle) { int halve = length / 2; return str.left(halve) + middleElide + str.right(halve); } // Bad mode. Just return the string. return str; } // Split a string on words. Double "quoted strings" // act as one word. QStringList split (const QString& str) { QRegularExpression re("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'"); QStringList list; QRegularExpressionMatchIterator i = re.globalMatch(str); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString word; if (match.captured(2) != "") { word = match.captured(2); }else if (match.captured(1) != "") { word = match.captured(1); }else if (match.captured(0) != "") { word = match.captured(0); } if (word != "") { list << word; } } return list; } // // // static int Next_ID = 1; static std::mutex ID_mutex; int createID () { std::lock_guard guard(ID_mutex); int id = Next_ID; Next_ID++; return id; } unsigned char ebcdicToAscii (unsigned char byte) { static const unsigned char ebcdicToAsciiTable[256] = { 46, 46, 46, 46, 46, 46, 46, 46, // 0 46, 46, 46, 46, 46, 46, 46, 46, // 8 46, 46, 46, 46, 46, 46, 46, 46, // 16 46, 46, 46, 46, 46, 46, 46, 46, // 24 46, 46, 46, 46, 46, 46, 46, 46, // 32 46, 46, 46, 46, 46, 46, 46, 46, // 40 46, 46, 46, 46, 46, 46, 46, 46, // 48 46, 46, 46, 46, 46, 46, 46, 46, // 56 32, 46, 46, 46, 46, 46, 46, 46, // 64 46, 46, 91, 46, 60, 40, 43, 33, // 72 38, 46, 46, 46, 46, 46, 46, 46, // 80 46, 46, 33, 36, 42, 41, 59, 94, // 88 45, 47, 46, 46, 46, 46, 46, 46, // 96 46, 46, 124, 44, 37, 95, 62, 63, // 104 46, 46, 46, 46, 46, 46, 46, 46, // 112 46, 96, 58, 35, 64, 39, 61, 34, // 120 46, 97, 98, 99, 100, 101, 102, 103, // 128 104, 105, 46, 46, 46, 46, 46, 46, // 136 46, 106, 107, 108, 109, 110, 111, 112, // 144 113, 114, 46, 46, 46, 46, 46, 46, // 152 46, 126, 115, 116, 117, 118, 119, 120, // 160 121, 122, 46, 46, 46, 46, 46, 46, // 168 46, 46, 46, 46, 46, 46, 46, 46, // 176 46, 46, 46, 46, 46, 46, 46, 46, // 184 123, 65, 66, 67, 68, 69, 70, 71, // 192 72, 73, 46, 46, 46, 46, 46, 46, // 200 125, 74, 75, 76, 77, 78, 79, 80, // 208 81, 82, 46, 46, 46, 46, 46, 46, // 216 92, 46, 83, 84, 85, 86, 87, 88, // 224 89, 90, 46, 46, 46, 46, 46, 46, // 232 48, 49, 50, 51, 52, 53, 54, 55, // 240 56, 57, 46, 46, 46, 46, 46, 46 // 248 }; return ebcdicToAsciiTable[byte]; } unsigned char ucharToAscii (unsigned char byte) { static const unsigned char ucharToAsciiTable[256] = { 46, 46, 46, 46, 46, 46, 46, 46, // 0 46, 46, 46, 46, 46, 46, 46, 46, // 8 46, 46, 46, 46, 46, 46, 46, 46, // 16 46, 46, 46, 46, 46, 46, 46, 46, // 24 32, 33, 34, 35, 36, 37, 38, 39, // 32 40, 41, 42, 43, 44, 45, 46, 47, // 40 48, 49, 50, 51, 52, 53, 54, 55, // 48 56, 57, 58, 59, 60, 61, 62, 63, // 56 64, 65, 66, 67, 68, 69, 70, 71, // 64 72, 73, 74, 75, 76, 77, 78, 79, // 72 80, 81, 82, 83, 84, 85, 86, 87, // 80 88, 89, 90, 91, 92, 93, 94, 95, // 88 96, 97, 98, 99, 100, 101, 102, 103, // 96 104, 105, 106, 107, 108, 109, 110, 111, // 104 112, 113, 114, 115, 116, 117, 118, 119, // 112 120, 121, 122, 123, 124, 125, 126, 46, // 120 46, 46, 46, 46, 46, 46, 46, 46, // 128 46, 46, 46, 46, 46, 46, 46, 46, // 136 46, 46, 46, 46, 46, 46, 46, 46, // 144 46, 46, 46, 46, 46, 46, 46, 46, // 152 46, 46, 46, 46, 46, 46, 46, 46, // 160 46, 46, 46, 46, 46, 46, 46, 46, // 168 46, 46, 46, 46, 46, 46, 46, 46, // 176 46, 46, 46, 46, 46, 46, 46, 46, // 184 46, 46, 46, 46, 46, 46, 46, 46, // 192 46, 46, 46, 46, 46, 46, 46, 46, // 200 46, 46, 46, 46, 46, 46, 46, 46, // 208 46, 46, 46, 46, 46, 46, 46, 46, // 216 46, 46, 46, 46, 46, 46, 46, 46, // 224 46, 46, 46, 46, 46, 46, 46, 46, // 232 46, 46, 46, 46, 46, 46, 46, 46, // 240 46, 46, 46, 46, 46, 46, 46, 46 // 248 }; return ucharToAsciiTable[byte]; } QString ucharToHex (const QVector& bytes, int from, int count) { QString str; str.reserve(count*2+4); for (int i=from; i= bytes.size()) { break; } quint8 decimal = bytes[i]; QString hex = QString("%1").arg(decimal, 2, 16, QLatin1Char('0')); str += hex; } return str; } QString ucharToOctal (const QVector& bytes, int from, int count) { QString str; str.reserve(count*3+4); for (int i=from; i= bytes.size()) { break; } quint8 decimal = bytes[i]; QString octal = QString("%1").arg(decimal, 3, 8, QLatin1Char('0')); str += octal; } return str; } QString ucharToAscii (const QVector& bytes, int from, int count) { QString str; str.reserve(count); for (int i=from; i= bytes.size()) { break; } quint8 decimal = bytes[i]; QString ascii = QChar(Seer::ucharToAscii(decimal)); str += ascii; } return str; } QString ucharToUShort (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } quint16 decimal = *(quint16*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(quint16); } return str; } QString ucharToShort (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } qint16 decimal = *(qint16*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(qint16); } return str; } QString ucharToUInt (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } quint32 decimal = *(quint32*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(quint32); } return str; } QString ucharToInt (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } qint32 decimal = *(qint32*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(qint32); } return str; } QString ucharToULong (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } quint64 decimal = *(quint64*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(quint64); } return str; } QString ucharToLong (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } qint64 decimal = *(qint64*)(bytes.data()+from); QString val = QString("%1").arg(decimal); if (i != 0) { str += " "; } str += val; from += sizeof(qint64); } return str; } QString ucharToFloat (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } float real = *(float*)(bytes.data()+from); QString val = QString("%1").arg(real); if (i != 0) { str += " "; } str += val; from += sizeof(float); } return str; } QString ucharToDouble (const QVector& bytes, int from, int count) { QString str; for (int i=0; i= bytes.size()) { break; } double real = *(double*)(bytes.data()+from); QString val = QString("%1").arg(real); if (i != 0) { str += " "; } str += val; from += sizeof(double); } return str; } int typeBytes (const QString& type) { if (type == "int8" || type == "uint8") { return 1; }else if (type == "int16" || type == "uint16") { return 2; }else if (type == "int32" || type == "uint32") { return 4; }else if (type == "int64" || type == "uint64") { return 8; }else if (type == "float32") { return 4; }else if (type == "float64") { return 8; }else{ qWarning() << "Bad data type:" << type; return 0; } } bool readFile (const QString& filename, QStringList& lines) { // Empty the list lines = QStringList(); // Open the file. QFile file(filename); if (file.open(QIODevice::ReadOnly) == false) { qDebug() << "Can't open:" << filename; return false; } // Read the file line-by-line and build up the string list. while (file.atEnd() == false) { QString line = file.readLine(); line.chop(1); lines.append(line); } file.close(); // All good. return true; } QString unescape (const QString& str) { QString result; bool quoted = false; // Maybe reserve `str.length()` bytes in result, so that it will not allocate during `push_back()` result.reserve(str.length()); // Loop through each character in 'str'. Look for a '\'. for (int i=0; i= str.length()) { // Nope, just add it. result.push_back(str[i]); break; } // If the following character is another '\', skip the first one. // This removes one level of '\'. if (str[i+1] == QChar('\\')) { continue; } // Treat the following character as an escaped character. // Unescape it. (Is that even a word?) switch(str[i+1].unicode()) { // We don't want to unescape things that are in double quotes. // So keep track of that. (Not the more fool proof implementation). case QChar('\"').unicode(): result.push_back(QChar('\"')); if (quoted) { quoted = false; }else{ quoted = true; } break; case QChar('n').unicode(): if (quoted == false) { result.push_back(QChar('\n')); }else{ result.push_back(QChar('\\')); result.push_back(str[i+1]); } break; case QChar('\'').unicode(): if (quoted == false) { result.push_back(QChar('\'')); }else{ result.push_back(QChar('\\')); result.push_back(str[i+1]); } break; case QChar('\\').unicode(): if (quoted == false) { result.push_back(QChar('\\')); }else{ result.push_back(QChar('\\')); result.push_back(str[i+1]); } break; case QChar('t').unicode(): if (quoted == false) { result.push_back(QChar('\t')); }else{ result.push_back(QChar('\\')); result.push_back(str[i+1]); } break; // and so on for \a, \b, \e, \f, \r, \t, \v // maybe handle octal, hexadecimal ASCII and Unicode forms, but probably in the more distant future // ... default: // unknown escape sequence — do not escape it — I think it is reasonable default result.push_back(QChar('\\')); result.push_back(str[i+1]); break; } i++; // Normal character. Just add it. }else{ result.push_back(str[i]); } } return result; } void printStackTrace () { // Capture and print the stack trace using Boost.Stacktrace. // See comments at top. // std::cout << "Stack trace:\n" << boost::stacktrace::stacktrace() << std::endl; } // Check if directory and file exist, otherwise, raise a notification bool isFileExistNotify (const QString& filename) { if (QFile::exists(filename)) { return true; } else { QMessageBox::warning(nullptr, "Seer", QString("File %1 doesn't exist.").arg(filename), QMessageBox::Ok); return false; } } bool isDirExistNotify (const QString& dirname) { if (QDir(dirname).exists()) { return true; } else { QMessageBox::warning(nullptr, "Seer", QString("Directory %1 doesn't exist.").arg(dirname), QMessageBox::Ok); return false; } } // // Icon colorization. // static QString _iconColorTheme = "auto"; void setIconColorTheme (const QString& colorTheme) { if (colorTheme == "auto" || colorTheme == "dark" || colorTheme == "light") { _iconColorTheme = colorTheme; }else{ qDebug() << "Bad iconColorTheme of: " << colorTheme; } } const QString& iconColorTheme () { return _iconColorTheme; } void colorizeAllIcons (QWidget* parent, const QString& colorTheme, const QSize& size) { if (parent == nullptr) { return; } if (colorTheme == "auto") { #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) // Get the current color scheme Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); if (colorScheme == Qt::ColorScheme::Light) { return colorizeAllIcons(parent, "light"); }else if (colorScheme == Qt::ColorScheme::Dark) { return colorizeAllIcons(parent, "dark"); }else{ qDebug() << "Bad colorScheme of: " << colorScheme; } #endif return; }else if (colorTheme == "light") { // Look for all button types. const auto buttons = parent->findChildren(); for (QAbstractButton* button : buttons) { button->setIcon(Seer::colorizeIcon(button->icon(), QColor("black"), size)); } // Look for all menu types. const auto menus = parent->findChildren(); for (QMenu* menu : menus) { menu->setIcon(Seer::colorizeIcon(menu->icon(), QColor("black"), size)); } // Look for all action types. const auto actions = parent->findChildren(); for (QAction* action : actions) { action->setIcon(Seer::colorizeIcon(action->icon(), QColor("black"), size)); } // Look for the app's titlebar icon. // XXX Doesn't work! // XXX Titlebar icon remains the same. It doesn't change. Don't know why. QApplication::setWindowIcon(Seer::colorizeIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png"), QColor("black"), size)); return; }else if (colorTheme == "dark") { // Look for all button types. const auto buttons = parent->findChildren(); for (QAbstractButton* button : buttons) { button->setIcon(Seer::colorizeIcon(button->icon(), QColor("white"), size)); } // Look for all menu types. const auto menus = parent->findChildren(); for (QMenu* menu : menus) { menu->setIcon(Seer::colorizeIcon(menu->icon(), QColor("white"), size)); } // Look for all action types. const auto actions = parent->findChildren(); for (QAction* action : actions) { action->setIcon(Seer::colorizeIcon(action->icon(), QColor("white"), size)); } // Look for the app's titlebar icon. // XXX Doesn't work! // XXX Titlebar icon remains the same. It doesn't change. Don't know why. QApplication::setWindowIcon(Seer::colorizeIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png"), QColor("black"), size)); return; } qDebug() << "Bad iconColorTheme of: " << colorTheme; } void colorizeListWidgetItemIcon (QListWidgetItem* item, const QString& colorTheme, const QSize& size) { if (item == nullptr) { return; } if (colorTheme == "auto") { #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) // Get the current color scheme Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); if (colorScheme == Qt::ColorScheme::Light) { item->setIcon(Seer::colorizeIcon(item->icon(), QColor("black"), size)); }else if (colorScheme == Qt::ColorScheme::Dark) { item->setIcon(Seer::colorizeIcon(item->icon(), QColor("white"), size)); }else{ qDebug() << "Bad colorScheme of: " << colorScheme; } #endif return; }else if (colorTheme == "light") { item->setIcon(Seer::colorizeIcon(item->icon(), QColor("black"), size)); return; }else if (colorTheme == "dark") { item->setIcon(Seer::colorizeIcon(item->icon(), QColor("white"), size)); return; } qDebug() << "Bad iconColorTheme of: " << colorTheme; } void colorizeChartViewItem (QChartView* item, const QString& colorTheme) { if (item == nullptr) { return; } QChart* chart = item->chart(); if (chart == nullptr) { return; } if (colorTheme == "auto") { #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) // Get the current color scheme Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); if (colorScheme == Qt::ColorScheme::Light) { chart->setTheme(QChart::ChartThemeLight); }else if (colorScheme == Qt::ColorScheme::Dark) { chart->setTheme(QChart::ChartThemeDark); }else{ qDebug() << "Bad colorScheme of: " << colorScheme; } #endif return; }else if (colorTheme == "light") { chart->setTheme(QChart::ChartThemeLight); return; }else if (colorTheme == "dark") { chart->setTheme(QChart::ChartThemeDark); return; } qDebug() << "Bad iconColorTheme of: " << colorTheme; } QIcon colorizeIcon (const QIcon& icon, const QString& colorTheme, const QSize& size) { if (colorTheme == "auto") { #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) // Get the current color scheme Qt::ColorScheme colorScheme = QGuiApplication::styleHints()->colorScheme(); if (colorScheme == Qt::ColorScheme::Light) { return Seer::colorizeIcon(icon, QColor("black"), size); }else if (colorScheme == Qt::ColorScheme::Dark) { return Seer::colorizeIcon(icon, QColor("white"), size); }else{ qDebug() << "Bad colorScheme of: " << colorScheme; } #endif return icon; }else if (colorTheme == "light") { return Seer::colorizeIcon(icon, QColor("white"), size); }else if (colorTheme == "dark") { return Seer::colorizeIcon(icon, QColor("black"), size); } qDebug() << "Bad iconColorTheme of: " << colorTheme; return icon; } QIcon colorizeIcon (const QIcon& icon, const QColor& color, const QSize& size) { #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) // Get the pixmap from the icon QPixmap pixmap = icon.pixmap(size); // Create a new pixmap with the same size and format (preserves alpha) QPixmap coloredPixmap(pixmap.size()); coloredPixmap.fill(Qt::transparent); QPainter painter(&coloredPixmap); // Draw the original pixmap painter.drawPixmap(0, 0, pixmap); // Use CompositionMode_SourceIn to colorize while keeping alpha painter.setCompositionMode(QPainter::CompositionMode_SourceIn); painter.fillRect(coloredPixmap.rect(), color); painter.end(); return QIcon(coloredPixmap); #else Q_UNUSED(icon); Q_UNUSED(color); Q_UNUSED(size); return icon; #endif } } epasveer-seer-97076f1/src/SeerUtl.h000066400000000000000000000135631526321767600171170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "QStringPair.h" #include #include #include #include #include #include #include #include #include // 1. A helper macro that accepts an argument and stringifies it. #define STRINGIFY_HELPER(x) #x // 2. The main macro that forces expansion of 'x' before passing it to the helper. #define STRINGIFY(x) STRINGIFY_HELPER(x) namespace Seer { QString version (); QString filterBareNewLines (const QString& str); QString filterEscapes (const QString& str); QStringList filterEscapes (const QStringList& strings); QString expandTabs (const QString& str, int tabwidth, bool morph); QString expandEnv (const QString& str, bool* ok = nullptr); QStringList parse (const QString& str, const QString& search, QChar startBracket, QChar endBracket, bool includeSearch); QString parseFirst (const QString& str, const QString& search, QChar startBracket, QChar endBracket, bool includeSearch); QString parseFirst (const QString& str, const QString& search, bool includeSearch); bool hasBookends (const QString& str, QChar startBracket, QChar endBracket); QString filterBookends (const QString& str, QChar startBracket, QChar endBracket); QStringList filterBookends (const QStringList& strings, QChar startBracket, QChar endBracket); QStringList parseCommaList (const QString& str); QStringList parseCommaList (const QString& str, QChar startBracket, QChar endBracket); QStringList parseArray (const QString& parentName, const QString& str); QMap createKeyValueMap (const QStringList& list, QChar separator); QStringPair parseNameValue (const QString& str, QChar separator); QString quoteChars (const QString& str, const QString& chars); QStringList quoteChars (const QStringList& strings, const QString& chars); QString varObjParent (const QString& str); bool matchesWildcard (const QStringList& regexpatterns, const QString& string); bool hasWildcards (const QString& str); QString elideText (const QString& str, Qt::TextElideMode mode, int length); QStringList split (const QString& str); QString unescape (const QString& str); int createID (); unsigned char ebcdicToAscii (unsigned char byte); unsigned char ucharToAscii (unsigned char byte); QString ucharToHex (const QVector& bytes, int from, int count); QString ucharToOctal (const QVector& bytes, int from, int count); QString ucharToAscii (const QVector& bytes, int from, int count); QString ucharToUShort (const QVector& bytes, int from, int count); QString ucharToShort (const QVector& bytes, int from, int count); QString ucharToUInt (const QVector& bytes, int from, int count); QString ucharToInt (const QVector& bytes, int from, int count); QString ucharToULong (const QVector& bytes, int from, int count); QString ucharToLong (const QVector& bytes, int from, int count); QString ucharToFloat (const QVector& bytes, int from, int count); QString ucharToDouble (const QVector& bytes, int from, int count); int typeBytes (const QString& type); bool readFile (const QString& filename, QStringList& lines); void printStackTrace (); bool isFileExistNotify (const QString& filename); bool isDirExistNotify (const QString& dirname); void setIconColorTheme (const QString& colorTheme); const QString& iconColorTheme (); void colorizeAllIcons (QWidget* parent, const QString& colorTheme, const QSize& size = QSize(32,32)); void colorizeListWidgetItemIcon (QListWidgetItem* item, const QString& colorTheme, const QSize& size = QSize(32,32)); void colorizeChartViewItem (QChartView* item, const QString& colorTheme); QIcon colorizeIcon (const QIcon& icon, const QString& colorTheme, const QSize& size = QSize(32,32)); QIcon colorizeIcon (const QIcon& icon, const QColor& color, const QSize& size = QSize(32,32)); } epasveer-seer-97076f1/src/SeerVarVisualizerWidget.cpp000066400000000000000000001140531526321767600226540ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerVarVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include "QEditDelegate.h" #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) #include #include #endif #include #include #include #include #include SeerVarVisualizerWidget::SeerVarVisualizerWidget (QWidget* parent) : QWidget(parent) { // Init variables. _variableId = Seer::createID(); // Create id for queries. // Set up UI. setupUi(this); // Setup the widgets setWindowTitle("Seer Struct Visualizer"); setAttribute(Qt::WA_DeleteOnClose); variableNameLineEdit->setFocus(); variableTreeWidget->setMouseTracking(true); variableTreeWidget->setSortingEnabled(false); variableTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); variableTreeWidget->setRootIsDecorated(true); variableTreeWidget->setItemsExpandable(true); variableTreeWidget->resizeColumnToContents(0); // variable variableTreeWidget->resizeColumnToContents(1); // value variableTreeWidget->resizeColumnToContents(2); // type variableTreeWidget->resizeColumnToContents(3); // varobj name variableTreeWidget->resizeColumnToContents(4); // varobj id variableTreeWidget->resizeColumnToContents(5); // exp variableTreeWidget->resizeColumnToContents(6); // numchild variableTreeWidget->resizeColumnToContents(7); // thread-id variableTreeWidget->resizeColumnToContents(8); // has_more variableTreeWidget->resizeColumnToContents(9); // editable variableTreeWidget->clear(); // Show debug columns. debugCheckBox->setChecked(false); debugCheckBox->hide(); // Create edit delegate. // The value column will allow editing of the cell. However, some cells can then // individually disable it again. ie: If the cell is for a node, not a value. // See 'new QTreeWidgetItem' QAllowEditDelegate* editDelegate = new QAllowEditDelegate(this); variableTreeWidget->setItemDelegateForColumn(0, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(1, editDelegate); variableTreeWidget->setItemDelegateForColumn(2, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(3, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(4, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(5, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(6, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(7, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(8, new QNoEditDelegate(this)); variableTreeWidget->setItemDelegateForColumn(9, new QNoEditDelegate(this)); // Connect things. QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerVarVisualizerWidget::handleRefreshButton); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerVarVisualizerWidget::handleHelpButton); QObject::connect(debugCheckBox, &QCheckBox::clicked, this, &SeerVarVisualizerWidget::handleDebugCheckBox); QObject::connect(variableNameLineEdit, &QLineEdit::returnPressed, this, &SeerVarVisualizerWidget::handleVariableNameLineEdit); QObject::connect(variableTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerVarVisualizerWidget::handleContextMenu); QObject::connect(variableTreeWidget, &QTreeWidget::itemEntered, this, &SeerVarVisualizerWidget::handleItemEntered); QObject::connect(variableTreeWidget, &QTreeWidget::itemExpanded, this, &SeerVarVisualizerWidget::handleItemExpanded); QObject::connect(variableTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerVarVisualizerWidget::handleItemCollapsed); QObject::connect(expandSelectedToolButton, &QToolButton::clicked, this, &SeerVarVisualizerWidget::handleExpandSelected); QObject::connect(collapseSelectedToolButton, &QToolButton::clicked, this, &SeerVarVisualizerWidget::handleCollapseSelected); QObject::connect(editDelegate, &QAllowEditDelegate::editingStarted, this, &SeerVarVisualizerWidget::handleIndexEditingStarted); QObject::connect(editDelegate, &QAllowEditDelegate::editingFinished, this, &SeerVarVisualizerWidget::handleIndexEditingFinished); #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 3) QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &SeerVarVisualizerWidget::handleThemeChanged); #endif // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); // Show/hide columns. handleDebugCheckBox(); // Restore window settings. readSettings(); } SeerVarVisualizerWidget::~SeerVarVisualizerWidget () { // Send signal to delete variable. if (_variableName != "") { emit varObjDelete(_variableId, _variableName); } } void SeerVarVisualizerWidget::setVariableName (const QString& name) { setWindowTitle("Seer Struct Visualizer - '" + name + "'"); variableNameLineEdit->setText(name); // Send signal to delete old variable. if (_variableName != "") { emit varObjDelete(_variableId, _variableName); _variableName = ""; } // Create the initial variable in the tree. variableTreeWidget->clear(); if (variableNameLineEdit->text() != "") { QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, name); item->setText(1, ""); item->setText(2, ""); item->setText(3, ""); item->setText(4, ""); item->setText(5, ""); item->setText(6, ""); item->setText(7, ""); item->setText(8, ""); item->setText(9, ""); variableTreeWidget->addTopLevelItem(item); } // Resize columns. handleResizeColumns(); // Send signal to get variable result. if (variableNameLineEdit->text() != "") { emit varObjCreate(_variableId, variableNameLineEdit->text()); } } QString SeerVarVisualizerWidget::variableName () const { return variableNameLineEdit->text(); } void SeerVarVisualizerWidget::handleText (const QString& text) { if (text.contains(QRegularExpression("^([0-9]+)\\^done,name="))) { // // "-var-create x2112 "*" me" // // "4^done,name=\"seer4\",numchild=\"1\",value=\"{...}\",type=\"Person\",thread-id=\"1\",has_more=\"0\"" // -------------- // QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { //qDebug() << "var-create" << text; QString name_text = Seer::parseFirst(text, "name=", '"', '"', false); QString exp_text = Seer::parseFirst(text, "exp=", '"', '"', false); QString numchild_text = Seer::parseFirst(text, "numchild=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); QString type_text = Seer::parseFirst(text, "type=", '"', '"', false); QString threadid_text = Seer::parseFirst(text, "thread-id=", '"', '"', false); QString hasmore_text = Seer::parseFirst(text, "has_more=", '"', '"', false); QTreeWidgetItem* topItem = variableTreeWidget->topLevelItem(0); if (topItem == 0) { return; } int varObjID = Seer::createID(); // Create id for queries. topItem->setText(1, Seer::filterEscapes(value_text)); topItem->setText(2, type_text); topItem->setText(3, name_text); topItem->setText(4, QString::number(varObjID)); topItem->setText(5, exp_text); topItem->setText(6, numchild_text); topItem->setText(7, threadid_text); topItem->setText(8, hasmore_text); topItem->setText(9, ""); if (exp_text != "") { topItem->setText(0, exp_text); } //XXX Ask for its editable attributes. //XXX emit varObjAttributes (varObjID, name_text); // If there are children, add a placeholder. if (numchild_text != "0") { if (type_text.endsWith('*')) { if (Seer::filterEscapes(value_text) != "0x0") { // If it is a pointer that is not null, add a placeholder. How universal is this for other languages? QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, name_text); topItem->addChild(child); }else{ deleteItems(topItem->takeChildren()); } }else{ // A non-pointer child, add a placeholder. QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, name_text); topItem->addChild(child); } } // Save the VarObj name. _variableName = name_text; } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,numchild="))) { // // "-var-list-children --all-values x2112.public" // // "4^done,numchild="1", children=[ // ------------ // child={name="x2112.public",exp="public",numchild="4",thread-id="1"} // ], // has_more="0" // QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { //qDebug() << "var-list-children" << text; QString children_text = Seer::parseFirst(text, "children=", '[', ']', false); QStringList child_list = Seer::parse(children_text, "child=", '{', '}', false); QString hasmore_text = Seer::parseFirst(text, "has_more=", '"', '"', false); for (const auto& child_text : child_list) { QString name_text = Seer::parseFirst(child_text, "name=", '"', '"', false); QString exp_text = Seer::parseFirst(child_text, "exp=", '"', '"', false); QString numchild_text = Seer::parseFirst(child_text, "numchild=", '"', '"', false); QString value_text = Seer::parseFirst(child_text, "value=", '"', '"', false); QString type_text = Seer::parseFirst(child_text, "type=", '"', '"', false); QString threadid_text = Seer::parseFirst(child_text, "thread-id=", '"', '"', false); // Do we have an existing item to add to? QTreeWidgetItem* matchItem = findItem(Seer::varObjParent(name_text), Qt::MatchExactly|Qt::MatchRecursive, 3); // No, just add to the top level. if (matchItem == 0) { // This shouldn't really happen. qDebug() << name_text << "from the listchildren does not exist in the tree."; // Yes, add to it. }else{ // See if item has a "{...}" child. If so, remove it and any other siblings. if (matchItem->childCount() > 0) { QTreeWidgetItem* childItem = matchItem->child(0); if (childItem->text(0) == "{...}") { deleteItems(matchItem->takeChildren()); } } // Create the item. QTreeWidgetItem* item = new QTreeWidgetItem; int varObjID = Seer::createID(); // Create id for queries. item->setText(0, ""); item->setText(1, Seer::filterEscapes(value_text)); item->setText(2, type_text); item->setText(3, name_text); item->setText(4, QString::number(varObjID)); item->setText(5, exp_text); item->setText(6, numchild_text); item->setText(7, threadid_text); item->setText(8, hasmore_text); item->setText(9, ""); item->setFlags(item->flags() | Qt::ItemIsEditable); //XXX Set item editable if it can. if (exp_text != "") { item->setText(0, exp_text); } //XXX Ask for its editable attributes. //XXX emit varObjAttributes (varObjID, name_text); // If there are children, add a placeholder. bool expandItem = false; if (numchild_text != "0") { if (type_text.endsWith('*')) { if (Seer::filterEscapes(value_text) != "0x0") { // If it is a pointer that is not null, add a placeholder. How universal is this for other languages? QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, name_text); item->addChild(child); }else{ deleteItems(item->takeChildren()); } }else{ // A non-pointer child, add a placeholder. QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, name_text); item->addChild(child); expandItem = true; } } matchItem->addChild(item); if (expandItem == true && expandRecursiveCheckBox->isChecked()) { item->setExpanded(true); } } } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,changelist="))) { //qDebug() << "var-update-children" << text; // // "4^done,changelist=[ // {name=\"seer4.public.age\", value=\"60\", in_scope=\"true\", type_changed=\"false\", has_more=\"0\"}, // {name=\"seer4.public.salary\", value=\"0.25\", in_scope=\"true\", type_changed=\"false\", has_more=\"0\"}, // {name=\"seer4.public.location.public.city\", value=\"\\\"Houston\\\"\", in_scope=\"true\", type_changed=\"false\", displayhint=\"string\", dynamic=\"1\", has_more=\"0\"}, // {name=\"seer4.public.location.public.state\", value=\"\\\"Texas\\\"\", in_scope=\"true\", type_changed=\"false\", displayhint=\"string\", dynamic=\"1\", has_more=\"0\"}, // {name=\"seer4.public.location.public.zip\", value=\"77063\", in_scope=\"true\", type_changed=\"false\", has_more=\"0\"} // ]" QString id_text = text.section('^', 0,0); if (id_text.toInt() == _variableId) { QString changelist_text = Seer::parseFirst(text, "changelist=", '[', ']', false); QStringList child_list = Seer::parse(changelist_text, "", '{', '}', false); for (const auto& child_text : child_list) { QString name_text = Seer::parseFirst(child_text, "name=", '"', '"', false); QString value_text = Seer::parseFirst(child_text, "value=", '"', '"', false); QString inscope_text = Seer::parseFirst(child_text, "in_scope=", '"', '"', false); QString typechanged_text = Seer::parseFirst(child_text, "type_changed=", '"', '"', false); QString displayhint_text = Seer::parseFirst(child_text, "displayhint=", '"', '"', false); QString dynamic_text = Seer::parseFirst(child_text, "dynamic=", '"', '"', false); QString hasmore_text = Seer::parseFirst(child_text, "has_more=", '"', '"', false); // Do we have an existing item to add to? QTreeWidgetItem* matchItem = findItem(name_text, Qt::MatchExactly|Qt::MatchRecursive, 3); // No, just add to the top level. if (matchItem == 0) { qDebug() << name_text << "from the changelist does not exist in the tree."; // Yes, add to it. }else{ matchItem->setText(1, Seer::filterEscapes(value_text)); matchItem->setText(7, hasmore_text); // If there are children, add a placeholder. if (matchItem->text(5) != "0") { if (matchItem->text(2).endsWith('*')) { if (Seer::filterEscapes(matchItem->text(1)) != "0x0") { // If it is a pointer that is not null, add a placeholder. How universal is this for other languages? QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, matchItem->text(3)); matchItem->addChild(child); }else{ deleteItems(matchItem->takeChildren()); } }else{ // A non-pointer child, add a placeholder. QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, matchItem->text(3)); matchItem->addChild(child); } } // Need to refresh? if (typechanged_text == "true") { handleRefreshButton(); } } } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,attr="))) { //qDebug() << "var-show-attributes" << text; // 4^done,attr="noneditable" // 4^done,attr="editable" QString id_text = text.section('^', 0,0); QString editable_text = Seer::parseFirst(text, "attr=", '"', '"', false); // Do we have any items that match the varobjid? QTreeWidgetItem* matchItem = findItem(id_text, Qt::MatchExactly|Qt::MatchRecursive, 4); if (matchItem) { matchItem->setText(9, editable_text); if (editable_text == "editable") { matchItem->setFlags(matchItem->flags() | Qt::ItemIsEditable); }else{ matchItem->setFlags(matchItem->flags() & ~Qt::ItemIsEditable); } } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { QString id_text = text.section('^', 0,0); QString msg_text = Seer::parseFirst(text, "msg=", '"', '"', false); if (id_text.toInt() == _variableId) { QMessageBox::warning(this, "Seer", QString("Visualizer Error: '%1'\n").arg(Seer::filterEscapes(msg_text)), QMessageBox::Ok); } if (msg_text.contains("Variable object is not editable")) { if (_previousEditName != "") { QTreeWidgetItem* matchItem = findItem(_previousEditName, Qt::MatchExactly|Qt::MatchRecursive, 3); if (matchItem) { matchItem->setText(1, _previousEditValue); } } } }else if (text.startsWith("^error,msg=\"No registers.\"")) { variableTreeWidget->clear(); // At a stopping point, refresh. }else if (text.startsWith("*stopped,reason=\"")) { if (autoRefreshCheckBox->isChecked()) { handleRefreshButton(); } }else{ // Ignore anything else. } // Resize columns. handleResizeColumns(); } void SeerVarVisualizerWidget::handleContextMenu (const QPoint& pos) { QTreeWidgetItem* item = variableTreeWidget->itemAt(pos); if (item == 0) { return; } // Create the variable name. // If it's a struct, include its parent names. QString variable = fullVariableName(item); // Create the menus. QAction* expandItemAction = new QAction(QString("Expand item")); QAction* collapseItemAction = new QAction(QString("Collapse item")); QAction* addMemoryVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); QAction* addMemoryAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); QAction* addMemoryAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); QAction* addArrayVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); QAction* addArrayAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); QAction* addArrayAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); QAction* addMatrixVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); QAction* addMatrixAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); QAction* addMatrixAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); QAction* addVarVisualizerAction = new QAction(QString("\"%1\"").arg(variable)); QAction* addVarAsteriskVisualizerAction = new QAction(QString("\"*%1\"").arg(variable)); QAction* addVarAmpersandVisualizerAction = new QAction(QString("\"&&%1\"").arg(variable)); expandItemAction->setIcon(QIcon(":/seer/resources/RelaxLightIcons/list-add.svg")); collapseItemAction->setIcon(QIcon(":/seer/resources/RelaxLightIcons/list-remove.svg")); // Are we on an item that has children? expandItemAction->setEnabled(false); collapseItemAction->setEnabled(false); expandItemAction->setText(QString("Expand item '%1'").arg(item->text(0))); collapseItemAction->setText(QString("Collapse item '%1'").arg(item->text(0))); if (item->childCount() > 0) { if (item->isExpanded() == false) { expandItemAction->setEnabled(true); }else{ collapseItemAction->setEnabled(true); } } // Populate the menu. QMenu menu("Visualizers", this); menu.setTitle("Visualizers"); menu.addAction(expandItemAction); menu.addAction(collapseItemAction); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to an Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addVarVisualizerAction); structVisualizerMenu.addAction(addVarAsteriskVisualizerAction); structVisualizerMenu.addAction(addVarAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); // Launch the menu. Get the response. QAction* action = menu.exec(variableTreeWidget->viewport()->mapToGlobal(pos)); // Do nothing. if (action == 0) { return; } // Handle expanding the current item. if (action == expandItemAction) { expandItem(item); return; } // Handle collapsing the current item. if (action == collapseItemAction) { collapseItem(item); return; } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { //qDebug() << "addMemoryVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { //qDebug() << "addMemoryAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("*") + variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { //qDebug() << "addMemoryAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { //qDebug() << "addArrayVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { //qDebug() << "addArrayAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { //qDebug() << "addArrayAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addMatrixVisualizerAction) { //qDebug() << "addMatrixVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addMatrixAsteriskVisualizerAction) { //qDebug() << "addMatrixAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addMatrixAmpersandVisualizerAction) { //qDebug() << "addMatrixAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("&") + variable); } return; } // Handle adding struct to visualize. if (action == addVarVisualizerAction) { //qDebug() << "addVarVisualizer" << variable; // Emit the signals. if (variable != "") { emit addVarVisualizer(variable); } return; } // Handle adding struct to visualize. if (action == addVarAsteriskVisualizerAction) { //qDebug() << "addVarAsteriskVisualizer" << variable; // Emit the signals. if (variable != "") { emit addVarVisualizer(QString("*") + variable); } return; } // Handle adding struct to visualize. if (action == addVarAmpersandVisualizerAction) { //qDebug() << "addVarAmpersandVisualizer" << variable; // Emit the signals. if (variable != "") { emit addVarVisualizer(QString("&") + variable); } return; } } void SeerVarVisualizerWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); QString text = toolTipText(item); if (text != "") { for (int i=0; icolumnCount(); i++) { // Set tooltip to all columns. item->setToolTip(i, text); } // Ask for its editable attributes. if (item->text(4) != "") { //XXX emit varObjAttributes (item->text(4).toInt(), item->text(3)); } } } void SeerVarVisualizerWidget::handleItemExpanded (QTreeWidgetItem* item) { // Ask for the children. emit varObjListChildren(_variableId, item->text(3)); // Resize columns in a sec. // Have to schedule the resize later. Doing it immediatedly messes up the // tree display. Must be a Qt bug. QTimer::singleShot(100, this, &SeerVarVisualizerWidget::handleResizeColumns); } void SeerVarVisualizerWidget::handleItemCollapsed (QTreeWidgetItem* item) { // Delete all children items. deleteItems(item->takeChildren()); // If there are children, add a placeholder. if (item->text(5) != "0") { if (item->text(2).endsWith('*')) { if (Seer::filterEscapes(item->text(1)) != "0x0") { // If it is a pointer that is not null, add a placeholder. How universal is this for other languages? QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, item->text(3)); item->addChild(child); } }else{ // A non-pointer child, add a placeholder. QTreeWidgetItem* child = new QTreeWidgetItem; child->setText(0, "{...}"); child->setText(3, item->text(3)); item->addChild(child); } } // Resize columns in a sec. // Have to schedule the resize later. Doing it immediatedly messes up the // tree display. Must be a Qt bug. QTimer::singleShot(100, this, &SeerVarVisualizerWidget::handleResizeColumns); } void SeerVarVisualizerWidget::handleExpandSelected () { // Expand the current item, if selected. if (variableTreeWidget->currentItem()) { expandItem(variableTreeWidget->currentItem()); return; } // Or the entire tree. if (variableTreeWidget->topLevelItemCount() > 0) { expandItem(variableTreeWidget->topLevelItem(0)); } } void SeerVarVisualizerWidget::handleCollapseSelected () { // Collapse the current item, if selected. if (variableTreeWidget->currentItem()) { collapseItem(variableTreeWidget->currentItem()); return; } // Or the entire tree. if (variableTreeWidget->topLevelItemCount() > 0) { collapseItem(variableTreeWidget->topLevelItem(0)); } } void SeerVarVisualizerWidget::handleResizeColumns () { // Resize columns. variableTreeWidget->resizeColumnToContents(0); variableTreeWidget->resizeColumnToContents(1); variableTreeWidget->resizeColumnToContents(2); variableTreeWidget->resizeColumnToContents(3); variableTreeWidget->resizeColumnToContents(4); variableTreeWidget->resizeColumnToContents(5); variableTreeWidget->resizeColumnToContents(6); variableTreeWidget->resizeColumnToContents(7); variableTreeWidget->resizeColumnToContents(8); variableTreeWidget->resizeColumnToContents(9); } void SeerVarVisualizerWidget::handleHideDebugColumns (bool flag) { variableTreeWidget->setColumnHidden(0, false); variableTreeWidget->setColumnHidden(1, false); variableTreeWidget->setColumnHidden(2, false); variableTreeWidget->setColumnHidden(3, flag); variableTreeWidget->setColumnHidden(4, flag); variableTreeWidget->setColumnHidden(5, flag); variableTreeWidget->setColumnHidden(6, flag); variableTreeWidget->setColumnHidden(7, flag); variableTreeWidget->setColumnHidden(8, flag); variableTreeWidget->setColumnHidden(9, flag); handleResizeColumns(); } void SeerVarVisualizerWidget::handleRefreshButton () { // Send signal to get variable result. if (_variableName != "") { emit varObjUpdate(_variableId, _variableName); } } void SeerVarVisualizerWidget::handleHelpButton () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/StructVisualizer.md"); help->show(); help->raise(); } void SeerVarVisualizerWidget::handleDebugCheckBox () { handleHideDebugColumns(!debugCheckBox->isChecked()); } void SeerVarVisualizerWidget::handleVariableNameLineEdit () { if (variableNameLineEdit->text() == "") { return; } setVariableName (variableNameLineEdit->text()); } void SeerVarVisualizerWidget::handleIndexEditingStarted (const QModelIndex& index) { _previousEditName = ""; _previousEditValue = ""; QTreeWidgetItem* item = variableTreeWidget->getItemFromIndex(index); if (item == 0) { return; } // Get the old value; _previousEditName = item->text(3); _previousEditValue = item->text(1); } void SeerVarVisualizerWidget::handleIndexEditingFinished (const QModelIndex& index) { QTreeWidgetItem* item = variableTreeWidget->getItemFromIndex(index); if (item == 0) { return; } // Get the new value; QString value = item->text(1); // If it hasn't changed, we do need to bother. if (value == _previousEditValue) { _previousEditName = ""; _previousEditValue = ""; return; } // Emit the signal to change the varobj to the new value. emit varObjAssign(_variableId, item->text(3), value); } void SeerVarVisualizerWidget::handleThemeChanged () { // Colorize icons for theme. Seer::colorizeAllIcons(this, Seer::iconColorTheme()); } QTreeWidgetItem* SeerVarVisualizerWidget::findItem (const QString& text, Qt::MatchFlags flags, int column) { QList matches = variableTreeWidget->findItems(text, flags, column); if (matches.size() == 0) { return nullptr; } return matches[0]; } void SeerVarVisualizerWidget::writeSettings () { QSettings settings; settings.beginGroup("varvisualizerwindow"); settings.setValue("size", size()); settings.endGroup(); } void SeerVarVisualizerWidget::readSettings () { QSettings settings; settings.beginGroup("varvisualizerwindow"); resize(settings.value("size", QSize(800, 400)).toSize()); settings.endGroup(); } void SeerVarVisualizerWidget::resizeEvent (QResizeEvent* event) { writeSettings(); QWidget::resizeEvent(event); } void SeerVarVisualizerWidget::expandItem (QTreeWidgetItem* item) { if (item->childCount() == 0) { return; } if (item->isExpanded() == false) { item->setExpanded(true); } } void SeerVarVisualizerWidget::collapseItem (QTreeWidgetItem* item) { if (item->childCount() == 0) { return; } if (item->isExpanded() == true) { item->setExpanded(false); } } QString SeerVarVisualizerWidget::fullVariableName (QTreeWidgetItem* item) { // If the item has no value or type, then return no variable. if (item->text(1) == "" || item->text(2) == "") { return ""; } // Otherwise traverse up the tree to build up a variable name string, which includes '.' or '->' // depending if the type ends with a '*'. QString name; QTreeWidgetItem* tmp = item; while (tmp) { // Skip items that have no value or type. 'public', 'private', 'protected'. if (tmp->text(1) == "" || tmp->text(2) == "" || (tmp->text(0) == tmp->text(2))) { tmp = tmp->parent(); continue; } // Add the variable part to the variable name. if (tmp->childCount() > 0) { if (tmp->text(2).endsWith('*')) { if (name == "") { name.prepend(tmp->text(0)); }else{ name.prepend(tmp->text(0) + "->"); } }else{ if (name == "") { name.prepend(tmp->text(0)); }else{ name.prepend(tmp->text(0) + "."); } } }else{ name.prepend(tmp->text(0)); } // Move to the parent to get the type, if we can. tmp = tmp->parent(); } return name; } QString SeerVarVisualizerWidget::toolTipText (QTreeWidgetItem* item) { // If the item has no value or type, then return no tooltip. if (item->text(1) == "" || item->text(2) == "") { return ""; } // Get the full variable name. QString name = fullVariableName(item); if (name == "") { return name; } // Tack on the variable value and type. QString text = name + " : " + item->text(1) + " : " + item->text(2); return text; } void SeerVarVisualizerWidget::debug (QString message, QTreeWidgetItem* item) { // 0 variable // 1 value // 2 type // 3 varobj name // 4 varobj id // 5 exp // 6 numchild // 7 thread-id // 8 has_more // 8 editable if (item == 0) { qDebug() << message << "NULL"; }else{ qDebug() << message << item->text(0) << item->text(1) << item->text(2) << item->text(3) << item->text(4) << item->text(5) << item->text(6) << item->text(7) << item->text(8) << item->text(9); } } void SeerVarVisualizerWidget::deleteItems (QList items) { // Loop through the list and delete the items. // Note, the list will still contain pointers, but they will be invalid. foreach (auto item, items) delete item; } epasveer-seer-97076f1/src/SeerVarVisualizerWidget.h000066400000000000000000000076461526321767600223320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerVarVisualizerWidget.h" class SeerVarVisualizerWidget : public QWidget, protected Ui::SeerVarVisualizerWidgetForm { Q_OBJECT public: explicit SeerVarVisualizerWidget (QWidget* parent = 0); ~SeerVarVisualizerWidget (); void setVariableName (const QString& name); QString variableName () const; signals: void varObjCreate (int expressionid, QString expression); void varObjListChildren (int expressionid, QString objname); void varObjUpdate (int expressionid, QString objname); void varObjDelete (int expressionid, QString objname); void varObjAssign (int expressionid, QString objname, QString value); void varObjAttributes (int objid, QString objname); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addVarVisualizer (QString expression); public slots: void handleText (const QString& text); protected slots: void handleRefreshButton (); void handleHelpButton (); void handleDebugCheckBox (); void handleVariableNameLineEdit (); void handleIndexEditingStarted (const QModelIndex& index); void handleIndexEditingFinished (const QModelIndex& index); void handleContextMenu (const QPoint& pos); void handleItemEntered (QTreeWidgetItem* item, int column); void handleItemExpanded (QTreeWidgetItem* item); void handleItemCollapsed (QTreeWidgetItem* item); void handleExpandSelected (); void handleCollapseSelected (); void handleResizeColumns (); void handleHideDebugColumns (bool flag); void handleThemeChanged (); protected: QTreeWidgetItem* findItem (const QString& text, Qt::MatchFlags flags, int column); void writeSettings (); void readSettings (); void resizeEvent (QResizeEvent* event); private: void expandItem (QTreeWidgetItem* item); void collapseItem (QTreeWidgetItem* item); QString fullVariableName (QTreeWidgetItem* item); QString toolTipText (QTreeWidgetItem* item); void debug (QString message, QTreeWidgetItem* item); void deleteItems (QList items); int _variableId; QString _variableName; QString _previousEditName; QString _previousEditValue; }; epasveer-seer-97076f1/src/SeerVarVisualizerWidget.ui000066400000000000000000000144671526321767600225170ustar00rootroot00000000000000 SeerVarVisualizerWidgetForm 0 0 798 683 Form Enter a variable to visualize. Variable name true Qt::Vertical Expand items below current selection. :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Collapse items below current selection. :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Show more variable details. Debug Expand recursively. Recursive Qt::Vertical Refresh the list. ... :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Automatically refresh after each stopping point. Auto Qt::Vertical Help on Struct Visualizer :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg Variable Value Type VarObj VarObjID Exp NumChild ThreadID HasMore Editable QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
QIndexTreeWidget QTreeWidget
QIndexTreeWidget.h
variableNameLineEdit expandSelectedToolButton collapseSelectedToolButton debugCheckBox expandRecursiveCheckBox refreshToolButton autoRefreshCheckBox helpToolButton variableTreeWidget
epasveer-seer-97076f1/src/SeerVariableLoggerBrowserWidget.cpp000066400000000000000000000465531526321767600243100ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerVariableLoggerBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include SeerVariableLoggerBrowserWidget::SeerVariableLoggerBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets variablesTreeWidget->setMouseTracking(true); variablesTreeWidget->setSortingEnabled(false); variablesTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); variablesTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); variablesTreeWidget->resizeColumnToContents(0); // timestamp variablesTreeWidget->resizeColumnToContents(1); // name variablesTreeWidget->resizeColumnToContents(2); // value variablesTreeWidget->resizeColumnToContents(3); // id variablesTreeWidget->setColumnHidden(3, true); // Hide the 'id' column. variablesTreeWidget->clear(); // Connect things. QObject::connect(this, &SeerVariableLoggerBrowserWidget::evaluateVariableExpression, this, &SeerVariableLoggerBrowserWidget::handleEvaluateVariableExpression); QObject::connect(variableAddLineEdit, &QLineEdit::returnPressed, this, &SeerVariableLoggerBrowserWidget::handleAddLineEdit); QObject::connect(variableDeleteToolButton, &QToolButton::clicked, this, &SeerVariableLoggerBrowserWidget::handleDeleteToolButton); QObject::connect(variableDeleteAllToolButton, &QToolButton::clicked, this, &SeerVariableLoggerBrowserWidget::handleDeleteAllToolButton); QObject::connect(variablesTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerVariableLoggerBrowserWidget::handleItemCollapsed); QObject::connect(variablesTreeWidget, &QTreeWidget::itemExpanded, this, &SeerVariableLoggerBrowserWidget::handleItemExpanded); QObject::connect(variablesTreeWidget, &QTreeWidget::itemEntered, this, &SeerVariableLoggerBrowserWidget::handleItemEntered); QObject::connect(variablesTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerVariableLoggerBrowserWidget::handleContextMenu); } SeerVariableLoggerBrowserWidget::~SeerVariableLoggerBrowserWidget () { } void SeerVariableLoggerBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // "6^done,value=\"\\\"abc\\\"\"" QString id_text = text.section('^', 0,0); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); if (_ids.contains(id_text.toInt()) == false) { break; } // If with brackets (a structure), filter out excess '\n' // in case pretty-print-on is used. if (value_text.front() == '{' && value_text.back() == '}') { value_text = Seer::filterBareNewLines(value_text); } QList matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 3); if (matches.size() > 0) { QTreeWidgetItem* match = matches[0]; Q_ASSERT(match->parent() == NULL); QString timestamp_text = match->text(0); QString name_text = match->text(1); // Populate the tree. handleItemCreate(match, id_text, timestamp_text, name_text, value_text); emit raiseTab(); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // "1^error,msg=\"No symbol \\\"j\\\" in current context.\"" QString id_text = text.section('^', 0,0); QString msg_text = Seer::parseFirst(text, "msg=", '"', '"', false); if (_ids.contains(id_text.toInt()) == true) { QList matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 3); if (matches.size() > 0) { matches.first()->setText(1, ""); // Overwrite "name" with "" because it's not a valid "name". matches.first()->setText(2, Seer::filterEscapes(msg_text)); } emit raiseTab(); } }else{ // Ignore others. } // Resize columns. variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); // Scroll to the bottom. QTreeWidgetItem* lastItem = variablesTreeWidget->topLevelItem(variablesTreeWidget->topLevelItemCount()-1); if (lastItem) { variablesTreeWidget->scrollToItem(lastItem); } break; } // Set the cursor back. QApplication::restoreOverrideCursor(); } void SeerVariableLoggerBrowserWidget::handleSessionTerminated () { // Delete previous contents. variablesTreeWidget->clear(); } void SeerVariableLoggerBrowserWidget::handleEvaluateVariableExpression (int expressionid, QString expression) { QString id_text = QString::number(expressionid); if (_ids.contains(id_text.toInt()) == false) { return; } // Add new item. Will be filled in by handleText(). QTreeWidgetItem* item = new QTreeWidgetItem; item->setText(0, QTime::currentTime().toString(Qt::TextDate)); item->setText(1, expression); item->setText(2, ""); item->setText(3, id_text); item->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); variablesTreeWidget->addTopLevelItem(item); // Resize columns done later in handleText(). } void SeerVariableLoggerBrowserWidget::addVariableExpression (QString expression) { if (expression != "") { int id = Seer::createID(); _ids.insert(id); // Keep track of which ones are entered. emit evaluateVariableExpression(id, expression); } } void SeerVariableLoggerBrowserWidget::handleAddLineEdit () { QString expression = variableAddLineEdit->text(); variableAddLineEdit->clear(); if (expression != "") { int id = Seer::createID(); _ids.insert(id); // Keep track of which ones are entered. emit evaluateVariableExpression(id, expression); } } void SeerVariableLoggerBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = variablesTreeWidget->selectedItems(); // Remove them. for (int i=0; iresizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableLoggerBrowserWidget::handleDeleteAllToolButton () { // Remove all. variablesTreeWidget->clear(); // Resize columns. variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableLoggerBrowserWidget::handleItemExpanded (QTreeWidgetItem* item) { Q_UNUSED(item); variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableLoggerBrowserWidget::handleItemCollapsed (QTreeWidgetItem* item) { Q_UNUSED(item); variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableLoggerBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + item->text(1) + " : " + Seer::elideText(item->text(2), Qt::ElideRight, 100)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerVariableLoggerBrowserWidget::handleItemCreate (QTreeWidgetItem* parentItem, const QString& id_text, const QString& timestamp_text, const QString& name_text, const QString& value_text) { // Add the complex entry to the tree. if (Seer::hasBookends(value_text, '{', '}')) { // Remove bookends QString text = Seer::filterBookends(value_text, '{', '}'); // Set the flatvalue text. parentItem->setText(0, timestamp_text); parentItem->setText(1, name_text); parentItem->setText(2, Seer::filterEscapes(text)); parentItem->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); parentItem->setText(3, id_text); // Convert to a list of name/value pairs. QStringList nv_pairs; if (text.startsWith("{")) { // String might describe an array: {a=1, b=1},{a=1, b=1},{a=1, b=1},{a=1, b=1} // parentItem->text(0) is timestamp -> parent name should be parentItem->text(1) nv_pairs = Seer::parseArray(parentItem->text(1), text); } else { nv_pairs = Seer::parseCommaList(text, '{', '}'); } // Go through each pair and add the name and its value to the tree. for (const auto& nv : nv_pairs) { QStringPair pair = Seer::parseNameValue(nv, '='); // Create a new item and attach it to the parent. QTreeWidgetItem* item = new QTreeWidgetItem; handleItemCreate(item, id_text, timestamp_text, pair.first, pair.second); parentItem->addChild(item); } // Add the simple entry to the tree. }else{ parentItem->setText(0, timestamp_text); parentItem->setText(1, name_text); parentItem->setText(2, Seer::filterEscapes(value_text)); parentItem->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); parentItem->setText(3, id_text); } } void SeerVariableLoggerBrowserWidget::handleContextMenu (const QPoint& pos) { // Get the item at the cursor. QTreeWidgetItem* item = variablesTreeWidget->itemAt(pos); // Construct the menu. QAction* addMemoryVisualizerAction = new QAction(); QAction* addMemoryAsteriskVisualizerAction = new QAction(); QAction* addMemoryAmpersandVisualizerAction = new QAction(); QAction* addArrayVisualizerAction = new QAction(); QAction* addArrayAsteriskVisualizerAction = new QAction(); QAction* addArrayAmpersandVisualizerAction = new QAction(); QAction* addMatrixVisualizerAction = new QAction(); QAction* addMatrixAsteriskVisualizerAction = new QAction(); QAction* addMatrixAmpersandVisualizerAction = new QAction(); QAction* addStructVisualizerAction = new QAction(); QAction* addStructAsteriskVisualizerAction = new QAction(); QAction* addStructAmpersandVisualizerAction = new QAction(); QMenu menu("Options", this); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); QAction* deleteAction = menu.addAction("Delete selected"); QAction* deleteAllAction = menu.addAction("Delete all"); QAction* copyAction = menu.addAction("Copy selected"); QAction* copyValueOnlyAction = menu.addAction("Copy selected value"); QAction* copyAllAction = menu.addAction("Copy all"); QString actionText; if (item != 0) { actionText = item->text(1); } QString variable; if (item != 0) { // Build up a variable string, incase it is a nested struct. QTreeWidgetItem* i = item; variable = item->text(1); while (i->parent() != 0) { variable = i->parent()->text(1) + "." + variable; i = i->parent(); } } // Remove potential '&' and '*' characters at start of string. variable.remove(QRegularExpression("^[\\*\\&]*")); addMemoryVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addMemoryAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addMemoryAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addArrayVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addArrayAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addArrayAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addMatrixVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addMatrixAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addMatrixAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addStructVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addStructAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addStructAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); // If no selected item, disable everything but allow 'copyall' and 'deleteall'. if (item == 0) { memoryVisualizerMenu.setEnabled(false); arrayVisualizerMenu.setEnabled(false); matrixVisualizerMenu.setEnabled(false); structVisualizerMenu.setEnabled(false); deleteAction->setEnabled(false); copyAction->setEnabled(false); } // Execute the menu. Return if nothing. QAction* action = menu.exec(variablesTreeWidget->mapToGlobal(pos)); if (action == 0) { return; } if (action == deleteAction) { handleDeleteToolButton(); } if (action == deleteAllAction) { handleDeleteAllToolButton(); } if (action == copyAction || action == copyAllAction || action == copyValueOnlyAction) { // Get selected tree items. QList items; // Get list of 'select' items. if (action == copyAction || action == copyValueOnlyAction) { items = variablesTreeWidget->selectedItems(); } // Get list of 'all' items. if (action == copyAllAction) { items = variablesTreeWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard); } // Populate the clipboard. if (items.size() == 0) { return; } QClipboard* clipboard = QGuiApplication::clipboard(); QString text; for (int i=0; itext(1) + ":" + items[i]->text(2); } else { text += items[i]->text(2); } } clipboard->setText(text, QClipboard::Clipboard); clipboard->setText(text, QClipboard::Selection); } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("*") + variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("&") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("*") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("&") + variable); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(variable); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("*") + variable); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("&") + variable); } return; } } epasveer-seer-97076f1/src/SeerVariableLoggerBrowserWidget.h000066400000000000000000000043241526321767600237430ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerVariableLoggerBrowserWidget.h" class SeerVariableLoggerBrowserWidget : public QWidget, protected Ui::SeerVariableLoggerBrowserWidgetForm { Q_OBJECT public: explicit SeerVariableLoggerBrowserWidget (QWidget* parent = 0); ~SeerVariableLoggerBrowserWidget (); public slots: void handleText (const QString& text); void handleSessionTerminated (); void handleEvaluateVariableExpression (int expressionid, QString expression); void addVariableExpression (QString expression); private slots: void handleAddLineEdit (); void handleDeleteToolButton (); void handleDeleteAllToolButton (); void handleItemEntered (QTreeWidgetItem* item, int column); void handleItemExpanded (QTreeWidgetItem* item); void handleItemCollapsed (QTreeWidgetItem* item); void handleContextMenu (const QPoint& pos); signals: void evaluateVariableExpression (int expressionid, QString expression); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); void raiseTab (); protected: void handleItemCreate (QTreeWidgetItem* parentItem, const QString& id_text, const QString& timestamp_text, const QString& name_text, const QString& value_text); private: QSet _ids; }; epasveer-seer-97076f1/src/SeerVariableLoggerBrowserWidget.ui000066400000000000000000000055531526321767600241360ustar00rootroot00000000000000 SeerVariableLoggerBrowserWidgetForm 0 0 794 528 Form Add a variable to the loggger. Enter a variable name to log true Delete selected variables. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Delete all variables. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg 4 Timestamp Name Value ID QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
epasveer-seer-97076f1/src/SeerVariableManagerWidget.cpp000066400000000000000000000226621526321767600230720ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerVariableManagerWidget.h" #include "SeerHelpPageDialog.h" #include "QHContainerWidget.h" #include #include #include #include #include #include #include SeerVariableManagerWidget::SeerVariableManagerWidget (QWidget* parent) : QWidget(parent) { // Initialize private data // Setup UI setupUi(this); // Setup the widgets tabWidget->setMovable(true); tabWidget->setTabsClosable(false); _variableLoggerBrowserWidget = new SeerVariableLoggerBrowserWidget(this); _variableTrackerBrowserWidget = new SeerVariableTrackerBrowserWidget(this); _registerValuesBrowserWidget = new SeerRegisterValuesBrowserWidget(this); _signalValuesBrowserWidget = new SeerSignalValuesBrowserWidget(this); tabWidget->addTab(_variableLoggerBrowserWidget, "Logger"); tabWidget->addTab(_variableTrackerBrowserWidget, "Tracker"); tabWidget->addTab(_registerValuesBrowserWidget, "Registers"); tabWidget->addTab(_signalValuesBrowserWidget, "Signals"); QToolButton* tabsContextMenuButton = new QToolButton(tabWidget); tabsContextMenuButton->setIcon(QIcon(":/seer/resources/thenounproject/preferences.svg")); tabsContextMenuButton->setToolTip("Show/Hide tabs."); tabsContextMenuButton->setContextMenuPolicy(Qt::CustomContextMenu); QToolButton* refreshToolButton = new QToolButton(tabWidget); refreshToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/view-refresh.svg")); refreshToolButton->setToolTip("Refresh the variable/register/signal information."); QToolButton* helpToolButton = new QToolButton(tabWidget); helpToolButton->setIcon(QIcon(":/seer/resources/RelaxLightIcons/help-about.svg")); helpToolButton->setToolTip("Help on variable/register/signal information."); QHContainerWidget* hcontainer = new QHContainerWidget(this); hcontainer->setSpacing(3); hcontainer->addWidget(tabsContextMenuButton); hcontainer->addWidget(refreshToolButton); hcontainer->addWidget(helpToolButton); tabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner); // Restore tab ordering. readSettings(); // Connect things. QObject::connect(tabsContextMenuButton, &QToolButton::clicked, this, &SeerVariableManagerWidget::handleTabsContextMenuButtonClicked); QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerVariableManagerWidget::handleRefreshToolButtonClicked); QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerVariableManagerWidget::handleHelpToolButtonClicked); QObject::connect(tabWidget->tabBar(), &QTabBar::tabMoved, this, &SeerVariableManagerWidget::handleTabMoved); QObject::connect(tabWidget->tabBar(), &QTabBar::currentChanged, this, &SeerVariableManagerWidget::handleTabChanged); QObject::connect(_variableLoggerBrowserWidget, &SeerVariableLoggerBrowserWidget::raiseTab, this, &SeerVariableManagerWidget::handleRaiseLoggerTab); QObject::connect(_variableTrackerBrowserWidget, &SeerVariableTrackerBrowserWidget::raiseTab, this, &SeerVariableManagerWidget::handleRaiseTrackerTab); } SeerVariableManagerWidget::~SeerVariableManagerWidget () { } SeerVariableTrackerBrowserWidget* SeerVariableManagerWidget::variableTrackerBrowserWidget () { return _variableTrackerBrowserWidget; } SeerVariableLoggerBrowserWidget* SeerVariableManagerWidget::variableLoggerBrowserWidget () { return _variableLoggerBrowserWidget; } SeerRegisterValuesBrowserWidget* SeerVariableManagerWidget::registerValuesBrowserWidget () { return _registerValuesBrowserWidget; } SeerSignalValuesBrowserWidget* SeerVariableManagerWidget::signalValuesBrowserWidget () { return _signalValuesBrowserWidget; } void SeerVariableManagerWidget::handleRefreshToolButtonClicked () { variableTrackerBrowserWidget()->refresh(); registerValuesBrowserWidget()->refresh(); signalValuesBrowserWidget()->refresh(); } void SeerVariableManagerWidget::handleHelpToolButtonClicked () { SeerHelpPageDialog* help = new SeerHelpPageDialog; help->loadFile(":/seer/resources/help/VariableRegisterSignalInfoBrowser.md"); help->show(); help->raise(); } void SeerVariableManagerWidget::handleTabMoved (int from, int to) { Q_UNUSED(from); Q_UNUSED(to); writeSettings(); } void SeerVariableManagerWidget::handleTabChanged (int index) { Q_UNUSED(index); writeSettings(); } void SeerVariableManagerWidget::handleRaiseLoggerTab () { int idx = tabWidget->indexOf(_variableLoggerBrowserWidget); if (idx < 0) { return; } tabWidget->setCurrentIndex(idx); } void SeerVariableManagerWidget::handleRaiseTrackerTab () { int idx = tabWidget->indexOf(_variableTrackerBrowserWidget); if (idx < 0) { return; } tabWidget->setCurrentIndex(idx); } void SeerVariableManagerWidget::writeSettings () { // Build up visible list. QStringList visible; for (int i=0; itabBar()->count(); i++) { visible.append(tabWidget->isTabVisible(i) ? "true" : "false"); } // Build up tab order. QStringList tabs; for (int i=0; itabBar()->count(); i++) { tabs.append(tabWidget->tabBar()->tabText(i)); } // Build up current tab. QString current = tabWidget->tabBar()->tabText(tabWidget->tabBar()->currentIndex()); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; QSettings settings; settings.beginGroup("variablemanagerwindow"); { settings.setValue("taborder", tabs.join(',')); settings.setValue("tabvisible", visible.join(',')); settings.setValue("tabcurrent", current); } settings.endGroup(); } void SeerVariableManagerWidget::readSettings () { // Can't move things? if (tabWidget->tabBar()->isMovable() == false) { return; } // Read tab order from settings. QSettings settings; QStringList tabs; QStringList visible; QString current; settings.beginGroup("variablemanagerwindow"); { tabs = settings.value("taborder").toString().split(','); visible = settings.value("tabvisible").toString().split(','); current = settings.value("tabcurrent").toString(); } settings.endGroup(); //qDebug() << "Tabs" << tabs; //qDebug() << "Current" << current; // Move tabs to the requested order. for (int i=0; itabBar()->count(); j++) { if (tabWidget->tabBar()->tabText(j) == tab) { tb = j; break; } } if (tb != -1) { tabWidget->tabBar()->moveTab(tb, i); } } // Show/Hide tabs. for (int i=0; isetTabVisible(i,true); }else if (flag == "false") { tabWidget->setTabVisible(i,false); }else{ tabWidget->setTabVisible(i,true); } } // Make a tab current. if (current != "") { for (int i=0; itabBar()->count(); i++) { if (tabWidget->tabBar()->tabText(i) == current) { tabWidget->setCurrentIndex(i); break; } } }else{ tabWidget->setCurrentIndex(0); } } void SeerVariableManagerWidget::handleTabsContextMenuButtonClicked() { // Build the menu and execute it. QMenu contextMenu; QWidget* container = new QWidget(&contextMenu); QVBoxLayout* layout = new QVBoxLayout(container); for (int i = 0; i < tabWidget->count(); i++) { QString title = tabWidget->tabText(i); QCheckBox* showTabCheckBox = new QCheckBox(title, container); showTabCheckBox->setChecked(tabWidget->isTabVisible(i)); layout->addWidget(showTabCheckBox); QObject::connect(showTabCheckBox, &QCheckBox::toggled, [this, showTabCheckBox, i](bool checked) { // Count visible tabs. int count=0; for (int x=0; xcount(); x++) { if (tabWidget->isTabVisible(x)) { count++; } } // Adjust the count. The 'checked' is made before the UI is updated. if (checked == true) { count++; }else{ count--; } // Reset the checkbox UI if the last visible tab was clicked. if (checked == false and count == 0) { showTabCheckBox->setChecked(true); // Don't hide last visible tab. }else if (checked == false and count > 1) { tabWidget->setTabVisible(i, checked); // Always show tabs when asked. }else{ tabWidget->setTabVisible(i, checked); } writeSettings(); }); } container->setLayout(layout); QWidgetAction* action = new QWidgetAction(&contextMenu); action->setDefaultWidget(container); contextMenu.addAction(action); contextMenu.exec(QCursor::pos()); } epasveer-seer-97076f1/src/SeerVariableManagerWidget.h000066400000000000000000000043471526321767600225370ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "SeerVariableTrackerBrowserWidget.h" #include "SeerVariableLoggerBrowserWidget.h" #include "SeerRegisterValuesBrowserWidget.h" #include "SeerSignalValuesBrowserWidget.h" #include #include "ui_SeerVariableManagerWidget.h" class SeerVariableManagerWidget : public QWidget, protected Ui::SeerVariableManagerWidgetForm { Q_OBJECT public: explicit SeerVariableManagerWidget (QWidget* parent = 0); ~SeerVariableManagerWidget (); SeerVariableTrackerBrowserWidget* variableTrackerBrowserWidget (); SeerVariableLoggerBrowserWidget* variableLoggerBrowserWidget (); SeerRegisterValuesBrowserWidget* registerValuesBrowserWidget (); SeerSignalValuesBrowserWidget* signalValuesBrowserWidget (); protected: void writeSettings (); void readSettings (); private slots: void handleRefreshToolButtonClicked (); void handleHelpToolButtonClicked (); void handleTabMoved (int from, int to); void handleTabChanged (int index); void handleRaiseLoggerTab (); void handleRaiseTrackerTab (); void handleTabsContextMenuButtonClicked (); private: SeerVariableTrackerBrowserWidget* _variableTrackerBrowserWidget; SeerVariableLoggerBrowserWidget* _variableLoggerBrowserWidget; SeerRegisterValuesBrowserWidget* _registerValuesBrowserWidget; SeerSignalValuesBrowserWidget* _signalValuesBrowserWidget; }; epasveer-seer-97076f1/src/SeerVariableManagerWidget.ui000066400000000000000000000031441526321767600227170ustar00rootroot00000000000000 SeerVariableManagerWidgetForm 0 0 772 469 Form 0 0 0 0 3 font-weight: bold; Variable/Register/Signal Info Qt::PlainText -1 QDetachTabWidget QTabWidget
QDetachTabWidget.h
1
epasveer-seer-97076f1/src/SeerVariableTrackerBrowserWidget.cpp000066400000000000000000000736121526321767600244600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerVariableTrackerBrowserWidget.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include #include SeerVariableTrackerBrowserWidget::SeerVariableTrackerBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets variablesTreeWidget->setMouseTracking(true); variablesTreeWidget->setSortingEnabled(false); variablesTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); variablesTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); variablesTreeWidget->resizeColumnToContents(0); // name variablesTreeWidget->resizeColumnToContents(1); // value variablesTreeWidget->resizeColumnToContents(2); // id variablesTreeWidget->resizeColumnToContents(3); // used variablesTreeWidget->setColumnHidden(2, true); // Hide the 'id' column. variablesTreeWidget->setColumnHidden(3, true); // Hide the 'used' column. variablesTreeWidget->clear(); // Connect things. QObject::connect(variableAddLineEdit, &QLineEdit::returnPressed, this, &SeerVariableTrackerBrowserWidget::handleAddLineEdit); QObject::connect(variableDeleteToolButton, &QToolButton::clicked, this, &SeerVariableTrackerBrowserWidget::handleDeleteToolButton); QObject::connect(variableDeleteAllToolButton, &QToolButton::clicked, this, &SeerVariableTrackerBrowserWidget::handleDeleteAllToolButton); QObject::connect(variablesTreeWidget, &QTreeWidget::itemCollapsed, this, &SeerVariableTrackerBrowserWidget::handleItemCollapsed); QObject::connect(variablesTreeWidget, &QTreeWidget::itemExpanded, this, &SeerVariableTrackerBrowserWidget::handleItemExpanded); QObject::connect(variablesTreeWidget, &QTreeWidget::itemEntered, this, &SeerVariableTrackerBrowserWidget::handleItemEntered); QObject::connect(variablesTreeWidget, &QTreeWidget::customContextMenuRequested, this, &SeerVariableTrackerBrowserWidget::handleContextMenu); QObject::connect(variableRememberToolButton, &QToolButton::toggled, this, &SeerVariableTrackerBrowserWidget::handleRememberToolButton); // Read state. readSettings(); } SeerVariableTrackerBrowserWidget::~SeerVariableTrackerBrowserWidget () { } void SeerVariableTrackerBrowserWidget::handleText (const QString& text) { QApplication::setOverrideCursor(Qt::BusyCursor); while (1) { if (text.startsWith("^done,DataExpressionTable={") && text.endsWith("}")) { // "^done,DataExpressionTable={ // entry={id=\"1\",expression=\"s\"}, // entry={id=\"2\",expression=\"v\"}, // entry={id=\"4\",expression=\"l\"}, // entry={id=\"5\",expression=\"m\"} // }" QString frame_text = Seer::parseFirst(text, "DataExpressionTable=", '{', '}', false); QStringList entries_list = Seer::parse(frame_text, "entry=", '{', '}', false); for (int i=0; i matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 2); if (matches.count() == 0) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, expression_text); topItem->setText(1, ""); topItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); topItem->setText(2, id_text); topItem->setText(3, "new"); variablesTreeWidget->addTopLevelItem(topItem); } } }else if (text.startsWith("^done,DataExpressionAdded={") && text.endsWith("}")) { // "^done,DataExpressionAdded={ // id=\"5\", // expression=\"m\" // }" QString frame_text = Seer::parseFirst(text, "DataExpressionAdded=", '{', '}', false); QString id_text = Seer::parseFirst(frame_text, "id=", '"', '"', false); QString expression_text = Seer::parseFirst(frame_text, "expression=", '"', '"', false); QList matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 2); if (matches.count() == 0) { QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, expression_text); topItem->setText(1, ""); topItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); topItem->setText(2, id_text); topItem->setText(3, "new"); variablesTreeWidget->addTopLevelItem(topItem); refreshValues(); emit raiseTab(); } }else if (text.startsWith("^done,DataExpressionDeleted={") && text.endsWith("}")) { // "^done,DataExpressionDeleted={ // entry={id=\"1\",expression=\"s\"}, // entry={id=\"3\",expression=\"vb\"} // }" QString frame_text = Seer::parseFirst(text, "DataExpressionDeleted=", '{', '}', false); QStringList entries_list = Seer::parse(frame_text, "entry=", '{', '}', false); for (int i=0; i matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 2); qDeleteAll(matches); } }else if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) { // "6^done,value=\"\\\"abc\\\"\"" QString id_text = text.section('^', 0,0); QString value_text = Seer::parseFirst(text, "value=", '"', '"', false); // If with brackets (a structure), filter out excess '\n' // in case pretty-print-on is used. if (value_text.front() == '{' && value_text.back() == '}') { value_text = Seer::filterBareNewLines(value_text); } // Find the ones that match our 'id'. QList matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 2); if (matches.count() == 1) { Q_ASSERT(matches.count() == 1); // There should be only one. QTreeWidgetItem* item = matches[0]; // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator itmark(item); while (*itmark) { (*itmark)->setText(3, "unused"); ++itmark; } QString old_text = item->text(1); old_text.replace("\\\"", "\""); old_text.remove('\\'); value_text.replace("\\\"", "\""); value_text.remove('\\'); if (old_text == "") { // If old_text is empty -> This node is created for the first time. Pass the same text for old and new handleItemCreate (item, value_text, value_text); } else { old_text = Seer::filterBareNewLines(old_text); handleItemCreate (item, value_text, old_text); } emit raiseTab(); // At this point, there are some new entries, some reused entries, and some unused ones. // For now, don't bother deleting 'unused' ones. } }else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) { // "1^error,msg=\"No symbol \\\"j\\\" in current context.\"" QString id_text = text.section('^', 0,0); QString msg_text = Seer::parseFirst(text, "msg=", '"', '"', false); // Find the ones that match our 'id'. QList matches = variablesTreeWidget->findItems(id_text, Qt::MatchExactly, 2); if (matches.count() == 1) { // There should be only one. QTreeWidgetItem* item = matches[0]; // Remove any children. QList children = item->takeChildren(); qDeleteAll(children); // Set the text with the error message. item->setText(1, Seer::filterEscapes(msg_text)); item->setText(3, "used"); } }else{ // Ignore others. } variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); break; } QApplication::restoreOverrideCursor(); } void SeerVariableTrackerBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } refresh(); } void SeerVariableTrackerBrowserWidget::handleSessionTerminated () { // Remember the variable names? if (variableRememberToolButton->isChecked() == true) { return; } // Delete previous contents. variablesTreeWidget->clear(); // Tell the GdbWidget to forget all tracked expressions. emit deleteVariableExpressions("*"); } void SeerVariableTrackerBrowserWidget::refresh () { emit refreshVariableTrackerNames(); emit refreshVariableTrackerValues(); } void SeerVariableTrackerBrowserWidget::refreshValues () { emit refreshVariableTrackerValues(); } void SeerVariableTrackerBrowserWidget::handleAddLineEdit () { QString variable = variableAddLineEdit->text(); variableAddLineEdit->clear(); if (variable != "") { emit addVariableExpression(variable); // After sending the 'add' signal, schedule a 'refresh' 200ms later. QTimer::singleShot(200, this, &SeerVariableTrackerBrowserWidget::refresh); } } void SeerVariableTrackerBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = variablesTreeWidget->selectedItems(); // Build a string that is a list of variable ids. QString variableids; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { variableids += " "; } variableids += (*i)->text(2); } // Don't do anything if the list of variables is empty. if (variableids == "") { return; } // Send the signal. emit deleteVariableExpressions(variableids); } void SeerVariableTrackerBrowserWidget::handleDeleteAllToolButton () { emit deleteVariableExpressions("*"); } void SeerVariableTrackerBrowserWidget::handleItemExpanded (QTreeWidgetItem* item) { Q_UNUSED(item); variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableTrackerBrowserWidget::handleItemCollapsed (QTreeWidgetItem* item) { Q_UNUSED(item); variablesTreeWidget->resizeColumnToContents(0); variablesTreeWidget->resizeColumnToContents(1); variablesTreeWidget->resizeColumnToContents(2); variablesTreeWidget->resizeColumnToContents(3); } void SeerVariableTrackerBrowserWidget::handleItemEntered (QTreeWidgetItem* item, int column) { Q_UNUSED(column); item->setToolTip(0, item->text(0) + " : " + Seer::elideText(item->text(1), Qt::ElideRight, 100)); for (int i=1; icolumnCount(); i++) { // Copy tooltip to other columns. item->setToolTip(i, item->toolTip(0)); } } void SeerVariableTrackerBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); refresh(); } void SeerVariableTrackerBrowserWidget::handleItemCreate (QTreeWidgetItem* item, const QString& value_text, const QString& old_text) { handleItemCreate(item, item->text(2), item->text(0), value_text, old_text); } void SeerVariableTrackerBrowserWidget::handleItemCreate (QTreeWidgetItem* parentItem, const QString& id_text, const QString& name_text, const QString& value_text, const QString& old_text) { // Fill in parent item. Whether is a simple or complex entry. parentItem->setText(0, name_text); parentItem->setText(1, Seer::filterEscapes(value_text)); parentItem->setText(2, id_text); parentItem->setText(3, "reused"); // Look for bookmarks. This indicates a nested structure. // There are two types. With and without an address. QString capture0; // With bookends. QString capture1; // Without. QRegularExpression withaddress_re("^@0[xX][0-9a-fA-F]+: \\{(.*?)\\}$"); QRegularExpressionMatch withaddress_match = withaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (withaddress_match.hasMatch()) { capture0 = withaddress_match.captured(0); capture1 = withaddress_match.captured(1); }else{ QRegularExpression noaddress_re("^\\{(.*?)\\}$"); QRegularExpressionMatch noaddress_match = noaddress_re.match(value_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (noaddress_match.hasMatch()) { capture0 = noaddress_match.captured(0); capture1 = noaddress_match.captured(1); } } // Simple entries don't have children. Delete them. // Then we're done. if (capture0 == "" || capture1 == "") { while (parentItem->childCount() > 0) { QTreeWidgetItem* item = parentItem->child(0); delete item; } } // Do the same for old_text QString captureOld0; // With bookends. QString captureOld1; // Without. QRegularExpressionMatch withaddress_match_Old = withaddress_re.match(old_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (withaddress_match_Old.hasMatch()) { captureOld0 = withaddress_match_Old.captured(0); captureOld1 = withaddress_match_Old.captured(1); }else{ QRegularExpression noaddress_re("^\\{(.*?)\\}$"); QRegularExpressionMatch noaddress_match = noaddress_re.match(old_text, 0, QRegularExpression::PartialPreferCompleteMatch); if (noaddress_match.hasMatch()) { captureOld0 = noaddress_match.captured(0); captureOld1 = noaddress_match.captured(1); } } // Add the complex entry to the tree. Reuse, if possible. // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. We start by looking for matches that // may already be there. If there are matches, the code will reuse it. If not, a new item // is created by the code. Note, when searching, we only look at the current level. Not any // children. // Use the one without bookends. QString text = capture1; // Convert to a list of name/value pairs. QStringList nv_pairs; if (text.startsWith("{")) { // String might describe an array: {a=1, b=1},{a=1, b=1},{a=1, b=1},{a=1, b=1} nv_pairs = Seer::parseArray(parentItem->text(0), text); } else { nv_pairs = Seer::parseCommaList(text, '{', '}'); } QStringList nv_old_pairs; if (text.startsWith("{")) { // String might describe an array: {a=1, b=1},{a=1, b=1},{a=1, b=1},{a=1, b=1} nv_old_pairs = Seer::parseArray(parentItem->text(0), captureOld1); } else { nv_old_pairs = Seer::parseCommaList(captureOld1, '{', '}'); } if (nv_old_pairs.size() != nv_pairs.size()) // Check if variable has changed type or is out of scope { // If sizes don't match, it seems that variables is out of scope or changed type // First, delete all children, otherwise we might have leftovers while (parentItem->childCount() > 0) { QTreeWidgetItem* item = parentItem->child(0); delete item; } // Then, recreate all children for (const auto& nv : nv_pairs) { QStringPair pair = Seer::parseNameValue(nv, '='); // Look for the existing child, if any so we can reuse it. QTreeWidgetItem* childItem = 0; for (int i=0; ichildCount(); i++) { if (parentItem->child(i)->text(0) == pair.first) { childItem = parentItem->child(i); childItem->setText(0, pair.first); childItem->setText(1, pair.second); childItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); childItem->setText(2, id_text); childItem->setText(3, "reused"); break; } } // Otherwise, create a new child. if (childItem == 0) { childItem = new QTreeWidgetItem; childItem->setText(0, pair.first); childItem->setText(1, pair.second); childItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); childItem->setText(2, id_text); childItem->setText(3, "new"); parentItem->addChild(childItem); } handleItemCreate(childItem, id_text, childItem->text(0), childItem->text(1), ""); } return; } QFont parentFont = parentItem->font(0); parentFont.setBold(old_text != value_text); // if value has changed -> set font to bold parentItem->setFont(0, parentFont); parentItem->setFont(1, parentFont); // Go through each pair and add the name and its value to the tree. for (int i = 0; i < nv_pairs.size(); ++i) { QString nv = nv_pairs[i]; QString nv_old = nv_old_pairs[i]; QStringPair pair = Seer::parseNameValue(nv, '='); QStringPair old_pair = Seer::parseNameValue(nv_old, '='); // Look for the existing child, if any so we can reuse it. QTreeWidgetItem* childItem = 0; for (int i=0; ichildCount(); i++) { if (parentItem->child(i)->text(0) == pair.first) { childItem = parentItem->child(i); childItem->setText(0, pair.first); childItem->setText(1, pair.second); childItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); childItem->setText(2, id_text); childItem->setText(3, "reused"); QFont childFontCol0 = childItem->font(0); QFont childFontCol1 = QFontDatabase::systemFont(QFontDatabase::FixedFont); childFontCol0.setBold(pair.second != old_pair.second); childFontCol1.setBold(pair.second != old_pair.second); childItem->setFont(0, childFontCol0); childItem->setFont(1, childFontCol1); break; } } // Otherwise, create a new child. if (childItem == 0) { childItem = new QTreeWidgetItem; childItem->setText(0, pair.first); childItem->setText(1, pair.second); childItem->setFont(1, QFontDatabase::systemFont(QFontDatabase::FixedFont)); childItem->setText(2, id_text); childItem->setText(3, "new"); parentItem->addChild(childItem); } handleItemCreate(childItem, id_text, childItem->text(0), childItem->text(1), old_pair.second); } } void SeerVariableTrackerBrowserWidget::handleContextMenu (const QPoint& pos) { // Get the item at the cursor. QTreeWidgetItem* item = variablesTreeWidget->itemAt(pos); // Construct the menu. QAction* addMemoryVisualizerAction = new QAction(); QAction* addMemoryAsteriskVisualizerAction = new QAction(); QAction* addMemoryAmpersandVisualizerAction = new QAction(); QAction* addArrayVisualizerAction = new QAction(); QAction* addArrayAsteriskVisualizerAction = new QAction(); QAction* addArrayAmpersandVisualizerAction = new QAction(); QAction* addMatrixVisualizerAction = new QAction(); QAction* addMatrixAsteriskVisualizerAction = new QAction(); QAction* addMatrixAmpersandVisualizerAction = new QAction(); QAction* addStructVisualizerAction = new QAction(); QAction* addStructAsteriskVisualizerAction = new QAction(); QAction* addStructAmpersandVisualizerAction = new QAction(); QMenu menu("Options", this); QMenu memoryVisualizerMenu("Add variable to a Memory Visualizer"); memoryVisualizerMenu.addAction(addMemoryVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAsteriskVisualizerAction); memoryVisualizerMenu.addAction(addMemoryAmpersandVisualizerAction); menu.addMenu(&memoryVisualizerMenu); QMenu arrayVisualizerMenu("Add variable to an Array Visualizer"); arrayVisualizerMenu.addAction(addArrayVisualizerAction); arrayVisualizerMenu.addAction(addArrayAsteriskVisualizerAction); arrayVisualizerMenu.addAction(addArrayAmpersandVisualizerAction); menu.addMenu(&arrayVisualizerMenu); QMenu matrixVisualizerMenu("Add variable to a Matrix Visualizer"); matrixVisualizerMenu.addAction(addMatrixVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAsteriskVisualizerAction); matrixVisualizerMenu.addAction(addMatrixAmpersandVisualizerAction); menu.addMenu(&matrixVisualizerMenu); QMenu structVisualizerMenu("Add variable to a Struct Visualizer"); structVisualizerMenu.addAction(addStructVisualizerAction); structVisualizerMenu.addAction(addStructAsteriskVisualizerAction); structVisualizerMenu.addAction(addStructAmpersandVisualizerAction); menu.addMenu(&structVisualizerMenu); QAction* deleteAction = menu.addAction("Delete selected"); QAction* deleteAllAction = menu.addAction("Delete all"); QAction* copyAction = menu.addAction("Copy selected"); QAction* copyValueOnlyAction = menu.addAction("Copy selected value"); QAction* copyAllAction = menu.addAction("Copy all"); QString actionText; if (item != 0) { actionText = item->text(0); } QString variable; if (item != 0) { // Build up a variable string, incase it is a nested struct. QTreeWidgetItem* i = item; variable = item->text(0); while (i->parent() != 0) { variable = i->parent()->text(0) + "." + variable; i = i->parent(); } } // Remove potential '&' and '*' characters at start of string. variable.remove(QRegularExpression("^[\\*\\&]*")); addMemoryVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addMemoryAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addMemoryAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addArrayVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addArrayAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addArrayAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addMatrixVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addMatrixAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addMatrixAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); addStructVisualizerAction->setText(QString("\"%1\"").arg(actionText)); addStructAsteriskVisualizerAction->setText(QString("\"*%1\"").arg(actionText)); addStructAmpersandVisualizerAction->setText(QString("\"&&%1\"").arg(actionText)); // If no selected item, disable everything but allow 'copyall' and 'deleteall'. if (item == 0) { memoryVisualizerMenu.setEnabled(false); arrayVisualizerMenu.setEnabled(false); matrixVisualizerMenu.setEnabled(false); structVisualizerMenu.setEnabled(false); deleteAction->setEnabled(false); copyAction->setEnabled(false); } // Execute the menu. Return if nothing. QAction* action = menu.exec(variablesTreeWidget->mapToGlobal(pos)); if (action == 0) { return; } if (action == deleteAction) { handleDeleteToolButton(); } if (action == deleteAllAction) { handleDeleteAllToolButton(); } if (action == copyAction || action == copyAllAction || action == copyValueOnlyAction) { // Get selected tree items. QList items; // Get list of 'select' items. if (action == copyAction || copyValueOnlyAction) { items = variablesTreeWidget->selectedItems(); } // Get list of 'all' items. if (action == copyAllAction) { items = variablesTreeWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard); } // Populate the clipboard. if (items.count() == 0) { return; } QClipboard* clipboard = QGuiApplication::clipboard(); QString text; for (int i=0; itext(0) + ":" + items[i]->text(1); } else { text += items[i]->text(1); } } clipboard->setText(text, QClipboard::Clipboard); clipboard->setText(text, QClipboard::Selection); } // Handle adding memory to visualize. if (action == addMemoryVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("*") + variable); } return; } // Handle adding memory to visualize. if (action == addMemoryAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMemoryVisualizer(QString("&") + variable); } return; } // Handle adding array to visualize. if (action == addArrayVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(variable); } return; } // Handle adding array to visualize. if (action == addArrayAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("*") + variable); } return; } // Handle adding array to visualize. if (action == addArrayAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addArrayVisualizer(QString("&") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("*") + variable); } return; } // Handle adding matrix to visualize. if (action == addMatrixAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addMatrixVisualizer(QString("&") + variable); } return; } // Handle adding struct to visualize. if (action == addStructVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(variable); } return; } // Handle adding struct to visualize. if (action == addStructAsteriskVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("*") + variable); } return; } // Handle adding struct to visualize. if (action == addStructAmpersandVisualizerAction) { // Emit the signals. if (variable != "") { emit addStructVisualizer(QString("&") + variable); } return; } } void SeerVariableTrackerBrowserWidget::handleRememberToolButton (bool checked) { Q_UNUSED(checked); writeSettings(); } void SeerVariableTrackerBrowserWidget::readSettings () { QSettings settings; bool remember = false; settings.beginGroup("variabletrackerwindow"); { remember = settings.value("remembervariablenames", remember).toBool(); } settings.endGroup(); variableRememberToolButton->setChecked(remember); } void SeerVariableTrackerBrowserWidget::writeSettings () { QSettings settings; settings.beginGroup("variabletrackerwindow"); { settings.setValue("remembervariablenames", variableRememberToolButton->isChecked()); } settings.endGroup(); } epasveer-seer-97076f1/src/SeerVariableTrackerBrowserWidget.h000066400000000000000000000053051526321767600241170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerVariableTrackerBrowserWidget.h" class SeerVariableTrackerBrowserWidget : public QWidget, protected Ui::SeerVariableTrackerBrowserWidgetForm { Q_OBJECT public: explicit SeerVariableTrackerBrowserWidget (QWidget* parent = 0); ~SeerVariableTrackerBrowserWidget (); public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); void refresh (); void refreshValues (); private slots: void handleAddLineEdit (); void handleDeleteToolButton (); void handleDeleteAllToolButton (); void handleItemEntered (QTreeWidgetItem* item, int column); void handleItemExpanded (QTreeWidgetItem* item); void handleItemCollapsed (QTreeWidgetItem* item); void handleContextMenu (const QPoint& pos); void handleRememberToolButton (bool checked); signals: void refreshVariableTrackerNames (); void refreshVariableTrackerValues (); void addVariableExpression (QString expression); void deleteVariableExpressions (QString expressionids); void addMemoryVisualizer (QString expression); void addArrayVisualizer (QString expression); void addMatrixVisualizer (QString expression); void addStructVisualizer (QString expression); void raiseTab (); protected: void handleItemCreate (QTreeWidgetItem* item, const QString& value_text, const QString& old_text); void handleItemCreate (QTreeWidgetItem* parentItem, const QString& id_text, const QString& name_text, const QString& value_text, const QString& old_text); void showEvent (QShowEvent* event); private: void readSettings (); void writeSettings (); }; epasveer-seer-97076f1/src/SeerVariableTrackerBrowserWidget.ui000066400000000000000000000066751526321767600243200ustar00rootroot00000000000000 SeerVariableTrackerBrowserWidgetForm 0 0 794 528 Form Add a variable to track. Enter a variable name to track true Remember variable names between sessions. ... :/seer/resources/RelaxLightIcons/pin.svg:/seer/resources/RelaxLightIcons/pin.svg true Delete selected variables. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Delete all variables. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg 4 Name Value ID Used QHistoryLineEdit QLineEdit
QHistoryLineEdit.h
epasveer-seer-97076f1/src/SeerWatchpointCreateDialog.cpp000066400000000000000000000042221526321767600232620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerWatchpointCreateDialog.h" #include SeerWatchpointCreateDialog::SeerWatchpointCreateDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); QButtonGroup* accessTypeButtonGroup = new QButtonGroup(this); accessTypeButtonGroup->addButton(writeRadioButton); accessTypeButtonGroup->addButton(readRadioButton); accessTypeButtonGroup->addButton(readWriteRadioButton); // Setup the widgets setExpression(""); setReadAccessEnabled(false); setReadWriteAccessEnabled(false); setWriteAccessEnabled(true); expressionLineEdit->setFocus(); // Connect things. } SeerWatchpointCreateDialog::~SeerWatchpointCreateDialog () { } void SeerWatchpointCreateDialog::setExpression (const QString& text) { expressionLineEdit->setText(text); } QString SeerWatchpointCreateDialog::expressionText () const { return expressionLineEdit->text(); } void SeerWatchpointCreateDialog::setReadAccessEnabled (bool flag) { readRadioButton->setChecked(flag); } void SeerWatchpointCreateDialog::setWriteAccessEnabled (bool flag) { writeRadioButton->setChecked(flag); } void SeerWatchpointCreateDialog::setReadWriteAccessEnabled (bool flag) { readWriteRadioButton->setChecked(flag); } bool SeerWatchpointCreateDialog::readAccessEnabled () const { return readRadioButton->isChecked(); } bool SeerWatchpointCreateDialog::writeAccessEnabled () const { return writeRadioButton->isChecked(); } bool SeerWatchpointCreateDialog::readWriteAccessEnabled () const { return readWriteRadioButton->isChecked(); } QString SeerWatchpointCreateDialog::watchpointText () const { // Build a watchpoint specification. QString watchpointParameters; if (readAccessEnabled()) { watchpointParameters += " -r"; } if (readWriteAccessEnabled()) { watchpointParameters += " -a"; } if (writeAccessEnabled()) { watchpointParameters += ""; } watchpointParameters += " " + expressionText(); return watchpointParameters; } epasveer-seer-97076f1/src/SeerWatchpointCreateDialog.h000066400000000000000000000020711526321767600227270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include "ui_SeerWatchpointCreateDialog.h" class SeerWatchpointCreateDialog : public QDialog, protected Ui::SeerWatchpointCreateDialogForm { Q_OBJECT public: explicit SeerWatchpointCreateDialog (QWidget* parent = 0); ~SeerWatchpointCreateDialog (); void setExpression (const QString& text); QString expressionText () const; void setReadAccessEnabled (bool flag); void setWriteAccessEnabled (bool flag); void setReadWriteAccessEnabled (bool flag); bool readAccessEnabled () const; bool writeAccessEnabled () const; bool readWriteAccessEnabled () const; QString watchpointText () const; public slots: private: }; epasveer-seer-97076f1/src/SeerWatchpointCreateDialog.ui000066400000000000000000000067311526321767600231240ustar00rootroot00000000000000 SeerWatchpointCreateDialogForm 0 0 403 256 Create a Watchpoint Watchpoint Location 0 0 Variable/Expression 100 0 true Watchpoint Type Read Access Read/Write Access Write Access Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SeerWatchpointCreateDialogForm accept() 248 254 157 274 buttonBox rejected() SeerWatchpointCreateDialogForm reject() 316 260 286 274 epasveer-seer-97076f1/src/SeerWatchpointsBrowserWidget.cpp000066400000000000000000000617401526321767600237210ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerWatchpointsBrowserWidget.h" #include "SeerWatchpointCreateDialog.h" #include "SeerUtl.h" #include #include #include #include #include #include #include #include SeerWatchpointsBrowserWidget::SeerWatchpointsBrowserWidget (QWidget* parent) : QWidget(parent) { // Construct the UI. setupUi(this); // Setup the widgets watchpointsTreeWidget->clear(); watchpointsTreeWidget->setSortingEnabled(false); watchpointsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); watchpointsTreeWidget->resizeColumnToContents(0); // number watchpointsTreeWidget->resizeColumnToContents(1); // original-location / expression watchpointsTreeWidget->resizeColumnToContents(2); // value watchpointsTreeWidget->resizeColumnToContents(3); // new value watchpointsTreeWidget->resizeColumnToContents(4); // type watchpointsTreeWidget->resizeColumnToContents(5); // disp watchpointsTreeWidget->resizeColumnToContents(6); // enabled watchpointsTreeWidget->resizeColumnToContents(7); // addr //watchpointsTreeWidget->resizeColumnToContents(8); // func Too long to show watchpointsTreeWidget->resizeColumnToContents(9); // file //watchpointsTreeWidget->resizeColumnToContents(10); // fullname Too long to show watchpointsTreeWidget->resizeColumnToContents(11); // line watchpointsTreeWidget->resizeColumnToContents(12); // thread-groups watchpointsTreeWidget->resizeColumnToContents(13); // cond watchpointsTreeWidget->resizeColumnToContents(14); // times watchpointsTreeWidget->resizeColumnToContents(15); // ignore //watchpointsTreeWidget->resizeColumnToContents(16); // script Too long to show watchpointsTreeWidget->resizeColumnToContents(17); // used watchpointsTreeWidget->setColumnHidden(7, true); // Hide the 'addr' column. watchpointsTreeWidget->setColumnHidden(8, true); // Hide the 'func' column. watchpointsTreeWidget->setColumnHidden(17, true); // Hide the 'used' column. watchpointsTreeWidget->clear(); // Connect things. QObject::connect(watchpointsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerWatchpointsBrowserWidget::handleItemDoubleClicked); QObject::connect(refreshWatchpointsToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleRefreshToolButton); QObject::connect(addWatchpointToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleAddToolButton); QObject::connect(deleteWatchpointsToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleDeleteToolButton); QObject::connect(enableWatchpointsToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleEnableToolButton); QObject::connect(disableWatchpointsToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleDisableToolButton); QObject::connect(conditionWatchpointToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleConditionToolButton); QObject::connect(ignoreWatchpointToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleIgnoreToolButton); QObject::connect(commandsWatchpointToolButton, &QToolButton::clicked, this, &SeerWatchpointsBrowserWidget::handleCommandsToolButton); } SeerWatchpointsBrowserWidget::~SeerWatchpointsBrowserWidget () { } bool SeerWatchpointsBrowserWidget::isEmpty() const { return (watchpointsTreeWidget->topLevelItemCount() == 0); } QStringList SeerWatchpointsBrowserWidget::breakpoints () const { return QStringList(); } void SeerWatchpointsBrowserWidget::handleText (const QString& text) { // Don't do any work if the widget is hidden. if (isHidden()) { return; } QApplication::setOverrideCursor(Qt::BusyCursor); if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) { // // ^done,BreakpointTable={ // nr_rows="2",nr_cols="6", // // hdr=[ // {width="7",alignment="-1",col_name="number",colhdr="Num"}, // {width="14",alignment="-1",col_name="type",colhdr="Type"}, // {width="4",alignment="-1",col_name="disp",colhdr="Disp"}, // {width="3",alignment="-1",col_name="enabled",colhdr="Enb"}, // {width="18",alignment="-1",col_name="addr",colhdr="Address"}, // {width="40",alignment="2",col_name="what",colhdr="What"} // ], // // body=[ // bkpt={number="2",type="breakpoint",disp="keep",enabled="y",addr="0x0000000000400c17",func="main(int, char**)",file="helloworld.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp",line="8",thread-groups=["i1"],times="0",original-location="main"}, // bkpt={number="3", // type="breakpoint", // disp="keep", // enabled="y", // addr="0x0000000000400d72", // func="function1(std::__cxx11::basic_string, std::allocator > const&)", // file="function1.cpp", // fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp", // line="7", // thread-groups=["i1"], // times="0", // original-location="function1"} // ] // } // QString newtext = Seer::filterEscapes(text); // Filter escaped characters. QString body_text = Seer::parseFirst(newtext, "body=", '[', ']', false); //qDebug() << body_text; // No rows? Just clear the tree. if (body_text == "") { watchpointsTreeWidget->clear(); // Otherwise, populate it. }else{ // Mark each entry initially as "unused". // Later, some will be marked as "reused" or "new". Then the "unused" ones will // be deleted. QTreeWidgetItemIterator it(watchpointsTreeWidget); while (*it) { (*it)->setText(17, "unused"); ++it; } QStringList bkpt_list = Seer::parse(newtext, "bkpt=", '{', '}', false); for ( const auto& bkpt_text : bkpt_list ) { QString number_text = Seer::parseFirst(bkpt_text, "number=", '"', '"', false); QString type_text = Seer::parseFirst(bkpt_text, "type=", '"', '"', false); QString disp_text = Seer::parseFirst(bkpt_text, "disp=", '"', '"', false); QString enabled_text = Seer::parseFirst(bkpt_text, "enabled=", '"', '"', false); QString addr_text = Seer::parseFirst(bkpt_text, "addr=", '"', '"', false); QString func_text = Seer::parseFirst(bkpt_text, "func=", '"', '"', false); QString file_text = Seer::parseFirst(bkpt_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(bkpt_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(bkpt_text, "line=", '"', '"', false); QString thread_groups_text = Seer::parseFirst(bkpt_text, "thread-groups=", '[', ']', false); QString cond_text = Seer::parseFirst(bkpt_text, "cond=", '"', '"', false); QString times_text = Seer::parseFirst(bkpt_text, "times=", '"', '"', false); QString ignore_text = Seer::parseFirst(bkpt_text, "ignore=", '"', '"', false); QString script_text = Seer::parseFirst(bkpt_text, "script=", '[', ']', false); QString original_location_text = Seer::parseFirst(bkpt_text, "original-location=", '"', '"', false); // Only look for 'watchpoint' type break points. if (type_text != "hw watchpoint" && type_text != "watchpoint" && type_text != "read watchpoint" && type_text != "acc watchpoint") { continue; } script_text = Seer::filterBookends(Seer::parseCommaList(script_text, '{', '}'), '"', '"').join('\n'); // Instead of creating a new tree each time, we will reuse existing items, if they are there. // This allows the expanded items to remain expanded. QList matches = watchpointsTreeWidget->findItems(number_text, Qt::MatchExactly, 0); // No matches. So can't reuse. Add the new entry. if (matches.size() == 0) { // Add the level to the tree. QTreeWidgetItem* topItem = new QTreeWidgetItem; topItem->setText(0, number_text); topItem->setText(1, original_location_text); topItem->setText(2, ""); topItem->setText(3, ""); topItem->setText(4, type_text); topItem->setText(5, disp_text); topItem->setText(6, enabled_text); topItem->setText(7, addr_text); topItem->setText(8, func_text); topItem->setText(9, QFileInfo(file_text).fileName()); topItem->setText(10, fullname_text); topItem->setText(11, line_text); topItem->setText(12, thread_groups_text); topItem->setText(13, cond_text); topItem->setText(14, times_text); topItem->setText(15, ignore_text); topItem->setText(16, script_text); topItem->setText(17, "new"); topItem->setFont(2, QFontDatabase::systemFont(QFontDatabase::FixedFont)); topItem->setFont(3, QFontDatabase::systemFont(QFontDatabase::FixedFont)); for (int i=0; icolumnCount(); i++) { topItem->setTextAlignment(i, Qt::AlignLeft|Qt::AlignTop); } watchpointsTreeWidget->addTopLevelItem(topItem); // Found a match. Reuse it. // But don't overwrite the file, fullname, line, value, and new value. }else{ QTreeWidgetItem* topItem = matches.takeFirst(); topItem->setText(0, number_text); topItem->setText(1, original_location_text); //topItem->setText(2, ""); //topItem->setText(3, ""); topItem->setText(4, type_text); topItem->setText(5, disp_text); topItem->setText(6, enabled_text); topItem->setText(7, addr_text); topItem->setText(8, func_text); //topItem->setText(9, QFileInfo(file_text).fileName()); //topItem->setText(10, fullname_text); //topItem->setText(11, line_text); topItem->setText(12, thread_groups_text); topItem->setText(13, cond_text); topItem->setText(14, times_text); topItem->setText(15, ignore_text); topItem->setText(16, script_text); topItem->setText(17, "reused"); } } // At this point, there are some new entries, some reused entries, and some unused ones. // Delete the unused ones. They are obsolete. QList matches = watchpointsTreeWidget->findItems("unused", Qt::MatchExactly, 17); qDeleteAll(matches); } }else if (text.startsWith("*stopped,reason=\"") || text.startsWith("*stopped,hw-awpt={")) { QString reason_text = Seer::parseFirst(text, "reason=", '"', '"', false); if (reason_text == "watchpoint-trigger") { //*stopped,reason="watchpoint-trigger",wpt={number="3",exp="i"},value={old="32767",new="42"},frame={addr="0x0000000000400d79",func="function1",args=[{name="text",value="\"Hello, World!\""}],file="function1.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp",line="9",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="0" QString wpt_text = Seer::parseFirst(text, "wpt=", '{', '}', false); QString number_text = Seer::parseFirst(wpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(wpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString old_text = Seer::parseFirst(value_text, "old=", '"', '"', false); QString new_text = Seer::parseFirst(value_text, "new=", '"', '"', false); QString frame_text = Seer::parseFirst(text, "frame=", '{', '}', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); // Find watchpoint number in the tree QList matches = watchpointsTreeWidget->findItems(number_text, Qt::MatchExactly, 0); if (matches.size() > 0) { //qDebug() << text; QTreeWidgetItem* item = matches.first(); item->setText(2, old_text); item->setText(3, new_text); item->setText(9, QFileInfo(file_text).fileName()); item->setText(10, fullname_text); item->setText(11, line_text); } }else if (reason_text == "read-watchpoint-trigger") { //*stopped,reason="read-watchpoint-trigger",hw-rwpt={number="5",exp="i"},value={value="42"},frame={addr="0x0000000000400d9a",func="function1",args=[{name="text",value="\"Hello, World!\""}],file="function1.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp",line="11",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="4" QString hwwpt_text = Seer::parseFirst(text, "hw-rwpt=", '{', '}', false); QString number_text = Seer::parseFirst(hwwpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(hwwpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString value_text2 = Seer::parseFirst(value_text, "value=", '"', '"', false); QString frame_text = Seer::parseFirst(text, "frame=", '{', '}', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); // Find watchpoint number in the tree QList matches = watchpointsTreeWidget->findItems(number_text, Qt::MatchExactly, 0); if (matches.size() > 0) { //qDebug() << text; QTreeWidgetItem* item = matches.first(); item->setText(2, value_text2); item->setText(3, ""); item->setText(9, QFileInfo(file_text).fileName()); item->setText(10, fullname_text); item->setText(11, line_text); } }else if (reason_text == "access-watchpoint-trigger") { //*stopped,reason="access-watchpoint-trigger",hw-awpt={number="3",exp="v"},value={old="1",new="11"},frame={addr="0x000000000040059a",func="bar",args=[{name="v",value="11"}],file="helloonefile.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloonefile/helloonefile.cpp",line="15",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="3" QString hwawpt_text = Seer::parseFirst(text, "hw-awpt=", '{', '}', false); QString number_text = Seer::parseFirst(hwawpt_text, "number=", '"', '"', false); QString exp_text = Seer::parseFirst(hwawpt_text, "exp=", '"', '"', false); QString value_text = Seer::parseFirst(text, "value=", '{', '}', false); QString old_text = Seer::parseFirst(value_text, "old=", '"', '"', false); QString new_text = Seer::parseFirst(value_text, "new=", '"', '"', false); QString frame_text = Seer::parseFirst(text, "frame=", '{', '}', false); QString file_text = Seer::parseFirst(frame_text, "file=", '"', '"', false); QString fullname_text = Seer::parseFirst(frame_text, "fullname=", '"', '"', false); QString line_text = Seer::parseFirst(frame_text, "line=", '"', '"', false); // Find watchpoint number in the tree QList matches = watchpointsTreeWidget->findItems(number_text, Qt::MatchExactly, 0); if (matches.size() > 0) { //qDebug() << text; QTreeWidgetItem* item = matches.first(); item->setText(2, old_text); item->setText(3, new_text); item->setText(9, QFileInfo(file_text).fileName()); item->setText(10, fullname_text); item->setText(11, line_text); } } }else{ // Ignore others. } watchpointsTreeWidget->resizeColumnToContents(0); watchpointsTreeWidget->resizeColumnToContents(1); watchpointsTreeWidget->resizeColumnToContents(2); watchpointsTreeWidget->resizeColumnToContents(3); watchpointsTreeWidget->resizeColumnToContents(4); watchpointsTreeWidget->resizeColumnToContents(5); watchpointsTreeWidget->resizeColumnToContents(6); watchpointsTreeWidget->resizeColumnToContents(7); //watchpointsTreeWidget->resizeColumnToContents(8); watchpointsTreeWidget->resizeColumnToContents(9); //watchpointsTreeWidget->resizeColumnToContents(10); watchpointsTreeWidget->resizeColumnToContents(11); watchpointsTreeWidget->resizeColumnToContents(12); watchpointsTreeWidget->resizeColumnToContents(13); watchpointsTreeWidget->resizeColumnToContents(14); watchpointsTreeWidget->resizeColumnToContents(15); //watchpointsTreeWidget->resizeColumnToContents(16); watchpointsTreeWidget->resizeColumnToContents(17); QApplication::restoreOverrideCursor(); } void SeerWatchpointsBrowserWidget::handleStoppingPointReached () { // Don't do any work if the widget is hidden. if (isHidden()) { return; } emit refreshWatchpointsList(); } void SeerWatchpointsBrowserWidget::handleSessionTerminated () { // Delete previous contents. watchpointsTreeWidget->clear(); } void SeerWatchpointsBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) { Q_UNUSED(column); int lineno = item->text(11).toInt(); emit selectedFile(item->text(9), item->text(10), lineno); } void SeerWatchpointsBrowserWidget::handleRefreshToolButton () { emit refreshWatchpointsList(); } void SeerWatchpointsBrowserWidget::handleAddToolButton () { SeerWatchpointCreateDialog dlg(this); int ret = dlg.exec(); if (ret == 0) { return; } // Build a watchpoint specification. QString watchpointParameters = dlg.watchpointText(); // If nothing, just return. if (watchpointParameters == "") { return; } // Otherwise send the command to create the watchpoint. emit insertWatchpoint(watchpointParameters); } void SeerWatchpointsBrowserWidget::handleDeleteToolButton () { // Get selected tree items. QList items = watchpointsTreeWidget->selectedItems(); // Build a string that is a list of watchpoints. QString watchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { watchpoints += " "; } watchpoints += (*i)->text(0); } // Don't do anything if the list of watchpoints is empty. if (watchpoints == "") { return; } // Send the signal. emit deleteWatchpoints(watchpoints); } void SeerWatchpointsBrowserWidget::handleEnableToolButton () { // Get selected tree items. QList items = watchpointsTreeWidget->selectedItems(); // Build a string that is a list of watchpoints. QString watchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { watchpoints += " "; } watchpoints += (*i)->text(0); } // Don't do anything if the list of watchpoints is empty. if (watchpoints == "") { return; } // Send the signal. emit enableWatchpoints(watchpoints); } void SeerWatchpointsBrowserWidget::handleDisableToolButton () { // Get selected tree items. QList items = watchpointsTreeWidget->selectedItems(); // Build a string that is a list of watchpoints. QString watchpoints; QList::iterator i; for (i = items.begin(); i != items.end(); ++i) { if (i != items.begin()) { watchpoints += " "; } watchpoints += (*i)->text(0); } // Don't do anything if the list of watchpoints is empty. if (watchpoints == "") { return; } // Send the signal. emit disableWatchpoints(watchpoints); } void SeerWatchpointsBrowserWidget::handleConditionToolButton () { // Get selected tree items. Only allow one. QList items = watchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one watchpoint when adding a condition.", QMessageBox::Ok); return; } // Get the condition text. bool ok; QString condition = QInputDialog::getText(this, "Seer", "Enter the condition for this watchpoint.\nA blank condition will remove an existing one.", QLineEdit::Normal, items.front()->text(13), &ok); if (ok == false) { return; } // Get the selected watchpoint number. QString watchpoint = items.front()->text(0); // Send the signal. emit addBreakpointCondition(watchpoint, condition); } void SeerWatchpointsBrowserWidget::handleIgnoreToolButton () { // Get selected tree items. Only allow one. QList items = watchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one watchpoint when adding an ignore count.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; int count = QInputDialog::getInt(this, "Seer", "Enter the ignore count for this watchpoint.\nA count of 0 will remove an existing one.", items.front()->text(15).toInt(), 0, 2147483647, 1, &ok); if (ok == false) { return; } // Get the selected watchpoint number. QString watchpoint = items.front()->text(0); // Send the signal. emit addBreakpointIgnore(watchpoint, QString::number(count)); } void SeerWatchpointsBrowserWidget::handleCommandsToolButton () { // Get selected tree items. Only allow one. QList items = watchpointsTreeWidget->selectedItems(); if (items.count() == 0) { return; } if (items.count() > 1) { QMessageBox::warning(this, "Seer", "Select only one watcpoint when adding commands.", QMessageBox::Ok); return; } // Get the ignore text. bool ok; QString commandstr = QInputDialog::getMultiLineText(this, "Seer", "Enter the commands to execute for this watchpoint.\nA blank list will remove existing ones.", items.front()->text(16), &ok); if (ok == false) { return; } // Get the selected watchpoint number. QString watchpoint = items.front()->text(0); QStringList commands = Seer::quoteChars(commandstr.split('\n', Qt::SkipEmptyParts), "\""); // Send the signal. emit addBreakpointCommands(watchpoint, commands); } void SeerWatchpointsBrowserWidget::showEvent (QShowEvent* event) { QWidget::showEvent(event); emit refreshWatchpointsList(); } epasveer-seer-97076f1/src/SeerWatchpointsBrowserWidget.h000066400000000000000000000044361526321767600233650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include #include #include #include "ui_SeerWatchpointsBrowserWidget.h" class SeerWatchpointsBrowserWidget : public QWidget, protected Ui::SeerWatchpointsBrowserWidgetForm { Q_OBJECT public: explicit SeerWatchpointsBrowserWidget (QWidget* parent = 0); ~SeerWatchpointsBrowserWidget (); bool isEmpty () const; QStringList breakpoints () const; public slots: void handleText (const QString& text); void handleStoppingPointReached (); void handleSessionTerminated (); private slots: void handleItemDoubleClicked (QTreeWidgetItem* item, int column); void handleRefreshToolButton (); void handleAddToolButton (); void handleDeleteToolButton (); void handleEnableToolButton (); void handleDisableToolButton (); void handleConditionToolButton (); void handleIgnoreToolButton (); void handleCommandsToolButton (); signals: void refreshWatchpointsList (); void deleteWatchpoints (QString watchpoints); void enableWatchpoints (QString watchpoints); void disableWatchpoints (QString watchpoints); void addBreakpointCondition (QString watchpoint, QString condition); void addBreakpointIgnore (QString watchpoint, QString count); void addBreakpointCommands (QString watchpoint, QStringList commands); void insertWatchpoint (QString watchpoint); void selectedFile (QString file, QString fullname, int lineno); protected: void showEvent (QShowEvent* event); private: }; epasveer-seer-97076f1/src/SeerWatchpointsBrowserWidget.ui000066400000000000000000000163001526321767600235440ustar00rootroot00000000000000 SeerWatchpointsBrowserWidgetForm 0 0 1052 528 Form 18 Number Expression Value New Value Type Disposition Enabled Address Function File Fullname Line Thread Groups Condition Times Ignore Commands Used Add a new watchpoint. ... :/seer/resources/RelaxLightIcons/document-new.svg:/seer/resources/RelaxLightIcons/document-new.svg Refresh the list of watchpoints. :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg Enable selected watchpoints. ... :/seer/resources/RelaxLightIcons/list-add.svg:/seer/resources/RelaxLightIcons/list-add.svg Disable selected watchpoints. ... :/seer/resources/RelaxLightIcons/list-remove.svg:/seer/resources/RelaxLightIcons/list-remove.svg Add condition to selected watchpoint. ? Add ignore count to selected watchpoint. # Add commands to selected watchpoint. ... :/seer/resources/RelaxLightIcons/go-next.svg:/seer/resources/RelaxLightIcons/go-next.svg Delete selected watchpoints. ... :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg Qt::Vertical 20 40 Qt::Vertical 20 40 epasveer-seer-97076f1/src/build/000077500000000000000000000000001526321767600164525ustar00rootroot00000000000000epasveer-seer-97076f1/src/build/README.cmake000066400000000000000000000023631526321767600204150ustar00rootroot00000000000000Notes for building Seer with cmake. % cd seer/src/build % cmake -DCMAKE_BUILD_TYPE=Debug .. # Debug release -g. % cmake -DCMAKE_BUILD_TYPE=Release .. # Optimized release -O. % cmake -DCMAKE_CXX_FLAGS=-Wall .. # With all compile warnings turned on. The above defaults to Qt6. If you want to use Qt5, add the '-DQTVERSION' flag. % cmake -DQTVERSION=QT5 -DCMAKE_BUILD_TYPE=Debug .. Once cmake is run, then just build Seer. % make clean # Clean files. % make seergdb # Build Seer. % sudo make install # Install it. Another way to ask cmake to do the build for you. % cmake --build . --config Release % sudo cmake --install . MacOS may need help finding the cmake config file for Qt6. % cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt6/ -DCMAKE_BUILD_TYPE=Release .. Sometimes you need to specify a newer version of g++/gcc. Your installation may have an old version as the default. % cmake -DCMAKE_CXX_COMPILER=g++-14 -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=Debug .. Checkout the Seer wiki for more build info. https://github.com/epasveer/seer/wiki/Building-Seer---Qt5 https://github.com/epasveer/seer/wiki/Building-Seer---Qt6 epasveer-seer-97076f1/src/build_seerutl/000077500000000000000000000000001526321767600202155ustar00rootroot00000000000000epasveer-seer-97076f1/src/build_seerutl/CMakeLists.txt000066400000000000000000000035041526321767600227570ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.1.0) project(seerutl VERSION 1.0 LANGUAGES CXX) set(PROJECT_NAME seerutl) if(NOT DEFINED QTVERSION) set(QTVERSION "QT6" CACHE STRING "" FORCE) endif() if(${QTVERSION} STREQUAL "QT6") message("-- Compile with QT6") elseif(${QTVERSION} STREQUAL "QT5") message("-- Compile with QT5") else() message(FATAL_ERROR "-- Use -DQTVERSION=QT5|QT6 not \"${QTVERSION}\"") endif() # Find includes in the build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_PREFIX_PATH ${QTDIR}) if(${QTVERSION} STREQUAL "QT6") find_package(Qt6 COMPONENTS REQUIRED Core) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) elseif(${QTVERSION} STREQUAL "QT5") find_package(Qt5 COMPONENTS REQUIRED Core) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) endif() set(HEADER_FILES ../SeerUtl.h ) set(SOURCE_FILES ../seerutl.cpp ../SeerUtl.cpp ) # Set non-Debug build as GUI application. # Debug build remains consle application. if(NOT CMAKE_BUILD_TYPE MATCHES Debug) #Release, RelWithDebInfo and MinSizeRel if(WIN32) # Check if we are on Windows set(SYSTEM_TYPE WIN32) endif() message("-- System type is " ${SYSTEM_TYPE}) endif() # for Linux, BSD, Solaris, Minix if(UNIX AND NOT APPLE) add_compile_options(-Wall -Wextra -Wunused-result -pedantic) # -Werror -Wdeprecated-copy endif() add_definitions(-DQT_DEPRECATED_WARNINGS) add_executable(${PROJECT_NAME} ${SYSTEM_TYPE} ${SOURCE_FILES}) install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) if(${QTVERSION} STREQUAL "QT6") target_link_libraries(${PROJECT_NAME} Qt6::Core) elseif(${QTVERSION} STREQUAL "QT5") target_link_libraries(${PROJECT_NAME} Qt5::Core) endif() epasveer-seer-97076f1/src/build_seerutl/README.cmake000066400000000000000000000027411526321767600221600ustar00rootroot00000000000000Notes for building 'seerutl' with cmake. 'seerutl' is a test program for testing the SeerUtl functions. It is used for my developent. It is NOT needed for the average person installing Seergdb from source. # Note the single '.'. The CMakeLists.txt file is local to this build directory. % cd seer/src/build_seerutl % cmake -DCMAKE_BUILD_TYPE=Debug . # Debug release -g. % cmake -DCMAKE_BUILD_TYPE=Release . # Optimized release -O. % cmake -DCMAKE_CXX_FLAGS=-Wall . # With all compile warnings turned on. # Specify a compiler version with debug. % cmake -DCMAKE_CXX_COMPILER=g++-13 -DCMAKE_BUILD_TYPE=Debug . The above defaults to Qt6. If you want to use Qt5, add the '-DQTVERSION' flag. % cmake -DQTVERSION=QT5 -DCMAKE_BUILD_TYPE=Debug . Once cmake is run, then just build 'seerutl'. % make clean # Clean files. % make seerutl # Build 'seerutl'. % sudo make install # Install it. Another way to ask cmake to do the build for you. % cmake --build . --config Release % sudo cmake --install . MacOS may need help finding the cmake config file for Qt6. % cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt6/ -DCMAKE_BUILD_TYPE=Release .. Sometimes you need to specify a newer version of g++/gcc. Your installation may have an old version as the default. % cmake -DCMAKE_C_COMPILER=gcc-13 -DCMAKE_CXX_COMPILER=g++-13 -DQTVERSION=QT6 -DCMAKE_BUILD_TYPE=Debug .. epasveer-seer-97076f1/src/resource.qrc000066400000000000000000000125061526321767600177150ustar00rootroot00000000000000 resources/icons/hicolor/32x32/seergdb.png resources/icons/hicolor/64x64/seergdb.png resources/icons/hicolor/128x128/seergdb.png resources/icons/hicolor/256x256/seergdb.png resources/icons/hicolor/512x512/seergdb.png resources/icons/hicolor/256x256/rr.png resources/ABOUT.md resources/thenounproject/memory.svg resources/thenounproject/source.svg resources/thenounproject/assembly.svg resources/thenounproject/keyboard.svg resources/thenounproject/configure.svg resources/thenounproject/stop.svg resources/thenounproject/fortune-teller.svg resources/thenounproject/preferences.svg resources/icons-icons/gdb.png resources/icons-icons/editor.png resources/icons-icons/font.png resources/icons-icons/arguments.png resources/icons-icons/debug.png resources/icons-icons/exit.png resources/icons-icons/console.png resources/icons-icons/hide.png resources/icons-icons/maximize.png resources/icons-icons/minimize.png resources/icons-icons/attach.png resources/icons-icons/style.png resources/RelaxLightIcons/application-menu.svg resources/RelaxLightIcons/document-new.svg resources/RelaxLightIcons/document-open.svg resources/RelaxLightIcons/document-print.svg resources/RelaxLightIcons/document-save-as.svg resources/RelaxLightIcons/document-save.svg resources/RelaxLightIcons/edit-clear.svg resources/RelaxLightIcons/edit-delete.svg resources/RelaxLightIcons/edit-find.svg resources/RelaxLightIcons/go-down.svg resources/RelaxLightIcons/go-up.svg resources/RelaxLightIcons/go-next.svg resources/RelaxLightIcons/go-previous.svg resources/RelaxLightIcons/list-add.svg resources/RelaxLightIcons/list-remove.svg resources/RelaxLightIcons/view-refresh.svg resources/RelaxLightIcons/view-filter.svg resources/RelaxLightIcons/debug-execute-from-cursor.svg resources/RelaxLightIcons/debug-execute-to-cursor.svg resources/RelaxLightIcons/debug-run-cursor.svg resources/RelaxLightIcons/debug-run.svg resources/RelaxLightIcons/debug-step-instruction.svg resources/RelaxLightIcons/debug-step-into-instruction.svg resources/RelaxLightIcons/debug-step-into.svg resources/RelaxLightIcons/debug-step-out.svg resources/RelaxLightIcons/debug-step-over.svg resources/RelaxLightIcons/help-about.svg resources/RelaxLightIcons/help-whatsthis.svg resources/RelaxLightIcons/tools-media-optical-burn-image.svg resources/RelaxLightIcons/data-error.svg resources/RelaxLightIcons/data-information.svg resources/RelaxLightIcons/data-warning.svg resources/RelaxLightIcons/dialog-question.svg resources/RelaxLightIcons/system-shutdown.svg resources/RelaxLightIcons/pin.svg resources/RelaxLightIcons/lock.svg resources/help/ThreadProcessInfoBrowser.md resources/help/seergdb.hlp resources/help/StructVisualizer.md resources/help/BasicStructVisualizer.md resources/help/MemoryVisualizer.md resources/help/ArrayVisualizer.md resources/help/MatrixVisualizer.md resources/help/ImageVisualizer.md resources/help/ParallelStacksVisualizer.md resources/help/StackInfoBrowser.md resources/help/VariableRegisterSignalInfoBrowser.md resources/help/SourceSymbolLibraryInfoBrowser.md resources/help/CodeManager.md resources/help/BreakpointGdbSeerManager.md resources/help/MainWindow.md resources/help/DebugModes.md resources/help/RunDebugMode.md resources/help/AttachDebugMode.md resources/help/ConnectDebugMode.md resources/help/RRDebugMode.md resources/help/CorefileDebugMode.md resources/help/Printpoints.md resources/help/GdbMonitor.md resources/help/Skips.md resources/mi-python/MIEcho.py resources/mi-python/MISkip.py resources/mi-python/MIKill.py resources/mi-python/MICheckpoint.py resources/mi-python/MICatchpoint.py resources/mi-python/MIObjectiveC.py resources/mi-python/MIFrames.py resources/mi-python/MISignals.py resources/mi-python/MIStart.py resources/mi-python/MIMonitor.py epasveer-seer-97076f1/src/resource_qdarkstylesheet.qrc000066400000000000000000000117411526321767600232110ustar00rootroot00000000000000 resources/icons/hicolor/32x32/seergdb.png resources/icons/hicolor/64x64/seergdb.png resources/icons/hicolor/128x128/seergdb.png resources/icons/hicolor/256x256/seergdb.png resources/icons/hicolor/512x512/seergdb.png resources/icons/hicolor/256x256/rr.png resources/ABOUT.md resources/thenounproject/memory.svg resources/thenounproject/source.svg resources/thenounproject/assembly.svg resources/thenounproject/keyboard.svg resources/thenounproject/configure.svg resources/thenounproject/stop.svg resources/thenounproject/fortune-teller.svg resources/icons-icons/gdb.png resources/icons-icons/editor.png resources/icons-icons/font.png resources/icons-icons/arguments.png resources/icons-icons/debug.png resources/icons-icons/exit.png resources/icons-icons/console.png resources/icons-icons/hide.png resources/icons-icons/maximize.png resources/icons-icons/minimize.png resources/icons-icons/attach.png resources/icons-icons/style.png resources/RelaxLightIcons/application-menu.svg resources/RelaxLightIcons/document-new.svg resources/RelaxLightIcons/document-open.svg resources/RelaxLightIcons/document-print.svg resources/RelaxLightIcons/document-save-as.svg resources/RelaxLightIcons/document-save.svg resources/RelaxLightIcons/edit-clear.svg resources/RelaxLightIcons/edit-delete.svg resources/RelaxLightIcons/edit-find.svg resources/RelaxLightIcons/go-down.svg resources/RelaxLightIcons/go-up.svg resources/RelaxLightIcons/go-next.svg resources/RelaxLightIcons/go-previous.svg resources/RelaxLightIcons/list-add.svg resources/RelaxLightIcons/list-remove.svg resources/RelaxLightIcons/view-refresh.svg resources/RelaxLightIcons/debug-execute-from-cursor.svg resources/RelaxLightIcons/debug-execute-to-cursor.svg resources/RelaxLightIcons/debug-run-cursor.svg resources/RelaxLightIcons/debug-run.svg resources/RelaxLightIcons/debug-step-instruction.svg resources/RelaxLightIcons/debug-step-into-instruction.svg resources/RelaxLightIcons/debug-step-into.svg resources/RelaxLightIcons/debug-step-out.svg resources/RelaxLightIcons/debug-step-over.svg resources/RelaxLightIcons/help-about.svg resources/RelaxLightIcons/help-whatsthis.svg resources/RelaxLightIcons/tools-media-optical-burn-image.svg resources/RelaxLightIcons/data-error.svg resources/RelaxLightIcons/data-information.svg resources/RelaxLightIcons/data-warning.svg resources/RelaxLightIcons/dialog-question.svg resources/RelaxLightIcons/system-shutdown.svg resources/qdarkstyle/light/lightstyle.qrc resources/qdarkstyle/dark/darkstyle.qrc resources/help/ThreadProcessInfoBrowser.md resources/help/seergdb.hlp resources/help/StructVisualizer.md resources/help/BasicStructVisualizer.md resources/help/MemoryVisualizer.md resources/help/ArrayVisualizer.md resources/help/MatrixVisualizer.md resources/help/ImageVisualizer.md resources/help/StackInfoBrowser.md resources/help/VariableRegisterSignalInfoBrowser.md resources/help/SourceSymbolLibraryInfoBrowser.md resources/help/CodeManager.md resources/help/BreakpointGdbSeerManager.md resources/help/MainWindow.md resources/help/DebugModes.md resources/help/RunDebugMode.md resources/help/AttachDebugMode.md resources/help/ConnectDebugMode.md resources/help/RRDebugMode.md resources/help/CorefileDebugMode.md resources/help/Printpoints.md resources/help/Skips.md resources/mi-python/MIEcho.py resources/mi-python/MISkip.py resources/mi-python/MIKill.py resources/mi-python/MICheckpoint.py resources/mi-python/MICatchpoint.py resources/mi-python/MIObjectiveC.py resources/mi-python/MISignals.py epasveer-seer-97076f1/src/resources/000077500000000000000000000000001526321767600173655ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/ABOUT.md000066400000000000000000000242201526321767600205610ustar00rootroot00000000000000  Version VERSIONNUMBER   Seer, a simple and easy-to-use gui frontend to the GDB debugger, having many features. Copyright (C) 2021-2026    Ernie Pasveer.       [https://github.com/epasveer/seer](https://github.com/epasveer/seer)     [epasveer@att.net](mailto:user@example.com)   Icons used by Seer are the property of the original creators. The main Seer icon and other icons.   | Icon | Creator | License | | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | |Icon fortune_teller.sgv | Created by Toli | (License CC3.0) | |Icons Breeze Icon set | Created by L4ki | (License GPLv3) | |Icon arguments.png | Created by Icon box | (License CC4.0) | |Icon console.png | Created by Icons8 | (License CC4.0) | |Icon debug.png | Created by Carbon Design | (License CC4.0) | |Icon editor.png | Created by Piksart | (License CC4.0) | |Icon exit.png | Created by Nicky Lim | (License CC4.0) | |Icon font.png | Created by Dave Gandy | (License CC4.0) | |Icon gdb.png | Created by John Gardner | (License CC4.0) | |Icon hide.png | Created by ferdi setiadi | (License CC4.0) | |Icon maximize.png | Created by ferdi setiadi | (License CC4.0) | |Icon minimize.png | Created by ferdi setiadi | (License CC4.0) | |Icon attach.png | Created by Unknown | (License CC4.0) | |Icon style.png | Created by Free Icons | (License CC4.0) | |Icon assembly.svg | Created by iyikon | (License CC3.0) | |Icon configuration.sgv | Created by tomas.knopp | (License CC3.0) | |Icon keyboard.sgv | Created by Flowicon | (License CC3.0) | |Icon memory.svg | Created by mudassar.hussain323 | (License CC3.0) | |Icon source.svg | Created by kozinn | (License CC3.0) | |Icon stop.sgv | Created by andre.buand10 | (License CC3.0) | |Icon preferences.sgv | Created by blairwolf | (License CC3.0) |     | Styles/Themes | Creator | License | | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | |Style QDarkStyleSheet | Created by Colin Duquesnoy | (License MIT) | | | | (License CC4.0) |     Credits to kdbg, gede, gdbgui, nemiver, and many other projects for ideas and examples.     epasveer-seer-97076f1/src/resources/README.icons000066400000000000000000000140751526321767600213660ustar00rootroot00000000000000 The main Seer icon is from TheNounProject under the CC3.0 license. The .svg file was converted to .png for better handling of fixed sized .png files. "Toli" is the copyright owner, as mentioned below. Seer uses it under the CC3.0 license. https://thenounproject.com/icon/fortune-teller-3505303/ https://thenounproject.com/tolicon/ thenounproject/fortune-teller.svg CC3.0 seergdb_*.png Some icons are used from "IconsIcons" and "TheNounProject" and are licensed under "CreativeCommons" CC3.0 and CC4.0 licenses. terms of the NetBeans License Agreement. https://icon-icons.com/icon/GDB/132365 https://icon-icons.com/users/AmQJzv5e8DpITUWIRmGPz/icon-sets/ icons-icons/gdb.png CC4.0 https://icon-icons.com/icon/keyboard/122169 https://icon-icons.com/users/z1gHIAw5WHSQk4RJ0exyV/icon-sets/ icons-icons/keyboard.png CC4.0 https://icon-icons.com/icon/web-design-writing-coding-development/220538 https://icon-icons.com/users/14h9fJJJmBr3Dm13gYSpS/icon-sets/ icons-icons/editor.png CC4.0 https://icon-icons.com/icon/font-symbol-of-letter-a/73556 https://icon-icons.com/users/2LUKwJe4QDNsjuhkS98IX/icon-sets/ icons-icons/font.png CC4.0 https://icon-icons.com/icon/setting-configure-repair-support-optimization-google/83447 https://icon-icons.com/users/Nixd2U1fkolfZAGKcPLGu/icon-sets/ icons-icons/configure.png CC4.0 https://icon-icons.com/icon/setting-balance-equalizer/152217 https://icon-icons.com/users/67020lqBmzmzx0F3OH2GE/icon-sets/ icons-icons/arguments.png CC4.0 https://icon-icons.com/icon/debug/215819 https://icon-icons.com/users/7dBLqleqakUowFGJkWLXY/icon-sets/ icons-icons/debug.png CC4.0 https://icon-icons.com/icon/logout-exit/176185 https://icon-icons.com/users/ah334sOoBVVE7GXS94Who/icon-sets/ icons-icons/exit.png CC4.0 https://icon-icons.com/icon/console/5091 https://icon-icons.com/users/Vn6TUStZ7Ng5JKLU3rRHX/icon-sets/ icons-icons/console.png CC4.0 https://icon-icons.com/icon/resize-maximize/175765 https://icon-icons.com/users/sr18GsT8hXb37mrJn4kOU/icon-sets/ icons-icons/maximize.png CC4.0 https://icon-icons.com/icon/minimize-window/175768 https://icon-icons.com/users/sr18GsT8hXb37mrJn4kOU/icon-sets/ icons-icons/minimize.png CC4.0 https://icon-icons.com/icon/attache-attached-attachement-clip-complement/113448 https://icon-icons.com/users/NXDGlLPTpYrqHz13UzsZ4/icon-sets/ icons-icons/attach.png CC4.0 https://icon-icons.com/icon/delete-remove/175783 https://icon-icons.com/users/sr18GsT8hXb37mrJn4kOU/icon-sets/ icons-icons/hide.png CC4.0 https://icon-icons.com/icon/face-glasses-sunglasses/107950 https://icon-icons.com/users/7VZI9qW3el29z8Ka5fjmo/icon-sets/ icons-icons/style.png CC4.0 https://thenounproject.com/icon/asm-file-document-icon-2598539/ https://thenounproject.com/iyikon/ thenounproject/assembly.svg CC3.0 https://thenounproject.com/icon/configuration-1115171/ https://thenounproject.com/tomas.knopp/ thenounproject/configure.svg CC3.0 https://thenounproject.com/icon/keyboard-key-4571629/ https://thenounproject.com/Flowicon/ thenounproject/keyboard.svg CC3.0 https://thenounproject.com/icon/binary-data-search-4065152/ https://thenounproject.com/mudassar.hussain323/ thenounproject/memory.svg CC3.0 https://thenounproject.com/icon/cpp-file-252779/ https://thenounproject.com/kozinn/ thenounproject/source.svg CC3.0 https://thenounproject.com/icon/interruption-4417639/ https://thenounproject.com/andre.buand10/ thenounproject/stop.sgv CC3.0 https://thenounproject.com/icon/preference-2331720/ https://thenounproject.com/creator/blairwolf/ thenounproject/preferences.svg CC3.0 Some icons are used from the RelaxLightIcons set. Licensed under the GPL-3.0+ license. L4ki https://github.com/L4ki RelaxLightIcons/debug-execute-from-cursor.svg RelaxLightIcons/debug-execute-to-cursor.svg RelaxLightIcons/debug-run-cursor.svg RelaxLightIcons/debug-run.svg RelaxLightIcons/debug-step-instruction.svg RelaxLightIcons/debug-step-into-instruction.svg RelaxLightIcons/debug-step-into.svg RelaxLightIcons/debug-step-out.svg RelaxLightIcons/debug-step-over.svg RelaxLightIcons/document-new.svg RelaxLightIcons/document-open.svg RelaxLightIcons/document-print.svg RelaxLightIcons/document-save-as.svg RelaxLightIcons/document-save.svg RelaxLightIcons/edit-clear.svg RelaxLightIcons/edit-delete.svg RelaxLightIcons/edit-find.svg RelaxLightIcons/go-down.svg RelaxLightIcons/go-next.svg RelaxLightIcons/go-previous.svg RelaxLightIcons/go-up.svg RelaxLightIcons/help-about.svg RelaxLightIcons/help-whatsthis.svg RelaxLightIcons/list-add.svg RelaxLightIcons/list-remove.svg RelaxLightIcons/tools-media-optical-burn-image.svg RelaxLightIcons/view-refresh.svg epasveer-seer-97076f1/src/resources/RelaxLightIcons/000077500000000000000000000000001526321767600224245ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/RelaxLightIcons/application-menu.svg000066400000000000000000000007001526321767600264070ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/data-error.svg000066400000000000000000000010241526321767600252020ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/data-information.svg000066400000000000000000000006661526321767600264110ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/data-warning.svg000066400000000000000000000012271526321767600255230ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/debug-execute-from-cursor.svg000066400000000000000000000007131526321767600301500ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/debug-execute-to-cursor.svg000066400000000000000000000007161526321767600276320ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/debug-run-cursor.svg000066400000000000000000000006761526321767600263610ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/debug-run.svg000066400000000000000000000007011526321767600250330ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/debug-step-instruction.svg000066400000000000000000000103521526321767600275640ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/debug-step-into-instruction.svg000066400000000000000000000101031526321767600305250ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/debug-step-into.svg000066400000000000000000000073551526321767600261650ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/debug-step-out.svg000066400000000000000000000073561526321767600260240ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/debug-step-over.svg000066400000000000000000000073451526321767600261660ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/dialog-question.svg000066400000000000000000000013301526321767600262460ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/document-new.svg000066400000000000000000000011661526321767600255560ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/document-open.svg000066400000000000000000000007301526321767600257220ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/document-print.svg000066400000000000000000000007621526321767600261220ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/document-save-as.svg000066400000000000000000000022331526321767600263200ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/document-save.svg000066400000000000000000000014241526321767600257200ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/edit-clear.svg000066400000000000000000000012271526321767600251600ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/edit-delete.svg000066400000000000000000000006601526321767600253340ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/edit-find.svg000066400000000000000000000013141526321767600250070ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/go-down.svg000066400000000000000000000007661526321767600245300ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/go-next.svg000066400000000000000000000010261526321767600245250ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/go-previous.svg000066400000000000000000000010311526321767600254170ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/go-up.svg000066400000000000000000000006071526321767600241770ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/help-about.svg000066400000000000000000000012531526321767600252060ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/help-whatsthis.svg000066400000000000000000000014131526321767600261100ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/list-add.svg000066400000000000000000000006711526321767600246520ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/list-remove.svg000066400000000000000000000005431526321767600254150ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/lock.svg000066400000000000000000000010561526321767600240770ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/pin.svg000066400000000000000000000006061526321767600237350ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/system-shutdown.svg000066400000000000000000000043071526321767600263460ustar00rootroot00000000000000 image/svg+xml epasveer-seer-97076f1/src/resources/RelaxLightIcons/tools-media-optical-burn-image.svg000066400000000000000000000020061526321767600310350ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/view-filter.svg000066400000000000000000000010321526321767600253760ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/RelaxLightIcons/view-refresh.svg000066400000000000000000000012441526321767600255540ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/flathub/000077500000000000000000000000001526321767600210125ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/flathub/BUILD.sh000077500000000000000000000006721526321767600222150ustar00rootroot00000000000000#!/bin/bash # Build the Seergdb flatpak flatpak uninstall -y io.github.epasveer.seer \rm -rf build-dir/ repo/ .flatpak-builder/ seer.flatpak flatpak run org.flatpak.Builder --force-clean build-dir io.github.epasveer.seer.yml flatpak run org.flatpak.Builder --force-clean --repo=repo build-dir io.github.epasveer.seer.yml flatpak build-bundle repo seer.flatpak io.github.epasveer.seer master flatpak install -y --bundle --user seer.flatpak epasveer-seer-97076f1/src/resources/flathub/README000066400000000000000000000041171526321767600216750ustar00rootroot00000000000000$ vim com.github.epasveer.seer.json $ ls -l ~/.local/share/flatpak/app/com.github.epasveer.seer/ $ flatpak update $ flatpak install flathub org.kde.Sdk//6.10 $ flatpak install flathub org.kde.Platform//6.10 $ flatpak list Name Application ID Version Branch Installation Flatpak Builder Flatpak org.flatpak.Builder v0-Flathub stable system ... $ flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo $ flatpak info io.github.epasveer.seer $ flatpak search gdb $ flatpak remove io.github.epasveer.seer $ flatpak-builder --force-clean build-dir ../src/resources/flathub/io.github.epasveer.seer.yml $ flatpak-builder --user --install --force-clean build-dir ../src/resources/flathub/io.github.epasveer.seer.yml $ flatpak run io.github.epasveer.seer -s /nas/erniep/Development/seer/tests/hellostruct/hellostruct $ flatpak run io.github.epasveer.seer --gdb-program=/app/bin/gdb -s /nas/erniep/Development/seer/tests/hellostruct/hellostruct $ flatpak run --command=bash io.github.epasveer.seer $ flatpak run --command=bash org.gnome.Sdk//46 $ flatpak run --command=bash org.freedesktop.Platform.GL.default $ flatpak run --command=bash org.freedesktop.Sdk//24.08 $ flatpak run --command=bash org.freedesktop.Sdk/x86_64/25.08 $ flatpak uninstall -y io.github.epasveer.seer $ \rm -rf build-dir/ repo/ .flatpak-builder/ seer.flatpak $ flatpak run org.flatpak.Builder --force-clean build-dir ../src/resources/flathub/io.github.epasveer.seer.yml $ flatpak run org.flatpak.Builder --force-clean --repo=repo build-dir ../src/resources/flathub/io.github.epasveer.seer.yml $ flatpak build-bundle repo seer.flatpak io.github.epasveer.seer master $ flatpak install -y --bundle --user seer.flatpak $ flatpak run --command=flatpak-builder-lint org.flatpak.Builder repo repo $ flatpak run --command=flatpak-builder-lint org.flatpak.Builder manifest ../src/resources/flathub/io.github.epasveer.seer.yml epasveer-seer-97076f1/src/resources/flathub/icons/000077500000000000000000000000001526321767600221255ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/flathub/icons/hicolor/000077500000000000000000000000001526321767600235645ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/flathub/icons/hicolor/128x128/000077500000000000000000000000001526321767600245215ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/flathub/icons/hicolor/128x128/io.github.epasveer.seer.png000066400000000000000000000122351526321767600316700ustar00rootroot00000000000000‰PNG  IHDR€€i7©@gAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDª�#2 pHYs``ðkBÏtIMEè06KFî �IDATxÚíÜw|WåÙ?ðw 4²A†¨X'CG}¬ŠV«8j‘>î¶ZŸúÐZô§×ÏU­Õ¶n­?«UªuÔª8ê®"V+S�!(2B˜!ëúý‘Ã×oBBI}½òÉ?¹Î¹ïó=×uîqÍ›´ -hA ZЂ´ ÍŽÖzÈÞÚ/ÑœØÁÑz¦¨l7ûÌ�Rt¦]nÇ­ý’M‰ë”{Zë„ÚÞDáq™ ÝÛá’æ}¥Ì-Äf�¡¯Þit7™L}ãP†V2º§.¨Hµ.0Üàÿl ö²¿Ù5EOA;'T¹Rä¤Þ¡§|eæ¦ZŸã/îÕù?Yõ4а=]±\{%TåÈN�€>2¬õyBµ3 ¡ü?YLÇ0Û'ô\˰OBUT;c¹% ÕϼayBç8Êá�¿g4¶º¹Õ(y µÄ è€ýv·]"€ ´JÞ!Oo,V˜´j;ë¼’zò±žò¸~Ûº¾ã—npJŠþ»ò�œ ó5f¡{2"ÊÌRjª G[̱ì`(>ñQòœ?·� %�-€ÆF „§vû\Ï sí’ÐC½ãæÔéàPS}OqŸAÉÿ‡[#Ü’ºwžRáÖÔz± ãr!ü:õªg ¥ŽNÝoS¯y<ÔzEO¨n& sì–ºßJù[›Õ�ȳsê›ÒÉ»ÂR‡&t{·ù½NUzäj¯·=ík°Aúë«›¶U¦ckÃ�$'¡.Âå©»YF[äÆ&^Âë�_YäÖ”~Ç ÖÏk—ÐÉhÈÐÙ·]àN/ù·Ï|¥P‘"Ë-2Ó8�»Ö©vßäËv3Møwš’üßÉ/´ÚÚ¬C–1B©Ñ²’+9 SÛôð4Å*±Ù¿2_zÍ•Ò&Õ·£7:;El¾°05A¶�±¨ìï1»Yçb÷%Wvu­n°­ìç4ÇÚ%™ûk|i�ùYn�òl¯‹zé©SòU‹|èIc-½t2%Ùz{Ü�ֻȃ�ü)·G[$,srêJ– ä8Â_¬B¹yþê"ß¶cÚŠ‘Ž|»:ÞõÞJzT˜ær½ª´ÙÎ!ܼ­™Ñ#¬æ;(íÚR$„BÏ9ÛΛ¼tð´GÝåjç:$ùúm vµIJ…0Õ… R=NV.ü-íJ–a.°Cs3œã{NM[ø2ŒT,\“Ð.õ¹–ºß!µ|óW™ÿkœŸv¯ƒ3¼©D(÷JjOlŠ7õMµÊu™5Â7·Y¡Ä}º¦®´ò 1 4V…°Ö£ÜÌfµ¯WM6Ã+”(ó‹Dxû¥¾hëL„°Ä¥Ú"CwRýÛù� Âinô5E¯',W" N3G�RçFÕF]ìd ã��¨È§ a¾[í�®®³L(7¦Šo�NþŸ áSÇ47û0À«Bø4¥éC+£ ëÝ�æüjè“?Tža´NøŽ÷…0ξ©V½<+„IÜìCwÙ ¬tAr¥µm;‹””.Îñv²Žs4zxX¹0-µü¯Þ´çÖbrýÌá¹Ès³2aV£ ÉçøHË]¡µÖ®·^˜•ˆ`°ús•M2Sß´5©‰�¡ Úfv¤û‹lW+¦TÙ · =ܪH(÷ˆ®2]b­0Ý~ �Ü*mo´Ðëº4­N5Ñi3ñkœo�0½‘ݘ™†™.„—õÁ(ë…÷ô©Ò*Ïé& aNµ;�Ž;…°ÈÍi®N8ÊaAãèçÕ°·×’ùÞG¦ë” O¤L-ú‹õB…·ÕÔƒ}nüÏ‘á\/¹Î¡© G%z™.LÖ£Y�á!\…6W§îu1Ü“¾J,Ë�ýÓmŒÂ*ã\ë�$´ÁÅB…‹š…}èê_ÂçöÖÆ«ÂÌÄ@lB¢:ûÀ¨Æ_�2œi’u‰|WyÅÎèàCaŠîßà‰™ ìdw»éÞ ÷pÅÂm8]‰ð¿à'BøÂÃNhºÍ°ƒ¡~oŠ B™¡8Ɇd@6Yöt¡ÇL0ßb‹|ê-¿3¬žJl[/•¥ƒ„·m‡n®r±=RŽÙ&D'ºÍ(ÛÉð'a‰þ è�mˆ‡,¬Á¼Á¿]a§zÂ<#ê©V_%,K&ag#ÜâŸX©¢1³�2]g‰YÞò°«�i�lä{Kx¿^¶¯×ùò´w[2Òÿæù©,=Ýi�°ÊåõRo‡Z¯ÂÈH,ÕH¢‹ý ±�ã™*¯ºÔ±èc¾ð@=úïc¼Þ6Ýý]EƺÂÎu“ñJ„ nÒJ–³}!”¸¥Ûcå[ü~«D¡ižu½Ø»1C'{»Ê#Þ2Ër%V;‡Y+ü¼ìW:¶×müYï::-V°ƒ™'”ºnªPæ¶´ÈCÍhãŸÂsrÐÞö×9SnddÈ×]Ç;B.ÎP¡Ä÷êèÕ×x¡ÂIì¦2Ñá•j/8ÔláKûƒ�&en¨ƒ� �“š?2ÄeÂÊTFGÍèâ%!ü1± :ø—07‰g;Ðζ{Òz¸uÂ=ÉRÛÏ$¡¸‹ïkÜ Ì¯—þÐÈø­°0-Hµ)òÜ'„'RÊé1Ö§ ˜|7%Kágέ½ ÌN�ŽA>V¤¥ÙÕ„‘²Ü!MžLó€0{³™½#•o¦µ¹R(Lܦ•“a�²´�¡°>-�f¨ÅÂ'öÞ̯œ-¬N<ÑCÜävwºßCƸ©>š@}VÊÚQ–,Ù²„w}"CJ•ÕÚë—É1Ó/’?ôÂW>G+'Ëö±Kê2]kfX¯ušiýŠ+ýη\çlEµüN±�%íüºšK~‚§CC<©À׃j¬ï+–‰µö¤+¦˜žº’!” •Lók�Ô. x+WÕñòOKõ6H÷ZP!’$œbïé¡\¹2eÊÍóqÝÌÕGeJT¨P!T •Ù˜æZ»õõ¸“ê8ç¹'¹Vb{í,·Ö ;Öƒv×Ne1å&­*±½kõVá.ŸÔú;92U(G©ÑîÊ“¿uŠëÁ]=�eÃo¨#jpâl¸[X°ÙÕ÷Û>¾JÛ**'ô>K©V¯%³õú*;K®[UT‹lŠóë±5 n–UI„ÚgZ-Ì5$¡X*ŒIùÏšë÷$ùã=LÆ%[f¶_Ù ¼_G¬ç aqj+mF\$¬sÄfÛdºB‰0ÃÁ ÇcÂZg$÷sõÐ51{rÜ&Ržl—X'̪3Ôv§0ëù¤¶')Ω£U®[” 3Q`‘°ÈªY{m]m½ð¶NÈ5Ú:a�£êx~Žç…wµEO¿u·QN1XïÍN›o„]ìï‡~í^±¯ÂÍuöËw›2a�á2ðk„"w9P�­tvœç” s„þ DXà¸:ŸÞÉáÏ2|�qT¦ÈgÆûaã1¿«ÿë9ÓªÂèbšðb=ŒÖ|7*Š\£Zš8F>ô‚—LMœ­“ŽþÆ aVšBT;ö³B¸ ðºÏ­N²KÂØÆ3‹þ�fgú؉Èö”0¯ZÞNÍÈ1Òr¡ÂK‘aˆ±ÖV1±—¸[mýÔ\!Œ¯g˜ý<¡Ø± ÕÎÎ6Üeî÷T�†Zp®y¦û»�°_*ñùaƒëùŒãoÏRwè¯Àá®ó¬w¼á1?·�†yU©Pâáz‰•  sklݨþá,=uÙd@}[‘ð‡z?e÷[-„¯üÕÙÚIO=íê0W§8 »Ÿ_§`#vô‰ðTSyêB�ñÂTÝêÝ#Çñ^Iò  ŸúÈd R—/ýÞ·ð§)Ize']›¯œb=dªŒÑ–:½A}Û:Á£>SRe Xc’ h Ù>÷-ô5Î ÷9©¡ACe–mÇ;Q{#½d?/ëèy§5PëÎÒ[?{é¥�rËÍ1Ù4Ëø.ûyI'�8W¹C½,¥æxÛËÞN_5":9Õã¾L¾ÙEÈñ„°Êw¾ñ33¶`ØÞ.¬Mv€Uô�\Ǻ¬)6Àtd:ËƒŽ¬2Óöp¤6bŽPîî& U6Q÷'åS£-tOÓ—HÔ…cÍT쨖§ y.¶\X›ª&k6gƒ°`s$ÃBQø*ò�ƒ¾¡ ŒðŽr¡Â2ae-õ¡'˜d|ÚéÍ„Ì4©†ÈPs…'ìåÞ¤tz™G}·AéËvr�wó{±kœ´Ù(D—¦>n©æ—ìS£ûéG*”�lG{>ñ÷­3Þ5†èXÇrÕÊNNq¿ÙI¢ÐÃ!Ï?„ÉM]·åÈ3V˜‘Ê É÷=O'ç„Õ>öˆ‹g€^:ØNmm¯³]h¸ë4ÝV¥":a¥w\fï*¾ý¾æ �mk'TÇujËßîàWyÑl«“á]ý¯ÜJ30ÑL_Z#ø´|Ýìn°ƒí“Œ¨b“=ãY³ü¬fäÙÓw¥ÊW_j©ù>5ÓŸûJ‘uJ”mÂD–y¶ÓÁŽv±»=ì¬K’öRj®·õø]zãFXP. ôEÉÚÁt‘þ©ºÔL9Ó¦™Lm¸‹»ik’kwÖQN“ ²Ç%:ŸxŒËM~ù�x›RîwáUÔægQ¤9ô4¹£/EÎô|“½û¼ÂlÆøÝ[ÓŸóLDϱâmÖPÏ�ÚŠ "}aõÞF®:\Jž(Ô¹&Zÿ:¬é£LŸàð–…xWäõ?“Ô1"õ׆»àª b™"е„;MîxF¤?Yéos;¥hh6m:KòÈW¦ Wpp§ -ƒŸÐŽM¢`ÿ†.´v ^qr¥¿K2�°œÅÜjW¼)Þ2× å<çy×1Ï�gÇ�NCšÑŠæ4&“š¤’@bœ_¯QN)Å#ŸCìc[ØÌVvsÈÐÔÜ!�èç<ÿ—ËLUÄ—ò®ØE|�Aá-òÈ ±Ø›âfî¼€Cb€ýÑ'ùÚA#Îgóû)¿öí(!‡ÕÌäq.¦©©Ñ˜Švì¿}Ù´[ud­¸£ÌZ"ªxVZ=�6-î^•$ì =>-‰ÎÜÍ'l¤ÀÏj7;ޱ™Y<@Wƒ–AF ¶;ïßJ;“ôº|+=sšÇg�€¸BªªBî3íA­XïµÄÓ™‡ùŽý!¨xýq�ŸyŒ®¦{`çqŽ¢qÈt�Ï$éI‹hîw!2d€8Fñ�ó3Œ&w b"©ÀlqÈ�Ú�ÞôåL�FÜåã(ùäs„ŽQB96b‰#‰RI%…D�îrù•YÌg»!%ž´f KLä†û+ö·q=ËÂ]à.DF€T^áñW6·0ßp�ƒ 8‡Ý|ª3Ò°s2×rmÝTÝ1ö³ƒMld»É!—£SJ™Ó7ÀF âH¤µ¨OSZÒŠæÔsco¬±‰Ù|Ì*EÄ>¼'„¿|†š6n Ôe¶4L®ç4Ÿ~åàL¦�m:h²�Ïx˜ hIŠŸM=�FtgSùCÒDÊÇ~Þã\S“rªð÷T„ᅥ-X,ð2“í]vÎà˜TNKÃÅ4 Z l£6Ýy„où×$ŸÃÌ §Ç<êJû™Ó-áÏ3:ó·T\sM¶[\hÏ«&•RÄJž£‡PÉxÆ) ánî`Ws!§Ó–z$›öÑD:1œMFƒC¼åÁòç éÎ¥ÜHÒièÃhr ;¥"{ÃM¡Ôa[ U±�¹ÊO¾óÙæüe9¥#—=¬ãg>à.3Õ×§pÙbÈyO›úÄòµ¸g;g¹}“¾,a3ïŸ(~FIn„« \ËAQh{LvëcèÃBÉJ âØÌX²üðc™éqõÿ¼Û§µäAVR¦ûÅr®6i®ã�©G¸ÁÍÓb¸CLc“ª¿„`çz~`÷¹ÑøÜ%´» r@c&�«+ú�£Ÿ"`6a”nšÇ >ËÔå]e*[ìqÌ©&¸N*b�-\çã¬×†ÏtîB.õa“ÆâH$‰Tjшvtãj†óÓyLêlÒhqŒ…ܦˆš§ñ‰0K«8æqŠ×œ›+z�¹ŽdQ†4ÞR*2—'=Š„è%ÙâV(ažÞ{•ý€ÏwJþ¥,ãV§õ?@·JÎèЬË<æÐ‘_¤»Ëù rLD*)<Æaéã˘îqùcç&ÉÔJCcQˆ›žQÞ@C£„¹B’ûÛ1ƒ)=‡an×ÝøCyÒDõÕ6ú±Q)Ì¥n×Èq<¤(_ ˜–¾R‡—ÙehGx_ì“y€}Ê»Ž2Õ&\)ôw=åf‡±Z£³nPÝÁ &Ò@Ï+³ë.n Á¼ì´çqV4Û¸OZ¼õV—¥üO8’G Eá}ˆ»CjµEÈä5¥rÑGwG*¯("ã át>4ànVêA)_HKÆVÌRf÷wtöK™¬©Ù ÷…ñÜ£hóUW«T&)ââ{àð H•x\y“›jòª²º_i.Û¦�ÑÄ ‹ �z£¥ëIL”ª¿œ÷!Ld /êìŽ 'výœöA.OºôÛLƲ„éê1‡¦\D§azhËL )e‰DâÇóÒào6“†6z0O§›øJì]Äp�¢²ž¤¨•l¤x¬Úó7EüËCѯŒóªß®Á…ô•\²í<,I¥Œó°o^¤ó{”&°BUØ"-wKù¯�â«�îÌSÈ:„û#ƒC/¾d Ï{5î�q³´ð+e\„;R�­¨t4¶aÖÆi(äžÖˆç¹¨ ß à²äÝÈõΓtë庡32QŸÉÊzf�p µq�$ àJ�ÏIàzÃåÒ“}üD_eŽ\Éí^5^mÙQ¢!‹ç~Å4m¿XÞÅð˜´"ØèÁv(‹‚{ â(âK²ÂýiÁáLEé[¡>íëAï•ÆçÒÝßF•~¼¯¢ßÛOçõ^‘®gº‡Q—G zÆ¿¹5 F?/ˆã)]Ð(àsÎ5•�m<-©XþŒºÍÑž¬Q&‚ãÜ…Šíшooú2:ȉ¨*ªá ³tC[…!e'ý}$ÿ¿=Â4špš2‡o¡»ózK‰9è¨Aû7N)›2лz™†%Ñ�Ÿ¥n…]õ¡o ‘vŒaá~éÑIú �UB·q®´\\¯ÐVÚùTÑ(Þ%r�ŸÈ`°nO_ãsieì�œ?5¦˜Fñˆd)fbs„uÐ=’0¨RVÝé•�ð¶)çqµACFJ\ßKâàåÒÚ9MÂýªA¡;›¥¯œàlæ‰L“F¸¥û“y˜E|ÉaÛé¬B´á%ç`X,)F2Y"É—„û%ƒÆe’2§P„«h#9‰ýE3åÉQ<æù §1žÜ*õÿG¥3¶Z@wJ‚ï6º8¯Þ(]1޹a�\ɹ‚ÆŠj®+\B44¾vnf%H�jþåL?žWŸÖ®1L–†ËþÁ?0BP[â)ãAçÕSÙ!®ÎðiØO¦XË>«žvÃÝœ®"ŸD{&§I#ÛN¡Ô}L\Ë÷bb£w²@ÚPz-¦G;ç3ž§9ǧõl¬$ï÷à>�¸CZú�/Ö@ÒÌv;¬×à|^g‹Îøì—h˜.wöè|–1Ú«£öÙ’öïÕhhß~!‰O$øÕΫ· óñ£&¡nì´å~‘<]Ç+‘/8Æ0Cyå<–0гÝXôÄðޏs—Þ4чΒ»û"§ÉXMJÊ0uÒkÀ«Šƒ¼¬>Ÿ îã1|hòòy,áºFƒ,ÉŽþåp¿z%a¤$ g»IŒ¹ º]чºöP×ðgD‹¦àÅ9B>rù�{”ÏxA¤í1ÙªÈqÈ5V:7¸k±TR{»&>£Ëú~>g`t§´q6“X놛³P¢Qo"ì…4Þ¬ÒùßN* hKgº’E{š�^‰ö·7в(g°óÚ0!Þí”¶½ãùR”H1«E—hé÷z4 o³É°¨ñª¸çva/”WEá•ì4äFð‹ÙÀr˜Cìc ËùŒQ\EËJ`ê©Á÷âëÇ9¯5–< äØÅg±œ£dó1×Tªûk•ÀNS2�íÊbf¸35‘¹âÚ7U°¼©OÞe½GúØb¶3‹¡´ñxÔÏ©.a ¸æšþ)"r=ºÑ®:m ÅЊ[™Én ÉãcaæÕUXÑ•q{¥¾��SÍÅw×ÓQÎ6Þàœ¾ñ g ëxJ2ò:]Ð]‰Jã?K;zs†ä#àÒˆmÒ팅6²xÍ ‘¤ç#—O¹ „B2•U¼<Ž ø©Q‹T)Ô›•¦ÞhÉ‹n*¿œ|ö²… lb‡Üˆ¬yL÷âÀ îù¬ò‘T¦.ß³vRü͹hA=ËÉ ä“˜Á{ù›¬a+9PŠ�xÒiH;²èLS¥Ï§2€^¼Ékì­„7ü‘ÝN¨6tâ»JÈ!‚ñÑú×KNa¡C'fzõaæ1ŒnÎqo*æÝÇ.ª„Q*Nr$íão’¨Ú…axF€8Éái©I€ö`Ÿ~#�Ñ\¹¶�/˜ÎïOšÑ˜Ú$RF.{ØÆ²‹]̦W1�ŽR•ŸÉ‡¼Ê’ú`PÌ÷ÂW¨;Éu{guhF;:ÒŽLÖ1ZÄLŽR4D¯eÜâg×c’Î ý o�å\ØÙiÇý|Í6ŽJ‹ÓrXÁÿ¸D(«ðIMU!5̹£f±Úgñ,‘&ô`(ÿã{¶(›CßE ·4�D§Ñ˜T¯«è>s~ÊÞê©>¯¹œ+\¬³xÍ„éÇuð ƒDá¶d¼Ž™ðïS:¤ •p™¤!¨xÓ—øNWí®#§ äù�ºLã‡ØÌbfðƒ9ŸÔ55ñxJ|Ê/>�ÄùŽ‹tÌ;¸WÄ­ÍS>-KøVlÐØé-­V44þehH§M׿ÏéêÉõX[)rS�xÀðš…ìc ó™ÂN—fÔXIø™x†:ظQç«?O :щù~èöñ€h¸uyAá);Ê“!dõºI¨Ã”„Ó‡<¼[;£òˆÁk‹t¯ä�)¢”‡LˆáÅ ñc$fž^†UÊn–2‹øˆù¬5Ä(f¼PZÅp­BkW„�‘:g )`›$¶Þg(¿r±–Ù<Çõœ™f!7{Qµ~-VØ]ÄÌzØ-[°ˆe„Âɳ‹›%j•st ÿ9Ì`m¨�v¨ÇÙ<Í*Å™½œ‰RŸÌâG%mJˆ¸êð—Y\b-YæÌ'—˜ÃXn¤+õ"{‡ ‰Gù‹ Ž Ç�bP½F쮉x,�*¹þ¥ì-ž¬øìãCÎt3‹gr�ÒÓKyBgò�²©õvHš€Cš‡H×[p/Oq gÒ š6„kÓ� Ìs|ĶpXŒ b'\vù6VÀ1<¬TÿBÅ´,]¡dÞÍ`/9¶WXþrN�ŒW”KSL‚Ùû×®à‹!­‹0#†TšÐ•¾ ç¼Áµ’ŠÕeûõ óQIX4æéüê‡KÃúf71½UÔdŠÔÓW*Ž* <%5¶r^ Á6ö`ñ¼Ï¢ŸÌÄ3O|ò#A?í&Eô›­ó+j+¹iîõy Ÿ&ùïh<­¤ÅòˆdQPʳAÏË �È’ê/d»7½òÃ\"…lÖøÚ°:þ¯$Õßmòû8j�l"S7‘"“lÖ…£qðˆ4 ro�ßpªpŒÙ]¶�¢‰�É éÔ“²Žþo yI‹¿/u|;6ºð sXÆ/LåzC<ò+%Üp]Z,OH²ÀAú†¨<öF)N@è \§Å�ÕXáç[d6j€XmäéšZ:Ï*¶Ë%üÈÙÊ ]ÕOme»ä¶ú’i­$Q±„ûü;‹e¥¬oÉLö�ÃArɧ€BŠDÌó2VF®#� ;18ˆ%Ž8âIÐV^+ }¥vÉ4‘H×JyÜÍæs/±\S¥ë;$ñíyú2FÚòý]]N]Ÿ¸Y¡Ÿ-ùñíÑI¾——k2*®Ú%Öóã¡©®PMvzs ©Äà Æy8œÿ-âk¦Š2VTX)åäËC‚rf0ÁÍSÒÅTs@ ²€DÖ:�QÀçе~3qP¤ïAs.3ˆ¥Ì$�…<ÉD§ˆX�Q\Ç>¿¿G£Dú¶ãHðºã_ {@å§C¨@¦Šp Fô¦œÉÎsWÕÄôd®ç9¼Â7÷ʼnœŽQ*®ÚŨSÈÏγŸ)tnð&(³påΞçVG7ƒk„‚©'—05€/rU£«l ùCÐLš¡�9¡¨þP5×z¨~ppo:«ÁUéö€üo¶°„Ë�ç5éÏŸR’Q*rŠ•ª¯\4˜xÚ;›@{±?P¬r®&Tâ¶°Ï—ÌÆ×²8 Ò“»„ëì%28;¥”QF)¥”Râü—Ï—|P^„j(ö’¾O ¡%b`uÔrE''“ �»ø‡·ÜÜWâ¬ø ’¤qb­óÿv¢�•tá!¡ Ìf·ô„ºâzž›Fv*/ ‹þ£<ˆ¾Ç& ür.Û¹�úÄPJ™ýÊ�G©4¦Ez*²µ|”SÊïÒJúJ±C¸6`÷Ç!B®‘íÆ±Ê¥bݯD–9 Š9 X1LPžð†¸>Ñ4‡† Éóø;SŒÄ"rKeU�{„jø™¾\L=J(Öý+!Ÿ•ìwPæÌ5!à�î÷Ès}^fk ÷ìa¯`äèÄŸâúŸÌà>çy¬"õoçé¯ I\\oò5xA²;øŽ1öÊ¡¤. B/EèF¾X8µ ø)õ �M4q2YÍ ¥¡70µ<¬³´ë%Þ3ׄ¼*žqÒ¦±§@Þ�,TÚE'F¹SD¸µÃAùÝuQ¬wfš(•†ŠÔ}:en3¦K“ˆ†Æ?\¯ì Ú¥ àWƒ¾ÂÁã!Ûª%çå‹€SÕÍ„ëUõ¤Ë%} Æ»g‰6)㺅\}™Îjv°™Ÿx°+q–ÄöûŒ.ÍÎý’M@õMEyüíÂ|C-)Tä  Ÿ5LªˆrÞÐéÒemZ.W~CšÓÈ$0KšdH¶G!+VùR®ã‚´Ùë,ì‚7Wš\/H`�(¾'ƒ|–ƒ§%)¾œÉº&ð’Ä¿Fø#{ê³ÒfïDe±jç.Å„|ZÐNZ‹Éè·Ètø 5l¼+Šï� -Ü™ cå¼¥Èõ6ÆJ•µÐÄYÜJãÊ&ÅHÃÁ¤Þ¯ñe‚º¹ö&¾PÌËNâz.#‹†¤T7ͧ$é=x£ÊÊμÆGÊÖO#~•Ò~WXùÌP“1Êü.›j'ò´Â04?$�-^2ÕB\ÈfÊ)æ YȇŒæ6zÓÞ�«]#�FtcçJ/>P °›ƒ0¤p!]gà1_éµ½�À=<æÖò.–ó˜¯Øþ¿&½u-&)J£ïC×+V’6\V‹ }Œë8îj7™s#Ó7È…xr·ò2ß²‘<Ê9ÂX!,�!ø¯ó=nxøŽ ÞR*îzI©7H|Ä2’Ίn,�èËGºw3%â–6ƒ_E# MX7—›\¡dTC·ŒGv€[Ï•ŽzœÉ-Œã6¼ír…Å[C6ˆ«CƒÊÏ…4^UŒ;²*ìl Ò…zרÏ"ÞâiäÆñ”௟J#ÅJáæhPÅð¾øÀþæEºyT¦^"mÍ~öÝȆ‹¼²ˆëýø�-zd¤Î,â({}Œ{ÏGRƒ •�`¤ât)¨Å¼êK [‡nœìópÕM²¹ûG1�¬nH–è'OŒ Ï'Ø'I oVcQp¨dâù¶´þOc“BcÓ(€,¶Öñ^$ãèÅ)wùV‰,†�Jéߤ˜eÕ­xšiÜ!Í�·H*ÐuÕ’49UþËZÉÆRH›bpE´¹ù[ƒ�,Þe¥gôÈüþÀFw¾’æÁÒ:ødi¬ŒÇ£AåéúHÛa»9CW*# ‘–2%Ú™E#ž—x7*!29à ©su¸_7„è )JE• ñôã'ƒî7c"Ó $2@D qm„^£Ü§ÄÜ¢�ráG&ßHß5Ý„‘ ƒ!"r€ëØÈ�Õa,ìÂGºA®”ù&NÎ X(ݳŒ–á~ñ Eq^_éñ›òˆ4|e6‰PÔ`¤!`ó&îu£?CP&UKѾ2ŽcŒd±×‡ 9mxI �[ÊUáþˆ``3ì æó¦ÇeÞõŠÁ �Ä‘�JËÛÝ6Ncª°”È6‰†E¨©xÖ—³ˆË¼Z³3Bq‰žZš•ƒ†K®¨e<çÇ^~,çñ9»XÍ èfJ•fõ�Œô)FH‚Bü¤1ÕÓ+à`¸ÒòE·O:xQz'Ò2$TaGö q„ýXצ)!¡4¦G]AÄó¸âˆþ¹Òôә̿ìcʉÀ h£ ·ÑÛ’Áé eƒ%k€:|ª4�ÙRpõÈG*/*Ö½ßè*ú61Âý]n5A}¦;7CÆJ ÐúJg�Eáò à{ÞS,¡ʉã#¥n¡tÏòÁ¢•Kx‹BWŸÏ”&ðOTøÐžª#¨øÆPýÐWÑŠäòx%8ŸG ²XªT±jAT—÷qðGôšÀÆU¬Wª–é,ÏHe±[Ê´�ñŽEΕì4ŠiÐ ¦3Qq“(ã« ¢ T.ÒyZa,cªÛ˜(v®•6�54불N\%¹†ia¤é>x"�ê\:×puZÇgñµ2Zò¼—Mí®Jôc�m ¨ž›Àf°s›Â¾—÷o祩hä31¢üäR¹[÷†{¸Ó‹Â  !S•=À|�ÃïàÇà ëöN¯›¿# ûd0ÀãÒ²êp³ Þ|/øøÛdF*ÓFatkþ}ýè1Ê*y�›¸_.ÄJ¦ãra}ÌaÞ,mÆó =Þñã[Ÿ‰elôSvG‡õ{ªw*ÃÞ¯>x¼ž¬ì�ÉÇ>Ƈ͂0“{ÝÐòËÓ±‹�UVI”Y»'Oc¾O~Ã%MÁ§®Ïmü×§P¡D&CYnp€Ý%5Ôçüz^&“M6ãOß(É àcúp*?‰_¼LL8·1žÓ|»B�ü‡•:Öƒ :¹,)Æ*Ÿ6¾\ˆ¥-mªè ÂŒ¶ü@!yÅÇ]>�Ô§´Ð”±:ëB �ý|D_?‹Ý?$Ó�— 6;q É@±¶9f¦Ê‚µ9‡.>{¹FŒ…ÂœÚÆY|d`üÕ(b£éò�4žÜË]H‰ãk˜QB�—ÀWâúÔ[Ç*4�´…#””.eŽ)ûw.‹ÍùÔ�b%�®ÜÏWnÄн¼ª³Ù»]LÛ Ñ-€ëÄ{¯‰qT2Wð•¢Sp¬åCî£'�ýÖÄR—ÓÄ$~5¡�=Þó_¥‹¡—7—Àî wáyG¤›Çò×:Ïg2À4L}"ÝÈ…n H�²�­l`#ÛÈæy£ˆ2§ oÆ�âH … êÑ„V´¡% IsS>e¬ç3>ašI‰¾Á`çù®âh¸‹Ð3"½œÌgÅ–1ˆÜÞC.çr:zô«+¥€|òÈ%Ÿ£RB96$�L iÔ É^d“,ã3æ“íöŽKøÌ9âäÒ‡Åá.ÂèÆC’¾Ð»ùT-úðëC‡ê8Ì"£‹W×Íš,¿îŒn¤±HåŸUŸKÏ2·s·¿G ;™ËHÎòymኆ°ºé¦O\ ìjó9×ÏߦqCx“eì ˆ-\ã[YÀX®¦µŸÛ�…–¢„ëÂ]ˆžÉ2€�׸Ãyþ—“ÐSÒh@ ÚÒš¦Ô§&©$kbO QJ1ä’Ãn6³‘�lã_ È3Ž�Įާ ¤$ÜEé‘gXáB3W¾°ú!—\Ö1ˆ'™4ÒÉ �T’IÀ�(£˜BŽ’Çaqˆ< ƒŒbTÌL.s–mÚóg¸‹2:1Tl¶ìˆX30w�ÕW�…ûe¢ÉÌ�j¥ê‹âí—GµcØÐSØÍ•�ÃFl�M£VPÊbOùwûǸ² Ê+@D® p•Xtýa¢LI¦+ÝiK ÙÊR–�@]Ç ¦˜èó¼Á{þ«XêdŒçj¾qlÄj�¦R„ñº4ç3WÑÿñ+7ùÍ­•Å*43ØÏµ�¯ùß&¶…²£�ä¡êq‡wë%Çñ ©Š§ˆ×üò"΄,þ5ßóo,9‰<î�.¤ò½(º÷”YÚÆƒ½o¹áß1"Káãñ½ ø—¿Ë’aE¥ªT;ô¦ôQRÎ׈W�RîõéùY:&_›€ùŸ%‚Õ‹=M ^açMQ¤ .¡dæHŽ–±ÜÁ,’¬ŒÿñÁ�<Ë„�Ë·&àoþ R4„™'†ËG(Ð^"•R9õzHNb³DÐéš¼ 9fx3ÂP«¿Ä¯&àþEÊ�Ï÷/P¸öÒ¶èHÕ)ë””d¾)Ÿz\ÚªÕ¿…!Šž·&àþõ$ޤ.Bx`È”ªè%Å&Ǽ¤ûÕ1 ¯ðà@®Vÿ6.N’¶œ=7�ÀòRüfST±œ„ 7‹¢ÍhI S�óßÇræñ#£ƒ$z@biÊiœÃ´ð•¯%%�Cä�Ãp€\ò8Â1'ate´vb‰#ž$RH%�šÔ¦u©E:i$z5å,#›ßùž_ØÉC¾ÑÖŽ£6méJ7N¡¡ŸGå”RJ¥ c¸1ÄàÀ�ݯrÉc3¿ñ ËÙÉ”�æˆÖPuiCgºÐžÆdT±Áu.;ù‹_ù� QTE¢»‡�ts's­h@Z%’1a?[Yˬa+( ÷LJêÑ\ˆ!�LÓ‚Ö4£uI'‰¸ ¾³„£f;ÙÄ6±� Âý¡¡Buk2$‘N-ê’I}êP›Z¤‘B‰Äá –g¼¨� Ê(¥„" (à09À^²ÙËösˆ£ÑÞÛÍP�€ñ[ÄG< ÄO±Ä8 £ËÑ(¡ØYýEQDqu¬p ,X°`Á‚ ,X°`Á‚ ,X°`Á‚ ,X°`Á‚ ,X°`Á‚ ,X°P­ðÿ¡ƒ v1»Rø%tEXtdate:create2024-01-16T00:48:30+00:00~iã˜%tEXtdate:modify2024-01-16T00:48:30+00:004[$IEND®B`‚epasveer-seer-97076f1/src/resources/flathub/icons/hicolor/32x32/000077500000000000000000000000001526321767600243455ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/flathub/icons/hicolor/32x32/io.github.epasveer.seer.png000066400000000000000000000020341526321767600315100ustar00rootroot00000000000000‰PNG  IHDR Ùs²gAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDª�#2 pHYs``ðkBÏtIMEè05ÒO¿°IDATHÇÍÕßOÕeð×ù œxHù¡”2E0 ÈU®lYkMçb®µÔ-odݵV­‹¶.úškóªÖÖV›WÍŠÌì†&–â”4Ø;ZˆƒçÐ… ?Îa®«z_~ž÷ó~ÞÏçóþ>_þk„î²CHÀÌ¿¨Th›•±Ý”2¦óƒyj 6Ø�Za«ÅPfg¾ãrK5hÕ)jHBHÌu)êÜo\•‘ÅôÀ?A/)ÑaƒÜãš°:c2’ú]Ôê3II™åZ}§Ô&«ÕãoÕ^p^Üón9礇U:´°¥ ŠÝ§T•*Ó>2¹`¥B‹Yç\õ›Z'ŒåëAÌia H/r6z•ú=h€[¹EžÖcÌs¿S� ÍÞøª€Zë±^“ ²· á;Ô´I� œqc¶²Ö.eý¤ÍŽ ¨õ¨QƒóWŸwP¯^§fm~ÛT-.®Ê#’†e ˜Òèº=FçÆ9ï`Ø bQ£`›Ý:Ô;‡f]öšv×”4l07‰›5‹É˜FÔ>G„ h±ËϦ|cŸ¦°Ú‹¶Îm›wÐo´�0ÒŽÙ­Çzm²6¹á_›ATÀ¨Ï]ʨ°G§Œ2)|©ÀS Uˆº×ÚA¥”v8³´‰.™R®Hè3b�2aW|âÇYÖN)QgtçŽqÒíö:>›³.ÝJÍøãNtËÕûй8¥ù(Ä5X¯XÖaùô¦_(õ±Tîf̨sA·uöçy'"ZŒéÕ-j´zÕ*ŸzOÍwA›½ï°B�yWÉÂ-áEA.I¸¦ËA.K ¨´QÔi[„ý oÑwºä=¸�«W¬ÆZYC.›pÓ+Nû>·1KÕdÄ;^3â[åVøJÊëÞvŹæ 47$"ªÄ[úýé qa…úÙ¸”žû¨î�vÌ S$lµR»S~uR¿-Bî&pÓ³ž”–”Õ+¢× qA¼¬ØÑù,ßÄušT‹ÉH›‘6¤ÓyS¹“_AqÅŠ¥�ù+ÿéÿ€µ…çÒ ÷•¶%tEXtdate:create2024-01-16T00:48:30+00:00~iã˜%tEXtdate:modify2024-01-16T00:48:30+00:004[$IEND®B`‚epasveer-seer-97076f1/src/resources/flathub/icons/hicolor/512x512/000077500000000000000000000000001526321767600245135ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/flathub/icons/hicolor/512x512/io.github.epasveer.seer.png000066400000000000000000000610031526321767600316570ustar00rootroot00000000000000‰PNG  IHDR^qqgAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDª�#2 pHYs``ðkBÏtIMEè07sâÖ¹w÷ùÎ>z¸3g朙93Ï<Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š·$z]ÅÒhI[ª±“¯«¢(JtéÉ—¬bëø‰3ô# (•‰¾,ÿ7må*×%$Ò’ÞC3¼nŒ¢TN²èDÚ’æ2_=þ(3üýøYÁA®JhÌ0–²ƒ,æzý ¥²‘ÄÙŒc=ÛYÍ—ôr•w…å&?¸Èß„ŸöË;’z^?E©Lø¸�ì2Cp%§»Èý`Àð÷ó±c9@Ïä~Äë¢(•‰ÃX[nþGSǹ‡ ÀRæn€ܳ¨ïõ#Q‚E…8ñÇ€€Ewgú8Î-û%;îÍ…}xýH”`Ñ ÞH¥SÀ5‡âs˜_žœænLFÀµü^?%Xtˆ7|â`mO¦Ãü…Â57+€À»g³Ñ뇢‹NñÆ.– W›:–Ň²ðÑ\¸º–m^?%X’¼®@%ÇÄòy¦p­6ÍYè(w(+€t WW°ÓEí›Ò—Nø˜ÅO,uÝv%Ìèà tãš²ƒ©Œg«‹œsÙIz¹kUèÀOŽr‡²ÈÕ~–Qì¸î§ò�wßm0"èç§(qLîcÝîc´|FÑÑEÞû©òîIï8ÄQ�÷?j:Ê{ ëò–p…ãš÷`ù~yWqT4º¢Ä 7“¿ßPïBŸ.“_„ à7ª:Ê}.EÂIþŽòžH^@Þ�œà°ÞÉ|�û R£ý蕲¨Ð šs}9Õ›Þôwœ{s…«NÅ€E‚Ô!Ñ¡&`Áò ›5ëÝŠc®uW[oÑ À ºÑ¬ÜgSÍqþÙµZ´p”·�’€kIeAÒ69>ëEe ¶ŽÄ€Á¯ª‹R†%ë|u®ùC¾ÃüJDÐ À –‰gö-9Þaþ\ƒ°®ƒ¼Á¯êR#àZ±CežLN®®f’Ã+B'/ð3‚W83@ÁÇ„,lé gð+€†‚½ÁV9ªoGº W§±Øñ3S"‚NÞ0�¿„«‡ÓÅaþ9ä\Ks$ ~h.ˆ.·±ÖQ}OT�J­>‰½FU�½!›o9:àj Î`²£üËØ ætr`[ü ™pm�#%æjô®®áWWϬÝiK!ÿ1Ý•õ�¢Ä íY!èóÍpè\#ƒ BîÉNÕÛ ê¼Û9Â6_ #„;~åèrô~.Ìöåuê‡à$&³ ?~røœ¶z+•Ý„÷¾õ2A¸ÚNЖ“ÈeŽpÕ‰6`°[€ Ñp)EjÛW8Ÿ(aŒ‹ @oÞ¦Çnµá,ð�çU,Ð T²èÏ|Å›œëJ«­ˆoØp5™3~%1`MZÙæ+†l‚°»/OmêW�Ö­V»ØTçÞrZ„Çp‰ãÜŠ1šðù^³ž|¾r|’P›iÂÂx]åîÍ!÷j¼4 W¾xH·?½Ø�/�SÔ´/¹BM¿t±¸Œ‚€ü¿:4~R,Ñ@(¤ó(öväÎæIÇ®¹`#…«u9ÕQnY°³íM¶+>+€&T ¸æìð$ápÓÍ >× õ«£@8Ð zqV¹+gr®‹ü£ÄA|µäÝ j¶±5É ¸Vä@ªÞ\˜8œÕçX᪛ À"\Íu¨‚¬X¢@(ô ð‘›Â­ŽÔqJ™-ƒÎôt�WÖllkÙ¿œ•×V²Èö~Ò¤´Æ�)OwÚW§:V!nÉU¢�Ã4W^”:„‚4(:r£ã3�|¾Ì‚Ò8ÓÑáÚ,áZáû¾?kù¿€s€�Ya{·mµŶ+‡N\~”0FôMˆ�+Ä#¿ |(œf(JT,·ülvì#0S(aíä øöYæÀ+@U^+ã�¨�w9;!@XÀy¶¹š0_hßrqU Ñ…•â3~Iƒš+ÞÓƒ�b÷üI0›1ñ”X­rvau@¾�ÉÖ3¸˜ï˜Å,¾g íš¡”t>(w¯T·Íu¾ ¿÷ó¹¡#@oŠOg™EQ¢N/‹´ˆ›—Ñ“-B ¿8Ð)HàžrÃk)‡;¾ou¨ã*¸xc>+säù��ƒ$Á  Ÿb:¼ãÑlŸïµV”Ò†¹b]äØÏo:?ù·;2 ®Âí,¡x÷Rþƒ£*xƒOx‘s)=5gq€*|)>ÛY®´-%¢\#.rý¼íXÑeÐî!¼zÅ¡ ¶\Â]ÜÇùQŠÑësa@v¬¨¬ô™Ã @?1w17E¥�ŠâˆjŒ'€ÎpXBs!ä¶Ÿ9À_î…B ‚b.w”·:ãÄç:Ù¡ sE‰½ ¢Àßyè¯ ¹·r°× ™~ ¼ÖŽòWV»¸ÈëF)Êþ$ð¬8”pŸÃNôì7;v»´ìþÏÑ¢>ÓÅgú£*+±GsfˆÝu¥Ã¯x5!ÖÏ_¢õ]|ácH¹V­s ìaóà'Ç‘ñÑþ5hÁÉœMw6Šâš�åB}íIŸ &4—ìvv±o§|›×M 5x­L8±U\êH´ÙŠyâÓüÄÕ±%Ôd‹ØE[øÞ‘‚µ¢E&ÃÅ.»“ å¯ÂSe¦€BÞª0sªpï3‰ñ<ç0ô‰�'Äg¹ÑåÎàíýò/¦—×C©¸ôÜí·üR¾±£üU¸�YÄbÆsµCí¼Pñ9E‰d˜M™éÊ*ñI¾âJý×ÇbÄ£ô\ãˆèt€ø!…v´3ÏeÈ �q¯ø/O0;W�¥¤S›—áÁ‘@2©d‘E&U©FU2I'�TRH&�$ ˜ ) ŸÒ©NИ†4¤.u¨F&™¤�H’­õg ÅS@.;ÈaëYÃ*V²† l%7 x½8[¼þ�«áß…'†?dÑD'ÅDc~ÞoÁø‡cuÞ=\XFàU6}á¥gµ9ˆ~ÜÃ;üÌ<6²K”¢› ØÂ"~åÿx�B=Wþ|Ý�Êgb f NÐÍÔg¬¡gFô=(qM èiœÃýûÒù\ìxùâ¢6t²hÃé<Èü˃Jr¸S›™Íã\¤z˜7‘X#ܳ˜[\”Q…7 u_¡îÄðŸÐe>wd+¿�Ã]?~f†Õ€%“N\À Lde¹ãÃh¦"Ö3…7H7†ÁÎ8^t :Õ¡N%€�Û G²~žR8Š ùÛSÂ+Žãõ•ò�ØõJ†:&јSy’ ¬œ�x•JØÈd^¤?-CÞôBˆä»r~› õüN­3­ÅH=~ xЕ¨´>SÅr^ ©vitàJ>a¾AÊ ©€e ç&º… uW—ÊãB'¢‹Á<ÛÏ?´ µ‹(™LƒàÈÏ®uUÒ9¢k°@r#ß±Z4ŽÅ´‘qÜ´òí�å ˆ6‹qeêßáÚˆûJPâžóÅý§?›è4þ/ „`¶‰´áj¾e­çC:˜´™±ÜÎA‚KPk2xºÌºŽ«ïÛÍ¿�.§p¥R’ÂãÆ�õrz»(©K€Ü šºªËœÅû, ëaži-_q‰Ë³”TNç=~c"/q„ãS+áß0×ÓP¥A5Ë’Å0®0üÛ,.æ_Ç%]ÂóeQVq=ß9Ì™L'Nç4:…¥Ó–°‹]ì ›¶“M6¹ä’G>{c&’D*©¤“I&Õ¨FÕ¨JÒÂrÞ_ÄB~`¹å‘@:~r]Üå ÞT¾çr6…¡�öçÞ2zòù•ˇ³HàDn +UØÎd^v¨ X�£Àq.½$rÙÆ:Ö°’å¬a=Éf';ɧ˜¬•’H ™*d�AMêQ�F4¥!õ©M–CW^2[ù�/Ëú�Úf¢ Ÿ„|39OŒ¤¬:Ò‚ŒVcß2H æ%“Aª±™ެ q p¨Cóáò”�ÃZ³�¹,b[ÈqzÞÒ©N]šÒŠö´¡)µ\šåî¡�™|É7,SÍöP�ÿ3ÄbØÀ¥ŒóÝ” NW1XGiz'"J½mÌŒ ¤üù¬`f8£ù�,e=9ÆS‹ÅiQê1å¶\ÛËå–çòœ¿ß ¼¼éø2Ì>}»ò»Åý6s}HÎO”!‹‰Æ—\Âðˆ8ŠîÁ/6ݹ�ès&IT¡uhBgŽâ,®ç >â°™BJ(!‡Ñ–ÿn¹àj{Úû7wXFiÀ[ë�œ¶oò1ü¬â|ýúW[vª ~d‚%‰KlOºqƒ ?÷^“@& 9„3¹„ 9Ò¦æ7Zì©çò ¥øµ;ߨ¨'mâΰKû¸l-›æs¢×]  ÅoÒ¾´–kÃæ4¢:�Ù¨¼æñ�뀣ñÄË6“ߤ¥1wWÛhKð Cªa-Ofþt¥Š¬ÄmøÖò$>�Â"ŠkƧ6Rÿ¹\1íþØà)›  ô)Ümq´×‰�l¢ާkÐõKåAŸ£lÙ¼~„Jø©Å36N«FÑ)Ä{Êo–wÈç#Ú{ý "ÎÙŽl Jø›«Œ¾ Òdã"m'U»L·ÞPñŽa!c9Åè]±+#,ƒŸ®ã ×:µyÓ¢Ì"ÞöìHV‰ G‚vîI¹9(+òDZêú—ðݽn|Ô8Èf%T6eó¶qåU�Øl‘w;ƒ]m§º1Âb#¸‹'=PÇR¢Ls>¶ü®ìâ5×–ä©ÜEŽeG}¦’}Ys9vz²„[ ú>N1¨qíÙT sl×ц-JÊá.õ\9Èâ_ö?ÑÅEy™à+žå¸�ŽfÓ8†»yœkè FÃ�@5á|®3ü6“×,$ÿ_ªÜß!myÃv3ð7Ç 9¸ÜBv3ÂF‘˲l¦3ì=–\Î-ª@T18’‰{N6•LÓxʨ–â\)EHæ þ°™Vs¹¨ñ.kŒy>Šàâ¾·–3SÚÅ ^?H%<Àå¼ÉÇ<ʆ¯D"wµþŠy;(c•›F)Añ¼ñŬáé0©ä$ó¤ñäœmpPÅ U¸Í2TØ,ŽÈããFc„£�ƒŽ'tŸÙÆ+ò³�g"±Hqˆ�w,_ÏîÑ…4À@£;ÑéêA6ìø8ÓÒ[Ãla Hfˆa—^ÄCA(þÔe°�ÿH?~ ù‘>•ÒÙK 1Äæ%•ðW…t6ÐË(i^h S –îL±\úíOçUã7Ú]ãúñ»ƒpî ¸AE¿ÞÓËÒmäž™úgÎR5¤±ÁŽÜÏzKkA%4Zñ�ÅýW°â¯Íׯ¡ÚÅñ};ñŽkÅlÞ¬Þã‚$· ÀíÇO.ßp¬ëåZoË»Æë¦Wpêò¾Å›ýCØ|µ0ºýúAT$*O2WÙD#(]SNâ4]øÇY<èÐëÜÞá`WgWÄ@Å<©] âTçE‹ó÷Ÿ ÿá†\Âc$WÙ„Žñãg÷¨½G¬áãPÞ³Ñ(ß“Vó”ã³�Ã�ª)_èî/*¤ó¸…ÇåáÂPìoèÛ8Ëæ^͘kÓwvò±:‹UR8žo-\E”M ¹›º¶%ÖfŒ!ÿtË·J8IãA‹Ã¸·¼.&0Øàlä?÷_çÚ8)ù“ó+xTǸ'ƒL´õ5Sº$üÙ&`$Á«éíuC+)ÜoœŠ°ËâCï߷À·Yô—õ<îÀõ¸ÔâËX2ûÒhËÃÁ ê(»¸Þë&V:R¸ß¸ØÁU¿oaðœÇ@‹» 4LøŒ¤—úý‰'qŸinçK¨o<ü{K—��Ê#Fᵜðûã Þ‡X¬û]ŒÌá*Õô‹GÚó¼íÙÀ‹†¼ #UèÈñtwäßÍ]Y%¾¾g4äCLs¸Áy÷*-÷ËCDí�íœä�iÃML°u ú®ÊÂE¾f¹låOžæ„0†ãJàeñå-S`%rÜb8¹ù¤Ü·ÝÇâï¾ "’d Næ–9pîçm�Âñ,ÙïÁî`:Os\X¦�®âס„»½n´bKUÃ�`.ýËý²5ó…ßípµH¢wò›1Q`R÷1a¡¶ÁAÇvþà Ž ÉrËÇ bÙÿ„!¦�y3lß~Þ-~³G8<±¯Ã™|h¸—)ͦ…×�§bp†…oX?Û™ÊãôR¿»“ù§Hçî¸á^QWÌ-å~טÂïrèc{‡ fºe”ÒÊ0(W¸ÏÁãÎa �r´ëi@öþ3Í�ß`%6¨c8çŸ`ù‹8U|l£p ÿºú~Öñ =½~0'@iÊf2�q´cã�,¿ÿ÷'ž8•l±7ð|¹c¸&Ì'Šv†rÓ騯íd2wÓIÆEŠ#˜ÄàÇÏVî'ÕPê¹¢³éY"yP|û+9¨Üïw�¡ÔL&Øö°åü�SÕ‡`¤9ˆwXî(pùd ‘Æpñ÷xÝT%DuÏ•[´­>¦B~&ã ùñ³�‰ÜJ;�G•0�D®äkV;ÒÁ*›¦‰û²l—ƒÝ€#•ê4¥Ý9–SèÇ™œN_zÑ•ÖÔ%=n»óu¢;×y4ÚïW>† ¿Êg€¡ÔóÄUb ‹yƒ>TóºÑ•�T:rß³ÞŰM”ó>%þö• ªÿŸENäf^f$ÓYÄ:rØÉ.òÉ'ŸãvŽ¢NÜè³_NA@K6 Þ‚¥øë�¡¿ëð,k(ÆO>óy‘ÞdyÝP¥”Lºs?“,ãÿøñ³ŽÎy/ÍHFV ûÿLºs7?²ÚTËIÊáo^å,ÅÁ4PKPÿ[ØÝŸ#+ßo,7‘Î\Ä5œAÓ8x •ŽjÅ£üaðëÇÏ7Ã:…/…ß á%â‘d:q;ã®�œ¤|æð*'ż¬û¼r^€K¸CøU1~ðÔ0Z˜*Q§&Çó,ÿn sDÀ¯;‹±`gV êœÊ‡Fßù¡¥\&s'íbx÷›Ê#elõŠx×  vŸØº“¼®¾*p*¯0{ï/� -üîV±ƒ?íuõC¤×1Ñ…±jpi¯rD̪¼¤ÒŸo™Ï"Æs­1´÷AbìèWt�_ðÑ�3¹“;¸É°hÍ€n�kÿÿ͸“ÿ‚Ò“&mâŽ1*XyM hléê#EÎ)wd¨TPwÇãÄpañ@CîZS2ø´•O8:ÎŽ ÷q‘ Î篫¥Dƒ{Å}«×Õ ŠÚ\Ãß®U£Â•6ó6Ç幉è!èí–o(a"S4-Z#Æ:©ôcbP‡|ùä°ž%Ìc&ÿ1‹ù,g;‚*k5CãÐzÂÇëB[æVÆM@¼.â‚¥- W§±À늹ä nålWÛ–¬g‹YÄ26²…�RL ‰$’B5©KSZÑš–Ôq¼ÃoÀýœÌ‹|M®×�Ä~Fsy@›s«¼®šY¤€®õºZ®¨ÁíXù{¿ˆ¯¹�chBšƒÒ3iÍi<ÌXÖ:Þ\ìâ ºzýX\Ñ@ ÷’×ÕR"K*ߊ€Ž^WÌ1>zñƒÃÅz!óy‡þ4 êØ.ƒN â+ÇZ˸5ŽÌc|¼&´á¯Ä�PbˆÖ,^ûHG_ÆX :÷²ÎÑpÜÀ.¡IÈb­:q¿:Ò/(âÛÝûØålÁÒ/GÔ …$ªS=nm,+ç‹6·y]-‡Ìw޾ý y†C-'µR©J]Ò˜†Ô¥*©–SEuNãS6:¸÷ʼnEEÑ#ä}a);‰ZÈÙ<ÀçLá>ä”XUžª\BÀžB{·ò»×Õr@ q?Ím~ågò‹ÅM MiCkšÒ€ê¤“L"Ų“m¬f9 YÀr¶PR.ç6F2†n\J?�‰Íy‰î e™×Ì–5L§uÀÕž¤±+È“¨FZÓ‘Ž´¦1Õ÷úÃ8ƒ—xœ�^7ºrSSôø»c/ÂÞQŸ—;‡òiwÐDÌŸL[.çüÃfË5D!›ø›w¸”6â+‘ƒy• ¶5™Êq^?2\-9— “‚5IÔ¤3gr?Ÿòë£äÒTg¢æ È¡¢à³^WËA½¶r+xĉ¦çñ+\) ±œO ºÊJä>² Œ¹Žc^²ÒEp,SÀÙŽò&R“Nôc0Ÿð'ëŒÃ¾lúS}{‹4ãçs–×Õ²$�,²éX9¼G1w îæ/G�SJùLçš å¦r:¿ØL)»x%ƬTe’Pï§,óøhÎ)ÜÇÇŽ‡ý¾´MÎ;'“^\Ê…ô¦ µÃbx’À»ÂKYF+¯›jA÷Ù8<)á7NZ5äæ9ô˦ÙÜI}¡üÚ´Føæ�-žê<ÎÂ�èg‘ë0a{R.'xÝàxá0F’�Ÿ¶³šÉ+ÜÆYJªy´U“?…—òC /Tëò¦!ö¾…öQ(W… ù3l6%üÁ¹âsê§6ÃaFLKξá+��ákðIHÏq}*œ{B71€ƒŸ¶°˜ßø”ǹŠ>t¤.iŽ�QºŠÇX�xÝX#mùÞfXŽçh±õíø?"C·_¯ÿ‰#�«l¶(«¸8f�lÚ wqšá×·„hpí4q%'•Ï=Î�¬g&cx‹{8�#hi£‡v‘ ÿÞÅé^7×@wÑqÕ¾´…GD‘Rç¦ÏÐÓ ú‰Cù@¾²\©lãŽõ ‡þxPümUC˜z§iY\{œˆ"E-Ö©�–1™§Œažà!ßJׇ>Ñ¡¯ÍîýN‡b&÷Û:I %máñ+V•»,]µçñDŒzÓ}A¨íWâh 1¨ˆ³TÀôõº©ñBß�–¯³ Êœiü(üzBLºÀJËÉîcƒà²Ž­Ì |*¢Ð¥p¯Ügž ÊXöÝé͘t»y©°¬Ÿ!6±=�)ŸŠÉf£xš±p6ö4ó)!wGžáLV\¯-ž’Ïb‡×Í-G—ò”Åyñžå¶ ÿÒ€aÆ7eÉe5KYÂ*6“KÉdP‹F´  lw©É\O nc}À¿Œe C`Ð{Od™ÜÎ:ï­È¶8ŽkHc6ür#óié D?;XÏf3‹¹¬`ù^72¾h¢ƒ« ¥ö£Èr]»È’È –KøœezÖãkÛ'³•Ÿ¹Ÿci,Jô«Ð„ãy�_l">7DÓËâ!ñ9ïIÃcÎyH]Á,¸ˆsÅß°4‰ÚÎbÆñWq$�ãÄ"F¹'Ĭ·„2/–z91 (‰[ÙnÑ®_Œ¶v5m¨–0Œ#íër4/Ùžð`P NäBÑârOES¯ó~¤ˆAb6üöÁ€ø¹,c¯q-ÇÐT¥üᡯ‹A�¦ÙcÂïÅTgLæ‹ð&Å|bÐó‡*¼h9e®à1Úºª‹�³PóÉã:cÞŒ±œšyý¸Ë ­ ÿ°8R®BCšÓØu@ )Ô¥3}¹š'ùŒÉ,b‹#÷j!Ðc ñTýí˜ñh›È-_ÿlî²8Gïca�·”+BÚ�¦s�Å‚~-½�9ò±ÅÔ=ʸš‰>=©…{›@%¢$‘EålîàUFñ/«Éõ²r¹EÖ­X!üö.¯›µ›®³°®ÛÀe3ŘóWCízZÞ¡¾1_ ^¶˜°¿µÈ]š±$ vÛcL:¤ìG*µiÇÑ\ÊÃü™ÏfòÈg;Ó¹L4Œé% °‚˜ q[�e%ý-r&òœ1çð°íµ[2Òx—',Ô|3xÌb ñYŒøß«Æïu+âB¯«¥8#� Ñ•S8‹£ ‡S²+°mêuå`±„_b²òx¶r~VÕ“†|c¸ÏFK/z©Ük!Ùx7&œˆ&ŠªçƒC/X‰îW,H£ûZhý-°±¤«Ê(CÎïþÀn$jR–®4¬D©IÜjÜÞó|Lœ—?!Ôíu¯+¥„“—„WüG ¸;\ Qµgøc“û|Ã{ZDDXí ‡{;m|è$r“Q»!Ÿb@õ:¡f#cÔ|I ‚$QKî[Ïý´¶cºqø/´�°—RÝà(l�mÎ`éc0øcs$–È­Æ3Ž\ãɳ/ËÂD:-&¶'JXÈ]?½îñ!`F‡ÿbn4Î&OÈYÄ.ê�H’+Ÿõ÷N^N³É—ÄmÆ)`£çNÙº ÊÏ cè R ‘zb¨C/8²xÏ8ü—ÒÇ6ªA÷ÿGG›šÉ�¼ÄgŒà3^äzRÃA¾ZŒïú©xöR–$î2Zy.öØW^kÁ-ÈõÞSqh%ÚJ¸ÚÃ%ñ°Ñ w�#'%‡ˆg[8Þ6g îbJ€òK6¿s§ ½“DcŸµd›3…!F'šS=õÌ(} rU âÐM8,sêþ92 4ŠÅ6s�£s¿g#×Èä:æW~f1ÈF=:Õ`väD©ª ϧ½o<ô�ÅoõɧŸgõQÂÌqÂþ37ìQàœsk à ‡«I&ª2Qüþe™«)Ù:²Îç}“ÝãÄ5À8G&1Y¼eP.áÏäîÉ‚¢S1WxT%ìœ%Ëlö,œu[þ1¾»Šää'Ã-=·f¼Íàß“ÆX:¾Hµ6"”§–h–åÇÚ¸(²$ð�PŸÛ=ª�v.¾:+]Ȇ‹FÇÅ<ïØEùõBþB.¶Èau显· éq…°�/á*‡uobŒs´Ö3¿ù/ µêQ]”°s“ðzç{â›&‰Ç�®¥?r¬˜$±ZˆðRyÕÅð÷ãg˜…4¡•èó-ÇǪ�ùÏp׿�>ù#ËÃB]^ SÙ>|$�«®Ñ½×Ê<Òî4?谡П aw³Ía)Õé \�Æ*cŽS¸ÔeM¯àgFþm9 “M'ª’í¨ì™ÜÌâ9{W†r9.ë:’�ÅL¢$ï#�&T'…$’R ɤìþ{ßÿÁrF3Q=FŸÇ…ù}ººˆéýø™É�.Êi/:N¿Þøûê¢÷{{I€ù Ý&üÞ�‹õ ž‹¸×­k…š|fü8&p"ß³†lrØÁNòȧ�"®kr è•É÷û¤¨ûo«i4ª]ëÒg¼ä8ÝʿᙢΠ]Êåc‰Ç 6~;lmÊ’À}†‰Mœå7— ³ïŒ› ‹ÅSÎR �ÄÖf ¦*!¤ã¥|‹å]$ðqƒ¡cïä!Ƹ*«� ,ÜÈJï9].æò3/ð¿°SÌ—ÎéÆoñr6\K£‘‹6”ðˆÿR‹‡£î2l—ÐR c£CBðdàc í£ÜºJŽOTºý>ʧÎ}Ødø"ˆ BoH2¬:†x/ŸëçQboèÉ�ô *‰øðáƒÝ Q;ÑÐ&ÞâIAžëÛXÅ �ë �!çp/›]—'}ë·&?h$œ‚üÈ�ûýÿŒæ¼€_eЈ?Å2‹Ùê°^Öüɼ%ä«Â½üÉl×å‹ÔLw¡ö›"ÖD­]ˆ5À±|Ä@É$‘H {'kjswˆí‘´ë¢)èm°yßÊà :¹OÜ2ä[TMhÿ”rÓE!S„œÉF›øQn�„üþK^kÞ–û£èo_ª�©Ïýâ½1-jír@lMµx(PƒÄã4iÎŽæQSâo;K‚lg æ -pøû…á›'<%Ÿ…b²t¿`úR1‹ k—1gç{æ†�{'ÃXæuÊ[ÀaRþzô®J@b§€/™ ^oÂGVøå)®™¿¾;Ú·ò‘k(S^…±<>„ÁbY;xÖ ˆÒ(ðZ³ˆ{�'.ÖøYÌ�¼µV9"¶d­kÛ�tØ¥hÃIQœ6ñ8‰GGg0›!.£!ûÅåwU _Òuä|KOå-•ùÿ6œ*äÌc­¡‰âæ`'niÈÓãùÖuiÁ#}üÆéì[6rÝÉ¢„"Š)¦h÷ŸbŠ(¤� w§}ÿµ‹åüÆ‚(¶Ê±5†\BàWÃ/–Í ~á5î˜ÀÍÌç#—¥I¸:$&€el˜Úó8·ïýŽ5á Ñ4j#Ë 5HO"¶âŽ 6ø/ü‹g\Ÿ�„B²¸þ1OÌ“™N}²()3ð÷ü½ï¸oßÑ_ [À,²CrƸAfÉ@jT'€^æpÑÑWCYÂd—­ ¤.Y䉿^ÍlÁð©?Íøˆ@.2Dþϸ¨.høÙèª Üh8ßÊ–º*+T$¥ŸBKAq!+¢ZÃJBºm˜kk‹'D±ÕËÂo§D=¦ëábx²R%ž®J’ül°pÊu³ñ‰åZ„í(¶0ð=XðG�çR…÷|C<¤†F]2u¹ Ç?ʵ‚–œ»­(Ÿ¶ò¬ÁÐâ)á×{ Žq�Q'ÿ WÂÀCg… 0þ¾ ƒxž³,üâ^$xpçFóhcÐÑ‘8“ü+|c«ãk�\ÈÅ ädš‘I Åûý)±”ŠYöÿ;ŸUŒgŠA† §R=˜ßß§‹Áé9¬`°cCÑ5¬˜0’8Œ/ ¿_Ä®Ý[”ð®Å"÷0a¥µ–õŽKoÏó†ée÷¡*Òj0ðô¤Bk¬áQ^¦!µ)¤ho*ýï’ÝÉ¿÷¿öü¿’µw‚RíâQ:ˆV{>®g5/:TOÚÌBá ïª= ¼K_ƒ.¢‰ñ|hü·Z¢ïùlqXvC† !ܲy dE›`�&€.Og”˜åJa�·ŽNžÔ¥‡èM§t ã<"í!¶¥KУŒ)-²ÔÇ8^ôi|·Ãº×àcÃ]‹xÐU˜’ð!I‰žð¤&J8Wˆ œCw�js‘1Xæ*AJ9Q ²ñŒežþ¬s8üWŠZ{ð‰ô¶;ôP…ŒŽ3>ñÀI @ µ¹×“º(@r ‘çx°…›$†ýÎu8-5M|çÙ¨Q÷s$ œm㞤‹„\SÇA½“yP8Á(MS<‹ÖœÂB}¼�Y¨„ )ö[‘‹w¸©&~qJÓ_Ždé>Þò–ØZäwc¸qúñ³“OmÍ]ïs>ï Ö‰Üf ¶„#<|“êcuª¢ÄíÄÅïmÖ¨±…—¾IŽÂd�.)δ5¥ÊâBÆ‹›�lFÓßÖ§%óÄ €½CoƒŒ›Ÿ-ô÷ðm4`Ž0Ú‡gUâ„Fb§}ÒÓ:u:Ýžô£—åµùCÌû˜ ǪËPF1‹•¬a3øŽ‡8Ú�jTψwýÅ�þæ…ŸH~vq›§‘šÛ ‘š¼ £„�êLºÝû[Bžl!”ûÎ�=Ù5Õ:›ð`ûHãšÓ–fÔqì€ë8Ñf±ƒ˜>ç±ÞÐÖ†…l=…•É2ËèHJ\‘Â÷BÇç�&Àþ 4.‰ýŒyí�I¿o¼eTŸPhÀ$ñŽ3mW,燿ŸO‚2‰'g þ‰ÿ Áñ§cøxKèx3"6Pœ’ÈÝ"¹o¨o“ÿaCÎ#âR3�× _ð;mr°XëüäÊ—pd¸Q¨×XÏ?JyHxÅ«=ŠX–4ž6ÌöóµÍ* ¥!Ôw·†}{“À]†Éêo›!|žÅðŸ*h4FŸç„š}à‘J’ Ê'îYDŠ,qu²'�¤©eî› ÓǶ0·öqµÜO>-ó]Êcëfqˆ×�Hõ>jó<’–®ÄÇ çÏÅ\îuµ¨Í§SÀO–á2kò“!ßf® Û7,‘k ¦»~†[øNä:ÁnqOZÄÑ^?zjç)V±Žkq oó¯s78‚T×é Öé(.C ½à°PŸSÀït±È{Œq��ýaq«™Áý¢î¿?+,lR¹Û˜ÏÏ Nòú±ï¦%+…M”IO´?”Q,/"›eLãk†q3§s0 ÉŠ1?› p3„NøYÌìóšð£Åð¯åÑÞ=F)Bï†d«bøùÉ·HZ•§ØelÑjúyýÈ÷rŒ0M­5èCÀ8‹÷TÀ&2‘�x”+8�ÔUQbôðY̼©¢¶÷4Ï öÑܸ˜÷ãg‰Å€©j¹…˜N¿ =¤r[”ý–±{×ãÂ͵œãõã.Â|h†Á²áj£G`Êe3ÃÛÜËù¬SAdðQ�6œÄí¼Ë׼ȩ†ý¢Øc)LcKÆZt§ \kÜi¶dŠEÎþÇÁ®—¥ ÊKx?ãŒgíe‘oçzý¨÷C:øN‰‹?™3åb.rô~ªÓŒôçN^gÿ±š6ò“"nòºÁñÁm!vÕWÅ=rCÑvnŠ!šP,`çij˜1%®ºðIÐÛ'yJ}C´I¨Ëƒ–þ~üäñL ?á‹©ÅÆ |¥Q›vôæ†ð>?3� ë°]¼õptq‰�ÿ…ÐUsyGÔ€dQ¾Ì뎇‹KÔý×Ci ä¬B&…(³Þ3„àDáÛŸÄÉL²ùæmâæˆø&¯ uU?4� êÓ…“¸–§ùœ)Ìc&Ã9_u�áã½ þR&ð2§ZpîòYÙ}ÅÍùÄvŸùç‹­®Å@&… ²ò³�é/ÚûuàuÁ×òþi§{êëÏŽšLjývXëœDUPG�ºÁù —¥üÂë\ϱ´ æÜãDÁÚÿÅœ.ÀþTeˆ�ˆÍÏN¾ä(1Ì[ ÎæSÁé¥]*b oÓG\´6à.16ÀþiŒE¼âØàpÁȹ$Ìž” hË›a¿Œ_xƒ8ÎÁ°ßGÑïq K$r®±è&Þ ›¨óŸB'nä[–YÆØ÷tçñ1—ÑJ,«6Wñ§­²P./xîpÍž[„šÇö–°Òp®`åžËr&ò&7r<-‚§ÈÆ;9Ñëæ:à F:ÐÑ[ÍËlXѤҊ~ á+¦³‚­ì¤�Š) �6°€I¼Ïœ@#CÈØ¸‚ßÈ–ry,ySE¥žß88¯PÄæÍGonâÒ�,c3™Ç6ˆ‘~�s�xì÷÷xÝ`Ôä&nþög£ø„©bPt€$ªQ�:Ô “TJØE>ÛÙÆV²Ù�)Îr Îà<ºÙF“.á'bš×Ë­'hü=o]I‰UhÃat§¥…Ó)·,§˜C~¬H ¯¥áï¾”Í(®¤iX¦÷LŽâ98XøÙÄSTlp± \Í�9c%%¬T=Ûg lb�Æ50 u¹ž â!Žõðj4òLæC1ÏR]T@äïÿ/®]Ádуû™èpz¿ËÒ�ïÈ-åþƒ,m¼O0„ÜxFåŒö¢Ä§0è0 UéÉCüfã/QÃŒ„‰šŒv5ôKXÆ»œjëí· ßˆùWÆ|TÅ >ƒè4CI§TçHf²q]º„¶^7½bp�‹0—ÙŒçFÚ8<Ï?ÕàýîµJ£Pè&jôs}XJ¯Á1<ÆÔË‹\ßÿý©Í±\Ï]\H+¯›]‘j1ôóù‡GéôpMcÄùÉ寛­„�,FöÿÁ»A%áHÃÙë>ãÜ�_dƒ,÷÷¸ u¡È\*ªò¨|>žHâ±rnr™Ì½7)}€’¸ªXÑ„Äw;A0Wb˜Lîe Eø)d)ïprX_`ÑJÌÏ2=ŒkxR·wm¸€ëéO«°Ñ%ð¼AÂð‘Š㘣 .R¿vQI©ð´e�ØUvr¡×US‚¤ºèÿßÏ&ŽöºjJìq‹ÁÄè?š{]5%(n5KyѸ‚L ÇsBÖ˜JÌSÛà,ÜÏ«®f*ÞsËÅ·9�6† yŽ%ä’Ë2^¦“× P¢Íi�îíÌ[pe ªA»£Ð¨þS¯œ¾À2Öµ_å"…· k€E§bJìr›ÁzäG£ùïƒÂ¯gq³ê‚T$jr—qí {¼öÌ7Lïêi@Ñ‹Õâ[ÜHoCŽ:bÈX?ÅLábƒÓp%®Hål&’K1…¬àiC « ^`w1Èë(©ËxÃ4þ¸1ÒAÖòøÉg4§©�ßø¦3ï•3úy_´ÌâkC7XÆ¡^7Bq@ÏÞàsµ± ²�Ï8J]|Æ'µ¸�%¯´€‹Ä_wc™¡ü¢û%œoˆˆ¸•S-reñ³åPª?ðºj†ÆIœÈxà ÿg†ýFc0ˆa&DfE¥ ïîY›³ýKÙe;øYÉc*ŽÚðŠ…óÆßÈseñ…!G.—{Ý$Å‚ºbèO?~~§¡MÞ*WÕpoÉ0:Èá-:„í>é¼jqÊ𓮢J‚åð³íTZÒ•ªæ=�‰b™_9=̦»µŒ6‚~üŒ§µ×¢Ò�Èu :“,å=)tâ4N££zz®(´gN¹.°‚{#ò hl46õãg"½~•‚dn5xoöãçKÅßÖ¼ËZòÉg oꪭ¢Ð‡™{;À>¦[ÄîÔ†ß-¦€iâõ£¨ð¤ñ€ÑNÓÏ|ްÈÛ¬\ä‡éãus”ðЊûÁO¼Åi!yïM¤½9†fFç‘ò—Å0SƒNE”ª<+û.MK- ¼|‚¯ÀU\¡[�ŠB UB4Ði ,%—,â)£ÉC-ƒü,å,¯D…¥.ùñ³ÒÆ*¯AÀV±tÅø” W:3a¿®ñ­1$DfYL¹Z½ÇF€6å"÷ìŸVÓÏ&W6Š9Kø&l*ÃJÜÒS q¿Å¯g[tÆ<,ºW‚çK}�ÕÖ]-ìûÿâ8¯¨xÉÉ¢/Ù?©mÌÑÃr#PÄ4òºQ†ú[zèYiûõ¨f þêÇÏ®V�Ï•tý×[êùfãyh|O#*Üc¡ôãg™¥¿ÿ²\jiÙ¿“g©åuc•h“ÌMÆîµÚF¹§ S,§€ô7ž&(ÎhÌ{–Î]çÛºvÛG�X!ú)á[Ú{Ý`%š¤ó°E—øÙv'ߎq–SÀ6†¨�@ô2ºú*MÿÑËUy) ²°ìôãç_úzÝh%ZÔàe‹¯Ë.G¥MŒ±÷|Uæs’× �KÒ¸Æè“±4ýJ— Ê=ÎxOZÇuªá_hÀÇæ=<åP¥¨oÙ“XÆ%*`rIÞ´ñÅ72hUÞ6|mé>.� ±£• Ck~°è;¸ß…Fa&C-÷–~ryYOã£/S-Ÿgïµ4œP“§Œ®DJÓ÷jÙQ‘éÆd‹—¿™k]ªò$s ë-;”Ÿ)œ¨"AÔâAƒÊξéù‘�õ,’h³Á˜©þþ+*½-5ùVr^P*ŧØD"ô³‰G©çuãcœ#c¡îëÇÏ®“¦å1L·¼Óntì@^‰Îb©ÅKŸ‚¸+ãl]“O¢�® Ôf°m4ž\ûÙÓŠ/-§›]<’q™c$r¥eÔÀét©ü†FÿDe7Ïh$™9�Ÿm¾ý~æ8Šèä†ê5“3ùÑÆó]`ÊáO^f­cf\�C¹�¯X„&älî´u–öŒ¸&Ь6€¢8FÒp*©Îâ~p¹ðã§�åŒä>úÒØ3‡£UéȼÄdW{ý}_þ™ÜES÷9ZÜ.½©§ôJ, ‡œrsV�E?†»’ ìK;YÀ·ä^΢ Hëd�DuZr4Wð ß3‡m¶®ÏÌi;£¹È¥ÛíÛ„rй* o·Â¯g̱à Üpm'çð£ë’’èLΠmÀa˜ ÙÎzÖ²œå¬b5È&‡�RD‰Ãz$‘BÕ¨A}Ò˜æ4¢5ɱ¿¬có;\æëÀO‚Vþ(ú“R}�B¤1cGbS8•-A—Ø—³9<,Â~òÉ#‡lrØÌV²É!—\òȧ`·V¢�D’I!• ÒÉ¢Õ¨IM²¨F©aÒ™(`.#Ál ƒÈ�Ìû\pu3§ðGXj§(A"û¸/ÄRÓ9’ç˜éò@Íy*¦ˆB v§BŠ(aQo—VóB4q’µñúõ+•›T¾ºåº0™5à<>f¹+•šØJ›ÃMt Ã9E=ÑžòO á¥xIWQ©÷ë0—L¢-Wò+ãlØÊ$†p8a{’S·¼0úsP×Ü/tÊB.û}RhÇå|ÂBq!K©„õŒå~Ž»ÚrOÑœúƒ0E R×Ô�IÏu|¾í–$šr&Ïó›"¸c6í`6ïs]ÂøÕ/K£…»®9–C%GçÏà9‚…«?±2B÷+b9ËN5Zs0‡sͨîù9ÎNÖ0›éLe(ŽØ}rù–>­m̉Ìõø Ä5^wŸø%‘·ußíœÉø¨Ü?�š4ç@ºÒ‰æÔ‰r »B¶±’¹üË¿,`=ùQ¸gk~¢YÀÕ‰œAvTÛ^¡Ð XÚð“ Éþ g�åšdR�æ´§=­iL2"dPÌN6±–¥Ìg‹XŶ~ñIäM®¸ºƒ3ÅZT0t ,}ÅPbßF}øÃ±ˆ±ø¨BMêÒ”f4¥ u©E ª­ÌSL>ùd³‘ ¬f%ËXÂZ6“Õa_¶>ù `¥“I?Æã÷¤F�‚#‹3„ÕÓJF{X'?;ÙÉ*þ ‰ ²¨F-jS‹šÔ¤:UÉ$�4’I&‰„½öÅSH!ùìb'9d³…-la3›ØB;(Œ‰!6…épµMYæuÕâ�‚ã`®þÌB¯+¶—"²ÉfÕ~×H ™dI$ßÞ)ÌO Å»õK„c“-|'L-9žw¼®šR™ðñ‚¨–rº×«ð(†_U!ü'+qCS!΀ŸiF2âÈî×¶ÐÓëŠÅ+êU%N ¥pu$›¼®X…§�á\­¡*ÁJôÈàá+. Åšzü#<ý9Ó¿T”rô#Ö}F ÅŠG…§_Äe^W+>Ñ-€{ΜuòMT´áÂK:íâPl$›®%rv”u!+z è–Æœ$\�ÃeÔ  Mh@UÙÉFV²ŒõAùÊ …4îcwð]”ï[¾ýXåªýÿñ«°ç?‚.L‰zK”JÇåb€Ï¡sgq<Ï1•õe¼ý“Ã|¾äª¨F½Mc(ùøYÁiQ¼«©ýóø‚+·_öÃôTÛ¡TRÒù^èzDµ òdp.?±ÝhP[Ì|††9j±‰=Ãß�Ÿ•QšÂ×þb´ Y¶!F%DŽ€N|Ì—Ž¢Íåꈫµ¤ñÈ~®E¢18oÿ í\ÈY¨‚@%²È€‚ÇÚýIäR–8v­‘Ï»ý–•þ‘Ÿܶÿ¶í?Œ�ª¨D›æ,ºÝÔ·Ì•Â�bð«ôm"Ôiø—N‘RdŽDûÓ.äÚÊQjƒ¢×‰®¸µÌ“È]®€úñ3!"¡¯LÃ?rS@¤Ú¡è4ýÅ8<ÖTKbŒº b™ë×_¿=ékj„¹eEòþ�@¤Ú߀ÿ„< 5b )úŠì/,ýïìbï[>•0$¬ŠZV_ÿH­Bi±Mû‡ŠÏìú°Ö_Qv“ÈÛB‡ÛÅ9y2ø"èî_ººßžÖÉð÷Ùöwc½�gBØ’+ Ð�Bw›f›¦?;��{sù™1Lc�…“ïoÂ$×¶[ü—MáS ½ý_[´?E4 ÞÁ‰á{銲‡{Åz�EŽL~4të­¼K_�I:5èÌ­¢…›?9ô CÝÝ ÿðMái‹;œ%Šÿ§ îJ¸©Ë_âr¹£EžÞñ×LN è¢MxÝ0Dß )X88_ü‡{ ˆ|ûk1EȱZŒ× (! :YΧ Ý_>5¨Â3¢•Á¢-¬¿þ戃¡OÑhÿ�â= ±æŠ²éŒt½Û¬ÆoBžm"¶ê¢�Ag†Psëáÿ÷Š÷Â1D§ýíX.äù�!Ô\QÊq´h0žªy:±VÈó¾åþô8¶ y ºÞÖÃ$��«Å¶…>D§ý ¼)äP«%Œ$ðª¸xd™ëDväÙÉÉ–y2øI¸ÓçA µ¬‡ÿ÷»›$0Èb ^5(Zí?–l!Ïh2ƒ¬·¢”£-Ë„.6ÛÆ Ý@a½ÀÖsÝ#Â�&‘D­�|ýKIˆÈ* Zí—=4æp\Pµ®t¨K0{Îb›(ÀU…g»žm6÷Z*\Ë b�Æ`î2ê(Žâú2µ/ámî6Ö¬1¯5D«ý¹|FQÀÕ,Î ùô¤R €õ \]Ï×6ù¤'[H‰M.É-V¢k—4î³þ×±b¿+%¼c14âµ ´£×þ±Ì®žD×u®„è`ljt®Žc¦M¾<lU·u\YW¸¶Ëe0Î4s·qø0üÁnЈW]¯¢×þµâdÜ�þ.k¬(d1VØaærªmÎs¿u›8Ø2O" wû�45¶VûùÞbn-t+ ˆfû;²RÈ7Kc(¡r ;„®åÄऻx¤u¯ežv¢¸ñuõu.ú“ð…q ˆfûeC­b®qQ_E …O„ŽUdsXJ}f‹gf§—>žÞµŽëÚð‡p®¢Û~ù0p¢ÁAQÓ]ô<7ƒ†ò&ñ±Ø�ß7j�Ífá÷›9ÌamCþ`· p®à¾ýçˆZ‰ÎÚ/ëjæiÌ@%xd Î5Í/uÛ yEˆ"œÀÑÜØÏx‡Záþ¥íÏ* ºí?Ol½lS‚¦½¸#µ¶,Kqì§„±œ\F�8…yÁ0äJ¸ÉѽÂ7ü!\�h¶j3UÈ¿…#ƒ~ÿJ%ç!±K¾îâèôAã ÚÎ/<Å5\Ë#Œ`µñw³v+ìZÞáášìÛ3<äö—r‹èXä UR‚Aþ~¹s<Ýœ™Æ®í$9úþðg…ÝàD5(:íßC Ñiû*õ ÃMâ÷d¸Ë´—å{OCMÛ;dð¨¥Áoðgá>®²žá@C1òí/‹|м5¥Ri©ÃBWÊsm›ŸÆAwÿ¥twp‡N~w‹y($?ù�Åoêžô……‘oYº‰&Èó£tU©\,zú%ˆsåú¢› û´™ó•Ÿ@±Û—¦ln zÜ–‰õûÕ¡®}¤Û_–$ÞJ*á¶ Ÿ€RIÉíÒ‹¸2¨ÒZŠ¥Ùuÿ+]|»­¦€œ §€6üb9üÛÅPû÷Ñ[Ô?œ.Ú(Š�ãDw–ÿØÄ4Ó„Ï,¼ïI‹ßs]vë)àF×S@+1 R0Ã?:íßC1f`!—ùæ”JÉsb·¼;„«1˜uŽ:?:Öý+Ë‹òÝN-Æá�öïAv>Ò¥ðV©ÄÔ€‹,´Ø�àã>5Ö÷¥bfpCÐÃ5´°\²3ü£ÓþRª‹[—õt ©T¥Ñ�MBz6 %§qo0_ð–WÂF~â:…T~8¦€fŒ±¢“‚þÑi)WŠ*ÈÎMª*L9�óø(`¨äp“ÂRz�8ˆn´¦™$�Ï&–3“¿˜OnÈ¥à%£Àk;ƒyÍÆ¹FSÞ°pvþ+ƒ˜ÓíhÀh:\}�+mý) p�ðýøG0` �DªP•êdXFvO(«€&ŒŠØ×?ZíD#®ß‚r­ªTB† Ýgxºi¤ä‰@#Ѥ62Ã?²œ/x#²÷H¬(¢w™wãÊ{b0z ùÖRô×ÞëF¹ ‡pŒ»6®Z x†OÔ&{/®&÷S@ñü<>‡?t\«lQ£ ůCàû¸s,áFPŸ¯-‡ü,þKé&ènÖ @qÆÃ ˜´ w8�êñe…þp²  ´š¶^WK‰®†A®MT»ØÄÉF .ŸW Å)Ò9Î\Gž…£Ù.t ·ãÒ³LËUÀ 4ýÇ÷ð¯Â�B[~v`¼¬(@#æ h­këôØÀj#°•?-Œtâéà¯,‡‹¾œ_õºZJ¼�$Ƨñ3e4k¼nF¼¡@pøhJoΠG'ÿÙ,áo¦òKÙj±§â’@MÚÐ�žt¡QP®WW1–/ø�í^7%Ñ ÒhωœB2‚.ÃÏVV0‹¿ø‡…l¤ÐëFE‰jÑ‚.FZµ¥‚]ÌàF2¿ÒNŸ!£@èT§;§Ò›V!ºßÁJæ2“,` Û*èæ �:´¢‡pMBЕX;äw6{Ý øF'€pÑ€îœÌQ4ÙõD![XÉ\þeKÙ@vL C#™ê4¤=Ñ™ÖÔé4$‡?ùžŸ˜_ž‹çèNhÄœLO‡ÅÍ.¶±†ÅÌc‹YÇòâh]࣠5iDkÚÒ�4¤FˆÚÌã'¾çoÝï‡ �ÂO�9ŒãèE‹°Å*bYà ±„%¬g+;(ÄïucË‘HjP—¦´ -iL]²Â`'YÈ2~eSXëu+:DŠês0'ЋVaVÿ)f'[ØÄzV²œ¬b3ÛÈa—B")¤S�Z4 1 iLêQ‡Œ°ùà+f9¿1šßYG«Ÿ¸A'€Hs�èÅ‘t x (&Ÿíd³• ¬cØÌfrØÎv¶S@1EaØ+ûH$‰$RÉ ‹,jP›zÔ£.õ¨Euª“v·,c ãù�å*å�:D‡ šs8Gs0MB82tF1E�K.Û÷N¥ÿ•Gyì"�Š(¡˜J(Æ��„ÝI$…RI#�*d’EU2É$‹jT#�t2H#1‚Ö ¹,ä7~æ/VëÐ�,:D“DêÒ�C8œÎ4ô$ÞpÉn[¹"J(¡ÿî¿}øð‘$�H‰»¯ø¢ÚCJØÈl~g3ØàÁÓ©„èà)4à@zÒ�¶ÔU�uÀ–3�IüÉÒ˜³N¨Ðèà%é4¤Ý8˜v4 Š×Õñ€�¬f&ÓøƒylP!_ôÑ H£.m9�.´§5ã.â€{¶³š9üÅtæ±®Ò¨?Ç :ĉT§!íèBgZP�ªl*(d3˘ſÌd1)ðºBŠN±I*5hHKÚÑžÖ4¤zÅ(O[XÍ"f3›¬$'æÔ—*1:Ä:IT¥�iAsZÑ”zT'-æc‘ËFV³„ùÌe1kÉQÍýXD'€x"™, !�iLSsu¨JZLD¾-!o¯ºòR³”ulŽ+Û…J‰NñŠ�T²¨A]êR�ú4 .µ©I&i¤’á7ë§€|rÙÊ&6²–5¬bëØB6ùºÄ�t¨(øH!ƒ 2©N jP›ÚÔ¤Yd�I&¤îVç-ý;ÁòÝû)¡˜"Š)¦€BòÈ%—\²ÙÂ&6±‰mlaÙä²Sµõâ�*6>’HÙ�ª�J*i»ÿ¤ì� JõþÀOPB1…좀| vçsÙE!P ƒ]QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ”áÿ:W„VeV¹„%tEXtdate:create2024-01-16T00:48:30+00:00~iã˜%tEXtdate:modify2024-01-16T00:48:30+00:004[$IEND®B`‚epasveer-seer-97076f1/src/resources/flathub/icons/hicolor/64x64/000077500000000000000000000000001526321767600243575ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/flathub/icons/hicolor/64x64/io.github.epasveer.seer.png000066400000000000000000000043241526321767600315260ustar00rootroot00000000000000‰PNG  IHDR@@`¹UgAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDª�#2 pHYs``ðkBÏtIMEè06KFî ÇIDAThÞíØypÕÕðÏËËš° V�¥HQ¤€‚È"XpQ¤2XAG mm-Œl*´ YZ•ulP�¡©�Ù·$$,"ŒÈAèÄÔ¼ò¥3í ߿޻g½çœß¹ç^®â*þ¯PC,^®ŠËŒ6R¬}ªšç¨�j˜h¿C—£**Bþ¾z"èNƒ£±4d¨š¯ÊÇ�@q¨;ù¥dE6k&ηΊEº"¤—êª{¥ÈòªFxW†Ø MUEò}…Ú:¬ŠV8¦’™†GÙ QÛ:³%Xæ9ÔÑG4êJDš¶hn³›q¯�+U âÐV„æ:Xà”»¼l˜Å®ÇVé²4–&Ñy_ɳÝ.ÇdØ.ÉR<⼟igˆ—V]¡)&¨e²l�ÔÁ½LÒDÀ_8î¼,=ÔPd½·(ò¦ÅÎ`Œñ™�8äA¥g«ífé/Ke1Ú{À@ݵ5Økr}bˆ4°Ít1¨¯ñåçýE7#hœ‰‚zXm»§ÔÿÏx»í±U[1ºèjŠ=ÞÕBª‡Õ@{ëM»\ªù“}†Š�ì æj“$M–Ö4¶Á:?ÑÍb;ôÝíðn)‡#D² òôô¬B�÷‚òå:Óì÷�M•ï>LöªÄH‹´çÖ7D¢Ü¤žq Ý–Ü�VÚ¦·_Èw§qhd¶•jGæ@;[üÓp•q—F„-™j®½z›b‡–h§5ú…ñ½… Ë4¹î’a‹é‰'›c›Î²eK2ÌÓjEj<±8c�¤˜áÒ"”O±B¶®öV¼r�¡z…+ždžEî—�Vò �Ô´—g¤IÖ¨.Ås¶ÙktyŒåÕæy1Z¬§å�âi§ÊáŠÕR_t‘®È—Η¢î—¢³— •ëKdû¥¥!<—D´¦ºÉô™qåP:{Ë>,÷¡Ír½âºžê®íuoŠ.Ùf9'O°åµ$ûƹڸÇD!ÉÆšä€ùö‰ò¥éd„¯mt®„딃ÎIp··�ÑY_#5°:4 e«;Á‹Ú(´Åo´uÈ®zªçÝâžQÅѺÚc¼Žž•a¢Ó¥¸×‹‘%à§ä:N¢´5Üd¿SÏ|‹BF–êÚ¡‹F¶X SP´æ–ù»:î‘obH·¬j�Qâ5•ùüc¹çK­Ä™i·›0Éz5µ0ÇoÕ×H®‘¤À˜KLE@œD e« l â4UIÐ{%9VŠö�~Fø›x?°Ü1óU•*Ép«uô²…R�µÙ²‰³Ž«,Ñ­õ¨ÜŠÈ0W-|l”@HÎ2�•‹(±Nˆ‘b£3jâ¤Ê¢œ³K‚ôR2çD9kƒcŠq´âÀÇj¡�–Ò%Xej)Zšª‹¹–ˆs·�>ÕU5ë<ƒV6›'±Ô³½iî¿Ë^Ð"¯‡¬¶´ÉbuÜ¢Ðh1ª©,Ád¹š¹ÞzKBN½J>ñ”Júè,Kr8†Úm®Ü`‚�U ¡·÷™íŒQà-£Œ±Ô^÷¹ÝVKÔ áδ[_�¬µ_ž¹ÂÙù+¶Ê6^ýåiV†£¹|n¬‡-²Öô i Í)çÌïm�&¨£�;u/û)–7–×娳ȰÒT³ÊpT÷ˆYï�(éZûÚt BšÌÐL?‰Ž:s±€—�8­uðŽ êèSîaÔÐnRÛ9û¬°Ta9<×Xn–·-ð•÷,·+ÜãèvKÈÑÐméyQ¾ $‰—¸ÜqÒ¾’;dœÇåDšÿ£¯þ%_ùLËt—í€Å†h(¾g’æ•ã°?ëo»‡J(5/5 UüBrõ,÷‚Yu1X|n§|ÇE©¢žFêûFŽ×|¤Èl×è§(Åá:0ÌÏÝZ<Íej«­†RÄá´ÃvøÔ:{‹[m³õ÷éå¾,â-ñ*Ü yɯ‘úâKB|�TÙÇ&]9ót”¯›Jæ(�çWÅeIzCõâUKèQž´1Ò ù¥0Ã_Åh¿þ~*ß ÅæWÙ(×5À zK×Ê5$Õá4ˆkÝn�Óª:í3›%¹ðtm€¡Ú˜!UJè•í¶ÂàRÓေ6IÃµÖØn¯·Uð’“n£œóx�NòÜv%ÌÇ[YòΕe´‡‹sÛÒ+dhg“Åųà÷éq>0ãJ8ë= ËmÁ-¬µÆVï•û4]UŽéW&ýäYe”&e^ÉZX[®ù4ƒ­°KÇŠ•‡Óˆnt¿.âm’cµ]¾(?Ó�òEñï(ÉêjíG:гÊ,k®Œß™ú¡îÚHqJ¾=ö9à˜Ή•¤º4™2ÕrÆfK­°ë{oWÄ� ¨¡�ë4×@•Å‹pÞ·N:*Ïl’±üJ8ð‚â%J+Ê9ß8é„Ó‘¼]ÅUüÏà_,”2y}F7˜%tEXtdate:create2024-01-16T00:48:30+00:00~iã˜%tEXtdate:modify2024-01-16T00:48:30+00:004[$IEND®B`‚epasveer-seer-97076f1/src/resources/flathub/io.github.epasveer.seer.desktop000066400000000000000000000004551526321767600270470ustar00rootroot00000000000000[Desktop Entry] Version=1.0 Type=Application Name=seer GenericName=GDB Frontend Comment=A GUI frontend to the GDB debugger Icon=io.github.epasveer.seer Exec=seergdb Terminal=false Categories=Development;Debugger;Qt; Keywords=debug;gdb;debugger;qt; StartupNotify=true X-Flatpak=io.github.epasveer.seer epasveer-seer-97076f1/src/resources/flathub/io.github.epasveer.seer.github.yml000066400000000000000000000013021526321767600274500ustar00rootroot00000000000000app-id: io.github.epasveer.seer runtime: org.kde.Platform runtime-version: '6.10' sdk: org.kde.Sdk command: seergdb finish-args: - --socket=fallback-x11 - --socket=wayland - --device=dri - --device=all # Needed for stdout/stdin to debug target - --share=ipc - --filesystem=host # Filesystem access for debugging programs - --talk-name=org.freedesktop.Flatpak # Permission to `flatpak-spawn --host` modules: - name: seergdb buildsystem: cmake-ninja builddir: true subdir: src config-opts: - -DCMAKE_BUILD_TYPE=Release - -DCONFIG_SEER_INSTALL_FLATHUB_FILES=1 sources: - type: dir path: ../../.. skip: - .git - repo epasveer-seer-97076f1/src/resources/flathub/io.github.epasveer.seer.metainfo.xml000066400000000000000000000031131526321767600277710ustar00rootroot00000000000000 io.github.epasveer.seer CC0-1.0 GPL-3.0-or-later https://github.com/epasveer/seer seer A GUI frontend to GDB debugger io.github.epasveer.seer

Seer is a graphical frontend to the GDB debugger that provides a rich development environment for debugging programs.

Features:

  • Source code browsing and breakpoint management
  • Variable inspection and modification
  • Stack frame navigation
  • Memory inspection
  • Assembly view
  • Register view
io.github.epasveer.seer.desktop Main debugging window https://raw.githubusercontent.com/epasveer/seer/main/images/mainview.png https://github.com/epasveer/seer https://github.com/epasveer/seer/issues Ernie Pasveer
epasveer-seer-97076f1/src/resources/flathub/io.github.epasveer.seer.yml000066400000000000000000000013701526321767600261740ustar00rootroot00000000000000app-id: io.github.epasveer.seer runtime: org.kde.Platform runtime-version: '6.10' sdk: org.kde.Sdk command: seergdb finish-args: - --socket=fallback-x11 - --socket=wayland - --device=dri - --device=all # Needed for stdout/stdin to debug target - --share=ipc - --filesystem=host # Filesystem access for debugging programs - --talk-name=org.freedesktop.Flatpak # Permission to `flatpak-spawn --host` modules: - name: seergdb buildsystem: cmake-ninja builddir: true subdir: src config-opts: - -DCMAKE_BUILD_TYPE=Release - -DCONFIG_SEER_INSTALL_FLATHUB_FILES=1 sources: - type: git url: https://github.com/epasveer/seer.git tag: v2.8 commit: 14266cc49a17d2b0abcef580dcce677ec98ac1fb epasveer-seer-97076f1/src/resources/help/000077500000000000000000000000001526321767600203155ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/help/ArrayVisualizer.md000066400000000000000000000051041526321767600237730ustar00rootroot00000000000000## Array Visualizer ### Introduction The Array Visualizer shows the contents of one or two variables, that are arrays, in a graph/chart view. When providing two arrays, they can be treated as two independant arrays (assigning both to the Y axis) or one array can be the X points and the other array can be the Y points. There are different views of the plot (line, spline, scatter) and the array values can be shown as points and/or labels. The Array Visualizer is made up of 3 main parts: * Input parameters * Values table * Plot area The plot area is a typical graph that has its 'Y' axis on the left side and the 'X' axis across the bottom. ``` ^ | | Y | | | | +---------------------------------> X ``` ### Input parameters This part of the Visualizer specifies the one or two arrays to view. If one array is to be viewed, leave the second entry blank. Otherwise, enter the array details for both arrays. Here are the details for an array. * Axis. Specify what axis the array is for. Can be 'Y' or 'X'. 'Y' is the default. * Variable name. The name name should resolve to an address. * Number of elements. The total length of the array. * Array offset. How many elements to initially skip. Default 0 (start at the begining of the array). * Array stride. How the elements are accessed in the array. Default 1 (use every element). 2 would access every second element. * Array data type. * Refresh. By having array offset and array stride, it's possible to handle the case of a single array containing X/Y points as alternating X and Y values. ### Values table This part of the Visualizer shows the arrays values as one or two columns. The number of rows in the column is the number of elements in the array. Note, the array offset and array stride is taken into account. Each column in the table will have a title, which reflects the variable name and the array offset and stride: ``` &array:0:1 ``` ### Plot area This area shows the plot for the one or two arrays. The plot can be modified with: * Chart title. Add a title to the top of the plot. * Plot mode * Line. Simple line plot. * Spline. Points are plotted using splines. * Scatter. Points are plotted using scatter points. * Annotation * Points. Visually show the points. * Labels. Annotate the value at each point. ### Operation The plot area can be interactive in these way: * '+', '-', mouse scroll button. Zoom in or out of the plot. * LMB drag and hightlight. Zoom in on the selected region. * Shift+LMB. Drag plot around. * 'esc'. Reset plot area. epasveer-seer-97076f1/src/resources/help/AttachDebugMode.md000066400000000000000000000011451526321767600236200ustar00rootroot00000000000000## Attach debug mode ### Introduction This mode allows Seer to debug a locally running process by attaching to the PID. ### Requirements In this mode, Seer needs: * The executable * Optional symbol file if the executable doesn't have debug information * The PID of the process. ### What can you do? In this mode, Seer will attach to the process and immediately interrupt it with a SIGINT. Seer will show the source and line number where the program was interrupted. The program's stack and threads are shown. From this point, you can debug the process as normal (stepping and setting breakpoints, etc...) epasveer-seer-97076f1/src/resources/help/BasicStructVisualizer.md000066400000000000000000000037511526321767600251510ustar00rootroot00000000000000## Basic Struct Visualizer ### Introduction The Struct Visualizer shows the contents of C/C++ structs and classes in a tree view. It is read-only and doesn't follow pointers. Use the regular Struct Visualizer for that. For each variable of the struct, Seer shows these two columns: * Variable name * Value *Variable name* is the name of the variable, at that point in the stuct hiearchy. *Value* is the value of the variable, presented in the best way possible by gdb. This version of the Struct Visualizer expands to all levels when the variable is first entered. After that, levels can be collapsed or expanded again. Also, variables that are pointers are never followed. Use the new implementation for that :^) ### Operation The Struct Visualizer has these main components * Variable entry field * Refresh * Auto mode * Variable Tree ### Variable entry field This entry field allows you to enter the name of a variable. This variable can be for a struct or a class. It could also be a simple datatype like an *int* or a *string* but that would be pointless as simple datatypes have no nesting structure. Enter the variable name and hit return. All levels of the struct will be shown. If it has any subvalues, a '+' icon will appear beside it so that it can later be collapsed. Note, if the variable name is not valid, a message will be printed in the Value field. ### Refresh This will refresh the tree with any variables that have changed values since the last time. ### Auto mode This mode will refresh the tree each time Seer reaches a stopping point (when you 'step' or 'next' or reach a 'breakpoint'). ### Variable tree As mentioned, the variable tree shows the variable names and values of the struct. A '+' icon is shown beside each level. This will expand or collapse the level. ### Modifying values. This implementation has no feature to modify values. ### Invoking other Visualizers. Using the RMB on a variable will bring up a menu to launch another Visualizer for that variable. epasveer-seer-97076f1/src/resources/help/BreakpointGdbSeerManager.md000066400000000000000000000130171526321767600254660ustar00rootroot00000000000000## Breakpoint/GDB log Manager ### Introduction This part of Seer shows Breakpoints, GDB log, and Seer log information. In detailed, the information is: * Messages * Breakpoints * Watchpoints * Catchpoints * Printpoints * Checkpoints * GDB output * Seer output * Save and load breakpoints * Manual GDB commands. ### Messages Various gdb execution messages are listed in this tab. These occur as you debug the program. The message types are: * Program startup and completion * Breakpoint encouters * Signal encounters * General gdb errors The message tab can be raised in various ways when a message is added to the tab: * Any message * Important messages (program startup, signal encounters) * Never ### Breakpoints Breakpoints sets up a stopping point of the program being debugged when a function and line number is reached. ### Watchpoints Watchpoints catch the access and/or modification of a variable and will stop the program being debugged at that point. ### Catchpoints Catchpoints catch the execution of one of these program actions just before they are called and will stop the program being debugged at that point. * C++ * throw * rethrow * catch * Shared Library * Load * Unload * Ada * assert * exception * handlers There are other types of catchpoints but GDB/mi only supports the above list at the moment. ### Printpoints A printpoint is a type of breakpoint that will print the value of a variable at a certain line of a function. It relies on gdb's ```dprintf``` feature. ### Checkpoints A checkpoint is a simple form of time-travel debugging. You can create a checkpoint at any point where the program you're debugging is stopped. This checkpoint is listed in the Checkpoints tab. You can continue to debug your program. At any time, you can return back to the checkpoint (go back in time) and continue debugging again from that point. You can create as many checkpoints as you want and switch between them. A couple things to note: * This is not supported on all platforms. * Switching to a previous checkpoint does not undo any I/O. You can't unwrite data written to a file or unprint text sent to a printer. ### Modifying existing breakpoints. Once a breakpoint (Breakpoint, Watchpoint, Catchpoint, Printpoint) is created, certain things about the breakpoint can be modified. Not everything, though. For example, you can not change the function or line number for a breakpoint. In that case, you need to delete the breakpoint and recreated it. These things can be modified. * Enable/disable state. * Add or remove a condition. eg: Break if 'i == 10'. * Add or remove an ignore count. eg: Ignore the first 5 occurences of the breakpoint. * Add or remove a series of gdb commands to execute when the breakpoint is reached. Not available for Printpoints. ### GDB output Any output from the GDB program is output to this logger. This is any regualar GDB output, including the result of any GDB command manually entered. ### Seer output Any output from the Seer program is ouput to this logger. Mostly, this is the result of any GDB/mi command, whether the GDB/mi command is manually entered or entered by Seer. Normally this logger is disabled. ### Console output Any output from the program being debugged is output to this logger. Basically, the program's stdout. The stdout can also be echoed to the terminal that started Seer. This logging tab can be started attached along side the other loggers. Or detached as a normal window. Or detached as a minimized window. See Seer's config dialog or View->Console menu option. Be sure to save the config changes. If the program being debugged is asking for stdin input, it can be entered in the "stding input text" field. ### Save and load breakpoints There are two buttons to save or load the various types of breakpoints to/from a file. The breakpoint file can be specified in the Debug dialog or on the command line: ``` --bl, --break-load ``` ### Manual gdb commands This input field allows GDB and GDB/mi commands to be manually entered. The results of the GDB commands will be logged to the GDB output. GDB/mi will be logged to the Seer output. Seer maintains a history of N commands, as set in the Seer Config dialogs. This history is remembered for the next time Seer is used. ### Macro gdb commands There are 10 macros you can create for custom commands. They are labelled "M1" through "M0". Think of your keyboard with numeric keys 1 through 0. They have hotkeys mapped from Ctrl+Shift+1 through Ctrl+Shift+0. Clicking the button or using the hotkey will execute the commands in the macro. Holding down the button will bring up an editor to edit the contents of the macro. A "nickname" can be assigned to the macro. This will be shown in the macro tooltip. Typically the macro contains gdb commands. Output will go to the GDB output tab. The macro is executed as if its commands are typed at the (gdb) prompt. ### References Consult these gdb references 1. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Set-Breaks.html#Set-Breaks) Using Breakpoints. 2. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Set-Watchpoints.html#Set-Watchpoints) Using Watchpoints. 3. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Set-Catchpoints.html#Set-Catchpoints) Using Catchpoints. 4. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Dynamic-Printf.html#Dynamic-Printf) Using DPrintf for Printpoints. 5. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Checkpoint_002fRestart.html#Checkpoint_002fRestart) Using Checkpoints. epasveer-seer-97076f1/src/resources/help/CodeManager.md000066400000000000000000000046241526321767600230120ustar00rootroot00000000000000## Code Manager ### Introduction This is the main part of Seer that shows source files as they are opened. Opening a source file can happen in three ways: * The program reaching a stopping point (via a 'step', 'next', or breakpoint). * Clicking on a frame in the Stack Info browser. * Clicking on a filename in the Source browser (Source/Symbol/Library browser). As well as the source files, Seer can show the code's assembly as a tab. See: ``` View->Assembly ``` Or ``` Config->Assembly ``` When in a source file, using the RMB will bring up a menu to do any of these: * Create a breakpoint * Create a printpoint * Enable/disable a breakpoint or printpoint * Execute the program to a certain line in the source file. Selecting a variable (highlighting) will allow that variable to be added to one of these via the RMB: * Variable Logger * Variable Tracked * Memory Visualizer * Array Visualizer * Struct Visualizer ### Keys The easiest method for logging a variable to the Variable Logger is to double-click the variable text in the source. When doing this, a key modifier (shift and/or ctrl) can be used to prepend a '*' and/or '&' to the variable. This will better handle pointers and references. ``` Double-Click Modifier Description Example ------------ ------------------------------------ ----------------------- None No modifier is prepended to variable 'argc' Shift Key Prepend '&' to variable '&argc' Ctrl Key Prepend '*' to variable '*argc' Ctrl+Shift Prepend '*&' to variable '*&argc' ``` Other key sequences. ``` Keys Description ------------ ------------------------------------ Ctrl+LMB Goto function defintion identified by text under cursor. ^F Bring up a text search bar in the source window. ^L Bring up a line number search bar in the source window. ^O Bring up a file bar to help locate the file for the source (in case it isn't in the directory that GDB thinks it is). ``` ### Buttons There are these buttons: * File open. Open a file. Can be any file, as long as it is plain text. * Close files. Bring up a dialog to easily select source files to close. * Search. Open the search bar. epasveer-seer-97076f1/src/resources/help/ConnectDebugMode.md000066400000000000000000000025111526321767600240030ustar00rootroot00000000000000## Connect debug mode ### Introduction This mode allows Seer to debug a local or remote process that was started with gdbserver (or other gdb servers). Typically, the gdbserver starts the process and interrupts it before anything happens. It then waits for something to connect to it. When Seer connects with it, the process is ready to continue executing. ### Requirements In this mode, Seer needs: * Optional executable file if the remote gdbserver/gdbstub hasn't loaded one * Optional symbol file if the executable doesn't have debug information * How to look for the gdbserver (machine and port) * Remote target type when connecting to the gdbserver. * 'extended-remote' (default) * 'remote' (sometimes required if gdbserver doesn't support all commands) * Optional enabling of gdb and gdbserver debug communication (set debug remote 1). See the gdb tab for output. * Optional gdb commands to execute before and after Seer connects to the gdbserver ### What can you do? In this mode, Seer will connect to the process via the gdbserver. Typically you set breakpoints first then tell the process to continue. From this point, you can debug the process as normal (stepping and setting breakpoints, etc...) ### References Check references for gdbserver and other gdb servers. * gdbserver * valgrind vgdb * servers for embedded development epasveer-seer-97076f1/src/resources/help/CorefileDebugMode.md000066400000000000000000000020101526321767600241340ustar00rootroot00000000000000## Corefile debug mode ### Introduction This mode allows Seer to debug corefiles. Corefiles are files that are the state of a process that exits unexepectedly via a signal (SIGTERM, SIGSEGV, etc...) ### Requirements In this mode, Seer needs: * The executable * Optional symbol file if the executable doesn't have debug information * The corefile. ### What can you do? In this mode, Seer will load the executable and the corefile. It will try to show the reason for the corefile (which signal). Look for this in the "GDB output" tab. Seer will also show the source and line number where the program crashed. You won't be able to do any stepping. You can move through the stack and show values of variables and memory, though. ### References Check your system's configuration to see how to enable corefile generation. Some distros have it disabled by default. Also, corefiles may not be located in the directory where the program ran. They may be located in some system directory (eg: /var/local/dumps). Check your distro. epasveer-seer-97076f1/src/resources/help/DebugModes.md000066400000000000000000000020201526321767600226470ustar00rootroot00000000000000## Seer debug modes ### Introduction Seer supports most debugging modes that gdb provides. These are: * Starting and running a program * Attaching to a local process on the system * Connecting to a gdbserver * Loading a previously created RR trace session * Loading a corefile leftover from a program that crashed ### What can you do? Select the mode and enter the appropriate arguments and settings. For all modes, you can specify 'pre' and 'post' native gdb commands. * 'pre' - gdb commands to execute before the executable is loaded (or attach, or connect, or loading of corefile). * 'post' - gdb commands to execute afterwards Click OK and Seer will start the debugging session. ### Projects A project file can be created. The project file will save: * Name of executable * Name of symbol file * Working directory * All arguments and settings for the selected mode * All 'pre' and 'post' commands The project file can then be loaded the next time Seer is used. The project file has a simple Json layout and can be hand edited. epasveer-seer-97076f1/src/resources/help/GdbMonitor.md000066400000000000000000000037301526321767600227060ustar00rootroot00000000000000## GDB Monitor ### Introduction The GDB monitor is used when gdb is communicating with some gdb "server", like the gdbserver program. The monitor provides extra commands that are directed to the "server" and not to the executable the "server" is running. For example, when using gdbserver as the "server", you can send the "monitor exit" command. It will tell gdbserver to exit. There are other types of "servers" other than gdbserver. For example, valgrind's vgdb server has its own set of commands. And they are different to the commands that gdbserver understands. OpenOCD is another "server" that is used when debugging Embedded MCUs. It, again, has its own set off commands. The rocgdb debugger is based on gdb. It has additions to gdb's monitor command. ``` (gdb) monitor set rocm ``` One thing in common is they all seem to accept the "help" command. Which will print the commands and options that "server" supports. ``` (gdb) monitor help ``` ### The View. The GDB monitor view contains 4 main sections. * A large text area that contains the text recieved from the "server". * 10 customizable macros. * A input field to easyly enter a command for that "server". * Clear, save, and print buttons. All responses from the "server" are printed to the bottom of the large text area. Any command that is sent to the "server" (using a macro or entering it from the input field) is first printed to the text area. Macros are created by holding the macro button down and selecting "Edit Macro". Enter the "server" command you wish the macro to perform then click "Ok". Note, you don't need to enter "monitor help". Just "help" is expected. Set up macros for your commonly used commands. The input field can be used for other monitor commands. Again, just type "help" and not "monitor help". The large text area can be cleared, saved to a file, or printed. ### Resources https://sourceware.org/gdb/current/onlinedocs/gdb.html/Server.html https://openocd.org/doc/html/General-Commands.html epasveer-seer-97076f1/src/resources/help/ImageVisualizer.md000066400000000000000000000036131526321767600237420ustar00rootroot00000000000000## Image Visualizer ### Introduction The Image Visualizer shows the contents of a region of memory as an image. ### Operation There are various things to control how the image is display. * Starting address entry field * Image format * Image width * Image height * Refresh * Auto Refresh A check is done to ensure the amount of memory given to the Memory Visualizer will cover the image size. If there is a problem, it's likely the wrong format is selected. ### Starting address entry field The 'Starting Address' input field takes the name of a variable that is in the current Stack Frame (selected by the Stack Frame browser). This variable should result in an address. For example, take this code: ``` int var = 10; ``` To visualize the memory for 'var', the variable should be '&var', not 'var'. As 'var' doesn't resolve to an address. Note, the variable name can be an address. Enter the address like: ``` 0xdeadbeaf ``` It can be the result of a function in your program. ``` myimage.pointer() ``` It can also be one of gdb' special variables. Like the program counter. Enter it like: ``` $pc ``` ### Image format. Two supported formats are available. Others can be added easily. * RGBA8888 * RGB888 ### Image dimensions. The image width and height, in pixels. These fields can take a gdb expression that result with an integer. ``` An integer value A function that returns an integer value A gdb special variable. ``` Examples are: ``` 256 myimage.width() $r9 ``` ### Refresh This will refresh the image since the last time. ### Auto mode This mode will refresh the image each time Seer reaches a stopping point (when you 'step' or 'next' or reach a 'breakpoint'). ### Image interaction Available Quick keys while in the Image Visualizer: ``` '+' zoom in '-' zoom out ESC reset to default zoom level. Ctrl+mouse wheel zoom in or out. ``` epasveer-seer-97076f1/src/resources/help/MainWindow.md000066400000000000000000000030421526321767600227120ustar00rootroot00000000000000## Seer Main Window ### Main Tool Bar The main tool bar has buttons for Seers's common functions. Most of these buttons also have hotkeys assigned to them. These can be configured with "Settings->Configure->Keys". The buttons are arranged in groups. * Starting/Restarting the debug session. * Debug - Start a new debugging session. * Restart - Restart the current debugging session. Stop in main(). * Terminate - Terminate the current debugging session. * Stepping. * Continue - Continue the program until it encounters the next breakpoint or it ends. * Next - Execute the next line. Step over if it's a function. * Step - Exectue the next line. Step into it it's a function. * Finish - Finish the current function. Honor any breakpoints. * Instruction recording. Use gdb's instruction and playback feature. * Record - Start the record mode. * Direction - Set playback mode. Forward or reverse. The direction affects the Stepping functions. * Program interruption. Interrupt the running program or send it a specific signal. * Visualizers * Memory - Visualize a region of memory in a 'hex viewer'. * Array - Visualize a region of memory as arrays. A table and 2D plot. * Matrix - Visualize a region of memory as a 2D table of values. * Struct - Visualize a region of memory as a nested C/C++ structure. * Basic Struct - Similiar as 'Struct' but doesn't follow pointers. * Image - Visualize a region of memory as a RGB or RGBA image. * Parallel Stacks - View and interact with threads. (BETA) epasveer-seer-97076f1/src/resources/help/MatrixVisualizer.md000066400000000000000000000030651526321767600241650ustar00rootroot00000000000000## Matrix Visualizer ### Introduction The Matrix Visualizer shows the contents of an array as a matrix, a number of rows and an number of columns. The Matrix Visualizer is made up of 3 main parts: * Input parameters * Values table * Statistic information ### Input parameters This part of the Visualizer specifies the array to view. Here are the details for an array. * Variable name of the array. The name name should resolve to an address. * Number of rows and columns. The total length of the array is determined from this. * Array offset. How many elements to initially skip. Default 0 (start at the begining of the array). * Array stride. How the elements are accessed in the array. Default 1 (use every element). 2 would access every second element. * Array data type. * Array memory layout. How the 2D matrix is laid out in memory: row-major (row by row) or column-major (column by column * row-major (C, NumPy) * column-major (Fortran, Eigen) * Refresh. By having array offset and array stride, it's possible to handle oddly constructed arrays. ### Values table This part of the Visualizer shows the array's values as a matrix. The number of rows and number of columns reflect the values entered in the input parameters. Note, the array offset and array stride is taken into account. ### Statistic information These statistical values are calculated from the array values. * Count of values * Count of number of rows * Count of number of columns * Minimum value of values * Maximum value of values * Sum of values * Average value * Median value * RMS value epasveer-seer-97076f1/src/resources/help/MemoryVisualizer.md000066400000000000000000000054531526321767600241740ustar00rootroot00000000000000## Memory Visualizer ### Introduction The Memory Visualizer shows the contents of a region of memory in different formats, including strings and assembly. * Hex * Octal * Binary * Decimal * Ascii * UTF-8, UTF-16, UTF-32 * Ebcdic * Assembly The memory displayed in 3 views. * A memory dump in the chosen Display format. Included in this view is the memory displayed in the Character format. A byte can be selected in this view to highlight it. * A table showing the highlighted byte in different numeric formats (int, float, double, etc...). * A separate tab showing the memory as disassembly. A CRC16 checksum of the memory region is also displayed. Useful for quickly determining if different memory regions have the same contents. Changes with the memory contents between step/next/breakpoints will show changed bytes with an underline. This requires 'Auto Refresh' on. ### Operation There are various things to control how the memory is display. * Starting address entry field * Number of bytes entry field * Display format * Character format * Column width * Refresh * Auto Refresh ### Starting address entry field The 'Starting Address' input field takes the name of a variable that is in the current Stack Frame (selected by the Stack Frame browser). This variable should result in an address. For example, take this code: ``` int var = 10; ``` To visualize the memory for 'var', the variable should be '&var', not 'var'. As 'var' doesn't resolve to an address. Note, the variable name can be an address. Enter the address like: ``` 0xdeadbeaf ``` It can also be one of gdb' special variables. Like the program counter. Enter it like: ``` $pc ``` ### Number of bytes entry field The default number of bytes to display is 256. Fewer or more than this number can be entered. This can take a gdb expression. * A value. '100' * An expression. '100+50' * The result of a function in the program. 'myarraysize()' ### Display format. The memory dump can be displayed in these formats: * Hex * Octal * Binary * Decimal ### Character format The memory dump can be displayed in these character formats: * Ascii * UTF-8, UTF-16, UTF-32 * Ebcdic Note, when displaying UTF, some features in the visualizer are restricted. For example, when clicking on a byte in the memory dump, the corresponding character in the text view is not highlighted. This is because UTF can be a variable length of bytes per character - due to UTF encoding. A possible delay may happen to load the extra fonts needs for the extra characters that UTF provides. ### Column width This specifies the column width of the memory dump. ### Refresh This will refresh the memory dump since the last time. ### Auto mode This mode will refresh the memory dump each time Seer reaches a stopping point (when you 'step' or 'next' or reach a 'breakpoint'). epasveer-seer-97076f1/src/resources/help/ParallelStacksVisualizer.md000066400000000000000000000144251526321767600256300ustar00rootroot00000000000000## ParallelStacks Visualizer ### Introduction The ParallelStacks Visualizer shows all the thread's stack frames as a node graph. This visualizer is dynamic. In that thread nodes can be interacted with to tell Seer to switch to different threads and frames within that thread. Likewise, if Seer's regular Frame and Thread views are used to change the current Frame or Thread, the ParallelStacks Visualizer will get updated. This Visualizer is taken from a feature in VSCode. ### Refresh This will refresh the image since the last time. ### Auto mode This mode will refresh the image each time Seer reaches a stopping point (when you 'step' or 'next' or reach a 'breakpoint'). Note, this can be costly. ### Method View The view mode combobox selects between 'Stack' and 'Method'. 'Stack' shows every thread's stack. 'Method' pivots the graph on a single function — the one in the current thread's current frame. That function is shown alone in the highlighted (heavier-bordered) box in the middle, merging every thread that calls it, however it got there. Threads that never call it are left out. * Above the pivot are its callees — what each of those threads is doing inside it. * Below the pivot are its callers — the paths that led to it, down to each thread's entry point. The pivot box's header shows how many threads call the function. If the function is recursive, the graph pivots on its innermost call. Like the Visual Studio feature, Method View follows the debugger: selecting a different thread or stack frame (in Seer's thread or stack frame browsers, or in the graph's own thread popup) re-pivots the graph on that frame's function. ### Search The search field highlights every frame, in every node, whose function name matches the typed text (case-insensitive). With 'Regex' checked, the text is a regular expression. Unchecked, it's matched as plain text, so characters like '(', '*' or '[' need no escaping. Matching nodes are also colored in the minimap. If a node's middle frames are hidden by the stack size setting, its '[...]' row is highlighted when any of those hidden frames match. Typing jumps to the first matching node. 'Enter' (or 'Ctrl+G') moves to the next matching node and 'Shift+Enter' (or 'Ctrl+Shift+G') to the previous one. The label beside the field shows which match you're on; hover over it for the total count of matching frames. The search is reapplied whenever the graph is refreshed. ### Filter The filter button (the funnel) opens a list of every library, function and thread found in the threads' stacks, arranged as a tree: library, then the functions in that library, then the threads that call each function. Frames with no shared library (the program itself) are listed under '(program)'. The text field at the top narrows the list. Checking items hides every thread that doesn't pass through them. A thread is shown if any of its frames is in a checked library or a checked function, or if the thread itself is checked. Checking a library or function checks everything under it. The graph updates as you check items, and the filter button stays pressed while a filter is active. Hover over it to see how many threads are shown. 'Clear Filters' unchecks everything and shows all threads again. The filter applies to both the 'Stack' and 'Method' views, and is kept when the graph is refreshed. Libraries and functions are remembered by name and threads by id, so they apply to whatever stacks the next refresh brings. ### External Code Frames without debug info (library or system code, like libc's thread start-up or a futex wait) are normally of little interest. Each run of consecutive frames like that is merged into a single '[External Code]' frame. Threads whose stacks differ only inside external code then share a node instead of each getting their own. Search sees through an '[External Code]' frame: it's highlighted when any of the functions it stands in for match. If the current frame is inside external code, its '[External Code]' frame is the one shown in bold. In Method View, the pivot function is never merged, even when it has no debug info. To see every frame, check 'Show External Code' in the settings dialog (see Settings, below). ### Settings The settings button opens a dialog that controls how the graph is drawn. The settings are remembered between sessions, and the graph is redrawn when the dialog is closed with 'OK'. * **Show Minimap** — A small overview of the whole graph, in the corner of the view. The rectangle in it marks the part of the graph that's visible. Click or drag in it to jump around the graph, and Shift+drag to move the minimap itself. * 'Auto' shows it only when the graph doesn't fit in the view (when there are scrollbars). * 'Always' shows it all the time. * 'Never' hides it. * **Function Name Length** — With 'Full' checked, function names are shown at their full length. Unchecked, names longer than the given number of characters are shortened by replacing their middle characters with ' ... '. Useful for long C++ template names. The default is 64. * **Stack Frame Size** — With 'All' checked, every frame of a node is shown. Unchecked, a node with more frames than the given number shows only that many: half from the top of its stack and half from the bottom. A single '[...]' row stands in for the frames left out of the middle. The default is 20. * **Show External Code** — Unchecked (the default), each run of frames without debug info is merged into a single '[External Code]' frame (see External Code, above). Checked, every frame is shown. ### ParallelStacks interaction Available Quick keys while in the ParallelStacks Visualizer: ``` '+' Zoom in. '-' Zoom out. MouseScroll Zoom in and out. ESC Reset to default zoom level. Ctrl+F Focus the search field. Ctrl+G Jump to the next search match. Ctrl+Shift+G Jump to the previous search match. Shift+LMB Grab a stack node so it can be moved. Hover Over a stack node to pop-up its list of threads. LMB+Click On one of the threads in the pop-up to select that thread. ``` ### Resources [Seer Issue](https://github.com/epasveer/seer/issues/312) [GDB python script](https://github.com/bravikov/parallel-stacks) epasveer-seer-97076f1/src/resources/help/Printpoints.md000066400000000000000000000102451526321767600231720ustar00rootroot00000000000000## Printpoints ### Introduction Printpoints are a type of gdb breakpoint that simply prints a custom message when the breakpoint is reached. After the message is printed, the program is continued automatically. So, basically, a way to add print statements without adding them to your code. ### Printpoint types There are 3 types of printpoints. ### 'gdb' printpoints The ```gdb``` printpoint is the most common. When used, it uses gdb's ```printf``` command, which provides C style formatting. Consider this example of code: ``` 12 13 std::cout << " C++ loop" << std::endl; 14 for (n=1; n<=count; n++) { 15 nfact = nfact * n; 16 std::cout << std::setw(12) << n << std::setw(14) << nfact << std::endl; 17 } 18 ``` A printpoint can be added to line 15 to print the value of ```n``` and ```count```. Create a printpoint by RMB clicking on line 15 of source, or click 'Add a new printpoint' in the Printpoints tab. Fill in the name of the source file and the line number. Now fill in the printpoint details: ``` Format : "N=%d COUNT=%d\n" Arguments : n count Type : gdb Function : Channel : ``` When you run your program, the print statements will appear in Seer's Gdb tab. ### 'call' printpoints The ```call``` printpoint type allows you to use an alternate ```print``` function instead of gdb's ```printf``` command. There are a couple restrictions for this ```print``` function. - Must have a signature that takes VA_ARGS. - Needs to be part of your program. ie: linked in or part of some .so, like glibc. There are 2 ```call``` methods. One without a "channel" and one with a "channel". What is a "channel"? It's like the first argument to ```fprintf()```, or ```dprintf()``` *** Here is an example of ```call``` without a "channel". It will use ```printf()``` from glibc. We'll use the same code example and will add the printpoint on the same line number. ``` Format : "N=%d COUNT=%d\n" Arguments : n count Type : call Function : printf Channel : ``` When you run your program, the print statements will appear in Seer's Console tab. *** Here is an example of ```call``` ***with*** a "channel". It will use ```dprintf()``` from glibc, which takes a file descriptor as its first argument. We'll be using FD of 1, which is stdout. We'll use the same code example and will add the printpoint on the same line number. ``` Format : "N=%d COUNT=%d\n" Arguments : n count Type : call Function : dprintf Channel : 1 ``` When you run your program, the print statements will appear in Seer's Console tab. ### 'agent' printpoints If your program is started with ```gdbserver```, a printpoint type of ```agent``` will tell the gdbserver to print the message. First, start the program using ```gdbserver```. ``` $ gdbserver :1234 hellodprintf ``` Then start Seer and connect to the ```gdbserver```. We'll use the same code example and will add the printpoint on the same line number. ``` Format : "N=%d COUNT=%d\n" Arguments : n count Type : agent Function : Channel : ``` The print statements will appear from the ```gdbserver``` process. ### Warnings Printpoints, actually ```dprintf```, are not very error friendly. Errors in your parameters are not checked until the breakpoint is reached. This can cause gdb to behave poorly or can, most likely, confuse Seer. You'll end up restarting your debugging session. The ```call``` method seems to work only with C/C++ code. It doesn't work with Fortran. Not sure about any other language. The error message is very vague and appears in the Gdb tab as "parsing error". Seer ends up in a confused state. ### References Printpoints use gdb's ```dprintf``` command. Not to be confused with the C language's ```dprintf()``` function. https://sourceware.org/gdb/current/onlinedocs/gdb.html/Output.html https://sourceware.org/gdb/current/onlinedocs/gdb.html/Dynamic-Printf.html Here's a good article from Andreas Heck where he creates a custom ```print``` function that writes to a file, instead of stdout. This works with a ```call``` printpoint without a channel. https://abstractexpr.com/2024/03/03/dynamic-printf-debugging-with-gdb/ epasveer-seer-97076f1/src/resources/help/RRDebugMode.md000066400000000000000000000042411526321767600227370ustar00rootroot00000000000000## RR debug mode ### Introduction This mode allows Seer to debug a RR replay session. RR allows time-travel debugging. In that, you can step forward or backwards in the execution of program being debugged. gdb has its own notion of time-travel debugging. However, it differs from RR's method. With gdb, the record of instructions is recorded as you are debugging the program. With RR, the record of instructions are made once when you run the program with 'rr record'. Seer can then load the recording (aka: trace-directory) by running the 'rr replay -s' command. Further information on RR is listed below in the references. ### Requirements In this mode, Seer needs: * Optional symbol file if the recording doesn't have debug information * A path to the directory containing the RR recording (aka: trace-directory) * Optional gdb commands to execute before and after Seer connects to the RR replay session See the RR config settings set the path to the RR program. ``` Settings -> Configure -> RR ``` ### What can you do? In this mode, Seer will load the RR replay session by running 'rr replay'. The program will be stopped befor 'main'. At this point you can set breakpoints and tell Seer to 'continue' or any typical debugging command. Seer will show a 'Direction' arrow on the toolbar. This will set the debugging direction to forward or reverse. And affects all commands like: 'step', 'next', 'finish', etc. A typical debugging sequence would look like: ``` # Use RR to record all instructions for a program. # The recording will be saved to 'hellosegv.rr' $ rr record -n --output-trace-dir=hellosegv.rr hellosegv one two three # Use Seer to debug this recording. Can be done as many times as you # want without creating a new recording. $ seergdb --rr hellosegv.rr ``` Now use Seer as you normally would. Use the Direction arrow in the main toolbar to change debugging directions. ### References Check references for RR and gdb. * [RR website](https://rr-project.org) * [RR github](https://github.com/rr-debugger/rr/wiki/Usage) * [gdb's record mode](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Process-Record-and-Replay.html#index-record-mode) epasveer-seer-97076f1/src/resources/help/RunDebugMode.md000066400000000000000000000031021526321767600231530ustar00rootroot00000000000000## Run debug mode ### Introduction This mode allows Seer to debug a program by starting the program itself. This is the most typical way of using Seer. ### Requirements In this mode, Seer needs: * The executable * Optional symbol file if the executable doesn't have debug information * Optional working directory to run the program from * Arguments to run the program with * Various Seer/gdb options to start the program by ### What can you do? There are a couple gdb settings that you can choose from when running the executable. The main one, though, is the initial breakpoint, which there are four ways: * Break in 'main'. The program is started and breaks in the program's main function. The definition of 'main' is language dependant. Seer/gdb will stop in the initial function for that language. * Break in 'function'. The program is started and breaks in a named function or at an address. * Break at 'source'. The program is started and breaks at a line number of a source file. eg: myprog.cpp:36 * Break at first instruction. The program is started and breaks at the first cpu instruction. This is usually before 'main'. This mode is useful for programs written in Assembly. * No initial breakpoint. The program is started and executes without any breakpoints unless they are specified in the optional breakpoint file. The program will run til the end or when it encounters a signal or breakpoint. No source files will be loaded until a signal or breakpoint is encountered. From this point, you can debug the process as normal (stepping and setting breakpoints, etc...) epasveer-seer-97076f1/src/resources/help/Skips.md000066400000000000000000000046551526321767600217420ustar00rootroot00000000000000## Skips ### Introduction Skips are gdb's way of ignoring non-important arguments that are functions when stepping into a function to debug. For example, consider this code: ``` 101 int func() 102 { 103 foo(boring()); 104 bar(boring()); 105 } ``` ` ` Suppose you wish to step into the functions ```foo``` and ```bar```, but you are not interested in stepping through ```boring```. If you run ```step``` at line 103, you’ll enter ```boring()```, but if you run ```next```, you’ll step over both ```foo``` and ```boring```! One solution is to ```step``` into ```boring``` and use the ```finish``` command to immediately exit it. But this can become tedious if ```boring``` is called from many places. A more flexible solution is to tell gdb to execute ```boring``` with out stepping into it. The ```skip``` command does this. ### Skip types There are 4 types of skips. #### 'file' skips This skip takes a single source file. All functions descriped in the file will be skipped when stepping. #### 'file glob-pattern' skips Functions in files matching file-glob-pattern will be skipped over when stepping. #### 'function' skips This skip takes a single function specification (see the Location-Specifications link below). This function will be skipped when stepping. #### 'function regex' skips Functions whose name matches regexp will be skipped over when stepping. This form is useful for complex function names. For example, there is generally no need to step into C++ std::string constructors or destructors. Plus with C++ templates it can be hard to write out the full name of the function, and often it doesn’t matter what the template arguments are. Specifying the function to be skipped as a regular expression makes this easier. ``` ^std::(allocator|basic_string)<.*>::~?\1 *\( ``` ` ` If you want to skip every templated C++ constructor and destructor in the std namespace you can do: ``` ^std::([a-zA-z0-9_]+)<.*>::~?\1 *\( ``` ` ` ### References Here is gdb's reference for the ```skip``` command. https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html https://sourceware.org/gdb/current/onlinedocs/gdb.html/Location-Specifications.html#Location-Specifications Here's a good article from "MaskRay" where he describes skips in an easy to understand way. https://maskray.me/blog/2024-12-30-skipping-boring-functions-in-debuggers ` ` epasveer-seer-97076f1/src/resources/help/SourceSymbolLibraryInfoBrowser.md000066400000000000000000000125111526321767600267720ustar00rootroot00000000000000## Source/Symbol/Library Info Browser ### Introduction This browser allows the program's symbol table to be seached and browsed. Seer presents this information in three tabs: * Source * Functions * Types * Statics * Libraries * Ada exceptions * Skips ### Source This browser lists the source files used by the program being debugged. They are categorized into three folders bases on setting in ```Config->Source```. ``` Folder Description ---------- --------------------------------------- Source files Source files your program has. Header files Header files your program has. Misc files System related header and source files. ``` Double-clicking on a filename will load the source file in the Code Manager. Source files can be searched for using an Unix style wildcard. This will limit the number of source files listed to those that match. ### Functions This browser lists all the functions that match a Regex wildcard the program being debugged uses. This information is shown for each Function: ``` Column Description ---------- ----------------------------------------------------------------------- Function The function name. File The short name of the source file where Function is declared. Line The line number in the source file where the Function is declared on. Fullname The fullname of the source file. Type The function prototype. Description ``` Double-clicking on an entry will load the source file in the Code Manager. Using RMB on a selected etry will allow that function to be added to the breakpoint list or added to the skip list. ### Types This browser lists all the class/struct types that match a Regex wildcard the program being debugged uses. This information is shown for each Type: ``` Column Description ---------- ----------------------------------------------------------------------- Type The class/struct name. File The short name of the source file where Type is declared. Line The line number in the source file where the Type is declared on. Fullname The fullname of the source file. ``` Double-clicking on an entry will load the source file in the Code Manager. ### Statics This browser lists all the static variables that match a Regex wildcard the program being debugged uses. This information is shown for each Static: ``` Column Description ---------- -------------------------------------------------------------------- Variable The static name. File The short name of the source file where Static is declared. Line The line number in the source file where the Static is declared on. Fullname The fullname of the source file. Type The static prototype. Description ``` Double-clicking on an entry will load the source file in the Code Manager. ### Libraries This browser lists all the shared libraries that match a Regex wildcard the program being debugged uses. This information is shown for each Library: ``` Column Description ---------- ------------------------------------------------- Id Library name. Target-Name Library name. Host-Name Symbols Loaded Are symbols loaded for this library? 1 == yes. Thread Group Which thread group is this entry for. Ranges Memory range where the shared library is loaded. ``` ### Ada exceptions This browser lists all the Ada exceptions that match a Regex wildcard the program being debugged uses. The program must be an Ada program. This information is shown for each exception: ``` Column Description ---------- ------------------------------------------------- Name The name of the exception. Address The address of the exception. ``` There is a button to quickly create a catchpoint for a selected exception. Once created, Seer will stop the program when the exception is raised. ### Skip commands This browser manages the gdb skip commands you might have set up. A skip will bypass entering a function when the 'step' command is used. Skips can be described in various ways - filename, function name, and with glob wildcarding or regex. See the 'gdb skip' reference below. This information is shown for each exception: ``` Column Description ---------- ------------------------------------------------- Number The skip's interal number. Enable Is the skip enabled? Glob Is the skip a file glob wildcard? File The name of the file. Can be if the skip is a function. RE Is the skip a function regex? Function The name of the function. Can be if the skip is a file. ``` Skips can be: added, deleted, enabled, or disabled. As well, they can be saved to Seer's settings or loaded. ### References Consult these references 1. [Link](https://en.wikipedia.org/wiki/Regular_expression) Regular expressions. 2. [Link](https://en.wikipedia.org/wiki/Glob_(programming)) Unix wildcards. 3. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html) GDB Skip command. epasveer-seer-97076f1/src/resources/help/StackInfoBrowser.md000066400000000000000000000063261526321767600240730ustar00rootroot00000000000000## Stack Info Browser ### Introduction The Stack Info browser presents the program's stack information for the current thread/process. The current thread/process is set by the Thread/Process Info browser. Seer presents this information in three tabs: * Frames * Arguments * Locals ### Frames Frames is the most useful. It presents a stack frame (a traceback) for the selected thread. This information is shown for each Frame: ``` Column Description ---------- ----------------------------------------------------------------------- Level The frame level. 0 is the lowest level frame (ie: the executing frame). 1 is the caller of frame 0. 2 is the caller of 1. etc... Function The function name for the level. File The short name of the source file where Function is in. Line The line number in the source file that is being executed. Fullname The fullname of the source file. Address The frame's address in memory. ``` Clicking on a Frame Level will cause Seer to make that frame the active frame. This will in turn cause the Editor Manager to bring up the source file for the frame (if possible). Because the frame is set as the active frame, other Seer and gdb actions will default to that frame. For instance, entering a variable name in a Visualizer will use the variable in the active frame. ### Arguments This tab shows the function argument names and their value for each level. For example, if level 0 is for main(), the arguments for level 0 will be the values for argc and argv. ``` Column Description ---------- --------------------------------------------------------------------------- Level The frame level. 0 is the executing frame. 1 is the caller of frame 0. etc. Name List of variables names at the frame level. Value Value of the variables at the frame level. ``` Using the RMB will bring up a choice of Seer Visualizers and Loggers to further view the values. Note, you may need to set the level as active first in the Frames tab. ### Locals This tab shows the local values in the selected frame. Local values means the variables of the execution line in that frame, plus any established variables before the current line. Selecting a diffent frame in the Frames tab will show the locals for that frame. ``` Column Description ---------- ----------------------------------------------------------------------- Name The variable name. Arg The function argument number, if any. May appear in the Arguements tab. Value Value of the variable. ``` ### Stack This tab shows a window of bytes around the current stack pointer (SP). The window has a start address and an end address, incrementing by 2 bytes. The address of the SP is somewhere between them, depending on your settings. The bytes are shown as 2, 4, and 8 byte groupings. Each grouping can be represented as: hex, octal, int, uint, and float. The line that contains the SP is highlighted. Any line can be double-clicked to bring up a separate Memory Visualizer for the address for that line. ### Refresh The refresh button refreshes the currently exposed tab. epasveer-seer-97076f1/src/resources/help/StructVisualizer.md000066400000000000000000000073521526321767600242100ustar00rootroot00000000000000## Struct Visualizer ### Introduction The Struct Visualizer shows the contents of C/C++ structs and classes in a tree view. For each variable of the struct, Seer shows these three columns: * Variable name * Value * Datatype *Variable name* is the name of the variable, at that point in the stuct hiearchy. *Value* is the value of the variable, presented in the best way possible by gdb. *Datatype* is the variables datatype (basic type, class, or struct). If the variable is a pointer, a '*' is shown at the end of the datatype. A variable of the struct that has a value of '{...}' means it has subvalues (ie: is nested) and can be expanded. There will be a visual icon (like a '+') to show the tree can be expanded at that level. gdb has the notion of virtual levels for structs and classes. * public * protected * private These indicate where the variables reside in scope withing the struct or class. All struct variables will have a scope of 'public'. Classes will have the appropriate scope as they are defined in the class header file. These virtual levels are easy to see in the tree as they have no value or type. ### Operation The Struct Visualizer has these main components * Variable entry field * Expand tree * Collapse tree * Recursive mode * Refresh * Auto mode * Variable Tree ### Variable entry field This entry field allows you to enter the name of a variable. This variable can be for a struct or a class. It could also be a simple datatype like an *int* or a *string* but that would be pointless as simple datatypes have no nesting structure. Enter the variable name and hit return. The first level of the struct will be shown. If it has any subvalues, a '+' icon will appear and you can expand it to look at the subvalues. Note, if the variable name is not valid, an error box is display. ### Expand tree The big '+' icon that appears in the top bar will expand the currently selected level in the tree. If no level is selected, it will expand the top level of the tree. ### Collapse tree The big '-' icon that appears in the top bar will collapse the currently selected level in the tree. If no level is selected, it will collapse the top level of the tree. ### Recursive mode When expanding, the recursive mode determins how many levels to expand. For example, a struct with multiple levels, if the recursive mode is 'off', it will only expand one level each time. If the recursive mode is 'on', it will expand the sublevels indefinetly. **NOTE** The recursive mode can be fooled by some structs and cause an infinite loop. To this end, the recursive mode will always stop if the variable is a pointer ('*'). Also, while the expanding is happening, turning off the recursive mode will stop the recursion imediately. ### Refresh This will refresh the tree with any variables that have changed values since the last time. ### Auto mode This mode will refresh the tree each time Seer reaches a stopping point (when you 'step' or 'next' or reach a 'breakpoint'). ### Variable tree As mentioned, the variable tree shows the variable names, values, and types of the struct. A '+' icon is shown beside each level. This will expand or collapse the level in the same way as the big '+' or '-' in the top bar. When expanding, it follows the same recursive mode. ### Modifying values. The Struct Visualizer allows variables in the tree to have their value changed. This is for simple datatypes only (int, floats, etc.). For a variable in the tree, double click the 'Value' column for the variable. It will then allow you to enter a new value (after you change it and hit return). An error box is shown if the variable can't be changed. ### Invoking other Visualizers. Using the RMB on a variable will bring up a menu to launch another Visualizer for that variable. epasveer-seer-97076f1/src/resources/help/ThreadProcessInfoBrowser.md000066400000000000000000000113401526321767600255640ustar00rootroot00000000000000## Thread/Process Info Browser ### Introduction The Thread/Process Info browser presents the program's thread and process information. In gdb speak, these are threads and inferiors. Seer presents this information in three tabs: * Frames * Ids * Groups ### Frames Frames is the most useful. It presents a list of Thread Ids the program is currently using. A Thread Id can be: * A system thread (aka, posix thread) * A system process (aka, another inferior because of a fork or exec) This information is shown for each Thread Id: ``` Column Description ---------- --------------------------------------------------- Thread Id An id given to the thread/process by gdb State The running state of the id. 'running' or 'stopped' Target Id Details of the id. Thread or process info Function The function name the thread id is in File The filename the thread id is in Line The line number in the filename Arguments The arguments passed to the function Core Which cpu core the thread id is running on ``` Clicking on a Thread Id will cause Seer to make that Thread Id the active thread. This will in turn cause the Stack Info Browser to refer to that Thread Id. ### Ids Ids is a simplified list of Thread Ids, with no other information. Clicking on a Thread Id will cause Seer to make that Thread Id the active thread. This will in turn cause the Stack Info Browser to refer to that Thread Id. ### Groups Groups is a list of Thread Groups. Basically, inferior processes. Most programs are just one inferior, even if they use threads. Program's that use fork and exec will have multiple inferiors. This information is shown for each Thread Id: ``` Column Description --------------- ---------------------------------------------- Thread Group Id An id given to the thread/process group by gdb Type The Thread Group type. Usually 'process' type Pid The process id Executable The name and path of the process executable Cores List of cpu cores used by the process ``` ### AdaTasks When debugging an Ada program, this view will show the state of all Ada tasks. Clicking on a Task Id will cause that Task Id to be the active task. This will in turn cause the Stack Info Browser to refer to the thread for that Task Id. This information is shown for each Task Id: ``` Column Description --------------- ---------------------------------------------- Active The current task that is active Id The identifier that GDB uses to refer to the Ada task Task Id The identifier that the target uses to refer to the Ada task Thread Id The global thread identifier of the thread corresponding to the Ada task Parent Id This field exists only when the task was created by another task. In this case, it provides the ID of the parent task Priority The base priority of the task State The current state of the task Name The name of the task ``` ### Scheduler Locking mode * Record. Behaves like 'off' in 'record' mode and like 'on' in 'replay' mode. This is the default. * Off. There is no locking and any thread may run at any time. * On. Only the current thread may run when the inferior is resumed. * Step. Optimizes for single-stepping; it prevents other threads from preempting the current thread while you are stepping, so that the focus of debugging does not change unexpectedly. ### Schedule Multiple mode This affects how gdb handles multiple inferiors when a 'continue' is executed. Choices are: * On. All threads of all processes are allowed to run. * Off. Only the threads of the current process are resumed. The default is off. ### Fork Follows mode This affects how gdb handles the program when a fork/vfork is encountered. Possible choices are: * Follow the parent process (the default). The child executes unabated. * Follow the child process. The parent executes unabated. * Follow both processes. A new process (an inferior) appears and either process can be selected. ### References Consult these gdb references 1. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Threads.html#thread-ID-lists) Listing thread information. 2. [Link](https://sourceware.org/gdb/onlinedocs/gdb/All_002dStop-Mode.html#All_002dStop-Mode) GDB all-stop mode. 3. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Forks.html) GDB follow-fork mode. 4. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Process-Record-and-Replay.html) GDB Record or Replay mode. 5. [Link](https://sourceware.org/gdb/download/onlinedocs/gdb/Ada-Tasks.html) Ada tasks. epasveer-seer-97076f1/src/resources/help/VariableRegisterSignalInfoBrowser.md000066400000000000000000000113371526321767600274140ustar00rootroot00000000000000## Variable/Register/Signal Info Browser ### Introduction The Variable/Register/Signal Info browser is a simple, but quick, method of viewing the values of the program's variables. Seer presents this information in four tabs: * Logger * Tracker * Registers * Signals ### Logger The logger is a simple method for printing the value of a variable. There is an entry field to manually enter the name of the variable. The variable must be part of the active stack frame, as selected by the Stack Info browser. This information is shown for each variable. ``` Column Description --------------- ---------------------------------------------- Timestamp When the variable was logged. Name The name of the variable. Value The value of the variable. ``` The easiest method for logging a variable is to double-click the variable text in the code editor. When doing this, a key modifier (shift and/or ctrl) can be used to prepend a '*' and/or '&' to the variable. This will better handle pointers and references. ``` Double-Click Modifier Description Example ------------ ------------------------------------ ----------------------- None No modifier is prepended to variable 'argc' Shift Key Prepend '&' to variable '&argc' Ctrl Key Prepend '*' to variable '*argc' Ctrl+Shift Prepend '*&' to variable '*&argc' ``` There are buttons to clear some or all entries in the logger. ### Tracker The tracker is a method to watch several variables at a time. Manually enter a list of variable names. Their values will be updated in the Logger display at each stopping point (after a 'step' or 'next' or a breakpoint) is reached. The variable must be part of the active stack frame, as selected by the Stack Info browser. There are buttons to clear some or all variables in the tracker. ### Registers Registers is a view of the program's register values. The register values are updated at each stopping point (after a 'step' or 'next' or a breakpoint) is reached. This information is shown for each register. ``` Column Description --------------- ---------------------------------------------- Name The name of the register. Value The value of the register. ``` The register value can be printed in multiple formats. ``` Format Description --------------- ------------------------------------------------------------ Natural Print using a format that's best for the register's purpose. Hex Print in hex. Octal Print in octal. Binary Print in binary. Decimal Print in decimal. Raw Print in the raw form. ``` Register values can be modified. Double-click on a Value column for a register will allow the value to be edited and changed. Using a RMB on a register will bring up a menu to change the register value as well. This second method can better handle resisters that have 'union' like properties (eg: xmm0 with xmm0.v8_bfloat16, xmm0.v4_float, etc...) where the register name needs to be modified slightly to include the 'union' field name. Register profiles can be created. A profile selects which registers to actually show. Multiple profiles are allowed. You can create new ones and modify existing ones. There is one profile that is special. It's called 'allregisters'. It means show all registers. It can't be modified or deleted. Switching between register profiles is easily done using the "Profile" list selector. ### Signals Signals is a view of the program's signal settings and how gdb handles them. The handling can be modified here. This information is shown for each signal. ``` Column Description --------------- ---------------------------------------------- Name The name of the signal. Stop GDB should stop your program when this signal happens. This implies the print keyword as well. Print GDB should print a message when this signal happens. Pass GDB should allow your program to see this signal; your program can handle the signal, or else it may terminate if the signal is fatal and not handled. pass and noignore are synonyms. Description The description of the signal. ``` ### References Consult these gdb references 1. [Link](https://sourceware.org/gdb/onlinedocs/gdb/Registers.html) Viewing/setting register values. 2. [Link](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Signals.html) Viewing/setting signal values. epasveer-seer-97076f1/src/resources/help/seergdb.hlp000066400000000000000000000133761526321767600224470ustar00rootroot00000000000000 Usage: seergdb [LAUNCHOPTIONS] [MISCOPTIONS] executable [arguments ...] Seer - A gui frontend for gdb. -h, --help Displays help on commandline options. -v, --version Displays version information. Launch Options (pick one): -r, --run [--sym ] Load the executable and run it without breaking in "main". 'sym' is optional if the debugging info is in a separate file. 'executable' is the name of the executable file. -s, --start [--sym ] Load the executable, break in "main", and run it. 'sym' is optional if the debugging info is in a separate file. 'executable' is the name of the executable file. -si, --starti [--sym ] Load the executable, break at the first cpu instruction, and run it. Common for debugging Assembly programs. 'sym' is optional if the debugging info is in a separate file. 'executable' is the name of the executable file. --attach [--sym ] [] Attach to a locally running process. 'pid' is the id of the running process. 'sym' is optional if the debugging info is in a separate file. 'executable' is the name of the executable file. If 'executable' is not given, use the executable stated by /proc//exe. --connect [--sym ] [] Connect to an already running gdbserver (local or remote). Possible connection mediums are: host:port /dev/ 'sym' is optional if the debugging info is in a separate file. 'executable' is sometimes needed for embedded debugging (qemu). --rr Load a previously created RR trace session from 'trace-directory'. --core [--sym ] Load a corefile. 'corefile' is the corefile to analyze. 'sym' is optional if the debugging info is in a separate file. 'executable' is the name of the executable file. --project Launch using a Seer project. Arguments: executable The executable to debug. Needed for 'run', 'start', 'attach', and 'core' run modes. Optionally for 'connect'. arguments Arguments for the executable. Needed for 'run' and 'start'. Misc Options: --cwd, --working-dir Set gdb's working directory path. --sym, --symbol-file Load symbols from a separate file than the executable. --bl, --break-load Load a previously saved breakpoints file. For 'run', 'start', 'attach', 'connect', or 'rr'. --bf, --break-function Set a breakpoint in a function/address. For 'run' or 'start'. --bs, --break-source Set breakpoints at a list of source files and line numbers. For 'run', 'start', 'attach', 'connect', or 'rr'. eg: --bs myprog.cpp:30,myprog.cpp:210 --sat, --show-assembly-tab Show the Assembly Tab on Seer startup. For 'run' or 'start'. --sar, --start-address-randomize Randomize the program's starting address. For 'run' or 'start'. --nsm, --non-stop-mode Continue to run other threads at breakpoints. For 'run' or 'start'. --gdb-program Use a different gdb than what's set in Seer's configuration. --gdb-arguments Use different gdb arguments than what's set in Seer's configuration. --config Launch with Seer's config dialog. Save settings with: 'Settings->Save Configuration' --xxx-debug Turn on internal Seer debugging messages. --xxx-resources Print the contents of Seer's Qt resources. --xxx-styles Print the names of Qt's available styles. epasveer-seer-97076f1/src/resources/icons-icons/000077500000000000000000000000001526321767600216115ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/icons-icons/arguments.png000066400000000000000000000021071526321767600243240ustar00rootroot00000000000000‰PNG  IHDR Ùs²gAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡�Ì¿ pHYsvv§ÂxêtIMEä :*�ô‘ÛIDATHǽÔÍKTaðßxDZL]� 4QËÚX&ä¢]+AŠB¡–µ£@¢��¸Jú ¿ M„M‹Y�¶ÈU¥¦$!1-¯W�fîmѳ:ïùzŸs8<�(RZµ ¬Š�TÄÎ;¯G�5ÓîšOÚ ï–_î™Óî¢]†ã¶ØÀˆûKvƒI7㕥ѠEÖ1c–KÞ“F°´eÄ�øf9�£®ª×äS$4§Í„ŸUÆ÷(�gÞj6n¯Ïa°Ý¼+«2ˆàÆ¿í ­ýz-H9躬Ñp#UæØDÞ°Ã2ÖÜö%ƒÔ¶WNÖ’Åxåª,ikæ>=v[õÜÌæAÌòÀ€19�º (zŸã:Nyé¤ÔèSp&Yy­)C‘÷%e6w°ßñŠ„ŠrÎ:ç}èé6å‰%/¼J£^·šŠ ö¨ÝÁ©ÓŠ×qGÈx°m„Ç#ÄÅi}zôoâÞA`Р�>èÒi„ßÉ�Ò儳žF)õ—䜬¾W?—r ò.8"cÍ´;Õ”1U¦üÿŠëº¨¶–^Å„âŠêµpYõšÌFR*‰kDTß… š�ë0&µ›w¹ƒ2H(®;%¡¸–¿ƒ!‡Ô•Ä5ñ¬{[ä,úZýÿ`B†SaÛ±%tEXtdate:create2020-09-08T07:58:22+00:00k…˜Ú%tEXtdate:modify2020-09-08T07:58:22+00:00Ø f tEXtsoftwarehttps://imagemagick.org¼Ï�tEXtThumb::Document::Pages1§ÿ»/tEXtThumb::Image::Height512��S�tEXtThumb::Image::Width512|ÜtEXtThumb::Mimetypeimage/png?²VNtEXtThumb::MTime1599551902p>[tEXtThumb::Size11671BBÍ`UtEXtThumb::URIfile://./uploads/56/VObWL55/2543/setting_balance_equalizer_icon_152217.pngM<æºIEND®B`‚epasveer-seer-97076f1/src/resources/icons-icons/attach.png000066400000000000000000000026511526321767600235670ustar00rootroot00000000000000‰PNG  IHDR D¤ŠÆgAMA±� üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<PPLTE      8     %                                                                                           ÿÿÿ¹a>pntRNS"A“Æà”B•ð÷å±ç‰C!ŒèÐ?Ñ’@=¨Ü¦;�ŽÇùD>ìíÞ:á¥./£ãÛ1 © ß% »[_sÄ#Èp½Å$^¼¾þü-ºo b‘kubKGDoUa� pHYsì8ì8q+Ê82IDAT8ËíÎÇVÂ`àÄÞ¥ †�ö`‰¨`PTªETá¾ÿÒ7š]»pV÷ÌýÃØ·Àj³Ûmó`Æ�ùàr»]žE‡!çåÉç÷ûˆ÷r0úH†D1´¦@¿@ÄKË+V¨Cœ«´¶®ñÂàà¸à óNÀ€‡‚¦ÁM)ÝÚÞ¡Ý­€¼ÛÇ�›ã”8Â~Ì%뀒ô‹Ç�¤N%:;ýIEÒ™Œ’ÍÅó@>žË*™Lº jýuýƒ? ”‹Kéê7�ƵŒÑŸ@¡(”>+”ÂEÎÜ”©‚1ÆÆqKå»t˜À==ˆ˜œÂc•jè õ=UšÍç*½Ô!«sµ`©×V[Ú­ÆfLê\-`³ÈÖ:‰D罎9f³¥Ûëu-fmû�{J<%tEXtdate:create2019-01-02T15:49:06+01:00“ÐàF%tEXtdate:modify2019-01-02T15:49:06+01:00â�XúFtEXtsoftwareImageMagick 6.7.8-9 2016-06-16 Q16 http://www.imagemagick.orgæ¿4¶tEXtThumb::Document::Pages1§ÿ»/tEXtThumb::Image::height512ÀÐPQtEXtThumb::Image::Width512|ÜtEXtThumb::Mimetypeimage/png?²VNtEXtThumb::MTime15464405469Í>jtEXtThumb::Size13.5KBB#'H%ktEXtThumb::URIfile://./uploads/56/WW2WPJb/1744/3643780-attache-attached-attachement-clip-complement_113448.pngä«_IEND®B`‚epasveer-seer-97076f1/src/resources/icons-icons/console.png000066400000000000000000000006051526321767600237620ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsÄÄ•+'IDATX…í×½JA†ágcD°‰7 X¤±»´¢ (¶Ö‚�•U × x Þ€XX)6ÁÚB°V¬µ� ±ˆÅÎÅbÝÌɇÝvøÞ�ŸsJVž³!bªB]ô"GÍï8ÄùHÿ÷·¶Ðh6"› ž½J Æ?”Hgà�‘½ç±Y �>"Ô²—ñÞ€AõÓv)m�¢šÿ ØÁ%>±_@ÛÒzÑÅA‘Ãä�ui =*À÷Oyà7ØÃBCÃiœ`Y:E ºfpŠÖp[„ù œa«¸ ý»¨çŒ½’.Û¿¦ðÌï¿õ7°”3ö)€I5œŒ;@v ëxŽì]'­ï¯˜‹lžé-QÎÅ4S§$ß¾¾¨†M[ºAžÄIEND®B`‚epasveer-seer-97076f1/src/resources/icons-icons/debug.png000066400000000000000000000023221526321767600234040ustar00rootroot00000000000000‰PNG  IHDR Ùs²gAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡�Ì¿ pHYsì8ì8q+Ê8tIMEæâ“IÊzIDATHÇÝÔËkÕGðÏ/7&1L„Fì5O¡Uk¤ µ¡jAŠJ[´P¨«B]¸t©"…îý¢Áe‚"ˆ;̃FÅ iD©Æ“¶>(«�7þnÆE~ÑûJŒt׳š33çÌë|‡ÿˆhžþr+ðP\Ð^4Ò HµK¬T)i4ˆÐ �ÔûTˆ|àËD&5z¬ò}Ðá´Xð„ /±³>]¬üK·¿ùI§-:uCð»Ý‹‘op[¬[k^o³n±;6¾K^í´ [mÑH­‚óêJɶûʇRØeÊPÁêsh5$c/Ê­òµs¯På°�תôˆ5—0xå¢?j²ÅF«õºæy„‡ì´ÞrÌHyây’Ð zÃj,D‚I7]rܳ¹(×h·Ùv{Ux(+BP®�Ä OYaÚ9—]u×?ÖB‹>)ßšH«œ¡€gu{+ÉOb@ÖÆÉRÄC®¤l1ÑXùKæ-ï·ˆTäÒrTZcµ´výµ |ÆJ]†�øÓˆ[^ÂGî˜YÁXNš�Ïãcɬ`ƈ�gwðÄm÷Œ5ég©î¥LÊ#Ç4hÓfÚßs§ªOª½Þ5ÿÚ6ï¶™rÕ2P©^4{‰ÁS0iÐRŸÏ»ƒÏTò d< _!¸Žï´—”·ùƒù9ÈÇZ—Á©¤œs�0[ÎA¯O–¹/vR[žA«b÷ úJ[ÌʵÞ÷ÃŽØï�ö;bX0f�µzJ[¬Kä`“ó¦Ó²²¦/]°5™Ù#èOf¾Á2r:k}£K¿Q£úuÙ—ó•­Ó'ã`¾AµEßv™:MšÔEkƒƒªý_ðl²×Õ_h†Ú%tEXtdate:create2022-02-21T15:29:04+00:00ü:L¨%tEXtdate:modify2022-02-21T15:29:04+00:00�gô tEXtsoftwarehttps://imagemagick.org¼Ï�tEXtThumb::Document::Pages1§ÿ»/tEXtThumb::Image::Height512��S�tEXtThumb::Image::Width512|ÜtEXtThumb::Mimetypeimage/png?²VNtEXtThumb::MTime1645457344{œ¥tEXtThumb::Size11358BB (lAtEXtThumb::URIfile://./uploads/56/7u5SC6c/3404/debug_icon_215819.pngk²`IEND®B`‚epasveer-seer-97076f1/src/resources/icons-icons/editor.png000066400000000000000000000126311526321767600236100ustar00rootroot00000000000000‰PNG  IHDR``â˜w8gAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYsUöUöÄç+tIMEæ. ˜²jçIDATxÚí�y”ÕuÆ·ºg‘„„Øz©,–`#d ÆÂ"ÌÀ{pÌŽ£f3ÎÉ Fp‚qlöEì>ñqÃÉ�'1v´æØ ËtÏ"Ħ…™éîºùãÖ몞îÑh4ÒôŒ4ß9ˆ™zÕ5Ýß½ï{÷Þ·´øÙà~à, •IŒ%€_ŠŸ ú€¶f¿›]›ÓÄä÷oåf¿«�ià hO'^Î}�f¿Ë� ²7ð 0Ф* ëAÖwõšýFwJÙÀÓ„ÊxÍ~S»:Ò£ÄÎß<´8èz‹ 5ˆÚ§  èsíA®­„àIØX”‹Ã¨Édˆ`䪿nfF¤;ò[€Ë�ÿ®Ú]»ª‚'³€_ÿ| #ױſ;i€H ø,æÁŸ‹þŸDðyÀަ jχyàH€0 ·ø'%ÈÁ !ôÊÀO�ð2ðö »6×bòòï-•–÷RÉö•XÏ8¸ Ø[ÜâŸ?hôó*…“€wwÕ(hV~_rm»ÑùñG)@ÂBwÌÅ>ù}OBIµ–UÛ•â+ëªí~¶,„h ‹=¯×pƒÃF`mtßkÉð.ðŸÀÇÍþÄã¬~¼æ$ÈÏv *¢ž ü30'ºÿ÷À“ØXzBâú‹Ày /C=–ƒ�S€ç'ÃЭ@”í~#;�Mù~tË“À «Aáh¬g|2jÿðWXMr<™” aàg¼ �€ÛˆÉ ˜¬"4_Vx8XÝ3¸3 ~>_}þ¤†�X9áCLC¦»GÍO ¬”âº. =ËÄT |˨ÁŒðsàH©x®WM`8ˆB˜Jƒ œýƒšW)º”BO\r(öPÏ“œó�W£¦£€ûU8üœ?i€-ÁÏ6f–ÃS�k¨/¾}[�ó�´óh‡bw§½VyÓg„ƒ�;=•I ? pÑŽÓüç�Ã’´éÀU  L¯7BÁá)LŽ^ŠšÆ ºjún3F{€û�Í7mhöço*üL@ºašo`ƒç�QÓËÀ<�{°‰™#±1áxl2áé»Í7$øÛ°iÓ§î"ï`ÕÒ€½€Y€7¢04ÊäDÑT³IÄ«Hj¡A©8È®(v*F´óü—±hgEôû4¬t=?ú}ð#Ð[@êfÂÏý¢NÖnu5Ô·ä°¤bv³9Ø’• �'öÚ3 Í–EFèþ #<‰§°d·ä¢£]ÊAÆ=ìo9¸™Øó—ÉN]°c3as0Íwžÿ6pn9”'èê®[¾èÿì7è-‹ÅÿUì2ð3IJs dGÑÏ�È<„Úhç`Þ»=…GÒ©X¦ †ük±Ü@° œÇ0ir“9U샰ŸõÙëŸõ3‹_Á<ß­^X†%Y+’IV>›wápê=ÿBàñ½³�U<«# zîÍù`ÑÎBlÀ=èQÑ‚Æ~¿Ó Ÿµ ôõ3‹'QOþ<`Åà$ËŠÄ:‹v’äÏ× �K:ªtFHxþ`ò/Sä> ÜÕÓùŒ»WEÛýl�zwj ò³H(X‘ñ:bòŸÇdg]ÑdJ> –�?Žî˜wf÷ÔÅC�Ÿ~BL~p‰Âm‚–»¢:Z�Ý\† È·ï´=ÀÏu¾ÿ>ÞÌ™ƒeg9í¬¨-Ĺê‡cžïÈ ÿu~s#ò;°<âkÑå À�»¥~A—쎪8k§ìA.U¼™3ËÎràl`…Ömƒ°hg0ùóÛS}�)2”ì$Éÿ¸L”{Ñzò£U»B¼ÏÛéz€Ÿ PQAåDêeç\"òcYð‡D÷;ò_.ü 4ý±Ý÷Ûk°Òü5Ääw— Ü«2ü·�Ê~.€�i˜Vþ2p µž_í$È?œÆ²óØé�Õ$Ë^€…°7_�.o.Óz§W’j(»5Øi$¨Z(›VJv–KcÙ9„²³yzßQ¡Ð[G~žzò/C¹×+�Œ|]øœÂ9~6K#.UxQ¨]]æçÄ­ðE¬¶³oÔô<æùË©zr�ë°=]V KF;¯µ~�^"ÚÞˆüí8ò»� ÷"²Õ²“Äh pFôßXâY�/ïW‰Éx­%Âþí8ò�ì,¯5V•üÃ0Ï?2jr²³¤´{™BoÝ€ÛHv¤Â–Eo€m!&žM#á4AÖÖí„ý-_¤žüyÀòäªfÀÍd9ÙI’Þ@ky‰›óuˆb÷F²ó#àžŠW¢Ø³å}`[ÂhzÀRàÆîXžðJËÎ'¢¦0Ï_¦É ôL‡ÛÙ2[-Ú9*º5pQÅ+?úޔΠ�^LþuÄä¯.¥¼8½Ù¯‹ó2b‹¦ÎÄŒ¸Ð1]I�€-ZMÊÎÙÀÒP<Ö­]“xÓCËNzÚb€®îFån ö|“Ñ;ï›±’f-³oªå3>›û>dÊ”'`I“#ÿ%à\A—V$Ew÷;I">ECÙI-n+o¦Xjf0Ùù&F~/p%"w²Ê #AÓz€ŸõÁK1eÊŒÓBvÚÒ-�È?4ºßÉN¸X`16"?‡•”kd§Ê´[€�f’M2@.Z� O½ìÌ^öDx£ðÖà—Ú.óØó‹Àù­¤+Ð]O¾“çù›€+YÔöñ¦šµ�͘K�Ÿ ìxTåO0ÙÙ/jz 8Wai ¡³;¹œˆeç Ñïk€‹=dñ 'SÊŽÀ� M•�$Æ~ e&–�ºm>oçK»ïÉrÛ‚ùE,ÉZ¬JƒÉrØž¬?'!;å–ö[Ò¥~Æ*ÉÚ4k 8˜xg Ød{¢e…Z½w0ùß×Téa ÑÒ‘ õä/X”.õ�+òaŒ{@�í Z ~03Ñ´ð�ؾã%‰ãËÎkÀ%šJ=,¡4p÷ÁdǑߋ¦±HÇ‘ì$1¦= " ¶\Œð.Ì×? Ü­Ê™ïý‡8Úé.}HCÕ›#²XUó/‰=ÿªJkëÍHó£�¡Ð š…i:X©x¶V"íáÀíDG|aäŸ_J{)R M¡Nv¾EBó�E©��qí …f$b‡aDƒ…��cÍ ØŠ�-ÿs'²¼\"ž÷pKED;²èß“¿¸Jàqþp³Ä "&w &C«�ïcg°�9†ï?’:Ùé$ z#¶ÛE°S¯J¥¸i"�ch€¨lÜN< –±Õu„¶¶n ‰£�Ä¿@µžŸm$;wT*lóZͱÆXKÐþÄóº�DGxuwÈå<å¬w=&G{b[>ûÃJø˜Ÿ 4:l„3Hv°,y»z~â›3NÀzï6C-ؘŽ�˜Œ½Ž!> æE”·œgww»“iƒW19ºÛØü)àn<¹ þÃSÍ r=öí±ìÀMv˜ç�m5Ýk´ä³ªx"K,&OÓ`+O(ЧâäèÌyàzO™rµä›ì°Ceç ¶?ù½cb±|â"Ú:ì°:twÉg|DäXó,ð±8¿�Xv®ÆÂÕ=à&W€ÿ;ªx$«Â+˜O&@^Œ¥A|NÂÿŸ£YƒHs=`oŒônL;;Ìóì 7…ŠŽñ€ûpÞÖüMßÏA%ðG˜£8ò{�¿ØáHT3�%>âý`“s¢Ä@·/6/pñÁÓ=r3æù·5�ü‘ÁÈ?“Ò£«½ÀEªò ˆŽÙ <#l*ðúû<ÚÚÃýülpV’þ<ñWDµ zýFì[)Vaßhñ¯Œã8ßÏçÁ΃Ø;¶Æ‘¿¸4"_‹=…13Àâóô?ŽikÏÆPÍ¢žðKÂ~�}©ÚG?¯ÂñJ<Ô�æùs£¦^à‡ €T†ÑàD…«‡ø¾™ÕÀ¯‰�f™��¡æáWQŸ–°Ü`FøÓÀëa:Ü(©™d×0ò�ìÌ�®:Ùy@º%ô‘ ¹ãíXbYŒläÿ—è÷ýmÉc/ Ø©%obIÙs@QUR)¡³küzú`$NÆ=Û*;7jZ \ ú Hý˜5R¬Æ¬™æ¾>j&ú3^?V\{‹&^Þ)A™bOw³yÜ&$Èÿ$íÌ�šz�K�ÙIb¤xKÿ?5Ì}obÚíp¶ô`%H/è¸Öò‘ áùƒÉ¿äAžšbØjD(cIÈ“#|�ë°Èe§BƒhgnÔ´ø¡i¾n1T7kC'†�vø5 _iúÒÄ ‹a¢¨�v†Â¤¶�dg¾ªüj8ÙIbR‚FÅj;‹h(;:¢ªìd9¤A´£J$;cw^Ð®Š“ˆ«šQ´Ã�’¬­AÒ)�½@ÕÏú“_g[…–A’YÇÙˆ¢�¡�4À�XÆVnöG‡<V•«íl{B™ÆÊmØŠ…CšýI'ÞÀdçÁm•�$ÒØdóYØ·MbËX\.ªÛgúÿ)5‡, õº%tEXtdate:create2022-04-21T06:46:11+00:00Ætô%tEXtdate:modify2022-04-21T06:46:11+00:00·RÌH tEXtsoftwarehttps://imagemagick.org¼Ï�tEXtThumb::Document::Pages1§ÿ»/tEXtThumb::Image::Height512��S�tEXtThumb::Image::Width512|ÜtEXtThumb::Mimetypeimage/png?²VNtEXtThumb::MTime1650523571LÚx€tEXtThumb::Size17893BBG"îAatEXtThumb::URIfile://./uploads/56/K0HqM4W/3497/web_design_writing_coding_development_icon_220538.png÷ŽrIEND®B`‚epasveer-seer-97076f1/src/resources/icons-icons/exit.png000066400000000000000000000020631526321767600232710ustar00rootroot00000000000000‰PNG  IHDR Ùs²gAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡�Ì¿ pHYs×ù×ùû$ÿtIMEä  SçqÕIDATHÇ¥ÕËKTaðŸzN©‘’aH™Ù¢@'$¢hÑÒ(kÕªjÙ"mQËVÒ:¥uˆÀ�CY«Èþ‚r—´JºÐEÔ¡Fhf¾1§sìÝ�ó½Ïó}Ï{mPËZõ9â€nÝ^ºjA kwÁ”y%A|3PÏ=*ûŠ ºî¨XÁœY1c6éÝÛÜ´,X2é¼Ý6¥y8�**švÂætеÛ~¸e{z0‘QEy74oÎIK‚±ðýâÊŸm¦/tü»gÑpEîœóÓŠ¡DRï råÍ&�µ$Ûeª’bÀ'%Ç«Šâ²’wzS„¼‚b\ð,eú:e9WD‘.ÌY­rj°W—P“ hRF�Q+‘(ÖpÚ'«wJblu¶QÃ:.M“¨‰|AS�“7ÎÔ‘°Ë¨Ëqû?‚8,úŸ4ެ¥ñ�Ï*¤‘?…Ô"+È&Q']3Ý©†§içÈ]‹•p²$O4P2åe­ÞÚ☃V½R¨KðÝW¥Zm&ycª°Ó„‚¢çÓŒõ¿Eœ3­QÆ~§õ‹ääk6Y…•·Rì”k‹¼7냯=‘O#¥Í%OÍ+þ^®‹õ—kífnÕ縌v{Ì®·Þž¢�ùV'ø%tEXtdate:create2020-12-17T10:11:06+00:00·ƒÁ%tEXtdate:modify2020-12-17T10:11:06+00:00ÆÞ°} tEXtsoftwarehttps://imagemagick.org¼Ï�tEXtThumb::Document::Pages1§ÿ»/tEXtThumb::Image::Height512��S�tEXtThumb::Image::Width512|ÜtEXtThumb::Mimetypeimage/png?²VNtEXtThumb::MTime1608199866;ŽœQtEXtThumb::Size10897BB].v%GtEXtThumb::URIfile://./uploads/56/hiqBEvd/2751/logout_exit_icon_176185.png^.×IEND®B`‚epasveer-seer-97076f1/src/resources/icons-icons/font.png000066400000000000000000000012141526321767600232630ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsÄÄ•+.IDATX…Õ×KˆOaÇñÏ\dr�)6L‰ac!å’�e6vŠ¢ÄBÙ)v,g1;²°²’Y� l¤X!Ò4¹eÆušË±xßiNÿÎ{æýç_žz:�Ëóü¾ÏsÞË9üÇv¢¯oµø< #‹~©Õsâ~ §•72á•´ÄV`¼à Ú[p¶@|Ú̵x^•Ü�k€]%⦰¡Nºïìh<~ÅŸ‚ûm8U3ge[ŠŸB¥¸¬¸ ßã³M·9‘­X'´¼âô\<ŽÉŸæ®ÝK¼^GÓl³™jóÕõ%2ìk&À@L:†å¹ë�JÜj–ø||ŽIoÜ¿�˜@o3å’­t«¥ãÅf܉Ɇ…–Ù£ÀPI f©+…M¦£x+´v²Á×›T‘õap�¤�W¾ôVñÒý¡¬mBõ½Â¼¾¯M{{Ãù6ì(È“ ûËÒR l¯™*ŽUx~“ô`¨+×bð(UŒy˜ø†uÄ{ð;_­w8�Å{•íd.pO�¸.|Iܯð$½Wÿ›¡?0¥âÿÖ\PMqX+¬ EWª$Ìùx–êüƒñ¸ ;qNXû§m£ðé5.ŒäÉÑ…ØŽãØ¯x î¦73WžKÏ߯ÝmwBü¶â…Ùü]'>â>áuô.a*vÇãâXáH`$BŒæü—б‰Ø�ù·b7–Äœ¥UKì/W¹»VÜgIEND®B`‚epasveer-seer-97076f1/src/resources/icons-icons/gdb.png000066400000000000000000000106641526321767600230620ustar00rootroot00000000000000‰PNG  IHDR``â˜w8gAMA±� üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYsÄÄ•+:IDATxÚíœytUÕÆy™ƒ"AiˆPPD±Ê LE±‚s¡Õ*Plµ8à´PPÁ©j¥ÖZëÐÖ¡`EêÄ h• ˆ€eP‰Ä éß>ë^^nòÞ !ãýÖº rÇs÷Ù÷÷>÷A„"Dˆ!B„"Dˆ!B„"Dˆ!B„ éIž— .ºk�’T¾! –Ä9éÀeÀHèí�û€§zð?‹€Sìï,àiàúT¬!  hd«íï­À7ÀÞ©|C@Fç|,FÀÀÁÀm©ü ÿ>–c‘UDØE¤…8·Š¥È*¶§zð nö½P�ý xxØ‘êA6täw"ÿ¾iv%°89Õƒû!àb`ðp!ÐØRà}àG©`CÇbàÀ¾}éÀo�5ŒIõ:*ÃÉŠÛß øx ÕlȈ�}€ÆqÇZÙx5Ÿl ŸpÌ)B¤ÅÀñ(ã]†,¢0 ü&”õNÎGTt!ʈ¿hôGùL!Êa*RôÅHñ·€2á[P�íRà$`ƒ�”Ü Ì·ýÏ·ϦH aÐ|ˆ,¹0ç#…{ÉÞ§¾èv7TM¸ ¨LG.h�´ €ˆšÞ|Œæ3€ScZ˜jéÖ€à, §½Ç ¤ñ=� ½øÔÞ«²’Ï‘’í´±1mB5µS€UÀ—~ž ´Dš¿iL¥Œ²sVWáç@š•‹ÌªÌw]*p°½àZ`:Ðø‰�m‘mƒQŒ›üèôA“òg;wWÐ 8˜ec8Ñû[�" Z�ø‹qÛâ„êÇ?�7þ‹r‡fÀ½@gÄšÞ~�&*,bˆ�åù¶|û7Ƕl¤þ-Û¶<àDL»Pü:ÜÆ?Óî}²ÞIÀfTÈAqn?Û¦ %¬ ŽCÖMì›¶ A8xø9�WŒ& Íp#`_dú%ö€êºfi&Ø}QP/Bn`?d…@dU¹& t».Íw�dÊéÛ�rÛ2�K� ¼,Eqâ[Ôãø iî�Àí6‰É"¹çÛ‘R–ÛØ‡/# hD ³©�)²üÕ‚jžC”nqÜþƒ‹ÈFÌRàu”ì9N}>2ùD½ê#ÐÄžHÕ fÏŒ·2¤%� ²Ç^È ƒbݓۣˆ` DÕÑE=�â&…ž(�®4A‡7Û#mÿÇÈŸ÷¢*Ó¸Ë6,ncÄúúö Dnæväcg¡Ž\S”M_jçõBî¬0ÁرsPhû’ ‚iˆÿ¯Æ‹m[ìÿs‘W8 YVÄó'¡˜àÆ5‚�kYyˆA5KVø¡À[ŽÊ³®6ÒѬ{veEH× ’…¢ÚM[ß¾îˆg¿„´ìH¼ „üi>r�OR•Þ&B!ð0‰'TæøYÏ�h"�Bñ°¹Ú“lÿT_¼¤¬^—m:^þ1/`· jˆ}]‰—uŽÄë'Ž L~ío„¸þ&ÄÁã1e‰ñ‰Ñh¸Áë `õ^µóJà’�3áR²ÅxùÁÕxñìBàÔD,¨7ªvAfø± l$ ®÷"ÿ÷ �;×<ØöOFþÐ�lÄLª®JxÍëj$KPÙØµ9]ñíKÂ'4ÅÈ�¼�JÔwWsÞ@?&¢`ëÇ{ç&— H9nF„¤¯Wžau�ވǗÃMÀÙˆ?¿†üù|4óÝñ–/Ž5��~éÐxlEÜ=»"Í~%ày…xx&bAex¦ê¬,Ÿð�µ9²¢÷P·.“ªÌ(Ö¾CmÄ ì@¥‰µÈ¢F™àGSµ ëk¹k�»^$jé-³·ÚÀ¿°A¿‰:F#M8'¢vÜ%¨ÖÞÏ&%¾¹³ó¦¡å�~tF&ýò¡CðV)ä™ðËìï.Ƚ…A ²Ì"4¹A´´'²ä5L€Ã»ö®O"«y Y�sYy(!+ñ�;ß7îoH‚ êY‰L2¥ä®Ü0ùÔdÝÁ ¨6T‘ˆ&ù.äW }ìƒ&-ßöÏÀ fÉô…AV÷0^Ã%wÚ»^‘ä=±w¿Ñ„¼åbˆh¬C}çinÀ+Æå˜,¢ƒ ¦ ޱˆ“·BZy?b‰p* œXÃ9ň†¾ˆÊÝ{ÙËLÁû(°b$™öb—#·– –RZ"­^…^dâŪRÔû¸M¦k;ÆLvŽæ "’z å(ëlÆ ?ÝÄ–ˆÚÅP|8‹Äå�t”oLFf=™y›jÎ?1®¾TŸ]ƒ‚_M¾±È÷O´û„-še¡|çl× wÓߎ·0¹¹n_3à©08Íî—È•œ‹hÖÑI^ï–•ø‘Iõ.$Å’qÈoW‡VÈbæSûŠçA((~ ü‘‡‹_¹ž×‘öOÇ[�ѯÿ Êó€Å(p F&:EýQ(X¯Ip}k¹ùõ•Çv˜Pæ €„|dhr—£¶gd!ÆÖÏÞiR´"¤`a±5è¿Aõ¬HÉ.@u²Oí¼®@«0°Å‚rdjÝ‘¶|Šü0ÈM…¡‡­Qµt� 4, Qª¿MÂS„_ßy*!¬2µA„`á'Óa=¢îN)]Âù^îÓ¿¶÷ÏDLÅÕEÚ£ 8›š[ˆAØqó¥xëeÂâV”‘ïW‹k;¢2u *ž¥#÷:•]\±� Ùy±X(ì ü MÂÓ(É9ù¼ãCÜgðGÔ¾6Äui(#^‹k QŸÀQì D�@¿zAm‚ ¨Óób§¡ öò™¥È¥$ƒ¨–´±©WCŽ# ¹½Wïï„˜Ó ¨È·‘‰3QÌyadZ¯hŒ¨¢[™öTúÿD™m‡�×Ö����õ¶DÚ^Ãé{…ýÑ¢,÷±_Qˆk]Q®i=Œ3•AQø¯OÜ÷¯Ý­S�}Q`Þ„"ý’+\`BÙ�ÈE–ö„�o* ŸŠ>Ž5S¾÷¿”�Lx+JÖÎ&ñ$8þ^׈!¢0Yg)ŠÓ‘¯wã„O›ð�¨Ô¥¿«@PŠ4l òëÏ © ¥ú~ìÊ~¸•Øî ÷�HgD‹�D9ÑÜ�([ÞŽÊ=PÅuU+³õ†Ý¡}È·�CåÝR´ y9J’*M››ª@ÚéÕN°YxŸ¹Íÿ…L.ŠM+@õ•|»ïFÔ|™Šá9(û,FVð.ªFÖ&Ü£'À¡52ñŸ Õ­P¾°«Vç&°eåe¨†³e³!Á— êç"<Ös(*9ÌCYsÊ¿u®�¯ÞÝ’¼æ(è¶@��!(]€´± ZüÕÕQ"Ë(G®@š½É¶2¼ŽY™‹ÏÚ <¥¹¿Uˆ©-bùžúþÙ�æ¨x7 ¹ƒíhÙK!*E<ŒÊÂQw+ÙÒðJÀîK˜=µÍ„k‹-ˆ�œ…„½ùêóÐR÷¥äSÔ­ ¶³‡þÂW}Oè«˜Ž¨n>­(hŒJÚÃPmèóT ¦¾�ª_>i‚’ Ö¨úµýÞ§­v3ŠPs'V!B„"Dˆ!B„"Dˆ!B„"Dˆ!B„zÁÿø¬³}º]û¤%tEXtdate:create2020-02-07T17:31:13+00:00îÏhd%tEXtdate:modify2020-02-07T17:31:13+00:00Ÿ’ÐØFtEXtsoftwareImageMagick 6.7.8-9 2019-02-01 Q16 http://www.imagemagick.orgA{âÈtEXtThumb::Document::Pages1§ÿ»/tEXtThumb::Image::height512ÀÐPQtEXtThumb::Image::Width512|ÜtEXtThumb::Mimetypeimage/png?²VNtEXtThumb::MTime1581096673´®ÕÅtEXtThumb::Size24.9KBBEݸ?tEXtThumb::URIfile://./uploads/56/sZzt1Ks/2148/gdb_icon_132365.png°kòXIEND®B`‚epasveer-seer-97076f1/src/resources/icons-icons/hide.png000066400000000000000000000015151526321767600232320ustar00rootroot00000000000000‰PNG  IHDR Ùs²gAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡�Ì¿ pHYsvv§ÂxêtIMEä (%ÒàöjîIDATHÇí”= Â@…¿H.`á)D[Ë ‚?•{›€‹­"֞Ô±õ&‚¥ÄÎX¬&×e$�ˆ¯ÉdØ÷eò†þò²J1 »V,MégÍ5¶Tö+º¯� áêyYRß h<íÀ# %T™3,t†Ì©Ê{&hTv¯ÐLYÙŽúØú~Uh&�½K9"uÙ]ƒ˜!ÑûC¥×èš@¡ Ÿ²ø`¢3FÂwÚ—Yov@À¨�¼AœÙHƬ �ˆ„D>ÁÁÒ‹íïú­ŸóÊ3HisþTÛ_1}ÂǞؕ�ü—tÄœ4Õ`Kƒ%tEXtdate:create2020-12-12T14:40:37+00:00»tj%tEXtdate:modify2020-12-12T14:40:37+00:00ÊSÌÖ tEXtsoftwarehttps://imagemagick.org¼Ï�tEXtThumb::Document::Pages1§ÿ»/tEXtThumb::Image::Height512��S�tEXtThumb::Image::Width512|ÜtEXtThumb::Mimetypeimage/png?²VNtEXtThumb::MTime1607784037Ðök£tEXtThumb::Size4431BBg;çItEXtThumb::URIfile://./uploads/56/MuYGGYA/2737/delete_remove_icon_175783.png3kÉ�IEND®B`‚epasveer-seer-97076f1/src/resources/icons-icons/maximize.png000066400000000000000000000016021526321767600241410ustar00rootroot00000000000000‰PNG  IHDR Ùs²gAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡�Ì¿ pHYsvv§ÂxêtIMEä (d†ÛW!IDATHÇí”?kÂ@À‘tMP(¥[KÇRWg)¨ÝúL?F¡“ÐoÐB7ıC+ˆ‹K§B Ý‚.BÀØÕà9x$š�ã UJé›Þ½{ï÷þïà_ŒP»æ ¡Õåy­š¡±Ê!}ráK.©$4+Èq©ÅŒ�¨qŠ ^q�3ª˜Ò6¢ËB8¢Ás9Ü\à˜"›Þ™¨&ßÜ2Þ² Jí„V<"ó ~`F?ÕÛ§ÍlÛâœ'E:?yûã-X8Ø©Þ6–PÀ!Ÿ ÈãPØq ûÄŸ1Àâ^.“ ÉP¢.Ï6�0ånc�=<>Ãuî0U¼$ªtyÜË e–šŸj9j$ô¨q¡™Öc�µò¿$+¾ÛA×µ‘%tEXtdate:create2020-12-12T14:40:26+00:00ÑÓ@%tEXtdate:modify2020-12-12T14:40:26+00:00 ŽÇü tEXtsoftwarehttps://imagemagick.org¼Ï�tEXtThumb::Document::Pages1§ÿ»/tEXtThumb::Image::Height512��S�tEXtThumb::Image::Width512|ÜtEXtThumb::Mimetypeimage/png?²VNtEXtThumb::MTime1607784026¾êjttEXtThumb::Size3899BBÞKW‚KtEXtThumb::URIfile://./uploads/56/MuYGGYA/2737/resize_maximize_icon_175765.png=dþeIEND®B`‚epasveer-seer-97076f1/src/resources/icons-icons/minimize.png000066400000000000000000000016641526321767600241470ustar00rootroot00000000000000‰PNG  IHDR Ùs²gAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡�Ì¿ pHYsvv§ÂxêtIMEä (�å~bSIDATHÇí‘»JA…¿Ù¬ˆ`ˆ�¦‰"¢°1ØKÀ i| E+„<€ 1›<€v±UÁ¤²ÁJ;oˆŒ ÉÎZh–]3Éì´â©†Ÿ9ßœóüKx§e–pC»N8þ>ÚÞp�aα´f—,ó�A�­}�X¤Ûý‹~E)°™¢l“ l°É÷죬sgèc�´Ï~ÿû‚¾‚Àb ›Ýÿ j}R'E®›]ŸÀá�<)6y¡_½$�Œ§ˆÍ-y性Dê|„K�`‰ä†GžzñU€I6H’$Ùb·w@ Ê³ìÐd\×P�4™¡ÀöO™Rc†"J´´+V2ìQax'FÄ´BÛÞ.ÃÂ1øípŵ®†¿‚d*`W¿…`‚!ʆY� à’ÅE°ªõHæxÈtÈg_©™¤üëúçRqß�Ò%tEXtdate:create2020-12-12T14:40:28+00:00�ì%tEXtdate:modify2020-12-12T14:40:28+00:00𱼡 tEXtsoftwarehttps://imagemagick.org¼Ï�tEXtThumb::Document::Pages1§ÿ»/tEXtThumb::Image::Height512��S�tEXtThumb::Image::Width512|ÜtEXtThumb::Mimetypeimage/png?²VNtEXtThumb::MTime1607784028YRGstEXtThumb::Size6354BB»XÛËKtEXtThumb::URIfile://./uploads/56/MuYGGYA/2737/minimize_window_icon_175768.pngÍK¾VIEND®B`‚epasveer-seer-97076f1/src/resources/icons-icons/style.png000066400000000000000000000027671526321767600234730ustar00rootroot00000000000000‰PNG  IHDR D¤ŠÆgAMA±� üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<zPLTEÿÿÿ�°"}tRNS?‡™˜‘$5–�8�¸}mnfl…Áƒ Ž›°~@¶)¿1zgwruo _š± s&¥¯“N£¬eDYœAQÀ�UE´•†tð‚`½'Ç艤Êd· º!„C×¹ž+I9:Rp¨S[2*q¾c;0(ŠÃ€"›­bKGD}¦±É pHYsKJKJtóÛƒ\IDAT8Ëc`$€‘‰™…•••�ÂåàrX¹¸y`ò¼|ü‚‚‚BÂ">»¨�+&.! áKIËÈb3—]N^ÌPT’Ån³²Š*˜fVÃå6u0Å*ˆK�†&BZh. :º¨rî¶ZŸúÐZô§×ÏU­Õ¶n­?«UªuÔª8ê®"V+S�!(2B˜!ëúý‘Ã×oBBI}½òÉ?¹Î¹ïó=×uîqÍ›´ -hA ZЂ´ ÍŽÖzÈÞÚ/ÑœØÁÑz¦¨l7ûÌ�Rt¦]nÇ­ý’M‰ë”{Zë„ÚÞDáq™ ÝÛá’æ}¥Ì-Äf�¡¯Þit7™L}ãP†V2º§.¨Hµ.0Üàÿl ö²¿Ù5EOA;'T¹Rä¤Þ¡§|eæ¦ZŸã/îÕù?Yõ4а=]±\{%TåÈN�€>2¬õyBµ3 ¡ü?YLÇ0Û'ô\˰OBUT;c¹% ÕϼayBç8Êá�¿g4¶º¹Õ(y µÄ è€ýv·]"€ ´JÞ!Oo,V˜´j;ë¼’zò±žò¸~Ûº¾ã—npJŠþ»ò�œ ó5f¡{2"ÊÌRjª G[̱ì`(>ñQòœ?·� %�-€ÆF „§vû\Ï sí’ÐC½ãæÔéàPS}OqŸAÉÿ‡[#Ü’ºwžRáÖÔz± ãr!ü:õªg ¥ŽNÝoS¯y<ÔzEO¨n& sì–ºßJù[›Õ�ȳsê›ÒÉ»ÂR‡&t{·ù½NUzäj¯·=ík°Aúë«›¶U¦ckÃ�$'¡.Âå©»YF[äÆ&^Âë�_YäÖ”~Ç ÖÏk—ÐÉhÈÐÙ·]àN/ù·Ï|¥P‘"Ë-2Ó8�»Ö©vßäËv3Møwš’üßÉ/´ÚÚ¬C–1B©Ñ²’+9 SÛôð4Å*±Ù¿2_zÍ•Ò&Õ·£7:;El¾°05A¶�±¨ìï1»Yçb÷%Wvu­n°­ìç4ÇÚ%™ûk|i�ùYn�òl¯‹zé©SòU‹|èIc-½t2%Ùz{Ü�ֻȃ�ü)·G[$,srêJ– ä8Â_¬B¹yþê"ß¶cÚŠ‘Ž|»:ÞõÞJzT˜ær½ª´ÙÎ!ܼ­™Ñ#¬æ;(íÚR$„BÏ9ÛΛ¼tð´GÝåjç:$ùúm vµIJ…0Õ… R=NV.ü-íJ–a.°Cs3œã{NM[ø2ŒT,\“Ð.õ¹–ºß!µ|óW™ÿkœŸv¯ƒ3¼©D(÷JjOlŠ7õMµÊu™5Â7·Y¡Ä}º¦®´ò 1 4V…°Ö£ÜÌfµ¯WM6Ã+”(ó‹Dxû¥¾hëL„°Ä¥Ú"CwRýÛù� Âinô5E¯',W" N3G�RçFÕF]ìd ã��¨È§ a¾[í�®®³L(7¦Šo�NþŸ áSÇ47û0À«Bø4¥éC+£ ëÝ�æüjè“?Tža´NøŽ÷…0ξ©V½<+„IÜìCwÙ ¬tAr¥µm;‹””.Îñv²Žs4zxX¹0-µü¯Þ´çÖbrýÌá¹Ès³2aV£ ÉçøHË]¡µÖ®·^˜•ˆ`°ús•M2Sß´5©‰�¡ Úfv¤û‹lW+¦TÙ · =ܪH(÷ˆ®2]b­0Ý~ �Ü*mo´Ðëº4­N5Ñi3ñkœo�0½‘ݘ™†™.„—õÁ(ë…÷ô©Ò*Ïé& aNµ;�Ž;…°ÈÍi®N8ÊaAãèçÕ°·×’ùÞG¦ë” O¤L-ú‹õB…·ÕÔƒ}nüÏ‘á\/¹Î¡© G%z™.LÖ£Y�á!\…6W§îu1Ü“¾J,Ë�ýÓmŒÂ*ã\ë�$´ÁÅB…‹š…}èê_ÂçöÖÆ«ÂÌÄ@lB¢:ûÀ¨Æ_�2œi’u‰|WyÅÎèàCaŠîßà‰™ ìdw»éÞ ÷pÅÂm8]‰ð¿à'BøÂÃNhºÍ°ƒ¡~oŠ B™¡8Ɇd@6Yöt¡ÇL0ßb‹|ê-¿3¬žJl[/•¥ƒ„·m‡n®r±=RŽÙ&D'ºÍ(ÛÉð'a‰þ è�mˆ‡,¬Á¼Á¿]a§zÂ<#ê©V_%,K&ag#ÜâŸX©¢1³�2]g‰YÞò°«�i�lä{Kx¿^¶¯×ùò´w[2Òÿæù©,=Ýi�°ÊåõRo‡Z¯ÂÈH,ÕH¢‹ý ±�ã™*¯ºÔ±èc¾ð@=úïc¼Þ6Ýý]EƺÂÎu“ñJ„ nÒJ–³}!”¸¥Ûcå[ü~«D¡ižu½Ø»1C'{»Ê#Þ2Ër%V;‡Y+ü¼ìW:¶×müYï::-V°ƒ™'”ºnªPæ¶´ÈCÍhãŸÂsrÐÞö×9SnddÈ×]Ç;B.ÎP¡Ä÷êèÕ×x¡ÂIì¦2Ñá•j/8ÔláKûƒ�&en¨ƒ� �“š?2ÄeÂÊTFGÍèâ%!ü1± :ø—07‰g;Ðζ{Òz¸uÂ=ÉRÛÏ$¡¸‹ïkÜ Ì¯—þÐÈø­°0-Hµ)òÜ'„'RÊé1Ö§ ˜|7%Kágέ½ ÌN�ŽA>V¤¥ÙÕ„‘²Ü!MžLó€0{³™½#•o¦µ¹R(Lܦ•“a�²´�¡°>-�f¨ÅÂ'öÞ̯œ-¬N<ÑCÜävwºßCƸ©>š@}VÊÚQ–,Ù²„w}"CJ•ÕÚë—É1Ó/’?ôÂW>G+'Ëö±Kê2]kfX¯ušiýŠ+ýη\çlEµüN±�%íüºšK~‚§CC<©À׃j¬ï+–‰µö¤+¦˜žº’!” •Lók�Ô. x+WÕñòOKõ6H÷ZP!’$œbïé¡\¹2eÊÍóqÝÌÕGeJT¨P!T •Ù˜æZ»õõ¸“ê8ç¹'¹Vb{í,·Ö ;Öƒv×Ne1å&­*±½kõVá.ŸÔú;92U(G©ÑîÊ“¿uŠëÁ]=�eÃo¨#jpâl¸[X°ÙÕ÷Û>¾JÛ**'ô>K©V¯%³õú*;K®[UT‹lŠóë±5 n–UI„ÚgZ-Ì5$¡X*ŒIùÏšë÷$ùã=LÆ%[f¶_Ù ¼_G¬ç aqj+mF\$¬sÄfÛdºB‰0ÃÁ ÇcÂZg$÷sõÐ51{rÜ&Ržl—X'̪3Ôv§0ëù¤¶')Ω£U®[” 3Q`‘°ÈªY{m]m½ð¶NÈ5Ú:a�£êx~Žç…wµEO¿u·QN1XïÍN›o„]ìï‡~í^±¯ÂÍuöËw›2a�á2ðk„"w9P�­tvœç” s„þ DXà¸:ŸÞÉáÏ2|�qT¦ÈgÆûaã1¿«ÿë9ÓªÂèbšðb=ŒÖ|7*Š\£Zš8F>ô‚—LMœ­“ŽþÆ aVšBT;ö³B¸ ðºÏ­N²KÂØÆ3‹þ�fgú؉Èö”0¯ZÞNÍÈ1Òr¡ÂK‘aˆ±ÖV1±—¸[mýÔ\!Œ¯g˜ý<¡Ø± ÕÎÎ6Üeî÷T�†Zp®y¦û»�°_*ñùaƒëùŒãoÏRwè¯Àá®ó¬w¼á1?·�†yU©Pâáz‰•  sklݨþá,=uÙd@}[‘ð‡z?e÷[-„¯üÕÙÚIO=íê0W§8 »Ÿ_§`#vô‰ðTSyêB�ñÂTÝêÝ#Çñ^Iò  ŸúÈd R—/ýÞ·ð§)Ize']›¯œb=dªŒÑ–:½A}Û:Á£>SRe Xc’ h Ù>÷-ô5Î ÷9©¡ACe–mÇ;Q{#½d?/ëèy§5PëÎÒ[?{é¥�rËÍ1Ù4Ëø.ûyI'�8W¹C½,¥æxÛËÞN_5":9Õã¾L¾ÙEÈñ„°Êw¾ñ33¶`ØÞ.¬Mv€Uô�\Ǻ¬)6Àtd:ËƒŽ¬2Óöp¤6bŽPîî& U6Q÷'åS£-tOÓ—HÔ…cÍT쨖§ y.¶\X›ª&k6gƒ°`s$ÃBQø*ò�ƒ¾¡ ŒðŽr¡Â2ae-õ¡'˜d|ÚéÍ„Ì4©†ÈPs…'ìåÞ¤tz™G}·AéËvr�wó{±kœ´Ù(D—¦>n©æ—ìS£ûéG*”�lG{>ñ÷­3Þ5†èXÇrÕÊNNq¿ÙI¢ÐÃ!Ï?„ÉM]·åÈ3V˜‘Ê É÷=O'ç„Õ>öˆ‹g€^:ØNmm¯³]h¸ë4ÝV¥":a¥w\fï*¾ý¾æ �mk'TÇujËßîàWyÑl«“á]ý¯ÜJ30ÑL_Z#ø´|Ýìn°ƒí“Œ¨b“=ãY³ü¬fäÙÓw¥ÊW_j©ù>5ÓŸûJ‘uJ”mÂD–y¶ÓÁŽv±»=ì¬K’öRj®·¤¸W9ݶdBnBÿÛðdS%&ÐQoh^·A—¼«Yðân½ãÛ KOŽLÉÿ“sïmþ9Þ¦7;ãû¶î‘·mÚ-›«(C‰�)Ÿ— î•ßè?KT¬%¥â0G‡†{èE¶å:�ÒÛ%Óê8v-Ó»êoïÕ»H}W”ÝÙß¾Y·ì³M�Þé;›CÖºÒâ¡IùòUCÍŽ]5í¶Q·l³n§¬=ë©aõt’ñºúáq¹ê!½õÖ”fëpþõvɾÊk§õºÄbYW²À�n–¯n>Z•’ŠÀôâ?i÷¹ò<N{’u�ïÝ4,_¿vÈsØ*óZGÞ{ËYò�­fÉ+_¨Š�&ÔSG\> çÝ]MÆé´7Ï“WëçMÓ‹ÿcZ&KuTR%Y¤vZ¿K|Åì¦ìù>Fúåí#Mi"€t[¤L»Û~éõs‚jsÙc²ßï–»ü ÍÖê�/êùm¨3Ùà]çõËCÕF,[èðú×ïštÑÙãÈ{Ó¯ó:û˜lNä ígËÇ^9[:§9ú<•|òÏÕ…zî™:®¸À~ÛöÈÑ;‡ àrÀçþ:(÷뤛7éÜ�ì§ò9t‡^÷èÃ{.ËóãòÎ_÷…ºÂ1[ë£ÒY Ã`³íŸ»rPþøï± z¼Vïú&k›à‹�lŒ²Ç™K›«%¥â°¿ à �°É¢Ï«þ¹ØwG›¯ÏÎÇì2Gö|ɬèw±å�÷ô[Gšu­šªÀFöÈô‹ÛFÜÕ°‘Úá;ö6ß|¤HëHi� À^–”€#Úö¾ý K–5'·¦›ÖÓ‰¾Sö˜Û|†M™¿l ù& jª";÷q*€oß8<íjØå~äkzå}ÞŸÿÆÿL½l‚÷àK¦]ÏvɈ‘´aâþ:`sÓI/Öw÷ß× ´—'Â>»>÷,��C´3ߪ﹫¦ª°‰Óc¯™ÞÄ©]ü_ÝuŽ|ðe=U«í:ÞÞò|ñoƒò³€‘ŠëD-˜8ƒrè¥Í÷ÅkJöÚì‡o™'ëë uúý}cr˜ŽêXTUgß9*ŸÒ·kJ¶bï»ÏÑ×¢³Ö”µö¿BUÞ¯“•wV˜¬¬½R‰ DNП¾bP~uÇêŸi7Ô;ÿY«ÑÒ_üÖœãuØý-ǰ{uª à*£�üqõoNìÎ₹²×KÓ_üÖö[žž0­ö²ÒÙ‘Z$;pâ+W ê‚‘ç€ÝñþŽyò’µ>À®Ô†}.^Ö\XGª*›/ùÀ…ýº÷¹Ó±»Íi®‚œ©4ÝQÊLÕ/æy€“î7ÿ1$']¿êI­utÆÚ†ý;¼(í„ß³›`¯ÞÞsA¿<¸¬ž×YUp‡®µÛ9}Ï)€�ï0[ÓÙþ™JöüooKlP‰ 8£nw¬œì=ÿÉ:Ûo¯úf2Ù�Û´ Ö´œµªV!íò‹¥«ÀÞ:ä?A‡þi^ô­:*ÿQQÚ„é úŠ·Ä„œQ?G_­¡l+'{mõé�z§½VÞyÚig_Ó#Ê´ z:cUØöÛö¤ØÒäg§í^Ð)§¾q^s·ãL&[ܵÿï—±p&ƒ�òÜUY=W5©µ•®–ûåžóÅêLvÑØ>v»vìßí9Úö»wëpÖÅêÄù ÉþÞVÿÙ¤V]©ªl]ýk~¾t…7¶¼÷T-½q“z—CÛ~�Qý?c¥ØšÚæ¥n�ŽéÖmÁúï+GèÔ†å„ë¦÷š².¦­T#g4®|pL>|Ñÿfµm±Êzño_Ó¦ëÄöÜl«íÏGuï¿îù·jvÁ÷èÅco6Ö;ç:Ñhk ì­ƒ‰a@wàmúÿßm�M\!{U˜ÀœÑ·ÂG8l¡�­ï¯+Ù¼Çõ�Nè Íñæyë‚-caÉ^/®ÛÛ[“±©îÃØfÝ.±ýË7Õ9aZW{R–ƒœ´mVûCõ?3¤­£3ÛDÔå:kñ¢Ñæ*ÃG¦dLM`]ø¹>Ta2°y ØrYûø…¥ë­÷Y¶ªL\o=gé3Û¨_¥¢<[÷XÝ«$[ät¡®Ç¸âÁqY¤ Ÿt¤¡ßIyêŸUlçÓA@s$0W§i^ØÛÑ”Bè>…*uo¥c€37é�ÙvÚâÛ¬òm}޵;LH²…:×éû}g“î/X~× )+Ö1U`r³�6ÉfwÝï¾ižìª[zC’ ëïÕ‹ý'·Œˆ-vz”O{…`\áàDh[[úÓ€Ü×?!ßÔï „®\ûÇÓþ¥÷�5ŸW[5U€µí£ºÈF6{lÜÝd’lÆwuYñ9w�÷Õž^Ó=L—ÔÓùìóKúÑ>¥³þ+OÄ­©¸a½"N¸vX~¬_Ÿiå y;ª ÀÊù¬n ¶1Ò¯è Z eK¯�ùûó\Sç ø{à„fÏäÖ»öŽú…ïW…luÞñúÉ){ŒÈ%Õ!{Õ¶™NXz_ùÙb&ÛNl;õìÛ}¤ú €ú™®²DÛiv²® Ìí¹µ„ 6IÚHË•Hñ €xlŸ)ù½ðOºaèÿÃ$8uåSÌ„þª3ûG]1 Ô´œ¹2„6.DîêöD>u-ŧÀ5:Yh+óZñ�H-@[¬1 ö1Œãt•ÙÊË`#ž²ö¢S À>µ¶ïÅýÍW¬¤4@$Îé¢ûv€­…Ï9¥€mÊù„nbºîžùSö�öcúIî½ÏïëÔ¹§°Òg®�3ïXó—–rçÙjõG5GÄV¾ÙJAÛ3Ð)…¾ÿϧ~p%çG¥\c�jŽÜOu™êÑú�ÉvI±`K{ß­£¥þÌ•r�7¨1r¶磺L8·wý«CS¶UØxÙB!ÒÌ@5q·‚éïàýN7©´SŠ)€óõw mâ�4s@MìíÂ?L;s»ý°d,ØžŠõ}ÿ¿jüxIM¡,ªPC¸mâo¯óûš¿Ç×n)–r_ Õ.qF5DòBݬb–lÇCöœöQ•º¾\ÜŽÜSµ T$m_ßµ^Ôù¾ŠUªõð¨ûÃ¥µ6¸°Â@Å€Ÿ¥?}uä4~úªâifìðº°XI-8³¯–Ÿ-›1(mtbP!˜öóׇè¯_©»×Ú5Õ-€袟¯]]îWx[­Ÿ € ¹xјþ¤t{S¾N,žÒ_-ê› µP!ö­»v{ï¿2Ž:`_ö9¸M'K+t£=â·»ÙÂóúÚ~&»N®¿¨t®þ²©u €ÀXزßt!K»ï]¯K¶)úÃúêϾöCj 0ö™ëC/m¯uÿ«BQ—ì ȶKò/5ýly`Ø8l% °K 8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê�I#8àã•*7$�|à€�WªÜ �4ð�C>^©r#€@ÒÀøx¥Ê]œöÛ¶GŽÞyNe¾¥`«u:åì…óe^w£3P _´ƒ‹ÀÂÍgɉ æJWG5¦—Ü?&‡\2 CãSÕ jñ£×ímȹ ×’�çW¶xhRüÃ€ÜøØx‹·¸¬ê'»ðß°Q·ì¼A—^¼"“S¾ ¸»³!ý£SrÁ=£òà²É"zËv/è”Ý7î–mû˜ÝÊ©£Ñ�Þ.‘‹�Éõ�rñ;Ð%ÉZœ’På$È„È$PT1 €T)™@™ŠjB ƒ*eB  “@QMÄ €bP¥LdBd(ª �@ ª” �L €LE5!ƒˆA•2!� �I ¨&b@1¨R&2!€2 Õ„@  UÊ„@&@&�¢šˆAÄ J™È„È$PT1 €T)™@™ŠjB ƒ*eB  “@QMÄ €bP¥LdBd(ª �@ ª” �L €LE5!ƒˆA•2!� �I ¨&b@1¨R&2!€2 Õ„@  UÊ„@&@&�¢šˆAÄ J™È„È$PT1 €T)™@™ŠjB ƒ*eB  “@QMÄ €bP¥LdBd(ª �@ ª” �L €LE5!ƒˆA•2!� �I ¨&b@1¨R&2!€2 Õ„@  UÊ„@&@&�¢šˆAÄ J™È„È$PT1 €T)™@™ŠjB ƒ*eB  “@QMÄ €bP¥LdBd(ª �@ ª” �L €LE5!ƒˆA•2!� �I ¨&b@1¨R&2!€2 Õ„@  UÊ„@&@&�¢šˆAÄ J™È„È$PT1 €T)™@™ŠjB ƒ*eB  “@QMÄ €bP¥LdBd(ª �þ ?M§¦Ö<äÕIEND®B`‚epasveer-seer-97076f1/src/resources/icons/hicolor/256x256/seergdb.png000066400000000000000000000267051526321767600252330ustar00rootroot00000000000000‰PNG  IHDRö{`ígAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDª�#2 pHYs``ðkBÏtIMEè06KFî ,¸IDATxÚí�w|U×Ç¿»Ùô„$´Ð{… ¯E¬XAEÁ‚Pì*byQñA *"6DQ@ÁNUT�^H(I !uÞ?²Ü½wf¶o²»a~óA'sgçÎÜzî¹çüX°`Á‚ ,X°`Á‚ ,X°`Á‚ ,X°`Á‚ ,X°`Á‚ ,X°`Á‚…(FL¸_ ŒH¤ ä‡û5,„�™N6ÿ0Ìm'¨CGj‡û5-ŽæŒ`,绩àçÑÐÐÈáÿLÓ/`99üF¯p†…ÀPŸŸÐÐ8È5&©qÌq6�›LÒkó›3u15Ãý)• {¸_ ÒГdp3ñ&éåâÌ,µmœg-¨îO©LTß+ÎÚ˜Ìä唘ÜéB#’�gyä¹É![¸?2xDw¨Ïeô"Å4m“�ïëÑÔ�*7€8“_7Ãá<Ë&×$½ ã™ÃË&O¶PehÏbJ(à-j˜¤6à1ËßjHµñ�H}Èä×Eê»&ý<^üz á.†àÍ#Àmœ…ƒDnæ"“Ôlç ©šÇ VêÙ[Ñ éDŽgÓ ÜÅ¢·ØÈtž9¸Úd/b­8ooÒO‹Å™±¤ÐÈy¦±Å$ïÞÔrž¦ Ü¢·h,}³íMîX-Ò[˜ˆ�ž„ÀZÔuž²Ã�šÂÅâ|!ûÂ]Á!zÌg›ó,“KMÒÿb`¦‰°æi¨Gºóì0Ù†ÔŽtÏøÆd‚°GË !šÀˆóËMÔ5ÛÙãõø]zãFXP. ôEÉÚÁt‘þ©ºÔL9Ó¦™Lm¸‹»ik’kwÖQN“ ²Ç%:ŸxŒËM~ù�x›RîwáUÔægQ¤9ô4¹£/EÎô|“½û¼ÂlÆøÝ[ÓŸóLDϱâmÖPÏ�ÚŠ "}aõÞF®:\Jž(Ô¹&Zÿ:¬é£LŸàð–…xWäõ?“Ô1"õ׆»àª b™"е„;MîxF¤?Yéos;¥hh6m:KòÈW¦ Wpp§ -ƒŸÐŽM¢`ÿ†.´v ^qr¥¿K2�°œÅÜjW¼)Þ2× å<çy×1Ï�gÇ�NCšÑŠæ4&“š¤’@bœ_¯QN)Å#ŸCìc[ØÌVvsÈÐÔÜ!�èç<ÿ—ËLUÄ—ò®ØE|�Aá-òÈ ±Ø›âfî¼€Cb€ýÑ'ùÚA#Îgóû)¿öí(!‡ÕÌäq.¦©©Ñ˜Švì¿}Ù´[ud­¸£ÌZ"ªxVZ=�6-î^•$ì =>-‰ÎÜÍ'l¤ÀÏj7;ޱ™Y<@Wƒ–AF ¶;ïßJ;“ôº|+=sšÇg�€¸BªªBî3íA­XïµÄÓ™‡ùŽý!¨xýq�ŸyŒ®¦{`çqŽ¢qÈt�Ï$éI‹hîw!2d€8Fñ�ó3Œ&w b"©ÀlqÈ�Ú�ÞôåL�FÜåã(ùäs„ŽQB96b‰#‰RI%…D�îrù•YÌg»!%ž´f KLä†û+ö·q=ËÂ]à.DF€T^áñW6·0ßp�ƒ 8‡Ý|ª3Ò°s2×rmÝTÝ1ö³ƒMld»É!—£SJ™Ó7ÀF âH¤µ¨OSZÒŠæÔsco¬±‰Ù|Ì*EÄ>¼'„¿|†š6n Ôe¶4L®ç4Ÿ~åàL¦�m:h²�Ïx˜ hIŠŸM=�FtgSùCÒDÊÇ~Þã\S“rªð÷T„ᅥ-X,ð2“í]vÎà˜TNKÃÅ4 Z l£6Ýy„où×$ŸÃÌ §Ç<êJû™Ó-áÏ3:ó·T\sM¶[\hÏ«&•RÄJž£‡PÉxÆ) ánî`Ws!§Ó–z$›öÑD:1œMFƒC¼åÁòç éÎ¥ÜHÒièÃhr ;¥"{ÃM¡Ôa[ U±�¹ÊO¾óÙæüe9¥#—=¬ãg>à.3Õ×§pÙbÈyO›úÄòµ¸g;g¹}“¾,a3ïŸ(~FIn„« \ËAQh{LvëcèÃBÉJ âØÌX²üðc™éqõÿ¼Û§µäAVR¦ûÅr®6i®ã�©G¸ÁÍÓb¸CLc“ª¿„`çz~`÷¹ÑøÜ%´» r@c&�«+ú�£Ÿ"`6a”nšÇ >ËÔå]e*[ìqÌ©&¸N*b�-\çã¬×†ÏtîB.õa“ÆâH$‰Tjшvtãj†óÓyLêlÒhqŒ…ܦˆš§ñ‰0K«8æqŠ×œ›+z�¹ŽdQ†4ÞR*2—'=Š„è%ÙâV(ažÞ{•ý€ÏwJþ¥,ãV§õ?@·JÎèЬË<æÐ‘_¤»Ëù rLD*)<Æaéã˘îqùcç&ÉÔJCcQˆ›žQÞ@C£„¹B’ûÛ1ƒ)=‡an×ÝøCyÒDõÕ6ú±Q)Ì¥n×Èq<¤(_ ˜–¾R‡—ÙehGx_ì“y€}Ê»Ž2Õ&\)ôw=åf‡±Z£³nPÝÁ &Ò@Ï+³ë.n Á¼ì´çqV4Û¸OZ¼õV—¥üO8’G Eá}ˆ»CjµEÈä5¥rÑGwG*¯("ã át>4ànVêA)_HKÆVÌRf÷wtöK™¬©Ù ÷…ñÜ£hóUW«T&)ââ{àð H•x\y“›jòª²º_i.Û¦�ÑÄ ‹ �z£¥ëIL”ª¿œ÷!Ld /êìŽ 'výœöA.OºôÛLƲ„éê1‡¦\D§azhËL )e‰DâÇóÒào6“†6z0O§›øJì]Äp�¢²ž¤¨•l¤x¬Úó7EüËCѯŒóªß®Á…ô•\²í<,I¥Œó°o^¤ó{”&°BUØ"-wKù¯�â«�îÌSÈ:„û#ƒC/¾d Ï{5î�q³´ð+e\„;R�­¨t4¶aÖÆi(äžÖˆç¹¨ ß à²äÝÈõΓtë庡32QŸÉÊzf�p µq�$ àJ�ÏIàzÃåÒ“}üD_eŽ\Éí^5^mÙQ¢!‹ç~Å4m¿XÞÅð˜´"ØèÁv(‹‚{ â(âK²ÂýiÁáLEé[¡>íëAï•ÆçÒÝßF•~¼¯¢ßÛOçõ^‘®gº‡Q—G zÆ¿¹5 F?/ˆã)]Ð(àsÎ5•�m<-©XþŒºÍÑž¬Q&‚ãÜ…Šíшooú2:ȉ¨*ªá ³tC[…!e'ý}$ÿ¿=Â4špš2‡o¡»ózK‰9è¨Aû7N)›2лz™†%Ñ�Ÿ¥n…]õ¡o ‘vŒaá~éÑIú �UB·q®´\\¯ÐVÚùTÑ(Þ%r�ŸÈ`°nO_ãsieì�œ?5¦˜Fñˆd)fbs„uÐ=’0¨RVÝé•�ð¶)çqµACFJ\ßKâàåÒÚ9MÂýªA¡;›¥¯œàlæ‰L“F¸¥û“y˜E|ÉaÛé¬B´á%ç`X,)F2Y"É—„û%ƒÆe’2§P„«h#9‰ýE3åÉQ<æù §1žÜ*õÿG¥3¶Z@wJ‚ï6º8¯Þ(]1޹a�\ɹ‚ÆŠj®+\B44¾vnf%H�jþåL?žWŸÖ®1L–†ËþÁ?0BP[â)ãAçÕSÙ!®ÎðiØO¦XË>«žvÃÝœ®"ŸD{&§I#ÛN¡Ô}L\Ë÷bb£w²@ÚPz-¦G;ç3ž§9ǧõl¬$ï÷à>�¸CZú�/Ö@ÒÌv;¬×à|^g‹Îøì—h˜.wöè|–1Ú«£öÙ’öïÕhhß~!‰O$øÕΫ· óñ£&¡nì´å~‘<]Ç+‘/8Æ0Cyå<–0гÝXôÄðޏs—Þ4чΒ»û"§ÉXMJÊ0uÒkÀ«Šƒ¼¬>Ÿ îã1|hòòy,áºFƒ,ÉŽþåp¿z%a¤$ g»IŒ¹ º]чºöP×ðgD‹¦àÅ9B>rù�{”ÏxA¤í1ÙªÈqÈ5V:7¸k±TR{»&>£Ëú~>g`t§´q6“X놛³P¢Qo"ì…4Þ¬ÒùßN* hKgº’E{š�^‰ö·7в(g°óÚ0!Þí”¶½ãùR”H1«E—hé÷z4 o³É°¨ñª¸çva/”WEá•ì4äFð‹ÙÀr˜Cìc ËùŒQ\EËJ`ê©Á÷âëÇ9¯5–< äØÅg±œ£dó1×Tªûk•ÀNS2�íÊbf¸35‘¹âÚ7U°¼©OÞe½GúØb¶3‹¡´ñxÔÏ©.a ¸æšþ)"r=ºÑ®:m ÅЊ[™Én ÉãcaæÕUXÑ•q{¥¾��SÍÅw×ÓQÎ6Þàœ¾ñ g ëxJ2ò:]Ð]‰Jã?K;zs†ä#àÒˆmÒ팅6²xÍ ‘¤ç#—O¹ „B2•U¼<Ž ø©Q‹T)Ô›•¦ÞhÉ‹n*¿œ|ö²… lb‡Üˆ¬yL÷âÀ îù¬ò‘T¦.ß³vRü͹hA=ËÉ ä“˜Á{ù›¬a+9PŠ�xÒiH;²èLS¥Ï§2€^¼Ékì­„7ü‘ÝN¨6tâ»JÈ!‚ñÑú×KNa¡C'fzõaæ1ŒnÎqo*æÝÇ.ª„Q*Nr$íão’¨Ú…axF€8Éái©I€ö`Ÿ~#�Ñ\¹¶�/˜ÎïOšÑ˜Ú$RF.{ØÆ²‹]̦W1�ŽR•ŸÉ‡¼Ê’ú`PÌ÷ÂW¨;Éu{guhF;:ÒŽLÖ1ZÄLŽR4D¯eÜâg×c’Î ý o�å\ØÙiÇý|Í6ŽJ‹ÓrXÁÿ¸D(«ðIMU!5̹£f±Úgñ,‘&ô`(ÿã{¶(›CßE ·4�D§Ñ˜T¯«è>s~ÊÞê©>¯¹œ+\¬³xÍ„éÇuð ƒDá¶d¼Ž™ðïS:¤ •p™¤!¨xÓ—øNWí®#§ äù�ºLã‡ØÌbfðƒ9ŸÔ55ñxJ|Ê/>�ÄùŽ‹tÌ;¸WÄ­ÍS>-KøVlÐØé-­V44þehH§M׿ÏéêÉõX[)rS�xÀðš…ìc ó™ÂN—fÔXIø™x†:ظQç«?O :щù~èöñ€h¸uyAá);Ê“!dõºI¨Ã”„Ó‡<¼[;£òˆÁk‹t¯ä�)¢”‡LˆáÅ ñc$fž^†UÊn–2‹øˆù¬5Ä(f¼PZÅp­BkW„�‘:g )`›$¶Þg(¿r±–Ù<Çõœ™f!7{Qµ~-VØ]ÄÌzØ-[°ˆe„Âɳ‹›%j•st ÿ9Ì`m¨�v¨ÇÙ<Í*Å™½œ‰RŸÌâG%mJˆ¸êð—Y\b-YæÌ'—˜ÃXn¤+õ"{‡ ‰Gù‹ Ž Ç�bP½F쮉x,�*¹þ¥ì-ž¬øìãCÎt3‹gr�ÒÓKyBgò�²©õvHš€Cš‡H×[p/Oq gÒ š6„kÓ� Ìs|ĶpXŒ b'\vù6VÀ1<¬TÿBÅ´,]¡dÞÍ`/9¶WXþrN�ŒW”KSL‚Ùû×®à‹!­‹0#†TšÐ•¾ ç¼Áµ’ŠÕeûõ óQIX4æéüê‡KÃúf71½UÔdŠÔÓW*Ž* <%5¶r^ Á6ö`ñ¼Ï¢ŸÌÄ3O|ò#A?í&Eô›­ó+j+¹iîõy Ÿ&ùïh<­¤ÅòˆdQPʳAÏË �È’ê/d»7½òÃ\"…lÖøÚ°:þ¯$Õßmòû8j�l"S7‘"“lÖ…£qðˆ4 ro�ßpªpŒÙ]¶�¢‰�É éÔ“²Žþo yI‹¿/u|;6ºð sXÆ/LåzC<ò+%Üp]Z,OH²ÀAú†¨<öF)N@è \§Å�ÕXáç[d6j€XmäéšZ:Ï*¶Ë%üÈÙÊ ]ÕOme»ä¶ú’i­$Q±„ûü;‹e¥¬oÉLö�ÃArɧ€BŠDÌó2VF®#� ;18ˆ%Ž8âIÐV^+ }¥vÉ4‘H×JyÜÍæs/±\S¥ë;$ñíyú2FÚòý]]N]Ÿ¸Y¡Ÿ-ùñíÑI¾——k2*®Ú%Öóã¡©®PMvzs ©Äà Æy8œÿ-âk¦Š2VTX)åäËC‚rf0ÁÍSÒÅTs@ ²€DÖ:�QÀçе~3qP¤ïAs.3ˆ¥Ì$�…<ÉD§ˆX�Q\Ç>¿¿G£Dú¶ãHðºã_ {@å§C¨@¦Šp Fô¦œÉÎsWÕÄôd®ç9¼Â7÷ʼnœŽQ*®ÚŨSÈÏγŸ)tnð&(³påΞçVG7ƒk„‚©'—05€/rU£«l ùCÐLš¡�9¡¨þP5×z¨~ppo:«ÁUéö€üo¶°„Ë�ç5éÏŸR’Q*rŠ•ª¯\4˜xÚ;›@{±?P¬r®&Tâ¶°Ï—ÌÆ×²8 Ò“»„ëì%28;¥”QF)¥”Râü—Ï—|P^„j(ö’¾O ¡%b`uÔrE''“ �»ø‡·ÜÜWâ¬ø ’¤qb­óÿv¢�•tá!¡ Ìf·ô„ºâzž›Fv*/ ‹þ£<ˆ¾Ç& ür.Û¹�úÄPJ™ýÊ�G©4¦Ez*²µ|”SÊïÒJúJ±C¸6`÷Ç!B®‘íÆ±Ê¥bݯD–9 Š9 X1LPžð†¸>Ñ4‡† Éóø;SŒÄ"rKeU�{„jø™¾\L=J(Öý+!Ÿ•ìwPæÌ5!à�î÷Ès}^fk ÷ìa¯`äèÄŸâúŸÌà>çy¬"õoçé¯ I\\oò5xA²;øŽ1öÊ¡¤. B/EèF¾X8µ ø)õ �M4q2YÍ ¥¡70µ<¬³´ë%Þ3ׄ¼*žqÒ¦±§@Þ�,TÚE'F¹SD¸µÃAùÝuQ¬wfš(•†ŠÔ}:en3¦K“ˆ†Æ?\¯ì Ú¥ àWƒ¾ÂÁã!Ûª%çå‹€SÕÍ„ëUõ¤Ë%} Æ»g‰6)㺅\}™Îjv°™Ÿx°+q–ÄöûŒ.ÍÎý’M@õMEyüíÂ|C-)Tä  Ÿ5LªˆrÞÐéÒemZ.W~CšÓÈ$0KšdH¶G!+VùR®ã‚´Ùë,ì‚7Wš\/H`�(¾'ƒ|–ƒ§%)¾œÉº&ð’Ä¿Fø#{ê³ÒfïDe±jç.Å„|ZÐNZ‹Éè·Ètø 5l¼+Šï� -Ü™ cå¼¥Èõ6ÆJ•µÐÄYÜJãÊ&ÅHÃÁ¤Þ¯ñe‚º¹ö&¾PÌËNâz.#‹†¤T7ͧ$é=x£ÊÊμÆGÊÖO#~•Ò~WXùÌP“1Êü.›j'ò´Â04?$�-^2ÕB\ÈfÊ)æ YȇŒæ6zÓÞ�«]#�FtcçJ/>P °›ƒ0¤p!]gà1_éµ½�À=<æÖò.–ó˜¯Øþ¿&½u-&)J£ïC×+V’6\V‹ }Œë8îj7™s#Ó7È…xr·ò2ß²‘<Ê9ÂX!,�!ø¯ó=nxøŽ ÞR*îzI©7H|Ä2’Ίn,�èËGºw3%â–6ƒ_E# MX7—›\¡dTC·ŒGv€[Ï•ŽzœÉ-Œã6¼ír…Å[C6ˆ«CƒÊÏ…4^UŒ;²*ìl Ò…zרÏ"ÞâiäÆñ”௟J#ÅJáæhPÅð¾øÀþæEºyT¦^"mÍ~öÝȆ‹¼²ˆëýø�-zd¤Î,â({}Œ{ÏGRƒ •�`¤ât)¨Å¼êK [‡nœìópÕM²¹ûG1�¬nH–è'OŒ Ï'Ø'I oVcQp¨dâù¶´þOc“BcÓ(€,¶Öñ^$ãèÅ)wùV‰,†�Jéߤ˜eÕ­xšiÜ!Í�·H*ÐuÕ’49UþËZÉÆRH›bpE´¹ù[ƒ�,Þe¥gôÈüþÀFw¾’æÁÒ:ødi¬ŒÇ£AåéúHÛa»9CW*# ‘–2%Ú™E#ž—x7*!29à ©su¸_7„è )JE• ñôã'ƒî7c"Ó $2@D qm„^£Ü§ÄÜ¢�ráG&ßHß5Ý„‘ ƒ!"r€ëØÈ�Õa,ìÂGºA®”ù&NÎ X(ݳŒ–á~ñ Eq^_éñ›òˆ4|e6‰PÔ`¤!`ó&îu£?CP&UKѾ2ŽcŒd±×‡ 9mxI �[ÊUáþˆ``3ì æó¦ÇeÞõŠÁ �Ä‘�JËÛÝ6Ncª°”È6‰†E¨©xÖ—³ˆË¼Z³3Bq‰žZš•ƒ†K®¨e<çÇ^~,çñ9»XÍ èfJ•fõ�Œô)FH‚Bü¤1ÕÓ+à`¸ÒòE·O:xQz'Ò2$TaGö q„ýXצ)!¡4¦G]AÄó¸âˆþ¹Òôә̿ìcʉÀ h£ ·ÑÛ’Áé eƒ%k€:|ª4�ÙRpõÈG*/*Ö½ßè*ú61Âý]n5A}¦;7CÆJ ÐúJg�Eáò à{ÞS,¡ʉã#¥n¡tÏòÁ¢•Kx‹BWŸÏ”&ðOTøÐžª#¨øÆPýÐWÑŠäòx%8ŸG ²XªT±jAT—÷qðGôšÀÆU¬Wª–é,ÏHe±[Ê´�ñŽEΕì4ŠiÐ ¦3Qq“(ã« ¢ T.ÒyZa,cªÛ˜(v®•6�54불N\%¹†ia¤é>x"�ê\:×puZÇgñµ2Zò¼—Mí®Jôc�m ¨ž›Àf°s›Â¾—÷o祩hä31¢üäR¹[÷†{¸Ó‹Â  !S•=À|�ÃïàÇà ëöN¯›¿# ûd0ÀãÒ²êp³ Þ|/øøÛdF*ÓFatkþ}ýè1Ê*y�›¸_.ÄJ¦ãra}ÌaÞ,mÆó =Þñã[Ÿ‰elôSvG‡õ{ªw*ÃÞ¯>x¼ž¬ì�ÉÇ>Ƈ͂0“{ÝÐòËÓ±‹�UVI”Y»'Oc¾O~Ã%MÁ§®Ïmü×§P¡D&CYnp€Ý%5Ôçüz^&“M6ãOß(É àcúp*?‰_¼LL8·1žÓ|»B�ü‡•:Öƒ :¹,)Æ*Ÿ6¾\ˆ¥-mªè ÂŒ¶ü@!yÅÇ]>�Ô§´Ð”±:ëB �ý|D_?‹Ý?$Ó�— 6;q É@±¶9f¦Ê‚µ9‡.>{¹FŒ…ÂœÚÆY|d`üÕ(b£éò�4žÜË]H‰ãk˜QB�—ÀWâúÔ[Ç*4�´…#””.eŽ)ûw.‹ÍùÔ�b%�®ÜÏWnÄн¼ª³Ù»]LÛ Ñ-€ëÄ{¯‰qT2Wð•¢Sp¬åCî£'�ýÖÄR—ÓÄ$~5¡�=Þó_¥‹¡—7—Àî wáyG¤›Çò×:Ïg2À4L}"ÝÈ…n H�²�­l`#ÛÈæy£ˆ2§ oÆ�âH … êÑ„V´¡% IsS>e¬ç3>ašI‰¾Á`çù®âh¸‹Ð3"½œÌgÅ–1ˆÜÞC.çr:zô«+¥€|òÈ%Ÿ£RB96$�L iÔ É^d“,ã3æ“íöŽKøÌ9âäÒ‡Åá.ÂèÆC’¾Ð»ùT-úðëC‡ê8Ì"£‹W×Íš,¿îŒn¤±HåŸUŸKÏ2·s·¿G ;™ËHÎòymኆ°ºé¦O\ ìjó9×ÏߦqCx“eì ˆ-\ã[YÀX®¦µŸÛ�…–¢„ëÂ]ˆžÉ2€�׸Ãyþ—“ÐSÒh@ ÚÒš¦Ô§&©$kbO QJ1ä’Ãn6³‘�lã_ È3Ž�Įާ ¤$ÜEé‘gXáB3W¾°ú!—\Ö1ˆ'™4ÒÉ �T’IÀ�(£˜BŽ’Çaqˆ< ƒŒbTÌL.s–mÚóg¸‹2:1Tl¶ìˆX30w�ÕW�…ûe¢ÉÌ�j¥ê‹âí—GµcØÐSØÍ•�ÃFl�M£VPÊbOùwûǸ² Ê+@D® p•Xtýa¢LI¦+ÝiK ÙÊR–�@]Ç ¦˜èó¼Á{þ«XêdŒçj¾qlÄj�¦R„ñº4ç3WÑÿñ+7ùÍ­•Å*43ØÏµ�¯ùß&¶…²£�ä¡êq‡wë%Çñ ©Š§ˆ×üò"΄,þ5ßóo,9‰<î�.¤ò½(º÷”YÚÆƒ½o¹áß1"Káãñ½ ø—¿Ë’aE¥ªT;ô¦ôQRÎ׈W�RîõéùY:&_›€ùŸ%‚Õ‹=M ^açMQ¤ .¡dæHŽ–±ÜÁ,’¬ŒÿñÁ�<Ë„�Ë·&àoþ R4„™'†ËG(Ð^"•R9õzHNb³DÐéš¼ 9fx3ÂP«¿Ä¯&àþEÊ�Ï÷/P¸öÒ¶èHÕ)ë””d¾)Ÿz\ÚªÕ¿…!Šž·&àþõ$ޤ.Bx`È”ªè%Å&Ǽ¤ûÕ1 ¯ðà@®Vÿ6.N’¶œ=7�ÀòRüfST±œ„ 7‹¢ÍhI S�óßÇræñ#£ƒ$z@biÊiœÃ´ð•¯%%�Cä�Ãp€\ò8Â1'ate´vb‰#ž$RH%�šÔ¦u©E:i$z5å,#›ßùž_ØÉC¾ÑÖŽ£6méJ7N¡¡ŸGå”RJ¥ c¸1ÄàÀ�ݯrÉc3¿ñ ËÙÉ”�æˆÖPuiCgºÐžÆdT±Áu.;ù‹_ù� QTE¢»‡�ts's­h@Z%’1a?[Yˬa+( ÷LJêÑ\ˆ!�LÓ‚Ö4£uI'‰¸ ¾³„£f;ÙÄ6±� Âý¡¡Buk2$‘N-ê’I}êP›Z¤‘B‰Äá –g¼¨� Ê(¥„" (à09À^²ÙËösˆ£ÑÞÛÍP�€ñ[ÄG< ÄO±Ä8 £ËÑ(¡ØYýEQDqu¬p ,X°`Á‚ ,X°`Á‚ ,X°`Á‚ ,X°`Á‚ ,X°`Á‚ ,X°P­ðÿ¡ƒ v1»Rø%tEXtdate:create2024-01-16T00:48:30+00:00~iã˜%tEXtdate:modify2024-01-16T00:48:30+00:004[$IEND®B`‚epasveer-seer-97076f1/src/resources/icons/hicolor/32x32/000077500000000000000000000000001526321767600227205ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/icons/hicolor/32x32/seergdb.png000066400000000000000000000020341526321767600250400ustar00rootroot00000000000000‰PNG  IHDR Ùs²gAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDª�#2 pHYs``ðkBÏtIMEè05ÒO¿°IDATHÇÍÕßOÕeð×ù œxHù¡”2E0 ÈU®lYkMçb®µÔ-odݵV­‹¶.úškóªÖÖV›WÍŠÌì†&–â”4Ø;ZˆƒçÐ… ?Îa®«z_~ž÷ó~ÞÏçóþ>_þk„î²CHÀÌ¿¨Th›•±Ý”2¦óƒyj 6Ø�Za«ÅPfg¾ãrK5hÕ)jHBHÌu)êÜo\•‘ÅôÀ?A/)ÑaƒÜãš°:c2’ú]Ôê3II™åZ}§Ô&«ÕãoÕ^p^Üón9礇U:´°¥ ŠÝ§T•*Ó>2¹`¥B‹Yç\õ›Z'ŒåëAÌia H/r6z•ú=h€[¹EžÖcÌs¿S� ÍÞøª€Zë±^“ ²· á;Ô´I� œqc¶²Ö.eý¤ÍŽ ¨õ¨QƒóWŸwP¯^§fm~ÛT-.®Ê#’†e ˜Òèº=FçÆ9ï`Ø bQ£`›Ý:Ô;‡f]öšv×”4l07‰›5‹É˜FÔ>G„ h±ËϦ|cŸ¦°Ú‹¶Îm›wÐo´�0ÒŽÙ­Çzm²6¹á_›ATÀ¨Ï]ʨ°G§Œ2)|©ÀS Uˆº×ÚA¥”v8³´‰.™R®Hè3b�2aW|âÇYÖN)QgtçŽqÒíö:>›³.ÝJÍøãNtËÕûй8¥ù(Ä5X¯XÖaùô¦_(õ±Tîf̨sA·uöçy'"ZŒéÕ-j´zÕ*ŸzOÍwA›½ï°B�yWÉÂ-áEA.I¸¦ËA.K ¨´QÔi[„ý oÑwºä=¸�«W¬ÆZYC.›pÓ+Nû>·1KÕdÄ;^3â[åVøJÊëÞvŹæ 47$"ªÄ[úýé qa…úÙ¸”žû¨î�vÌ S$lµR»S~uR¿-Bî&pÓ³ž”–”Õ+¢× qA¼¬ØÑù,ßÄušT‹ÉH›‘6¤ÓyS¹“_AqÅŠ¥�ù+ÿéÿ€µ…çÒ ÷•¶%tEXtdate:create2024-01-16T00:48:30+00:00~iã˜%tEXtdate:modify2024-01-16T00:48:30+00:004[$IEND®B`‚epasveer-seer-97076f1/src/resources/icons/hicolor/512x512/000077500000000000000000000000001526321767600230665ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/icons/hicolor/512x512/seergdb.png000066400000000000000000000610031526321767600252070ustar00rootroot00000000000000‰PNG  IHDR^qqgAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDª�#2 pHYs``ðkBÏtIMEè07sâÖ¹w÷ùÎ>z¸3g朙93Ï<Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š¢(Š·$z]ÅÒhI[ª±“¯«¢(JtéÉ—¬bëø‰3ô# (•‰¾,ÿ7må*×%$Ò’ÞC3¼nŒ¢TN²èDÚ’æ2_=þ(3üýøYÁA®JhÌ0–²ƒ,æzý ¥²‘ÄÙŒc=ÛYÍ—ôr•w…å&?¸Èß„ŸöË;’z^?E©Lø¸�ì2Cp%§»Èý`Àð÷ó±c9@Ïä~Äë¢(•‰ÃX[nþGSǹ‡ ÀRæn€ܳ¨ïõ#Q‚E…8ñÇ€€Ewgú8Î-û%;îÍ…}xýH”`Ñ ÞH¥SÀ5‡âs˜_žœænLFÀµü^?%Xtˆ7|â`mO¦Ãü…Â57+€À»g³Ñ뇢‹NñÆ.– W›:–Ň²ðÑ\¸º–m^?%X’¼®@%ÇÄòy¦p­6ÍYè(w(+€t WW°ÓEí›Ò—Nø˜ÅO,uÝv%Ìèà tãš²ƒ©Œg«‹œsÙIz¹kUèÀOŽr‡²ÈÕ~–Qì¸î§ò�wßm0"èç§(qLîcÝîc´|FÑÑEÞû©òîIï8ÄQ�÷?j:Ê{ ëò–p…ãš÷`ù~yWqT4º¢Ä 7“¿ßPïBŸ.“_„ à7ª:Ê}.EÂIþŽòžH^@Þ�œà°ÞÉ|�û R£ý蕲¨Ð šs}9Õ›Þôwœ{s…«NÅ€E‚Ô!Ñ¡&`Áò ›5ëÝŠc®uW[oÑ À ºÑ¬ÜgSÍqþÙµZ´p”·�’€kIeAÒ69>ëEe ¶ŽÄ€Á¯ª‹R†%ë|u®ùC¾ÃüJDÐ À –‰gö-9Þaþ\ƒ°®ƒ¼Á¯êR#àZ±CežLN®®f’Ã+B'/ð3‚W83@ÁÇ„,lé gð+€†‚½ÁV9ªoGº W§±Øñ3S"‚NÞ0�¿„«‡ÓÅaþ9ä\Ks$ ~h.ˆ.·±ÖQ}OT�J­>‰½FU�½!›o9:àj Î`²£üËØ ætr`[ü ™pm�#%æjô®®áWWϬÝiK!ÿ1Ý•õ�¢Ä íY!èóÍpè\#ƒ BîÉNÕÛ ê¼Û9Â6_ #„;~åèrô~.Ìöåuê‡à$&³ ?~røœ¶z+•Ý„÷¾õ2A¸ÚNЖ“ÈeŽpÕ‰6`°[€ Ñp)EjÛW8Ÿ(aŒ‹ @oÞ¦Çnµá,ð�çU,Ð T²èÏ|Å›œëJ«­ˆoØp5™3~%1`MZÙæ+†l‚°»/OmêW�Ö­V»ØTçÞrZ„Çp‰ãÜŠ1šðù^³ž|¾r|’P›iÂÂx]åîÍ!÷j¼4 W¾xH·?½Ø�/�SÔ´/¹BM¿t±¸Œ‚€ü¿:4~R,Ñ@(¤ó(öväÎæIÇ®¹`#…«u9ÕQnY°³íM¶+>+€&T ¸æìð$ápÓÍ >× õ«£@8Ð zqV¹+gr®‹ü£ÄA|µäÝ j¶±5É ¸Vä@ªÞ\˜8œÕçX᪛ À"\Íu¨‚¬X¢@(ô ð‘›Â­ŽÔqJ™-ƒÎôt�WÖllkÙ¿œ•×V²Èö~Ò¤´Æ�)OwÚW§:V!nÉU¢�Ã4W^”:„‚4(:r£ã3�|¾Ì‚Ò8ÓÑáÚ,áZáû¾?kù¿€s€�Ya{·mµŶ+‡N\~”0FôMˆ�+Ä#¿ |(œf(JT,·ülvì#0S(aíä øöYæÀ+@U^+ã�¨�w9;!@XÀy¶¹š0_hßrqU Ñ…•â3~Iƒš+ÞÓƒ�b÷üI0›1ñ”X­rvau@¾�ÉÖ3¸˜ï˜Å,¾g íš¡”t>(w¯T·Íu¾ ¿÷ó¹¡#@oŠOg™EQ¢N/‹´ˆ›—Ñ“-B ¿8Ð)HàžrÃk)‡;¾ou¨ã*¸xc>+säù��ƒ$Á  Ÿb:¼ãÑlŸïµV”Ò†¹b]äØÏo:?ù·;2 ®Âí,¡x÷Rþƒ£*xƒOx‘s)=5gq€*|)>ÛY®´-%¢\#.rý¼íXÑeÐî!¼zÅ¡ ¶\Â]ÜÇùQŠÑësa@v¬¨¬ô™Ã @?1w17E¥�ŠâˆjŒ'€ÎpXBs!ä¶Ÿ9À_î…B ‚b.w”·:ãÄç:Ù¡ sE‰½ ¢Àßyè¯ ¹·r°× ™~ ¼ÖŽòWV»¸ÈëF)Êþ$ð¬8”pŸÃNôì7;v»´ìþÏÑ¢>ÓÅgú£*+±GsfˆÝu¥Ã¯x5!ÖÏ_¢õ]|ácH¹V­s ìaóà'Ç‘ñÑþ5hÁÉœMw6Šâš�åB}íIŸ &4—ìvv±o§|›×M 5x­L8±U\êH´ÙŠyâÓüÄÕ±%Ôd‹ØE[øÞ‘‚µ¢E&ÃÅ.»“ å¯ÂSe¦€BÞª0sªpï3‰ñ<ç0ô‰�'Äg¹ÑåÎàíýò/¦—×C©¸ôÜí·üR¾±£üU¸�YÄbÆsµCí¼Pñ9E‰d˜M™éÊ*ñI¾âJý×ÇbÄ£ô\ãˆèt€ø!…v´3ÏeÈ �q¯ø/O0;W�¥¤S›—áÁ‘@2©d‘E&U©FU2I'�TRH&�$ ˜ ) ŸÒ©NИ†4¤.u¨F&™¤�H’­õg ÅS@.;ÈaëYÃ*V²† l%7 x½8[¼þ�«áß…'†?dÑD'ÅDc~ÞoÁø‡cuÞ=\XFàU6}á¥gµ9ˆ~ÜÃ;üÌ<6²K”¢› ØÂ"~åÿx�B=Wþ|Ý�Êgb f NÐÍÔg¬¡gFô=(qM èiœÃýûÒù\ìxùâ¢6t²hÃé<Èü˃Jr¸S›™Íã\¤z˜7‘X#ܳ˜[\”Q…7 u_¡îÄðŸÐe>wd+¿�Ã]?~f†Õ€%“N\À Lde¹ãÃh¦"Ö3…7H7†ÁÎ8^t :Õ¡N%€�Û G²~žR8Š ùÛSÂ+Žãõ•ò�ØõJ†:&јSy’ ¬œ�x•JØÈd^¤?-CÞôBˆä»r~› õüN­3­ÅH=~ xЕ¨´>SÅr^ ©vitàJ>a¾AÊ ©€e ç&º… uW—ÊãB'¢‹Á<ÛÏ?´ µ‹(™LƒàÈÏ®uUÒ9¢k°@r#ß±Z4ŽÅ´‘qÜ´òí�å ˆ6‹qeêßáÚˆûJPâžóÅý§?›è4þ/ „`¶‰´áj¾e­çC:˜´™±ÜÎA‚KPk2xºÌºŽ«ïÛÍ¿�.§p¥R’ÂãÆ�õrz»(©K€Ü šºªËœÅû, ëaži-_q‰Ë³”TNç=~c"/q„ãS+áß0×ÓP¥A5Ë’Å0®0üÛ,.æ_Ç%]ÂóeQVq=ß9Ì™L'Nç4:…¥Ó–°‹]ì ›¶“M6¹ä’G>{c&’D*©¤“I&Õ¨FÕ¨JÒÂrÞ_ÄB~`¹å‘@:~r]Üå ÞT¾çr6…¡�öçÞ2zòù•ˇ³HàDn +UØÎd^v¨ X�£Àq.½$rÙÆ:Ö°’å¬a=Éf';ɧ˜¬•’H ™*d�AMêQ�F4¥!õ©M–CW^2[ù�/Ëú�Úf¢ Ÿ„|39OŒ¤¬:Ò‚ŒVcß2H æ%“Aª±™ެ q p¨Cóáò”�ÃZ³�¹,b[ÈqzÞÒ©N]šÒŠö´¡)µ\šåî¡�™|É7,SÍöP�ÿ3ÄbØÀ¥ŒóÝ” NW1XGiz'"J½mÌŒ ¤üù¬`f8£ù�,e=9ÆS‹ÅiQê1å¶\ÛËå–çòœ¿ß ¼¼éø2Ì>}»ò»Åý6s}HÎO”!‹‰Æ—\Âðˆ8ŠîÁ/6ݹ�ès&IT¡uhBgŽâ,®ç >â°™BJ(!‡Ñ–ÿn¹àj{Úû7wXFiÀ[ë�œ¶oò1ü¬â|ýúW[vª ~d‚%‰KlOºqƒ ?÷^“@& 9„3¹„ 9Ò¦æ7Zì©çò ¥øµ;ߨ¨'mâΰKû¸l-›æs¢×]  ÅoÒ¾´–kÃæ4¢:�Ù¨¼æñ�뀣ñÄË6“ߤ¥1wWÛhKð Cªa-Ofþt¥Š¬ÄmøÖò$>�Â"ŠkƧ6Rÿ¹\1íþØà)›  ô)Ümq´×‰�l¢ާkÐõKåAŸ£lÙ¼~„Jø©Å36N«FÑ)Ä{Êo–wÈç#Ú{ý "ÎÙŽl Jø›«Œ¾ Òdã"m'U»L·ÞPñŽa!c9Åè]±+#,ƒŸ®ã ×:µyÓ¢Ì"ÞöìHV‰ G‚vîI¹9(+òDZêú—ðݽn|Ô8Èf%T6eó¶qåU�Øl‘w;ƒ]m§º1Âb#¸‹'=PÇR¢Ls>¶ü®ìâ5×–ä©ÜEŽeG}¦’}Ys9vz²„[ ú>N1¨qíÙT sl×ц-JÊá.õ\9Èâ_ö?ÑÅEy™à+žå¸�ŽfÓ8†»yœkè FÃ�@5á|®3ü6“×,$ÿ_ªÜß!myÃv3ð7Ç 9¸ÜBv3ÂF‘˲l¦3ì=–\Î-ª@T18’‰{N6•LÓxʨ–â\)EHæ þ°™Vs¹¨ñ.kŒy>Šàâ¾·–3SÚÅ ^?H%<Àå¼ÉÇ<ʆ¯D"wµþŠy;(c•›F)Añ¼ñŬáé0©ä$ó¤ñäœmpPÅ U¸Í2TØ,ŽÈããFc„£�ƒŽ'tŸÙÆ+ò³�g"±Hqˆ�w,_ÏîÑ…4À@£;ÑéêA6ìø8ÓÒ[Ãla Hfˆa—^ÄCA(þÔe°�ÿH?~ ù‘>•ÒÙK 1Äæ%•ðW…t6ÐË(i^h S –îL±\úíOçUã7Ú]ãúñ»ƒpî ¸AE¿ÞÓËÒmäž™úgÎR5¤±ÁŽÜÏzKkA%4Zñ�ÅýW°â¯Íׯ¡ÚÅñ};ñŽkÅlÞ¬Þã‚$· ÀíÇO.ßp¬ëåZoË»Æë¦Wpêò¾Å›ýCØ|µ0ºýúAT$*O2WÙD#(]SNâ4]øÇY<èÐëÜÞá`WgWÄ@Å<©] âTçE‹ó÷Ÿ ÿá†\Âc$WÙ„Žñãg÷¨½G¬áãPÞ³Ñ(ß“Vó”ã³�Ã�ª)_èî/*¤ó¸…ÇåáÂPìoèÛ8Ëæ^͘kÓwvò±:‹UR8žo-\E”M ¹›º¶%ÖfŒ!ÿtË·J8IãA‹Ã¸·¼.&0Øàlä?÷_çÚ8)ù“ó+xTǸ'ƒL´õ5Sº$üÙ&`$Á«éíuC+)ÜoœŠ°ËâCï߷À·Yô—õ<îÀõ¸ÔâËX2ûÒhËÃÁ ê(»¸Þë&V:R¸ß¸ØÁU¿oaðœÇ@‹» 4LøŒ¤—úý‰'qŸinçK¨o<ü{K—��Ê#Fᵜðûã Þ‡X¬û]ŒÌá*Õô‹GÚó¼íÙÀ‹†¼ #UèÈñtwäßÍ]Y%¾¾g4äCLs¸Áy÷*-÷ËCDí�íœä�iÃML°u ú®ÊÂE¾f¹låOžæ„0†ãJàeñå-S`%rÜb8¹ù¤Ü·ÝÇâï¾ "’d Næ–9pîçm�Âñ,ÙïÁî`:Os\X¦�®âס„»½n´bKUÃ�`.ýËý²5ó…ßípµH¢wò›1Q`R÷1a¡¶ÁAÇvþà Ž ÉrËÇ bÙÿ„!¦�y3lß~Þ-~³G8<±¯Ã™|h¸—)ͦ…×�§bp†…oX?Û™ÊãôR¿»“ù§Hçî¸á^QWÌ-å~טÂïrèc{‡ fºe”ÒÊ0(W¸ÏÁãÎa �r´ëi@öþ3Í�ß`%6¨c8çŸ`ù‹8U|l£p ÿºú~Öñ =½~0'@iÊf2�q´cã�,¿ÿ÷'ž8•l±7ð|¹c¸&Ì'Šv†rÓ騯íd2wÓIÆEŠ#˜ÄàÇÏVî'ÕPê¹¢³éY"yP|û+9¨Üïw�¡ÔL&Øö°åü�SÕ‡`¤9ˆwXî(pùd ‘Æpñ÷xÝT%DuÏ•[´­>¦B~&ã ùñ³�‰ÜJ;�G•0�D®äkV;ÒÁ*›¦‰û²l—ƒÝ€#•ê4¥Ý9–SèÇ™œN_zÑ•ÖÔ%=n»óu¢;×y4ÚïW>† ¿Êg€¡ÔóÄUb ‹yƒ>TóºÑ•�T:rß³ÞŰM”ó>%þö• ªÿŸENäf^f$ÓYÄ:rØÉ.òÉ'ŸãvŽ¢NÜè³_NA@K6 Þ‚¥øë�¡¿ëð,k(ÆO>óy‘ÞdyÝP¥”Lºs?“,ãÿøñ³ŽÎy/ÍHFV ûÿLºs7?²ÚTËIÊáo^å,ÅÁ4PKPÿ[ØÝŸ#+ßo,7‘Î\Ä5œAÓ8x •ŽjÅ£üaðëÇÏ7Ã:…/…ß á%â‘d:q;ã®�œ¤|æð*'ż¬û¼r^€K¸CøU1~ðÔ0Z˜*Q§&Çó,ÿn sDÀ¯;‹±`gV êœÊ‡Fßù¡¥\&s'íbx÷›Ê#elõŠx×  vŸØº“¼®¾*p*¯0{ï/� -üîV±ƒ?íuõC¤×1Ñ…±jpi¯rD̪¼¤ÒŸo™Ï"Æs­1´÷AbìèWt�_ðÑ�3¹“;¸É°hÍ€n�kÿÿ͸“ÿ‚Ò“&mâŽ1*XyM hléê#EÎ)wd¨TPwÇãÄpañ@CîZS2ø´•O8:ÎŽ ÷q‘ Î篫¥Dƒ{Å}«×Õ ŠÚ\Ãß®U£Â•6ó6Ç幉è!èí–o(a"S4-Z#Æ:©ôcbP‡|ùä°ž%Ìc&ÿ1‹ù,g;‚*k5CãÐzÂÇëB[æVÆM@¼.â‚¥- W§±À늹ä nålWÛ–¬g‹YÄ26²…�RL ‰$’B5©KSZÑš–Ôq¼ÃoÀýœÌ‹|M®×�Ä~Fsy@›s«¼®šY¤€®õºZ®¨ÁíXù{¿ˆ¯¹�chBšƒÒ3iÍi<ÌXÖ:Þ\ìâ ºzýX\Ñ@ ÷’×ÕR"K*ߊ€Ž^WÌ1>zñƒÃÅz!óy‡þ4 êØ.ƒN â+ÇZ˸5ŽÌc|¼&´á¯Ä�PbˆÖ,^ûHG_ÆX :÷²ÎÑpÜÀ.¡IÈb­:q¿:Ò/(âÛÝûØålÁÒ/GÔ …$ªS=nm,+ç‹6·y]-‡Ìw޾ý y†C-'µR©J]Ò˜†Ô¥*©–SEuNãS6:¸÷ʼnEEÑ#ä}a);‰ZÈÙ<ÀçLá>ä”XUžª\BÀžB{·ò»×Õr@ q?Ím~ågò‹ÅM MiCkšÒ€ê¤“L"Ų“m¬f9 YÀr¶PR.ç6F2†n\J?�‰Íy‰î e™×Ì–5L§uÀÕž¤±+È“¨FZÓ‘Ž´¦1Õ÷úÃ8ƒ—xœ�^7ºrSSôø»c/ÂÞQŸ—;‡òiwÐDÌŸL[.çüÃfË5D!›ø›w¸”6â+‘ƒy• ¶5™Êq^?2\-9— “‚5IÔ¤3gr?Ÿòë£äÒTg¢æ È¡¢à³^WËA½¶r+xĉ¦çñ+\) ±œO ºÊJä>² Œ¹Žc^²ÒEp,SÀÙŽò&R“Nôc0Ÿð'ëŒÃ¾lúS}{‹4ãçs–×Õ²$�,²éX9¼G1w îæ/G�SJùLçš å¦r:¿ØL)»x%ƬTe’Pï§,óøhÎ)ÜÇÇŽ‡ý¾´MÎ;'“^\Ê…ô¦ µÃbx’À»ÂKYF+¯›jA÷Ù8<)á7NZ5äæ9ô˦ÙÜI}¡üÚ´Føæ�-žê<ÎÂ�èg‘ë0a{R.'xÝàxá0F’�Ÿ¶³šÉ+ÜÆYJªy´U“?…—òC /Tëò¦!ö¾…öQ(W… ù3l6%üÁ¹âsê§6ÃaFLKξá+��ákðIHÏq}*œ{B71€ƒŸ¶°˜ßø”ǹŠ>t¤.iŽ�QºŠÇX�xÝX#mùÞfXŽçh±õíø?"C·_¯ÿ‰#�«l¶(«¸8f�lÚ wqšá×·„hpí4q%'•Ï=Î�¬g&cx‹{8�#hi£‡v‘ ÿÞÅé^7×@wÑqÕ¾´…GD‘Rç¦ÏÐÓ ú‰Cù@¾²\©lãŽõ ‡þxPümUC˜z§iY\{œˆ"E-Ö©�–1™§Œažà!ßJׇ>Ñ¡¯ÍîýN‡b&÷Û:I %máñ+V•»,]µçñDŒzÓ}A¨íWâh 1¨ˆ³TÀôõº©ñBß�–¯³ Êœiü(üzBLºÀJËÉîcƒà²Ž­Ì |*¢Ð¥p¯Ügž ÊXöÝé͘t»y©°¬Ÿ!6±=�)ŸŠÉf£xš±p6ö4ó)!wGžáLV\¯-ž’Ïb‡×Í-G—ò”Åyñžå¶ ÿÒ€aÆ7eÉe5KYÂ*6“KÉdP‹F´  lw©É\O nc}À¿Œe C`Ð{Od™ÜÎ:ï­È¶8ŽkHc6ür#óié D?;XÏf3‹¹¬`ù^72¾h¢ƒ« ¥ö£Èr]»È’È –KøœezÖãkÛ'³•Ÿ¹Ÿci,Jô«Ð„ãy�_l">7DÓËâ!ñ9ïIÃcÎyH]Á,¸ˆsÅß°4‰ÚÎbÆñWq$�ãÄ"F¹'Ĭ·„2/–z91 (‰[ÙnÑ®_Œ¶v5m¨–0Œ#íër4/Ùžð`P NäBÑârOES¯ó~¤ˆAb6üöÁ€ø¹,c¯q-ÇÐT¥üᡯ‹A�¦ÙcÂïÅTgLæ‹ð&Å|bÐó‡*¼h9e®à1Úºª‹�³PóÉã:cÞŒ±œšyý¸Ë ­ ÿ°8R®BCšÓØu@ )Ô¥3}¹š'ùŒÉ,b‹#÷j!Ðc ñTýí˜ñh›È-_ÿlî²8Gïca�·”+BÚ�¦s�Å‚~-½�9ò±ÅÔ=ʸš‰>=©…{›@%¢$‘EålîàUFñ/«Éõ²r¹EÖ­X!üö.¯›µ›®³°®ÛÀe3ŘóWCízZÞ¡¾1_ ^¶˜°¿µÈ]š±$ vÛcL:¤ìG*µiÇÑ\ÊÃü™ÏfòÈg;Ó¹L4Œé% °‚˜ q[�e%ý-r&òœ1çð°íµ[2Òx—',Ô|3xÌb ñYŒøß«Æïu+âB¯«¥8#� Ñ•S8‹£ ‡S²+°mêuå`±„_b²òx¶r~VÕ“†|c¸ÏFK/z©Ük!Ùx7&œˆ&ŠªçƒC/X‰îW,H£ûZhý-°±¤«Ê(CÎïþÀn$jR–®4¬D©IÜjÜÞó|Lœ—?!Ôíu¯+¥„“—„WüG ¸;\ Qµgøc“û|Ã{ZDDXí ‡{;m|è$r“Q»!Ÿb@õ:¡f#cÔ|I ‚$QKî[Ïý´¶cºqø/´�°—RÝà(l�mÎ`éc0øcs$–È­Æ3Ž\ãɳ/ËÂD:-&¶'JXÈ]?½îñ!`F‡ÿbn4Î&OÈYÄ.ê�H’+Ÿõ÷N^N³É—ÄmÆ)`£çNÙº ÊÏ cè R ‘zb¨C/8²xÏ8ü—ÒÇ6ªA÷ÿGG›šÉ�¼ÄgŒà3^äzRÃA¾ZŒïú©xöR–$î2Zy.öØW^kÁ-ÈõÞSqh%ÚJ¸ÚÃ%ñ°Ñ w�#'%‡ˆg[8Þ6g îbJ€òK6¿s§ ½“DcŸµd›3…!F'šS=õÌ(} rU âÐM8,sêþ92 4ŠÅ6s�£s¿g#×Èä:æW~f1ÈF=:Õ`väD©ª ϧ½o<ô�ÅoõɧŸgõQÂÌqÂþ37ìQàœsk à ‡«I&ª2Qüþe™«)Ù:²Îç}“ÝãÄ5À8G&1Y¼eP.áÏäîÉ‚¢S1WxT%ìœ%Ëlö,œu[þ1¾»Šää'Ã-=·f¼Íàß“ÆX:¾Hµ6"”§–h–åÇÚ¸(²$ð�PŸÛ=ª�v.¾:+]Ȇ‹FÇÅ<ïØEùõBþB.¶Èau显· éq…°�/á*‡uobŒs´Ö3¿ù/ µêQ]”°s“ðzç{â›&‰Ç�®¥?r¬˜$±ZˆðRyÕÅð÷ãg˜…4¡•èó-ÇǪ�ùÏp׿�>ù#ËÃB]^ SÙ>|$�«®Ñ½×Ê<Òî4?谡П aw³Ía)Õé \�Æ*cŽS¸ÔeM¯àgFþm9 “M'ª’í¨ì™ÜÌâ9{W†r9.ë:’�ÅL¢$ï#�&T'…$’R ɤìþ{ßÿÁrF3Q=FŸÇ…ù}ººˆéýø™É�.Êi/:N¿Þøûê¢÷{{I€ù Ý&üÞ�‹õ ž‹¸×­k…š|fü8&p"ß³†lrØÁNòȧ�"®kr è•É÷û¤¨ûo«i4ª]ëÒg¼ä8ÝʿᙢΠ]Êåc‰Ç 6~;lmÊ’À}†‰Mœå7— ³ïŒ› ‹ÅSÎR �ÄÖf ¦*!¤ã¥|‹å]$ðqƒ¡cïä!Ƹ*«� ,ÜÈJï9].æò3/ð¿°SÌ—ÎéÆoñr6\K£‘‹6”ðˆÿR‹‡£î2l—ÐR c£CBðdàc í£ÜºJŽOTºý>ʧÎ}Ødø"ˆ BoH2¬:†x/ŸëçQboèÉ�ô *‰øðáƒÝ Q;ÑÐ&ÞâIAžëÛXÅ �ë �!çp/›]—'}ë·&?h$œ‚üÈ�ûýÿŒæ¼€_eЈ?Å2‹Ùê°^Öüɼ%ä«Â½üÉl×å‹ÔLw¡ö›"ÖD­]ˆ5À±|Ä@É$‘H {'kjswˆí‘´ë¢)èm°yßÊà :¹OÜ2ä[TMhÿ”rÓE!S„œÉF›øQn�„üþK^kÞ–û£èo_ª�©Ïýâ½1-jír@lMµx(PƒÄã4iÎŽæQSâo;K‚lg æ -pøû…á›'<%Ÿ…b²t¿`úR1‹ k—1gç{æ†�{'ÃXæuÊ[ÀaRþzô®J@b§€/™ ^oÂGVøå)®™¿¾;Ú·ò‘k(S^…±<>„ÁbY;xÖ ˆÒ(ðZ³ˆ{�'.ÖøYÌ�¼µV9"¶d­kÛ�tØ¥hÃIQœ6ñ8‰GGg0›!.£!ûÅåwU _Òuä|KOå-•ùÿ6œ*äÌc­¡‰âæ`'niÈÓãùÖuiÁ#}üÆéì[6rÝÉ¢„"Š)¦h÷ŸbŠ(¤� w§}ÿµ‹åüÆ‚(¶Ê±5†\BàWÃ/–Í ~á5î˜ÀÍÌç#—¥I¸:$&€el˜Úó8·ïýŽ5á Ñ4j#Ë 5HO"¶âŽ 6ø/ü‹g\Ÿ�„B²¸þ1OÌ“™N}²()3ð÷ü½ï¸oßÑ_ [À,²CrƸAfÉ@jT'€^æpÑÑWCYÂd—­ ¤.Y䉿^ÍlÁð©?Íøˆ@.2Dþϸ¨.høÙèª Üh8ßÊ–º*+T$¥ŸBKAq!+¢ZÃJBºm˜kk‹'D±ÕËÂo§D=¦ëábx²R%ž®J’ül°pÊu³ñ‰åZ„í(¶0ð=XðG�çR…÷|C<¤†F]2u¹ Ç?ʵ‚–œ»­(Ÿ¶ò¬ÁÐâ)á×{ Žq�Q'ÿ WÂÀCg… 0þ¾ ƒxž³,üâ^$xpçFóhcÐÑ‘8“ü+|c«ãk�\ÈÅ ädš‘I Åûý)±”ŠYöÿ;ŸUŒgŠA† §R=˜ßß§‹Áé9¬`°cCÑ5¬˜0’8Œ/ ¿_Ä®Ý[”ð®Å"÷0a¥µ–õŽKoÏó†ée÷¡*Òj0ðô¤Bk¬áQ^¦!µ)¤ho*ýï’ÝÉ¿÷¿öü¿’µw‚RíâQ:ˆV{>®g5/:TOÚÌBá ïª= ¼K_ƒ.¢‰ñ|hü·Z¢ïùlqXvC† !ܲy dE›`�&€.Og”˜åJa�·ŽNžÔ¥‡èM§t ã<"í!¶¥KУŒ)-²ÔÇ8^ôi|·Ãº×àcÃ]‹xÐU˜’ð!I‰žð¤&J8Wˆ œCw�js‘1Xæ*AJ9Q ²ñŒežþ¬s8üWŠZ{ð‰ô¶;ôP…ŒŽ3>ñÀI @ µ¹×“º(@r ‘çx°…›$†ýÎu8-5M|çÙ¨Q÷s$ œm㞤‹„\SÇA½“yP8Á(MS<‹ÖœÂB}¼�Y¨„ )ö[‘‹w¸©&~qJÓ_Ždé>Þò–ØZäwc¸qúñ³“OmÍ]ïs>ï Ö‰Üf ¶„#<|“êcuª¢ÄíÄÅïmÖ¨±…—¾IŽÂd�.)δ5¥ÊâBÆ‹›�lFÓßÖ§%óÄ €½CoƒŒ›Ÿ-ô÷ðm4`Ž0Ú‡gUâ„Fb§}ÒÓ:u:Ýžô£—åµùCÌû˜ ǪËPF1‹•¬a3øŽ‡8Ú�jTψwýÅ�þæ…ŸH~vq›§‘šÛ ‘š¼ £„�êLºÝû[Bžl!”ûÎ�=Ù5Õ:›ð`ûHãšÓ–fÔqì€ë8Ñf±ƒ˜>ç±ÞÐÖ†…l=…•É2ËèHJ\‘Â÷BÇç�&Àþ 4.‰ýŒyí�I¿o¼eTŸPhÀ$ñŽ3mW,燿ŸO‚2‰'g þ‰ÿ Áñ§cøxKèx3"6Pœ’ÈÝ"¹o¨o“ÿaCÎ#âR3�× _ð;mr°XëüäÊ—pd¸Q¨×XÏ?JyHxÅ«=ŠX–4ž6ÌöóµÍ* ¥!Ôw·†}{“À]†Éêo›!|žÅðŸ*h4FŸç„š}à‘J’ Ê'îYDŠ,qu²'�¤©eî› ÓǶ0·öqµÜO>-ó]Êcëfqˆ×�Hõ>jó<’–®ÄÇ çÏÅ\îuµ¨Í§SÀO–á2kò“!ßf® Û7,‘k ¦»~†[øNä:ÁnqOZÄÑ^?zjç)V±Žkq oó¯s78‚T×é Öé(.C ½à°PŸSÀït±È{Œq��ýaq«™Áý¢î¿?+,lR¹Û˜ÏÏ Nòú±ï¦%+…M”IO´?”Q,/"›eLãk†q3§s0 ÉŠ1?› p3„NøYÌìóšð£Åð¯åÑÞ=F)Bï†d«bøùÉ·HZ•§ØelÑjúyýÈ÷rŒ0M­5èCÀ8‹÷TÀ&2‘�x”+8�ÔUQbôðY̼©¢¶÷4Ï öÑܸ˜÷ãg‰Å€©j¹…˜N¿ =¤r[”ý–±{×ãÂ͵œãõã.Â|h†Á²áj£G`Êe3ÃÛÜËù¬SAdðQ�6œÄí¼Ë׼ȩ†ý¢Øc)LcKÆZt§ \kÜi¶dŠEÎþÇÁ®—¥ ÊKx?ãŒgíe‘oçzý¨÷C:øN‰‹?™3åb.rô~ªÓŒôçN^gÿ±š6ò“"nòºÁñÁm!vÕWÅ=rCÑvnŠ!šP,`çij˜1%®ºðIÐÛ'yJ}C´I¨Ëƒ–þ~üäñL ?á‹©ÅÆ |¥Q›vôæ†ð>?3� ë°]¼õptq‰�ÿ…ÐUsyGÔ€dQ¾Ì뎇‹KÔý×Ci ä¬B&…(³Þ3„àDáÛŸÄÉL²ùæmâæˆø&¯ uU?4� êÓ…“¸–§ùœ)Ìc&Ã9_u�áã½ þR&ð2§ZpîòYÙ}ÅÍùÄvŸùç‹­®Å@&… ²ò³�é/ÚûuàuÁ×òþi§{êëÏŽšLjývXëœDUPG�ºÁù —¥üÂë\ϱ´ æÜãDÁÚÿÅœ.ÀþTeˆ�ˆÍÏN¾ä(1Ì[ ÎæSÁé¥]*b oÓG\´6à.16ÀþiŒE¼âØàpÁȹ$Ìž” hË›a¿Œ_xƒ8ÎÁ°ßGÑïq K$r®±è&Þ ›¨óŸB'nä[–YÆØ÷tçñ1—ÑJ,«6Wñ§­²P./xîpÍž[„šÇö–°Òp®`åžËr&ò&7r<-‚§ÈÆ;9Ñëæ:à F:ÐÑ[ÍËlXѤҊ~ á+¦³‚­ì¤�Š) �6°€I¼Ïœ@#CÈØ¸‚ßÈ–ry,ySE¥žß88¯PÄæÍGonâÒ�,c3™Ç6ˆ‘~�s�xì÷÷xÝ`Ôä&nþög£ø„©bPt€$ªQ�:Ô “TJØE>ÛÙÆV²Ù�)Îr Îà<ºÙF“.á'bš×Ë­'hü=o]I‰UhÃat§¥…Ó)·,§˜C~¬H ¯¥áï¾”Í(®¤iX¦÷LŽâ98XøÙÄSTlp± \Í�9c%%¬T=Ûg lb�Æ50 u¹ž â!Žõðj4òLæC1ÏR]T@äïÿ/®]Ádуû™èpz¿ËÒ�ïÈ-åþƒ,m¼O0„ÜxFåŒö¢Ä§0è0 UéÉCüfã/QÃŒ„‰šŒv5ôKXÆ»œjëí· ßˆùWÆ|TÅ >ƒè4CI§TçHf²q]º„¶^7½bp�‹0—ÙŒçFÚ8<Ï?ÕàýîµJ£Pè&jôs}XJ¯Á1<ÆÔË‹\ßÿý©Í±\Ï]\H+¯›]‘j1ôóù‡GéôpMcÄùÉ寛­„�,FöÿÁ»A%áHÃÙë>ãÜ�_dƒ,÷÷¸ u¡È\*ªò¨|>žHâ±rnr™Ì½7)}€’¸ªXÑ„Äw;A0Wb˜Lîe Eø)d)ïprX_`ÑJÌÏ2=ŒkxR·wm¸€ëéO«°Ñ%ð¼AÂð‘Š㘣 .R¿vQI©ð´e�ØUvr¡×US‚¤ºèÿßÏ&ŽöºjJìq‹ÁÄè?š{]5%(n5KyѸ‚L ÇsBÖ˜JÌSÛà,ÜÏ«®f*ÞsËÅ·9�6† yŽ%ä’Ë2^¦“× P¢Íi�îíÌ[pe ªA»£Ð¨þS¯œ¾À2Öµ_å"…· k€E§bJìr›ÁzäG£ùïƒÂ¯gq³ê‚T$jr—qí {¼öÌ7Lïêi@Ñ‹Õâ[ÜHoCŽ:bÈX?ÅLábƒÓp%®Hål&’K1…¬àiC « ^`w1Èë(©ËxÃ4þ¸1ÒAÖòøÉg4§©�ßø¦3ï•3úy_´ÌâkC7XÆ¡^7Bq@ÏÞàsµ± ²�Ï8J]|Æ'µ¸�%¯´€‹Ä_wc™¡ü¢û%œoˆˆ¸•S-reñ³åPª?ðºj†ÆIœÈxà ÿg†ýFc0ˆa&DfE¥ ïîY›³ýKÙe;øYÉc*ŽÚðŠ…óÆßÈseñ…!G.—{Ý$Å‚ºbèO?~~§¡MÞ*WÕpoÉ0:Èá-:„í>é¼jqÊ𓮢J‚åð³íTZÒ•ªæ=�‰b™_9=̦»µŒ6‚~üŒ§µ×¢Ò�Èu :“,å=)tâ4N££zz®(´gN¹.°‚{#ò hl46õãg"½~•‚dn5xoöãçKÅßÖ¼ËZòÉg oꪭ¢Ð‡™{;À>¦[ÄîÔ†ß-¦€iâõ£¨ð¤ñ€ÑNÓÏ|ްÈÛ¬\ä‡éãus”ðЊûÁO¼Åi!yïM¤½9†fFç‘ò—Å0SƒNE”ª<+û.MK- ¼|‚¯ÀU\¡[�ŠB UB4Ði ,%—,â)£ÉC-ƒü,å,¯D…¥.ùñ³ÒÆ*¯AÀV±tÅø” W:3a¿®ñ­1$DfYL¹Z½ÇF€6å"÷ìŸVÓÏ&W6Š9Kø&l*ÃJÜÒS q¿Å¯g[tÆ<,ºW‚çK}�ÕÖ]-ìûÿâ8¯¨xÉÉ¢/Ù?©mÌÑÃr#PÄ4òºQ†ú[zèYiûõ¨f þêÇÏ®V�Ï•tý×[êùfãyh|O#*Üc¡ôãg™¥¿ÿ²\jiÙ¿“g©åuc•h“ÌMÆîµÚF¹§ S,§€ô7ž&(ÎhÌ{–Î]çÛºvÛG�X!ú)á[Ú{Ý`%š¤ó°E—øÙv'ߎq–SÀ6†¨�@ô2ºú*MÿÑËUy) ²°ìôãç_úzÝh%ZÔàe‹¯Ë.G¥MŒ±÷|Uæs’× �KÒ¸Æè“±4ýJ— Ê=ÎxOZÇuªá_hÀÇæ=<åP¥¨oÙ“XÆ%*`rIÞ´ñÅ72hUÞ6|mé>.� ±£• Ck~°è;¸ß…Fa&C-÷–~ryYOã£/S-Ÿgïµ4œP“§Œ®DJÓ÷jÙQ‘éÆd‹—¿™k]ªò$s ë-;”Ÿ)œ¨"AÔâAƒÊξéù‘�õ,’h³Á˜©þþ+*½-5ùVr^P*ŧØD"ô³‰G©çuãcœ#c¡îëÇÏ®“¦å1L·¼Óntì@^‰Îb©ÅKŸ‚¸+ãl]“O¢�® Ôf°m4ž\ûÙÓŠ/-§›]<’q™c$r¥eÔÀét©ü†FÿDe7Ïh$™9�Ÿm¾ý~æ8Šèä†ê5“3ùÑÆó]`ÊáO^f­cf\�C¹�¯X„&älî´u–öŒ¸&Ь6€¢8FÒp*©Îâ~p¹ðã§�åŒä>úÒØ3‡£UéȼÄdW{ý}_þ™ÜES÷9ZÜ.½©§ôJ, ‡œrsV�E?†»’ ìK;YÀ·ä^΢ Hëd�DuZr4Wð ß3‡m¶®ÏÌi;£¹È¥ÛíÛ„rй* o·Â¯g̱à Üpm'çð£ë’’èLΠmÀa˜ ÙÎzÖ²œå¬b5È&‡�RD‰Ãz$‘BÕ¨A}Ò˜æ4¢5ɱ¿¬có;\æëÀO‚Vþ(ú“R}�B¤1cGbS8•-A—Ø—³9<,Â~òÉ#‡lrØÌV²É!—\òȧ`·V¢�D’I!• ÒÉ¢Õ¨IM²¨F©aÒ™(`.#Ál ƒÈ�Ìû\pu3§ðGXj§(A"û¸/ÄRÓ9’ç˜éò@Íy*¦ˆB v§BŠ(aQo—VóB4q’µñúõ+•›T¾ºåº0™5à<>f¹+•šØJ›ÃMt Ã9E=ÑžòO á¥xIWQ©÷ë0—L¢-Wò+ãlØÊ$†p8a{’S·¼0úsP×Ü/tÊB.û}RhÇå|ÂBq!K©„õŒå~Ž»ÚrOÑœúƒ0E R×Ô�IÏu|¾í–$šr&Ïó›"¸c6í`6ïs]ÂøÕ/K£…»®9–C%GçÏà9‚…«?±2B÷+b9ËN5Zs0‡sͨîù9ÎNÖ0›éLe(ŽØ}rù–>­m̉Ìõø Ä5^wŸø%‘·ußíœÉø¨Ü?�š4ç@ºÒ‰æÔ‰r »B¶±’¹üË¿,`=ùQ¸gk~¢YÀÕ‰œAvTÛ^¡Ð XÚð“ Éþ g�åšdR�æ´§=­iL2"dPÌN6±–¥Ìg‹XŶ~ñIäM®¸ºƒ3ÅZT0t ,}ÅPbßF}øÃ±ˆ±ø¨BMêÒ”f4¥ u©E ª­ÌSL>ùd³‘ ¬f%ËXÂZ6“Õa_¶>ù `¥“I?Æã÷¤F�‚#‹3„ÕÓJF{X'?;ÙÉ*þ ‰ ²¨F-jS‹šÔ¤:UÉ$�4’I&‰„½öÅSH!ùìb'9d³…-la3›ØB;(Œ‰!6…épµMYæuÕâ�‚ã`®þÌB¯+¶—"²ÉfÕ~×H ™dI$ßÞ)ÌO Å»õK„c“-|'L-9žw¼®šR™ðñ‚¨–rº×«ð(†_U!ü'+qCS!΀ŸiF2âÈî×¶ÐÓëŠÅ+êU%N ¥pu$›¼®X…§�á\­¡*ÁJôÈàá+. Åšzü#<ý9Ó¿T”rô#Ö}F ÅŠG…§_Äe^W+>Ñ-€{ΜuòMT´áÂK:íâPl$›®%rv”u!+z è–Æœ$\�ÃeÔ  Mh@UÙÉFV²ŒõAùÊ …4îcwð]”ï[¾ýXåªýÿñ«°ç?‚.L‰zK”JÇåb€Ï¡sgq<Ï1•õe¼ý“Ã|¾äª¨F½Mc(ùøYÁiQ¼«©ýóø‚+·_öÃôTÛ¡TRÒù^èzDµ òdp.?±ÝhP[Ì|††9j±‰=Ãß�Ÿ•QšÂ×þb´ Y¶!F%DŽ€N|Ì—Ž¢Íåꈫµ¤ñÈ~®E¢18oÿ í\ÈY¨‚@%²È€‚ÇÚýIäR–8v­‘Ï»ý–•þ‘Ÿܶÿ¶í?Œ�ª¨D›æ,ºÝÔ·Ì•Â�bð«ôm"Ôiø—N‘RdŽDûÓ.äÚÊQjƒ¢×‰®¸µÌ“È]®€úñ3!"¡¯LÃ?rS@¤Ú¡è4ýÅ8<ÖTKbŒº b™ë×_¿=ékj„¹eEòþ�@¤Ú߀ÿ„< 5b )úŠì/,ýïìbï[>•0$¬ŠZV_ÿH­Bi±Mû‡ŠÏìú°Ö_Qv“ÈÛB‡ÛÅ9y2ø"èî_ººßžÖÉð÷Ùöwc½�gBØ’+ Ð�Bw›f›¦?;��{sù™1Lc�…“ïoÂ$×¶[ü—MáS ½ý_[´?E4 ÞÁ‰á{銲‡{Åz�EŽL~4të­¼K_�I:5èÌ­¢…›?9ô CÝÝ ÿðMái‹;œ%Šÿ§ îJ¸©Ë_âr¹£EžÞñ×LN è¢MxÝ0Dß )X88_ü‡{ ˆ|ûk1EȱZŒ× (! :YΧ Ý_>5¨Â3¢•Á¢-¬¿þ戃¡OÑhÿ�â= ±æŠ²éŒt½Û¬ÆoBžm"¶ê¢�Ag†Psëáÿ÷Š÷Â1D§ýíX.äù�!Ô\QÊq´h0žªy:±VÈó¾åþô8¶ y ºÞÖÃ$��«Å¶…>D§ý ¼)äP«%Œ$ðª¸xd™ëDväÙÉÉ–y2øI¸ÓçA µ¬‡ÿ÷»›$0Èb ^5(Zí?–l!Ïh2ƒ¬·¢”£-Ë„.6ÛÆ Ý@a½ÀÖsÝ#Â�&‘D­�|ýKIˆÈ* Zí—=4æp\Pµ®t¨K0{Îb›(ÀU…g»žm6÷Z*\Ë b�Æ`î2ê(Žâú2µ/ámî6Ö¬1¯5D«ý¹|FQÀÕ,Î ùô¤R €õ \]Ï×6ù¤'[H‰M.É-V¢k—4î³þ×±b¿+%¼c14âµ ´£×þ±Ì®žD×u®„è`ljt®Žc¦M¾<lU·u\YW¸¶Ëe0Î4s·qø0üÁnЈW]¯¢×þµâdÜ�þ.k¬(d1VØaærªmÎs¿u›8Ø2O" wû�45¶VûùÞbn-t+ ˆfû;²RÈ7Kc(¡r ;„®åÄऻx¤u¯ežv¢¸ñuõu.ú“ð…q ˆfûeC­b®qQ_E …O„ŽUdsXJ}f‹gf§—>žÞµŽëÚð‡p®¢Û~ù0p¢ÁAQÓ]ô<7ƒ†ò&ñ±Ø�ß7j�Ífá÷›9ÌamCþ`· p®à¾ýçˆZ‰ÎÚ/ëjæiÌ@%xd Î5Í/uÛ yEˆ"œÀÑÜØÏx‡Záþ¥íÏ* ºí?Ol½lS‚¦½¸#µ¶,Kqì§„±œ\F�8…yÁ0äJ¸ÉѽÂ7ü!\�h¶j3UÈ¿…#ƒ~ÿJ%ç!±K¾îâèôAã ÚÎ/<Å5\Ë#Œ`µñw³v+ìZÞáášìÛ3<äö—r‹èXä UR‚Aþ~¹s<Ýœ™Æ®í$9úþðg…ÝàD5(:íßC Ñiû*õ ÃMâ÷d¸Ë´—å{OCMÛ;dð¨¥Áoðgá>®²žá@C1òí/‹|м5¥Ri©ÃBWÊsm›ŸÆAwÿ¥twp‡N~w‹y($?ù�Åoêžô……‘oYº‰&Èó£tU©\,zú%ˆsåú¢› û´™ó•Ÿ@±Û—¦ln zÜ–‰õûÕ¡®}¤Û_–$ÞJ*á¶ Ÿ€RIÉíÒ‹¸2¨ÒZŠ¥Ùuÿ+]|»­¦€œ §€6üb9üÛÅPû÷Ñ[Ô?œ.Ú(Š�ãDw–ÿØÄ4Ó„Ï,¼ïI‹ßs]vë)àF×S@+1 R0Ã?:íßC1f`!—ùæ”JÉsb·¼;„«1˜uŽ:?:Öý+Ë‹òÝN-Æá�öïAv>Ò¥ðV©ÄÔ€‹,´Ø�àã>5Ö÷¥bfpCÐÃ5´°\²3ü£ÓþRª‹[—õt ©T¥Ñ�MBz6 %§qo0_ð–WÂF~â:…T~8¦€fŒ±¢“‚þÑi)WŠ*ÈÎMª*L9�óø(`¨äp“ÂRz�8ˆn´¦™$�Ï&–3“¿˜OnÈ¥à%£Àk;ƒyÍÆ¹FSÞ°pvþ+ƒ˜ÓíhÀh:\}�+mý) p�ðýøG0` �DªP•êdXFvO(«€&ŒŠØ×?ZíD#®ß‚r­ªTB† Ýgxºi¤ä‰@#Ѥ62Ã?²œ/x#²÷H¬(¢w™wãÊ{b0z ùÖRô×ÞëF¹ ‡pŒ»6®Z x†OÔ&{/®&÷S@ñü<>‡?t\«lQ£ ůCàû¸s,áFPŸ¯-‡ü,þKé&ènÖ @qÆÃ ˜´ w8�êñe…þp²  ´š¶^WK‰®†A®MT»ØÄÉF .ŸW Å)Ò9Î\Gž…£Ù.t ·ãÒ³LËUÀ 4ýÇ÷ð¯Â�B[~v`¼¬(@#æ h­këôØÀj#°•?-Œtâéà¯,‡‹¾œ_õºZJ¼�$Ƨñ3e4k¼nF¼¡@pøhJoΠG'ÿÙ,áo¦òKÙj±§â’@MÚÐ�žt¡QP®WW1–/ø�í^7%Ñ ÒhωœB2‚.ÃÏVV0‹¿ø‡…l¤ÐëFE‰jÑ‚.FZµ¥‚]ÌàF2¿ÒNŸ!£@èT§;§Ò›V!ºßÁJæ2“,` Û*èæ �:´¢‡pMBЕX;äw6{Ý øF'€pÑ€îœÌQ4ÙõD![XÉ\þeKÙ@vL C#™ê4¤=Ñ™ÖÔé4$‡?ùžŸ˜_ž‹çèNhÄœLO‡ÅÍ.¶±†ÅÌc‹YÇòâh]࣠5iDkÚÒ�4¤FˆÚÌã'¾çoÝï‡ �ÂO�9ŒãèE‹°Å*bYà ±„%¬g+;(ÄïucË‘HjP—¦´ -iL]²Â`'YÈ2~eSXëu+:DŠês0'ЋVaVÿ)f'[ØÄzV²œ¬b3ÛÈa—B")¤S�Z4 1 iLêQ‡Œ°ùà+f9¿1šßYG«Ÿ¸A'€Hs�èÅ‘t x (&Ÿíd³• ¬cØÌfrØÎv¶S@1EaØ+ûH$‰$RÉ ‹,jP›zÔ£.õ¨Euª“v·,c ãù�å*å�:D‡ šs8Gs0MB82tF1E�K.Û÷N¥ÿ•Gyì"�Š(¡˜J(Æ��„ÝI$…RI#�*d’EU2É$‹jT#�t2H#1‚Ö ¹,ä7~æ/VëÐ�,:D“DêÒ�C8œÎ4ô$ÞpÉn[¹"J(¡ÿî¿}øð‘$�H‰»¯ø¢ÚCJØÈl~g3ØàÁÓ©„èà)4à@zÒ�¶ÔU�uÀ–3�IüÉÒ˜³N¨Ðèà%é4¤Ý8˜v4 Š×Õñ€�¬f&ÓøƒylP!_ôÑ H£.m9�.´§5ã.â€{¶³š9üÅtæ±®Ò¨?Ç :ĉT§!íèBgZP�ªl*(d3˘ſÌd1)ðºBŠN±I*5hHKÚÑžÖ4¤zÅ(O[XÍ"f3›¬$'æÔ—*1:Ä:IT¥�iAsZÑ”zT'-æc‘ËFV³„ùÌe1kÉQÍýXD'€x"™, !�iLSsu¨JZLD¾-!o¯ºòR³”ulŽ+Û…J‰NñŠ�T²¨A]êR�ú4 .µ©I&i¤’á7ë§€|rÙÊ&6²–5¬bëØB6ùºÄ�t¨(øH!ƒ 2©N jP›ÚÔ¤Yd�I&¤îVç-ý;ÁòÝû)¡˜"Š)¦€BòÈ%—\²ÙÂ&6±‰mlaÙä²Sµõâ�*6>’HÙ�ª�J*i»ÿ¤ì� JõþÀOPB1…좀| vçsÙE!P ƒ]QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ”áÿ:W„VeV¹„%tEXtdate:create2024-01-16T00:48:30+00:00~iã˜%tEXtdate:modify2024-01-16T00:48:30+00:004[$IEND®B`‚epasveer-seer-97076f1/src/resources/icons/hicolor/64x64/000077500000000000000000000000001526321767600227325ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/icons/hicolor/64x64/seergdb.png000066400000000000000000000043241526321767600250560ustar00rootroot00000000000000‰PNG  IHDR@@`¹UgAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDª�#2 pHYs``ðkBÏtIMEè06KFî ÇIDAThÞíØypÕÕðÏËËš° V�¥HQ¤€‚È"XpQ¤2XAG mm-Œl*´ YZ•ulP�¡©�Ù·$$,"ŒÈAèÄÔ¼ò¥3í ߿޻g½çœß¹ç^®â*þ¯PC,^®ŠËŒ6R¬}ªšç¨�j˜h¿C—£**Bþ¾z"èNƒ£±4d¨š¯ÊÇ�@q¨;ù¥dE6k&ηΊEº"¤—êª{¥ÈòªFxW†Ø MUEò}…Ú:¬ŠV8¦’™†GÙ QÛ:³%Xæ9ÔÑG4êJDš¶hn³›q¯�+U âÐV„æ:Xà”»¼l˜Å®ÇVé²4–&Ñy_ɳÝ.ÇdØ.ÉR<⼟igˆ—V]¡)&¨e²l�ÔÁ½LÒDÀ_8î¼,=ÔPd½·(ò¦ÅÎ`Œñ™�8äA¥g«ífé/Ke1Ú{À@ݵ5Økr}bˆ4°Ít1¨¯ñåçýE7#hœ‰‚zXm»§ÔÿÏx»í±U[1ºèjŠ=ÞÕBª‡Õ@{ëM»\ªù“}†Š�ì æj“$M–Ö4¶Á:?ÑÍb;ôÝíðn)‡#D² òôô¬B�÷‚òå:Óì÷�M•ï>LöªÄH‹´çÖ7D¢Ü¤žq Ý–Ü�VÚ¦·_Èw§qhd¶•jGæ@;[üÓp•q—F„-™j®½z›b‡–h§5ú…ñ½… Ë4¹î’a‹é‰'›c›Î²eK2ÌÓjEj<±8c�¤˜áÒ"”O±B¶®öV¼r�¡z…+ždžEî—�Vò �Ô´—g¤IÖ¨.Ås¶ÙktyŒåÕæy1Z¬§å�âi§ÊáŠÕR_t‘®È—Η¢î—¢³— •ëKdû¥¥!<—D´¦ºÉô™qåP:{Ë>,÷¡Ír½âºžê®íuoŠ.Ùf9'O°åµ$ûƹڸÇD!ÉÆšä€ùö‰ò¥éd„¯mt®„딃ÎIp··�ÑY_#5°:4 e«;Á‹Ú(´Åo´uÈ®zªçÝâžQÅѺÚc¼Žž•a¢Ó¥¸×‹‘%à§ä:N¢´5Üd¿SÏ|‹BF–êÚ¡‹F¶X SP´æ–ù»:î‘obH·¬j�Qâ5•ùüc¹çK­Ä™i·›0Éz5µ0ÇoÕ×H®‘¤À˜KLE@œD e« l â4UIÐ{%9VŠö�~Fø›x?°Ü1óU•*Ép«uô²…R�µÙ²‰³Ž«,Ñ­õ¨ÜŠÈ0W-|l”@HÎ2�•‹(±Nˆ‘b£3jâ¤Ê¢œ³K‚ôR2çD9kƒcŠq´âÀÇj¡�–Ò%Xej)Zšª‹¹–ˆs·�>ÕU5ë<ƒV6›'±Ô³½iî¿Ë^Ð"¯‡¬¶´ÉbuÜ¢Ðh1ª©,Ád¹š¹ÞzKBN½J>ñ”Júè,Kr8†Úm®Ü`‚�U ¡·÷™íŒQà-£Œ±Ô^÷¹ÝVKÔ áδ[_�¬µ_ž¹ÂÙù+¶Ê6^ýåiV†£¹|n¬‡-²Öô i Í)çÌïm�&¨£�;u/û)–7–×娳ȰÒT³ÊpT÷ˆYï�(éZûÚt BšÌÐL?‰Ž:s±€—�8­uðŽ êèSîaÔÐnRÛ9û¬°Ta9<×Xn–·-ð•÷,·+ÜãèvKÈÑÐméyQ¾ $‰—¸ÜqÒ¾’;dœÇåDšÿ£¯þ%_ùLËt—í€Å†h(¾g’æ•ã°?ëo»‡J(5/5 UüBrõ,÷‚Yu1X|n§|ÇE©¢žFêûFŽ×|¤Èl×è§(Åá:0ÌÏÝZ<Íej«­†RÄá´ÃvøÔ:{‹[m³õ÷éå¾,â-ñ*Ü yɯ‘úâKB|�TÙÇ&]9ót”¯›Jæ(�çWÅeIzCõâUKèQž´1Ò ù¥0Ã_Åh¿þ~*ß ÅæWÙ(×5À zK×Ê5$Õá4ˆkÝn�Óª:í3›%¹ðtm€¡Ú˜!UJè•í¶ÂàRÓေ6IÃµÖØn¯·Uð’“n£œóx�NòÜv%ÌÇ[YòΕe´‡‹sÛÒ+dhg“Åųà÷éq>0ãJ8ë= ËmÁ-¬µÆVï•û4]UŽéW&ýäYe”&e^ÉZX[®ù4ƒ­°KÇŠ•‡Óˆnt¿.âm’cµ]¾(?Ó�òEñï(ÉêjíG:гÊ,k®Œß™ú¡îÚHqJ¾=ö9à˜Ή•¤º4™2ÕrÆfK­°ë{oWÄ� ¨¡�ë4×@•Å‹pÞ·N:*Ïl’±üJ8ð‚â%J+Ê9ß8é„Ó‘¼]ÅUüÏà_,”2y}F7˜%tEXtdate:create2024-01-16T00:48:30+00:00~iã˜%tEXtdate:modify2024-01-16T00:48:30+00:004[$IEND®B`‚epasveer-seer-97076f1/src/resources/mi-python/000077500000000000000000000000001526321767600213115ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/mi-python/MICatchpoint.py000066400000000000000000000041161526321767600242070ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT # # Python MI command to manage gdb's "catchpoint" command.. # # Gdb has most catchpoint MI commands, but are missing these: # # -catch-signal # -catch-fork # -catch-vfork # -catch-syscall # -catch-exec # class MICatchpoint(gdb.MICommand): """ Run the 'catchpoint' command. -catch-signal [signal... | ‘all’] The delivery of a signal. -catch-fork A call to fork. -catch-vfork A call to vfork. -catch-syscall [name | number | group:groupname | g:groupname] ... A call to or return from a system call, a.k.a. syscall. -catch-exec A call to exec. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Set-Catchpoints.html#Set-Catchpoints """ def __init__(self, name, mode): self._mode = mode super(MICatchpoint, self).__init__(name) def invoke(self, argv): if self._mode == "signal": gdb.execute ("catch signal " + " ".join(argv), to_string=True) return None elif self._mode == "fork": gdb.execute ("catch fork " + " ".join(argv), to_string=True) return None elif self._mode == "vfork": gdb.execute ("catch vfork " + " ".join(argv), to_string=True) return None elif self._mode == "syscall": gdb.execute ("catch syscall " + " ".join(argv), to_string=True) return None elif self._mode == "exec": gdb.execute ("catch exec " + " ".join(argv), to_string=True) return None else: raise gdb.GdbError("catchpoint: Invalid parameter: %s" % self._mode) MICatchpoint("-catch-signal", "signal") MICatchpoint("-catch-fork", "fork") MICatchpoint("-catch-vfork", "vfork") MICatchpoint("-catch-syscall", "syscall") MICatchpoint("-catch-exec", "exec") epasveer-seer-97076f1/src/resources/mi-python/MICheckpoint.py000066400000000000000000000061121526321767600242000ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT import re # # Python MI command to manage gdb's "checkpoint" command.. # # https://sourceware.org/gdb/current/onlinedocs/gdb.html/Checkpoint_002fRestart.html#Checkpoint_002fRestart # class MICheckpoint(gdb.MICommand): """ Run the 'checkpoint' command. -checkpoint-list List all checkpoints, including the id for each checkpoint. -checkpoint-create Create a checkpoint at the current debugging position. -checkpoint-select Select a checkpoint to make active as described by ID. -checkpoint-delete Delete a checkpoint described by ID. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Checkpoint_002fRestart.html#Checkpoint_002fRestart """ def __init__(self, name, mode): self._mode = mode super(MICheckpoint, self).__init__(name) def invoke(self, argv): if self._mode == "list": checkpointentries = [] result = gdb.execute ("info checkpoints " + " ".join(argv), to_string=True) lines = result.split("\n") for line in lines: if (line == ""): continue columns = re.search(r"^([ *])\ (\d+)\ (.*?)\,\ (.*?)\,\ (.*?)$", line) if columns: checkpointmeta = {} checkpointmeta["id"] = columns.group(2) checkpointmeta["state"] = columns.group(1) checkpointmeta["process"] = columns.group(3) checkpointmeta["file"] = re.sub("^file ", "", columns.group(4)) checkpointmeta["line"] = re.sub("^line ", "", columns.group(5)) checkpointentries.append(checkpointmeta) else: columns = re.search(r"^([ *])\ (\d+)\ (.*)$", line) if columns: checkpointmeta = {} checkpointmeta["id"] = columns.group(2) checkpointmeta["state"] = columns.group(1) checkpointmeta["process"] = columns.group(3) checkpointmeta["file"] = "" checkpointmeta["line"] = "" checkpointentries.append(checkpointmeta) return { "checkpoints": checkpointentries} elif self._mode == "create": gdb.execute ("checkpoint " + " ".join(argv), to_string=True) return None elif self._mode == "select": gdb.execute ("restart " + " ".join(argv), to_string=True) return None elif self._mode == "delete": gdb.execute ("delete checkpoint " + " ".join(argv), to_string=True) return None else: raise gdb.GdbError("checkpoints: Invalid parameter: %s" % self._mode) MICheckpoint("-checkpoint-list", "list") MICheckpoint("-checkpoint-create", "create") MICheckpoint("-checkpoint-select", "select") MICheckpoint("-checkpoint-delete", "delete") epasveer-seer-97076f1/src/resources/mi-python/MIEcho.py000066400000000000000000000015571526321767600227770ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT # # Gdb's own custon Python MI command. # # https://sourceware.org/gdb/current/onlinedocs/gdb.html/GDB_002fMI-Commands-In-Python.html#GDB_002fMI-Commands-In-Python # https://sourceware.org/gdb/current/onlinedocs/gdb.html/Basic-Python.html#Basic-Python # class MIEcho(gdb.MICommand): """Echo arguments passed to the command.""" def __init__(self, name, mode): self._mode = mode super(MIEcho, self).__init__(name) def invoke(self, argv): if self._mode == 'dict': return { 'dict': { 'argv' : argv } } elif self._mode == 'list': return { 'list': argv } else: return { 'string': ", ".join(argv) } MIEcho("-echo-dict", "dict") MIEcho("-echo-list", "list") MIEcho("-echo-string", "string") epasveer-seer-97076f1/src/resources/mi-python/MIFrames.py000066400000000000000000000225541526321767600233360ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT import gdb # # Python MI command to add a -frames commands. # class MIFrames(gdb.MICommand): """ Add a command to list all frames for all threads. Usage: -frames-list [OPTIONS] Options: --max-frames N Maximum frames per thread --thread-id ID Only show specific thread --include-args Include function arguments --include-locals Include local variables --simple-values Only simple types --no-values Don't include variable values --frame-filter PATTERN Only frames matching pattern """ def __init__(self, name, mode): self._mode = mode super(MIFrames, self).__init__(name); def invoke(self, argv): if self._mode == "list": # Parse options options = { 'max_frames': None, 'thread_id': None, 'include_args': False, 'include_locals': False, 'simple_values': False, 'no_values': False, 'frame_filter': None } i = 0 while i < len(argv): if argv[i] == "--max-frames" and i + 1 < len(argv): options['max_frames'] = int(argv[i + 1]) i += 2 elif argv[i] == "--thread-id" and i + 1 < len(argv): options['thread_id'] = int(argv[i + 1]) i += 2 elif argv[i] == "--include-args": options['include_args'] = True i += 1 elif argv[i] == "--include-locals": options['include_locals'] = True i += 1 elif argv[i] == "--simple-values": options['simple_values'] = True i += 1 elif argv[i] == "--no-values": options['no_values'] = True i += 1 elif argv[i] == "--frame-filter" and i + 1 < len(argv): options['frame_filter'] = argv[i + 1] i += 2 else: raise gdb.GdbError(f"Unknown option: {argv[i]}") # Save current thread and frame current_thread = gdb.selected_thread() current_frame_level = gdb.selected_frame().level() if current_thread else None try: result = { 'frames': [], 'current_thread_id': current_thread.num if current_thread else None, 'current_frame_level': current_frame_level, 'total_threads': 0, 'total_frames': 0 } # Get all threads all_threads = gdb.selected_inferior().threads() # Filter by thread ID if specified if options['thread_id']: all_threads = [t for t in all_threads if t.num == options['thread_id']] if not all_threads: raise gdb.GdbError(f"Thread {options['thread_id']} not found") for thread in all_threads: thread_data = self._process_thread(thread, current_thread, options) if thread_data['frames']: # Only include if we got frames result['frames'].append(thread_data) result['total_frames'] += len(thread_data['frames']) result['total_threads'] = len(result['frames']) return result finally: # Restore original thread and frame if current_thread: current_thread.switch() if current_frame_level is not None: try: frame = gdb.newest_frame() for _ in range(current_frame_level): frame = frame.older() frame.select() except: pass else: raise gdb.GdbError("frames: Invalid parameter: %s" % self._mode) def _process_thread(self, thread, current_thread, options): """Process a single thread.""" thread_data = { 'thread-id': thread.num, 'target-id': str(thread.ptid), 'name': thread.name or '', 'state': 'running' if thread.is_running() else 'stopped', 'current': thread == current_thread, 'frames': [] } if thread.is_running(): thread_data['state_detail'] = 'Thread is running, no frames available' return thread_data try: # Switch to thread thread.switch() # Walk the stack frame = gdb.newest_frame() frame_count = 0 while frame is not None: # Check max frames limit if options['max_frames'] and frame_count >= options['max_frames']: thread_data['frames_truncated'] = True break # Get frame info frame_info = self._extract_frame_info(frame, options) # Apply frame filter if options['frame_filter']: func_name = frame_info.get('func', '') if options['frame_filter'] not in func_name: frame = frame.older() continue thread_data['frames'].append(frame_info) frame = frame.older() frame_count += 1 except Exception as e: thread_data['error'] = str(e) return thread_data def _extract_frame_info(self, frame, options): """Extract detailed frame information.""" info = { 'level': frame.level(), 'addr': hex(frame.pc()), 'func': frame.name() or '??', } # Architecture info try: info['arch'] = frame.architecture().name() except: pass # Source location try: sal = frame.find_sal() if sal.symtab: info['file'] = sal.symtab.filename info['fullname'] = sal.symtab.fullname() info['line'] = sal.line else: info['from'] = gdb.solib_name(frame.pc()) or 'unknown' except: pass # Frame type try: frame_type = frame.type() type_names = { gdb.NORMAL_FRAME: 'normal', gdb.DUMMY_FRAME: 'dummy', gdb.INLINE_FRAME: 'inline', gdb.TAILCALL_FRAME: 'tailcall', gdb.SIGTRAMP_FRAME: 'sigtramp', gdb.ARCH_FRAME: 'arch', gdb.SENTINEL_FRAME: 'sentinel' } info['type'] = type_names.get(frame_type, 'unknown') except: pass # Variables if options['include_args'] or options['include_locals']: try: block = frame.block() if block: if options['include_args']: info['args'] = self._get_block_variables( block, frame, True, options ) if options['include_locals']: info['locals'] = self._get_block_variables( block, frame, False, options ) except: pass return info def _get_block_variables(self, block, frame, get_args, options): """Get variables from a block.""" variables = [] while block: for symbol in block: if get_args and not symbol.is_argument: continue if not get_args and (symbol.is_argument or not symbol.is_variable): continue var_info = {'name': symbol.name} try: value = symbol.value(frame) var_type = value.type # Type filtering if options['simple_values'] and not self._is_simple_type(var_type): continue var_info['type'] = str(var_type) # Value if not options['no_values']: try: var_info['value'] = str(value) # Add address for pointers if var_type.code == gdb.TYPE_CODE_PTR: var_info['address'] = hex(int(value)) except: var_info['value'] = '' except Exception as e: var_info['error'] = str(e) variables.append(var_info) if block.function: break block = block.superblock return variables def _is_simple_type(self, gdb_type): """Check if type is scalar.""" return gdb_type.code in [ gdb.TYPE_CODE_INT, gdb.TYPE_CODE_FLT, gdb.TYPE_CODE_BOOL, gdb.TYPE_CODE_CHAR, gdb.TYPE_CODE_ENUM, gdb.TYPE_CODE_PTR ] # Register MIFrames("-frames-list", "list") epasveer-seer-97076f1/src/resources/mi-python/MIKill.py000066400000000000000000000025671526321767600230160ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT import re # # Python MI command to support gdb's "kill" commands. # # https://sourceware.org/bugzilla/show_bug.cgi?id=31090 # https://stackoverflow.com/questions/9669025/gdb-exit-program-without-exiting-gdb class MIKill(gdb.MICommand): """ Run the 'kill' command. -exec-kill Kill the child process in which your program is running under GDB. -exec-kill-inferiors Kill the inferior or inferiors identified by GDB inferior number(s) infno. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Kill-Process.html https://sourceware.org/gdb/current/onlinedocs/gdb.html/Inferiors-Connections-and-Programs.html#Inferiors-Connections-and-Programs """ def __init__(self, name, mode): self._mode = mode super(MIKill, self).__init__(name) def invoke(self, argv): if self._mode == "kill": gdb.execute ("kill" + " ".join(argv), to_string=True) return None elif self._mode == "killinferiors": gdb.execute ("kill inferiors" + " ".join(argv), to_string=True) return None else: raise gdb.GdbError("kill: Invalid parameter: %s" % self._mode) MIKill("-exec-kill", "kill") MIKill("-exec-kill-inferiors", "killinferiors") epasveer-seer-97076f1/src/resources/mi-python/MIMonitor.py000066400000000000000000000016041526321767600235410ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2026 Ernie Pasveer # # SPDX-License-Identifier: MIT # # Python MI command to support gdb's "monitor" command. # class MIMonitor(gdb.MICommand): """ Send a command to gdb's monitor. -monitor-exec Run a command in gdb's monitor. Return the resulting text, if any. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Server.html """ def __init__(self, name, mode): self._mode = mode super(MIMonitor, self).__init__(name) def invoke(self, argv): if self._mode == "monitor-exec": result = gdb.execute ("monitor " + " ".join(argv), to_string=True) return {"monitor-output": result} else: raise gdb.GdbError("monitor: Invalid parameter: %s" % self._mode) MIMonitor("-monitor-exec", "monitor-exec") epasveer-seer-97076f1/src/resources/mi-python/MIObjectiveC.py000066400000000000000000000020401526321767600241220ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT import re # # Python MI command to manage gdb's Objective-C commands. # # https://sourceware.org/gdb/current/onlinedocs/gdb.html/Objective_002dC.html#Objective_002dC # class MIObjectiveC(gdb.MICommand): """ Run the ObjectiveC command. -objc-evaluate-expression Evaluate an Objective-C object via 'print-object' and '_NSPrintForDebugger'. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Objective_002dC.html#Objective_002dC """ def __init__(self, name, mode): self._mode = mode super(MIObjectiveC, self).__init__(name) def invoke(self, argv): if self._mode == "evaluate-expression": result = gdb.execute ("print-object " + " ".join(argv), to_string=True) return { "value": result.rstrip('\n')} else: raise gdb.GdbError("objectivec: Invalid parameter: %s" % self._mode) MIObjectiveC("-objc-evaluate-expression", "evaluate-expression") epasveer-seer-97076f1/src/resources/mi-python/MISignals.py000066400000000000000000000112111526321767600235050ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT import re # # Python MI command to manage gdb's "signal" command. # # https://www.sourceware.org/gdb/current/onlinedocs/gdb.html/Signals.html # class MISignal(gdb.MICommand): """ Run the 'signal' command. -signal-list-values List all signals, including the attributes for each signal (name, stop, print, pass, description). (gdb) info signals Signal Stop Print Pass to program Description SIGHUP Yes Yes Yes Hangup SIGINT Yes Yes No Interrupt SIGQUIT Yes Yes Yes Quit ... EXC_BREAKPOINT Yes Yes Yes Breakpoint SIGLIBRT No No Yes librt internal signal Use the "handle" command to change these tables. """ def __init__(self, name, mode): self._mode = mode super(MISignal, self).__init__(name) def invoke(self, argv): if self._mode == "list-names": signalnames = [] result = gdb.execute ("info signals", to_string=True) lines = result.split("\n") for line in lines: if (line == ""): continue columns = re.search(r"^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)$", line) if columns: if (columns.group(1) == "Signal"): continue if (columns.group(1) == "Use"): continue signalnames.append(columns.group(1)) return { "signal-names": signalnames} elif self._mode == "list-values": command = "" result = "" signalentries = [] if (len(argv) == 0): command = "info signals" else: command = "handle " + " ".join(argv) result = gdb.execute (command, from_tty=True, to_string=True) lines = result.split("\n") for line in lines: if (line == ""): continue columns = re.search(r"^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)$", line) if columns: if (columns.group(1) == "Signal"): continue if (columns.group(1) == "Use"): continue signalmeta = {} signalmeta["name"] = columns.group(1) signalmeta["stop"] = columns.group(2) signalmeta["print"] = columns.group(3) signalmeta["pass"] = columns.group(4) signalmeta["description"] = columns.group(5) signalentries.append(signalmeta) return { "signal-values": signalentries} elif self._mode == "stop": # handle signal [ signal … ] stop gdb.execute ("handle " + " ".join(argv) + " stop", from_tty=True, to_string=True) return None elif self._mode == "nostop": # handle signal [ signal … ] nostop gdb.execute ("handle " + " ".join(argv) + " nostop", from_tty=True, to_string=True) return None elif self._mode == "print": gdb.execute ("handle " + " ".join(argv) + " print", from_tty=True, to_string=True) return None elif self._mode == "noprint": gdb.execute ("handle " + " ".join(argv) + " noprint", from_tty=True, to_string=True) return None elif self._mode == "pass": gdb.execute ("handle " + " ".join(argv) + " pass", from_tty=True, to_string=True) return None elif self._mode == "nopass": gdb.execute ("handle " + " ".join(argv) + " nopass", from_tty=True, to_string=True) return None elif self._mode == "set-value": # handle signal [ signal … ] [keywords…] gdb.execute ("handle " + " ".join(argv), from_tty=True, to_string=True) return None else: raise gdb.GdbError("signal: Invalid parameter: %s" % self._mode) MISignal("-signal-list-names", "list-names") MISignal("-signal-list-values", "list-values") MISignal("-signal-stop", "stop") MISignal("-signal-nostop", "nostop") MISignal("-signal-print", "print") MISignal("-signal-noprint", "noprint") MISignal("-signal-pass", "pass") MISignal("-signal-nopass", "nopass") MISignal("-signal-set-value", "set-value") epasveer-seer-97076f1/src/resources/mi-python/MISkip.py000066400000000000000000000077701526321767600230320ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2025 Ernie Pasveer # # SPDX-License-Identifier: MIT import re # # Python MI command to manage gdb's "skip" command.. # # https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html # class MISkip(gdb.MICommand): """ Run the 'skip' command. -skip-list List all skips, including the id for each skip. -skip-delete Delete a list of skip id's. -skip-enable Enable a list of skip id's. -skip-disable Disable a list of skip id's. -skip-create Functions described in manual syntax will be skipped over when stepping. -skip-create-file Functions in file will be skipped over when stepping. -skip-create-gfile Functions in files matching file-glob-pattern will be skipped over when stepping. -skip-create-function Functions named by linespec or the function containing the line named by linespec will be skipped over when stepping. -skip-create-rfunction Functions whose name matches regexp will be skipped over when stepping. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Skipping-Over-Functions-and-Files.html """ def __init__(self, name, mode): self._mode = mode super(MISkip, self).__init__(name) def invoke(self, argv): if self._mode == "list": skipentries = [] result = gdb.execute ("info skip " + " ".join(argv), to_string=True) lines = result.split("\n") for line in lines: if (line == ""): continue columns = re.search(r"^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)$", line) if columns: if (columns.group(1) == "Num"): continue if (columns.group(1) == "Not"): continue skipmeta = {} skipmeta["number"] = columns.group(1) skipmeta["enable"] = columns.group(2) skipmeta["glob"] = columns.group(3) skipmeta["file"] = columns.group(4) skipmeta["re"] = columns.group(5) skipmeta["function"] = columns.group(6) skipentries.append(skipmeta) return { "skips": skipentries} elif self._mode == "delete": gdb.execute ("skip delete " + " ".join(argv), to_string=True) return None elif self._mode == "enable": gdb.execute ("skip enable " + " ".join(argv), to_string=True) return None elif self._mode == "disable": gdb.execute ("skip disable " + " ".join(argv), to_string=True) return None elif self._mode == "create": gdb.execute ("skip \"" + " ".join(argv) + "\"", to_string=True) return None elif self._mode == "createfile": gdb.execute ("skip -file \"" + " ".join(argv) + "\"", to_string=True) return None elif self._mode == "creategfile": gdb.execute ("skip -gfile \"" + " ".join(argv) + "\"", to_string=True) return None elif self._mode == "createfunction": gdb.execute ("skip -function \"" + " ".join(argv) + "\"", to_string=True) return None elif self._mode == "createrfunction": gdb.execute ("skip -rfunction \"" + " ".join(argv) + "\"", to_string=True) return None else: raise gdb.GdbError("skips: Invalid parameter: %s" % self._mode) MISkip("-skip-list", "list") MISkip("-skip-delete", "delete") MISkip("-skip-enable", "enable") MISkip("-skip-disable", "disable") MISkip("-skip-create", "create") MISkip("-skip-create-file", "createfile") MISkip("-skip-create-gfile", "creategfile") MISkip("-skip-create-function", "createfunction") MISkip("-skip-create-rfunction", "createrfunction") epasveer-seer-97076f1/src/resources/mi-python/MIStart.py000066400000000000000000000021011526321767600232000ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2026 Ernie Pasveer # # SPDX-License-Identifier: MIT import re # # Python MI command to support gdb's "start" commands. # class MIStart(gdb.MICommand): """ Run the 'start' or 'starti' command. -exec-start Start the program, break in main. See gdb's 'start' command. -exec-starti Start the program, break at first instruction. See gdb's 'starti' command. See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Starting.html """ def __init__(self, name, mode): self._mode = mode super(MIStart, self).__init__(name) def invoke(self, argv): if self._mode == "start": gdb.execute ("start" + " ".join(argv), to_string=True) return None elif self._mode == "starti": gdb.execute ("starti" + " ".join(argv), to_string=True) return None else: raise gdb.GdbError("start: Invalid parameter: %s" % self._mode) MIStart("-exec-start", "start") MIStart("-exec-starti", "starti") epasveer-seer-97076f1/src/resources/qdarkstyle/000077500000000000000000000000001526321767600215505ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/qdarkstyle/ABOUT.md000066400000000000000000000015121526321767600227430ustar00rootroot00000000000000 Seer uses the QDarkStyle style sheets to provide a "dark" theme. Inversely, Seer uses the "light" theme as well. The QDarkStyle project is here: https://github.com/ColinDuquesnoy/QDarkStyleSheet And its license is here: QDarkStyleSheet is released under the MIT license and its icons are released under the CC4.0 license. https://github.com/ColinDuquesnoy/QDarkStyleSheet/blob/master/LICENSE.rst Copyright (c) 2013-2019 Colin Duquesnoy QComboBox menus, with this style, look weird. There's a large "space" to the left of the menu text. It isn't resolved in the official QDarkStyleSheet project. This link shows a fix for the QComboBox entry in the "dark" and "light" css files. So I've applied it to my copy of the stylesheet. https://github.com/ColinDuquesnoy/QDarkStyleSheet/issues/308#issuecomment-1661775924 epasveer-seer-97076f1/src/resources/qdarkstyle/dark/000077500000000000000000000000001526321767600224715ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/qdarkstyle/dark/darkstyle.qrc000066400000000000000000000233541526321767600252110ustar00rootroot00000000000000 rc/arrow_down.png rc/arrow_down@2x.png rc/arrow_down_disabled.png rc/arrow_down_disabled@2x.png rc/arrow_down_focus.png rc/arrow_down_focus@2x.png rc/arrow_down_pressed.png rc/arrow_down_pressed@2x.png rc/arrow_left.png rc/arrow_left@2x.png rc/arrow_left_disabled.png rc/arrow_left_disabled@2x.png rc/arrow_left_focus.png rc/arrow_left_focus@2x.png rc/arrow_left_pressed.png rc/arrow_left_pressed@2x.png rc/arrow_right.png rc/arrow_right@2x.png rc/arrow_right_disabled.png rc/arrow_right_disabled@2x.png rc/arrow_right_focus.png rc/arrow_right_focus@2x.png rc/arrow_right_pressed.png rc/arrow_right_pressed@2x.png rc/arrow_up.png rc/arrow_up@2x.png rc/arrow_up_disabled.png rc/arrow_up_disabled@2x.png rc/arrow_up_focus.png rc/arrow_up_focus@2x.png rc/arrow_up_pressed.png rc/arrow_up_pressed@2x.png rc/base_icon.png rc/base_icon@2x.png rc/base_icon_disabled.png rc/base_icon_disabled@2x.png rc/base_icon_focus.png rc/base_icon_focus@2x.png rc/base_icon_pressed.png rc/base_icon_pressed@2x.png rc/branch_closed.png rc/branch_closed@2x.png rc/branch_closed_disabled.png rc/branch_closed_disabled@2x.png rc/branch_closed_focus.png rc/branch_closed_focus@2x.png rc/branch_closed_pressed.png rc/branch_closed_pressed@2x.png rc/branch_end.png rc/branch_end@2x.png rc/branch_end_disabled.png rc/branch_end_disabled@2x.png rc/branch_end_focus.png rc/branch_end_focus@2x.png rc/branch_end_pressed.png rc/branch_end_pressed@2x.png rc/branch_line.png rc/branch_line@2x.png rc/branch_line_disabled.png rc/branch_line_disabled@2x.png rc/branch_line_focus.png rc/branch_line_focus@2x.png rc/branch_line_pressed.png rc/branch_line_pressed@2x.png rc/branch_more.png rc/branch_more@2x.png rc/branch_more_disabled.png rc/branch_more_disabled@2x.png rc/branch_more_focus.png rc/branch_more_focus@2x.png rc/branch_more_pressed.png rc/branch_more_pressed@2x.png rc/branch_open.png rc/branch_open@2x.png rc/branch_open_disabled.png rc/branch_open_disabled@2x.png rc/branch_open_focus.png rc/branch_open_focus@2x.png rc/branch_open_pressed.png rc/branch_open_pressed@2x.png rc/checkbox_checked.png rc/checkbox_checked@2x.png rc/checkbox_checked_disabled.png rc/checkbox_checked_disabled@2x.png rc/checkbox_checked_focus.png rc/checkbox_checked_focus@2x.png rc/checkbox_checked_pressed.png rc/checkbox_checked_pressed@2x.png rc/checkbox_indeterminate.png rc/checkbox_indeterminate@2x.png rc/checkbox_indeterminate_disabled.png rc/checkbox_indeterminate_disabled@2x.png rc/checkbox_indeterminate_focus.png rc/checkbox_indeterminate_focus@2x.png rc/checkbox_indeterminate_pressed.png rc/checkbox_indeterminate_pressed@2x.png rc/checkbox_unchecked.png rc/checkbox_unchecked@2x.png rc/checkbox_unchecked_disabled.png rc/checkbox_unchecked_disabled@2x.png rc/checkbox_unchecked_focus.png rc/checkbox_unchecked_focus@2x.png rc/checkbox_unchecked_pressed.png rc/checkbox_unchecked_pressed@2x.png rc/line_horizontal.png rc/line_horizontal@2x.png rc/line_horizontal_disabled.png rc/line_horizontal_disabled@2x.png rc/line_horizontal_focus.png rc/line_horizontal_focus@2x.png rc/line_horizontal_pressed.png rc/line_horizontal_pressed@2x.png rc/line_vertical.png rc/line_vertical@2x.png rc/line_vertical_disabled.png rc/line_vertical_disabled@2x.png rc/line_vertical_focus.png rc/line_vertical_focus@2x.png rc/line_vertical_pressed.png rc/line_vertical_pressed@2x.png rc/radio_checked.png rc/radio_checked@2x.png rc/radio_checked_disabled.png rc/radio_checked_disabled@2x.png rc/radio_checked_focus.png rc/radio_checked_focus@2x.png rc/radio_checked_pressed.png rc/radio_checked_pressed@2x.png rc/radio_unchecked.png rc/radio_unchecked@2x.png rc/radio_unchecked_disabled.png rc/radio_unchecked_disabled@2x.png rc/radio_unchecked_focus.png rc/radio_unchecked_focus@2x.png rc/radio_unchecked_pressed.png rc/radio_unchecked_pressed@2x.png rc/toolbar_move_horizontal.png rc/toolbar_move_horizontal@2x.png rc/toolbar_move_horizontal_disabled.png rc/toolbar_move_horizontal_disabled@2x.png rc/toolbar_move_horizontal_focus.png rc/toolbar_move_horizontal_focus@2x.png rc/toolbar_move_horizontal_pressed.png rc/toolbar_move_horizontal_pressed@2x.png rc/toolbar_move_vertical.png rc/toolbar_move_vertical@2x.png rc/toolbar_move_vertical_disabled.png rc/toolbar_move_vertical_disabled@2x.png rc/toolbar_move_vertical_focus.png rc/toolbar_move_vertical_focus@2x.png rc/toolbar_move_vertical_pressed.png rc/toolbar_move_vertical_pressed@2x.png rc/toolbar_separator_horizontal.png rc/toolbar_separator_horizontal@2x.png rc/toolbar_separator_horizontal_disabled.png rc/toolbar_separator_horizontal_disabled@2x.png rc/toolbar_separator_horizontal_focus.png rc/toolbar_separator_horizontal_focus@2x.png rc/toolbar_separator_horizontal_pressed.png rc/toolbar_separator_horizontal_pressed@2x.png rc/toolbar_separator_vertical.png rc/toolbar_separator_vertical@2x.png rc/toolbar_separator_vertical_disabled.png rc/toolbar_separator_vertical_disabled@2x.png rc/toolbar_separator_vertical_focus.png rc/toolbar_separator_vertical_focus@2x.png rc/toolbar_separator_vertical_pressed.png rc/toolbar_separator_vertical_pressed@2x.png rc/transparent.png rc/transparent@2x.png rc/transparent_disabled.png rc/transparent_disabled@2x.png rc/transparent_focus.png rc/transparent_focus@2x.png rc/transparent_pressed.png rc/transparent_pressed@2x.png rc/window_close.png rc/window_close@2x.png rc/window_close_disabled.png rc/window_close_disabled@2x.png rc/window_close_focus.png rc/window_close_focus@2x.png rc/window_close_pressed.png rc/window_close_pressed@2x.png rc/window_grip.png rc/window_grip@2x.png rc/window_grip_disabled.png rc/window_grip_disabled@2x.png rc/window_grip_focus.png rc/window_grip_focus@2x.png rc/window_grip_pressed.png rc/window_grip_pressed@2x.png rc/window_minimize.png rc/window_minimize@2x.png rc/window_minimize_disabled.png rc/window_minimize_disabled@2x.png rc/window_minimize_focus.png rc/window_minimize_focus@2x.png rc/window_minimize_pressed.png rc/window_minimize_pressed@2x.png rc/window_undock.png rc/window_undock@2x.png rc/window_undock_disabled.png rc/window_undock_disabled@2x.png rc/window_undock_focus.png rc/window_undock_focus@2x.png rc/window_undock_pressed.png rc/window_undock_pressed@2x.png darkstyle.qss epasveer-seer-97076f1/src/resources/qdarkstyle/dark/darkstyle.qss000066400000000000000000001512611526321767600252310ustar00rootroot00000000000000/* --------------------------------------------------------------------------- WARNING! File created programmatically. All changes made in this file will be lost! Created by the qtsass compiler v0.4.0 The definitions are in the "qdarkstyle.qss._styles.scss" module --------------------------------------------------------------------------- */ /* Light Style - QDarkStyleSheet ------------------------------------------ */ /* See Qt documentation: - https://doc.qt.io/qt-5/stylesheet.html - https://doc.qt.io/qt-5/stylesheet-reference.html - https://doc.qt.io/qt-5/stylesheet-examples.html --------------------------------------------------------------------------- */ /* Reset elements ------------------------------------------------------------ Resetting everything helps to unify styles across different operating systems --------------------------------------------------------------------------- */ * { padding: 0px; margin: 0px; border: 0px; border-style: none; border-image: none; outline: 0; } /* specific reset for elements inside QToolBar */ QToolBar * { margin: 0px; padding: 0px; } /* QWidget ---------------------------------------------------------------- --------------------------------------------------------------------------- */ QWidget { background-color: #19232D; border: 0px solid #455364; padding: 0px; color: #DFE1E2; selection-background-color: #346792; selection-color: #DFE1E2; } QWidget:disabled { background-color: #19232D; color: #788D9C; selection-background-color: #26486B; selection-color: #788D9C; } QWidget::item:selected { background-color: #346792; } QWidget::item:hover:!selected { background-color: #1A72BB; } /* QMainWindow ------------------------------------------------------------ This adjusts the splitter in the dock widget, not qsplitter https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow --------------------------------------------------------------------------- */ QMainWindow::separator { background-color: #455364; border: 0px solid #19232D; spacing: 0px; padding: 2px; } QMainWindow::separator:hover { background-color: #60798B; border: 0px solid #1A72BB; } QMainWindow::separator:horizontal { width: 5px; margin-top: 2px; margin-bottom: 2px; image: url(":/qss_icons/dark/rc/toolbar_separator_vertical.png"); } QMainWindow::separator:vertical { height: 5px; margin-left: 2px; margin-right: 2px; image: url(":/qss_icons/dark/rc/toolbar_separator_horizontal.png"); } /* QToolTip --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip --------------------------------------------------------------------------- */ QToolTip { background-color: #346792; color: #DFE1E2; /* If you remove the border property, background stops working on Windows */ border: none; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Remove opacity, fix #174 - may need to use RGBA */ } /* QStatusBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar --------------------------------------------------------------------------- */ QStatusBar { border: 1px solid #455364; /* Fixes Spyder #9120, #9121 */ background: #455364; /* Fixes #205, white vertical borders separating items */ } QStatusBar::item { border: none; } QStatusBar QToolTip { background-color: #1A72BB; border: 1px solid #19232D; color: #19232D; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Reducing transparency to read better */ opacity: 230; } QStatusBar QLabel { /* Fixes Spyder #9120, #9121 */ background: transparent; } /* QCheckBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox --------------------------------------------------------------------------- */ QCheckBox { background-color: #19232D; color: #DFE1E2; spacing: 4px; outline: none; padding-top: 4px; padding-bottom: 4px; } QCheckBox:focus { border: none; } QCheckBox QWidget:disabled { background-color: #19232D; color: #788D9C; } QCheckBox::indicator { margin-left: 2px; height: 14px; width: 14px; } QCheckBox::indicator:unchecked { image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QCheckBox::indicator:unchecked:disabled { image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); } QCheckBox::indicator:checked { image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QCheckBox::indicator:checked:disabled { image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); } QCheckBox::indicator:indeterminate { image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); } QCheckBox::indicator:indeterminate:disabled { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_disabled.png"); } QCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); } /* QGroupBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox --------------------------------------------------------------------------- */ QGroupBox { font-weight: bold; border: 1px solid #455364; border-radius: 4px; padding: 2px; margin-top: 6px; margin-bottom: 4px; } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; left: 4px; padding-left: 2px; padding-right: 4px; padding-top: -4px; } QGroupBox::indicator { margin-left: 2px; margin-top: 2px; padding: 0; height: 14px; width: 14px; } QGroupBox::indicator:unchecked { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QGroupBox::indicator:unchecked:disabled { image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); } QGroupBox::indicator:checked { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QGroupBox::indicator:checked:disabled { image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); } /* QRadioButton ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton --------------------------------------------------------------------------- */ QRadioButton { background-color: #19232D; color: #DFE1E2; spacing: 4px; padding-top: 4px; padding-bottom: 4px; border: none; outline: none; } QRadioButton:focus { border: none; } QRadioButton:disabled { background-color: #19232D; color: #788D9C; border: none; outline: none; } QRadioButton QWidget { background-color: #19232D; color: #DFE1E2; spacing: 0px; padding: 0px; outline: none; border: none; } QRadioButton::indicator { border: none; outline: none; margin-left: 2px; height: 14px; width: 14px; } QRadioButton::indicator:unchecked { image: url(":/qss_icons/dark/rc/radio_unchecked.png"); } QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_unchecked_focus.png"); } QRadioButton::indicator:unchecked:disabled { image: url(":/qss_icons/dark/rc/radio_unchecked_disabled.png"); } QRadioButton::indicator:checked { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked.png"); } QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked_focus.png"); } QRadioButton::indicator:checked:disabled { outline: none; image: url(":/qss_icons/dark/rc/radio_checked_disabled.png"); } /* QMenuBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar --------------------------------------------------------------------------- */ QMenuBar { background-color: #455364; padding: 2px; border: 1px solid #19232D; color: #DFE1E2; selection-background-color: #1A72BB; } QMenuBar:focus { border: 1px solid #346792; } QMenuBar::item { background: transparent; padding: 4px; } QMenuBar::item:selected { padding: 4px; background: transparent; border: 0px solid #455364; background-color: #1A72BB; } QMenuBar::item:pressed { padding: 4px; border: 0px solid #455364; background-color: #1A72BB; color: #DFE1E2; margin-bottom: 0px; padding-bottom: 0px; } /* QMenu ------------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu --------------------------------------------------------------------------- */ QMenu { border: 0px solid #455364; color: #DFE1E2; margin: 0px; background-color: #37414F; selection-background-color: #1A72BB; } QMenu::separator { height: 1px; background-color: #60798B; color: #DFE1E2; } QMenu::item { background-color: #37414F; padding: 4px 24px 4px 28px; /* Reserve space for selection border */ border: 1px transparent #455364; } QMenu::item:selected { color: #DFE1E2; background-color: #1A72BB; } QMenu::item:pressed { background-color: #1A72BB; } QMenu::icon { padding-left: 10px; width: 14px; height: 14px; } QMenu::indicator { padding-left: 8px; width: 12px; height: 12px; /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ } QMenu::indicator:non-exclusive:unchecked { image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QMenu::indicator:non-exclusive:unchecked:hover, QMenu::indicator:non-exclusive:unchecked:focus, QMenu::indicator:non-exclusive:unchecked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QMenu::indicator:non-exclusive:unchecked:disabled { image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); } QMenu::indicator:non-exclusive:checked { image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QMenu::indicator:non-exclusive:checked:hover, QMenu::indicator:non-exclusive:checked:focus, QMenu::indicator:non-exclusive:checked:pressed { border: none; image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QMenu::indicator:non-exclusive:checked:disabled { image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate { image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); } QMenu::indicator:non-exclusive:indeterminate:disabled { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate:focus, QMenu::indicator:non-exclusive:indeterminate:hover, QMenu::indicator:non-exclusive:indeterminate:pressed { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); } QMenu::indicator:exclusive:unchecked { image: url(":/qss_icons/dark/rc/radio_unchecked.png"); } QMenu::indicator:exclusive:unchecked:hover, QMenu::indicator:exclusive:unchecked:focus, QMenu::indicator:exclusive:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_unchecked_focus.png"); } QMenu::indicator:exclusive:unchecked:disabled { image: url(":/qss_icons/dark/rc/radio_unchecked_disabled.png"); } QMenu::indicator:exclusive:checked { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked.png"); } QMenu::indicator:exclusive:checked:hover, QMenu::indicator:exclusive:checked:focus, QMenu::indicator:exclusive:checked:pressed { border: none; outline: none; image: url(":/qss_icons/dark/rc/radio_checked_focus.png"); } QMenu::indicator:exclusive:checked:disabled { outline: none; image: url(":/qss_icons/dark/rc/radio_checked_disabled.png"); } QMenu::right-arrow { margin: 5px; padding-left: 12px; image: url(":/qss_icons/dark/rc/arrow_right.png"); height: 12px; width: 12px; } /* QAbstractItemView ------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QAbstractItemView { alternate-background-color: #19232D; color: #DFE1E2; border: 1px solid #455364; border-radius: 4px; } QAbstractItemView QLineEdit { padding: 2px; } /* QAbstractScrollArea ---------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QAbstractScrollArea { background-color: #19232D; border: 1px solid #455364; border-radius: 4px; /* fix #159 */ padding: 2px; /* remove min-height to fix #244 */ color: #DFE1E2; } QAbstractScrollArea:disabled { color: #788D9C; } /* QScrollArea ------------------------------------------------------------ --------------------------------------------------------------------------- */ QScrollArea QWidget QWidget:disabled { background-color: #19232D; } /* QScrollBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar --------------------------------------------------------------------------- */ QScrollBar:horizontal { height: 16px; margin: 2px 16px 2px 16px; border: 1px solid #455364; border-radius: 4px; background-color: #19232D; } QScrollBar:vertical { background-color: #19232D; width: 16px; margin: 16px 2px 16px 2px; border: 1px solid #455364; border-radius: 4px; } QScrollBar::handle:horizontal { background-color: #60798B; border: 1px solid #455364; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:hover { background-color: #346792; border: #346792; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:focus { border: 1px solid #1A72BB; } QScrollBar::handle:vertical { background-color: #60798B; border: 1px solid #455364; min-height: 8px; border-radius: 4px; } QScrollBar::handle:vertical:hover { background-color: #346792; border: #346792; border-radius: 4px; min-height: 8px; } QScrollBar::handle:vertical:focus { border: 1px solid #1A72BB; } QScrollBar::add-line:horizontal { margin: 0px 0px 0px 0px; border-image: url(":/qss_icons/dark/rc/arrow_right_disabled.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { border-image: url(":/qss_icons/dark/rc/arrow_right.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { border-image: url(":/qss_icons/dark/rc/arrow_down.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal { margin: 0px 3px 0px 3px; border-image: url(":/qss_icons/dark/rc/arrow_left_disabled.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { border-image: url(":/qss_icons/dark/rc/arrow_left.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/dark/rc/arrow_up_disabled.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { border-image: url(":/qss_icons/dark/rc/arrow_up.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { background: none; } QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { background: none; } QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; } /* QTextEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets --------------------------------------------------------------------------- */ QTextEdit { background-color: #19232D; color: #DFE1E2; border-radius: 4px; border: 1px solid #455364; } QTextEdit:focus { border: 1px solid #1A72BB; } QTextEdit:selected { background: #346792; color: #455364; } /* QPlainTextEdit --------------------------------------------------------- --------------------------------------------------------------------------- */ QPlainTextEdit { background-color: #19232D; color: #DFE1E2; border-radius: 4px; border: 1px solid #455364; } QPlainTextEdit:focus { border: 1px solid #1A72BB; } QPlainTextEdit:selected { background: #346792; color: #455364; } /* QSizeGrip -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip --------------------------------------------------------------------------- */ QSizeGrip { background: transparent; width: 12px; height: 12px; image: url(":/qss_icons/dark/rc/window_grip.png"); } /* QStackedWidget --------------------------------------------------------- --------------------------------------------------------------------------- */ QStackedWidget { padding: 2px; border: 1px solid #455364; border: 1px solid #19232D; } /* QToolBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar --------------------------------------------------------------------------- */ QToolBar { background-color: #455364; border-bottom: 1px solid #19232D; padding: 1px; font-weight: bold; spacing: 2px; } QToolBar:disabled { /* Fixes #272 */ background-color: #455364; } QToolBar::handle:horizontal { width: 16px; image: url(":/qss_icons/dark/rc/toolbar_move_horizontal.png"); } QToolBar::handle:vertical { height: 16px; image: url(":/qss_icons/dark/rc/toolbar_move_vertical.png"); } QToolBar::separator:horizontal { width: 16px; image: url(":/qss_icons/dark/rc/toolbar_separator_horizontal.png"); } QToolBar::separator:vertical { height: 16px; image: url(":/qss_icons/dark/rc/toolbar_separator_vertical.png"); } QToolButton#qt_toolbar_ext_button { background: #455364; border: 0px; color: #DFE1E2; image: url(":/qss_icons/dark/rc/arrow_right.png"); } /* QAbstractSpinBox ------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractSpinBox { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; border-radius: 4px; /* min-width: 5px; removed to fix 109 */ } QAbstractSpinBox:up-button { background-color: transparent #19232D; subcontrol-origin: border; subcontrol-position: top right; border-left: 1px solid #455364; border-bottom: 1px solid #455364; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-bottom: -1px; } QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off { image: url(":/qss_icons/dark/rc/arrow_up_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::up-arrow:hover { image: url(":/qss_icons/dark/rc/arrow_up.png"); } QAbstractSpinBox:down-button { background-color: transparent #19232D; subcontrol-origin: border; subcontrol-position: bottom right; border-left: 1px solid #455364; border-top: 1px solid #455364; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-top: -1px; } QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off { image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::down-arrow:hover { image: url(":/qss_icons/dark/rc/arrow_down.png"); } QAbstractSpinBox:hover { border: 1px solid #346792; color: #DFE1E2; } QAbstractSpinBox:focus { border: 1px solid #1A72BB; } QAbstractSpinBox:selected { background: #346792; color: #455364; } /* ------------------------------------------------------------------------ */ /* DISPLAYS --------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QLabel ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe --------------------------------------------------------------------------- */ QLabel { background-color: #19232D; border: 0px solid #455364; padding: 2px; margin: 0px; color: #DFE1E2; } QLabel:disabled { background-color: #19232D; border: 0px solid #455364; color: #788D9C; } /* QTextBrowser ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QTextBrowser { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; } QTextBrowser:disabled { background-color: #19232D; border: 1px solid #455364; color: #788D9C; border-radius: 4px; } QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed { border: 1px solid #455364; } /* QGraphicsView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QGraphicsView { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; } QGraphicsView:disabled { background-color: #19232D; border: 1px solid #455364; color: #788D9C; border-radius: 4px; } QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed { border: 1px solid #455364; } /* QCalendarWidget -------------------------------------------------------- --------------------------------------------------------------------------- */ QCalendarWidget { border: 1px solid #455364; border-radius: 4px; } QCalendarWidget:disabled { background-color: #19232D; color: #788D9C; } /* QLCDNumber ------------------------------------------------------------- --------------------------------------------------------------------------- */ QLCDNumber { background-color: #19232D; color: #DFE1E2; } QLCDNumber:disabled { background-color: #19232D; color: #788D9C; } /* QProgressBar ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar --------------------------------------------------------------------------- */ QProgressBar { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; text-align: center; } QProgressBar:disabled { background-color: #19232D; border: 1px solid #455364; color: #788D9C; border-radius: 4px; text-align: center; } QProgressBar::chunk { background-color: #346792; color: #19232D; border-radius: 4px; } QProgressBar::chunk:disabled { background-color: #26486B; color: #788D9C; border-radius: 4px; } /* ------------------------------------------------------------------------ */ /* BUTTONS ---------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QPushButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton --------------------------------------------------------------------------- */ QPushButton { background-color: #455364; color: #DFE1E2; border-radius: 4px; padding: 2px; outline: none; border: none; } QPushButton:disabled { background-color: #455364; color: #788D9C; border-radius: 4px; padding: 2px; } QPushButton:checked { background-color: #60798B; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:disabled { background-color: #60798B; color: #788D9C; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:selected { background: #60798B; } QPushButton:hover { background-color: #54687A; color: #DFE1E2; } QPushButton:pressed { background-color: #60798B; } QPushButton:selected { background: #60798B; color: #DFE1E2; } QPushButton::menu-indicator { subcontrol-origin: padding; subcontrol-position: bottom right; bottom: 4px; } QDialogButtonBox QPushButton { /* Issue #194 #248 - Special case of QPushButton inside dialogs, for better UI */ min-width: 80px; } /* QToolButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton --------------------------------------------------------------------------- */ QToolButton { background-color: #455364; color: #DFE1E2; border-radius: 4px; padding: 2px; outline: none; border: none; /* The subcontrols below are used only in the DelayedPopup mode */ /* The subcontrols below are used only in the MenuButtonPopup mode */ /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ } QToolButton:disabled { background-color: #455364; color: #788D9C; border-radius: 4px; padding: 2px; } QToolButton:checked { background-color: #60798B; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:disabled { background-color: #60798B; color: #788D9C; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:hover { background-color: #54687A; color: #DFE1E2; } QToolButton:checked:pressed { background-color: #60798B; } QToolButton:checked:selected { background: #60798B; color: #DFE1E2; } QToolButton:hover { background-color: #54687A; color: #DFE1E2; } QToolButton:pressed { background-color: #60798B; } QToolButton:selected { background: #60798B; color: #DFE1E2; } QToolButton[popupMode="0"] { /* Only for DelayedPopup */ padding-right: 2px; } QToolButton[popupMode="1"] { /* Only for MenuButtonPopup */ padding-right: 20px; } QToolButton[popupMode="1"]::menu-button { border: none; } QToolButton[popupMode="1"]::menu-button:hover { border: none; border-left: 1px solid #455364; border-radius: 0; } QToolButton[popupMode="2"] { /* Only for InstantPopup */ padding-right: 2px; } QToolButton::menu-button { padding: 2px; border-radius: 4px; width: 12px; border: none; outline: none; } QToolButton::menu-button:hover { border: 1px solid #346792; } QToolButton::menu-button:checked:hover { border: 1px solid #346792; } QToolButton::menu-indicator { image: url(":/qss_icons/dark/rc/arrow_down.png"); height: 8px; width: 8px; top: 0; /* Exclude a shift for better image */ left: -2px; /* Shift it a bit */ } QToolButton::menu-arrow { image: url(":/qss_icons/dark/rc/arrow_down.png"); height: 8px; width: 8px; } QToolButton::menu-arrow:hover { image: url(":/qss_icons/dark/rc/arrow_down_focus.png"); } /* QCommandLinkButton ----------------------------------------------------- --------------------------------------------------------------------------- */ QCommandLinkButton { background-color: transparent; border: 1px solid #455364; color: #DFE1E2; border-radius: 4px; padding: 0px; margin: 0px; } QCommandLinkButton:disabled { background-color: transparent; color: #788D9C; } /* ------------------------------------------------------------------------ */ /* INPUTS - NO FIELDS ----------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QComboBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QComboBox { border: 1px solid #455364; border-radius: 4px; selection-background-color: #346792; padding-left: 4px; padding-right: 4px; /* padding-right = 36; 4 + 16*2 See scrollbar size */ /* changed to 4px to fix #239 */ /* Fixes #103, #111 */ min-height: 1.5em; /* padding-top: 2px; removed to fix #132 */ /* padding-bottom: 2px; removed to fix #132 */ /* min-width: 75px; removed to fix #109 */ /* Needed to remove indicator - fix #132 */ } QComboBox QAbstractItemView { border: 1px solid #455364; border-radius: 0; background-color: #19232D; selection-background-color: #346792; } QComboBox QAbstractItemView:hover { background-color: #19232D; color: #DFE1E2; } QComboBox QAbstractItemView:selected { background: #346792; color: #455364; } QComboBox QAbstractItemView:alternate { background: #19232D; } QComboBox:disabled { background-color: #19232D; color: #788D9C; } QComboBox:hover { border: 1px solid #346792; } QComboBox:focus { border: 1px solid #1A72BB; } QComboBox:on { selection-background-color: #346792; } QComboBox::item { /* Remove to fix #282, #285 and MR #288*/ /*&:checked { font-weight: bold; } &:selected { border: 0px solid transparent; } */ } QComboBox::item:alternate { background: #19232D; } QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #455364; } QComboBox::down-arrow { image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus { image: url(":/qss_icons/dark/rc/arrow_down.png"); } /* QSlider ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider --------------------------------------------------------------------------- */ QSlider:disabled { background: #19232D; } QSlider:focus { border: none; } QSlider::groove:horizontal { background: #455364; border: 1px solid #455364; height: 4px; margin: 0px; border-radius: 4px; } QSlider::groove:vertical { background: #455364; border: 1px solid #455364; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical { background: #346792; border: 1px solid #455364; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical :disabled { background: #26486B; } QSlider::sub-page:horizontal { background: #346792; border: 1px solid #455364; height: 4px; margin: 0px; border-radius: 4px; } QSlider::sub-page:horizontal:disabled { background: #26486B; } QSlider::handle:horizontal { background: #9DA9B5; border: 1px solid #455364; width: 8px; height: 8px; margin: -8px 0px; border-radius: 4px; } QSlider::handle:horizontal:hover { background: #346792; border: 1px solid #346792; } QSlider::handle:horizontal:focus { border: 1px solid #1A72BB; } QSlider::handle:vertical { background: #9DA9B5; border: 1px solid #455364; width: 8px; height: 8px; margin: 0 -8px; border-radius: 4px; } QSlider::handle:vertical:hover { background: #346792; border: 1px solid #346792; } QSlider::handle:vertical:focus { border: 1px solid #1A72BB; } /* QLineEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit --------------------------------------------------------------------------- */ QLineEdit { background-color: #19232D; padding-top: 2px; /* This QLineEdit fix 103, 111 */ padding-bottom: 2px; /* This QLineEdit fix 103, 111 */ padding-left: 4px; padding-right: 4px; border-style: solid; border: 1px solid #455364; border-radius: 4px; color: #DFE1E2; } QLineEdit:disabled { background-color: #19232D; color: #788D9C; } QLineEdit:hover { border: 1px solid #346792; color: #DFE1E2; } QLineEdit:focus { border: 1px solid #1A72BB; } QLineEdit:selected { background-color: #346792; color: #455364; } /* QTabWiget -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabWidget { padding: 2px; selection-background-color: #455364; } QTabWidget QWidget { /* Fixes #189 */ border-radius: 4px; } QTabWidget::pane { border: 1px solid #455364; border-radius: 4px; margin: 0px; /* Fixes double border inside pane with pyqt5 */ padding: 0px; } QTabWidget::pane:selected { background-color: #455364; border: 1px solid #346792; } /* QTabBar ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabBar, QDockWidget QTabBar { qproperty-drawBase: 0; border-radius: 4px; margin: 0px; padding: 2px; border: 0; /* left: 5px; move to the right by 5px - removed for fix */ } QTabBar::close-button, QDockWidget QTabBar::close-button { border: 0; margin: 0; padding: 4px; image: url(":/qss_icons/dark/rc/window_close.png"); } QTabBar::close-button:hover, QDockWidget QTabBar::close-button:hover { image: url(":/qss_icons/dark/rc/window_close_focus.png"); } QTabBar::close-button:pressed, QDockWidget QTabBar::close-button:pressed { image: url(":/qss_icons/dark/rc/window_close_pressed.png"); } QTabBar::tab, QDockWidget QTabBar::tab { /* !selected and disabled ----------------------------------------- */ /* selected ------------------------------------------------------- */ } QTabBar::tab:top:selected:disabled, QDockWidget QTabBar::tab:top:selected:disabled { border-bottom: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:bottom:selected:disabled, QDockWidget QTabBar::tab:bottom:selected:disabled { border-top: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:left:selected:disabled, QDockWidget QTabBar::tab:left:selected:disabled { border-right: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:right:selected:disabled, QDockWidget QTabBar::tab:right:selected:disabled { border-left: 3px solid #26486B; color: #788D9C; background-color: #455364; } QTabBar::tab:top:!selected:disabled, QDockWidget QTabBar::tab:top:!selected:disabled { border-bottom: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:bottom:!selected:disabled, QDockWidget QTabBar::tab:bottom:!selected:disabled { border-top: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:left:!selected:disabled, QDockWidget QTabBar::tab:left:!selected:disabled { border-right: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:right:!selected:disabled, QDockWidget QTabBar::tab:right:!selected:disabled { border-left: 3px solid #19232D; color: #788D9C; background-color: #19232D; } QTabBar::tab:top:!selected, QDockWidget QTabBar::tab:top:!selected { border-bottom: 2px solid #19232D; margin-top: 2px; } QTabBar::tab:bottom:!selected, QDockWidget QTabBar::tab:bottom:!selected { border-top: 2px solid #19232D; margin-bottom: 2px; } QTabBar::tab:left:!selected, QDockWidget QTabBar::tab:left:!selected { border-left: 2px solid #19232D; margin-right: 2px; } QTabBar::tab:right:!selected, QDockWidget QTabBar::tab:right:!selected { border-right: 2px solid #19232D; margin-left: 2px; } QTabBar::tab:top, QDockWidget QTabBar::tab:top { background-color: #455364; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; min-width: 5px; border-bottom: 3px solid #455364; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:selected, QDockWidget QTabBar::tab:top:selected { background-color: #54687A; border-bottom: 3px solid #259AE9; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:!selected:hover, QDockWidget QTabBar::tab:top:!selected:hover { border: 1px solid #1A72BB; border-bottom: 3px solid #1A72BB; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:bottom, QDockWidget QTabBar::tab:bottom { border-top: 3px solid #455364; background-color: #455364; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; min-width: 5px; } QTabBar::tab:bottom:selected, QDockWidget QTabBar::tab:bottom:selected { background-color: #54687A; border-top: 3px solid #259AE9; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } QTabBar::tab:bottom:!selected:hover, QDockWidget QTabBar::tab:bottom:!selected:hover { border: 1px solid #1A72BB; border-top: 3px solid #1A72BB; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:left, QDockWidget QTabBar::tab:left { background-color: #455364; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-left-radius: 4px; border-bottom-left-radius: 4px; min-height: 5px; } QTabBar::tab:left:selected, QDockWidget QTabBar::tab:left:selected { background-color: #54687A; border-right: 3px solid #259AE9; } QTabBar::tab:left:!selected:hover, QDockWidget QTabBar::tab:left:!selected:hover { border: 1px solid #1A72BB; border-right: 3px solid #1A72BB; /* Fixes different behavior #271 */ margin-right: 0px; padding-right: -1px; } QTabBar::tab:right, QDockWidget QTabBar::tab:right { background-color: #455364; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; min-height: 5px; } QTabBar::tab:right:selected, QDockWidget QTabBar::tab:right:selected { background-color: #54687A; border-left: 3px solid #259AE9; } QTabBar::tab:right:!selected:hover, QDockWidget QTabBar::tab:right:!selected:hover { border: 1px solid #1A72BB; border-left: 3px solid #1A72BB; /* Fixes different behavior #271 */ margin-left: 0px; padding-left: 0px; } QTabBar QToolButton, QDockWidget QTabBar QToolButton { /* Fixes #136 */ background-color: #455364; height: 12px; width: 12px; } QTabBar QToolButton:pressed, QDockWidget QTabBar QToolButton:pressed { background-color: #455364; } QTabBar QToolButton:pressed:hover, QDockWidget QTabBar QToolButton:pressed:hover { border: 1px solid #346792; } QTabBar QToolButton::left-arrow:enabled, QDockWidget QTabBar QToolButton::left-arrow:enabled { image: url(":/qss_icons/dark/rc/arrow_left.png"); } QTabBar QToolButton::left-arrow:disabled, QDockWidget QTabBar QToolButton::left-arrow:disabled { image: url(":/qss_icons/dark/rc/arrow_left_disabled.png"); } QTabBar QToolButton::right-arrow:enabled, QDockWidget QTabBar QToolButton::right-arrow:enabled { image: url(":/qss_icons/dark/rc/arrow_right.png"); } QTabBar QToolButton::right-arrow:disabled, QDockWidget QTabBar QToolButton::right-arrow:disabled { image: url(":/qss_icons/dark/rc/arrow_right_disabled.png"); } /* QDockWiget ------------------------------------------------------------- --------------------------------------------------------------------------- */ QDockWidget { outline: 1px solid #455364; background-color: #19232D; border: 1px solid #455364; border-radius: 4px; titlebar-close-icon: url(":/qss_icons/dark/rc/transparent.png"); titlebar-normal-icon: url(":/qss_icons/dark/rc/transparent.png"); } QDockWidget::title { /* Better size for title bar */ padding: 3px; spacing: 4px; border: none; background-color: #455364; } QDockWidget::close-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/dark/rc/window_close.png"); } QDockWidget::close-button:hover { image: url(":/qss_icons/dark/rc/window_close_focus.png"); } QDockWidget::close-button:pressed { image: url(":/qss_icons/dark/rc/window_close_pressed.png"); } QDockWidget::float-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/dark/rc/window_undock.png"); } QDockWidget::float-button:hover { image: url(":/qss_icons/dark/rc/window_undock_focus.png"); } QDockWidget::float-button:pressed { image: url(":/qss_icons/dark/rc/window_undock_pressed.png"); } /* QTreeView QListView QTableView ----------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview --------------------------------------------------------------------------- */ QTreeView:branch:selected, QTreeView:branch:hover { background: url(":/qss_icons/dark/rc/transparent.png"); } QTreeView:branch:has-siblings:!adjoins-item { border-image: url(":/qss_icons/dark/rc/branch_line.png") 0; } QTreeView:branch:has-siblings:adjoins-item { border-image: url(":/qss_icons/dark/rc/branch_more.png") 0; } QTreeView:branch:!has-children:!has-siblings:adjoins-item { border-image: url(":/qss_icons/dark/rc/branch_end.png") 0; } QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings { border-image: none; image: url(":/qss_icons/dark/rc/branch_closed.png"); } QTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings { border-image: none; image: url(":/qss_icons/dark/rc/branch_open.png"); } QTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover { image: url(":/qss_icons/dark/rc/branch_closed_focus.png"); } QTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover { image: url(":/qss_icons/dark/rc/branch_open_focus.png"); } QTreeView::indicator:checked, QListView::indicator:checked, QTableView::indicator:checked, QColumnView::indicator:checked { image: url(":/qss_icons/dark/rc/checkbox_checked.png"); } QTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed, QListView::indicator:checked:hover, QListView::indicator:checked:focus, QListView::indicator:checked:pressed, QTableView::indicator:checked:hover, QTableView::indicator:checked:focus, QTableView::indicator:checked:pressed, QColumnView::indicator:checked:hover, QColumnView::indicator:checked:focus, QColumnView::indicator:checked:pressed { image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); } QTreeView::indicator:unchecked, QListView::indicator:unchecked, QTableView::indicator:unchecked, QColumnView::indicator:unchecked { image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); } QTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed, QListView::indicator:unchecked:hover, QListView::indicator:unchecked:focus, QListView::indicator:unchecked:pressed, QTableView::indicator:unchecked:hover, QTableView::indicator:unchecked:focus, QTableView::indicator:unchecked:pressed, QColumnView::indicator:unchecked:hover, QColumnView::indicator:unchecked:focus, QColumnView::indicator:unchecked:pressed { image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); } QTreeView::indicator:indeterminate, QListView::indicator:indeterminate, QTableView::indicator:indeterminate, QColumnView::indicator:indeterminate { image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); } QTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed, QListView::indicator:indeterminate:hover, QListView::indicator:indeterminate:focus, QListView::indicator:indeterminate:pressed, QTableView::indicator:indeterminate:hover, QTableView::indicator:indeterminate:focus, QTableView::indicator:indeterminate:pressed, QColumnView::indicator:indeterminate:hover, QColumnView::indicator:indeterminate:focus, QColumnView::indicator:indeterminate:pressed { image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); } QTreeView, QListView, QTableView, QColumnView { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; gridline-color: #455364; border-radius: 4px; } QTreeView:disabled, QListView:disabled, QTableView:disabled, QColumnView:disabled { background-color: #19232D; color: #788D9C; } QTreeView:selected, QListView:selected, QTableView:selected, QColumnView:selected { background-color: #346792; color: #455364; } QTreeView:focus, QListView:focus, QTableView:focus, QColumnView:focus { border: 1px solid #1A72BB; } QTreeView::item:pressed, QListView::item:pressed, QTableView::item:pressed, QColumnView::item:pressed { background-color: #346792; } QTreeView::item:selected:active, QListView::item:selected:active, QTableView::item:selected:active, QColumnView::item:selected:active { background-color: #346792; } QTreeView::item:selected:!active, QListView::item:selected:!active, QTableView::item:selected:!active, QColumnView::item:selected:!active { color: #DFE1E2; background-color: #37414F; } QTreeView::item:!selected:hover, QListView::item:!selected:hover, QTableView::item:!selected:hover, QColumnView::item:!selected:hover { outline: 0; color: #DFE1E2; background-color: #37414F; } QTableCornerButton::section { background-color: #19232D; border: 1px transparent #455364; border-radius: 0px; } /* QHeaderView ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview --------------------------------------------------------------------------- */ QHeaderView { background-color: #455364; border: 0px transparent #455364; padding: 0; margin: 0; border-radius: 0; } QHeaderView:disabled { background-color: #455364; border: 1px transparent #455364; } QHeaderView::section { background-color: #455364; color: #DFE1E2; border-radius: 0; text-align: left; font-size: 13px; } QHeaderView::section::horizontal { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-left: 1px solid #19232D; } QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { border-left: 1px solid #455364; } QHeaderView::section::horizontal:disabled { color: #788D9C; } QHeaderView::section::vertical { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-top: 1px solid #19232D; } QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { border-top: 1px solid #455364; } QHeaderView::section::vertical:disabled { color: #788D9C; } QHeaderView::down-arrow { /* Those settings (border/width/height/background-color) solve bug */ /* transparent arrow background and size */ background-color: #455364; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/dark/rc/arrow_down.png"); } QHeaderView::up-arrow { background-color: #455364; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/dark/rc/arrow_up.png"); } /* QToolBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox --------------------------------------------------------------------------- */ QToolBox { padding: 0px; border: 0px; border: 1px solid #455364; } QToolBox:selected { padding: 0px; border: 2px solid #346792; } QToolBox::tab { background-color: #19232D; border: 1px solid #455364; color: #DFE1E2; border-top-left-radius: 4px; border-top-right-radius: 4px; } QToolBox::tab:disabled { color: #788D9C; } QToolBox::tab:selected { background-color: #60798B; border-bottom: 2px solid #346792; } QToolBox::tab:selected:disabled { background-color: #455364; border-bottom: 2px solid #26486B; } QToolBox::tab:!selected { background-color: #455364; border-bottom: 2px solid #455364; } QToolBox::tab:!selected:disabled { background-color: #19232D; } QToolBox::tab:hover { border-color: #1A72BB; border-bottom: 2px solid #1A72BB; } QToolBox QScrollArea { padding: 0px; border: 0px; background-color: #19232D; } /* QFrame ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe https://doc.qt.io/qt-5/qframe.html#-prop https://doc.qt.io/qt-5/qframe.html#details https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color --------------------------------------------------------------------------- */ /* (dot) .QFrame fix #141, #126, #123 */ .QFrame { border-radius: 4px; border: 1px solid #455364; /* No frame */ /* HLine */ /* HLine */ } .QFrame[frameShape="0"] { border-radius: 4px; border: 1px transparent #455364; } .QFrame[frameShape="4"] { max-height: 2px; border: none; background-color: #455364; } .QFrame[frameShape="5"] { max-width: 2px; border: none; background-color: #455364; } /* QSplitter -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter --------------------------------------------------------------------------- */ QSplitter { background-color: #455364; spacing: 0px; padding: 0px; margin: 0px; } QSplitter::handle { background-color: #455364; border: 0px solid #19232D; spacing: 0px; padding: 1px; margin: 0px; } QSplitter::handle:hover { background-color: #9DA9B5; } QSplitter::handle:horizontal { width: 5px; image: url(":/qss_icons/dark/rc/line_vertical.png"); } QSplitter::handle:vertical { height: 5px; image: url(":/qss_icons/dark/rc/line_horizontal.png"); } /* QDateEdit, QDateTimeEdit ----------------------------------------------- --------------------------------------------------------------------------- */ QDateEdit, QDateTimeEdit { selection-background-color: #346792; border-style: solid; border: 1px solid #455364; border-radius: 4px; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; min-width: 10px; } QDateEdit:on, QDateTimeEdit:on { selection-background-color: #346792; } QDateEdit::drop-down, QDateTimeEdit::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #455364; } QDateEdit::down-arrow, QDateTimeEdit::down-arrow { image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus, QDateTimeEdit::down-arrow:on, QDateTimeEdit::down-arrow:hover, QDateTimeEdit::down-arrow:focus { image: url(":/qss_icons/dark/rc/arrow_down.png"); } QDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView { background-color: #19232D; border-radius: 4px; border: 1px solid #455364; selection-background-color: #346792; } /* QAbstractView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractView:hover { border: 1px solid #346792; color: #DFE1E2; } QAbstractView:selected { background: #346792; color: #455364; } /* PlotWidget ------------------------------------------------------------- --------------------------------------------------------------------------- */ PlotWidget { /* Fix cut labels in plots #134 */ padding: 0px; } epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/000077500000000000000000000000001526321767600230755ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/.keep000066400000000000000000000000021526321767600240120ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_down.png000066400000000000000000000010061526321767600257610ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¸IDATX…í”=‹Q†Ÿ÷†•A´‘AÌL÷ø ìD‘E-[Ùÿ @´°´±PÄJ ÅÒBKí×dg¢+%ü€™×"‰F7™ø±Í<0Ì�3gÞ÷pν5555;ŒÊE7ÍÞ öýSÃûNïSñð›üA˜Y¬µϰÁ.€ü¯\v�=qòÓ• véû}ƒÁ`ϧ/_ïÇ'¡0†Àa|ãáîÕ]g¢(Ít Š¢ÑèÃðpgêýEV7§4¿=ú8<=m^&Ì`»±•ö¯#.ØFÒ2��í Ì�VÒ¼$)ÿ9é—ORÞJš%®H*óªtBÀØ_kÍš—‰ÛÒKÓ ÐÕñ“ *¶ÿÂ4ÑõF;I®Í«t.Ý4='th¬ñ朵6AB@nt¾“4oÍÓ^¸­/Ót= »À*Æh¦ˆrLŸ |öp’ðâ�K>šîËsd\§.`Œ/8IVF�x}ûyø¸å¹gú¿IÔÎØ>‹“L}Ï}ƒÄÙ­géÝ–ç¾9®ä�ñ¾áïÒ ÃÓ/ IЫӞ÷鸵Læc€N.<(ðÚ´ç}5)-ƒÁ`0 ƒÁ`0 †{‰§0—Ó·ØIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_down_disabled.png000066400000000000000000000010421526321767600276100ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÔIDATX…í”±kQÇ?ß„  qÐÁI‰J%¸:yµHéP Ž‚mfÿAÝü ’¸V¼¡uðzCuí-. .µd±¡æ~—3§mc’»ÜÞÝû¾ï÷û~ï÷2dÈ�အdà]Ÿûþ“ïFجpý(r»Ò÷)¯þ@ÑiàuŠÝýx„¢ßÞÆ«ž×Ÿ¿±®Ã�+@€áHÑv«sñ�éx�ßXO¦siî§ÕÕ­r©øô‡åÏJ”0´·˜€Ù“‚kß\šŸßL3r/iµZÝr©ø¬cùãˆKŒ[ÅæÄ� ¹vÕ÷ýŸÛhƒ$¼™¹ûˆ»½×̆uOÌAÂfí°ãÚmHcíÃÛ•âùò0Ù «Ý„˜á$’�ß ›õ‡ƒøôB¼)ž»¸†4 ¸^_ìÂÌœ$wÿ­°Y¯ýKèó�¸Q�23ÈW!JϧÌ7%U–jχÑ©Á&ff/›ÜØQ33)¾ß}sµ�l*X¨¿Vsä÷*Õ D' L‰†ø†4úµw£è�uÅ®VfÏD!èTüÅ>;‡ø��£j�ý›ñ¦oŸä�ûzÏV÷Z¸øøë¸Z2dÈp ø¤ñ¤ŽDÆQ^IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_down_disabled@2x.png000066400000000000000000000020541526321767600301660ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÞIDATxœí˜Ïk\UÇ?ç¾44‘Š`q“¶.²Ð�"ÆB­YĦi Z51 "Mð@‘ ‚ºP .4�i‰3�t„š23)#âª6éª1]m+ˆ¦ ›Ò@fæIcß›7ÉdfÞ4ÚûY¾óîyßsï¹ç¾{Àb±X,‹Åb±X,‹Åò`!þ�=ýï‰1ÇQÀ´ö²ªŠ!¯®û~:~jè^c]ÁÛ²<€©…š 8"æ8à™€ÿO€eR0ªî ÿõ´@u96/5àPOG^LB`›Ç¨,×…Í‹ªAė‘t,’ñ¿8]}{4Ïy„íþ/€q7_m@ þ˜”yqèNŽE.U”î¾þ'ò®I;½NUÙl™P<\sŒÛu~ìÔl±AkN@׋Gwj�“žô™”ͳ‚‚ÿErù®dbäúz×$™¹ž­7íÀÏ>“€:Acj‡°¢ÁüÅl½i_/x(ñÌœžoȺÏ!\(" æ¸N@O6dÝ™ÓÃó¥ø)YüììôÒ®½O}ëdM+Ð⑦„ÝTEDŠ|3^w§¡÷ܹ/ï”êiC«÷ëå˹]�½pÆi\hž R6r÷×¶�è#æï׉‘ìý•§£³wàc�7ºÖ)¼È'©ØÉ·)ã»eïß¹™©TsKÛ""ýrÂÈ…¢+¯úVêLd¨pDiTTÀæf¦jnmûäy¼ÙTÕ- Þe0�~^¡ïÊéììô Þgªø_AQ�RK*¼šŽEâ•ø†*®Ô�žÁN#zxÈkQ…òþŒj¼�èK©Xt²<¥^ªšª‡úŽíu]ùxÔcPÙ`&()ÐwÓU9<?y±2¥ÿRõjÕùò@‹R@“ÏTúv¸Ñ7Ô¥+=™©‚ÌUªÞI�Gfòªû�«>SðæC þª³¿ÚÁCH¡ ñèoâÖµ+Ly Ë)½ÖÉãø žÂT�É?›¾‚ÔðZbÉñ/þܲu±å¿M'!ðN‘Ù²u±cblä¯$!÷'FGoeÎu#úݽÏW–ØAd5+¼Y/�ÈnËž½¦ÆÐorË÷‡#1§qáqàiŸY,ÄúUöæŽ×2gO,…­¯&]áLf(·owS¿"Ÿ­ÿ¶~ºo÷Žc™ÌP.|eµ½ÃÈÁWÞAù0Шún2ýˆ6kÞ̘»2õcskÛ+÷‡»¨(o$ãѵÖs_º9sW¦/5·îid¹Ïx[”£Éxäëû¡Åb±X,‹Åb±X,‹Åò ñdv7oÔaIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_down_focus.png000066400000000000000000000010131526321767600271560ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+½IDATX…í”=kQ…Ÿs×B ˆ6AÁZl’E;Y‘຋¦QÁ�_ ¨¿@lRÚX(²‰A CJ‘$k£)RYØ(X%¨‘�ݽÇbfÝe£›™õ#Í<0ð2Ü9çÜû¾w    `ŸQ·˜œ‹‚#ÿÃÔ°Ù¬‡£ágõêM¿W¯hé$°’&�Îßxl¢{þË©W¦?ÙéE�ú�Q”0†À„áåö˜®®U´µëÖ*ÚúÚÒeä'HHƒ!ó`#CH$üø[[Õ~ó]Ö§µ3Þ ×mϦÞÁΠ‰ Àöìx;ÜXŸÖÎàºß Û*?‹w±n'‚ŠÂ™Úa$áts¾·Z w�~ùíž;+Ï{û~7(7wR"®™•º [ŸéhË ßD~”†…è3ï ÝZ­éÑ^Ú™{;9ç)á§ÀA’›:¢;°ÛFךu½È¢›k¸&>äçÀaƒ•†0%Z_4Õ¼¢WY5sO÷ļÏ{8†0ÑÝ–ŽÒÅ75½Í£7Ò?»àS±ã%àDúêC(éÂrUïój�ü“9·àãíŽ?ï”téuUŸFÕ*(((ØW~¤ø±x‹Ç¸IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_down_focus@2x.png000066400000000000000000000017401526321767600275370ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+’IDATxœí˜Mh\U†Ÿ÷ÞPE¡Ú�èV\·d"©hTJ›BÒI àJ´þ�kAD¬`ºÐ­ŠW®šŒÉ¢J5›ÊLÒtÓŸ�ÅeDÒ¸ˆ:s_¡2¹÷&™™Ü™Dzžåùî9ç}¿ósÏ9�@ �@ ¸·Pº`pÆJþˆ ‰À{ «0 D@ÃÖÇ‹“ú¨9žI@i6©q¯ö˜Fm"êk.ˆöJÉ~!“[gÐÿ{Úç"lëL¶8‡ÒŒG�ç€R!IäIDÖך¤±jY é�sPªø0ö÷À¡T ãý™C¤¬§¤ãµ²–óêl™€#s~éÃë oOû±{_Òß6‚e“ ‹iD`V±ÙOm=cùJ}Ü2ª²l®t^²³µHm†¡jqÁ…©‘¹¥FÙ°­lï@ŸP?€ªõ¤8�®DßÔh±´¼×tæ.w#»¸7!áXuVžaG'G 7iGlGn°Ë‘?¬D½ ™ƒÉ€yßœÃå«ùQtcí¬loÿ^áÜÖ×™~ûWß¡«<\|U3öËö\Ú‰ã>lTÛí3æ{&¯�zG¯©CÞqbh«yÞ¸ÁÁ[¹î¾ò•“oâj5}ËìÊlvôNðÒOÙÁ烅÷Íj%$$$¬*¿¯8¬‚âQIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_down_pressed@2x.png000066400000000000000000000020561526321767600300660ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+àIDATxœí˜Mh\UÇç½2©š¸±”´RÄ�Ö�`2º(4~„ˆR”JQWÍ¢é¤i&ê' V°]¨ÍÔ|Œ”D„‚›b]i©L®æM nüÀEi5 ›H!�¦SçÉhæ½—Nfæ½IJïoyÏ»çþϹïÞ{îƒÁ`0 ƒÁ`0 ý…xâ]©PÁVpt=„……‚X¢ùÐI÷®´oòõP°¬:錌⠫`ƒ% ¸ë¬T�+rWÿöA(¢¨÷¶ûö€Ö®Sm"rhò|® n$ ÃÃÂ×<"ûœÑÞŒ÷ãÀ´tŸjµ\ùØRbPaC&AÁL³®¥Ó#}¹ >«& ÞýÙã¸ÖE`‡§›îÆ9 d9xõÆsËmwFú]½gž>òù-.;=]7HÀÂü/bÛíÙážkwê]öÈ÷\SÍïœR‹Š¢vùF‡ŠÚ¾à…¬j~O¹àa�Ç`.}l¶áöÍg~ð PìõÈ�‚¸Ž}©!óÙ\úØìZüT¤}ïÁñÍó g}Å/H]©Óñ©¨4yçnÄxã÷TòÖZ}UTe&:›šg€žñÚ±´Â„VÃRi¼žyôïæ•U V‰N�Þ Ùý¡X×û zÒI'ߥŠ?°¦‹'Ro£z"À«‹†�‚f^äg´÷dµ^íZ$Í8“?nkíøSD^¢4™¢„¸„ à]�CÎXïéÚ\‡@<‘Ú�êY æ1-× 5TÚæ^ÏŽ%ÏÕè;¼IŠz‹o€V¶ëÒ–]e$¨ÀYôåìXߥê|zFÃI‘xbhÊwÀCžaª¸D?'®ûBö‹þl-:KF ËQ‘–#Ÿ>!…M}Øcª`9ÿ‡kÚ§‡ßü9™ÿ�¦³"Oõœ~Äþǽ:3`!ŠÞ2ñ`‘3 '1ë‚ÓU × _Û[ä @òÖçï½pû>C/–H30ó⺠çA™™¢0|Xèõ’ æÇ1|µdfù‰��{„½]„�O×2j{"ËËË£³;ÁW$CþTB­�ÌÏÏŸT>¹ãóŠdòĄڃˆãøG&“�~‘7ÃÌÚ �<…8Ž¿3å×ßù3UЪ �•a¯×K&Æ ÀSbhÍ„FÇáb~a nNN‰£Ÿˆz½íŸ`ÜŒ¶Ä¢æMhe&ŽÃð=Œ»¨nžŒÔ¨ ­-Eq¾ z Ê‹f_™[]‹ã(:`Æ“E®éÍSë/#Q·û,â…i†5´ohÝ3S/ê> ¼Vä%̈¯u`só4»÷+E~ó‚t½s‚ì0“OîD|TVdàîvxÞÇñ©ñè—ÝÀge¥ž[¢à™KKK?MF§w!¾j¢?ï X\\ü^ùx'p¬î¾¼4`aa! ÐNàÄÙÙ�ðÖ€(оT`»€Ÿ‹¼Ë_f¼6`¡Ûý4G·PØ7ü/~™)â²(ú´˜€Md<ÓvL3Ì0ÿ€¥N˜ÿYIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_left_disabled.png000066400000000000000000000010551526321767600275770ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ßIDATX…å–±kQ‡¿ß»C‚‚G,l¬í-­,$·%ÍÅ�ÕdÓùÄBìETâ!x•®wM°ð6XXYŠ­ ÚØè Aro,VÅJ÷í>"èt;3ßüvæ1ð¿›b'\L³#Þë-`ÅèþüŸ¾oÇ,žôû‡üŽž�ª1.Vñ4MØÎÜ8 MÓÖ'ßy–„ÆÆÐgß¹-8�à÷`á\vXÃ'ß1*Z£!\è]\—qÉcT(Ðíe}‰›?‹^¼6@²œ-!=(½z�×HzÙ)C��–aV·óZÝôÒ “Ûæ03¡ ‰oÐ]¾|oÏÀXùß›[%€ÓéÚ1˜ÀQÀ¸ë¿³JkØò{ïq£‡Š ^Cà `ϵπ½S@LT€çùÝÐN€�€,"DåDÅèÞœAÛ*™(AIŠ|ã•Ì/»€ÌšC'˜Œ/„­3 ��uµ:˜Œ›˜](=s4¸-kKXŒCÐú�<¥ûPŒ6n™ì€yœj(Ñxˆ¶ž ® î 0èDŒU²Ž›^1x„€À͈²ËyžÏæÝt4 ��ö¢åyþUw{ÀË¿0¿8gg‘¶�iÌÜÿ®}hG• ˆIàIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_left_disabled@2x.png000066400000000000000000000021651526321767600301540ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœí›Oh\UÆçÍ´ZŒ¶º0¨+QÔ�P„"Hl'‰A vÆÑ•Øü™P¢EðãЊ"¶I¦ÆEŠš& ¡;Id Š (Å… â¢A­m “¹ÇEyófÀß½ïbæ[~ÜsîwÎý÷˜�:è`3C’N`£ÈdG‹"ò2QÕCËsÇ^�cÜ ŽAl£?;üB4 ’ ^‰kìt\ÙBonx§!X�æn�­p^w@_nì4Xº"’‰+†·dòc·(¦‚°£�¬qÅñÒ€�üÐ Sn¶Ë;‡¯]3©OnwÏ+zöí»úÒÖ`Ø‘bkù(¼1 §§˜ÞòGú8ÊĸéEá‹’Þ¾zeo«juòà‰™Üè‚GhEÄêäÁz-¼ ð|Éúä!a2¹BÕÃm¤º«3 “+ä=ÒD®ïõN*ß@"ìÉ2‚o‰`°x䵃súó#÷¢óÀÖˆdP·“ÇìÉÝiŒ,ׄyÁ}åpöÞ�¹50R®�HFš<8ꀾ½ûoL K@w˜$±Ê7`½2ù±ëÔ¬} r[³¢šdå°Ú»ò¶‰1 À=IÁþ-o#°f@OO1Ý¥>î�HÖï÷W+‹Å`Ëös“¨ F$o*߀ 䋳«oO6±Ú¨|â˾ ±�É�¾(è�Aüiû0b5 7WØ/p¨Ug�›+ElôfGƒ¾åÅö#¾‰~Ð$Ñ[ÞF›Òö ïõÜ� 0È3´Î8ñ/Nÿ†Ø\ž�øxºUÑT\1l Ö -ÍN¾ZlfÀ[boÑ¥ÙòAÞŽòŠz¹l$¥»îê~V•é0)ˆXŠ÷Ÿ`%¡R©dÎï†ù8" žu‚µd¾¯]uYCõófED=꫉œ:5~±fêƒ|æÄ—=ÁzÕù©ßkAíA�¼ "üHËIª3S?Ћ°æ‘dMpÖ†•™É¥®ý(çü*ë'D"pº+'ËgMÊ<\lV4 ¡åà|#Z™9ö¥"Y Ö&ç&$²/ÏNœå ¢�'%p½1&vUæ&?Dô©&RÖ7F—$z/�(Ex©Uq÷‚Lü2²tbòuEÞj#9É-q½ïÞ�ðN®Ì>@©T2µ_»G]óoˆVsô€jµ´Vëª?Žr&"Y5ÁªSS—ÓÛ. *|‘¬ ^°8=}!0éà{ñ¼3 ròÈ/uÕ>àœíX^ðÙ\ù'Ôû€ßÚȱ- o X™yï» Ðàψ´9þ2pz¦ü•QyôŸwƒl†¿Ì„±27± ­#ÔEx-éœ:è ƒÿþì5-Œ›ãmIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_left_focus.png000066400000000000000000000010471526321767600271500ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÙIDATX…å–1kTA…¿3YE *ZØXXÙXˆMؤ±L@ ¸‰®•;!?@,BzK!©|º‰,¢��YÓH AMcgdQ’ì‹eÁJß¼7(è©çžûÝ;÷Î{ð¿K¹ ' Ÿˆ ¿·ðëV8þ»ó�œÉÏ­{4öü 8&—‹ ¹’Ÿ-|ðpÏ+ÀxJ\€«…GŽˆKÀdÉÂ3Øú؈÷±®a#ÿ(@s%.݃IM¨Ðìxé6€­iÉk4;¾Ž|—AÖ¨ÄÊkŒ?õ4òCT® ••üŒu|ÁÑ0b쪕•Ô�±UŸòpl¡¤‰¯Ð|â3Á^ŽZ˜ ÉKL>Eð à$©»þ+•š�Øð'cr´ýg•½‚-€²˜ìa_�H¥c²¼jk›¨Ià3FV>ˆÒFÝ+z¥)`GFÆY ’L6[z­ià»PˆdƒÍY½TPè Të·®R—µ†u@ƒ.T†¨ÜÂ‘æ‡>®Që»-ÝÃ^PEˆÚCÔ� wl?�� Q•$Ÿî‡[È���Ó6#Ë.?n«ÿu/ÌÏS—"Û‹ö¶­Ýo£š6þ ÀÖ”za_—�wl¾äôþwõ‹Ê­IsBïIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_left_focus@2x.png000066400000000000000000000021371526321767600275230ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›MhUÅgò�•¢¨QW¢¸iÉGEIE«U Í{¥®D*Šv!*(‚ ±´bÁ…ˆqaÑ�/Z�J+H›]¯Ï7zzò¸v”ÇEŠT߸×#ÏüÝy)·ºƒ08î«y?p^Ò7Äyµ,€uc¾<Ž< \”ÍΫ� Ü0æ‹k5Ï—ÝV­èV«ëßñùÆ~sUí5†^wïRËÓ˜õIß9Nù¬‚0tÀµÅµÞÜ” „•㢗Ulý¾ï5Œd\\ç!ýSñó {S¦0Žü²*00é'@�'=·ïúÂ;˜ôýÆ{²¾µÊª¡2ýSn¿š2 61.lÑïP%Æ}3ö¾lû±TÜ#ïL*Àà”û,Oç$}›8Ï-îJU*€þi_Ûû禗?òË* À† _AìYàÂt¢˜Š:%�6Lú’þ¸4�(¦Ìï *|¬óÚ%ù}àÊT »êÎCÁ3`pÌkâšg0×¥a¬R6:ÿ¤ÂfÀÐ×âšßnLú.a¿`ÔÑâBü0œò >ÙýåÀÖÀµñ F÷d“�F~Y¹˜âI£GSf{­ ®ó�3€¾I?h¼»#�J;ܬV¹è›lí~%ë;ÀiŸTŽ3 óBƒöûûª¶¸+Un�Ó<è®·•éa2]–ˆBÿü˜€¹��êLœËGÌ¢”ëS`¾®—A£�I¸rßÌ�°ËòKiW ¢ï†üw‚’›Ç¢GŒßLùF¸ú·ÐYSÐNÅ­£íÀ»™D(,…sä�Zªiði*hÿÐ!…rdX'ÿ�îŽg"¡ð"Ž�èçxI·¾JúB2ª|Y,e>Û¦ï©é໤/U ¡´iØÖ×-t+°�ôÕ¾*ƒPê}øy]_ÝœÌÖአ”¾5ë:ìXuàTÒDvù*Y‰›[õ�¬»Éž*€PÙ£h®¡·míH™Z>A–§JŸÅ͆öÚzª#py‡§Ê7#Í:Ï ¿˜2uúðT‚*€ä¹ãÑcÂo¤ü’¶ÌÕØ©¸÷‚è>`&“~x pp£–Öü¢» Ÿ¤#Xg0n×¢z5 Mú*p“€ùÛõkÚ œ(£½àªë‡kðmÑm àPCßiðS6ËóÜ,€ù-ú2’6c~Kúʱî QSÖ–Ì©Îþ¿Ì$5·Uaí¢ýù­…ôlÕ5uÕUWg‡þ�°QVìÍ�IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_left_pressed.png000066400000000000000000000010761526321767600275000ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ðIDATX…å–1hSQ†¿?}­RA1‚...âР]+Tº©SM–´©à&Šâ&´M+؇ƒ`'p)êæ¢ò:HAA¨`¡EÛ䇤N‚ïÞ\"èÙÜóÿß=ïÜs/üï¡Ð‚ƒ¦ò[Qï;0[ŽÇ÷þi}ÒüèØí]�(z ¶'kN.”ù‘âõ¾¾þ� N¸ä({úóûC®¹LïóŸïg10,í*@¡4wTÃd©�u `àÒlÕà*€IÎæ ”kcˆiƒT†³¹7@¡4;‚é~û3~æ^…ÒÌIƒE ‡–±·¹3@áâô1#·ìl;uüï"ó$<^ªNÑ`·�)€9d¬À`yê`ÓôÌ`?Î2V`Ë¢�¿®-…3‡¬=`¬„4uèÍ5† >´a‚]`™^Ì_þaC‚/´Æ]0ˆÌB¯â‰·¤ÍSÀšZ™ N"ɽÉ×"¾ÂY ‰«Ï£@êìY絃$_BvØnJoï.ÏO,U·u̳ýÃ$®Ô·dæÑq%qåšÄ]Jɵ&u@vhõ@xˆ@ÈI3ÈY®×G›_WÏO]sƒM´7õ››?Î^þ€•…+ëQ£qX} ©ýïÆO2” ok ÞIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_left_pressed@2x.png000066400000000000000000000022031526321767600300430ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+5IDATxœí›KˆU†¿SÝ“1$Aˆñ…¨+Q\C·d�1ø]‰N0Ó’žv@|Ð6‰˜€øè6¦{ u4:ºH@�Ìtâq!ˆ¸Ð¨„(š ffº~m ªƒÑz\LÿËÿ@Ýs¿:}ï=UÕÐW_}�Ͳ¬ø§*Ž6kfzJ`H[;Õg⸮ÇE’Vaôå›0j‚<�Ãì鸮í<€Õ¥fÑÌ&AÁj�-o§F›Wùh°<è ü¸Æp@aô¥ËÌ4¬ŠÆ ×8ù¸.§†Fç›1\šôXÎUÀ ë·¯È-á=àÊ4Æs ÀðC¯Ÿ37°t/P úбä£rÀp­–ÿ}ðøÁÍ‘�,ÆE/*GÈŽ9¯mèî°o"ÁɃ#Š¥ævŒõAO˜@‰NP(5‹ú–Âä!c×– ¶-ꦕCfŠåæ½­¨¯”îü)e ¸¡q ÒžEÆ÷­·ð¥¦ÔË�Õxì–}> î÷§T\Wj\�Ø,‹„|Sú“‡ mzåòl Xôÿêì2™<¤àšòÎ ¼ÿCC—}�gg÷o”x7XmŸk:ù>pEÐWéä!á ¸~ü…¥fs“ÀP( Kô|&J Àp­–ŸŸÍ¿º1è«wÊubò�€ZÍ›ýiÕ.ŒuA[¸sçO)²â‘•ÏKz0ì»7yH`,–O ™˜{“‡˜+ Pj–‘m ™3K­¹9SÅ Xjl3´3êËð3ßëN£ø* ò@z�� {ýé¥×Ãǩؘ©Jänæ¹þú563­ê;H•¨/‘sB¬»@g¢ºÃ ô @ʹú&>öƒÐL»²¬v Pæ`SI™:}Dðf4�ÌxÿMÉ$T¯ûhpx71ä„Ä’94Qš—ï> sB¢‰š(�X8Ù½Sðy8"g~‰'ñÙîñ_½\îvà›HÈzÕ�­R¹ 3¯núÑëÚ­ˆBá)c©•áô®Ê·xº ø%è›ðz� ²Qª¿ÃN«ú¥‡wp"�y"©/DÓíÍŸøf÷óAß0OTB&+ñáVåà Ú<É<¥|fÎl+šiWÞÆØõMxiÈt/î´ÆÚˆ'C¦�¤\Z9d~éLTžCz1dš¡”N‹™Sçâc�šÙ!¥Ò78¨×ýe}1ò-ùÒ Àþz}aùÜŠû1DB¦ótÀþÝ#äXú–àÖè€ƒÍ±ßæl`-ðuã9à‹ÖÆŸ»yo�°ï“ËIŸîØü]­ŽEcqž�p°=öÆZ`6èÛÙò—€NklŸ»ø~0Î�)�Ðymì#உ.æ=›uN}õÕ×ÿC—v>ƒb‰ŽƒIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_right.png000066400000000000000000000010241526321767600261270ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÆIDATX…í×=kQÆñÿ¹£F F;uf’5¥ ­…¥¤‰•ˆ� ­…䈈_@¬E,±[D±´°¶ŒÙÌŒÈÚ(ƒÜûXÌ,¦sç…›BOu‹9÷ùÍ™[Ü�½l–‡FYþÅÀ"gý8Ž?w p3>wTpä—÷ƒñx<¿€ªìÜ÷Ÿ;χÃá�½H+ó‡KŠÂÀ›!àÊfV<�4Óê`& •kndEq', ,^·FY¶ 3óåÒîmdÅÕЀ �0ôè}–­† 1=‘Þmäùù €j šŒFÎT5E,àüËõ¢X Ø�8y½Îóüxh¾4°8�Á@•ˆ3Á‡Àfdœ p”÷‹Og’$ù0 ßÒÄ­,Çñz�Æ–¥iøûý“ïêt·åGŸxt¹Ÿ$oên°¯]xù®ŸJ“A“MšNÀ$U½Zë§ñ“†û4š€ÎÌ0ãîb’Þoµï„»Æ.¦q|»Mx}€UcO—Òø¦™é/Êÿ˜WÛß¾^ûs#jW5Ï€Þš›»´”žÞé"¼@[’ÙþÈ­öz½í®ÂÿÀo§ë—6“=v„IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_right@2x.png000066400000000000000000000021531526321767600265050ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›MˆEÇÿ¯f“‰„x1xÉv÷ôÌ®šk\¼Š!‰DÈ‹ˆ!à ž ! ‡DЀ"x0`¢(xCrJBHÂIÀ‹ ‚Ñgº¦A× ·»ž‡™„¥«Wv´ªºóƒ9Lêÿê_¯«êõ0a„ �R¾Ù“ý,é§KR¦‡«Žgµ�©Žz²Ÿ£N™m�ãàŠ©þm!LuÄÌ÷úb€ ÔY)壦ú·…1ˆHZ60èb·;xØ”† Œ€K6R-¿Ô ƒ:F1iÀJµL-ü0lt 56. À�Ô³üµk‹Üè­›páÏ\ý¾Û§ÛívÝ¢æØØ4@TXxëT½þÅeæ)‹ºcaù`EÅÅ‘1¥éqf6vù?X_ÐL Æ I¿ÿŽmíÕàdd@±¶IÒÁžLºÐÿ7í€ äz+¿ÛMÒ]ÅP†3xøSÅv"þ(IÒyWqqf0,’À𠂉Oü$å6—±Üw®H`è™°V€NwÓô1×á¸7`H™ ëIñù$I6» ¤*€Aš 0‰KÝn7rD• WËhl"1µÐéttBµx´A,ƒðPmÍÚ ívû~ÛêP##–³ejMýl¯×[gSØ�^7‡¨�´YmJÀkV(žˆ@GMixm”-{Û½¹9YÆhìÚ$1èSS^ €Z1ˆðj# >4¥áï%À¬ ž‡ahlð€¯@T21ôAM¿mZÊÇ (œøüy#œ~�¨ø Å„˜/ ‡,Pxiƒ@ç~_\|^ün `}𾪠<377·dKÖ ¸lð„ïT¶´+‚¿ljW¾� ¥=:*ËžlµZØÖ¯:h4ûËù…U¾½Ùlþê"€*3€ OÀ ÞÅqâ*ˆª (üŸPâ©(ž¾ê2÷——~‰ óq<ýµëpœÀ�4MfðsÍ0\pË]œ]+WvüJ3ŠN¹Š£ˆ³ PŒšÞÊo4£ècW1”áÄ"*œñ˜ñ~# +MƺfíˆûYl7ãbÙ¬ŸïÏ$að’ƒì ´;z„+Pù³OeuǦÅ™ÿ6»sgOÇ·-jŽ�›m�ñcžý½svvö¦½1p±þ¬òÚö™™™ßlkýLPöàò:Xíhµ6õ êÅÊ'3@À-EØÙh4¾7¥a[ŸÌ0�÷¶ÂðSýÛÂ\Ž”È~+Š¢/Mõ=a„ ¶ø‚¢HE˜ÚIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_right_disabled.png000066400000000000000000000010411526321767600277550ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÓIDATX…íÕ;‹QÆñÿ3ñ†‚ÙNP [ÑVÄr6Íjav°qQ4),d?�H𠈂�Ù îB6.È"ÎÆÎÂÚÞÂJ°q‰ x!籘 Ø™Ë0)ô­Nñ^~œsæ üë¡q’âzcPùdÚ]û\$ 3o¨z¨íÅ••Có`qÎßö÷’$Ù7@µÝP}š$I¥t€P0Xpeªó0¶$gknÅ—­R™ÂÄ�¸Þ\-�+!_ß�ë�«%À`i„àÉârs©T€�3 ÛÝÚrãB©€uÙ<ùdˆH³ÑAÒøÈØ¹J±Xt’«W ê� ÁšðÔ·§Ï¾ ¤g\Á¼2ƒ^Hå /ÙòÕd6OŒ£©\þ›*À �ÍÀô~:[ÈÙRñؽ¢Ü»¶|7Rö˜aíXôÞæ°¹j+¾7ÿ� ‡cÁ“�ˆžmÔ*ïÙRðx˜“áµÆ\ÙÚä P!wžã͹ÊB>A³‚9û�¸wÛóûvƒxV´]]÷øò˜š,•J!·Ã�ãÍ àÞ²Nþ›Kjô±gfV\éza3™ïg(µç»Ï�µ]jG¿ˆˆÀÁ=ÿ›^áÝK å\ËG»ˆhµèõ�áÏX7žZZ¨ü%‘BdôR&ϸ ˜Ò§æ§—Ê#*ˆMíK <òu­|F2y¢»ÒÙV½ò½t:Ò´¡É z²9÷aC8ò(ã°cjÕÊŸ çqÉc0 æ—õêŒ`R+ ¬§§Q¯FþLƽ¡Í Ï6kÕá ¹×Í _¬œ¿} LpûP2¬­]¾<Úy|y¹Ôq¥;(.J;»Ÿâ›Û{—ggÿs¥y=HÁ_•ŽgOœøWHoÝHp–•J5NNÿ- 506ïa?\žg�t«6ó‡E«8ùdf•‹š)Ó:YùÅ¢†uì}4…þW_Ì ~t©^þÁV|WXüjŒ�‚и à�æ\uÉVì!C† qÅÿ¡2½)�ÒIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_right_focus.png000066400000000000000000000010351526321767600273300ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÏIDATX…íÖ=‹SAÅñÿ™Dñ_:A+ µ1aKI³²Ye×FÐÖBöˆ,~Q°±�Í.q±‰I¥Vk#Ø(‹ø‚&s,æF,s“0ú—[ÌÌùÍÜgà¿^eP­?É(ôu¨³¨�Ó„QÉìöĪÛG×½3;à�šÙþÕ�¬xë_8=»¶Ä» +®d`"ÂXçßUâ-ì‘zhj clƒ¤ËõÕ¸œP”�˜ÞtµÞòRnöo„oÔ[¾� °Ñq§öȳY a¨?¨­úTV@B(’ÛÝ>Ñòñ¬€‚�šsw°ŸÌ¬ùpf(5¥�}qà§'×¼?+ PÄô58Øøq~@B ëX~€ …`£ZÑ�¬‹@Jÿ*:ý|Nï3dl5:sz;êÌêÄÑ8 øî 3½¦^•™?Ñ ØR>0Zè5õ¬ìcŸ€�$§ H—zój�³Î¸' ¥¦Ch©;¯{c®S`#îÜ×_œÕÍqÃKœ~Ò]—ow›áÚ$á¥Â!õœïw_†+HÎ H;gýs?\d¹ø™°Êނη:÷¦¡Ó/ØDVøf_7ôeZáÿ àž¤@—ñœêIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_right_focus@2x.png000066400000000000000000000021301526321767600276770ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœí›Kˆ\E…Ï©4A¢ ! î|¬{Ú¸0™€&Ý‚àƒ® $ˆL@\(øBÑ…(ŠÝó@&2Adzš²A\Aƒ % é[ÇEϨÜ*5�TUØßò.êüÿ¹UÕÀˆ#þÏ0Ô@•¦ž5´O‰”,�,7x8ÔØ1 fÀD³(@šÕQEpÇR�‹¡Æ�… 6ÒZò PÒÜÄ´¶?Á `K—6@útë¬n¥ƒ`�çòƱBÇo�ÑæP:¡ ·þ™ÍÆjaËœ6&ИÀ�ã…ŽÝ>« ‰ô.˜h¨¼$„­½B3“óº<–æÅÍtêÂŽÓ]½¿ýs�ÇÒ”¸K@°p‹c½{Ú¾)ØäRHQœ™ ò¡jË>Ÿ@û?IS«rI T¦u ‰þ¿�ji çšôBµ©‡SÅà#™�|§Eˆz£ÚR=Y%Ò€þiÑc‚ôAõcÝ•2–?ÅS Ðêîðw.5sÛ´*©ãIn€ž™@\a¥ùjK7¥ e8`­yby&\#èø¶¦®KÇÐ è#Ÿ ×Ô¶–6¥ˆ`È}T>-^_@Ç&æuelõ Z§ynQWsÛßѺ˜Ê™°Ú<•L pǹ«ôaÌæ)Vñ5O÷vÏØ·ðŒ¢Ä𛀝y¨Ül_ŒÑAæh@¿�.ÕE‚OTZ8Z*O€t›'êh¥©ý!eò5€[®¤^›hj_(�¬  ïÈ Ô+¡4²6è/{Á¶Å¼ ègïÄ(èíPÙ<�õ"�¹×øØrüJ"ãàMþévƒÁ’r4€€ã¾¹×Ëí:Ž„–ËÎ †*g¯÷Ú'Ìã }/`/‰¼ K·žÀ'½SæAvž!' œ;�/ØãÔÊ~ž�%šÉ. ãÙñOôz¼geŠçb*Ý�,O{ßaœw¯Ôy6¶þP—@?y§Ïÿ‘†;Û{øSІg€àKþŒµÜµTãÉTa Å KÚÂïwwöñë”±$¯ÈròÀyÖÛ5.¥Ž'é �@ÊÑÉûÛ5.¤Œe�t3€„gÍä£K5~”,ŽÉf€dÝæ†<Ô®ñÍT1øHcaèlõz©½CÿL&…îWzw¹fžŒÑÜ J\úÕ¾|Ä�]µy$‡ä�¸Júš›Åõgyßâ�ìÅÒ”h»€s¾¾Â:îY¬³KóbHµ |;N¶wó×DzL ~èõ¸óË:N 50!˜ð=Áÿ…க)~J'4Áj]3³âd§ÁoBiÄ äøë™!Kîí4Ø 8~Bþ4u@ €ø\§ÆÏ‚�=bĈ‘ønþN~àÆ%SIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_right_pressed.png000066400000000000000000000010761526321767600276630ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ðIDATX…íÖ?haÇñïó^b¥‚Š]DœüÌàà(]ê$ÁEÑEÒÚ4ÁQJptP’Zk@u‹[ÅÑ¡ mÄÅÉ¡“(HK‡Š5Éýî²8Ý]ŽË ÜvÏûûðÜûÞüëeQn:]®o€Y¾Û9²üèÆzšñ¾½ =�\®uüò�]ÃôëÌÈèÈËc¥¹Ã Ý7ö¤Tzáeø`.®�}k€"í¡Ô¾$¦Š“õZ¦€a’á»U,7f3˜�P€@÷ŠåÆ¥Lð×$ÐãÂäüD¦&�à9ùK…©úÙL�?Dìt>­âµ»'³„Éì–ó^®ß?š-0Sÿ±ßz½·§*�ƒ™‚ N†Áa×Ñ«!Dˆ81€90k½¼ŠÒ‘K+Zà,ø6|—ç�û8?ý5J_ZpüÜl:o/L‰Ü˜F8Aø/ßqþýÃê§8̓> ¯žo®Ô~Pyw�Ä�Éúý†]m/VZIÖI:3™�˜]iÎ,Vç � 0p {¾z`}&|÷T1÷€aðfkãÇš5Ðpˆ¿–·n_ø¼Tû�F8Dœ€`ÓÀòÝîÄÊÓ›[i…ÿ/€?”¢c�Åû‰IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_right_pressed@2x.png000066400000000000000000000022121526321767600302260ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+a YÀþ¡GÞZaSÛ @…t&·Í•~}ÏæåÉ’a‚àžÇú÷ Ñ°«_€ˆbêIòáðèÊ—lÜ ý3„€ Ô^1>–›O™VóЀED$ÑÊ¢`{X�*&u¼5€2ºE€˜ +Ñý¦t¼5$»eMS^àLuÏØcÑ›—“Y,-=k“Þ4¥á¯(¢�Þ�lj·jo˜’ñÔImñ¤<7›[<ào ´�D�xó6ÓBf€zåãÛí+~Ü’ñ�á¼ñ+mñ~H®X�ñq½'0€GHAjñ8T¼0y Wl©úqˆrúÎøœ\~÷§;ë¿Ù”ö!$½ó ¾.&êÎN\ùÙ¶x®p±× RƒßƒdÍg{ÆŽ¹ˆ!Ï# ¢oÀOÂ`íá]õo\‘KP2v8¡ÜÕÞ½ù —±äa€5Ýó“õîƒqüq”Y;O>Ô‰ëS.cù §5@ ºádµÝ}ße§â2 韞‰Gc‡1h81€Y;¼ÒnÕsÿ™Œƒ# �@ëòövZµ'm\nºÅvdÜìðAß•Ç7ø°xÀb�$ÝâÓÿÑ÷àôxý¤-Ýn±ùCÉôâg %Ü;½÷Ñßmiž ®ƒ_Í˲uGš#¿8Ò;k\ð©Öi�üà@«kLþa"ëþqUHÖvâ±oMé˜ÆXdÜìæD©u³­-_šÒ°�Á øç!ð¾öî±¶©ùmað_cÁv!@€/´[£Ÿ›»G�=,ñ'¯C¯^ÎÃIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_up.png000066400000000000000000000010051526321767600254350ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+·IDATX…í”±jQ†¿sGBˆ’h½dÌŠÖk±•âˆIg# >€¨¯ �`ð …ˆ�ÖÍlifææfSˆ‚6š½¿ÅìĈ»1;.±™¦™{ïù¿9sf ¡¡¡á?cu†ZûÒ[D'1ZišîÕ©ãêÚáÒ~TÑŠ­!\<�<ß½ìbì+ Ê‹•$ª—e»�iëMõ ²��k&6€E@‘RÁ�j}•±v!Mß·æ±;°íýª‰Í*ˆÏ_ŠX2±YÅ�™ d>ÜqØk`¾ ³­’˜—¹7EnÏD ÷þ�¡ç@š~ !! ‘éEæÃýÚ’,÷þ1Ø“ª8ØQá˜ÍJICë¹÷�$Mœµ± ’\º‰{’0³ª½Ó`’œ™aÆÓóËËGuŽè÷ûs§Ï,>ø5ºU'üpý²ËâåçOïv»ÝƒÁÂ÷áðâú ÂeÈ��ñn.In¶Z­oxïÏEÜèJ9kDÌþ5¼¤œ‡‚-‹ÃÕv»ýàTµ'ÊrLK¥–AÍßôXìW£ ®šK àìo!“çtöüõSjhhh8I~Dë±fh›?IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_up@2x.png000066400000000000000000000017471526321767600260240ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+™IDATxœí™ÁoEÆ¿7»„Z. ‡ÊñÚX-gʽ¥"ªz"9öUPq¨BBPÎHU›rC¨è©µ”CýPÎ8 ÉÎîÖê!åNZï~ì¤öîàØÎî&¨ó»ù�ß¼ï½y3žI‹Åb±X,‹Åb±X,Ë«…U`­£  Dp§îy7ŽBÇ‘`;ˆ® x €Ú³‘rm©^]+[‹:ø+ùâÁuo§c‹ðŽD_”­§´ )AÝ$ñÙxAü¡æy×E„eè*¥mÒ­Ñm>šÈAð“®V?¹ Ò+XZñð}âüÁ‡ÃöÁò&ƒ�*#Dpq|¥ÑhüS¤¾BÏ€ÍÍÍ7 ÔÃtò ¡€X @Ä™~'V Ü�ÎÎÉ"5Ö›OŸ¾é<ÑàÝ‘ï÷À蘕$Àãs¯]nž>½S„ÎB °µÕõ”Û[äÌh4!€s¾‰(�)]܈]÷ƒ·+•(o­¹@kýD­XLE"¸¿çB´EHâåF£ÑÉCçKY9²†ï)¢àTj¨¿òÓa*Â߉àÒ[ž÷xV�¦ ¹ÁE‡xSò2uòø¤÷Ê)‡hk­ßŸQf†\  u´š@81l'+?Ë•¦ï“ æ6Ÿ ¨–ÖÑÊÌ‚‡8t´Ž®Rø+€¹a»™eåSüÇë;nÐ÷ý³PÎ:€jÊÉÜ‚GˆŠé|!{ÎòÒRecŒŸ™­0<ç- )‡c—üKDõÿÄ0dž x©V«ýaò0‚Z?¹àítò�qòÀ©·6�…hû~tÞä‘é†7@|�i§ÿ9Òÿñüªîyߤì£è ìpÊ“VÄõšçÛJÿ¿Àq#S€Dð- ÇxŸÏŠ$ýÜ,‹Åb±X,‹Åb±X,¯6ÿ�–S^ÀihAIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_up_disabled.png000066400000000000000000000010451526321767600272700ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+×IDATX…í•=hQÀÿwýÂÁ(-:t)Úê±›¥PÄ$”ÆÁæNð Á&Ö.Ýœƒ›{· ÒÍÅ¡JD¬‹é"ØQ'?&ÇÒI8Ï{‡\lBªM«î·w÷ÿø½{ïÞƒ””””ÿŒ$M¼äÝulô4KhG_?ü5I“$)WZœplØÍÐ/oaüŸä¼Êyˆ c (2fU…«w³*PpËÓX|à ‘@(ÊIkŒ_pËÓ"�w+E«¬ƒÕæÀmÛk ª@Æ*ë—çæþª@®T¾¥ªkÀª*�ÍcĪ¢À�ˆ<Ë»•›½Ôvö È—ÊË@ 0ŠªˆìÒ}Ø|›T@r¥ÊCàQ|k¥µæþŒŠÄ>Âìø¹ òñý¦¿/�jµjF&V€q©Ö÷Œì\fNŸ�¾}íÊ+ß÷»jtmDžç lÛÌ*p=Ùwó¶òÚZgO¶†Í�wµZø[�bñÞ‘`0z 2‹F,š´ù/QUÓl¤/Ç­×kߺæn,ÿ„uàbüÈÒÛœï퀈î|‰�0úQ|³¶º Ð× ‚ð³@¦-/Ñ6½Ú9Ž©~§ï p¬£IâS)%%%å°óÿšXð7Ÿ IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_up_disabled@2x.png000066400000000000000000000020621526321767600276420ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+äIDATxœí™Ëo[UÆ¿9¶K¡B$l© AjÓvã´¬��Kì‹ÚEZ?²€,ÈÃüˆUØTB¬BB¡$,²0�¶ Œ¬¶‰ha(ÞÕT*F¢Í XTUÕ¨±Ï°H×÷;~Ük1?É›™ó˜ù “o¨ÔÚžö*0�0A)A)`à¨ðj­íé¿b ÖòŒ¢W€CÆDœKCt¶WôJ­é‹#5P_ôMá60¶LÜ#ˆd3“¼ÔhùÆH 4Z¾‡ý¨Ô'¾ÅFÌb¨?k4}·¸[õV:kü(ÿŒú­xnEçq–çÍô!ö®—}ðƇz5Î�î¢6¦½Gœ½� ûñÛ�á>³ýô81ï}“øtÝY¦( '¾iÂ2?ï} ·Önk}W§^ø@Òóp!·"CV>�C.õª—èÚÚ%ýè3pnÙG~v½,qÆ€L¤`å;ÙÞ :]iæý}H6‚Ö»þ$1¾éJÅ~ÓƒÐöAŸÝoÖWàÑ»'ì§URRRòG~Qãºr”/rÅIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_up_focus@2x.png000066400000000000000000000017361526321767600272210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+�IDATxœí˜ÏoTUÅϹóÒÔ1J݉.�uÛ™1Ædª�˜.´Óì�ýTâ‚bBü±6!P`EL ó¦¸`’&2$ØÈˆ¬Õ5î$ã¢UÚ{\Ì€Ówo;¿Þ›©x?Ëûîý~Ï÷¼ïÜwï�@ �@ �ÿUâ|EeR_0�.4r§G¡c$c�t€y,D”s$?Œ=äìí£ü5 �™0yU/F‘VHd»ãîFÈÑõ³5<|wŽ÷S–š¾ÅX‡­x!ñH ,:íí$ºÚîË#߽͟ÒS›ò9`º¢iA·á+]ßšIÀ‚ÎìýÖèÛü’¦RÛ"5¦«zÝP7ìkÔ,¾W 8&ì£Q=ëµ¾…&HÅ€b¬y#ݰ§}\�ö^ü¿X4 lg¡Z¾¢òq3°ùªNº`¬}\ °ø´r㌑Z*ÄzgÐè��õ¥ÅdœfñΛëBò˜`],Äêp´î»$cû©Hçò"ÀÒýí¦áyi‚>û¾l>êçþг¥º¢õßì9‘'\!™ßÌ!�ôš°øÒ†yïÚÑíY~z2 tYãkÏè €ùDöfñî§+$�€ñ¨�Ÿç±Ú,ÿê6V×¼r]Oolj€ó j]j†R|[No'ø&—c¹ÛûCWL~­‰hS5[!ÀÞZ.UHÀÚ¸µ wFœ½÷&t ÑiÂô²ö«�ú;àd�ÿþð#Ä#�þ²ÓÒ?ƒ//é ±ZÅn.ØîÔxˆF«S×uÀ·äÛv@~IS4ª˜pÒí¦âÛñwÂ�o4ʼç[âí€BE34ª#Q¼vsñмj';aR½XUÉ·Äé€BE§atÆãäp·ùqÄ‚åÇ�~²ã¼bl7øþžúÏC`óμ‰ÚÇ<'ª'_mî@žmíªO‚yvÔ2�@ �@ £æ<�P};×£õIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_up_pressed.png000066400000000000000000000010521526321767600271640ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÜIDATX…í•¿kSQÇ?ß›hJ«*µ«.‚T’Qél‹�DQp2?+þ!›“Å…fêæâ  T»ìRÔ¿@§ªƒâ$´Mîqȳ©iªÍkÄå}à ïÞ{Îùpî»ïBDDDÄFaÏäï�®[ü¥`¬¹O£o+·WÃäqa‚Nç_·øÁ€Û°¥ÔÍGÇÂäê¹™³§p±×ÃS_œ_ž›yßK¾ž:�*”'ÌÅjÃ4[� 8â¡–*”'þ‰@*_™vžEà€�!|{Ö¼™ ržÅt¶|¡¯™ÜÃkÎü3`0±µx É|Е‰ç™|ùênrÇþ¶ �-Ï ª�¬Ñ¥xÛÃÂGÆ'¿}ª¿Z)`Jç’%‰{Á€þŒ0$4u43©Õ•…”vXÞ�bÑ�N–�[´ªzí¦øV}LB.x©¬Œ|½C©´}ë:N\.î<œœ®˜ð²ÞŠoJÉ6¿³'f‰ëõjncG�tvnPní)Æ&ój±ÐüÖ ±`>q©^ÍýØ&p²ðøPÂ/0Î�{.Þ–@jŸ¸¥ÆZsúÝüÝïñ_‹¾ñj›)Ôoºû|.žˆBÈ»`ïô¥±ýá'h꘠^nCÞIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/arrow_up_pressed@2x.png000066400000000000000000000020351526321767600275400ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÏIDATxœí˜OlTUÅÏyO‰…ÔDª%îÀ¥}oêÂÄ t¡”… VÂ̈±ºÀ°Â±1!!�ÈÌ ŠHÀ˜5ʪ%�P¨‰iG—†Ä•ª‰’˜©ßý\0•y:�o¦â÷[¾oî½çœ¹÷Î÷PEQEQEQEQþ_°S ÷ç ÃFx €Eà£ÙG�tB‡Ý‰EÓ¹â~`€.Ïmvvþòkéâ·íÖÒöœlñ0€B»�ä‹=é¡…ù¹É™vêicB'Û}œÀÛU>´£ÇÝõÈ|iâ+`¬-ªÚr äóÝúmã€#5 œëÚ|#{elìï„¥%ÀÀ+ç¾µöægv‡k1AÀŠÖøåú;]{¯|<òW’ú à™×‹üE\°=fer_…ì°—SwvÏœ;|3)�‰ðôHñQ{ &A8ÁŠ «DÄŽ‘4ç/bè»ó£¿'¡3‘œÌÉ-¤5`k¨$Lu9bÅèºNÛÞ1ûþk?µR'söš¥ïà{O‘Ö ê6¿ô€*lߟq2Þ¶Vé\¢¥¤œL[¾}ÀÁ k0_‰Â!ô’r­?ë¹MÊ Ð²ÒÙ bY—lª|.¤óe»6Èt_Î{¾ ©Z@:[Ü#àîµµ•YÏ7&v'tY"“ý¹ÂpãóÞ§éܬ·_€q©@ážñ&ÌW�'e„Ÿ»¹â¾f§oªv3Å·@xˆÜÚ·}›B0¸¼ô¸»óö|éâ×�ÎÛ`B7³ñÈw"À°Åæ�²s †Âæ`�»kÝ|iâR#ïu÷å¾þ4Àýáš@1Xƒ %ztIœ}òÆc¹ññ—£MVê  Ü× `OT˜J²æ+Ö"…q÷צ°÷oôN­sÕÀ³ûŽ­_\³î‚ÁŸ „0Dä¶N��ˆ áÒÚ» õ¾?Ô€“9ÑM¦&›�ôÛê<Œˆ½0+fq¨tæÐ+ _1€ôÁS½âûSBm(kp@@‹� á÷¶‘ÁoÎŽþ\mlÕœŒ·�”)½¡¤ió®_Z‡üË Î}ðæõåF-Ûõg=—”«ˆ5�Uf(ïÆ°¨-0Öµ¾W NÜ`™œLa»�Lè,�%ó«#Ѻ-Ãi7ç Ä ˆ�t®pDÄ‹ÙNÿq(¤ÉÏž~ãÝʧÑÿâ óžy Ü©äÃO£Gà´þ/1Þ¢;€<*­x‹[e`„<ÚiŠ¢(Š¢(Š¢(Š¢(J§ùîs?õ¢WIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/base_icon.png000066400000000000000000000023501526321767600255250ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿ�r1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDY�Ø !Œ�qÏ¥¬�¬•Q¹ �Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý Ì�Õ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ—� ´/Imеá–]ÃtåH½I±Î¿� ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ �º ¦®œfÚ×â=åï1ChLûc @P× �Þ¹‚2Û ‚ú»56î{½ýÊ�Ž|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>�kÏ–¼¿Ú…í QW Ömõ°gÀ0�}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!�{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þ�o2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕì�Ëiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/base_icon@2x.png000066400000000000000000000063261526321767600261060ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{�ý£}*P´A�6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„�ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w�¾ÑþÜ©�*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾�£ 4�Šï?÷4Tý÷%p—§P9òmS¨ �ŸÿÄÿŸòmh§¾})è{îq1o…R’-� ��@V�1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö �?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0�ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "�œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r Î�›B}�oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™�~‘ �ßx+¶ŠQ@ɘµ¯² ®�]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö�¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=zá�ê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§�.Hxfû:VîGèÊ­c �¨/’Ñgîä§ñcXy .*P�FÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦�U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ�¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ ò�ÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t�˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'�Y 1a5rIH™Gƒ�eOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàK�ª'à%¸C4Ós–�ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤�)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·º�ôHe H .åã( ¾óGF{e%´ò�œ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 �1�œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! �Ñ$ À£ý2b…»}�4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌò�š¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa(�[9ÆHrç9my"è“Þ')ƒ�óIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ù�æ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡Á�ÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœ�á%^œ(Ιew1,S|¼’…œYµp†*—rA†8î�»÷O·ýWÐ8Ósúc�¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ�×í+rJØîí°õKU\²8ž¯/Î�]�I�#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— �—¤ NÑøü=/„a‰!­5 �ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N�÷óÖJ>dŒ¡C� #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ�¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ�¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf�"NT€ì£µ?÷Æ— hÝF�›%à¹î°œ�Ÿ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿ�FfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­�À}LÁÑ÷Ùë9qž¶øÌ�“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­ä�Ÿ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ� /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ�¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/base_icon_disabled.png000066400000000000000000000023501526321767600273540ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿ�r1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDY�Ø !Œ�qÏ¥¬�¬•Q¹ �Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý Ì�Õ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ—� ´/Imеá–]ÃtåH½I±Î¿� ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ �º ¦®œfÚ×â=åï1ChLûc @P× �Þ¹‚2Û ‚ú»56î{½ýÊ�Ž|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>�kÏ–¼¿Ú…í QW Ömõ°gÀ0�}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!�{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þ�o2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕì�Ëiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/base_icon_disabled@2x.png000066400000000000000000000063261526321767600277350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{�ý£}*P´A�6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„�ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w�¾ÑþÜ©�*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾�£ 4�Šï?÷4Tý÷%p—§P9òmS¨ �ŸÿÄÿŸòmh§¾})è{îq1o…R’-� ��@V�1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö �?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0�ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "�œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r Î�›B}�oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™�~‘ �ßx+¶ŠQ@ɘµ¯² ®�]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö�¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=zá�ê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§�.Hxfû:VîGèÊ­c �¨/’Ñgîä§ñcXy .*P�FÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦�U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ�¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ ò�ÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t�˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'�Y 1a5rIH™Gƒ�eOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàK�ª'à%¸C4Ós–�ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤�)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·º�ôHe H .åã( ¾óGF{e%´ò�œ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 �1�œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! �Ñ$ À£ý2b…»}�4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌò�š¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa(�[9ÆHrç9my"è“Þ')ƒ�óIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ù�æ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡Á�ÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœ�á%^œ(Ιew1,S|¼’…œYµp†*—rA†8î�»÷O·ýWÐ8Ósúc�¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ�×í+rJØîí°õKU\²8ž¯/Î�]�I�#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— �—¤ NÑøü=/„a‰!­5 �ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N�÷óÖJ>dŒ¡C� #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ�¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ�¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf�"NT€ì£µ?÷Æ— hÝF�›%à¹î°œ�Ÿ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿ�FfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­�À}LÁÑ÷Ùë9qž¶øÌ�“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­ä�Ÿ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ� /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ�¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/base_icon_focus.png000066400000000000000000000023501526321767600267240ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿ�r1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDY�Ø !Œ�qÏ¥¬�¬•Q¹ �Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý Ì�Õ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ—� ´/Imеá–]ÃtåH½I±Î¿� ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ �º ¦®œfÚ×â=åï1ChLûc @P× �Þ¹‚2Û ‚ú»56î{½ýÊ�Ž|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>�kÏ–¼¿Ú…í QW Ömõ°gÀ0�}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!�{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þ�o2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕì�Ëiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/base_icon_focus@2x.png000066400000000000000000000063261526321767600273050ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{�ý£}*P´A�6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„�ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w�¾ÑþÜ©�*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾�£ 4�Šï?÷4Tý÷%p—§P9òmS¨ �ŸÿÄÿŸòmh§¾})è{îq1o…R’-� ��@V�1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö �?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0�ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "�œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r Î�›B}�oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™�~‘ �ßx+¶ŠQ@ɘµ¯² ®�]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö�¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=zá�ê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§�.Hxfû:VîGèÊ­c �¨/’Ñgîä§ñcXy .*P�FÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦�U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ�¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ ò�ÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t�˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'�Y 1a5rIH™Gƒ�eOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàK�ª'à%¸C4Ós–�ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤�)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·º�ôHe H .åã( ¾óGF{e%´ò�œ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 �1�œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! �Ñ$ À£ý2b…»}�4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌò�š¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa(�[9ÆHrç9my"è“Þ')ƒ�óIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ù�æ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡Á�ÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœ�á%^œ(Ιew1,S|¼’…œYµp†*—rA†8î�»÷O·ýWÐ8Ósúc�¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ�×í+rJØîí°õKU\²8ž¯/Î�]�I�#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— �—¤ NÑøü=/„a‰!­5 �ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N�÷óÖJ>dŒ¡C� #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ�¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ�¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf�"NT€ì£µ?÷Æ— hÝF�›%à¹î°œ�Ÿ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿ�FfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­�À}LÁÑ÷Ùë9qž¶øÌ�“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­ä�Ÿ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ� /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ�¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/base_icon_pressed.png000066400000000000000000000023501526321767600272520ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿ�r1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDY�Ø !Œ�qÏ¥¬�¬•Q¹ �Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý Ì�Õ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ—� ´/Imеá–]ÃtåH½I±Î¿� ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ �º ¦®œfÚ×â=åï1ChLûc @P× �Þ¹‚2Û ‚ú»56î{½ýÊ�Ž|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>�kÏ–¼¿Ú…í QW Ömõ°gÀ0�}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!�{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þ�o2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕì�Ëiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/base_icon_pressed@2x.png000066400000000000000000000063261526321767600276330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{�ý£}*P´A�6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„�ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w�¾ÑþÜ©�*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾�£ 4�Šï?÷4Tý÷%p—§P9òmS¨ �ŸÿÄÿŸòmh§¾})è{îq1o…R’-� ��@V�1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö �?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0�ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "�œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r Î�›B}�oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™�~‘ �ßx+¶ŠQ@ɘµ¯² ®�]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö�¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=zá�ê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§�.Hxfû:VîGèÊ­c �¨/’Ñgîä§ñcXy .*P�FÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦�U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ�¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ ò�ÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t�˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'�Y 1a5rIH™Gƒ�eOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàK�ª'à%¸C4Ós–�ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤�)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·º�ôHe H .åã( ¾óGF{e%´ò�œ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 �1�œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! �Ñ$ À£ý2b…»}�4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌò�š¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa(�[9ÆHrç9my"è“Þ')ƒ�óIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ù�æ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡Á�ÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœ�á%^œ(Ιew1,S|¼’…œYµp†*—rA†8î�»÷O·ýWÐ8Ósúc�¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ�×í+rJØîí°õKU\²8ž¯/Î�]�I�#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— �—¤ NÑøü=/„a‰!­5 �ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N�÷óÖJ>dŒ¡C� #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ�¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ�¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf�"NT€ì£µ?÷Æ— hÝF�›%à¹î°œ�Ÿ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿ�FfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­�À}LÁÑ÷Ùë9qž¶øÌ�“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­ä�Ÿ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ� /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ�¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_closed.png000066400000000000000000000006121526321767600263700ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+�"ô™¦ùYUŽÄ Ö¾#¤ êBÔâfM¢çð—Ù™Ž8=ˆø3+ù8‰®˜ªTvtál̨š·Ìm²ý¿‰ ôõÍ…„Ý1£ÛõÈöO¼è7Í÷ ‹�’í½) „áT¶›¢€r¹¼Fjbõ„^ËöN¼€J¥ÒE©ôcùF�7ò–‘íŸhÌœªá8€=�:�ïXB\W‘!Ñoú6€£M"ã©mš—ˆ(ö’´Ñ$V€íº£�6‰„·‹?³'ªr$rrÿ8?lô'`:eÐ^!DEeåؾ?Œˆ'dWT^`ÃØWâ�êŸwdzj4�F£Ñh4�F£Ñ´ãoÜíz5ïõIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_closed_disabled.png000066400000000000000000000006521526321767600302230ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+\IDATX…í”?KBQ‡ŸW­M¬!ŠZ ·lrtp mhºÚAß IÎÐÒ'¨Tp 2�†Z¤¾€Ðä”ÔÑ�SCê=MZ�÷\¸K÷Ù^8ç÷>¼çøøøüwÄéú´U°£áìýMµïV àdq±XœOC¹\.è©€RÊFôö¸îÛ‘¡§­zåJàx\g¬Â££>u;íX<‘–�ùØJb¡×íÜ™d9½„H[= Ò4¯ËçN3Áo’«K“ já,³•Oy* ”²�éð�„I)ßj6ójúcBÚ쎆G@x•ɨ¢Zkº(+‡›L³wCÏß»·ï' 5†Ñ¾-e»GF‡ž½’™�° ˜áÕô6'Œ:¥¼¼;~*3‹%€WÓGÌ?dÙ†T"òIVË >#ü¤+]O¢—3f³¥ÆÒ}øÛZZl¦¯`é)Hº9–0 f³Åt�ÙÌ«éßed°ü$Öw3ø•0¾Ãd´ªJÓo‰ö·¼Hv†9A�Q'À1ÑÞË¢ œ[âk…©Ïa}=ë2õ‹ö¶¼€ÚÚfµ#`óœÇùT,T!ÚßÒü~¿mÚÁ:@°'_'à­©x( #ƒ¥L°ÒK8’¯‚ÓãO0=$-5…›ÎüÊ\•¼pfs•2ßYó0Tßt„Ç þsÔ¾·'zmLféTkÍ嬀sVã@šûÅB/eç‘úà©ots°»È»x3”A³ââ‰òŸ\Cˆ­ Àœ³??•ì ¥då0"¥Ÿ¯Å‘cä¶åëœð ÉX8"#ÃB/ ÐWæ:* £o‡Ï‰ö/„ðú_��Åìƒé³O9uHÚëÿ…Ð]Àçkq̸2Jòä7ÅŽ¢Š{W¥<ïBè ø²é7ã@6_²åì5ËåâÁ¯Å? 0wÙ®aÂáá%uÉxð­HO…B¡P( …B¡P(ŠBüêÝSçIòIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_closed_focus.png000066400000000000000000000006131526321767600275700ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+=IDATX…í“?/Ca‡Ÿs[ÁЈoÐ]b»ÚÉb4H+lÂfð $:X|ÒÁªôv1K,¢�Ô,¢“„Ôû3PMl÷½É]Üg;É{~çÉÉy!##ã¿c±^KVjɼ›MÞT¬—T ˆõzg(<*½.5”KW fNØò |Ì«Ÿ®Ð©Ú©Ðî .E®›ªÀ·Dn ¸ø)§ËÑ羯@¼#üC)r&Ùz»bGq3¼60 ÝµáJ‡aS³© P37Þ·Âo˜é2]à>€{ßþd’F\(Ï9Y1U�rä¶‘­o˜Í_-ÚCÜ ï_0iÕÐ1à„-tªvî“ãµ�°¥9Cua¾Ã½Â3MRÈ›´×©Ú�ïðø’�À¦“ëÛ`3Ép€|܃'àn¬¬Q3—T ###ã Fpb¡›SjIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_closed_focus@2x.png000066400000000000000000000014521526321767600301440ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÜIDATxœí™OHTQÅÏyóÒÑ IˆAP­ªEá›0!"%g,#ZTA´iä¢v´ÒEHXŽæb"m¡�ÏrQ!Dÿ% )øÞýZ„1ž ‚÷¾ û[~æœ9ï>î�;€Åb±X,‹Åb±X,–ÿ ê6ðraÀS@òÜD†½º=WƒÖöHr¡AJ†ÂC~Guú®G맯‡[1£Œì{ Ûµú®¯€’¨¹›à†ñ4çuûWCï °5`å*„2‡nÑî_ íîw2D’ Qš·GBÝþÕ0òü6Î9 îˆÒ¼œ3‘a%Œ-ÁBšoy8Björá S9Ê1ú>Ïð‰�+^Nåä´É,œã0MåÂ^Ï”ÏÒ+d8i2K,€—SïTœÜ·Œ§ùÅTŽØ V>#8ë �\ˆÒÖšX÷áàk¢æÊ•Ÿ1òpb-`ª‹K�ËMQš7(ßMdˆý$6uŒ3!¸+BjðÃ{ºýc/^dù`{… <©ÛûŸ(…éX|ã0-Ç{(›%_>Á3ÝÞ±°wXêÊ0ˆm%åÚd‡Ó¬Û?ÖNôK ¤@S©"·ýv§ÛD†X øàª›ÒÅ3Õmt.€Œ<$­5ñ…åDn•�_º ¶˜¼)Š¥€¦É�2PæÿÉ ˜*tò³É,Æ H ‰'JFÔ�ç¡xÀ?ÎW¦ó$Lšý¾ –ÅWdÀ´ßÁ‚É,ËD^Xê`¿4*GòÊÎþìò³|l*G9Fv�Ö¼Ô*W†ì,D®ûYÞ1‘a%ôÐ-Îì¢êÐR*È]?ë\Õî_íx»qeù¿Á"ž6&�ó¦öú¿¡uhÍKíì¢ü�,¿YWÃæ±£4ò{¿ZWÀ×�P–ŠG$Ûþ•/h.`ª‹KϘ0­È#¾×éi±X,‹Åb±X,‹ÅR�_D”̾Äù «IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_closed_pressed.png000066400000000000000000000006371526321767600301240ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+QIDATX…í”-HCQ€¿ó6gÑf,¾U‹˜M³jqOÐMŒ‚à^°˜ÜÝÆÂª›Y°Ï¿dS›ø“Š»Ç´‰ñݯø¾vàü|Ü{î…˜˜˜ÿŽKWq½]ðýÙºª¯}„peoºÂÉžÄ{&ÓHD+àûFUæ:á]êñ;Z༚;Be«»ÙÒu¤ÍjnCàaÂõж—ð/®WÒn ê5««Õ =¬N Csäõw E*iog*R|ß´‰þN¨8gÑ ¼<)ÜÛ–‡Pé® ŒOí¤3´C¨�Ä]J@ò@Ë8:s¹Ÿ¿ ÚÃúLf‹ó"RŒgö¢¼rbÓ'iS”öŠÓŠÔY¶;�^ÜWäH¢º}^É•m‡[¨Ç4€Aà°9ú¶f8X\�Àƒ ·}Ÿ øyV &&&æž5a7 meåIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_closed_pressed@2x.png000066400000000000000000000015431526321767600304730ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí™_HSaÆŸïœÍé +’¼RŒ®ºÚ™V&D¡7aÑUFâQk³$è"hu™m‘s�zI&ÙEeåf”Aöç¢4DK4ûûvc1·cCðûŽÐ÷»Ûûžç{λ�wg€D"‘H$‰D"‘H$’ÿ Æ[@Ó½½Žc81ìw÷ðÖ\ \ØS×�ûË6N­ÑÞP e�§îJPx¾ù”}Á’^cŒ=ÑšÚJyê®2ªÛbáõÏ»ÎÏóÖÏ× €’ESkÞ<îúÙàn ¯ïHBÍA¾QOû¾!Á[?B®À+Ÿ{.©ª[�zšî}&ÂÃrÁ‘›§ÆhŸA«Ò¡û®ˆò‘Ž*Rl"4ðy‹³z@Mj�»Š�ÕãÁG£"ý,j‹ÇÙèë!¢ã †Š ßýZ¤SM÷}(cHXYñ›® Q>L X~G°Úãö¡k­a£Þjcê}˜È–cT�-XrqL ÐcDÑMF=M÷ýáÁôM,87 FÛ Zùšî½Ã[ßô èoyÐAƒÖQÞÚk" RÆÌÐ]TÔ·ofŒú3 /xk›€£¡ÓžP•JRëŒÑ¥ ß]É[ßÔjk戴Ez”§Ö ¸5ìw{Dx05€O…“WH+¬+ši˜á’´Ú˜¶ :u_ �ÚSk¼Í�…«D>)2%€òÆë‡’Äî¥éµ²øŽ!ë7‘^„àhh¯`L�—RžO*ÉÝ#gÞ‰öcø¼ŽZS[)HyZrø8 ép ?< ðKpçɶB$-ý ,Ýýô`çéÇ¢|¤#dÊ\^[<Šû¶¥ÖpyØïîáa9øO€Ç£DÑM@ÕÒÝît]䮟î8&7^Àâƒ)<�Íaõ¢îõÿ‚ë] ÌåµD1 ÷o‘؇ˆªVŽv4 ù½Ÿ ®�±%Äþ¼fÀ”E‰×¬•ÜôêLC2±ÿ¥ÿìžš‰D"‘H$‰D"‘H$Ùø Y›Ú ñ"OIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_end.png000066400000000000000000000002231526321767600256630ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+EIDATX…íα A‚Øfb¡È“„!ŒÅ_oë[3¤´RZÎGwÆ7@@Àó€á_ÄLéM@Tí ç|àל 9™¥�®IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_end@2x.png000066400000000000000000000003131526321767600262350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+}IDATxœíÙÁ € A´ÿÊl‚`#XÆš0ÓÀÙpcŒÐ\ïžëÝ冻<þÔjÔjÔjÔjÔjÔjÔjÔjÔjÔjÔjÔjÔjÔjǸÊãõ×øý xâûp‚üà ·&ú*dIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_end_focus.png000066400000000000000000000002251526321767600270640ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+GIDATX…íα A‚*ÛÁBiØ/ÀFJó×ÛúÖ¹FÿÞø>œàÚ¯Ž ¯IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_line.png000066400000000000000000000002041526321767600260430ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+6IDATX…íÎÁ 01ÔÉÙe“Oß?‘«MÒ“ôæãmÆ|_§�–iXïIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_line@2x.png000066400000000000000000000003561526321767600264250ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœíÐA 1‚�Œ€Œò¸Øec@kŸ»ö¹²aÊñt€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@{×€Á|³OIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_line_disabled.png000066400000000000000000000002071526321767600276750ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÎ10A&âP€„ =" Üëÿg#eõdõl>Þf|Àe#;X{¯ IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_line_disabled@2x.png000066400000000000000000000003601526321767600302470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¢IDATxœíÐA Ã0o(Àþ-€Œðh ¬·1 µÏ]û\Ù0åø:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë =�úu +“ÐIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_line_focus.png000066400000000000000000000002061526321767600272440ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íÎA @Arª�‡!$’œxÎþÛLÄ¢ì©ì©ÍÇÛŒ/ø¬yßV1ÉIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_line_focus@2x.png000066400000000000000000000003561526321767600276240ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœíÐA Ã0S¸F" #<ëm hís×>W6L9þƒÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h¯çC—’Y¼IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_line_pressed.png000066400000000000000000000002071526321767600275730ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÎ10A&š… ,à8" Üëÿg#eMgMo>Þf|À9?™9;&IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_line_pressed@2x.png000066400000000000000000000003571526321767600301530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¡IDATxœíÐA Ã0Mx†AFx4ÖÛÐÚç®}®l˜rü ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ðs×(˜ÍgIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_more.png000066400000000000000000000002421526321767600260600ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+TIDATX…íÕÁ CQ÷7q´Žæ&ÒIt#äçžòÈ¥) Yî¶ÜM¹Q”ò‹á€*_Ø{(/ùƒrž½5»­‡/„òí …IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_more@2x.png000066400000000000000000000004041526321767600264320ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¶IDATxœíÙÑ ƒP ÅÐuŽ"ö Á"tŒƒôìbY÷/3�óºŸóºé°Éão Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4Кå|äqýŸióÕ33ÇþcK\~КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð,àÄ… ”™¼WIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_more_disabled.png000066400000000000000000000002471526321767600277140ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+YIDATX…c` ¸…¤4¸…¤4Pb%š©F0ê€QŒ:`Ô£p°PjÀJªä¡Œ v­™Ó@®þ�QŒ:`Ô£uÀ¨Üž ?¶mĽIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_more_disabled@2x.png000066400000000000000000000004071526321767600302640ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¹IDATxœíÙQ ƒPÑ¥Á °€¬Z¨Ä�ŒÓäÍØÉäþí ä8¯ç8¯G:|äñ Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4Кålò¸~�Ï´€ÙµÀÌÌýû²%.¿€hM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h–ð.Vv�bñIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_more_focus.png000066400000000000000000000002441526321767600272610ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+VIDATX…c` X¬ýÛ`±öo%f0Q¢™`Ô£uÀ¨F0ê€w åFüw ¤J!ÀxàD0s¹º<F0ê€QŒ:`Ô£p0Ë ‰(GGIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_more_focus@2x.png000066400000000000000000000004041526321767600276310ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¶IDATxœíÙA Ã@ÅÐiNáQ áR›Âx•Ö&0–õo3¹îõ^÷z¥Ã!�ÿКhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ðlà#�ë×øL ˜S ÌÌ<߃-qû@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@³}€g DøîëLIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_more_pressed.png000066400000000000000000000002411526321767600276040ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+SIDATX…c` ˜dLl0ɘØ@‰L”h¦uÀ¨F0ê€QŒ:`ÀÀB3(©’‡E83#¿�\Í£uÀ¨F0ê€Q ¸¹“�G-ÍÊIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_more_pressed@2x.png000066400000000000000000000004061526321767600301610ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¸IDATxœíÙÁ ƒPÄÐ ¢$zâF1Üè)=‘2^¤o7°–5·��çýçýJ‡Mÿ  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- Y>ÀGׯñ™0»˜™ù>[âò (€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€fù?úªØçj,äIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_open.png000066400000000000000000000006271526321767600260660ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IIDATX…íÑ¿JAðù6¤I!‚ M²Þ@ˆ��UPÓ V±Uðll,| ),¬AlE°H#Øzûç^Àpˆ�çXˆ…Br¹T‚û+—a˜å‚ ‚ÿNЉ÷'B¶r‘î’ÖO“”c"ªJ_Àa¤õ¦ˆpTV¶‘³€,Wˆ{kíZQÜ9ׂª<° Ê\Q¾p@U©®@ÎÌPÔUâÜΨ¬µvãr `à ˜·Çý~¢�FãmQ×·Ep  *�SãÒ’?Îg¼ß£¨ 5û¯YÖŽãø¥¨¿ký¾q>7ÎÓXß U’ʸôÈ8Oã<­÷‡¿Ç�3qð[â\G gjîf€¬xWÄné^™¾ÒàÙûE^2ÿõÂŒ"[M­¯ËvM5¬µ1E%RæªÓlÖ§íšI)sï ‚àOúo‡>NxÓEIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_open@2x.png000066400000000000000000000014431526321767600264350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÕIDATxœí×AHaðÿûf•ÀŒ.A²;;³l¤—ÂCE&]ìCD:Du :FàEˆºT‡ #*»„$lØ¥Óž2w¾™5Sa1LÝu_‡”ÖQÜÙ5ðýŽßûæÍÿ{;ð€B!„B!„B!¶ ÚÀuÝ}  ÇD™é^ŠÝ%"#Üj´Îžaân ¦+¶méxŽë½pøOCzòc:w±¡¡a>hïRÌLÚó®ÔU²œ›ü>¾«±±1¿Ñ¾*h0òõ`ð¹šÚÚ·Žãì Ú{É sD{Ù^ßáoLà�/_¥#PF*“ÉXAû§ÇÇ·[ÞØ —}¥9·ùõ�&Zë ´×WúF\lµmûÓûÖ1©WøJS |ʲ¬Ô†—ü€mÛND©fC¾Òn&5¤µnýמ®ëÖ³RÃXyøLÑPMai`šæTa~î8O}¥&õÒñ¼ŽõöÒZ-‚R`Ä— ÕU“±Øç02!½¥˜Yi/{ÀÍ•7ãn+¿ADŵ®Ï¸n;�¨ò]Ü_mmÑht&̼¡`IÆu/¨€á+=Cqá|"‘˜-]üý™»ðíUböØñØ5"Z;gÙZg[˜ø9€šÒuRÕ†:‹Å& �NW×Ôî¸à‚¯|5aY=åÊXÖ€Öz?“z  ÎW1-ù|~ˆTõ1pÌWŸ%¦³¶mö—3_Ù££_ã*²ð@ýzö0ÁEu2‘ˆ —9Zx_�¿I&£^±�?Ä wëØ>RPÔT‰Ã$“ÉÜÌtî€Gkï¢ó£y�i~©T®Š¼¥ÿÔtÔ¹<õ í¦iþ¬t¦M¡]÷�ãz…Œëå7ÛÅÌ{ÿƒÌÇq¶mv!„B!„B!„b‹ø%'óùƒ3F¡IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_open_disabled.png000066400000000000000000000006461526321767600277160ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+XIDATX…íÒ1/CQÆñÿ9‰Bº›‰°‰E´iÐDµµÕÀÀfÀ¬µ4bh™­DBH7ÂÖE'ƒDÊäÞûZ8Ú.ç7?yÎó&,˲¬ÿN™¡¸³ +_R…ƒôÝoJ#3+½^ÀÍ/Åüö4 ßeµy¡´ƒ¢õe8挛òá¤3ì5¹%`¤Ó”7¨ê¶ŠH›hŽ'ÎüwÙ‰ÙÅ)ñ9GèÔÙ»çEøáz€€i@å¾ä¦’Ñ|åéµSë’òÃõùç\(¾´¢Y Èvè—¹£ýÝ7S¿ñ|}ÄY¶�°óÜ¥—§ƒAïê¶²‰Rk¢dã4—^Çpy]ÂñŨ ö€� U`p²\ȧ3µôÕ< _}tT•òÅ\¦PkW]ÂI§O|ÊÀ£öýèÉAæ¦Þ®F(8²,Ëú>w…k0Ô ågIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_open_disabled@2x.png000066400000000000000000000015501526321767600302630ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÖOleÇñï3Û­DÄ4£‚JÄQë ˆd…Ý%¤©Èn—b±¦ÛFL<o¦ñF‚‘piBÿ$MT¦8(è–&”¤ˆFÊ­€š!FÁ�ÐRö}¼pØE°3»„ð|ŽóÌüö÷¾³³³`Œ1ÆcŒ1ÆcŒ1ƘDž„ ؘ{·Î+Æаø¼Ðßó á«Í.•iÛ*¢{ù Ð×}4L^è Heó#Àú’È/j¼kyß÷o…Í�TSÛǨî.9výêBï™Ó]]Ós õB×R dhóß®æûÄ[-5¡³ïH$:ªRÙ|g`ñ€„¾�¡7@”]ÀŸ3Ž¡oÄcñÑ ™ÖçÃæ'rï?_té0ð^`4%¸·ÃÜ}ˆàHçò/:ÇQ��ð?D½†ºÆæ’»)Ó¾¸(î[�úÀè*ªo ôŽÎ¹ôá à÷üót-p¢ô¸ÂsN܉d¦µáÿfnʶ­tâNͲø çdM‹ˆEp~üÌÍ/¬ûÊÅo׫KFÕ"²}y]ýå‰_Ç~y�¬ôÖü À³3'úS•ç6ú{/DÕ;² 8wîçbó¶ÆÁ —oT¯—ŒD ay]ýüæm�Ã###÷|M&›ò;O΃OLŶ9Ü{=ÊΑüÌ&�É·«ÐÉÝ›|hzÁíwŽ80ì’ʶ~òéÝiº¯Æûç#ß÷‹Q÷,Û¤›Ú6«ªÌŒF�»µexðà_¹\®úš{z?HKà<ùp¨¿{_¹:–u’ÙÖWùX…dàÒITv t–³_Ù7 ™k_&ÎV>ÐÊ…Æc=§ÊÛ,¢×àýó»~WÏ[ ßÿl=ëÅtM%¿þËÄøé©×VÕ~=©ó–¯Üã´“ÓÕ±Ôð7=+Õ«"�@ð3ÓMùU:MúnÈ‚�?ú{oV²Lž¥Î��¯}©~)ÂË€CuÏÚUKw}Ù¹;ÔÿúGN"ÑQ•hi™÷°{cŒ1ÆcŒ1ÆcŒ1�‰vCô=PÃpIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_open_focus.png000066400000000000000000000006141526321767600272610ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+>IDATX…íÒ¿+…QÆñïóÊb�R¬ü½÷–Í$?Š›˜X)€Í$“É,R/)%‹"ñŠ¢Ìe±Ð¤î½��ÅëÞMÎg<===§s ‚ øï”Èo•—-u•ÑÄEA7¿)Ío»Íö:â)Ö ’¿ËFYeFM@g>‰÷fåsÛî²}ôP¡9+Ÿ9 *kØ…÷ãÄ“ßeã-`­ÀáK¤¾Ÿnÿ«§czN¯5^ê…×r‰ç°?=_œxZò.Ð^/–Ôw5¢Ç¬þÌ?ðQ.ñ xém¸WKÑÔå=帣² 4 €=Ÿ¢¹¬›×4 ¿ã!W¼4Lj"¦(�¦Ò‚Vªé«z@¼énEÞZÞ�ŠH£éˆªíªi@¼ëv•| Ü �t]kWíl}ýŒAÁŸó +r�ôï‚IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_open_focus@2x.png000066400000000000000000000014271526321767600276360ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÉIDATxœíÖMHTQà÷½^K² ‚ ŒVAATÒ8„E&)&Ì"Ê¢ŸE‹¢‚� E`n‚(ˆjø3W¤¿Môæ80�›­¢¬° 5¯÷m#ä\+̹3A}Ïò|ç¼|ç»fcŒ1ÆcŒ1ÆcŒ1Æü/˜k@E·V!Ð Ë^L7àû"üø�L‚o|Ÿ <˜ÁöA§ˆ•…¸·ºþ«=žú.«úêù²P}ä d‘O-"[B•NÇgS_‚#…l§ð˜KN\!Ø @‚.¤œS¿ûðOª~(·úšJþvÆcŒ1ÆcŒ1ÆcÌâ;_zòê±nМIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_open_pressed.png000066400000000000000000000006451526321767600276130ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+WIDATX…íÒÍ+DQÆñ﹓Ò()åeÇ ÷’²³š0;e5Vš;ˆ�ݬd¥¦¹w3#y©YXX)%E"®¢¬m”lˆ©;ó³0 Ô¸3c%ç³<===§s@Ó4MûïTPÀ²3+`˜¨bÌËÎ\URÚ—HwøʃzòrSà¤\Ölš@ºuÔ�p‚âÝÓ—Ð Ð4åÔ5bÀÐhˆìZ¶3V.kÆ�!£¨€V`ßó#?ݾ¢Çé¹W¯í~TPK@°Ñc;)�/ÏgÚnB)¶�0Hþåá>r±>ûÔø>³â™I”r>†ËšH½}Þ~[°îš�ùRáÂYn:tóšôØNT`+8Ô3È à£°½lrµš¾ªôÚ®%ÈŽ@KéèY„‘óåä^µ]5 èw;‹!¹n ˆžæ’—µvý‚¨ïŸQÓ4MûsÞW+iEÄtL…IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/branch_open_pressed@2x.png000066400000000000000000000015341526321767600301630ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÕKlTuÇñï¹S¦Ú�ÐИPMJdcR6ÀLÇG¢©Ï¤$,pAK3í€bâÂÄLº3ñQ;¥‰ )1`ݘX’RÚY²¢ƒ„Ð Iƒ�ÚÎqQ£Ók%Ø{gºà|–ÿsïo~÷Ì Œ1ÆcŒ1ÆcŒ1Æó¨¯ÏÆÓõ³Êq„§P¾íM~¢~”[H4ѹµ ò)IŽö%½äy^@$ž}éïåÄý߯w_íoŸöš=ŸJ8žùPà“¢Ã{ª•OŒõÆÿXlªãC±ùÂŽªU5߯oé¨öž=§1•ªˆÄÓ]®‡Ÿ{5�¼/@t¯Àm×éË�ÊÀð†ÖCk¼Æ×ï;¼|òVÍY�„k”xÇË»>l º;ót! ƒÀ3®Ñ-U§y¬·-·˜Üp¬£V$pØèM òÖhwrx1¹Å|ø @ö«äÏËff^¹à­)\ÇÒÍÿ7³aÏ¡u"�Küëáå'§à<ïÇÃO 9zpânPßNºF!¾ ÇÒ{6kc"óŠ:…a nþD.ÏNësÙ¾¶kž ÿ%àWÀDvpöæ¦è@íd((ðbÑHDh~2Òº¹)úCCÿù7‰§w œªŠÏ@ƒ[rG[ïùÙٗ߀…Db�1Dºp-YáÔŠüŠw<¶kjþ* ñÌÇ íî,E;×NÔ~Ðßÿö¬ß=K¶€ÈžLŽö!×hØ©p¶d·�ÔoK_UÓ#ÐâºNyÿJO²³TKº€H"½åÎ`„õ—¢º)"QÚó©—0íV�°~+ðƒú$/�ê@\|X1È�µ¶”¬ÍbýÄ}ZR‘Ϫjfµ>Qúw@ØAÙï <±aøB@f±>Qªm;õ¨'¨ì«ò¾73›õˆH$ª›À嘴ÌÖO A]„í‘ ÂVd³>€ïyŽ˜ÖúÌ#Žbjë3@û(0²XÀbdcZëeþ—<ïPJMœPÝ-Ù´ȼ6ïW³Ù\Ž‹�'×QTžÀU«ï-§I¬s­DȺ {5çd±P¨þéáfS³Ù\¾jµÊ‚¼"ƒV’µaƒI…•>�LuF3tµ»{�Mzr:l4û¯ßþ1ó‰teIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_checked@2x.png000066400000000000000000000023261526321767600274140ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ˆIDATxœí›OoÜDÆŸ×6EâÖSTu×ΚÍ�¨R‘š[O‘€KK/ ¢­ú¸P‘H$!´” |‚Vjª(—*½¤•ÚkzA°\6ÎÚÞÂ�«Û/‡î¯×®½ñøOšýI{ðÌØóúÙç�­`Ê”)ÇÊҨìµìÁ%&þÀ€Ó^/4²ÉÙðÀ61ÝÛ5‰¼´“R°lû]ýà- A–I—ÁŸ™†ñëË)IÌL}ÇY&ÐŽÞÍÀ<�¶vm{‰™ÿèDl×]bÆ×ÅÄV&ôMßq¾H¬�+Ú~+RüŒ™Vø ÃpˆÈ—gN˜Yµm[ ^ âu'GêÁïťØfmÖqGÈöüøÞeÓ4÷Š^6–eÍ(ª¶ÁÀ;¡ân_ož�Œc)в—0šóÿxÿ|zTnLÓÜ |ï2€g¡âùá½�0&ÀðQ÷ÿ1Ój»Ýþ[~˜ÅbšæƒVÃeÑ{âÁ…ÑþCɱ•†Âþf¤èÜX›˜óN‡ ÃpdU&1±7¢mâ™áÕm´Ÿ„˜ØÇf¯‰ó€ã‚VuYè¹n[ °Âà†E÷Uº®ë;y¯]{ì¸îœð#_ðÆðwÕg<î¹n;ïõk-@‡Y£€p*¦ú”ð—yû¨µ-×½N1�®æí£¶ôç 3ÖŠî§–t˜5…qÀk)MÎÛW-È`}8PÀ·òöU;²[Ÿ× Ãèæí¯Vdµ>Û}]ÿNFŸµ «õ |-ËÏ,ÔF€ ­ÿ§¬~k!@ÖHypçMŸ±‚áÄ„@¿x ÖÛÍf/Ëù-×½Î%[_�Û=×mûŒÇ®b8Wgð5àG;®;—z~EÖä@ °‚ä¹ú�æD—Ui}AnB¯¨1uX˜uœÏ“ê«õ£”0ÒZÏqÎDK«¶¾@†÷SêOhŒÛáT¨ƒõ¹PÀß8xY›h*ÔÁú‚܆Ñ%ÂWé-_¤B]¬/�2ì6›·x’Òì„Ê|W6Pë ¤°Hä„kHI€ÞãlÊåJ±¾@ÚS ­ëdK…4ʱ¾@êc0c*$R¦õRÈž ±”j}�ô‰ÐáS¡\ë ™ Nš UX_Pˆ¦B%Öö.�=ª±¾ Ð—¡´T¨Òú‚BX$ò…>a|‘Áñú¤*ë n7›=OQÎhÀsÏ ´é)Êù¬ŸÌФ”õs�ÆÀûeô5)µø*\%q쇘Y-)éÄľm'ÀÓð�mۺ̠Ê$&öA´MœÛáƒê™A•I@êÅHÑØ#yLbº7rL¼nYÖŒäØ Ç²¬�LÄ¢÷İk4ø+TtRQµ�£$‚X,�ÑãÝá½�0ÙryЪÂþf­—Ë“zqøÏn¹¼ ï8˯Ɔ àå–a܈«IœÍæ €—‹ ªà¥Y]¿™Ô 릩ïÌK ­x2mš:̶¹sx±êºŽÛæžL²mnÊ”)Ç›ÿæ2ùÓŽª@ IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_checked_disabled.png000066400000000000000000000013331526321767600306660ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+�IDATX…å—OHTQÆç�¸‚u5¸ÉMm2Œ(œ¦…o¶Ìd­\©-‡ÁÕ-’,'(ƸI(ÿ´©�ÕNÝØB)háF˜{ZøÞôš?o|¶¨oõÞ¹çžï{ß¹—w/üï�âÀÕñnDî]@S@<»Àªé\6³ìy_"v|X�@;Ð9N­vDn¶uœÛÛøúqÕ(8‰ ^cÞ?Q²BÌ¿�Íü‚ýZ,~ÊäéEd8�ê%׉º‚cFAu(—ÍLAìÂù�éˆ�Qž9-¾`yòº¬óA’{¡ù}·öy7æÐäQ{,Xœ{þÝy<íÆêJäÖŒ¨}«OUˆÈà«'¯Ëå* K„Õè Îr„´”›c•ôƒd2i©á)>·o`V?»\öÆÆþŠ€h,VÕ{‡Ée©»³uòØ”°~ϲ4žJ¥L¥ùa¥U]Âú‘ÜìÔf5Pч¼hVÕ™h,.ˆ;‚õ.ünÃc$“L&#+ëÛ5[_µ…1� ÷]Ð+ËëÛ·-áÖ»¨Ø‚îÎÖIE–¼1� U}x˜ÜŸõU H¥RƲ4ì•Ióm}Õf§6Ed´Ô¸ÂÈ‚Oë} ¸p¦åQq+Èk³Þ·€­¨Ùzßà ƨ ººeŒÚµZïÂ÷ïxq.óWL¬^váàTñbôô4:�;°`òô— Õ»µ?¸±ß-PM#Ò‡ÈxÄNˆæ÷ç=g¸#¡§ QBõ½¢< ªé‚(obÄŽ‹Jš*E0(£¹ìÔ}7pèf´ñåÓJ[ÇÙEDš€“w;ÚÞ¡šÈe3/ªù�௠¨ããpáIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_checked_disabled@2x.png000066400000000000000000000024661526321767600312500ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+èIDATxœí›OLUÇ¿¿™YLz!URizq›ˆ!©Ho½l\�C+‘ÀF�Ð4Ù�½z±Y 1¦õäÍè%šf[0„Æb6-z¢’].ÅaléYØ™ŸöÉìììÎ,ógÙÏíÍüfÞo¾ùþÞ{3y4hÐà$Cv‚"‘¤¢´äúˆñ.€KÚ¼àifµ“�°Ê„»…�¶¹Lf¼`u‘¥=ý‰n–ð€v’ôÊ’Æ-Φ–ªEÉÕîÐ=˜á€3®ææg@·wîm¬¯ýR)¨¢Ýƒ‰0>õ&7!ІÛ;óëk+¦§Ím¿Xr�ñŒ‰G%‰4cw3�N«¤{db±˜¼‹æóšÆWˆi„Óúó¤¡Ç¬ÊˆD’Jè¥ÜïÐÕ<?©ûZžKm{’½ËDû­rÓ ¼ux”²ûÿ¼|Ñ80JÆ‹•–\J¼§Ð”ŽËÃÀò\j[ÝÇÏ�òkÅg+¡L€âTwx8¹8ûåß^$ê%Ës©m%õnjϘ€ƒyþ0@¢.çæ’Ìóú6]e1&×µéÍØÝt9/ß0æÎÀ9cŒ™%+¼ �öµ`’{ÙêÕL€…RïìЋ‡5Mxˆq¯ I?ÿðÕ†Ó{ÞÝ7.h=xÀ)§˜pM–µG½±xØéý-@$’TÀê÷Κœ>Ë*}â´�@ jÉÝ•O]& :í#°ôôÇ;ÀóºŸ@ ‰$&º dšvÚW °²~‘=MRo;í+pص>1�-§§²Nû ”5Xuïé¹ÏÝè3Pص¾ºn烧³ìé�w°Më/̤þt«ß@8 Ö¸â€7ßùðEÒF&t_’´‰…ôä;ׇZr7ÁþZ_àØ½±xX–µGL¸†âZàaM£‡Ý7.X]_˨¿pÿk׬/p,ÀÁ[šùZP¿‹D’]VOë \^Q+p©éÅ­�+�¬Ç¨oÄóA�‰ÆzúãÆãõ¶¾À±Ä¸gÒÄMéK!Ö8@•Õ[ö,ÂJJ!Ö8`9=•aÜ*N”BP¬/pe Øßi» Æc‹°&–è[–¤iÀúWÈdÆ Ä|Ö¥ð:À-b|±¾ÀµY`qvò;¥`…_Ö¸: Ú,…jøf}�«ÔP føj}�ë ¡£–‚ßÖx²Q—˜ðÀsæÆe»ŸÌ¼Ä—¯Â?Τ¶¼íG_µˆ¯ÂõÄL€¼¾‹Åªí'4&¹ç�1fäô�]4Ÿw3)?1æNÀ–1ÆL€U}CÓøŠËyù†¦ÒU}›Q>%— À„»ú61MDû­î§ç-ѾD+�KbÆgL(ì´ÍXÿïá´ÂôqAl–.Ý1NÙⳕPÛvyPR’y>ÐÛåUºJàñ#o—üo~˜@Ì#‹3“Ÿ™�«8Åý•ým%ÜÞ™QÔ»Ô<‡Yš™¼U) ê¿±¾¶~õ�_AÔ…c÷ßeIÃÐÒLꛪQvn¥ÿmŽ€®â®ëÀý6GÀ�kùm®Aƒ'› ™ž‚ß’IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_checked_focus.png000066400000000000000000000012171526321767600302370ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+AIDATX…í—1kQ…¿3Y«€…b vùbµ»¢ˆ‚]BŠ$øj•Ê$e©V°0`PAAÒÁ-‚ vA²»•ø’:AÁ"•É‹�·¬›ÙìNv´Ñ¯zÜwgî™sß̼ÿ:ê”ßûfŒ—eÁ•<Š1õUê³úÜS@©êÇà'iÂr"ÆZjÌêé)¥ªo�??°¢j»÷õ=�ª7ÞùR<Â$ò:pQÖíàD!$Ù^’ÖBcV›y$²Y¬ZÂoc¼ LDí,QˆN¨åY¼‹€D)Ú‚ËËö4š3ú– ÇB¬Ð#÷Ü«ž~`ô 9£gåç* ¸í ýôb rõ¬k¢³&3±âHÇ~ŠJnJ×xÜéŒIZû+ŠÛžH>`�ìÔ¿ðòÏ H³Þ¹ yV÷»¼ï"ì·ªS­�´Ø˜ÖÞ úû:�ÆeoµìNÄ a} Ûk(Fuì׬ø@ªõ³~`’Ölot„î–¯óÐ1bë}[�عÓ³½�ü¼+5“õ `U± šÇõÌÉ°ê³ šÓÚ-õšW¤ÅfFë3 h|å]­H8—õ™¤¶bë³  ÕŠHšö�ýHš;¯õ�Ì¿ãÝ}&ú&HÛÃ!´6�yݼ›bÕ—“áÁ)˜:@<Â䟭{Û4B Ý‚UŒ§�׋U ¨uìá†"yòIág@¡J˜K;˜TÈs§ô;½&�p4K¶ÎcÝóçäÀ¦‘v4ûÏ/¦Në­¹mËIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_checked_focus@2x.png000066400000000000000000000023651526321767600306160ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+§IDATxœí›ÏoUÇ¿g¦…ÂÊç¦!XX6M0ñ¥/•M›¨�–¢‚‰mb[›(Šý 4±Ñmñ‘²©&m �<-£uƒ 𲍋Ö-й_}SfæÍtæ1w~Ô¾Oòsîyïž{Þ÷ܹ3¹hРÁNF¢8uϰim'ÔY� ì`wÒÁÕ�'<"8gÀ¸ÚRÀÍÙYû^hJ“| à7^ÕizÌòa¥_~ÞÊÉl!¥s‚ƒ§±ýí§K782ð�L@ç$DøY2±¥ùyé'|Ôì›™ªì§=æŠ ÁÄ­CkX¸þ®XZ�É™k4¶à ,r@Áí!oû•CMºgØ´ºÂßᔽàr®Ò+KÚ#O€R™­Pñ¦Ã<¿§ G¼cM ¬­àÜ5¿lR>Ø.ƒ€J¯,Á�sVæöêØ\Ô$@A�u^Sdøn¿ü£?Ìd©ôÊ’P†�6ïØŸ¤è2˜¸¥=º”P͘r[äu¯OMìw^ZÂîÀÒÂ'ö^¸Wxy›íëÁ»ßê5x!´ChÊ:€(t•Ù¦”åÔ†…㦣wOÊßq;÷ (�ó°²x”óön|ä‚EÞé*³-îïç:Ý3l‚ÁìóiÞ§,õIÜ>r�€Ç˸ æÖõ9·�ÜÎÅIv8’t?¹T@÷ ›Lð;Í[ù x=n_¹L@¸ôOiWâö•»ˆ,}‘‘JŸÌÇí/W ˆ*}æö¼„¯tô™«D•¾²äb”žQÈM Ô#ýßNËŸºúÍ…²�¾�¼qƒ¯XTC› á„a£÷zåA”ï?^Æ%‘t¥o[]e¶Yä@.À^«SÎ+‹·Kã<öýâ$;DÒ—¾Mì(¥†°V‡Éºg¨²,¥oØ|DõkCqõ_|ԜŬï%ùI�)N²ÃkÎZú6Àñ‡]¦ð[g)äAú6ñ`_xº¥�§ò }›Ø ¨ôÉ<)Ÿ†:VK!/Ò·Ñ2ì}WÜqÛe‚ß›àr }- ˜í‘u ra¥¼àHˆO*Ò·Ñv˜ë—?"•B)IßFëm0b)“¢ôm´& ŽRð#UéÛh_½p)¤,}›DV‚u—BÒ·I$u–B&Ò·IìY r)d$}›D†BK!CéÛ$š€ÙY7LyO¤v“… CÞÏJú6‰?ßë•TrT€)«V˜¢’£Q_™%I*o…+§dÀ;iôU/¹x+œ%~›¤ž8¯Ï\£™^8zñÆîà¿Iê‘óúa ê-|b_ôúø(€s.ƒ…czÃJ㎻-¬¹%×$À€qÕy-äh©ÌVÝÁ%M©ÌV ] 1ïØ6lZ ¸ à/‡©Å±í”„ÍÍÒîãóÕ±¹¨k»¼P†U3¦ò¼]Þx†ãÕþŶËÛtNpðq`D+'å²_Sà:à×~\†È`rQ¥¨ôá‹ ‡¨‡¦¾Ю5´ä‰thªîcsÕ-çòxlÀ"Àûõ›kРÁÎæ?·7é‹ù]VIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_checked_pressed.png000066400000000000000000000013001526321767600305560ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+rIDATX…å—ÏNaÅ÷k»"1QÀ»¾‚ЊÑL\ qÅÐÐ&@IŒÂ²iX•D#-�BÀİÁ½MØ(‰‰Š@}X)1qÁªv®‹ÎÔ±Ð?Sz–çÞ™sæÜo2wà‡Ôý‰Ü-TgPº}R9BÙF$³—Ÿ|W×@$>ÿH‘¹³ŒùK•éâJòÉ)}cÏn‹˜·ÀD“¡R¹ðaíáw?ToŽ>½R †PÉ—¹ã$¬:3 ¢É½üÔºÂìYï�gx�ê ðÀT»„€P©\ðSÜ 4…Š7ª\µj8¿b? ;‹Ç)®:\°~{{¸žX6j­XbÆ>å'^5ê÷Õ@4– [jm¶‘ÞFטFEOH¥ŒÐçŽx«ðÍ@ä°+ º9UfÿŠ�h,Vt®†Þ*ö/_¼�³£?1e%�¶š]Þô6;Ցî„¢ƒnN•Ç;«“û­øoš€-Þôµ6¢±\Ø©�'z^_Ã+ k¤R÷¬Ãö£oÙ€*³",¹¨»}_:ãFD탦#°ãÜrs",)ºXÓê)ú– �N[¦,£ÀIƒ.ÏÑ·nØY�Üdº^½�è=ؽö-OÍ(l´½guFÑvôÞ àŒBGi7zž?Ç»ËS›@¸ic‹p¯dGPY ýºy-¢ã �)¾ž6 l”B�¡‹2`ý´†*R|t¸ß#É :ŒJ¶?ž4g‡;/¢ã �¶ø<`!’©Êºí“ ~nJâÔ�IÀ]ý\Ü|ß¹ÿ踌Çõª왿A$V\N¾ôãžÿ~)r/NÀ¢ÊIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_checked_pressed@2x.png000066400000000000000000000024471526321767600311450ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÙIDATxœí›OhWÇ¿¿™ÑBÓ"v…Ý�¢‡ÆCE°$[öàe¡µm.mjKU<„¬�6æÒ‚�f²�bk/Ù`ĵ�Z4ö"”´‡ ½,Ùx�º½Øƒ!Ö¬E0HÂÎüzH^;»;»;›ù›f?°‡yó›y¿ùî÷7ófxhРÁV†¬ÅUUY^ uèÀQEnð‚˹ÕË @œ•€«M‘¥É™d²Pë šD�9â×�ÉÓȤ¾lú̯Õâ¤*§ h÷H? Oo¶‹öúô›‰Ô9€+þÑr¥ÑîP?_º“ž—Ð[-ÑÌÊßs¿ünº×¬1š¸xЧKšŸ€0 èÆž§áù‰‰4ÇsµAgç5ùþŽün]áÃ` ØY!½cVeÄUUyöp×�"Û~“ ú±ÌX_ÞùÔ�'Ö5ÖiŒ·E¹—#KJoŒe÷€åÅPGIÍ?^Ŷ�7ËÅ@f¬//ôcžˆ6ö-/†:JcËÐ�£E õÎåO¹‘¨›dÆúò V�me×Öžó†€Ýp>=o�5iʸM@{iŒÉc�[Œ[{ž†ç�NÌ+Lrµ4ÆlP4 ÚݾLr/½Vm ¿°B[Ïh«TÐ@xo½é:3†æ®ôþe÷Ü�w@,‘Ú+iÚMŽxqýw‚·ÚzF[íž?ÐÄUUј~Ðl²»YÒ´/ìöhž= }*txßn� z*µ„A·û ¤qUU Ó÷¶U‹#¢ »}R Ö€U‰ù‚ݾ'€Uëx0“îÍÙí/PXµ>€lSäñ7Nô(¬ZŸt餕žVŒõXöÛ3w�ê7øa}�#ïíÝ#¯ab`ÂøYWä¡Û—Nß³r¼ÖØv@[Ïh+n81V'—4íf,‘Ú[ëx¿¬/°-€TÐPa¬®�~Œ«jE—ùi}�ý{À¯¨fD—_ù¬ÒN?­/pý&È Áè©ÔþÒv¿­/pB€ë5öoÓwÆR‚õ¶��¯¬Ö+*… X_`[€Lº7F²Vœ(… X_àÈ=à¥æ¥ `ÌÕÛ–~`¦qÀúG˜I& �ø$j–¿AÀ�§óÄúÇžÙËgÿ°R µðÊúGƒK¡žY_à¨ÖKÁO­/p| ´ÑRðÚúWF‚(Ï­/pE€:KÁë \{°Z ~Y_àêË�…RðÍúW˜I& º"Àl’ż.Ëùe}�ë¯Ã·/�¾'k8Hà)Ï<'ð”¬á ÕOfnâÉü€ÌXï€w½è«^ñUØOÌX1ntv^«8�6è˜ä¾Rc"=0nÝß‘ßíhVb’ûBiL™ ηu…;œ—gh²~ĸÍ($— W‹C±®á°ãÙ¹L¬k8L ¢�XÙµÁD€¦ÈÒ$˜þ44íÔi|3‰ðïdiÃŒqrM‘¥ÉÒØº¦Ë3X•5i*ÈÓå5Y?²þÏolº¼ Ú=ò?Y0¸6}ö¼Ù¾Šã€ì•Oϸ߽´<�™éÜlº÷«J–M1ôáµ58›«‹¦6°líX›uÀesX``®žes 4ØÚüø­òûI6ÖIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_indeterminate.png000066400000000000000000000007411526321767600303030ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+“IDATX…í—ONÂPÆ¿yv¸�(þ¥—€Dãð zYõÖÄ…˜x.`b‡ð•Wº¢‰aiÇ… -%H &ö[¾7™ï—™ÉËà¿‹æ”R‡.èŒ*û‘¸0† ´Ø(•J/ d׺$Â]XDr‰qU.ï}¯J Ð3€×SB´ …Â{®½^ooâº55ì ðñ|%`*«i*‹¥R§Q˜I*uf*‹Me5§gbv˨@JˆV\iMórsÅà \TeR>ŸóÌü[R�l`gY@ײΙù Ìj©yDD7åbñ),*´RÊ3W7Ê0£!¥Ìý` Ðu½O„ €G«§æ꺮÷â–΀×ÃÐ>®£¿Ý‚ Ø,c|} ã2³m;ë™ ü„6L\·ÀØq¼ÜÔ™žÍ"6\Ð �R)JkZëû·žlÛÎŽ§F ®Ó» ÅÄ@|³±x1™j¶š�+?¯ë‰u‚V³DŸä�Ê''Ý-IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_indeterminate@2x.png000066400000000000000000000016271526321767600306610ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IIDATxœí›?OA‡ïí%V©(€vC#…˜@ci¢P@h-$á;å ‰$бòÏ' ¡¡5P€&”6�ˆv»7ËQ`!†½»×⎸»·'w;»7àÍÓÍìÜÜ3¿Û��À `0zj§ÑsÞ–åY&~`À€k™šu΀#»Ä´î‰Á÷ˆ*}èÂ\)è-€[)Hv“?v„øø¯F¹V˜™J¾_$Ð6®Þà`”@Ûž”‹ÌÜò‡n€<<\dÆ‹lܺ ½,ùþÓ–Wã*·ýv¤ú„™žåPÝBøDTMÕSf¶¤”…¬i"^кžŒ{šØaÎû‡_¸í øT«VæÇ9ÎB>m\×íÏYù5îªJ…¡±èÄØôز<‹ð3ÿ£òû×£«2xpç¸V­Ì8 T�6Æ¢)€Æ«îo™iiddä{úšÙâ8Î1ƒ–‚uѱñ“àD¸Au3e·®‘ãêF¤j¼©MÌç‚!„Ÿ¦T7‰qŒ¶‰ ´Â»l³}'ĸ7­^[®z€nݘt èÆ [@7&ݺ1èÐ� @·€nòitâúþ$¯Á¸�6ÿ× ¼ÏDOœB!úwËŽQ¾<)牱Ʋ<êßAwˆ±åI9¯Ú™RžçÝð^U"9ô®á�¥ˆòwº®Ò‡"7êÉéùIP)æÊg§)¹$á´á�¥lÛþ ð‚JjðBÝ!9Ê�€-Ä*¦þ€UûkaŸ S¶«ª�¥²h¼�•ßÉ:0“ nݘt èÆ [@7&ݺ1èÐ� @·€nL1ugÁ3[]rI�÷³h›¸Ž‚)e!M©nã^޶‰ `7X¨ÁšNSª›ÔÈš‰TíEÛ4@Lë¡2ñ²ëºý)»eŽëºý~¬‹Ž ˆ Àƒ| Tõå¬üÚU á|³4Â;Æc ÑÙvyÐRŽ«—z»ÙvùsJ¾_ü?Lm!Vâ®´\ˆ¡¡€‹ÙIuxq¸PxÕªA»‡¦ÞMU-{Ú:4•äØÜ8ê»®/ã±¹2€½NŽÍ †Þæu„G3\oXIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_indeterminate_disabled.png000066400000000000000000000010411526321767600321240ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÓIDATX…í—±kSQÆ_^é"´ÄþJG],(.yê T^×"äé ˜©Tÿ38ÁÅdÐE”… â ¨uÑM·îmQ�àRÈ=¾ŸR^‰}iEóM÷�{8ßïÞsyÜ ÿ»ô{àüåò¤›À�ÏÈgXǬÚn6^''¼ä‡”—„V�àHFæDµf�®LÏžú¶ñéýÛx¢¿þµ³rîð³JΣõüIãKîÊÇ]�"R 8ŠÙ¹x'Æú$Î-¬Òn6V²0Ž-dÅBÉxµ¸�KäÍäZzßã¶rÛ=ïÜÃw¿¼wïM¸P(í ­%)Hèú®B„gà°ÕUeÍSP0Ë„ÇK_ýélvxiµN«> ±†ÛºÙB(G_ÎL$§eyU Äâ ŒØí¨¶Ö°„s]Ý=¿çós/ë%Õ5 4‹ƒqÝm-„(ØÕÝSšÏÏÍØ>¶ V^ûLU�ñƒ‰¯j=ó¡øitt´ì‚Üu�F=EøöŸ$¦k t˜Ÿ“�°ÝçPc@ �н; `úæ xQ^Äàt:¹àŠz‡ Fb�/1p|%J¹Åo{Y'FÍÚYßUˆ zÂûC?»YÓéäByƒ`üX‰ò�ÊØª¨1 ²Ô­t'2÷¾¸!ÔM¦ÓÉ%Ì1ëØ°¼Î¯$hôÌam-CóðSs›€Þš›~~sÇâ'‡uµ «vöZsì ¨Úám´Ù¾l´×ì^í h+”²ÈF [€l”²ÈF [€l”²ÈF [€lt'Š„.„Áž[Äÿk€¼W¦žÜϬš½ Âo@¸ÿây°öàCpð¨üÆa°ö<Üñ¼h1!}C; Ð]Që…¡Ý ô í©!dÀÝ{Œ€m"5Äàí[tï1‘ m? ð{iñ5@¿œÓ<ôkYÃú2 ;9ò“`\©!Á¸”�ù)RCøÈŒ¥€ŒÞay‰rè=È8‘K=-æÈ> ² ¯É2P“ l²QÈ e€l²QÈ e€l²QÈ e€M¬dnD£ÑFç‰746ÚKÖ; æF¾}NŠj%Ví|¶æØ0knŸtXWË0ÊtÊÜfà�5§Æ&<6·‰éZ0ët^ž»#±N›cÖ±6,}õ§äÿ/m&þ–®>1N¹Êتhî¸<(¡yøé†>._¦S^÷qù¿ü7&s<3žºa÷¬î÷1÷v¦«»§¢ {Ò\‡ˆO�§nÖKh¸ÆÏççfºöy¢^lº{C”#ƒSãɇ ³ÖRÊ|mŽ€ÞÊ©ë wmŽ€Ï ¼iæÚœB¡hoþA�XIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_indeterminate_focus.png000066400000000000000000000007221526321767600315010ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+„IDATX…í—ÍJ#A…¿ÓºÕ…2ú&é Š/�a>„`Vbæ&‚ #¸Ü Øà"/0 ¦}$kûÌ® Il1vtÀ>«âÖ¥ÎW?÷Âg—Fõ3¯e¸�¨ ¾”ab¸Åô#Ôé7uñ,@œx|0 ¬$eXûiS‡cqâuðà«=лÜÖß2\¿þöR6G¹ ,ÊÚ'1’lïK«•6uZ†qP¾‘ÓZb ÿÊpø ³D z W¦ùˆzq ƒ+ëØ'éjKwùpe à£TT0ÿRB|æäŸÀÂ+×`ýH›:)J*<�øÜ«ÈÇS˜, wãs¯N ð*H7u�µ ¦X{€ÕJ7u]”ôâÈï°ðߢÿû *€ à] ·ðX@Îʬ–x9ÞŒ`úÙ�YÀãÚ6i ?¢uŒ¿!wk‰ôžÔpoR¾ó†ð�E¨æ&5&f÷6žoL‚Bk–—Î+£óSêÆ&�ÔšUúñ䄆ê WùIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_indeterminate_focus@2x.png000066400000000000000000000016421526321767600320550ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+TIDATxœí›½OSQ‡Ÿ·…X��$:Ë $’6n˜( ‘&È ÿ�qS$šø'?þ1‚Dœ4%˜ Îp°ÄŤ¯ƒsïí­Òž{{@γ�÷žžþÞß=_iχñ“‘ÍTêžÕ–r‰3*ƒ‚t)ìØ•´¸zPø!ðYÑù©‡™,O_—ŸÿúÜ? ÈOêIлÀ¡X”6�E�‹Å‚¼ü[¥TÍ'ª’{¬£ 3l¿ä:@gòS:‚jÍ]Ó€Ü$#"z=mMDõFþ —k=ŽtÆëö3¡pIE®�æùÁ2K�ÎÉz¬B ˜Ðô§ X用^²ÁÒ5ª èžÕ–ï%ý€¿Û ¯HÉP±OVbWžùim£¢PNøÂ‹»³r$<1V �r‰3Çü×´Êùí’<@±OVHÉPò…;¼ÜTP¡2è/«ÈØ›‚|‰_f²ûdETÆü±pna€ ]�@šç±«k•Vž#r4\§Ê…ýþòÁ2Kq kÚÛÃu"z@p‡·Õfûzk�Ú½ÖÞíœ¶ØÆ`[€mœ¶ØÆ`[€mœ¶ØÆ`[€mZâh$?¥=¨Þ³Éÿ Pà="—ŠýþݲnŒ{@nR‡Q}!ùäñ¾£Õ¹I6mÌÈ€Î)Ý'è}S�"è½Î)ÝgÒ†‘8ì1iÃ�½ž††Ùñ“ ‘ex |‹IK#|ó44Œ‘ ý²ªÈ“6LPäÂB¿¬š´a<æ 2ŽH/°Àï%*i6–ÁÞ¹‚Œ›6Ë>À[��×d¸IжÛ8l °�3À¶Û8l °�3À¶Û8l °�3 Pøá/Lhºyrâ%¬=œD’úì/Êp ~iÍ!Bûr¸NDÐù@`�SñÊj©5N#ú®ªNu õÐ_Õkùim‹[\Òä§µME¯úcáÜ~ÇBd²<>úBY*ú`;™ðç°tðÄø¢—[€ºŽË‹ÊX¥•g[ù¸|j�ÓÞ›oì¸ü¹Ç:ú_\˜-öËͨG5÷sn"2šœª¦  #ųܪUa³—¦î±JKžM]šªûÚœwä¼}+^›–AßÕsmÎápìl~C�‡»æ?šIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_indeterminate_pressed.png000066400000000000000000000010061526321767600320230ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¸IDATX…í—ÏJQ‡¿3IV%B+©àk4ÿŠÅhJ_¢Á”jF)%ö¡%™Ø¢E’•pÓ.«i“×4(”,cr\Ìd ÆŽ˜Lbió[Þ{¸ß7÷\†{á�\ˆ¾.Í¡ºŠ�D‰øDi !’¯mdþ(Ëß)²v“˜O騒«5?ö ˜Çñ=ÊÐÜŠ< 0EÝzÞÛÙ€EUy6 *•èE¯@ -ÂðÆóž�æËeŸ½¾ ¼ï¶éÀ÷ýU%òcL·Ùr& wý×h|ÝØklê�ø¾¿ÚmÓ�¢„‡óFáN4ªC^Œ@ˆ2×q€[Ù?¿Äžèœ øl€ °6ÀØ`ŠI6½Önt�õ©€)H`ŒéÖå6ÆtQ‚ÌUF@»Ùr&uDÌf³ëfË™Âø[[`Ç/ª<)B”�¿§�›¿¹sv19�¯f!ÙèÜ)?ÿ!k²Õl\^Í,Ÿðf8-Y¨dIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_unchecked@2x.png000066400000000000000000000015171526321767600277600ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›OOQÅÏ­XCXbaø#S»puÅR¾`$wMD—ð t­&âRI$¾.YQX™ØiJY’ÆJz\PÊËÌio+ï·êÜw§9÷ô½é,î,ËuFêI*‹]¥ryä8DFHô ÐÑhq�#@n@d¥3ÿê8ÎáE÷�kIñòùi@^è»2µÍa‡àÜÝ¡¡EáYIg°¶¶v³;ÑóÀLCä5��û{/FGGG-Fnãã_~ë=À§�¥ ˆo)’¬\¹Ô@Db HK3݉�|µ"wÀ�\nZ ŸŒÐ�Pf]wpé¼íÔ �”\në…ot×âà“”ë~æ‡ (‹]¥_å羽y~‚•ûÉdr§‘¯Ïóú ±u·«¡Bç­ø½àƒ1¼±T.OÂ|àQ^¶[ñ�L&w@ye„úKåòD0/dÈqã*㺃K Ð×\wð €L-@Öa€ÈÈi>V[ýÌŸ‡ˆ�Äêi$6Ì @¢ßø‚ÝF‰kf ‚ë!Ì7¼Vû«» f Qo¯á#pͰh ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´±h Ð&Ü$�|‘¶7ȬÁ¬í„p“” P»�ìmœ´æ`Ö �íàzT£äFíÁɺf Z’"‚±ÓHe3˜Õ(¹b\¥=ߟl„¸fàùþC˜�ã"ËÁœ ›¥Aì³r”N¥RmÕ4™ÍfÈ�uÕP}ÍҎ㜫 ‰ud<ÏŸj‡ã@R<ÏŸ ‚óQ#4‘LøžÉTû‡w[­‹TDb${«g>X^HÝy^÷Àð_�Ì,ìïÍž52sáÐT6Ÿ,�7h¿¡©ÁùKM™TÇæ&ŽûícÃZrl² T6!²Ü�/×36g±X®7p°v€–è‹IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_unchecked_disabled.png000066400000000000000000000006071526321767600312340ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…í׿NÂPÇñï¹!0Z|†¾@_€ŠL&¨#˜°ÖYd‡•DWFe4"OÐè;°PGá8”*]lãàý�77ý}Ò»œÿ=²}à_^Ÿ Ü€z€“QO *tÇÏ�oþU³#*·À ˆP>2©Ž(¡tÞ_žîw•z³fŒ¼ ŒY£a’Iù*Õz»ŒY |EjéŸ0écLÌò( û–…04øêý¾¢åQ¾�@"o'³7ÿ)ª1Âñ>ÀŸÄ,À,À,À,`¯¦×|#â L÷$Üj½]Ϋ;ù¶ºá@¡ ”0‹AˆÊyë³EEzéùÆbrzÑz@¸æÉôªq&í"¨ .&i’ÕLo}zýU”)B¨Ho{5³ùÃ%f/å�+=IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_unchecked_disabled@2x.png000066400000000000000000000015441526321767600316070ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›¿OSQÇ¿ß�Nò#î.XWML¬us¨#IѤ¥DÐþ�ÁD¬8hM ²ƒl¸ºP˜œ)’¶ DòŽ}MsûjiOîgº=÷¾ö{¾½÷ÝåÀb±\dxšEáX,àtŒPp À €¶º*ûwŽäl ‘qºŽWÓéB­‡jÀðƒø˜€/ œ‡Ê²#ÄôZf! @ª-ªjÀ�d²½;/s LÔE^£¾Ýïåä÷Tê·ßtµmÌK{îkI#ž%ðM ?)Ž{¾Jÿ¡ëìà&€`i‚2Ñ�<…ÏNðÝ¡hbŒ‚e¡=™Z[~ÿÙïKš †"ñG$gôxA!¯e>V,6áX, ¿:~À;ó‚¼çúÊrj§Ž¢Ï�{‘ä€ wD/€È±ëèªùbtÌ݃Ž”½ðò¼Õ’€•åÔ¾(ƒRè6×UP¼ê<²Åmß’¬fÞ}�-(µ ÀÉ=‘u4ÿ™ÿRÌÁcÈ\àgÀ 7 ±[U�ÄÈáŠ9ïg@éjl¶«î,9T\û~\(¬Ú´±h ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´±h ÐÆ -@k€¶m¬Ú´ñ3àØÝ–7ÈÈáØœ÷K0WzXp¹¢‰‘ö9ïgÀ¦7 y §ì)hRXÌÁcË\Pa€™²�Áp$1Re� ˆòÊqá’¹¦Â§ëh@©6Xˆ¹;÷-wn?é‘ÙR€È1pXÛ€Õtº ÄtY¨ÏiG6‰�¢5ŽC‘øh»Û¶ Ï 0ã×BS-!Þ�Œ¿ñéÉŠÈ:‰Ýf«"ºŽ.Ï|Иžÿúeá|êž«uŒÈ~/'»ó€aB�dðä›­†š ÿß9¿ßãL¡JÑwͦ©P4£àZ­iŠÈ 0s榩r±X@ �ÃÅzû!œT]7cÛÜ6€-—8\:MÛœÅb¹ØüßsáµÏ3¦ÑIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_unchecked_focus.png000066400000000000000000000006031526321767600306000ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+5IDATX…í—1NQEÏe(‘×0"µ ´;V�µZH/« SŒ•1±6q6ÀhÀR“™k“ ‚…™‰…ÿ–ï¿ü{òþ/Þ…ÿ.m’[÷Tó9�%ù,�Ô¹nÒ3=íèÜe#¤ û`fx+Ã]Ð4Ä‚òèõ$ºúp4u?Ç�ˆçȼœj^†y¡îÔíLž`Ž�«_L¢V4äxhx¯ÂàåTóÈŠ<,êµ�žD0«Â|˜a’]e½ùOòêC¶vü‰@ €6–‚fÕ†Z­ú‹]©!îNÝ®Ê|}wŒH¿8×� ‘É“* :>Ìä Pw¦qQÿLî³k¬KàƒU0Y–a¾{ Ô÷“BÉ­{Š<\¯Î­íó_j�H�i¼Í‚>h±o/|A'>IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_unchecked_focus@2x.png000066400000000000000000000015221526321767600311530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›½OQÅÏ™¬l©¾zYâb!55ŸF±“hZÂ_ 5˜¥šHÂg,©± $4,TÖ,´Ü¥`�cá²;Ì "»w7¼_µ÷Ý;Éy'ïÍlq/àp8n3¼JQ׺’MyŒ€"Ð)¡@¢ÊÚþ•"‰œ€]ˆËÇI,îô1ÙC 1³†1Bo´Ý”Òq pj«ŸAê¼¢s èž×�DÊŸ8^}µBóÅ#ob{œ'qÙøc,1±ê¿ø"”ÉJúFz?Hø7-õ�àI~+ÉÇÒ• Ç)�^Æ�„Ø�YÕ¡��¥_'·°pÑqª $fVñ”Ô €»åeðùÖ?…Ë#ü}áé;*wþgQìÚäAÕDW�îµ%¨÷JK¹ã$ï‡_Œ^øÁ¦ÌšÛì÷^Åõ=ÇOŒ�*Îk"‘ò2! 1 ªÇê˜JhîäÈ›<¯éû*CSϽCã MåN_{h*H׺’Í .µœw ÇæìƒØ#¸ThÆÒUÆæÇíæý[ö<ÿÚGIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_unchecked_pressed.png000066400000000000000000000006231526321767600311300ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+EIDATX…í×±NÂPÆñÿ)¡Œ–Ÿ¡  ø&ð¬&”ÁœÕAvè ð ÆÄ'¨‰Kß�)�ã5XÀAÛ8x¿ñ´É÷Ko‡{à¿G’ƒŠ7¬[ª×@ pRê™ÁZ¤÷æ_>T[�]…`"úžJ½Ê ¨ D´ûê_Ýíª­AC‘'„—ˆ|sâ·§©”oSöF%›åå|-Òˆ¿„õ‰D:À"‹r€‰ßžFä›@”SíÄskç�H˜Eù.B!ÔÍÿµpR;óo"Â(üI À À À ÀvóÍí5Û¨â³C€Ô-{£RVåeoTp‚=ÀZ¤l–ã,g§6Ë1`¯Dúñüëbâ îUåˆÂíò×QÅpûèb§â ë9ÕÎöê\L>ÿafÁJ¤Ÿ\ÍL>§|n2Û½dEIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/checkbox_unchecked_pressed@2x.png000066400000000000000000000015361526321767600315060ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›MOQ†ßSÑ!t©„÷n°Ý´Ä�þ ÁHRܘV‰­²0�_  M[#íNI4þî¤ +×It 2 }]´”afJ+2=m¸Ïj:çNòÞ'÷önî ÃeFÚM,„­�þI÷Þ0  /ØhÿÌ!€ ›¬ÚûËK/÷Z}ÔB%–ÌN‹È+#“³cì˜[/¤—a³AMÄ’…«;A*�x�‚(VºTLýñ+7YÆ‘|@ÒU(‹à ˆïU z±Iÿ�‚`˜Ä]‘FA�ÚøÔo%ø®€x*; àƒãÕOR2¥â³Ïg-§î€KæŠ0 ຣðh½�ùèíM,„¯ Xßp²ç�GÑRqv'˜ÀÁK¾¹²à€¨üþeßrÿ1†ÜZý“püá‘ò¼×&¥âìŽ^4^F­°5áçP;ê”k˾7ùº˜þ |ü›”Öêç|í \ëþ=ÂÚê�cî>0zR”Ý`‚uŽSsÜôÖ½4ŽÆn;ê΃kžcßOÀ¥ÂР� @#@;€6F€vmŒíÚÚ´1´hchÐÆÐ � @#@;€6F€vmŒíÚÚ´1´hchÐÆÐ �Ÿ€CG±ç¹æpèS÷P9~¨‚CA„ê$§æ@l»ë>d³ñ¹°­ž‚î„R›C‘-÷�V?#ã©üd0á‚'þ$ûŽ›ã"\q�ñ°÷–Qk6P˜»óømÏm…ñ™wÀd/ˆŠ½g·P¿M=çøpð¨/TŽ%sS½±(±dnŠÕ£ ƒ�ׂy¿š&¢Ä“¹÷>Ý"e‚k!Èn·Ý" ¡*8Tßó‘ÓU.®23~÷ž›tŒ‰BZhÃ%!"�Ñf·U©eòKÅE²?ÓìÒw˦©x*—ð½Ö4ET ˜?wÓ”“hb!l…­ R&@ŽÕo]w_Û± ‘-®Ø{öJ;msƒáróô°å&aEIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_horizontal.png000066400000000000000000000001701526321767600270010ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+*IDATX…íÎA ±ÿ™bd�ÄÀnÖ{ÎM¬døÂ7�¥±ô'¡IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_horizontal@2x.png000066400000000000000000000002111526321767600273470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+;IDATxœíÐ Á×þE‹ø)ä@f,[ÀÿÆÚç¦#’f: Í€t¼×þ…©@ ¬!IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_horizontal_disabled.png000066400000000000000000000001711526321767600306310ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•++IDATX…íÎA İ o(˜ü[Ç#1ÐVa½çÜäÀJÆ€/<èÿ÷Ík%IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_horizontal_disabled@2x.png000066400000000000000000000002131526321767600312000ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+=IDATxœíÐ Á×n&°‚ý+ø)ä@f,[ÀÿÆÚç¦#’f: Í€t¼×ºaY¯ŒoIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_horizontal_focus.png000066400000000000000000000001671526321767600302060ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+)IDATX…íÎA İ S¸žD@ÆñH ´U@Xï979°’qà Ó²æj„F˜IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_horizontal_focus@2x.png000066400000000000000000000002111526321767600305460ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+;IDATxœíÐ Á×R¶6¢~ 9�™ËVð¿±ö¹éˆ¤™H3 ï5†jêÑC3bIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_horizontal_pressed.png000066400000000000000000000001701526321767600305260ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+*IDATX…íÎA İ Mxš ƒŒã‘h«€°Þsnr`%ãÀ¾0í¹[–IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_horizontal_pressed@2x.png000066400000000000000000000002121526321767600310750ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+™�éÎ ¥IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_vertical@2x.png000066400000000000000000000003661526321767600270020ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¨IDATxœíб €0Ä@ Aì?‚EBËGaw_½å±!®ûYß}s�]œþ‰hM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4/p1€2UÄIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_vertical_disabled.png000066400000000000000000000002071526321767600302510ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÎ10A&ÞP€ü[ " Üëÿg#eõdõl>Þf|ÀäÆ5‰•.IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_vertical_disabled@2x.png000066400000000000000000000003711526321767600306250ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+«IDATxœíÐ1€0ÄPŠ·*À²°€Ä•Ÿ!Ùnº¼Œ 1�s}÷s_CxìâôO@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- yUÑ€;ºêIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_vertical_focus.png000066400000000000000000000002051526321767600276170ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+7IDATX…íα01.K±5#B†€RßÛ§ˆEY=Y=›�·_ð‹i‡|áÍIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_vertical_focus@2x.png000066400000000000000000000003661526321767600302010ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¨IDATxœíÐ1€0ÄPZSõ�P|` ºâà3$ÛM——q Öõ¼ß}Ÿs�)NÿD´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4К dA€Éä’­IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_vertical_pressed.png000066400000000000000000000002061526321767600301460ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íÎ10A&šð„ Pîõÿ³‹²z²z6o3¾àøb—_;ÃkIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/line_vertical_pressed@2x.png000066400000000000000000000003701526321767600305220ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ªIDATxœíÐ1€0ÄPЦzbC žðTV|†d»éò26Ä<®õÝÏ}᱋Ó?Q- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€æXá€\†C¼IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_checked.png000066400000000000000000000023541526321767600263530ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+žIDATX…å–]ˆ”eÇç}÷+¶Õ(Y,wfÞ�uÁdëj¼°ÒDAó£ BŠS’.º,-É kÛnK´BˆÀ» E7µ„L¯J\a evwfÞ™u«ÅÀJ«uæýw13ë;;û]wþ¯žç<çœÿÿù<Üé°Ù8÷ Eœ|°ÙÐj°R †ƒ”ç\àÐÓ‰$ÿWƒÙì2 ‚n°•3Ì{ÁA{b±Ø·ÿIÀÀÀÀ|Ç­=Œ±¥dëÅtJfƒ…ššá» … P(,”äÉÜ5À&P¬è®“*¶Åãñ_f- ?›]ì:< Û—‰¶|¶Ò,?•hIN:›}ñÇð•w6Æã-—f, “ÉÄ…�,ŽåGÿy±½½ý÷©ˆÇ#™LÖ×Ô×Bln˜‚žç]œV@2™œWSWÿ=°ì€myÍÌ‚Ù�—!ÉÒ¾¿¬Ë ‡‚ežç ‡}jÆÕÖ5Z ôNDÞ?4qóù톭Š‚ˆŒà„Cp$L`f’Ô�ñý¸°í˜{TÒj3Ó„+0àû�ޏ€ ·ÚÛÚÚ®‡fã¤}ÿ °·�†I&}ô¦�~&I$u�Mó/�–˜l½çEN–Çœp´+Þ�Ùþñäßÿ¬k r€F°i?{HÒØä:::FM¼UÌ­îðØ˜€t:}¿à à·›\ÿ$œ5íçö {A3Äδï¿6Äb-=`—�‡R©¡‡«f3ìDGGÇhÙžÉdâ ½f³y8í]ß÷ë™ ‚ãæžª`²Ç_‡ÓÌ^jgÁ\FcA¶£B’ôM©µªZ€)µR•A¶~äÅXôd¸/i°Ôl© ’Qº5 0P|®$bá~>Ÿ/ç^T>ˆNUT%LÓûL�;å(•+0TlÕ.ó0 2s€üpÏuÝrî«å.tɽ‚ÖJ™:É!YE¬ãÔÅ‹9É�Ùn3él1е•ø˜K-uŽT2­)RèL•׬·D¸¾¯¯oìÚÅb±Ÿ€gÎ[~¬¬Ëó¼±U:ÐÜž*Ñhô*ØÁ‚ûš›·‡S^ùõuf¼ð…mÙ¶¦²Ù ÀRàGÏ[4ö7¨8á�iwiû’Éä¼²½³³óÖµ‘‘Í`˜b;y‰./Ù®¢‰D¢ÎÊuí™´ f2G {8æE#OW•cßïp`§‰u@T âM±¯TpÇã‹®Tˆ’,íg/cœõ"‘US ˜ïÔÔýZ"ñAk,²k²‰$ÀÌ “Œ[ÚÏí½\u�GŠ[}V—Òð

­9Ð9‚ §µµõòlòÞÙøýg÷�/EqúIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_checked@2x.png000066400000000000000000000052361526321767600267270ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ PIDATxœí[k�UþN÷îd7d^I¤2==½›ÅP$”JP âjP Ä@¨’Gñ Š( U@DPRTa�2) ¤ÄB�‹Gª¡¢BA ˆƒ„ÚÍL÷ôL²„ðÈØ�™¾Ÿ?vÝ=3Ý3»³)Kóýës¿{î×gîÜî{îi`?öc?þŸ!ûb�þmÛ¦·Wú(j st8ÀTt»î$È„ú·FnH§Ó¹‰Ö6aÈçó= ¸� ‹!8jŒnr$ž¢†û» c£ˆ°¥"Ñâ�»P8J]ÈÂVú CÁ²w¶ohþüùåúm l»°¢n'0¿U>ë pi:•z°3bÜÈf³3¡ëw äÜšð7¬‡’ÍÔ±Eïj•ÊîJG‡—(•ºHNt‹¢ä8_Ðásƒ.1MóõñèW²®ûyQ|ÀaÕ­Ü È“By¢­MžN&“ï4ãÛuÝNÏóN h§X\{ Ap‘•Jý~,ú�qÀ¶Ýs(\`R•(ðn ¸Õ4Í÷Æêß�L&“˜2eêw(¼�áv·X¦qƒˆ¨f}7’š�wopm¨I ¸ª¬ë?ïM& Íúm›7¿Ý5©sè*B`JPÿ`rÇysgÌØÓŒÏ¦@R³w g…š¶R“Ó» ã¥fü�ý…B²ÝS�U/¸òJ¥4ôåÞÞÞ]�úÒšØqÝ¥U7/xQ¨æï«›€Þd² kÒGpM°…ŸmOt¬!©7ê«á�Ëç¿âá�ù(ï2˲†õÓJ�;_¸à­Ü o·Ló§�øh([òùù±@Ç'ù�™J�?ogÍ"ç8?ä.¿�àݦù`\ߨ …CÊžú'€Y>óKPÞ—šýåmÛ>šv:‰£$’è(@P…M€z´Ù=I±w%ßö™KBu\:�ÞÕ76¹|~%ˆ‹|¦­ºà˜T*µµq™L&q@W×@» àœFúò „w§ cµˆx�ôèïïŸÔ–èXðxŸy“�2¾°P¤Rw¤(§[g�Ùà3J;Þ²’/6"*—ÏŸ&Äf7¯_òÇétz]#ìl6;SÓÛ2õù¸Ò2Í»ëõ©û ):äW~›€k¹ù�7¶gíü= ûÍ€|†¢=›sœ¥$cŸXÝÝÝo¼%¨Y®< ^ŸºNíB¡�ÀŸ©,À�q"Ç9èàé3ŸÁåqÜÆ!7:ùŠÅâäXªR÷B�ß{IàСRé»õèõg€ÂÕ ‚ßš¦™�;“É$äq¿+´IÓ,Ûu¿Z‹[3¢ëçðGl]ww÷[Qƒæò…s ¹$NÜø!7lqœš7ó1CÄ#ñHÀ¨pA-nÍ8%莰X,N–‘·±} ²,îuWt jœ\«OUá–Â+ë‰l¸ì]…à‹ÒDcžã.Œ"¤“É—øgí´\¡pt˜W€ááác$>±ðÕžžYù0ïãVRàñš[ ¯ŒjEAà‡¥ªò”UPÀÜ@'`C˜ã‡m¾Áôh¹‚y[\·7Š d@»@;2Ì©±Èþ+­¿šó ¨ǫ́ö‰„¦ÔQíB†´óˆ0§Ö"˜èE>ûEMx¸þØÐªþÓ~� h'`…9µf@WàJäýH²O¿(LÆPÂڻ„`€äyzÝI�µ³µûBD �Nðï™L&áçT@Â;ÄvÖMx¬éßTZ­• Ð>^Uâ îö_ëJUM›½ÝgG¾!N$DfŸmÛž$@›ÏTš;wnÉÏ©µ2ª$ŒQŒU:A�˜Œœ6°;̩ǥ W­œ!™¨ö‰=¶¦%º|À®âTwSoø¯Dù²AÁ£Qí *rl%^H;7Wû�@è°‘ Â?ÄóÖ ÐÔiLk Žiš¯D1´`B§æl­ À‡��/🿮¿P¨û¸±,k‚ûcõ¶"¼/*%?òˆ–E£ÒׇyU=[{ÁokSjQ˜çG¹½ý&;£%·®.Ás€0²®{4‚ï(»ìô¬�a^í|%¼ý]5Xïa‡½M"2cÔJr�aEqôjÍO×J�× @›Æ5)jØ;â ýÛ¶EîøÓXà™(N+ �ÕV*¹&ŠCR#%°Iʵ¸5�J¥¶‚Xë3Mj.‡�ÃX(R�òÎøf„´(ñ¼HU¹4î8Îq g‡asfrm-nÝ×XMøëÐàßËf³fÔÀ–e½¯'×ÂØ RØÈJå´¸ã¸L&“ ð¡ÞwÕ;ª€T*µ 1LˆÞ¶4N¨išY(u,€šˆ‡uMúâ³0yÊ´KÜö¾;üQÇŠzüºBi×…Ìç;޹Ff‚�2¾ðgí-š�; X’6�sâ=x³XŒV2£9NáTŽ,RÇ´Ò7€¬ËHoe+Ks'ì£)ÇqޤÈÞ�¦£›Až$ð€eË÷qØ'ŸÍ ‹†V©,àÈÑÏæ,¦�˜*@Gò‰»¸€l†p³F>ŸJ¥Þøo¨EÞ�ýØ�ÿ]ükul ­IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_checked_disabled.png000066400000000000000000000024701526321767600302010ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+êIDATX…å—[lTU†¿µg: $å"F*Ѐ)L%‚¢ÐÖŠ@)9R"ö!&ú`‚‚' õÅE”Ú�òÂô¢m(ÐÒ¾€kCÀBb,K«10Š´�Ùˇ™)gzoñ�õtöÚëüÿ¿×Ùk¯}àA7JpÚêœ$ëñfбËQI¦FàºB ªõˆ·2X¾ÿ—ÿU@º“· lM¡ Ï÷,¢Û‚e%'îKÀrgÓ±ös`]ÔÕ¦PmÐ#a¤ÙgÂm¡°õšÃj§‰H°˜�¯±�䞨*þcÈÒ�¼ÖJ0+B,þÐ�Iêê Bý‰öûýæÔ…ë¯ÉÀ5cíªc•¥ç-`YVN²Ása‚À÷ž‘ÿ¾väàÁ¿ú#înoŽèuwŸ ¹À?Š.9^^Ò8 €ŒììÄÐÝQ§AgƒîY4gÊÛv(änü´¬¼­*² h1j«(jsx»¿º;jo„œêÞÈÓVç$©×›úð¸€Uô*"‡�5ÅÝ´¶¢¤05+?!ßû-°Ð^3�º6÷i0g�?Õ˜™ÇE·cs~¿ßœ>ßò®Š¼ŒìcÅÿ¼W[^ü©›Äqß-;æ�¬–×ÄæL\¾0»TegwòS®Me_ä£ö¤®Íßç^\ èPa{tXèžë�žµé1…eÀÍqž[ûݨ§.´ìÖß[S?‰Ùœºvã[n÷ñ²âJà07}Mî“=(veD™1ÿ²¬œd�ÀàŽ­®ý0uUî¤8i"Uê1kz –¨Ú£nw ‘Ól¸6Õ=�ö„öä(v|t7¿ß/Å `ž°Ýàr dBcž‚‚+põ>\sÚºÅÖÖØçÞ¿ˆ0=B¨a¸¦ñï& ÉQKÌwO€¡.ú”î~),á/€áô‚ñP§GLbNöСÕQu+æoÚÔUv'šDø$:7 ÅBTÙU(vW”(²*ÊZÙC@°ª´á$„q7l¾ôÆxóP3˜ƒH"*‹çNÞéö§fm\mr?_vÝ âv¸µ²@FvvbÌßPTÔyóa“ º‡þ?Ge×XÏíuî.ê8ŽawD nÕ˸2¹|ñ§ÖäYóf ,ÔPÂìõ¯¬Hz5Çq|·mâ^E6wÀ>,/ý±{\¯'Õ¯M�7§§Ìÿ!M`‰GÃfÌšw;éÑ•ç¯\©ï·$ý~¿I˜ð„Ó®¾2�T"W±´ÚŠâ†ÞâûÝ×K3_›`¼ENÔÕ"P zD0ÍÛÖÞ¶>�o¢E§é‚®¦«Hm§éÜPøê÷¾8õc²ÌÉ]h¬)žL<ЈحÁ²ÒÚ�‡ôköbææi!Ê#ËE5I#mÕ´-¢Z�x*kË‹. ÷Á¶ÿ÷€Ú°€ÝBIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_checked_disabled@2x.png000066400000000000000000000054671526321767600305640ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ éIDATxœí[}pTÕÿ�»›M"æCÁ¯?0È@C¬´ÆÒÈG²…`6¼V±h ›ZÛâ´Ne¦®±Ú±#£hØ@D£m—¬1_vS…Ð"5DÅÔVIB@ ûvßé!ðöíÛ·o“]¦Óò›Ù?Þ¹¿{ÎyçÝwß½çžÎã<Îãÿt.ŒJ‹.‘kž ÎV ¸àt¥B�„~ý þ ö³ AØÖäqŠ·oq ÀÌ»*2…5P*˜Š¸~˜j1sCÔ´Ö¯Ý €cé#ûЬâ²Ù$Ä£žcÝ{™°¢÷bñꮪ*9VJc€ÙŽÅ3¿05V:õÁ]<ÑTW½1#À¬"çedųD¸×€¦0ð.1¼ > Èò ƒzd1p,ð�B$Ò@4Œ Dœ ¦Éá2°ÍZÚX·vßHüQfKe7+ mp…¶��cÞD[��·Z7m8�î\iYò¨@ÿL‚˜ â"=NXÜ\ç~}X7€ ßQ¶€ˆÖH qŠè9›ÍúÌ_^[Ó;\ýjH’dëSÒÊ<àRm;OçNÎx¼²²R‰VwÔp¹\bû¾î§Àü˜¦Ic�¨l¨wŽV¯-N9a�áç.T·1h³_$,ôz^8�Ψàr¹Äöׂèn�–nA\Üè©~?}ÃE¡Ã9ÖO؄Рw·5éäô†ÚÚ~³º,Ѷ�¾®DiÄï ³ëÜ£Ñ5|¼¿½ÿ²É·½š ø®! Zc\ð'dçLÎüsGG‡©/„éØÎ‚°Z#~YNñK­¯W÷™Õ+îxÏß¹¿}Sæ¤O€(§G3N!9©³£½ÅŒS¯@AÉâ©€Ø I%~µ¹Î}â°:‹ùçψ°R-cÂý-Ý"õ�€YÅ÷�Âögµã}9Õ›·¦æTTŽ;'‘Å̸ž€±ü&à03ÚÉ‚úaì¨Àá¬a‘Jæ,rë«Ú ;Ftº¤¼šÀ‹U=ºáSnjÞ²®ÛŒgƒŸ°ô¥/0ÑL»Áô\º¥ï�Ç0Ó¡°ðáDÿ'ßpë�Œ�vÿ‘Œïz½•þpý„‘Ò|©bZÐÍÌ JÌÞ¼½¤ì®>%mÀ«`þæàF¯ïSÒvÚ‹�3ÍthhX= Èp€ñõ�Œ€)¶Ñ_’µ¾�Órô¾)AF€{}:—“_0c ÛG…øž¢¥D €`›c;½*ÓËÖž+À[S3@½´I’¤žàu´Eö vÒÖFǹ!a¤*Bœ'Ʊ sȰ‚×[é'Àp…W(0Ì>O/-M`U‰|�ǧ愮OjÏ^éFF˜ñEdOã"ãXz¬iÑ1-'4À§ÁVBgNMû^ÃöøÂØv¢rmÐ5£KKÑ[ìW_Èp±¦zÃö8‚XÚ&A¾3p@Ë €`620MËQCN•›Du#|ÚX_µÛˆ ˜ƒ}×­!ðYm;œI0¥Ðá û¹Ì S� ‡c B Rò.—K0hN��áÕòBpúlm‡Zæ'�" ¬Âÿ$€£†ÇŸ§”•F„w>ìÎAÐ…úý=;µ<Ýo8ší¯Rdd¬Á³þ+¦ˆ£XbùÏÊ“FZŸù-½ô¸nXVj¨Žšif¡´ÈpÇçÿzì*�FœØ€^i®s×1\.— &í&íe=®nš·¬ë&B“J”(+Víqx¼ÞJ¿ðßÍ@<Iß“Sä D8ŽÛ±¯û¨Î!øR>’Ñ¤Ç »ŒeðÔ×~h¦£ìj#ÃÞÍ5}Ì�;â„�ŠŒ»"ÇI’dcæ_«e̼2ÜéPØ4o¬~›8h2´YODò²µ~}§?à¿ ݈ Ì<.Rò"%f WI­@ð¶·'ÙÏkÂñ�62¬,Ñ}vÉi¸G‚|ä[w‚è—¬³ü4 Æ×-m®¯^iÒ€é÷TŒ!Я4:~³e˺°>fV;;Ú»2¿�“ à;§EFá¸ë¦¼vè`û7F}»ºÚ”ÎŽöwÇO¼¹šH¹@`z÷v”€Ul?hÙ¸ö]3$I²ÉrâVÐÙ´{zƈ²îÚ¶v(âé°½xÉ¥lñïã2•x»õDò̆†ÕfœSç§’”Û£„�l f‘‡Î ¿¨Ìí$È“F}­Ú][$”8×X¢ÉBð´He;¦ $òÎ[ˆà…ª"ŒAëZêÖ:1‚‰\iYrúq¿M õ`Ÿ_þ 3?¯–ÃÙTﮎÔ×t‘T�£l!ˆ‚*.¨ºH}8Ú§C�½Äù0+¡šÏˆ°ªi£{™¦k„:÷ïÞ“™•s€ï�1äœR’ò®ºaê]{w�ˆÆó‘B’$[Ƥ[_°Á²Q>’±¨««ÍTÍ`Té¬tê[ŽÁò´³ Ü–à |�/UdG£k$°/¹´/�Ú  LÓ´Oøï6ªÑ"êBII’,½Júï ¬b2€5¤XŸnÚôâ¿£Õk¹Ò²äåØ�™ñ·r Ë=-žª¨6eÃ.•µ;œeLXƒÐOÛq"Ùm0$I²õÒóñ\óè-Ãeb,53ۇÈËåíó]ÉVË*šL@þÊL-JàcV¸'aTÒq…ú¾”Â@Ä8A˜ÀL¹ š pª�ÎH`i“ǽk$þÇìöùå…Ìü[ .râB7ÀO¦S¿{8C>T] 1XLÝ=Ä�¸)–ºtX!§ø«£-Ð4BÜþ45»¤<‹�R˜0|©€Þ¬¼œ›=ö�áüÀ„�øÃ>oÑ•J‚e�²e"˜ÆH�ŠÁ“›£úúà `hkõ¬ß�ÿ‚Zäó8�óøßÅ€ꀲ·úIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_checked_focus.png000066400000000000000000000023201526321767600275430ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+‚IDATX…å—]ˆÔeÅç�ñ+©4$¬\«%ûX*uV‰>4QÒtwkÛˆ"A¥‹.‚JKÚ¢2» ¬ÐŠ ¯ÌvVÍí ½�]Í6HŠÀÐV· %Ólæ=]Ìì8ãή;Ö�çfø?ÿç=ç¼_ÿç¸Ô¡j’§·»&‘£Ñò‹ÌAŽ zŒv)G:Ó¬ŸÿW3ÓNE{-0kˆ¤]9iUW“¾úO¦nö•ÉdÜz¬êÅÞî>SŽƒÃ#½'‰ŽŒ—¸AŠsA Àõö‚–dô{ÕfnõM1çmÀm@¯Pëȱ|´s–²ƒN©Õ!5…Ge¿ÔJŽÖ¢Î‡Ô=dÓ¶¸6œÆ[©'3óurPáóð@‡G?׃–`NëîÝÍÚAõ¾‚3Þ Ô�×eºÃ3¼¢X�x¶êÛY‰½èÉZ©}«·4%ÙoÐßñ]P�ÍöÎïû‹OowMˆq)Ò|ÌD b�vdáÃ2É{m*íZ¡¥Iyö$W\�ÔOSp—á�\V“öµèDñe«CýžÇ~ YyÆœ’ôž&Þ)©Ûìá—'Ý ÜJÔ‚L³:úÞ…ÒñJø €`½ÚO|rÜXXÊÊâùéŒ6^7#×c'w Eg…^Ì+zm黢�©ŸøÌýÀñ“9Þ/å­ŸÌjИ!ÁhE};O—Æö4‘~îH¥¹³Ÿ�d`! äZt¶/>m‹kÁ« 3:¢_¿k«¯->K–½ 86õ3€ã}ùŸðy)O"Ÿ†U!]dô?‘eež¾°4»¿TSøK‘µ jñ¢?XúÄÁ<'*ȃ8w�ò‡¥öb Ø…OrcG¸Åu}1Tw/£ æ AâÜeäG_Œ¼¢h8t±€Ã¥'N¹�ö}àJ øWn,£�;¸Hˆò±¹sÛÙÓ+°ÃN€à8¯ŒDá=àbjÁÙ˜ –;Šs j_÷30,Év£SßwñÚeuùíjÕ-­é\¤s7Êh@TH÷3ðMƒŽ_ã†]ÍÒR²ì±ð¢Š­ðÇ�ßñjidF �:à‡®FнAÙ �ÖʼY·ÖwøŠ¾ø¾åú'{L�àu ¾Yá5³á±Ò*Z·Ùí|�QЪ«!@ª-·Ièq`k¦[�_ާµùöqÖ|ÄDÀ†CŸæaÃÞýT¾V}:n-vfš4{Pù>Ð{€[�ßêìÏÔ�<²Ù €�[”«¸¶Rí<+ûMàh2¡é…­.¢by)ôƒà* mTV‹w¶èÏŠ" ßÄwAË€¿uog³öžŸ7`}KµùfámÀ-ÀK­—�aãPšÒShv¾)�ôÈjØó°¾­”>h��’ö˜Ž€)„zlo‰ðY.ËÁd¤÷ô0â¨ãsp}qžómyßç˘Õâ®ý6�Æ�*|ªÍ3…×÷ %ßb¿ÐÊL“¾¼PnUÍf¤}ƒ#�Ès€ò4ô z@»BŽôîfýX ï¥�SëÛx¸øà6IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_checked_focus@2x.png000066400000000000000000000051401526321767600301200ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœí[k�Õ=çÎÌ®ƒ,ˆøHJ(ƒ1–®Lp™]‚+˜¤T‚,»‹¥â#*&ÆÄ$&Z¥‹F�Æ–Uµ‚¥"•d`w-Q«ÄµÙ]^jùÀ2QB4*ÊCyÌô=ù± Ý=3Ý3;3”•pªæG÷ÜïžûM÷íûø8€8€ÿgp4rJR‡ï‰¡‘ÖŽ”Áñ�p€A"¶íý½'è À¼Ž(–÷Ná;•ÖV±ŒK雎µÓAN0ª_N„w`´ÔZó𪬩òª,w$6¤pº…®0±œ® ¼*pVæC<¶æ ¦Ëè·V74c;5”ÐËŽr™{ã[yj×ÅÜUŒÐúN�`…f; â0Ã86‘Ú$kÖ*†Î¢×);àÅ.ëŠ Ý­\T54‰Ng.ÀK\¦ÍÑëV4qs!Új“ªª‰a¤+_Hë xïð4æ-h£SH�3ŸTõÇ;µŒÄ8—ym|]™ÉW/0‰N�´Ü­ ⸞Vv"jlJSiuˆc áçÀKÕÛÂe…�‹u$½ à°}6‚×t·ðÞ|uò‚ýÁgœ_HçÇ< X"åÜG)UBçà$BÏÖw83Ѯ막@¼Í£ºqÔÓ:8_�¼NRh0ÞeJ;Ö´‡‰ÿ„†Ä×RˆW…q …ÈöÄhý}Ì ãÆ·á~ï¹L‡ ø Wäãç €…~㾦ôÀêi|;¨ñÚ¤ªÒ{´HÀ÷ÄöÓ¢i=v'ô ÌôüQ‚®Í77Èé¬.©¯8ÃeJ+jn ”'q`ÔÞ 1�W ˆÖÄhzOc€·\¦£6ü 7g"Qœ‡¾­ª} /ëiâA�&á|‚—…‰+¼©~¡rvf´Ñ!´ÀSËØ‹rqs@ÐYƒå’ Ç,ÑHwqÊ Í �îãÓÌI¹êd`ïˆé~—"ãà‰ ¶b®…w¢TiŒÜÃô B÷:¬à¾koŠaŒŸ—€êÏQ ÊeziMßóóöáì¤"Vúy¨ä2ƒÒ5�„›i)yþ8){Ÿ2+ø¶§=¡,lŒá‡Š© F&ê[AKãÑ.Úýœì1@öÁš·²8nºì´@™•„AkPqÄÀ§�'ø9Ù ¿á¾´@à»b¥w�ƒÏz¦ÝÈìñiFø9Y�E��ði î×ÁÏ�aA…–¥½ÆÏÉ é%Y"ÿ[߬,×níþB`º¦c7÷J°ª6)÷Ÿ#¾"-ònxL˜“ËÇ~D¬TÙ�°Ý}í¿#ÜØ»Îœ!V�»ÏF5€¨Ë´çõ6îqsr ‚ðì¨Ú¾SÜ ü+¤¼’ ÀÎC1ØgÚîçdÀjƒ�‘5rºAèÕ òJB!mËÁ1>Ó»~NŽç׼ᾢlàd2��å„ oÛ£]Ðú,YUßa#Çgq\8hžÞ•Æî¬ "v¼÷ÚdÝ1Yˆg°€ûüý»‰å}Ýt]Ì]”•[fH|0pK¾]àdo%tùiYØ{¶¶ÒS�˜ìç¹sÌ-¶*./6FÌ"Ô�Âxç(Ûâ‡bµŸ—g?€žU¡)A�-o㇃wŒÊ ò†•mÜD1°Í‚žÊµ=ž3±æ£/©aoeœvJR�+¾øÜâé@áå5¯g*ærÚe@zi´æ‘\ÔœXÑÄÍžù¢2P�ŽZÿq¸]™ÙÝwpúf ¸ÒÐÿÔ\vW?çÂ{ó~|è—ýq#ï4VäŸ<×àOÇuèè †_jæ§Žå$T"ÄjD85ì8®6©*I¿wÛDÎÎw:”7«¦b¼ƒa•;3Lçêi|{7YäŽxÿ ¿™4Ã6f`` —ƒžÉÛ–˜Áœ|üü R$oðÙ.L¤‚×à@ß�ÂürL?‹ÀGgô4›óÂ=³D‡QòáC¼}Eój\Éu7³ Ô<_J%ëÈ01]™éná�ðXIs|VÇ…­€îÈdxlo ï/ä¾6©ªHF áÍ!z%óòž œ�ëÔô €/:-áÅ¡qž¶tw‡Õ߇1K4 –Á m•8}»È‡€€ l´–4 ¶¥ñ¬Õ†úNgŽÀ+]¦´!LJe®” ‘èP½¨.oF˜êi6—•’ Ñ�Tü��°Å2�¾«@Ý綉¼¬·™sÃêœ$•èР¼ÒƒÛsu±ÿVÙ ±>…«͆ûq¦îéiŽü²Ee‰Õw8wŠ¼Î£xÞ‰rÚš)ü¨_¥¢6©ªAûg‘—z ˆ§ã‡prPR„Emg wÌ RÞöpj4£U ‹4²_¥`\§Ž¨‰ê٬ίíÏ)´ó@?%ÏN*²1jïè¿ÅÒ€æD`n{±…ÿ)Öo!hH*îDñ3B×â+^šÉðÜ5m,jQÖÿTÙ”.eßëÍ¿1¹ƒÒÝŠ›YÅ$,aÂsŠîÚ‚é¢f"Ǥ YGgÌu…æ¹QR²t]‡ Õ `hŽâO=™ÇÇ3Å£6©ªA�2ö,€MrMÃÓ"g2ÚçCÉéòu‹4ÜXÝ %€–ñ¼,Ÿ£Á›þ!ƒ-ÕQìH8fjlËÁǶàéèû¤&ŸðU"gô4sM)úËöÁD}JgJº@¥ÃÍo9ÚÁ_úsËûQÞOfÚeÆŽB“¡®PWVßÀÛgÅ·bn± šA¨ØGSu u¢1vúÞ�Žë§›÷=ieYõ ^èÏ÷aØ/ŸÍÕ-ÒpZL4²'Š<Àƒ% BßÉÍVô}6·ÐzÒ¬ñ|OÞø*ä"ÀÀÿ.þ ‘ZÀ‹yåmIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_checked_pressed.png000066400000000000000000000024101526321767600300710ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ºIDATX…å—[l”EÇg¾Ò*x!-‰‹rm@±Q£t·èƒ7$�€\4VC4btKa š  Äµ±¾@º]ZvmbHx²‰ T@I4𤥻6<Ø`L `iK„&»ìÎña»Ë×ûEßø¿}gÎ9ÿÿÌ73ç Üé�ñ8û*Ì´©äQY‚0aŠA¹ŒHÂiGmSKdëoÿ«oy¨¥xqŒY[Eugkdë÷ÿI@qYä~‘Þz`mŸ© ¤Y•ê¤Îë?¦kÒdc5�ÇŠ�c KÕ²av_úãN*µ¾¥aÛ•q XXq`žIÚ£ˆ> t‰œòÀµ/OUU%GœR0h¼Ýo€ì-.Xu&Ryv̼›öbsZ€iÀ'—·[j+ÿ‘xæByS{©CX\Gx6v°²mT‹¡û’ ~(R´&îéy�ª*;òÛPñùC;Ù t¨¦JâÑw»Ü9CR½„E(š‡"OŸ„Ô�å³,ÈEUŽA²¡?�hkD«}åµ…ªl0â]¢C®@‰¿ÖkÑV„?ÔæÍ�GýfƒAãëÎÿ@‘��»†™òuU>ŒGµn’¢Ò`îäü‚³ÀбÈÖã™1㎶¢Ÿ¨êî�äÞîüC}K99Àj¼þPhvrí�U ��úæ\íË (.Û?å% çfOOÄ�Õ×]° ä­ˆ]P@Ê}þp¥ÛÚ 4ç€ÇKüµO  ˜•€ ko¬JdìÞMû v��<�)-C?}jKíƒ.»¢zÀо2H"/¤åÛ~é4§˜4vYLqlt¬1ߥsÊâÁ`&€#rÁ¤ÊŠ �§!ú²û3—äy…ƒdŒFn¹Ž‘ P8q™+9�«“œLî‡2Ñ r#ø‰Œê3g”ÜîMÈe€„8ž¬Súº8aÈ%÷×½ÖxÒºèÌ\p·g§ò;€±Ì�ä8…h¿Xs+U БµÝÕS"²Ìä �‰Ô‚„IJC?†¥ ? �Ê‘fU]Q\É»–He;7½ÊÞ3 � nƒUY`lªi�€¶p SÒʦAï†~¹4ïýñý mŒM¿ºÛmñn ¯(~iýb[¶7è¿Ã­Ý BpQ t_Æ�úo©æ®Q´†‘GaïÜžékÝU´¨4˜«6]gv[ Šý¡ÃoGbžk¯,ÇÞòšÇP)–³H_þýFŒÖÇê·ý:`5Ä[V[�àNÅ"�Å# H÷�? €}1ϵíÃ5$¥¥_9��¯§†^oyx;ªŸ£t¦rÅ×tº=†lÉV˜gR© øú†ã¬k¯Ûü÷Ð$C£¨4˜{w~AX`#pà ϟ‰bý†mJK6†¶ÆQä²@ðÏÕCciJ}Wò_³*{æªfu<ºåç¡ÜGlËŸ|gÿÔœ<)í3uˆÐŒrkÎçØD×Í”X'7Ç£†ÙÆÚeˆYÝ× œÇY×Z·¹{8Ž1=LJüág,Z úÜXü�6UvÄ£•'Gs×Óìéòýs’ÖYƒ°í{š�t¤¯W=mÕ4Å£�sãÉ{gã_^ï×= ²_BIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_checked_pressed@2x.png000066400000000000000000000053641526321767600304560ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ¦IDATxœí[{pTÕÿ}÷în`“dƒÒ‘Ø–ÑX˜!» R5"ÚÑZÅ®õ1(QØM€,ÂT[�©K¬v´j»`ÜA¦­™Q§:ŠLµ¡Ô"d–úÀñ4�JÂ#²ÙÝóõ� Ü{÷î½w“]¦Óòûo¿ó;ßù�ïž=÷<¾ œÆiœÆÿ3èT42µ*|¦\@•€˜ ¦óA8�£ 8€ ÐGÀüøPJÑÖkj;ò­-opûÃß—ó˜1„)CtÓÁà7$ÁÍmÏ.‰Ä9‰œ€É_Å û\ž[ßxŸ@õ‚/´7¹rš³¸ý+/'¢ßðäʧøÌËÛ›‚ës1"†€éóÎJÊÒSÜa@¼âV!¤=@ê3Q��m½Éc©”<"Y ¶�"F™`šDà üÀHá[!¤š¶g0ýà €§:< ŒWŒ×)îð:^%YÚ´cõâîl|ÏXZ?rà¨m×�0;CýîŽEƒ¿Ï^ý †·?r;¯P�&Š9—í�ý³qáÁ¡úW¢Ür8Ç”, ¢‡—F`z46þÀC¨«ÙúÎ>¡�äÞ?ö? )DX'%Q·}MpoÖ~-àâ»/ŽÛœË@ü EšâWúdyî‡O/ú6ŸÙ ’<ûÆnñ­*;£nŒ=Ü‘•¿!búüð„”Œ—‘>áî’˜¹=7j¼ÜrˆÔ+®0:ÜLè_�PÈðoÛÚ\ÕO̓’–eZè:ó.\] àj…)! ñˆ±>¦B—k5À•Ƽa€hŽ{¿ËtNì.ÝÀÀ''ª�ÏùÌÕu¥W7"•¼ŠEoo_so—Q£ÞÀª;˜1ßLÜpAÀCžaÝÎ|‡––[RDhQÚ$æ»ô¸º ÐuËŸŒtû£Nþ`å¨ÕáÚïÖòÒPàt\ÀqÒBïµ7Ýû•–÷|¾e"Í5ç¼Ä°¸®N¬zpÌéç”:éGÃV£v:\]—‚q¦¡˜ü`òôÀʘÕÚ‰q¡–“f¾@õâ-GSáfÃò<"ÉÒ£r‰¡ÖN¸ �£5a¢ÊÀdøî(¯§À†-§ý§U°Û´ÚË´”ô@(V5"‘É^ÿ”N~*0Á¨¼°Ï©Õ^¬å¤Ï¬&IÌ™ÏØWez§µ§l€ÖæyqÊ� £Ür(9zëÕ))‰Œ3ëgu¬–c؇ë@O|¯ŠÀrÚ°ùÇ÷Ù†+ļ‚axú ªU<ÚDÄ¿L…æ d€c¶Ã£4¦^-'}}©jCJŸ9Õåô¾Qy^ÁÆm³l;OmÀZŽÎ$È)`¼Ø ¼dTžO0Ȱm¡Ò΄=ZNzHR]62«EÒPt¬h3€¬ncrÆ—íM‹vS4ÚuFLZúdÚ@yÿ^1}~8ã릵¹ªŒf3½y@“á‘|($p­ÒÄ2·jii¼[£mJ[R¦kµ<%R < à°‰à\âk{aR{ ‚·sŒê5Ê‘3ÆuÇ´<ýw8«wQD<Û¨±]Ï¿!°É‰Qî@ ·­XvÌ�$I*Í lÒ;× @ÊAœ<�eÌšZ6Üñ–ö4𦡨\€±¡-ºX{'¨F($1 Ú¤øy=ªnŽŸûoV˜ d{Úu¸ ­uuÉD”ݯªó`}U4Þ@`v0þì4¿‚³æVŸ¨÷7Löh¨Ê×�†ÿÇÐ7µÖþV#^kå·J@ÒL­kP­SºYa‹Â÷ýzíõ‰Ø²ü�±\@0¶º·Šèºn½ö|}�iš„”¬ ¹UŽM”}�§¦‹ˆC[% ÓÁ¡ -®ÙDÍîñÉÉÉ®ŽÃ% pÇ[<Ï›» ØvïÀÀ‹�È—J‡ ¹‰�»Á²U˜FC]Nçr¹þNÁ³ÙlÔêç :¤=ïŠÐ§À}‘h÷Ç’Ú^¦’¬·¯ÿ]`ÆÅ¤ç}Ñü¼ ߯�Œä‹¥·Û‘¨@¯/ó.<×YIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_unchecked@2x.png000066400000000000000000000041671526321767600272740ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+)IDATxœí›ŒeÇ¿ÏÌÞÞ]Û»b EÓÝÙ�½»ZÒbb9��¦Zƒš¶P$Q0)©R5F Ô`ÖU¨R~˜P ‚i0A¡±†ýƒ¶©J�.öÈ]wgv÷Ú£–"mÕî�y¿þÑÖÎÌÎîíÞÎ.W½Ïó¼ÏûÌwž}÷�™÷}˜a†þŸ‘Nœdôðáy]ÅÊrŠº�ER.Ð/€Nà8Àã€ä9@¨¿iä¾d2™m·¶¶% —Ë (àf*¬†àS “%ñ<5ü<�¿&" U$BNI± …« Ô@V„[€4[Þ:räÉááárˆqÃÁ² + j3�á°bÖ:À�IÃx"ŒÑr2™ÌÅÐõûò¹:n ÀïE°JF¨ã Ži•ʉJO�-•úHÎt“¢r9€�è­sŸ®O$¯·¢¿¥dòù‹âï«nå @žÊÎHD^ˆÅbo5;ŸÏ÷:Žs%E[`uð9p ‚µ¦a<5ý@ °¬ü > »Jø�Ü“H$Þžj|7ét::gNÿ: ïd¾¿�Ä&3¿[DT³±›NIÍÊå¿àN_“ðñ²®{(+4·FFþÞ×Ý{ê6o'0Ç+ ;þ9«çóKæÏ?ÙL̦@R³ìüv>ëk:DMÖ¤âñWš‰7UF …X—£ž­žpåO•Ò©� o4–Ö̉í|~cÕÅ ö Õp§.†b±‚®Ér‚Û½-ü`W´g;I½ÑX �€l.÷¿ô™·A9·š¦yªÑ8aBR¬\á€÷Às-Ül&ßh$FC 8˜Ë kÄ>=ç:òÉ„aܨާ³fÉÚö×¹ßm#xS*‘xb²¾“þ …Â…±®‹ð •Z7.’†ñ ˆŸ¹myÔ²¬¥“õ�4e¥6Xà2ÒkÞ­a„ˆ°R.®ä.s”¢=º›ŒÔë[7m{ˆµ.¡´O†q¨Áí`hh¨H§|­G]æ¥É\îKõúÕLIÑ!?pÛÜnš±ý-jm©TêM‚›Ü6�Ü5111»VŸš ° …å–¹Le¾‚Îö¢Ô#äθèT©ôÅZîµG€Âîcü$‘HdÂQÙ>ÎÌMžŠÄmµž oƒÙlö½Ðô€³�Êt*ñT*õf¨jÛIÝÊåú¯Qð Ó0^ôûŽÑõpîâà¥óåâ@DO{Œ 7ù&€À*o@ü&4uBtñj|*èoP•€‰‰‰Ù ®pÛœ²þÛж™d,ö*÷¨�›-.óûU% X,~@ôœ…X�óûMwDDQàùáD©ªuʪ(`‰§°/|y�AH�v�¶Øï0È%î#m4la�BHŸv^â÷ š“:ÓþÞ_ ’íL¿OÐèó‰ü#laį½Ïï�zœGoj�m:‘L&‹*.S4�NGÝ>U ÿÓa§Å;»¨JÁîc]©ªas¾`YV·îõ€Ò’%KJnŸ 9À³¢Jò‚¶¨ë§w›<œðû%Àv)èU3çù‚¦ESîcV•Ou7uÀ}$âz£:ÏPâø´sÄï0À·ÙÈe~ŸóÍ» Ò>^þÕÛû2÷þûÒÑB!¾¼öBR#d¥Ç¨ô=~¿ªœÙ[{Ùm‹(µÒï7ÝÉäó—Á»£|ÜJ.xÍï¼@ñ¿þ®Q[GЫ5¿°B¤â÷ L@Dãvœ.j8 qåèáÃóBUØFHj¤\ç¶ e[�o` Ã8b—ËÔ)–ýÛáÓÛ.\p‘Ë4‘MÄvùÖ\Ö„?ò_Îd2‰p$¶�t:¥ð»^«Ü4ü�: 0 ã%€îÉ0*zdcÛʬ9s¿ïkï±â¿{¶Öò¯™!”öMŸùFÛ¶«ÖÕ¦ oŒ�_$¢îrÛ„øþ¢Eóª�ÏRwoÐ4ã{ò ·¿‚<›Éd.nQkè¤Óéh´ìüÊSCDüåèÑ#Õë7éîp¥\¼ÞÕÕ¸è]ÏŒŽŽú‹£ÞUf÷õ?ÁG]¦2uY7YQå¤ <¥] xÎÊ+"ÝÝ“ìH­ñdX§w€ouÛ„²¾‘²�†j„L3¶Ÿà:�‘Xkå �øWX: IÉÚöWIüØ×ô@2¬‘Mý‚YÛ¾� ^Ø[êÒ¯{ÿ‚Gktk ét::«¿ÿa!nñ5½hñ•µn{~š-“Ó­|þik|M–Òdõ@<þ×fâM•±±±ù‘®è¯}Û÷ð:”³Ì4͆r§R(©[vþ‡|Ý×Td«S.n<ÒlÜFÈçó½e_á�Þãi<¯ÊåëÞi&f+¥²·P¸@—/àI‚÷UJ¥-Í,Öc7IØ…›E¸Þz%‰-f"¾ADœfc·V,�Ë-â4¿ `'Á�N©´«Ùd¤Óého_ßr Ú*W z / e}£^-ßÆÆÆÇãºã<âÚ:neöB°JÞPJÆT·ëªTN–J%§§§§O)5—¤IM[ârWè¯óÕ3åòlEˆLä?Iá½. +f üNÒ0~:•!ï'ìOf4Û.\ÍӓԇŒ #ÄÒy,ÌŶ=ÉÙ¶½˜"g?šZ8Å0›3!˜ ¢_€�w�dÂ�ÜkÆ�éRŽ;à 3üoòK` Âd½Í»IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_unchecked_disabled.png000066400000000000000000000020251526321767600305400ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÇIDATX…å—QH]eÀÿïê]óÁm!ÌJÙ&+¶¨Z V+õš §3B6mD/Aàèá Ez*ÆbN-"Ÿ®WKk¶{u\_ÃBF+„ÈF]µˆ �Zê½÷û÷p¯v½×9/^{Ùÿéœïü¿ÿï÷Î9ßÿÀ�’M²¯öx©õäÕ‰±¨”%€˜Rˆ :Šäõ‡gÌ©@•Ó|0nM» O¯³î¢'C½]#¨pZ¶‰µ/$‡f :G&½&>³‹Û<³¥8®v·ˆø€Z`W2ÿ¼�Ò42Ðù{ÖUNó^keØŸ‹»~ïGáp[l-i×uÍ¥«SÏïeÀ/ÆÚ£ú»¯¬[ ¼þx™Ás¡HàsÏ]ÿ¼8ÔÓóçZàô¨®~}K´`þŒ MÀߊt�ßV º¡¡06_ð5胠ï?ñPÉmmm6xj}_}s«Š¼ DŒšƒú:fRLúŒØ|ÁéœÁ Â4Ø×ÕŽÒ ”Xc?%mÑ+N*Ÿkz Ìð‡sÿ°¿cnðåpÇ;k·]öGB�ÎóK×VÜÁœP•·sðûý‹*¼•Ä\ÌXÔÁ¤Ý‘--ù›ÀEŽ&©ý¡�îi„‹E;®Û—sM¯¬?Q“Üä¾ùÏ-÷+Þk¥@·º¡¡0WpÇq¼§= èª#}çÆTéAÙŸßú‰ëº¹xMe6¾ýƒäêÃÁ@ש3ó0¡P{éjä½ JHe}󛈾‚0MÔ6�²z¸EK–ì/w}Qãm ûÏü• Ùqïœ-<­È à&اB�îoÒó<«Mþé‡ñ{öø Á'pÈ£ñƽû�+ÝYóݵk£kvH®ëšü¢œõö‚T’hÅ|Á¾ÎoWË_³-?\÷Òö|“×�à$‡"ƒ C‚™ÄØ™…hÜz=Þb‹îª­%Ñ ŒšhcØÿño·b¬ëǤÜizÜXÓ<¹ž|`±­¡Þîàí³ú5{¶îÕÝ1«#¢Zª‰mÕD€ˆ¨Ž"žþ` c"›ºwvü ë2dÔTÂCIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_unchecked_disabled@2x.png000066400000000000000000000043451526321767600311210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+—IDATxœí[mlÇ~Þ¹Û¡þh!¡ÈЬ (¦*˜V5E`Àœëª˜ø`Õ� bã�†¤­J”F)9܆~¤ ‰œ�!ÐH=l#“Æál§F¤€B U6QR‡Pj%Q±��í»›·?øÚÝ[Ÿï|»®iýü›gÞ}÷Ùçfgfgæ€1Œa ÿÏ ‘¸I¡RzwPÚ âÙ’1ƒ€ig€( 6 ¾‰Ô.Gý>ïÇVk³Ì€%÷Wf {¸D01ðÍa¦ù˜™›¢¶µ~×;ØL�€ùÐÒâ²â /69÷&líùŠØwjçΠYIM3 À½n±$ñ €yfå4Ÿ'`³¿®z/Lh °´¨|"Ùñ,~%L2ð7b´1øœ Û?Ôý—S@á�0R‰D:ˆ¦‚1�ˆsÁ´ @Ê` 8j­?\·ël"ú2 @)ûŽ”tÀ$}—¼.ˆ…Ãýo´6ì½Oî\eCʸp` A,q‘Ñ=ôX×\ç}uX€ Èw—=HD5’"D½àtÚ÷—?mïn~5EqöÊô O¸G_OÀ–Üì̧ªªªd¼¹ã6Àãñˆcg»žóF]•£ÆT5Õ{/Æ›7­K½j�áq_R×1è`H8Ö´ù^ºOθ ðx<âØû÷ƒè]–.A\|ØWýv<ù†‹Bwùä¡‘î»öäkyMû÷bÍe‹çÆÎñ÷U�èQ}B°Xz¸ÎûA<¹ÁG§³ísÈ�{‰4sŒIá�cvNvÖŸÛÛÛc!b6Àå.ÿ/êè=ÁÔ�Òújuo¬yÌÂÅö¡ÎŽÓ Y3ç\Q>n´f¦÷!%¹³ýtK,ybz–­\7G$«è}ÍuÞµ°`v/òÝå¿ ÂsjŽ µðîêZ1TÀÒâµãqê‡g¼L U`<<´Ô{·�±[ÍcW�»rîP×i‰¤gdÞ&Ð…�,n«­íŽX‹Àök)ëSqÎ0É]yy{´ £�¯T. ð:õ�XbescMWb-ASÓ‹ý27ÿ¾É0×9þ_�D».šDáðouÜþ–zï‰D„Z‰ÖFïg lQsÌxÒµf͸Á®Ô€eJÅB-PQAÉa� :-E(-´À…[a_MþÉ`ñƒ·Æ/µ½ÜZ¿»3a…£­¶¶LºŠSÅpÈ74 O)ù*˜¿¯¢‚2ÈO›¦ÒbdØz_øC•Ù#3ò�b pHǃÐN’Þlmô~f¢FKáóùÂ`ò©9?d;È+ÀË55š%n¤@$ôš`ôDp£Çœ¯æ$ÑkæÊ³¹Ù“N‚ nµé¤åèã" àkÎïpª¨¿·øv^ÐÇ�vTUUI04?œd±Nù °ÈV‰pÔtu#kµ3féc ÀLuQJú0"æN �vž©‰4€ø^-!GýØ?(¨×>Uc4 ¤ª Œø·¾i¡=U2¤‚9®5¶Ñ„¶ÚÚ~!åTEÝÁ Y$ 1*¾ù­B„ĸ¬ `Žh6w òJJ’¨×|>߀:&rp}§övȰFžõ°uÛÓuÔe}L¤À'‚"{Î;Irš¦Ì8¯1št¨‹ºÏdY#b¡ÑÎÀ9}L„‚¡Ùld`�>æN�`Öj'œ‰ˆÑvçq·öß ˜[è.Ÿl…@+áñxƒ~¨!mú¸nì­Ws!Ò%ºðÖû]9Ðì(S Ô�ùŽ>Îp=€Ýç¯,2UÝ€„^3¿ÑÖVÒÇÀA¹€j«™–*¥w›ªÐBx<AL«tô£XCškºˆàWQIAi×o‡�Z?ÛµÀŒ›e> ^Êôź*Ìà?ªË~t‰»ì릩´Š¢8™ù×jŽ™Ÿ3jþ@šT¿I¬é �6ÂfsdZ‡™V ígowJˆ·mgˆ¥À&-Ek]JyĺÚhAÞêÊ zRC2~ÓØX1¾‰¨{ƒ-¼m½¢Žg‰†¥EåRjEq:úå¨Îð^÷ñB´ë†Þ–¶Çu««S„õ……?ÓŽú¯¢W¦oa‘Š ’àŠ¡Ui€¿aÇç,q?€~=?xWßK¡³ÆCÁµªâ«9b¬�åÌRLGd:;N_Ìš9çߺ0gÚ7æNÊÉÎò···‡ãVmȵ²üç lƒêÇ Âóþ:¯~gÛ1Ÿêìx÷½¬Y9wøÞ­9}2yá×¾5ïµógN]�Gy¢PÅ™9sþË6AÛ/e–ž?$¦3ƒC¾jdPï&\?žv„EŽ�ðÉ|¥rv<¹�«øá{zÃi­ÊtUgƒáЃ�ùFˆûVÅÖ#3þ@à ºª €í$í[ü ;>�7o,ÈU6¤¤ÊË?eÆF¾¬­å&¶Õ-¾�_Ä“sØ�˜Ë]^Æ„íºª+DxÖ–tmk<£!/ÏcwL¸X¦ÍPŸWºÞš!Oø|¾¸û¢„zq—»l!Õ© =pÈ–rÍ¯Š¢8»Ã ñr+MÃÄXï¯÷VG?`Â0æZQ:…í¶ç¸£„ 8„¿2Ó6þˆ%w;Æ%_‘÷¤¦úÓ),¦ ÂtfÊQÀiQrž$�õ~Ÿ÷T"úMÇ]«* ™ù÷¬í ]ÿ*ƒÞá4ùÈt&âúaê® ÞàÛfæÐ `k05TmæEËfr++f1PÂà"Ó‡“ƒ€O%èuÁrOîìÉo çÿ1ÜÃz¸V”N‘ÛbÍä 0M� ×wn¾蟟cà‹ð‘Vßã¸cÃþ7ñ8ñàç�^bIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_unchecked_focus.png000066400000000000000000000017231526321767600301140ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+…IDATX…å—MhœU†Ÿ÷fÒ¡µ•¢)6´­š��ÔI²ð§¥´Ti“š©…¢¸p').¢(p¥EDÑMh3i¢©,éBÚi¬¥ CAˆ “F”jµ?Ìw_3I“N’&dâ¦gs?Îw¾ó>÷~÷ç\¸ÙMó ~°×Õ -–·ZTcÖ 0ŠÈWB&Û¦Ë Ð”q:Ú]Àæ9&J¤ýC»õÍ‚ê»}k*ß=]t�a÷;„#JY»’":R%±AŠÛ@ÍÀúbö‚öe›õÛ¼šû¸ê\¶š�7+?k—:Òu<%û  Fâçhí:õ„ÎÎ`ÓA×Tg�5Àa–éÙìcúkVáëlÇ€—þq9¾Ú‡ù'X�hÓ™4 x%—}¨¿“=^â5ÅùˆO˜­†^:°ßry+}ºUc“CBÉGWâ Ö¦Aâ’³-t¬KÉŸaOéô€ôAoÂÚcø=I´gAâ“ .æÃ‹À9`KÃ!vÌ  ¿¬×O·ë‚ŋ6Ü®«B¯Ý5y&êymJþü;¯µÃíºZ. 02î3ª_#� ì„üeÙÅ$ËÇÝ×~�㣅&|Uvñ¢E…¯,m)@Õ…†Ÿ ˆ̺i Î ÆX$[½´˜[Ü9>K÷�ÿË^¥`À‘ªÅÒ¼pi"÷ùñ=f€pà®ÅH ¦ø˜÷MØa 8n_,·ÕŽ•T¦è0z¼þW–]Üh@TÈ”|Û¬óÀ1`Måíà^`ÔRç-«ød.Eicm.¥÷9YÍ'[õýtá³–åu¯Zêø!èÉ¢+g»?T„#Iž‘TdìR%qyBUëCˆÛ](ËÇ7œ£1¯½Cíúu&�9]LÒ=nîžK¼Å¡Žìn½Qì¼®f�op¤y+PMá­rˆèxHÈœhÓ¹ùä½¹í?‰Gc¦‘&ÐIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_unchecked_focus@2x.png000066400000000000000000000041171526321767600304660ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí[}pTÕ=çî&a« ~´£ŠN [ lBÁiÇÊqLÕJu¨ÅÖ™Ö±tpF­Øj+¨H[?**Ó™…Íé€:S ƒ|lBÆÖQ¡cë0©Z åÃØÝ{úGPß{»›ìf߯¤Í™Ù?Þïžû{çž÷ö¾ûî½Æ0†ñÿ ÄI®ˆê¼Óe˜Ik/“ÁŠ 8ÀHÇÎüö Ú ˜7Äööù|§ÔÚJfÀô¸.I[»ä|“ú•DxF[¬5Ow4`Hù«Òo$ÖÅqµ…–˜ígj¯ \•ú'žë¼�IóúƒpL³aô „©~åÌ�w.o�à? oÔJÛ‡~§š°T›¬Ùgø»R8l-Ž�Ò' *Ë€Q2'`< :ßê%çvk¹¤cß(FQÔÅ5ÍJ­¾˜¥ø8¨Í”Ùd�Úø¯‚rGJpi真ãÝ"oi�ðýÑaÀ´˜nõ� ¯(J�+Ì/_™Ë#ýÍïDuTå•A,t/€ó½å‚V¶ÿÅÜ‹´…æ.Ü€f™ð${Èež+è)ʬH4ò`ÁyóÀ×7ª2iq'¥»œí*ZCi.lkâ‰Brf@³Lør»àõž’.CFvEØ^P¾~"ÓE0Š{;\¯²‚³sx,ß\¦ Õ.ÏÒøÝ)qê@5� ìƒ.t„º‚FÚ¾ËîÂ¥–¤F�0K$ìtDËE=>k«‚½UíÕ€p‹f¼ÅÄÆõì*Fo)°eO1ȇáÉÝGp{oõr Ð/<Áu‰Fî.BgI‘¨çW:c‚î™ô¢ÎÊU'§uqÌ0ÃJ¦­i.^fi:†ß�Øï�û¹�p[.~N,ôç1¥ßîYÀ·}ÐXRôôMt](Awæd5 &ª/ø–#”TÐÜçŸÌÒ¢*‰g¼å]øžÁ7²q³âFôLUõ€x9QÏüYJ¬obšÐzgŒÆÞœ�›ÕAó\Ëç}S7P0Æ£™s²ý 2 8ÓcNwÆRiüÑgy%ÇîWÑÀy׎:X†)^^†ÿA-€rGèÏ�MÜïå z¬ ¥äºpRæ�=^^ŽùºÞ¢Í÷W^éa`]š½Ð6›©L^”°=›ÎTÆUWDužï*K…f� œ!Z³65«;êÙ%à¥O*É õ.‡ZÔ^ŽLp„Þ�ù´=Näœùk×1øƒé1�õGbéPU¹¤Ÿ;c"Wg»ý�^ è¸/ÃÝ–§a—û¢²„8» ß]ƒ·Ãekrñs¯ ‘"y·'vS8®ŒyµÁ‚)Ïë\J®%|ˆ÷ï¨gÆøcôº6¸;Â6PϺøR<¼Q'ÕTGUHiÜ{ˆ^K£½Õësu8 sܳ«UJ©åšÍònŽúL12h!p¥#”4äâ¾6UöiÀÎ~ñZ§>Ž‘˜~¸Û>Ö³€úÙ#Óí¿ïŒ‰\’϶�¼Ži!(÷Ž éwÇÓæï;ö€AbmwZ çŤND?Î'EAW°6–~@äR—`[:È�óy(W½R :ªò‘û˜È[]Ä‹¡s87×cÏ‹‚v‰U¥ÍÝâîóáÊ`Ju­º¬�\Å`z‹Î¯ êO�Þ8^Ÿoã�~l”¼.ªÀ� ý•@ï-–´&³rg?,4o>¨‹*”⇄–ø¼§xK*Å:›x´�œýß*×­”Ö(ó� ô�BfU!{ì­ vÆ"QËáÞ¯´jlÊ,]ßÄt¡¹‹êÅkbši¨c²´ 2›ÂK…šQUùHƒ™2vÀzÙ†áI‘KÚ#|²?ú¶Ë×´ªÊX=  ¡ZÄ6Yn¥Á_%üM‡+‚8‘4H›¨´å¥4Æ�OØ:€W£ç“š\Â;D.IDØYŒ~ßžãµq]#é¥î »$þllOôç–÷Âß�L³Ì´I¨7Ô25¾æÞ¸*tOú¹G±d#¹š šhŒ]tæc‡ñýLó> ÍVfmÇkx¥?ßô…ÊÖ´ªŠ³�ìD‘Œ#1JÂHô¬ÜEÏgsí#Í>ÛõØ;X¶ãcÃøßÄÔS’/ˆIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/radio_unchecked_pressed.png000066400000000000000000000020031526321767600304320ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+µIDATX…å—]h›UÇÏyû�Sçl‹Ø²YªbA‘5Íô¯96D¶N°ˆÈœ ×t­éª txƒC ‚Å4­&ˆ¢W‹ít:Pº+é²X¼°„ š6®Åm6Ë{/’~fíZšz³ÿåó>çüÏá=ç<nvÉj’ëš»+­›Ù/*»**P Ê"I„sŽÚÞÁèÑ_ àm ûP:€§V8k\T�Å£G¿_@mcô‘é�€s¡H¿*gÔqGõ_“*Þ`¬¦ñX±ÛŒa·Zê¶æ¦ÿÆqÝCƒ'Û.®`{swµÉØ>DR"oÝ2ùÉ@(”Y¶¤`Ðx'Ê_9Zün`ßùhëÏ+ðù  [4l¾rJxy°«õïe�©:.Ý4MÂ!à2Âc>nº!ÀŽ@xc&Í�5Š~˜ðL½A(dWc>'•:¸]‘w�¤ªëKÄ^OÍÏ0‹‡¸ÓDj€þµ™ˆÆ£­"œ*Œ8Ÿƒ.(z€ÏßåE8€ð§jé�µ™ÏA\žœlFvzýág–°¢ï¨ê;‰˜ÿ¯µ›g5|*”x+Ô1fj;ïBy˜º:5-”ùŒâÑ@/0<èów=” ˜½€ |=|*”.4ˆ¢Ú`EŸË@äIE¾-¼yVÖ˜ï²(²3*‘ßÖ  „Ì(€BEÀLÐȵTþÐÂèR±33÷Ý3?bÞ9ð¿)øöB�1€´8žõò¼Ý€ÂøÌ3·*Ë=ë`®¹UÉÙØÜW‘=ë`Ø  ðC€[$ýªúlmc´¸ðö*Ve€±noÀP$0.Y²Í0ýj¡í½G"{s—Ü/ñm³½ÁÂ]`m;€Á�ðÆB™×4KÔfï�c z]€ø‰¶¸ÂÀ7Ígƒئ*î,窈G§çÍ7ÐÒ²—F½w¢üýµA¨x›"o"øQÆÝbyi~õ°DK¶½¹»Ú¸î P|yÅq÷´ü³뚆`É-eå�ÃÀƒ¸°8oɦÔw8rŸ5¶¸_‘1�àmžKŸ®¤)­»Xö¼U9.p/�T5õ‰Øk?]/}Ù¶üáW:7•šHC.”¡å ÖŒÙtêª+Ö))ò¨a«±vbêsÝ0ÀYqœƒñž–‰¥Kàå†I„ "Šò†ÚÀqËqSÀmóžÏêp¸—�ø ™†æ­íŠòðÁW�·ÓZTU´ŒÜ ât<£³Ãkû-Åë!¦Ì^S°æ ÷Å…i ¡À¹Tc +ìkÍ^a¼yö1b}uóÐP8îtG Ølhš(;y³ßÿ¦’j¬”…¾’ÐÏi9"Ú4¤#Ë¿w}é™TãØ…ãûÞ‰¶4mß2Úרà.\Í4öÌ ¶AÍM;ÿœJœ”�É%¡ Þ`Ðe–ß×IÇêÌ* ŠƒK@xÅ@?® ¼Ö]ßn�É‹VybÀVènû3;†õ‡›€ðÚ²*€o ×y‹WMê®o· �ù�¯¹D0šcNš]¿qîëVÓâ3.*áïÒE$×MSUG²žIà-®¼„yŠ¥‚Ÿ~°ª¬¹7vÓ�OB�%*ï𥆞ÔÖâY˜¬_’0‰ç Üæ÷«ûzn3½h¨]Ò ÆJ-G„§'<üâ�D}&ÀW*p»†Š@ÄÔÞÛL/2;³Ö8¦¡F:Ý®’Dú„ `�_ê Ô„«—}Ök‡iFýƹˆ`ø¢Ä²Dkƒ¸ ð-\�`††Š(R>k—Ét㆓9¯3ðñ7×¾æSOë]ñ´q cч Y$ðnCí’VÛ�¦ uu÷LjP§åó£ñ´q@ ™æOv™ë+°”FÏ?Ž÷˜pqƼUËI޽m¯½ô£)÷t#í¨vÄsÂkÔ™�áv}€ë2CÿhZ»ä˜Q×ïQ^.Ö}qÌæ}Ê8�€ø®�Øc«±>³Þ;1Æ5¦0óͺkÈ��š+‚¡÷N¸Ù¤1D¸AG0õûßþ„p:ŒÞóŒó di¯IPŸ¿ëÛ…!ín£÷,£Æ<°^$˜-í±õ'ÔoœÓ ª¡\ù~Õ¥ÕÄ[è6I¢Bö‹wþt!^ÚtVLÃæJÁ´93h÷:Ö•wj5æIÐí¨²äáé±—~|í8;Ì@µ5æIô¹öš„yæ¼RÀŠcŒžÀQ£&Î$ȇ´—|Çf_} ©ó΄ÃF�9$t‡�̺M‘+ ƒw¦�SÚÚ @{þ>iÊü൶»K7TUp�–b…ë�2SºÎÖh¯–‹*t�Q×ßáká…þDùÜÐQ'ÃF]ü-1Ö¿Eñ,[Ýõ„Ðyf`g}yyÔ$‹×7æ¢Í.53îœ87x•ÝÓU üLKxS `€mŠ »¬&#߯ºÜÃ=…¤`&KÜ B¼ex ÒpMÙúØ`C¹¼oáêë8«p_Y„Ý�ø+ýK0ŠrêÓy·#‘h–dǰ(#��Ë©Ý�®¿Ô$rÞ(‰K߯~¼©7þmû/( ý‚Ÿ�Þɰ«.ù×y'sj{2ä�°w!£ªbrkö½´ Ÿ­±AŸ�eEfçÐõvÖ(¦m%ç+Z5^ žCàYÆö0Ì 0¶ÉM�9§ÿÖ“ÿt‡>YÊ^œ'¦ƒy<@ã@È0 ]ϸƒAg‰qÄÿ&Âa)qØAØÝPSv¨¿”ã`øßÄ3AÇÎav�êIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal.png000066400000000000000000000002321526321767600305410ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+LIDATX…í×Á ÁS,ÌÂKÒˆ–O|î>ó�Df+b®ˆy»g5[°Õ­=©¾ý ìϨHÃÙ)ëÄr»½,«ŒIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal@2x.png000066400000000000000000000004631526321767600311210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+åIDATxœíб Â@Ñý.‚ É5ÑÑ5Y&¡ L`‘Atgó"_°7‰¤V[ÿÁ4ÝOK=¯IRËpÇã­ç}«aËO’õ1uHêð~XÏûV›Xóé»×}›ü6Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh{x|ùîußdóµÔ9•9•¹–:÷¾—¤/ó½(8¶I:ÖIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal_disabled.png000066400000000000000000000002331526321767600323710ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+MIDATX…í×± Q4fîÀ˜&¬æ"Äò®ü Ék¡dºÌu™¿îQ£`˜ÉýZ¯ý ÒŸQÙ™�¢Ø !�{ˆÑIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal_disabled@2x.png000066400000000000000000000004651526321767600327520ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+çIDATxœí›±Â0Åž"1ÇÐ0 #pLÀ4©²…)]:Ûˆ;¤êÿ}õNDäŸ)£°?ž¥æš$µäò¼ß=÷[Ù�üx’¬ÇLI¦Ïa=÷[ ïc¶æ^ûM|#ÀOcZ€Æ´�hÐ4 h @ Ѐ 1-@cZ€Æ´�hÐ4 h @ Ѐ 1-@cZ€Æ´�hÐ4 h @ Ѐ 1-@cZ€fü£©dÙš{í·2<@MNIæ$ó:wÝiá,'"0žBóIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal_focus.png000066400000000000000000000002321526321767600317400ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+LIDATX…í×Á Fa‹vòÚÄM¸™´A¦t|ïøƒð]¡dºÜt¹½îQ£`˜ÉýZ¯ý òŸQ“�Ú)è�× ½÷y�9IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_horizontal_focus@2x.png000066400000000000000000000004611526321767600323160ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ãIDATxœíб‚@á÷[µX-Y‘]P‡uY ™Fw°Î¸_tÁ ¼ÛDÒ?«½pžÖqÍzÛ~V×ûXSÏû­N{~IDATX…íÓ¡ ÁƒB€R0tMB)$ß(,òßì¨s«NKol³¥£î�­–!IÙ#üðÂ]k�  Ÿ£IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical@2x.png000066400000000000000000000003241526321767600305350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+†IDATxœí×± Â@ P;C ¤ÌÄ T™(›0O$šˆ!r´èBʽW~¹øvçú‘u°,¯{ÉmŽÈK‹BZ³äcoÏïp¨§Nº|Dĵ e®ÃÝz³;@–aŠ(ïe¶æ–SëÀÿð ÔS']>Â/ð›_€N|áû(âª×IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_disabled.png000066400000000000000000000002141526321767600320100ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+>IDATX…íÓ±Á£2‰ ´ ,-hÀ˜ÑšH*$¹�>»èA’ôY8#—º€ô(:Go ¾J7¾@’¤ï6ñ) {¾iÌIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_disabled@2x.png000066400000000000000000000003261526321767600323660ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ˆIDATxœí×± Â@À}Š@Dˆ qENh�”Ä Y4ñ¤È/Bë‘=®.Ø»ìö£,ƒóõ~)5c’c‡>«)É\“Ûô|¼¾óC3¸Á哤&§$ã2o°7ÍjÉ�äݡ˪J2'z÷þ‡_ Üàò‰_à'¿;ñ×Sü¯IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_focus.png000066400000000000000000000002131526321767600313570ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+=IDATX…íÓ!ÑåRªâ.êfd—2’*Rö¥ß6}�$}ÎHm ?ªöYcˆO‚Ò…/�$é» »X ƒ2eIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_focus@2x.png000066400000000000000000000003231526321767600317330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+…IDATxœí×± Â@À}èQ u : rEî‚�èÄ¢xRô&µÙ3áꂽË.`;Jœnõ\SÇ$‡}–4å]®�K¹‡»vj¥Ë'ɱìëØ†³lÍì%eHòìÐeiS}•¡w àøÚ©•.Ÿø~ó °]¼$lŸƒAIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_pressed.png000066400000000000000000000002171526321767600317110ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+AIDATX…íÓ¡À Ñ…š(“ZpƒJ1™¡�…Â"ùfŸ:·ê@’,íQÚ˜@½Týþ·?ùJP:ð’$…[ Ô é IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_move_vertical_pressed@2x.png000066400000000000000000000003211526321767600322570ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ƒIDATxœí×± Â@À}Š@4B#´@€Ñ ‰E#TáB,šxRd}jŒü3áꂽË. eœo�K’±&Ç ú¬iNêuzÞ_ßá¡1¸Çå“ä””q¶ЕÖ†’¼Þd}sR‡­KÿÃ/ÐÜãò‰_ Í/@'>ìý:W˜ÉIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal.png000066400000000000000000000002271526321767600315770ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IIDATX…í×± AƒŒÁ‘%’�!LÇëÚHTö.{'#Íè^RO -úŒš´^AþíT(ûö£‰|IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal@2x.png000066400000000000000000000004441526321767600321520ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÖIDATxœíб ÂPDÁ;Šp†äšhÁÑ5Y&¡ L`‘AêAòNô³¿÷ª"âÈZ}<Ï�ËÚ¯[UU¯§ë8žïbÇI|ZUµßCUŸ °ÿí½/à?$€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ %€ ÉÏï]±½öT]Ku-½ö¤vDı½mTº– IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_disabled.png000066400000000000000000000002271526321767600334260ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IIDATX…í×± AƒŒ&d…Œ‰”ÕÂtü÷±®�DF‘Õ‘ÕÎÆ2 Û¼×tÀÍúŒ†t^AþíÝ뮢IvßIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_disabled@2x.png000066400000000000000000000004431526321767600340000ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÕIDATxœíÛ1Â@Ñ "¢  A  &.BAèRg™a_uÝýÛþ É?¬‹÷Çóa˜¹Ì—çýö0vìŒK–Ç�Àø aÐðyüÚySf€ŸP{€­ö[ì¶Øl°Ø `°À`+€=ÀV{€­ö[ì¶Øl°Ø `°À`+€=ÀV{€­ö[ì¶Øl°Ø `°À`+€=ÀV{€Íû4¯µóÖ´3œ€ ˜–s’lî »“Pçç·yIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_focus.png000066400000000000000000000002251526321767600327740ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+GIDATX…í×± AƒØ)-g¤l1„éøïc]‰Œ"»"»œ�e¶y¯é€›÷ �GŽ�»²Ó|c…~IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_focus@2x.png000066400000000000000000000004401526321767600333450ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÒIDATxœíб‚PDÑ]‹ ë "+² ê°"«4Ó”ë9Ì�~ög_UDœY«�¯ó6nµÝ÷}{Œ=‹ñiUÕûø¡ª†O�¨ýøoïCÉ!ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ô-ôMxþxÊX{ꮥ»–Z{b;"âÔ^hN;FäÒIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_pressed.png000066400000000000000000000002271526321767600333240ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IIDATX…í×A Áƒ ©pS?ÕCRkˆ8~ìþ{™o%2Ьެv6–iØæ½¦;nÞg4t9>îŽÂa¾‘IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_horizontal_pressed@2x.png000066400000000000000000000004461526321767600337010ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ØIDATxœíÒ±MÃPFцð&,’R †¡‰²Da‹Tla ,¥ˆh}"åÉÒsõ>_y&É3{Q¿½fæ´½~|Ÿ?/bÇ«¸tsZg–uf™[ˆÝ±Û‡ß�÷&ÿ€‡P=@+€ @Ð  hдèZô­z€V=@+€ @Ð  hдèZô­z€V=@+€ @Ð  hдèZô­z€V=@“~þ9ï X�3sý{Ö£Û‘ä™ýÉnJ�" IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical.png000066400000000000000000000002111526321767600312100ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+;IDATX…íÍ¡ À уA€Q0lMÒQšüE@Õ"1½§ÎH’ôwé‹7âaÑ/Mg«eäCI’¤“ ½×%!U"IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical@2x.png000066400000000000000000000003051526321767600315660ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+wIDATxœíб ÂP P;C ¤ÌÄ T™(›0O$šˆ!bZôS‡/‘÷Ê“‹óEg�m°,¯{å6Gä¥G¡­YùÇÛó;Ú«?}>"âZCÍm¸àlvd SD½{”9Øš[N½K¿÷%~SÇ IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical_disabled.png000066400000000000000000000002101526321767600330360ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+:IDATX…íͱÀÀ0™ÆV0–,àÜYM¥Ujä«tI’~NäR�Mçè-ÄCI’¤› ¬~ˆcIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical_disabled@2x.png000066400000000000000000000003101526321767600334110ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+zIDATxœíбmÂ`…Ñïgˆˆ�2bƒÐx"š¬�6 Y,á´‘]ƒ%8§¼zÅ}·€w0ÖÁçùrK×êc‡>3j^êëöóýû??l_ðùª¥ŽÕu�ox7›–ÑTÝwèòP£æjÚ»ð| Ñ Ÿ[ÇIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical_focus.png000066400000000000000000000002071526321767600324140ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÍ¡Ñc)U1€EMà=ÙRž¤ŠŠûéÚ�$I¿ 'R[È�®}ÖXâ“¡$IÒÅe¼É9ŽøIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical_focus@2x.png000066400000000000000000000003051526321767600327650ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+wIDATxœíб Â@À=èQ u : rEî‚�èÄ¢xRôŽ�%<®.ØÛØ‚êƒÓ­�[Ú˜ä°BŸ%My×õq©ûw¸ë¯þôù$9Ö¾�}8`kfTjHò\¡ËÒ¦öªaíÀï}Nþ*?ç�IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/toolbar_separator_vertical_pressed.png000066400000000000000000000002121526321767600327360ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+Ÿ$·¤ ë°5À©´èKòÙ½Éö–¤öG—ö÷¦p„™IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/transparent.png000066400000000000000000000001501526321767600261400ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/transparent@2x.png000066400000000000000000000001651526321767600265200ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@�òÉQIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/transparent_disabled.png000066400000000000000000000001501526321767600277670ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/transparent_disabled@2x.png000066400000000000000000000001651526321767600303470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@�òÉQIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/transparent_focus.png000066400000000000000000000001501526321767600273370ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/transparent_focus@2x.png000066400000000000000000000001651526321767600277170ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@�òÉQIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/transparent_pressed.png000066400000000000000000000001501526321767600276650ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/transparent_pressed@2x.png000066400000000000000000000001651526321767600302450ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@�òÉQIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_close.png000066400000000000000000000013351526321767600263010ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+�IDATX…å—InA@ßïdÜÁ]m¯à \�à@Bˆ3Iá‘8ËìX@æy@Hœ�3ÀÊ=Ip`Aú³ðÔi÷hõñVõWÕÏ¿ª»møßC†ÏóªXïî¢òÆqëy^ØFô-ð[Ðׯ˜/·\?ü zp!,6mû¼¸ (Ç€ÕÏÈ·¦i<`œÐ;±5ʉ�úá€è½1h”“- ªS ‚Î"UÝšpœÆ5ÂRŠÄñ4øÉé¶Œ¹œhÚöiŠÄLU‰ÌoŽt[¦qŸk‘ˆ¦mŸŠÊ«4‰žïÏÁ{¾??€ÏÁ!v$ÃóÂE=LHÞ(ºØ2æ" .ÈI®Š,§Ás/Uô ŒDÏ÷Ÿ rZ^(P ñbx˜¦…—èÂ%A÷Ó$úEÒàÚmsXT»”@ŽÄð Æs¥á•b9ë*Á!å6Ì‹–i)²,ˆfÀWªÀ+ XÊ/ES€Ÿ•ëU™ìyá\$z–±Îä¬çûϪÔ,}Cl T¬í$\”�iáŽcAb;Ù^§½ZGpDZw¦…HÜLˆZ›@ø¡h·x\B‘eà;à¢Ñf]µÿýø –ï€QvéŸIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_close@2x.png000066400000000000000000000031241526321767600266510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíšÉsE‡¿×YXœ @E£Iä!„Ä ±C6þNp€•ŽðwP@¨Ä+{ XеŠ*bkFãC ˆCˆ�²úqˆ”2’lõX3¶(ü{^÷¼ßçni$ ÖXc�ÿ3Ònðܹs7ý={õŽ@ΈÖ^ ‚ ²Âý-‹0 ‹*}/‚îfAN^Þ¸þõ[·þÕ\Û"à§ŸÎß²~ãì »š.]ÄÈ`Ñó>Ϫñ4˜¬V1ʰé_„oççæžÚ¾}ûÌÂaÓ¼Àº W^l`V‡+q¼'ÕŽSdÑðʹu^jn`„cKÜ£¿W%,þ:z¼y¤E€ÂÆ÷êÇêðT?š´É¬˜¬VwwÀ†æ�À'÷ì«#½ ¡~”Îá´%[‹käpÑáÞ«.!Ix`¦f̫̓-Êž÷³9ˆ»„U9 ¶=À Ö –=ïçæ mŸ¦âøQ±:ô;Ü࢞- _8ÔvME[dØÜ¹Z/aû‹ùÏÚ]]Tô¦„4ÃCÐ[Ò*q¼«Ã¸K8P.¾tYÛ•0 R1£À­�«õ’hß`äÏtªt«+!«ðÐþ9 -EÏûk�™ŽÅ°É(£“Õên×õ#yxr  v@ƒJeú1Lmä‡ò?ë¯ ËÚ I ü…ÚÁ >Mr�Ä ¹ƒð}ÿ«$÷X‰ðõ¹Ë#K aîR1cd¾>ù„áô^•Úé4%$ /è�ïû.Ÿ_[£;Ò”°Òá!Á»ÀbAþŒ¨�^r(ßl‘‘0 j¾Pï|ækè¡nÃ××J‡0 GÌi…›Êÿµ‚ ø R™~cÇ€-s/[t¨ìûwÕp�ÔÀò$¨æìj…‡”@B ÊŒ¢ˆˆËÓeêá!Q=¡È)Ç�àÂe• …�RZï:™€T%dRxX ß÷?©¡‡Zþ‘€Ë*<—UxÈp4˜Œ¢' r ¸)áÔFø³è«Aæ .Aeéø•{ƒY³�…ˆ13WL¹*5ãò±»k20Ç;Åê8nßÞ6èÇØ±JeúÁ¬új�éXþ¶e.qkö‹ùoÒìk!™í€©8Þi¬Ž±üð[0vljjú�´új&“0Ç÷÷YW¸=¥%/hÍ ”JùoSZï:©ï€„áçT™s¨Û"}Ùì„T$ +C;Ôß–…„ÔŽÀÙjuGN™p /jA~ ÇOcõ=àF‡¹¿«‘�’ç}×UÃuRÐMø«%¡ë#�<¼=Ò èy`å0®ÇÁêøTïLÜp] 8[­îè³8ŸùkáƒñÅ ŠEïý$ŒÕ±n%,û4Â#ÜáP~Å G}ßsY»R‰ŸÁè{tþ¹¿ÕŒ ”=ï{—µÛÌONE÷Y• Çð³=â¾ÁJIH,`%Â7Ãé}*ö$JH$ Š¢û,Œƒlu(ï*|ƒ¤æ…}÷ ?¸®ïü"˜4¼Mpæ—"ò¢öp¥S­Âí9eâlµºÃu}§Eѽ&’„/ûþ¨k.„a8 bÞ%å�ÐQ@ÒðŠ+ùþˆCmb¢(Úo‘wp�€r¾fè$aI½~AOû-ò.m~õÙ‚ƒ„E\ /ãÀ�}ͪp¼T( ;ÔvMR FtŸïû?¶»ÜV@Âðs*[©ð Ò’Ð" ŽãmóV¿îrècUÂ7˜Œ¢æÚkBg 诵\n÷=Û¶Å G[Þç­¾Ì <@Ù÷G-z˜í\-[sóó¯4�¶yÐgî=Ç žù¥(ûþ¨¢Çp� È¾æ±6¤Öa�9„ãÅBá´k“YSòý' JK¶vO‚KýUç0ò|/…oPòý޳”‘SÍC-nè3'€É6Ó¯…÷¼–Ez…R¡0¼„„ÊüºÜ‰æÁù|þ÷«¹¾ÇTx$ýx[Ô>ÞËá” …a¬Ù‹òð H¤Ê›óënسýî»Ï¯vk¬±FoñeCªìù'fIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_close_disabled.png000066400000000000000000000014641526321767600301330ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+æIDATX…å–ËnÓ@@Ï ,€ÏH³i ‹$;Öi6H´µÃKB-[ðH|KvH$@åÕ&ÐvË6)�Ú¼b^ü°i.‹ÔÁŽíÄ)Ù îjlÏÜsæÎèÊð¿‡øƒJÕ>©ª·�£*ÜØÞ¨·¦ *W-C”›À/T¯mµÏ2þUm'€œ(ëÃ:7-x¥jŸeÈÇ©ûß2¦é‘ÀšŒ �¦!Q©ÚçUu-ÌâXD@É\zÓ”¨Ö¹xÑëþÃ!à¹mw&_|,ñçnÂRn¶ø¶ë¶w'† �"pXÙj6žDö%^ÇHd&•؇¯ å߇×ç†|‰ìl჈D$²ùÒoŒDÙ´ÏÒßùXx¬@_¢ó*NBÀ%Q6í³‚Ã5 ž(àKäæJ]`1�Ä|µvFàq |9 >R ë´%fæ ®çtŽÊÄpIGƼi]V ßè=D/ôQ1pÕ•­VãÁ¸Ü©’$zÚÅRÃaÌÃsÛ/gòE�á>ÞÄDð‰Ý!‰\…KÛÍôp—.U(ò“þ ‡ˆfzü˜4ßD(›¶)è“„u‚`æf‹N×m;S(W-Cà)p8ðÚ¯D°cšÙ|i×sÛnš¼©Ž`ÿg"ô² —É!AŸ–MÛL“{læ {IàY|³ÙXõœö‹\¾ð d�p³JU‰‘󆽄hŽÊ•­V}ÕÑu;IF6_rFI$ Œ†ß¹?<¿ëv^ÌÌ–>#L$+P1k‹ëiá~xn{'Qb®¸ë9Q‰ˆ@Ŭ-*�«PÛnÖáA‰ì\ñ‹Ài†ïDŒDH \µ@6báõ{ãà '½Ä@ lÔN Òú[xP"—/|‰Häò…�®Ûy�>�¹5 Ô:Ü�Ífã® á>qX‘[ÉUPk³Ù¸{Pø‰½ˆ@Fõ*àßQ]™<(,#|>J�«ÓÊýïÇoÏ †Áýß�¹IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_close_disabled@2x.png000066400000000000000000000032651526321767600305060ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+gIDATxœí›Mp[WÇç*…”ФM?g »4I“6´h¬/§�íÚŠvmgbÙÖ¬ÊLlØ2S[vWíF¶4 M?éÉ壄å£-0ÌtJÝQ Äij;ÝÃÂ’1ú¼OzÏ6ƒÿË{Ï;çü¾÷>=éöµ¯}ý?KÚ ¦ž}ö�®}ö;(#ÀA…«ÆðC¯�ÿ`‡ûëK©ìÔ—¬åy�Ç�uU.ߊ}æG¯~üIsl €ÑÑÉ;Ön3?N7M]LÚ[š}3¢¾CQ|bú+F´ ùïyûÀÁO¿ùÚK/­n5Í Ö˜çi5pDQ/•™y,Ä~CUgóúPmýöï6�¶@í\BïUÝÍoJa¬y¬€ÀíÝKmBHgs�öÑg$Jf&Ïô2_×Áæ�Ö ¼Ñ»¤¶Ö”÷„dfò ˜ ½Í­ÞZ¨Ä.×zçÚ}ÁÌË*Ä~Ð<Ú ¼ôÂ{Æh g²+Û¡nÞeÙ²ªªéòÒ ïµÌtº$�Í=j­)ƒvèçšUIúŹß8ĬTvêµT€;{Å*\GIUŠù_·›ïö&„0ÍC°· „m¤23�)ê¹B›(/-¼å’ÛU鉙‡-¶‚pW¯X…ëjlÚ/,\íëvBTæ¡Ýç€ò–fßTÕôæí¤§Ž€©lžÔƒ)¨y#2ìj¬€†S_EðîpÿØd¿+!ˆyàI{‹s¿ R#0A ¯�ÿm�;aúÑBHdr§EÅ�Ú< ž�|\¬YBPó¨—‹óÏ/í5ÂN›‡w�Nò W�ȰÂu‡ð;µF9=1ópóD"“;-ˆóžWcÎ jBX ¥.LMU—�Ï÷ Vþi0‰åâìï’ÙéSXõ�£¥n¨1ÕÂì/ëxS¡€þ ؘÚÝ2!€€DWQqùtºyˆ@r"÷uD®àÁM7Œpny1ÿ‹�òm)*„ÈÌCw�N*çßPcÎ-?FÐ Q}2*óá h(‘�ù†X{8ðÒ¢ú¤Wœÿy}59¨C¨Yéõ•{]ºXMGm"ÜÛ¥Ö®"rÓý½©1ãòØ=°"ÏL�4PuùÞ¾.9ŒU?™�>]gõJQ&ÿ�yîî3Å?0/æþf_ÛÙ ˆg¦NŧóG±ê§Ç' «¯fE ‘�9aážÒµÆT£‚:€Dvæ„ÔlÕżÀ†Â†CÚ£Ö˜HVB¨‚˜Ö¬0lTSÀ§ñwG!¼ÇáñÜqYq5oÔ>µ\\XHf§¿…ÕW�Ï9\û±…!)ÿÎ@ × €AÌ7´[Ô¼XÎ{¥|µÝdâÂÔ¢\f! t¤ÆsÇÕˆóžïf ²˜]…§p<ŒâÇ3S'�n£¾l™‡{Â×éf¾¡mÖzfî1ŠŸÈΜpè¡CŠ>”ÎL?hÑÜ̯#z¾¼8ï©Q߯Òó�%@ù»ÆÌP¥0ûn�Ѐ�0¿Ukbò¬s™!P7_îsÈüVÍ€Dõ¬Wšÿ£k~gAÍ[•¿8WqÍßM©ñ©!5¼BœÁxöâ±Ý2à•òU±œÇñ`T‘•Ôxî¸KîžâÙ‹ÇŒ�­àh^,£ašoÈ+嫈Žà ÁHÕB×-Ð�y¯”/;Äö­ä…\•WhóÖg}$V‡ºm‡Ž+ ž½xÌh,À�gÇ¢6P^œ÷=¬;„ß«FªéÌôƒ�Ú®€-óÊýE6;Z^\ðbCSЕ`�³ËKsjžh0”ýöØ[o)<à�xWÌ7Ÿ˜NÑŸâáor«vÆûÉ‹nlÙ±Zí{ÿ æüâ\ŪŒà¶îÓXìû̓m^–Ö'’m(2¶›æò‹s±ŒâA„³Ícmþ_@j=òl(2VYš[vo3Zy¥|Ù‚B‹·V¢ÝþªÖêÓ{É|C^)_FìÝ!\ihP«Ý¼$ð~›‹7¬Õ§ýÒ|K’½¢òâ‚×ÂLíRó`¬%ê/o¯}ñÔ™—c5=ÜÜDÔ7{®\ŠîWÚ°ô×?ÿþý/䲪< ›ï}¬ª/߳ϼVxñ£Ýîo_ûÚ×ÞÒ¿îƒDRôœš;IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_close_focus.png000066400000000000000000000013301526321767600274730ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ŠIDATX…å–=rÓ@†ß×IœƒZKp ¢5Ä!$qþfÂ2Ã(ÓQ$;ä×HÎ g`ÆÖ! ƒÖKá(È+É’�w%Ïÿ{1¾xt­ÇQ¤·î’|=4 ê¹�Œ¤7$~A|5lñ34â†(Ò€‡ î 껾ÚuÁ�@+‚ú“l<u?k$úî$®¢Îê�p­:M²HÜK �û¢:%&s§á¢HÜO Œ<ú"×2$Nç‘p}µE�Ùp��аŸ€Ðãy†ÄBU‰xê—ƒìŒ<~Hö6`Uèñ\âz¦Ä@Ë…ð�–oà Ep ñÚÕôµJêÄ’“\z¼Ê…Kg\ 7²à3À ôRP¯ŒD3ÐsBçUà…³$¾ˆ_¦yá¥Àh R7Kb’;£OвK äIHˆ@€Ób¥á•½ó*Á+ ÜJ=Hö\ Ü {UòRÿ%ê§$ÙƒDáGÕ°JÎ@-H̘G êÂñõ¬Jfé-pA—à k;Æ Û#�~™ÜR+�¸%a@rK ]:µjhúòòà¡a74ì ÜšWb¦@Ó—Gêʆ“Ü »ñ@hØÍ‘¸(’Șz|o÷‡†]’Û–Äb‘DæKØh‰R¿,2|W·²¶¡`%n6}=!u]÷|¿:çõë§'8Ð�ôÿ,õZèÜèy�Ÿ·Œ7[F¸íM¯Ô‹ªÄ¬ì¼=�Ù2ðx@øLçªEUzmî†B’æ! „¤ÍC€Ü‚eÍÛ"�ÌëlmV·Br‡*7gÏ™løF@øCµ‚Ö£ƒÀþBHË<ô¼ì­Ê´ª˜&€�È`8*gË™’�†æßIqÍ;§ÉPó£ZÊÎYÙ"ðX@ø?Íë•~;!¦ù»Îib}Z¿�sFlÒÙêŒ~猽01F ]Õ¢*˜ÎwÂÇl9;oχæÏ—ìô^˜‡>@‚¡ †�/Ùiïl…@ó2Mökú�veÊ–vƒÆ¡ó•¢B~¼í¨¾; ¥ZAëÎi’ðNXÊÍÙs�MóÁm:?¨yH ZÊ/Ø ÞÛ àëáÿ�él¥¨ßŒÍÛ³Îl8ùIãÒdµ _VqC‰€þ l;ü~™‡„@<&6d@ÈÝe æ!¹9{Ñd× ë„h÷ì�Îצõ^"ùÚ” HBŠæ!�o��Ô¸Bë<ÐõLj`÷<º�–yH±ZÊ–í{˜]G<ëƒMóõ¢ÞM©4`À!,¢ÈGî ›M¤mR�/ɳ�ø"8Þé \ÐÏî�•:€lÉNál•°§· ™�8³•±y{6½ÊJuÚÌ?ÑgŠÏ½ôr}FH²®v¥ i~xrÀTŸ¯ô~uu*•È/ØÉ„̶š)Û3 äêRâò vÒ{[%À¼Á–`+ í1a+i@H@óÀ}'Mn7ž,ý+ þ‰4 $`´l'â˜Çt±2£›õ¢Þuè1 dKvj°jÿ§D.‚£e;q[#†ùjQkí‹ù²ýÀcï�äø ¯ñê¬þØO½í@\ó†.Õ Zíµ™›·—Ìì{a -Û GxÛïf 2£›’.8¸ÁÇ¡ïh™<~ßK—ë3Z ÉÝì„wˆ~]àSç4¾>­?…äîT_ÆJv\ÎÖÍozéR¨ù–ö BìØ óÐL�ûáOzo«ù;÷œX0V²ã®qoÿt@xßæÛ•�³3騯 ÛèÌ­‚þš?¸âš—ŸùÝT-jÍÐ%;á¶6Z¶¡ùƒ: »`ßÅÛ1ÌWfµZDˆ2eö6 wB$€¸æASÕ‚–bcklÞ^vfoÁà�Æ£ ì `˜Ì·Ô„ð6t¿õÙ©;^šæƒgéJÚæê3ZñÒ%`3*Vð”ÃVÇJv|—˜nµ™ÿfÔ![’¦ª3ZŒŠMRq;Á¼ÎÔgõ—ν.ù7ìÛþ°Ý¾�x_Ì·”+ÙYsö€�½Óh}Zk_ì~[ü°ÿ1_ó•Y-Ëë2ã<-ïÒ¹Øëÿ^ŠÊd°…וý4ßRãëVSAЙΕ^ÁíÝR´Ì×fu#´È´Õ¸øFCPoÝoõ”ÁÖ!4=Læ[ª´„t…]!ØõΕ.fîªÁ_»Ö›æ× êJ2,ªÎhqGƇýÛ]í\îP+è³íÃÊ�ýøøxÓ™^fó-Ug´è¥<Æðwà#d¿xh[Ù÷^Õ'û]ß�t áÒrÒI0.é­:IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_close_pressed.png000066400000000000000000000013501526321767600300230ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…å–»rÓ@†¿ã¤ž#%T±Rð �„Ä!dr#Dj,7™á(e5’' Ø!ÎÅÀ0Ã3PY~èà €ûPÄJd]lËqÃp*iµûŸV«Ù…ÿ½$¼0^:µ Ê]^µ}ûã4A†Y]Rå5ÂoD¬À+(„´ GÀ„9…–aº¥iÁ‹–³¦ÐB˜î£z>»€;‘1E›Ó�(ZÎ*§Qp/! "@oš†é–Rà=U9H^ù°‘"q:‰„aº%E›q¸ [�Z¹•|û,Eb&¯DžxsA¶Ú~ù]´¯�RóûžÄº"ºÞö*—Cá–³ª*M`fP�Z¹)Â&ñÏ¡Ò4,g5Ex%/†Ì@X†U}®J#&ÛU•gábšßwWDô,/|,Ãt7­§I¤ÁÝ ¼Êɨì±²$´ÿydPllx.�ˆDcȸ\ðÜ74@ãcØ|»‘'/ó/È*~)ª‰ö+�Ÿyór -wÕsI×o;/šÕ§y2s,Âê’Â0ig"šÓE¤Ôß[FÖX3�WÕ`;"0ƒêEÑr—§"°`9‹YðN­R|»Ñ™Hb¨À‚å,öT.ãpv;µJ=lèÔ*õ ‰óQ™ÃàmÏ~ïß©Uê"ìÆ$fGIdmÇOD´5.ÿZ­°·Á^í"f.98ѰÆÈèÈ%‰@t�©žo8ìÙŽ2¿LèÈ%-º@#ñh�¶bèàŠÃÞÛnB0ñ¬ÅàÇþÅ–óÙ÷ºp7a[ÆaC|㶯°f ÝËùìûþ õF€âtfeĵz×}ìG™K¥ÇR±¡Olˆ¿Û!üª5t—¦2—ë]¬ûAÈ#98Ñ�2´;ltE¬}¦0;ZpˆmšøÐxÂXYÀ]|×fâ¡�°³L[<8�è;,bæp4Á ÇWò#E—Ü®$ú'ã"v8à~Õ`ºWò×:P)`ûLˆJ4v(h½~Z2 98þ(ˆóÌ[‘S¥é‘¥ÍŠÓ#¿ hÂb«&4=·Å+÷;„_´·�Ï.ºåÎ=�ê9ÿ]àïªÒ¹:3òG—Ü~šê€Tzò`ñ7‚ˆ‡Û�p¸î~Ÿˆ.%ús�¹æ¯&p¤Ò“5f/*ˆøjýãGEä,vB RéɃ»¤ð€CxKâ=‚š€èÑâtöO®ù� *Koq6³àš+⃹N£ú˜àdÀá�‰G,\ÜñQ™Ðð ,s:lñ¥é‘%A{q<A–*ïT[³e4%>?<ïÛ4©�ñcмÔüë³ácÐέ:aÓ8<0ñÈ:8ϼ*}Q‹(䳋‚žn4 VîYª¼m×§nxâ�j*«rzu&3çA;AÖÍÑÂìðŸk/ù82ø‹‡oi[xÈ¡Žmï‘LOÇðkLø±X²ðÊ‹U¯×ŒÀ-ÛöCþÄg3 Xzq…°ë?ò¯×žÂÓ{—­HßvŠ÷¨¼ã˜Ó¸˜ õ¯Õ °Þ OÙŠô•¦G.¸—-•Ã×É„m5lõª–}n'‰÷(æ‡çUéc D8ï_«1À´™3Àuî/ ú\!Ÿ­I²SX�ÉÌma‡ÿ*sÆ¿ó/ü¥pîúWÇ^‰íCyP„›(‹ŠùNq&º_iÃ⯫¿ùàáx×YÄ<@ùDE_µ7åù·~•ùx»ëÛe—]vÿ^ì ö^&­IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_grip.png000066400000000000000000000006341526321767600261360ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+NIDATX…åÖ½N„@†áï ÈÞ�&»YB£VVÖ‹`¢WjlLL–‹XBg¡•5ÇÂ�-�ÍÌ™�ÁBJ8äyäà¿4%VUÕ ©ø ïËùüÔ¤x \¡Ç©>?IÀμqßÞèkÁ_Á/¼kWiš~L`ƒØàÁlñ Ü{€÷à‚{ °Å˲<ŽŽf�@ÿµ\,rÀÃ"’áÉàK%úüAr<÷M}«¯9¿W¼mêë,Ë> ð…;ñÀ9€—®©ó!.ð�‹BàÖ¶øvnm‹[„Ä�Žøk×Ô«1\´ Ãà–›0^Àf q=·7}42,ƹksדþqãRÀÌŠ¢øÉ„33Q?˜ðáÜ>|ðsf6†?!ÙÎ�âcs6û̬˜Ù¸˜˜™|Îýùñ VdÖ}ˤ„TIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_grip@2x.png000066400000000000000000000013101526321767600265000ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+zIDATxœíš¿nÓP‡¿¨ÊKT6;6</ÁBÕР++o+J ˆ÷ðÆ©®Ó!UbAHä0 !רicß{}¯“ßhÿt¿OŠ6Ùd“uŽô}ÛÉçó»(ÏAÎ#ߎ¢¯åûWû:˜‹äóùÊ!0e´�WÀ�ǫ̀Ÿ£ÙÏyø¿ôFun�êà�ß*<«ÎN@#<:MãøKu~P/Áeð·&“OuÏ F@xˆ€¶ð0]à!p]á!`&à!P¦à!@&á!0¦á! 6à!¶à!6áÁs¶áÁc.àÁS®àÁC¦á�‹âž¨¼äQ’DŸË÷½`þ¿>å[šÄ7Ë3Þl„¬Ã7Ä Žà*ú¤:ÛûZܼ¨Áƒc¾ÁƒC>ƒ#á$Iô~•.ë|†Ë|‡‹B€KB� B‚ÃBƒƒB„CB…ûWðÉ$:Zµï¸(vEåXØ º„Oã¸üé� ¯ÿõ™Ü ß�V|‡?99ݯ�7³ ^EßTûŒìC†ï¼ þ¾Š¾­ö]ôÕy)C…‡Kp¿ŸÆñ‡UûºÀÆKøŸÏçS”w5}+}Œj¬ <Ô8.Š]AŽ0ßÐ×~I_«è9Y–m�wv¾ƒ\/]n ßÐ×ÞtT~ �Çã+ Û¥K�þ–RÓ×é°¦û " MÓŸ O�_ ?ÝëòŸœš¾i—ÚîkÌl6ÛβlË×¾<ϯ™ìÛd“5Î[štaŸ›½IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_grip_disabled.png000066400000000000000000000006621526321767600277660ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+dIDATX…åÖ1NÃ0Æñÿs“r:p‚–‰‰¹�ÄX\¡·ð5�è*,ˆB{ œ€&öÒ˜�†¢¦!vâ„�ö“Ÿlç)ð߇ԉEýAK…æäe<ž¨zq¦ û`v’ùZ¬pÚÀs<—Ãd­ò+Hãt﯆¯µÈÃ+ `ƒWÀ¯$€ î=€+î5@Ü[[üàètÛ¨�ƒ¼ß�Î{à¡9â`O0Íd¾T€ø.ð(qpœ¬¾‚xt{qöV*€/¼P7|1Óž$zë¸s߸S€*p°ü lñ¨?h¹à`q.¸ eâ‚ç(†ËLâFwîÔ +ÂS�0¨_L�k�°Qg¹i6õ- Ìχ™Ý àm�Y<7½¢S6oê _Õe��ÐZ+2ÎÃQ!×yøz]þ`9¶€‡ßþd´ÖÒüªËÄSu6ý­µÂ®5‹çº¿Ÿù¾¦•…ÿ¼ŽIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_grip_disabled@2x.png000066400000000000000000000013741526321767600303410ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+®IDATxœíš?nA‡¿Ù…&H¹%)i�ˆ-¥CØ „$ɱ¡€Ðr�Ç‚±�h³>D$.À"! Šüh�pÆÞïÎÌÎlüÊõÛŸæû´ž=-ÌjV³:Ï¥ò^€í*Wj·„èÈw‰¢Gýƒ×_‡¿�×Â\T¹Z_‘=�@ /�ëÃ=Q.+sPÿàO1^Òû ) þ·(žê½…û $Á£d½ßi}Ñû µ žwZãî)Œ€4ðPiᡲÀCà²ÂCÀLÀC LÁC€LÂC`LÃC@lÀC lÁClƒçlÃÇ\Àƒ§\Áƒ‡Lתµ;ˆz€¨‡q¯ùyøw¯&B¦áËÕú¢ö�%` %¯ôoØ€“7R^p?Ôc½7w®à•R÷ûÝæ'½?×MÐ%üa§¹7îžÜø9 ðrà<8à<8à#<8àì=/²Õïµ>L“e]€Ïð`Y€ïð`Q@ð`I@(ð`A@Hð`X@hð`P@ˆð`H@¨ð`à!WðÀf¿×jO›·R©ßUÈsÀüLÐ%|ÜÝ�¾TÙÙTH3Áà�7L`L%Àwørµ¾Á(¼™™`ð"òVÏ32 >óLÐwø•Ûµ{J©wzÞ¤Wç (*<À\ÊÅÚ˜älÄÝÝýió²ÀÄ'À%üa§éÎ8 ú_ªì¬#ðLybûÿ^Ï#Å2"àïÙ¹�!ø„¼ô�}B)7ÐS–�ùËǃc‹C—SÃ'䥆7�ÚIpñädNÁÂÐ¥LŸ¥ŒÉË´XÓy ½¿ýºrõÚà¦ÀÏHØŠ»­NÚp=Ôƒ¸ÛüèK^b­®>YXn4æ}Í»±½}ÑdÞ¬fuŽë}ê¿ �YIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_grip_focus.png000066400000000000000000000006301526321767600273310ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+JIDATX…åÖ?JÄ@ÇñïK½�[x×Ê*`·ñ ñ@z"!ØÂn'¤^ÿœÀB+°áY„(ÄÄ™—�‰…SÎ<øü˜y<þû’)±¬Ô9;-^«"¹H&ÅkÝ d(Çíþ$¾p8^˜Éª=‹þ?ðT–ÕJÞ& à£ðÁ£ðÅ£°àÁXñ ÆàÁøâç7z´½å£*’ " ^£kQ΀ƒv6%œ <&HÑž�~‚=ð‹‡BÞ÷  Àˆo€ð”"y7�›ÄÀÒ�xVê\Õ�°àÔº¶àÎ#ñçYöá¦I÷ž„‘ð °pNB#ÞÖ â®Þ�žb3N*ùØÆ”NqhÜyCM^iB­÷.U‘Zo]x·nÿЬC`ûëOæѦƒ·ƒxO�Ï „d6ë8Þ�™�Yû–³w?Í9Ú][WËZÖ²¹¬î ø®N¦-“žHüh·íÁç-û6y}¥®�…¨îP}¤# e㱞×'{ZõlÍu‡êÃ_øk-ãZ¾¯‘Šà�±°ÇùÞÆ½Àï�vìC¾¿QÁðïŠîiŒ€2ðÐeᡪÀCâªÂCÂ\ÀC¢\ÁC‚\ÂCb\ÃCB|ÀC"|ÁC|ÂCä|ÃCÄBÀC¤BÁC„\Ãw†ºz€ìþhײÉëQM„\Ãw‡ê:5Ø0ØÀ4È÷D#À|AÞ¹ŠB@ ø³–ÙÃ|oíBÁv÷˶½Í÷×ú ¿cGE÷Ô& x¨I@,ðPƒ€˜à!°€Øà! €á!�€Pð’ÝíÚñÏÉL0iøª3ÁØá;ïuÛL¯ÏåÍøé¼”€¦ÂÃ%Î ‡‚;mÛé¼yUàaÆþëNxx¸@@ôð™öMz“Ï›÷5*°(ðíüB/ÓèGðSòJÃ÷2í¡óye? ÿ=›­®lè;°>±\~J^ix×y�û'¸~…6°6±TéXJA^¥ÍºÎƒœ€O÷ì—a�€ßÀOdý*gròyf¶_e³®ó¦ÖÍ�ZÛh5Ö¼/tÕeÞ²–µÀõÖAL+lÞIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_grip_pressed.png000066400000000000000000000007071526321767600276640ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+yIDATX…åÖ1NÃ0Æñÿ³›r:p‚‚„ÄÔ¹åHp…°TÜ ¡T∠©™‘:Q('`€‰¹!5C¡¶ic§Nðh?ù÷ɶž ÿ}H•X«Ûo$Zß�y zgªR\éL d/�¯UŠ‹ibäMÏ’“t­ô+ÈÀÛO·—•ÈÃK `ƒ—À/%€ î=€+î5@Ü[[üðüz·nâàk4èuÀC'tćÀPOç· P?^¦œ¦k…¯` üøùæâs«¾ðB\ðÀÄ‘À>ð:• ³Œ;ð�;(Ð>ñV·ß1Ö8Xœ€ þ­ÕÐÏ P70‰%hgáN�°$|¥fþ ËÀG̯g¡®Cs_gðrÿ¯”ëf_!¤ÂÃÐ'foá^�EðªÒ˜Œ;ÍþB-‚ç÷ߧ=SëÀCA¬ �"�"`"` "`"`"à"à "àààà `¾ÜÜ‘’>(¡­ÏÃî‡ÙûAíÙ†¯$½ºˆž ì¡ìM‘‘ÙŒð)ys„OðSA™½¹ ð/Üÿ2ì¾3ûs]ýÂwÓžÉM@ð�“€Pà!!Áƒg¡ÁƒG!ƒ'¾àUåÞdÜ>Z%˹€�áÁ±€ÐáÁ¡€àÁ‘€XàÁ�€˜àÁ²€ØàÁ¢€áÁ’€XáÁÂ!_ðÀÁdÜ>^5¯šôjŠ<{‚>῎:«Ã·ªrìdO0 xôK×<|ÒßO�·³'¼òÚ̳²'7|Æ=ÁÐáËÍÁ]}cæ-ût^H@Qáák€7xÑ}ßð°dx…vOVÍË çü †_iõ0ÏŠŒ©3 xÞÎå­±†l™ªI¯†Ê–àä­ _Mz5HÉ[sýo”›£m‘ßß�Ý™Ë'¤æexçíæ�ñØ=½ºìÌ\Êt,%%/Ó`mç�!àÓˇ¿Ty œ?�z–39fžˆ6² ÖvÞºÑîï”›£íPón=xqÍfÞ¦6u‰ë/W>ž4a¼´IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_minimize.png000066400000000000000000000003131526321767600270100ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+}IDATX…íÒ!ƒ@…á†;4©@ô&ÜQÑ*Ð=²7A H¸Cwª MHê&kÞçfÍÿÄ‚ˆˆHeö{D„½ É vð6³8 ˜ç¥Ãã \3@l¸÷·¶�üx÷òÈ�Ø…ã‘Íþ÷P|Öüdl÷ýªþ EDDªûW(õ1IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_minimize@2x.png000066400000000000000000000005151526321767600273660ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÿIDATxœíÖ!NÄP…áóúJ'A À6¤I% ‚à`¬Ã ˜Mà‘$àØ’Ô`†„ŒC��´½XòZp½$ôÿä¹§Ç´0 á·£™…):u™Ä±Ô‡úŸî£<­V»EÛ-%�IÚž¨›—�ÉnóÎ˲|I�ƒš¦Ùɋţ¤}�vnLkëÛƒªª^¿ÇYú\^,®ôß^^’‚öã2�H:q¨ó'‚Âiš� 0+cÜ»·pb²»4 Ð~~\Jzö(äÊ´V×]¤ñ`€º®ß¶bv$éZÒ»G·‰mLv3¦_‰!`.¾~³7oߊñIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_minimize_disabled.png000066400000000000000000000003171526321767600306430ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+�IDATX…íÒ1‚P„áŸw á6¯àöZp Â-(°µµµ1á6&Ü– ˆ˜Øñhæëv³ÉL± ""r0ÛÎ1V§=»®ÿ)PœoÑœ�ïYèÇÑ/ïçý–µÓ$ÈB°v¿ËÖF |döŽ]רoÉŸPDDäpjYÎû>üIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_minimize_disabled@2x.png000066400000000000000000000005201526321767600312110ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÖ-NQÅñs)áK À³’ |Ç<†Ô#1, ™tMI%¦ �†°v€"!u˜fÊ»Xò5�„ùÿä¹#Î3#­`¿Ý‹bØÉÒ¤!½žBY–á§û·gç{Ë0rÓ©¤�ÆÚåQ™üÆk¿¸ŸMžãc2ÀÉ`°»ª¶%;ÈP.§E¨uø0¿| ×â§>–Ûå?|yIÚ·u�â0À]ý<}ò3Óqœ%´M2€™æQ$wÝÅY2@gó}(ùS–Fy-|¥Ë8L¸�N_C¨�Ìu%é-KµfU&¿Vºñ@âGh‹OÆåB‰±í—†IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_minimize_focus.png000066400000000000000000000003161526321767600302120ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+€IDATX…íÒ!Â@„á–;�päž� 0 �ÆÖ"ë8 Iï@Õ& ®[3Ÿ{o7™"""6¦Åd«öìÖ ì+$ÿ8v®¶ÀaÍÀPÐùuÒ L[Û·áûß§¡üûÙÂ\@Òx7È<ê2ç.ž68ˆˆˆÍ}^“ 7ä™ìIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_minimize_focus@2x.png000066400000000000000000000005151526321767600305650ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÿIDATxœíÖ¡JQÆñïÌŒÓÚ}AP°Ú\¶lñ9,>€ììKØ-ж)†�¾�iAlAï1Xä^µÍYpþ¿x΄ï~áΕ€A°?·îvܪÊÒ‹¶UÒÌÒoû 8¸öQóžæ’�JÚê-]ŒN®EÓØÙýÔVù²(àèÆ·Õùƒ¤ÝˆtQ\z¶Úö–S{ú>¯Š/ßÒLÿìð’dÒŽ¤y>/ p; I´&ç³²€�) 0¿[CŽ.¿Íge›Õ…¤Ç€<¡¾.Áê<Ÿ,'öâ²CÉ/%½†¤ëW'×ÕFmûù@â! Å'¶;Á |PŸIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_minimize_pressed.png000066400000000000000000000003221526321767600305350ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+„IDATX…íÒ± ‚PÄñÿ÷Ü�Ä=€M,lèA˜�kg°´wvгR!$všûu—÷%wÅ33³•Å4*ªc³ÉYxk›'„fʺ«�.À6瀀´»ŸW€ô}‘úÜå‚âE:rúw¼„߀ˆxä. ìGylùOhff¶º7•y À²g/IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_minimize_pressed@2x.png000066400000000000000000000005211526321767600311100ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÖ!NÄP…ásûš  < !�‹ƒ°ÜLHXÀPÏ@¢ðHpØQ„ HÈ8™LÚ^,yp}“Ðÿ“çVœÓJÀ Øßg·ƒÉyÈS¥OR§ºî~»ÿ8ÀîÉņY5•t,i­§n¹,ä~ßVÅøùzô“öG—ëÍR/&me©—‹išn{vsúþ=.âçÚ¥ê÷ò’äÚlB1�ãd¹f)´&ÅY:ÀÀ¤˜?® G.=ÄY2@¨4qé5K£œLó²íÎâ8`v5þe±'éVÒgŽn=[Èý®-m'þHüCñ­ñ<56PŽiIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_undock.png000066400000000000000000000010111526321767600264460ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+»IDATX…í–¿JÃPÅÏ—D ¾@ �â^pA|ÑA\|]§¢Kñ œú.‚Žöú'·ˆ\t°ZkŽCMÛT“&¤µƒ=Ó½ÉwïùåËÉ%À—DÝt]7Óxkæ!²0›ÒÊ!Yœ™Ò�LÓ|àºn¦ÑlÞ‚È¥3îç@iZ×—}-¬®ñÖÌ݈ÜûÇgÞŸ†´Û>‰È†?6ÂË‚ï|.kEæe�ªŽâo{‡wà�4ø‘�rùÁ£µÚ½R«ï†m¢iô„,Y–u'"ŸIÁªÔÔ>ÇÎHݽMÛ¶ûoCØ uçT•ÚÁI sX¡h—$õ¸ º R ”RKq‹{žV§çq7b €Ù]+9· ‚y˜·¬ÐÐõ«¢„Øñçž'±¿®±†€ ÀØÒœz¡a¡ê¨BD…ã�ÆÒ’E<’DJPš1ô#ú‡‡ÄYïq›ç[UG=˜†Áíùlö"Nm§¯†cŽ–g×që;žaì ð”@#L³ž`Á4ë-C_$Xð’Зï!زmë4áÚ®/XˆÄ=\IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_undock@2x.png000066400000000000000000000015601526321767600270310ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+"IDATxœíš½kAÆŸw/’;"6bŒxw{{æ !`kïÄÂ.ì•t6!�±D‹¤³‰�‰ v¶B !ñön³ F,”„Kˆ·¯EBÀÛ½»ìÇ›ÉeçWÎνï3ÏÍ3h4š4Cq¬nnžh4¦4FÀ€þtÅa—�U/mçró#ƒƒ[�*Ç2 Z¯ß2@ äãÄ‘‚×O–Mó}»:FÔ൚3I w'µñÀ@ž@+¶ãL´«©Tç61VÃÀc¦ÉàÑ žÚ€ý1¿óÀåD¤¸[¹ìÕÖ9!ô?8ÐhL¡Çì‡íÿÚ�%#éø ÒÚ€ƒ¥®' ÒÞ!NÇuÞ2‹±÷q°ëwøìÓÞ+³¸ÚÕT£ P-@5ÚÕT“zºn„jµÚ%Æ#fºðÅnõíº³U Ì—=Znîí¼¨T*¢Æ ‘³=UǹKŒ祅`Ã3îYVþs¨uÞ úvªm‡€]ߘ%ƨi<X0¼O¶ã<”Lh€í8ãOK&>"0ælÛ½.•Àg€mÛ%0^J%Œ@†÷jmmíœDp0úfˆ$‹�•9“} Øg�ïH$Š 2º|œÔS^b]¡DšU$„d€ax¼Òî;'p‰Dh† …È�N¬ol #¸ ©ß kT P�6@µÕhT P�6@µÕhT P�6@µÕDy Š+ÝN|�ÀnkAªz«­e©2€ÀK­e©1€w;—›o-O‹M<ôn¸—&Á¨4A¸_.¿>Õ=€—Á£V±¸Ø®Îiì‡Ïå³ýýsCCCÛ�*ûŽšXk¥øf™Åᤃú‡ãgÒI’�~HD š>H$Š ”ˆë¿óŒ§ö$’Åà<ï¹D`Ÿårþ 'ámÀ! ž(•Jß%b.ƒ¥Bá�^K$ Í–Mó­Tô@ˆÈ3‹ùqCÝpøÍàqË,ÌH&ézãZ­º×Èð¦ÜႤ˜A.ƒ–áý}bYVM:ŸF£I7ÿnÓ\ؘ<IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_undock_disabled.png000066400000000000000000000010301526321767600302760ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÊIDATX…í–?HÃ@Æ¿— )Õ]©‹¸vA\Œ®ÒXÄ!.­.ºD\œ:8.Å¥V\”’‚ÐE³"8ÚÑÁ¡8¸þ …æž‹©55iÒ¿ƒý¦wÉË}¿¼»{ðßEn/4mX”ƒ)GL´éUX—+�½B!Sn ° iÃ\ÞiÓØ&*Êš± $§4Q¦:o©ÈfÊ9|—½K"ÕŠ†\²~­¹¡g]÷K3)j‚ÿšÛ±½Ò aÌÇ6Âdšs ÏÕø–Ó$I‚…(Ž>ïs¹œÙ2Àür|›„ØQ�ÒN“03@„71r»ÝX¹Êg^¼Ô–@Q«Ät`‡ò#fM±X,àÀN«Ævˆw34í5¿þoí]ïȇ„$EÜùøÕh =ë¸éìRÔlZcÁÂóéêû1 úÐr×s�ÒŠšplÝJVЧ °nE]©€»¨(W¤=kÔË ”>¬¿uíWQ×?uÄŠyÍÈŸœyI­U€ ŒŽ˜U2Å�×äŸ%¨Š$¯mÛ3v¯/OŸ½¦×.O�Ÿ“S‘s’( Hãd_¶@‘ˆ’†ž=öñÝ@øgÛ€¥ÉrZÉIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_undock_disabled@2x.png000066400000000000000000000016341526321767600306620ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+NIDATxœí›ÍkAÆŸwÓ¨…R""ö`m<¨ѓފ6‰›”ÒTûñÿëQiý"í¥Ôƒ1UZM*´àÁ‹‡"=XÌ¥Š‡–Š©If<³›M³»“1Íü޳Ãó>ûd23ìÎ …¢–!»m¡�7Ï ‚ñ­¶:àËëàX€F± ¹Gçb·×Ì:Û À×ñr ãšìè$E áÄãh²X—Ue_°'̉ØnU£4‚еïÐÑ/Ÿ>¼}oÔÁÒðžûÀµš-{•#G F#¡ìÚB nökÀG¬UŽTFÛr pN(ûtóÌ ªïæ )ïýÊÂŒ‡±#ïåðg©«N ¼×Y�1]ç“ñ¨í½…¼Á7¹¬ó^-³¸0T² ÈF Û€lT² Ȧæ(¹ò®ìf`ý œ$`—Ù.|ÁÈG«f8À¤˜vmûyofrrÕªÖF1 Àè=ˈ�Ø‘7X´Øôäá@[6]ß߈tÍNE_ÛÔ3¥è_Àèñ§Èß¼š‰ðÊìíYÄ0_ rDC" oÀGÚ‘c¢ è8u®o/'º/ª \DxÐÑÝÝ(B\@Ö•½p!ÅlМK×_!¬ €€Ó" Ù… òe4ü¯�¸…ø*û�ˆ¦ñý"Œd³ðhÍ»N¼Ä1¢ì^ÄÆ,otÌð‡zÀ˜esj~+¬�m@6*Ùd£�m@6*Ùd£�m@6*Ùdcå|€8ÐRâÝÿFX/l¨­À±PØT[hÓ5Éð!‰T†Ü£…�U3Ø$G ṸþÜp-�ã„Þd‘ó›=€1„‹Ý<°9ø{\žêÓ#‰‰‰f�u�šXk…@ÀR"õ8­k´ |sºˆp`Y„®Q³" Ù†ã¥Y]c7dD³Áw Úº/F–ß-{YÈ/¢ übb*úF„¶áNðxkÓM‰(X. 'âcÏDé~34??Ï/…ÎÄS_WW:Q¬Ÿ`V8èr2½%²HÉ7®þÎða¦iCÚìi&OŠÓu¹ºëÏŸÜý\�z …¢†ù )ÐôÆlë�IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_undock_focus.png000066400000000000000000000007671526321767600276660ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+©IDATX…í–±JÃP†ÿ“d±_@Ô7¨`¡A|) *]|]—ND—â8YI:A †R°�P;¸¸(Ô©¹Ç¡&6µ·MLk†öŸn’sÏÿåÜ{˜uѨ�©*'QdPÀjD¯ƒMGS �ú �ªrr¡Ã5k�Õìj´éB(²¨DG§`kjWÝ)ÀwÙ§"îXç[s;§ŒÜ/ã¤[‚‡å–Và¿4øµÒe^ÑTlì{Ÿ©ð‘, šËžîöÈù3€nñ ÀçÃÀˆ¹$ÍB=Ü �i“÷½ð– Sá<ÀÃÌChK#¾Ý-³€˜O#û Ú*6‚÷ÿí@×ãëàž”°äÍì媅ð5;§J7Ý tË@‡€ütÅ~ çs€Ø¢t=©ˆ¹¤[BÞº�–;ˆ¥ 6ãh:šRˆ Åà«þ1Ð×~uK¼XœˆÓ�mÐM�П 0î'bt…Ї Á€PéÀ[d{¦³z–Ú¡êYj …ÖÁ0|„µð PÞ6è2äÜב{2båkIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_undock_focus@2x.png000066400000000000000000000015421526321767600302300ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíš;hQ…Ï™]0b°1…ÁX awí¾0…� 1`—€¨¤³ )­Œ¥� ZXZ$î† $‚ ‚Ù€E$……¢Å‚ˆX(>Ü�cDwfw33{÷&Î|å�›óŸ9™Ç¿w.���gU oZ�«iŒ ÐK`[+Œ…EÀ�‚3L=»Ào�æG [Ô @÷tEÑ1HàH)ÏÇõ&8a•³E�z„Í{òÐh![Ôp½ ¡®€ì¬NBZ@„ÛLài¿+!p}Óêü™ÖkûZb­}”·Wx¨ö™ø?¸šÆ(¶ÞÉ@׺÷€ ÁÖøi?~ÞC€ÞÖØi?~ÞÓAEš½çKy'ro…lÑU½c~Þ·ÊSÜI¶ Ø& À¶Û$Ø6`›Øд:RÐÞ´ã^•Ëc ö4›Ÿ)ºoš¡ e�óìÀ�R?¿†ÕÚpÍFs�uÀ.ÓF<ï^, p1ÈŸ5êo§Z÷È«¢æ`ãä€èõ5n²HÓ/®™¢î˜Àãv›4³NÒ<çÆây¾oC½„„„óé ÑìË IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_undock_pressed.png000066400000000000000000000010331526321767600301770ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÍIDATX…í–±J#Q†¿“dT°p‹-Å0 #,‚ì+,ŠŠ…–މ"6V)¶»«#+›´V*yAÁô T,TÐB AP�…NL¢3Î$Ñæ¯î�9sÿoÎ=sæÂg—¸ÝìM6… �~„öŠœ”#„Œjd>—6¯ßèM6}iŒl D+2~ÁÁ>éµ!N�á†p¢ÚæQ‘›„=w鯶y^Ê€= 9ûïy6w­—·d˜–¾¶¶K>Fu€5Ð=¾Ð&ù�_7&¬I§EDå^…ýŽ‹o;ëëCweô˜‹3ŠüB_)NeÉiEAá°åt«{üïp.=}â ¿†i�(’,…ò#…¾€Wׂ¾@fË5.…8øzöÝk|ÁÛji×ûçÝT~ ÚjÏE‰Û>Šÿ ÙTܱèJe˜@,$êùëªùgX¨Ô ì®ç*eÉ0-ÇÖ�rdk“!cß'.z:”ÎÛó�ËÀcÚÿžˆ¡ ý¦u 4WÅLt,ûjÅKèsT7ªb·mz ÎH(4 œWê®ÊÜîrìØ7ÀîrìX‚Á.T3À•__�=DGréøoŸÏ~r='™y‘öwYÙIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/dark/rc/window_undock_pressed@2x.png000066400000000000000000000016111526321767600305530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+;IDATxœíš½kAÆŸÙ „ Øˆc Cb¡BrÑ”â'± Š�x`6—ÓS þÆ*¸—Kr)Ò6ÑB„œ ‹H.)$ˆ…‚Å)µˆäƒ3™}-"·{{·s“sçWÎ ÏûìsóÅî …"ʰ G3»›8O2BŽh ÁWŠ ,Ãô†®g>Œ%WÝ: fŒž¬)­AtR´x>{óU¹š_娀¬—ع­€•ë6Ò×Ëuð5ºúÍsŒ!‡ÖhœF‚ç¶ç¼õ‘�„ã­fÖuýpéšàùlâqðÞàCÆuŸÏgS�ÏAˆ&¹üló^/«¸0T² ÈF Û€lT² È&òT<uõ�ì×4-A`§Ah®Ô?f˜Ÿ|»! Ìè�ȾK§~ùÖª×b‰ô%X4E„½4Û}»Ù>Cv€á$ÿ�Dg¼º8žšó­We§@Ì0‡aÑsÀÓÇI›fám—‘YÄ1€n#}À�ÈÂU¢3ÐhgÂìUÀ@ÏÀÈAMŠ*è]³ðäÄ-s�q[[Ôp€�bhãE"„¦õŠ(!¾œÖ€�ù–—ÄøòüBÄÒõC"Œè|«ƒÀre;°àqœðÀâXÒÿAÇ…ÎÁ 4ÎEH»ù£° @¶Ù¨d�� @¶Ù¨d�� @¶Ù¨d��Ÿû²h¯ðí¿Š¥ Ñ„¥Ò¦H@ Ó¥mQ  °¡ë™ÒƨÀ-îto8 pv£Ü}ázÚüP´ø¼Ëeéÿ1€×å7׋£ïß[sël{ÕÂ^+ŠÏùlª#lQûÀð=ì"¡À°,BÖᵈBAa 7"tmhÀC›"Šà§eYã"„õÒ†¯ ¹å–îÞUçEô®ä'ï,ˆÐv<ä›<ðTDA¯0FÃóÙÔ Qú¶˜�¥o�?kYÛµàTÙ~bYaŒ®ÍOÜ6E©øÅõ¸a³€!0œaŸH3)l¦�m=˜›¸û¥õ E„ù:ÞÐ1K4jIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/000077500000000000000000000000001526321767600226575ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/qdarkstyle/light/lightstyle.qrc000066400000000000000000000233571526321767600255700ustar00rootroot00000000000000 rc/arrow_down.png rc/arrow_down@2x.png rc/arrow_down_disabled.png rc/arrow_down_disabled@2x.png rc/arrow_down_focus.png rc/arrow_down_focus@2x.png rc/arrow_down_pressed.png rc/arrow_down_pressed@2x.png rc/arrow_left.png rc/arrow_left@2x.png rc/arrow_left_disabled.png rc/arrow_left_disabled@2x.png rc/arrow_left_focus.png rc/arrow_left_focus@2x.png rc/arrow_left_pressed.png rc/arrow_left_pressed@2x.png rc/arrow_right.png rc/arrow_right@2x.png rc/arrow_right_disabled.png rc/arrow_right_disabled@2x.png rc/arrow_right_focus.png rc/arrow_right_focus@2x.png rc/arrow_right_pressed.png rc/arrow_right_pressed@2x.png rc/arrow_up.png rc/arrow_up@2x.png rc/arrow_up_disabled.png rc/arrow_up_disabled@2x.png rc/arrow_up_focus.png rc/arrow_up_focus@2x.png rc/arrow_up_pressed.png rc/arrow_up_pressed@2x.png rc/base_icon.png rc/base_icon@2x.png rc/base_icon_disabled.png rc/base_icon_disabled@2x.png rc/base_icon_focus.png rc/base_icon_focus@2x.png rc/base_icon_pressed.png rc/base_icon_pressed@2x.png rc/branch_closed.png rc/branch_closed@2x.png rc/branch_closed_disabled.png rc/branch_closed_disabled@2x.png rc/branch_closed_focus.png rc/branch_closed_focus@2x.png rc/branch_closed_pressed.png rc/branch_closed_pressed@2x.png rc/branch_end.png rc/branch_end@2x.png rc/branch_end_disabled.png rc/branch_end_disabled@2x.png rc/branch_end_focus.png rc/branch_end_focus@2x.png rc/branch_end_pressed.png rc/branch_end_pressed@2x.png rc/branch_line.png rc/branch_line@2x.png rc/branch_line_disabled.png rc/branch_line_disabled@2x.png rc/branch_line_focus.png rc/branch_line_focus@2x.png rc/branch_line_pressed.png rc/branch_line_pressed@2x.png rc/branch_more.png rc/branch_more@2x.png rc/branch_more_disabled.png rc/branch_more_disabled@2x.png rc/branch_more_focus.png rc/branch_more_focus@2x.png rc/branch_more_pressed.png rc/branch_more_pressed@2x.png rc/branch_open.png rc/branch_open@2x.png rc/branch_open_disabled.png rc/branch_open_disabled@2x.png rc/branch_open_focus.png rc/branch_open_focus@2x.png rc/branch_open_pressed.png rc/branch_open_pressed@2x.png rc/checkbox_checked.png rc/checkbox_checked@2x.png rc/checkbox_checked_disabled.png rc/checkbox_checked_disabled@2x.png rc/checkbox_checked_focus.png rc/checkbox_checked_focus@2x.png rc/checkbox_checked_pressed.png rc/checkbox_checked_pressed@2x.png rc/checkbox_indeterminate.png rc/checkbox_indeterminate@2x.png rc/checkbox_indeterminate_disabled.png rc/checkbox_indeterminate_disabled@2x.png rc/checkbox_indeterminate_focus.png rc/checkbox_indeterminate_focus@2x.png rc/checkbox_indeterminate_pressed.png rc/checkbox_indeterminate_pressed@2x.png rc/checkbox_unchecked.png rc/checkbox_unchecked@2x.png rc/checkbox_unchecked_disabled.png rc/checkbox_unchecked_disabled@2x.png rc/checkbox_unchecked_focus.png rc/checkbox_unchecked_focus@2x.png rc/checkbox_unchecked_pressed.png rc/checkbox_unchecked_pressed@2x.png rc/line_horizontal.png rc/line_horizontal@2x.png rc/line_horizontal_disabled.png rc/line_horizontal_disabled@2x.png rc/line_horizontal_focus.png rc/line_horizontal_focus@2x.png rc/line_horizontal_pressed.png rc/line_horizontal_pressed@2x.png rc/line_vertical.png rc/line_vertical@2x.png rc/line_vertical_disabled.png rc/line_vertical_disabled@2x.png rc/line_vertical_focus.png rc/line_vertical_focus@2x.png rc/line_vertical_pressed.png rc/line_vertical_pressed@2x.png rc/radio_checked.png rc/radio_checked@2x.png rc/radio_checked_disabled.png rc/radio_checked_disabled@2x.png rc/radio_checked_focus.png rc/radio_checked_focus@2x.png rc/radio_checked_pressed.png rc/radio_checked_pressed@2x.png rc/radio_unchecked.png rc/radio_unchecked@2x.png rc/radio_unchecked_disabled.png rc/radio_unchecked_disabled@2x.png rc/radio_unchecked_focus.png rc/radio_unchecked_focus@2x.png rc/radio_unchecked_pressed.png rc/radio_unchecked_pressed@2x.png rc/toolbar_move_horizontal.png rc/toolbar_move_horizontal@2x.png rc/toolbar_move_horizontal_disabled.png rc/toolbar_move_horizontal_disabled@2x.png rc/toolbar_move_horizontal_focus.png rc/toolbar_move_horizontal_focus@2x.png rc/toolbar_move_horizontal_pressed.png rc/toolbar_move_horizontal_pressed@2x.png rc/toolbar_move_vertical.png rc/toolbar_move_vertical@2x.png rc/toolbar_move_vertical_disabled.png rc/toolbar_move_vertical_disabled@2x.png rc/toolbar_move_vertical_focus.png rc/toolbar_move_vertical_focus@2x.png rc/toolbar_move_vertical_pressed.png rc/toolbar_move_vertical_pressed@2x.png rc/toolbar_separator_horizontal.png rc/toolbar_separator_horizontal@2x.png rc/toolbar_separator_horizontal_disabled.png rc/toolbar_separator_horizontal_disabled@2x.png rc/toolbar_separator_horizontal_focus.png rc/toolbar_separator_horizontal_focus@2x.png rc/toolbar_separator_horizontal_pressed.png rc/toolbar_separator_horizontal_pressed@2x.png rc/toolbar_separator_vertical.png rc/toolbar_separator_vertical@2x.png rc/toolbar_separator_vertical_disabled.png rc/toolbar_separator_vertical_disabled@2x.png rc/toolbar_separator_vertical_focus.png rc/toolbar_separator_vertical_focus@2x.png rc/toolbar_separator_vertical_pressed.png rc/toolbar_separator_vertical_pressed@2x.png rc/transparent.png rc/transparent@2x.png rc/transparent_disabled.png rc/transparent_disabled@2x.png rc/transparent_focus.png rc/transparent_focus@2x.png rc/transparent_pressed.png rc/transparent_pressed@2x.png rc/window_close.png rc/window_close@2x.png rc/window_close_disabled.png rc/window_close_disabled@2x.png rc/window_close_focus.png rc/window_close_focus@2x.png rc/window_close_pressed.png rc/window_close_pressed@2x.png rc/window_grip.png rc/window_grip@2x.png rc/window_grip_disabled.png rc/window_grip_disabled@2x.png rc/window_grip_focus.png rc/window_grip_focus@2x.png rc/window_grip_pressed.png rc/window_grip_pressed@2x.png rc/window_minimize.png rc/window_minimize@2x.png rc/window_minimize_disabled.png rc/window_minimize_disabled@2x.png rc/window_minimize_focus.png rc/window_minimize_focus@2x.png rc/window_minimize_pressed.png rc/window_minimize_pressed@2x.png rc/window_undock.png rc/window_undock@2x.png rc/window_undock_disabled.png rc/window_undock_disabled@2x.png rc/window_undock_focus.png rc/window_undock_focus@2x.png rc/window_undock_pressed.png rc/window_undock_pressed@2x.png lightstyle.qss epasveer-seer-97076f1/src/resources/qdarkstyle/light/lightstyle.qss000066400000000000000000001514211526321767600256030ustar00rootroot00000000000000/* --------------------------------------------------------------------------- WARNING! File created programmatically. All changes made in this file will be lost! Created by the qtsass compiler v0.4.0 The definitions are in the "qdarkstyle.qss._styles.scss" module --------------------------------------------------------------------------- */ /* Dark Style - QDarkStyleSheet ------------------------------------------ */ /* See Qt documentation: - https://doc.qt.io/qt-5/stylesheet.html - https://doc.qt.io/qt-5/stylesheet-reference.html - https://doc.qt.io/qt-5/stylesheet-examples.html --------------------------------------------------------------------------- */ /* Reset elements ------------------------------------------------------------ Resetting everything helps to unify styles across different operating systems --------------------------------------------------------------------------- */ * { padding: 0px; margin: 0px; border: 0px; border-style: none; border-image: none; outline: 0; } /* specific reset for elements inside QToolBar */ QToolBar * { margin: 0px; padding: 0px; } /* QWidget ---------------------------------------------------------------- --------------------------------------------------------------------------- */ QWidget { background-color: #FAFAFA; border: 0px solid #C0C4C8; padding: 0px; color: #19232D; selection-background-color: #9FCBFF; selection-color: #19232D; } QWidget:disabled { background-color: #FAFAFA; color: #9DA9B5; selection-background-color: #DAEDFF; selection-color: #9DA9B5; } QWidget::item:selected { background-color: #9FCBFF; } QWidget::item:hover:!selected { background-color: #73C7FF; } /* QMainWindow ------------------------------------------------------------ This adjusts the splitter in the dock widget, not qsplitter https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow --------------------------------------------------------------------------- */ QMainWindow::separator { background-color: #C0C4C8; border: 0px solid #FAFAFA; spacing: 0px; padding: 2px; } QMainWindow::separator:hover { background-color: #ACB1B6; border: 0px solid #73C7FF; } QMainWindow::separator:horizontal { width: 5px; margin-top: 2px; margin-bottom: 2px; image: url(":/qss_icons/light/rc/toolbar_separator_vertical.png"); } QMainWindow::separator:vertical { height: 5px; margin-left: 2px; margin-right: 2px; image: url(":/qss_icons/light/rc/toolbar_separator_horizontal.png"); } /* QToolTip --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip --------------------------------------------------------------------------- */ QToolTip { background-color: #9FCBFF; color: #19232D; /* If you remove the border property, background stops working on Windows */ border: none; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Remove opacity, fix #174 - may need to use RGBA */ } /* QStatusBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar --------------------------------------------------------------------------- */ QStatusBar { border: 1px solid #C0C4C8; /* Fixes Spyder #9120, #9121 */ background: #C0C4C8; /* Fixes #205, white vertical borders separating items */ } QStatusBar::item { border: none; } QStatusBar QToolTip { background-color: #73C7FF; border: 1px solid #FAFAFA; color: #FAFAFA; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Reducing transparency to read better */ opacity: 230; } QStatusBar QLabel { /* Fixes Spyder #9120, #9121 */ background: transparent; } /* QCheckBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox --------------------------------------------------------------------------- */ QCheckBox { background-color: #FAFAFA; color: #19232D; spacing: 4px; outline: none; padding-top: 4px; padding-bottom: 4px; } QCheckBox:focus { border: none; } QCheckBox QWidget:disabled { background-color: #FAFAFA; color: #9DA9B5; } QCheckBox::indicator { margin-left: 2px; height: 14px; width: 14px; } QCheckBox::indicator:unchecked { image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QCheckBox::indicator:unchecked:disabled { image: url(":/qss_icons/light/rc/checkbox_unchecked_disabled.png"); } QCheckBox::indicator:checked { image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QCheckBox::indicator:checked:disabled { image: url(":/qss_icons/light/rc/checkbox_checked_disabled.png"); } QCheckBox::indicator:indeterminate { image: url(":/qss_icons/light/rc/checkbox_indeterminate.png"); } QCheckBox::indicator:indeterminate:disabled { image: url(":/qss_icons/light/rc/checkbox_indeterminate_disabled.png"); } QCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed { image: url(":/qss_icons/light/rc/checkbox_indeterminate_focus.png"); } /* QGroupBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox --------------------------------------------------------------------------- */ QGroupBox { font-weight: bold; border: 1px solid #C0C4C8; border-radius: 4px; padding: 2px; margin-top: 6px; margin-bottom: 4px; } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; left: 4px; padding-left: 2px; padding-right: 4px; padding-top: -4px; } QGroupBox::indicator { margin-left: 2px; margin-top: 2px; padding: 0; height: 14px; width: 14px; } QGroupBox::indicator:unchecked { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QGroupBox::indicator:unchecked:disabled { image: url(":/qss_icons/light/rc/checkbox_unchecked_disabled.png"); } QGroupBox::indicator:checked { border: none; image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QGroupBox::indicator:checked:disabled { image: url(":/qss_icons/light/rc/checkbox_checked_disabled.png"); } /* QRadioButton ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton --------------------------------------------------------------------------- */ QRadioButton { background-color: #FAFAFA; color: #19232D; spacing: 4px; padding-top: 4px; padding-bottom: 4px; border: none; outline: none; } QRadioButton:focus { border: none; } QRadioButton:disabled { background-color: #FAFAFA; color: #9DA9B5; border: none; outline: none; } QRadioButton QWidget { background-color: #FAFAFA; color: #19232D; spacing: 0px; padding: 0px; outline: none; border: none; } QRadioButton::indicator { border: none; outline: none; margin-left: 2px; height: 14px; width: 14px; } QRadioButton::indicator:unchecked { image: url(":/qss_icons/light/rc/radio_unchecked.png"); } QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_unchecked_focus.png"); } QRadioButton::indicator:unchecked:disabled { image: url(":/qss_icons/light/rc/radio_unchecked_disabled.png"); } QRadioButton::indicator:checked { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked.png"); } QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked_focus.png"); } QRadioButton::indicator:checked:disabled { outline: none; image: url(":/qss_icons/light/rc/radio_checked_disabled.png"); } /* QMenuBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar --------------------------------------------------------------------------- */ QMenuBar { background-color: #C0C4C8; padding: 2px; border: 1px solid #FAFAFA; color: #19232D; selection-background-color: #73C7FF; } QMenuBar:focus { border: 1px solid #9FCBFF; } QMenuBar::item { background: transparent; padding: 4px; } QMenuBar::item:selected { padding: 4px; background: transparent; border: 0px solid #C0C4C8; background-color: #73C7FF; } QMenuBar::item:pressed { padding: 4px; border: 0px solid #C0C4C8; background-color: #73C7FF; color: #19232D; margin-bottom: 0px; padding-bottom: 0px; } /* QMenu ------------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu --------------------------------------------------------------------------- */ QMenu { border: 0px solid #C0C4C8; color: #19232D; margin: 0px; background-color: #D2D5D8; selection-background-color: #73C7FF; } QMenu::separator { height: 1px; background-color: #ACB1B6; color: #19232D; } QMenu::item { background-color: #D2D5D8; padding: 4px 24px 4px 28px; /* Reserve space for selection border */ border: 1px transparent #C0C4C8; } QMenu::item:selected { color: #19232D; background-color: #73C7FF; } QMenu::item:pressed { background-color: #73C7FF; } QMenu::icon { padding-left: 10px; width: 14px; height: 14px; } QMenu::indicator { padding-left: 8px; width: 12px; height: 12px; /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ } QMenu::indicator:non-exclusive:unchecked { image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QMenu::indicator:non-exclusive:unchecked:hover, QMenu::indicator:non-exclusive:unchecked:focus, QMenu::indicator:non-exclusive:unchecked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QMenu::indicator:non-exclusive:unchecked:disabled { image: url(":/qss_icons/light/rc/checkbox_unchecked_disabled.png"); } QMenu::indicator:non-exclusive:checked { image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QMenu::indicator:non-exclusive:checked:hover, QMenu::indicator:non-exclusive:checked:focus, QMenu::indicator:non-exclusive:checked:pressed { border: none; image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QMenu::indicator:non-exclusive:checked:disabled { image: url(":/qss_icons/light/rc/checkbox_checked_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate { image: url(":/qss_icons/light/rc/checkbox_indeterminate.png"); } QMenu::indicator:non-exclusive:indeterminate:disabled { image: url(":/qss_icons/light/rc/checkbox_indeterminate_disabled.png"); } QMenu::indicator:non-exclusive:indeterminate:focus, QMenu::indicator:non-exclusive:indeterminate:hover, QMenu::indicator:non-exclusive:indeterminate:pressed { image: url(":/qss_icons/light/rc/checkbox_indeterminate_focus.png"); } QMenu::indicator:exclusive:unchecked { image: url(":/qss_icons/light/rc/radio_unchecked.png"); } QMenu::indicator:exclusive:unchecked:hover, QMenu::indicator:exclusive:unchecked:focus, QMenu::indicator:exclusive:unchecked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_unchecked_focus.png"); } QMenu::indicator:exclusive:unchecked:disabled { image: url(":/qss_icons/light/rc/radio_unchecked_disabled.png"); } QMenu::indicator:exclusive:checked { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked.png"); } QMenu::indicator:exclusive:checked:hover, QMenu::indicator:exclusive:checked:focus, QMenu::indicator:exclusive:checked:pressed { border: none; outline: none; image: url(":/qss_icons/light/rc/radio_checked_focus.png"); } QMenu::indicator:exclusive:checked:disabled { outline: none; image: url(":/qss_icons/light/rc/radio_checked_disabled.png"); } QMenu::right-arrow { margin: 5px; padding-left: 12px; image: url(":/qss_icons/light/rc/arrow_right.png"); height: 12px; width: 12px; } /* QAbstractItemView ------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QAbstractItemView { alternate-background-color: #FAFAFA; color: #19232D; border: 1px solid #C0C4C8; border-radius: 4px; } QAbstractItemView QLineEdit { padding: 2px; } /* QAbstractScrollArea ---------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QAbstractScrollArea { background-color: #FAFAFA; border: 1px solid #C0C4C8; border-radius: 4px; /* fix #159 */ padding: 2px; /* remove min-height to fix #244 */ color: #19232D; } QAbstractScrollArea:disabled { color: #9DA9B5; } /* QScrollArea ------------------------------------------------------------ --------------------------------------------------------------------------- */ QScrollArea QWidget QWidget:disabled { background-color: #FAFAFA; } /* QScrollBar ------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar --------------------------------------------------------------------------- */ QScrollBar:horizontal { height: 16px; margin: 2px 16px 2px 16px; border: 1px solid #C0C4C8; border-radius: 4px; background-color: #FAFAFA; } QScrollBar:vertical { background-color: #FAFAFA; width: 16px; margin: 16px 2px 16px 2px; border: 1px solid #C0C4C8; border-radius: 4px; } QScrollBar::handle:horizontal { background-color: #ACB1B6; border: 1px solid #C0C4C8; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:hover { background-color: #9FCBFF; border: #9FCBFF; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:focus { border: 1px solid #73C7FF; } QScrollBar::handle:vertical { background-color: #ACB1B6; border: 1px solid #C0C4C8; min-height: 8px; border-radius: 4px; } QScrollBar::handle:vertical:hover { background-color: #9FCBFF; border: #9FCBFF; border-radius: 4px; min-height: 8px; } QScrollBar::handle:vertical:focus { border: 1px solid #73C7FF; } QScrollBar::add-line:horizontal { margin: 0px 0px 0px 0px; border-image: url(":/qss_icons/light/rc/arrow_right_disabled.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { border-image: url(":/qss_icons/light/rc/arrow_right.png"); height: 12px; width: 12px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::add-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { border-image: url(":/qss_icons/light/rc/arrow_down.png"); height: 12px; width: 12px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal { margin: 0px 3px 0px 3px; border-image: url(":/qss_icons/light/rc/arrow_left_disabled.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { border-image: url(":/qss_icons/light/rc/arrow_left.png"); height: 12px; width: 12px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::sub-line:vertical { margin: 3px 0px 3px 0px; border-image: url(":/qss_icons/light/rc/arrow_up_disabled.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { border-image: url(":/qss_icons/light/rc/arrow_up.png"); height: 12px; width: 12px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { background: none; } QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { background: none; } QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; } /* QTextEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets --------------------------------------------------------------------------- */ QTextEdit { background-color: #FAFAFA; color: #19232D; border-radius: 4px; border: 1px solid #C0C4C8; } QTextEdit:focus { border: 1px solid #73C7FF; } QTextEdit:selected { background: #9FCBFF; color: #C0C4C8; } /* QPlainTextEdit --------------------------------------------------------- --------------------------------------------------------------------------- */ QPlainTextEdit { background-color: #FAFAFA; color: #19232D; border-radius: 4px; border: 1px solid #C0C4C8; } QPlainTextEdit:focus { border: 1px solid #73C7FF; } QPlainTextEdit:selected { background: #9FCBFF; color: #C0C4C8; } /* QSizeGrip -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip --------------------------------------------------------------------------- */ QSizeGrip { background: transparent; width: 12px; height: 12px; image: url(":/qss_icons/light/rc/window_grip.png"); } /* QStackedWidget --------------------------------------------------------- --------------------------------------------------------------------------- */ QStackedWidget { padding: 2px; border: 1px solid #C0C4C8; border: 1px solid #FAFAFA; } /* QToolBar --------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar --------------------------------------------------------------------------- */ QToolBar { background-color: #C0C4C8; border-bottom: 1px solid #FAFAFA; padding: 1px; font-weight: bold; spacing: 2px; } QToolBar:disabled { /* Fixes #272 */ background-color: #C0C4C8; } QToolBar::handle:horizontal { width: 16px; image: url(":/qss_icons/light/rc/toolbar_move_horizontal.png"); } QToolBar::handle:vertical { height: 16px; image: url(":/qss_icons/light/rc/toolbar_move_vertical.png"); } QToolBar::separator:horizontal { width: 16px; image: url(":/qss_icons/light/rc/toolbar_separator_horizontal.png"); } QToolBar::separator:vertical { height: 16px; image: url(":/qss_icons/light/rc/toolbar_separator_vertical.png"); } QToolButton#qt_toolbar_ext_button { background: #C0C4C8; border: 0px; color: #19232D; image: url(":/qss_icons/light/rc/arrow_right.png"); } /* QAbstractSpinBox ------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractSpinBox { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; border-radius: 4px; /* min-width: 5px; removed to fix 109 */ } QAbstractSpinBox:up-button { background-color: transparent #FAFAFA; subcontrol-origin: border; subcontrol-position: top right; border-left: 1px solid #C0C4C8; border-bottom: 1px solid #C0C4C8; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-bottom: -1px; } QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off { image: url(":/qss_icons/light/rc/arrow_up_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::up-arrow:hover { image: url(":/qss_icons/light/rc/arrow_up.png"); } QAbstractSpinBox:down-button { background-color: transparent #FAFAFA; subcontrol-origin: border; subcontrol-position: bottom right; border-left: 1px solid #C0C4C8; border-top: 1px solid #C0C4C8; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; width: 12px; margin-top: -1px; } QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off { image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QAbstractSpinBox::down-arrow:hover { image: url(":/qss_icons/light/rc/arrow_down.png"); } QAbstractSpinBox:hover { border: 1px solid #9FCBFF; color: #19232D; } QAbstractSpinBox:focus { border: 1px solid #73C7FF; } QAbstractSpinBox:selected { background: #9FCBFF; color: #C0C4C8; } /* ------------------------------------------------------------------------ */ /* DISPLAYS --------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QLabel ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe --------------------------------------------------------------------------- */ QLabel { background-color: #FAFAFA; border: 0px solid #C0C4C8; padding: 2px; margin: 0px; color: #19232D; } QLabel:disabled { background-color: #FAFAFA; border: 0px solid #C0C4C8; color: #9DA9B5; } /* QTextBrowser ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QTextBrowser { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; } QTextBrowser:disabled { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #9DA9B5; border-radius: 4px; } QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed { border: 1px solid #C0C4C8; } /* QGraphicsView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QGraphicsView { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; } QGraphicsView:disabled { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #9DA9B5; border-radius: 4px; } QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed { border: 1px solid #C0C4C8; } /* QCalendarWidget -------------------------------------------------------- --------------------------------------------------------------------------- */ QCalendarWidget { border: 1px solid #C0C4C8; border-radius: 4px; } QCalendarWidget:disabled { background-color: #FAFAFA; color: #9DA9B5; } /* QLCDNumber ------------------------------------------------------------- --------------------------------------------------------------------------- */ QLCDNumber { background-color: #FAFAFA; color: #19232D; } QLCDNumber:disabled { background-color: #FAFAFA; color: #9DA9B5; } /* QProgressBar ----------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar --------------------------------------------------------------------------- */ QProgressBar { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; text-align: center; } QProgressBar:disabled { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #9DA9B5; border-radius: 4px; text-align: center; } QProgressBar::chunk { background-color: #9FCBFF; color: #FAFAFA; border-radius: 4px; } QProgressBar::chunk:disabled { background-color: #DAEDFF; color: #9DA9B5; border-radius: 4px; } /* ------------------------------------------------------------------------ */ /* BUTTONS ---------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QPushButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton --------------------------------------------------------------------------- */ QPushButton { background-color: #C0C4C8; color: #19232D; border-radius: 4px; padding: 2px; outline: none; border: none; } QPushButton:disabled { background-color: #C0C4C8; color: #9DA9B5; border-radius: 4px; padding: 2px; } QPushButton:checked { background-color: #ACB1B6; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:disabled { background-color: #ACB1B6; color: #9DA9B5; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:selected { background: #ACB1B6; } QPushButton:hover { background-color: #B4B8BC; color: #19232D; } QPushButton:pressed { background-color: #ACB1B6; } QPushButton:selected { background: #ACB1B6; color: #19232D; } QPushButton::menu-indicator { subcontrol-origin: padding; subcontrol-position: bottom right; bottom: 4px; } QDialogButtonBox QPushButton { /* Issue #194 #248 - Special case of QPushButton inside dialogs, for better UI */ min-width: 80px; } /* QToolButton ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton --------------------------------------------------------------------------- */ QToolButton { background-color: #C0C4C8; color: #19232D; border-radius: 4px; padding: 2px; outline: none; border: none; /* The subcontrols below are used only in the DelayedPopup mode */ /* The subcontrols below are used only in the MenuButtonPopup mode */ /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ } QToolButton:disabled { background-color: #C0C4C8; color: #9DA9B5; border-radius: 4px; padding: 2px; } QToolButton:checked { background-color: #ACB1B6; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:disabled { background-color: #ACB1B6; color: #9DA9B5; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:hover { background-color: #B4B8BC; color: #19232D; } QToolButton:checked:pressed { background-color: #ACB1B6; } QToolButton:checked:selected { background: #ACB1B6; color: #19232D; } QToolButton:hover { background-color: #B4B8BC; color: #19232D; } QToolButton:pressed { background-color: #ACB1B6; } QToolButton:selected { background: #ACB1B6; color: #19232D; } QToolButton[popupMode="0"] { /* Only for DelayedPopup */ padding-right: 2px; } QToolButton[popupMode="1"] { /* Only for MenuButtonPopup */ padding-right: 20px; } QToolButton[popupMode="1"]::menu-button { border: none; } QToolButton[popupMode="1"]::menu-button:hover { border: none; border-left: 1px solid #C0C4C8; border-radius: 0; } QToolButton[popupMode="2"] { /* Only for InstantPopup */ padding-right: 2px; } QToolButton::menu-button { padding: 2px; border-radius: 4px; width: 12px; border: none; outline: none; } QToolButton::menu-button:hover { border: 1px solid #9FCBFF; } QToolButton::menu-button:checked:hover { border: 1px solid #9FCBFF; } QToolButton::menu-indicator { image: url(":/qss_icons/light/rc/arrow_down.png"); height: 8px; width: 8px; top: 0; /* Exclude a shift for better image */ left: -2px; /* Shift it a bit */ } QToolButton::menu-arrow { image: url(":/qss_icons/light/rc/arrow_down.png"); height: 8px; width: 8px; } QToolButton::menu-arrow:hover { image: url(":/qss_icons/light/rc/arrow_down_focus.png"); } /* QCommandLinkButton ----------------------------------------------------- --------------------------------------------------------------------------- */ QCommandLinkButton { background-color: transparent; border: 1px solid #C0C4C8; color: #19232D; border-radius: 4px; padding: 0px; margin: 0px; } QCommandLinkButton:disabled { background-color: transparent; color: #9DA9B5; } /* ------------------------------------------------------------------------ */ /* INPUTS - NO FIELDS ----------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* QComboBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QComboBox { border: 1px solid #C0C4C8; border-radius: 4px; selection-background-color: #9FCBFF; padding-left: 4px; padding-right: 4px; /* padding-right = 36; 4 + 16*2 See scrollbar size */ /* changed to 4px to fix #239 */ /* Fixes #103, #111 */ min-height: 1.5em; /* padding-top: 2px; removed to fix #132 */ /* padding-bottom: 2px; removed to fix #132 */ /* min-width: 75px; removed to fix #109 */ /* Needed to remove indicator - fix #132 */ } QComboBox QAbstractItemView { border: 1px solid #C0C4C8; border-radius: 0; background-color: #FAFAFA; selection-background-color: #9FCBFF; } QComboBox QAbstractItemView:hover { background-color: #FAFAFA; color: #19232D; } QComboBox QAbstractItemView:selected { background: #9FCBFF; color: #C0C4C8; } QComboBox QAbstractItemView:alternate { background: #FAFAFA; } QComboBox:disabled { background-color: #FAFAFA; color: #9DA9B5; } QComboBox:hover { border: 1px solid #9FCBFF; } QComboBox:focus { border: 1px solid #73C7FF; } QComboBox:on { selection-background-color: #9FCBFF; } QComboBox::item { /* Remove to fix #282, #285 and MR #288*/ /*&:checked { font-weight: bold; } &:selected { border: 0px solid transparent; } */ } QComboBox::item:alternate { background: #FAFAFA; } QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #C0C4C8; } QComboBox::down-arrow { image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus { image: url(":/qss_icons/light/rc/arrow_down.png"); } /* QSlider ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider --------------------------------------------------------------------------- */ QSlider:disabled { background: #FAFAFA; } QSlider:focus { border: none; } QSlider::groove:horizontal { background: #C0C4C8; border: 1px solid #C0C4C8; height: 4px; margin: 0px; border-radius: 4px; } QSlider::groove:vertical { background: #C0C4C8; border: 1px solid #C0C4C8; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical { background: #9FCBFF; border: 1px solid #C0C4C8; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical :disabled { background: #DAEDFF; } QSlider::sub-page:horizontal { background: #9FCBFF; border: 1px solid #C0C4C8; height: 4px; margin: 0px; border-radius: 4px; } QSlider::sub-page:horizontal:disabled { background: #DAEDFF; } QSlider::handle:horizontal { background: #788D9C; border: 1px solid #C0C4C8; width: 8px; height: 8px; margin: -8px 0px; border-radius: 4px; } QSlider::handle:horizontal:hover { background: #9FCBFF; border: 1px solid #9FCBFF; } QSlider::handle:horizontal:focus { border: 1px solid #73C7FF; } QSlider::handle:vertical { background: #788D9C; border: 1px solid #C0C4C8; width: 8px; height: 8px; margin: 0 -8px; border-radius: 4px; } QSlider::handle:vertical:hover { background: #9FCBFF; border: 1px solid #9FCBFF; } QSlider::handle:vertical:focus { border: 1px solid #73C7FF; } /* QLineEdit -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit --------------------------------------------------------------------------- */ QLineEdit { background-color: #FAFAFA; padding-top: 2px; /* This QLineEdit fix 103, 111 */ padding-bottom: 2px; /* This QLineEdit fix 103, 111 */ padding-left: 4px; padding-right: 4px; border-style: solid; border: 1px solid #C0C4C8; border-radius: 4px; color: #19232D; } QLineEdit:disabled { background-color: #FAFAFA; color: #9DA9B5; } QLineEdit:hover { border: 1px solid #9FCBFF; color: #19232D; } QLineEdit:focus { border: 1px solid #73C7FF; } QLineEdit:selected { background-color: #9FCBFF; color: #C0C4C8; } /* QTabWiget -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabWidget { padding: 2px; selection-background-color: #C0C4C8; } QTabWidget QWidget { /* Fixes #189 */ border-radius: 4px; } QTabWidget::pane { border: 1px solid #C0C4C8; border-radius: 4px; margin: 0px; /* Fixes double border inside pane with pyqt5 */ padding: 0px; } QTabWidget::pane:selected { background-color: #C0C4C8; border: 1px solid #9FCBFF; } /* QTabBar ---------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar --------------------------------------------------------------------------- */ QTabBar, QDockWidget QTabBar { qproperty-drawBase: 0; border-radius: 4px; margin: 0px; padding: 2px; border: 0; /* left: 5px; move to the right by 5px - removed for fix */ } QTabBar::close-button, QDockWidget QTabBar::close-button { border: 0; margin: 0; padding: 4px; image: url(":/qss_icons/light/rc/window_close.png"); } QTabBar::close-button:hover, QDockWidget QTabBar::close-button:hover { image: url(":/qss_icons/light/rc/window_close_focus.png"); } QTabBar::close-button:pressed, QDockWidget QTabBar::close-button:pressed { image: url(":/qss_icons/light/rc/window_close_pressed.png"); } QTabBar::tab, QDockWidget QTabBar::tab { /* !selected and disabled ----------------------------------------- */ /* selected ------------------------------------------------------- */ } QTabBar::tab:top:selected:disabled, QDockWidget QTabBar::tab:top:selected:disabled { border-bottom: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:bottom:selected:disabled, QDockWidget QTabBar::tab:bottom:selected:disabled { border-top: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:left:selected:disabled, QDockWidget QTabBar::tab:left:selected:disabled { border-right: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:right:selected:disabled, QDockWidget QTabBar::tab:right:selected:disabled { border-left: 3px solid #DAEDFF; color: #9DA9B5; background-color: #C0C4C8; } QTabBar::tab:top:!selected:disabled, QDockWidget QTabBar::tab:top:!selected:disabled { border-bottom: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:bottom:!selected:disabled, QDockWidget QTabBar::tab:bottom:!selected:disabled { border-top: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:left:!selected:disabled, QDockWidget QTabBar::tab:left:!selected:disabled { border-right: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:right:!selected:disabled, QDockWidget QTabBar::tab:right:!selected:disabled { border-left: 3px solid #FAFAFA; color: #9DA9B5; background-color: #FAFAFA; } QTabBar::tab:top:!selected, QDockWidget QTabBar::tab:top:!selected { border-bottom: 2px solid #FAFAFA; margin-top: 2px; } QTabBar::tab:bottom:!selected, QDockWidget QTabBar::tab:bottom:!selected { border-top: 2px solid #FAFAFA; margin-bottom: 2px; } QTabBar::tab:left:!selected, QDockWidget QTabBar::tab:left:!selected { border-left: 2px solid #FAFAFA; margin-right: 2px; } QTabBar::tab:right:!selected, QDockWidget QTabBar::tab:right:!selected { border-right: 2px solid #FAFAFA; margin-left: 2px; } QTabBar::tab:top, QDockWidget QTabBar::tab:top { background-color: #C0C4C8; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; min-width: 5px; border-bottom: 3px solid #C0C4C8; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:selected, QDockWidget QTabBar::tab:top:selected { background-color: #B4B8BC; border-bottom: 3px solid #37AEFE; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:!selected:hover, QDockWidget QTabBar::tab:top:!selected:hover { border: 1px solid #73C7FF; border-bottom: 3px solid #73C7FF; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:bottom, QDockWidget QTabBar::tab:bottom { border-top: 3px solid #C0C4C8; background-color: #C0C4C8; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; min-width: 5px; } QTabBar::tab:bottom:selected, QDockWidget QTabBar::tab:bottom:selected { background-color: #B4B8BC; border-top: 3px solid #37AEFE; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } QTabBar::tab:bottom:!selected:hover, QDockWidget QTabBar::tab:bottom:!selected:hover { border: 1px solid #73C7FF; border-top: 3px solid #73C7FF; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:left, QDockWidget QTabBar::tab:left { background-color: #C0C4C8; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-left-radius: 4px; border-bottom-left-radius: 4px; min-height: 5px; } QTabBar::tab:left:selected, QDockWidget QTabBar::tab:left:selected { background-color: #B4B8BC; border-right: 3px solid #37AEFE; } QTabBar::tab:left:!selected:hover, QDockWidget QTabBar::tab:left:!selected:hover { border: 1px solid #73C7FF; border-right: 3px solid #73C7FF; /* Fixes different behavior #271 */ margin-right: 0px; padding-right: -1px; } QTabBar::tab:right, QDockWidget QTabBar::tab:right { background-color: #C0C4C8; margin-top: 2px; padding-left: 2px; padding-right: 2px; padding-top: 4px; padding-bottom: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; min-height: 5px; } QTabBar::tab:right:selected, QDockWidget QTabBar::tab:right:selected { background-color: #B4B8BC; border-left: 3px solid #37AEFE; } QTabBar::tab:right:!selected:hover, QDockWidget QTabBar::tab:right:!selected:hover { border: 1px solid #73C7FF; border-left: 3px solid #73C7FF; /* Fixes different behavior #271 */ margin-left: 0px; padding-left: 0px; } QTabBar QToolButton, QDockWidget QTabBar QToolButton { /* Fixes #136 */ background-color: #C0C4C8; height: 12px; width: 12px; } QTabBar QToolButton:pressed, QDockWidget QTabBar QToolButton:pressed { background-color: #C0C4C8; } QTabBar QToolButton:pressed:hover, QDockWidget QTabBar QToolButton:pressed:hover { border: 1px solid #9FCBFF; } QTabBar QToolButton::left-arrow:enabled, QDockWidget QTabBar QToolButton::left-arrow:enabled { image: url(":/qss_icons/light/rc/arrow_left.png"); } QTabBar QToolButton::left-arrow:disabled, QDockWidget QTabBar QToolButton::left-arrow:disabled { image: url(":/qss_icons/light/rc/arrow_left_disabled.png"); } QTabBar QToolButton::right-arrow:enabled, QDockWidget QTabBar QToolButton::right-arrow:enabled { image: url(":/qss_icons/light/rc/arrow_right.png"); } QTabBar QToolButton::right-arrow:disabled, QDockWidget QTabBar QToolButton::right-arrow:disabled { image: url(":/qss_icons/light/rc/arrow_right_disabled.png"); } /* QDockWiget ------------------------------------------------------------- --------------------------------------------------------------------------- */ QDockWidget { outline: 1px solid #C0C4C8; background-color: #FAFAFA; border: 1px solid #C0C4C8; border-radius: 4px; titlebar-close-icon: url(":/qss_icons/light/rc/transparent.png"); titlebar-normal-icon: url(":/qss_icons/light/rc/transparent.png"); } QDockWidget::title { /* Better size for title bar */ padding: 3px; spacing: 4px; border: none; background-color: #C0C4C8; } QDockWidget::close-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/light/rc/window_close.png"); } QDockWidget::close-button:hover { image: url(":/qss_icons/light/rc/window_close_focus.png"); } QDockWidget::close-button:pressed { image: url(":/qss_icons/light/rc/window_close_pressed.png"); } QDockWidget::float-button { icon-size: 12px; border: none; background: transparent; background-image: transparent; border: 0; margin: 0; padding: 0; image: url(":/qss_icons/light/rc/window_undock.png"); } QDockWidget::float-button:hover { image: url(":/qss_icons/light/rc/window_undock_focus.png"); } QDockWidget::float-button:pressed { image: url(":/qss_icons/light/rc/window_undock_pressed.png"); } /* QTreeView QListView QTableView ----------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview --------------------------------------------------------------------------- */ QTreeView:branch:selected, QTreeView:branch:hover { background: url(":/qss_icons/light/rc/transparent.png"); } QTreeView:branch:has-siblings:!adjoins-item { border-image: url(":/qss_icons/light/rc/branch_line.png") 0; } QTreeView:branch:has-siblings:adjoins-item { border-image: url(":/qss_icons/light/rc/branch_more.png") 0; } QTreeView:branch:!has-children:!has-siblings:adjoins-item { border-image: url(":/qss_icons/light/rc/branch_end.png") 0; } QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings { border-image: none; image: url(":/qss_icons/light/rc/branch_closed.png"); } QTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings { border-image: none; image: url(":/qss_icons/light/rc/branch_open.png"); } QTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover { image: url(":/qss_icons/light/rc/branch_closed_focus.png"); } QTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover { image: url(":/qss_icons/light/rc/branch_open_focus.png"); } QTreeView::indicator:checked, QListView::indicator:checked, QTableView::indicator:checked, QColumnView::indicator:checked { image: url(":/qss_icons/light/rc/checkbox_checked.png"); } QTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed, QListView::indicator:checked:hover, QListView::indicator:checked:focus, QListView::indicator:checked:pressed, QTableView::indicator:checked:hover, QTableView::indicator:checked:focus, QTableView::indicator:checked:pressed, QColumnView::indicator:checked:hover, QColumnView::indicator:checked:focus, QColumnView::indicator:checked:pressed { image: url(":/qss_icons/light/rc/checkbox_checked_focus.png"); } QTreeView::indicator:unchecked, QListView::indicator:unchecked, QTableView::indicator:unchecked, QColumnView::indicator:unchecked { image: url(":/qss_icons/light/rc/checkbox_unchecked.png"); } QTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed, QListView::indicator:unchecked:hover, QListView::indicator:unchecked:focus, QListView::indicator:unchecked:pressed, QTableView::indicator:unchecked:hover, QTableView::indicator:unchecked:focus, QTableView::indicator:unchecked:pressed, QColumnView::indicator:unchecked:hover, QColumnView::indicator:unchecked:focus, QColumnView::indicator:unchecked:pressed { image: url(":/qss_icons/light/rc/checkbox_unchecked_focus.png"); } QTreeView::indicator:indeterminate, QListView::indicator:indeterminate, QTableView::indicator:indeterminate, QColumnView::indicator:indeterminate { image: url(":/qss_icons/light/rc/checkbox_indeterminate.png"); } QTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed, QListView::indicator:indeterminate:hover, QListView::indicator:indeterminate:focus, QListView::indicator:indeterminate:pressed, QTableView::indicator:indeterminate:hover, QTableView::indicator:indeterminate:focus, QTableView::indicator:indeterminate:pressed, QColumnView::indicator:indeterminate:hover, QColumnView::indicator:indeterminate:focus, QColumnView::indicator:indeterminate:pressed { image: url(":/qss_icons/light/rc/checkbox_indeterminate_focus.png"); } QTreeView, QListView, QTableView, QColumnView { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; gridline-color: #C0C4C8; border-radius: 4px; } QTreeView:disabled, QListView:disabled, QTableView:disabled, QColumnView:disabled { background-color: #FAFAFA; color: #9DA9B5; } QTreeView:selected, QListView:selected, QTableView:selected, QColumnView:selected { background-color: #9FCBFF; color: #C0C4C8; } QTreeView:focus, QListView:focus, QTableView:focus, QColumnView:focus { border: 1px solid #73C7FF; } QTreeView::item:pressed, QListView::item:pressed, QTableView::item:pressed, QColumnView::item:pressed { background-color: #9FCBFF; } QTreeView::item:selected:active, QListView::item:selected:active, QTableView::item:selected:active, QColumnView::item:selected:active { background-color: #9FCBFF; } QTreeView::item:selected:!active, QListView::item:selected:!active, QTableView::item:selected:!active, QColumnView::item:selected:!active { color: #19232D; background-color: #D2D5D8; } QTreeView::item:!selected:hover, QListView::item:!selected:hover, QTableView::item:!selected:hover, QColumnView::item:!selected:hover { outline: 0; color: #19232D; background-color: #D2D5D8; } QTableCornerButton::section { background-color: #FAFAFA; border: 1px transparent #C0C4C8; border-radius: 0px; } /* QHeaderView ------------------------------------------------------------ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview --------------------------------------------------------------------------- */ QHeaderView { background-color: #C0C4C8; border: 0px transparent #C0C4C8; padding: 0; margin: 0; border-radius: 0; } QHeaderView:disabled { background-color: #C0C4C8; border: 1px transparent #C0C4C8; } QHeaderView::section { background-color: #C0C4C8; color: #19232D; border-radius: 0; text-align: left; font-size: 13px; } QHeaderView::section::horizontal { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-left: 1px solid #FAFAFA; } QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { border-left: 1px solid #C0C4C8; } QHeaderView::section::horizontal:disabled { color: #9DA9B5; } QHeaderView::section::vertical { padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; border-top: 1px solid #FAFAFA; } QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { border-top: 1px solid #C0C4C8; } QHeaderView::section::vertical:disabled { color: #9DA9B5; } QHeaderView::down-arrow { /* Those settings (border/width/height/background-color) solve bug */ /* transparent arrow background and size */ background-color: #C0C4C8; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/light/rc/arrow_down.png"); } QHeaderView::up-arrow { background-color: #C0C4C8; border: none; height: 12px; width: 12px; padding-left: 2px; padding-right: 2px; image: url(":/qss_icons/light/rc/arrow_up.png"); } /* QToolBox -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox --------------------------------------------------------------------------- */ QToolBox { padding: 0px; border: 0px; border: 1px solid #C0C4C8; } QToolBox:selected { padding: 0px; border: 2px solid #9FCBFF; } QToolBox::tab { background-color: #FAFAFA; border: 1px solid #C0C4C8; color: #19232D; border-top-left-radius: 4px; border-top-right-radius: 4px; } QToolBox::tab:disabled { color: #9DA9B5; } QToolBox::tab:selected { background-color: #ACB1B6; border-bottom: 2px solid #9FCBFF; } QToolBox::tab:selected:disabled { background-color: #C0C4C8; border-bottom: 2px solid #DAEDFF; } QToolBox::tab:!selected { background-color: #C0C4C8; border-bottom: 2px solid #C0C4C8; } QToolBox::tab:!selected:disabled { background-color: #FAFAFA; } QToolBox::tab:hover { border-color: #73C7FF; border-bottom: 2px solid #73C7FF; } QToolBox QScrollArea { padding: 0px; border: 0px; background-color: #FAFAFA; } /* QFrame ----------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe https://doc.qt.io/qt-5/qframe.html#-prop https://doc.qt.io/qt-5/qframe.html#details https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color --------------------------------------------------------------------------- */ /* (dot) .QFrame fix #141, #126, #123 */ .QFrame { border-radius: 4px; border: 1px solid #C0C4C8; /* No frame */ /* HLine */ /* HLine */ } .QFrame[frameShape="0"] { border-radius: 4px; border: 1px transparent #C0C4C8; } .QFrame[frameShape="4"] { max-height: 2px; border: none; background-color: #C0C4C8; } .QFrame[frameShape="5"] { max-width: 2px; border: none; background-color: #C0C4C8; } /* QSplitter -------------------------------------------------------------- https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter --------------------------------------------------------------------------- */ QSplitter { background-color: #C0C4C8; spacing: 0px; padding: 0px; margin: 0px; } QSplitter::handle { background-color: #C0C4C8; border: 0px solid #FAFAFA; spacing: 0px; padding: 1px; margin: 0px; } QSplitter::handle:hover { background-color: #788D9C; } QSplitter::handle:horizontal { width: 5px; image: url(":/qss_icons/light/rc/line_vertical.png"); } QSplitter::handle:vertical { height: 5px; image: url(":/qss_icons/light/rc/line_horizontal.png"); } /* QDateEdit, QDateTimeEdit ----------------------------------------------- --------------------------------------------------------------------------- */ QDateEdit, QDateTimeEdit { selection-background-color: #9FCBFF; border-style: solid; border: 1px solid #C0C4C8; border-radius: 4px; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ padding-bottom: 2px; padding-left: 4px; padding-right: 4px; min-width: 10px; } QDateEdit:on, QDateTimeEdit:on { selection-background-color: #9FCBFF; } QDateEdit::drop-down, QDateTimeEdit::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; border-left: 1px solid #C0C4C8; } QDateEdit::down-arrow, QDateTimeEdit::down-arrow { image: url(":/qss_icons/light/rc/arrow_down_disabled.png"); height: 8px; width: 8px; } QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus, QDateTimeEdit::down-arrow:on, QDateTimeEdit::down-arrow:hover, QDateTimeEdit::down-arrow:focus { image: url(":/qss_icons/light/rc/arrow_down.png"); } QDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView { background-color: #FAFAFA; border-radius: 4px; border: 1px solid #C0C4C8; selection-background-color: #9FCBFF; } /* QAbstractView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractView:hover { border: 1px solid #9FCBFF; color: #19232D; } QAbstractView:selected { background: #9FCBFF; color: #C0C4C8; } /* PlotWidget ------------------------------------------------------------- --------------------------------------------------------------------------- */ PlotWidget { /* Fix cut labels in plots #134 */ padding: 0px; } epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/000077500000000000000000000000001526321767600232635ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/.keep000066400000000000000000000000021526321767600242000ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_down.png000066400000000000000000000010501526321767600261460ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÚIDATX…í”=kQ†Ÿsg!BXq &Æ0Æ -lcc Hˆ•µ•µ�?ÀÎ_`áP,,1XˆX¨•:,b& N²NvƒlÀÀ΋ùØe×MvÖ`šyàÂåιïûιw öI'“Ó ‡þ“íf͵+&]RÔôß°·tze“Òv8%ð¾£.½µÍyWÚ§zxžSGåèrû™fGôï+ ©ÏK•yÏsê=|ÛÞªŒDKŠ<ŽWÄÐqO† 3WôQe$¼áÛöVg�Õ½#‚°Ù˜{Z Ž€\iw!w5q}ðÓ=w;Þ´º‹zÄ8Ú¬o¼(ž0 WAòº `@á^m¥zœèo…}Ä4¯Ë•£› ‰¨º‹¹I‚ÞYw«÷w*Þ1@ÂÿP_Y"»˜Ò'„š¤[!¢·jnõánú·vâôùE#ò8ª ]-ÍÌGª7ýÕêóAts�íäÌ…9"ž‰�" ‘~-¿ˆd±öÍ~;¨fî«}|föRYËÀxÒ‰TÃ7&\Xûê|Ê£7Ô7~bzöLˆõ 8•,}·ç=×YÉ«5ôOæäÙËÇZ­ÖÂç’UºþãËÇõaµ ö•?åf©¬˜ÕIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_down@2x.png000066400000000000000000000017661526321767600265360ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¨IDATxœí˜Mh\UÇç%L°v"d ™I ’¤c“ÜØ ~´´ ~7®Ä…àÖE©*¥ÝTDÜ ŠàB°´]ˆ4 ꪶ‹Ìh33û1o Í$í MŒ™9.ÒÀäÍÍ8™yo2Òû[¾ÿ»çžÿ¹÷¾wï‹Åb±X,‹Åb±X,˃…xDG?ùPD;€2ˆnC^>¢8ªR=‘K'ŽWª†Œ­ŠÐѲüZˆ*¥\:ÞYùÌÙ®dÚCô$ð?ŸöFô¾· T-€èÐÞçç,öÄP�r éù†: ^_}%—L\ô¾m,@lhìiÐAvy:hã"˜Ìëm�Ãn*~ÙÔbÓô ìVG'�~oO@»Á¡ÚÏu)Ë¡ììÔt­F›’��šôY„kIÖªÝ.hµyáš j™‡:þÙTâNhøu£"Ú¿Kí0¬ùK8¡ñl*qã¿Z×\•ì‡VCg^0È¥zãøˆ`@… «�+¯ßžž.Ô¤î¼7?¿ydÇw%§k/0â‘[½ŒæAN‰›33÷ê ´¥)¼¸¸¸ZÜÿä÷á;Ë»žªNJÙ¤j�jó*_ºéá·òùŸÿÙJ´F³•¾¡ÑSŠ5heÛH™Í+|’KÅßo¤ß†?b……¹ÉîžÞ%à G h ˜Í sSñã¦õÐÔW¼°0÷Kw$z x™�Æ}^Fóe}'›J|ÑLd_2Œ î›@ô[ ä‘üØ0™68+¨¾é¦§›Œíßtí{Iá Âé‰"÷õEGåµ[é© �Å܈¯ë5:°ÿqÊ?�ÔHL#?¯Z>’Kÿv©Ñ½øþÁŠ=6:BY&�Ýi+E0™¿‰£‡Ü™ÄÕfs¬$�/vl`äQœÎóÀ㩞"˜Ìÿ�–ºé߯û•ceg¾ãÎ^ý³ŒŒW<’PûÏÓAµù+*�‚0¿žP`ôìÙÓÝ¥�ž3ÈÞóƒ©0ÿ–¥WóÉä]ÿ³[#Ð=|>™¼ÛU*V8g�×G{³Yq¶«T8¤yhÁ!&“É,çú#À×›ôoÚÝ}åöGÞÈd2ËAçôÉ¥'68ö)Â{5ßR>sÓñ£´èÆ©•Z\˜;ŽDW€�oˆ~à¦ÑÂ[é–ßèóýîéͱv~XG�wÝTâóVç³-WZÅ…¹Ë;{zw<Uäí\*þÍväb±X,‹Åb±X,‹ÅbyÐø‡h(×®²ƒÑIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_down_disabled.png000066400000000000000000000010351526321767600300000ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÏIDATX…í”?kSQÆϵŠ âà¤à˜ÁÉèMÔ,ˆtýý‚ú Ä¥£ ‚£‡4$©I'…ŒR°¢…ZÄ‚-íyr›¤ÿÌ‹]î.¼Þ÷yÞsÎ{¤¤¤¤0Ú fª�àÿÉv¹�ÏŽD�Ní]°Ïö]^íàpÎõ®¬lìÇ']þﯭ Äq¼´º2zMfÀ�H’øwÚ>z»º2:ÇñRgŸÛh6›G—=ÜJ‚ÁC9 Ù‰¹yyrìØ½L&³Ö�³ãÞ3™ÌÚâÂüm¬©V‘ü$„ºÌ5õýëü�íæ­¼=°­r­ñxÐÚ�‚í¾NB’ìö =¾šË>”´kmÏ�•+õI‹'›}±u v#jëÊ“…Ü¥§m¶W3•ú]Ä3ààd.vYD÷‹¹‹/zi÷}·¥JcBò+à(¸s‰HäVøÛÖÍâåì›~t®rmîŠ^Ç‘,;XаüMòÙJ¿šOw©6w^ÓÀ) ·‘oVt½˜»ða½¡šÒìì9…èp&Yúì(ŒãøÓ ZC¿tÕjõô:#_€�#¬ßÈçó Ãj¥¤¤¤(¹Ä«-@DX·IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_down_disabled@2x.png000066400000000000000000000020251526321767600303520ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÇIDATxœí˜Oh\U‡¿sgAt£;éZ]'3Ì_^*¡MA…JÁµ¢‚+Ѫ("b7)âZ…€n\Iµ]ˆXšÎ˜¤™í¶Ú�©¸�ˆÐ¨I3�÷s1‰ÌÌ{™L’y“ÒÞoyÏ=ï�wÏðx<�Çãñx<�ÇãñÜYX÷Bm~ñ=Iï93‹%éâff’Ð4³Âòèûòn…êlý&FnhÑ«óíK.m×íK2·DäÜ)Ãn»*&9w*¹žBu®g�ûºDâÁ‡7@ ‡y­Jz*ª”ªÉíÛ03[Ìßv©tkÁÌ!uç´‹#ã•âO©*½ìÍÌ-=ìhžuú1 Å·ÌçÂáHä£å˜üÄxðø/½T{R«ýpH¹ø;à‘NÅÖM8è´0''ÿ³5ÝD®õÒOy: ÃÂ55òàÇöu!ü\rÉ䵤F¾²SòÐG¢hd%ÏÍq`&EœÛñe‚J€Iò4GÑÈJ?Vú*@«j¬}Õ-‹[7a˜u0¡´ØÏü³ú×± Vû5Ôw¢(ZWcý„ÐtG4›¶Ì²/¦×íHhú�ß—OLNNÞØ•½½!Éjó‹SÀÉ”c2š K?yétß2Û}·¯«Î/¾�4•0šÁµmòfoŽ•GOïÝî>¹8·ð‚aŸÐõsdÚ&ºvbÃ^ ƒÑéT¥~mïGy‹™ùúq'¾îîí«unõ7æH¾ñ†ž ƒÒ™½Ún÷1.Î. ÂRéJÓšeàjûº$ì§?”–<\Í‘/:yÈ ‡Ëå_ï²fãrûºÔš¶ë—bÈ%ÆY㲋7‚Jed9‹X3íÜêõúý7švNRØ!àhn�Ó­¯}ê`U½'ÏÓÅbñzV1fr¶(‹×ã��ç:ÄäÌ03,NIÞà¬kG³L2.lÍkÇ…>ï´ž'%ûz೸±ölEëYÇ7´ N’«Í×?{µ÷Fû( 'Íl(»e~¶0³8,_{§Ç¶·Ã ðú°’‡áÎðÿS›[|Ièã¶%!^«?v,ógP�]˜Âìy )㕨\üò bñx<�Çãñx<�ÇãñÜIüzÉ[Gy.fIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_down_focus.png000066400000000000000000000010131526321767600273440ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+½IDATX…í”ÍKTQÆÏ™>t“¶è:BÑ\Úö¸Jˆ�ZÙ. š™hþBú„.’‹Ò¦EK]$-[ز\9´)œ;` „0÷má½3ŠcwfÝÜ\8¼œó<Ï9ç=2222N%ƒBPû)< Sƒ_ÕòÐE·§ê]qü š^ÍÁ¹ÜÎUàcˆ€Æ±|Fk‚X�½öX/oõ÷ÙM`e÷bÌa­+:Ân…Ì!�x×ÞF׋Ã[¬Mä·ÏÖï˜é5„ƒ#…Ю†½:3P¿»6‘ßÞ?¡o,çÿç0Ç•š‡Ø¹y²Añ¼2à=áží&µÇLþB8�1ÕCˆ¦¹`f£ä=Ej»6õxý`sô,‰ùŸu«wL“•GÞlZÒT Aí¾à�K ‘ôLÃăjièešvÇ æ›c ·@ß!!ó¿`ã•r~¹Ý®:ÜŸGp¶\@‡hûIc%ïC§š]?1?o€­’a–hÔ@·*eïS7z=½ñk aÁEö¸—¾EN£_‹^µ[­ž2×ë—£Fôøìrîö—‡—~ôª•‘‘‘qªü!‘Ê‹k�*IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_down_focus@2x.png000066400000000000000000000017551526321767600277330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ŸIDATxœí˜OhTWÆ¿sߤ›"Ò™üJ a¦íºÐUM±¢¥E\šøKAèÂþ R FŠkg’ˆÝtU¬v!¢vmuÛ:Z«Mt2í&ikм÷u¡sß�™Ì¼7ñüàmî÷î¹ß9÷μ{/ (Š¢(Š¢(Š¢(Š¢<_ˆÝ�Ÿ®O†  è`|ʼn4„FÌ—%?}ÄW“+ÖVxm³×^‚òxOêÉÓ)'›…H„æ(ä™_öQš£Ñfƒ…;#FÌ9[ì ÂdƆA4¯%Jø^Åï»b¿ì, N×ß4 /xÙ’lÚ"¸’ÿ3³½ê§¯­ÕÁIÕO_3žyÛ’² ÿ;Ä™ü-㙡µ’‡£C„ÁSs¯˜ï" ¯[ÒfZ ŽäùK˜ ¶UG³öF:>•êhö¶0¦ð'K€Þú%Lzˆ$/W…ÁðzÉ#Úqm^›­o ‚ð¬ïXHÐhœØ ýíÜqÙóÁ�±ôR#aþ-ßK/­tý»À÷öˆ<�í[ ¤@$š»ð5��Ÿö�•¹Ì!‘¶\¶´÷:ƒ”üLísR¾r›‘/J~úX3‡šféÈ}N®P›€àäM„ð@Ùï-¶ÛKÇ.´rÅÚc Š|Tñ3ßuÊ‹¢(Š¢(Š¢(Š¢(Šò<ñ²#,;lŽgìIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_down_pressed.png000066400000000000000000000007741526321767600277070ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+®IDATX…í“1kQ…¿ó‚² ÚXX° (Ù˜ÒNI©±ˆÆl´Ï/Œ¿@lÒ¨‚…(VZ()Sv‰$�2…TŠ4 3'ÅÎl‚›lf5Í|0ðxïÎ9çÎ}%%%%ÇŒ²EÔôwàôòýQ¿¬3aßf8¤ø_:ñý˜E @Äã±HRM Ÿâú3ßöæV\�·x‹¸æÖaÒŽÓ#i¯Ñ•>nŽ_Ôæ�^¯ºoósÀít«÷B$„ÔåUõ$÷F´½¿¤cî£Ú®®3&3Ó®QgÐ\æn™ËÌT×¹ó§y«ìlk¶É4âaZ™àœ_"3,×k<’tà»Gv5<…x’å¢5’n„LWbjbHO»gÍAÔô] *]Cˆ€ÛLLëåQÚ¹gûbÉ#JxœØ�!²Î;pk²¦÷yt ]®Ù†¯X¼N!ŒÓ{�ÿ$0R¯i!¯fáÛ5| øˆ8›†È460×ëÃZ.¢Wü÷ž-ùBÅÌcΧ*_bqõAMkEµz ðü³Ï…˜¯ˆ•$pãþ ¾õªURRRr¬ìoÉ“TniFÃIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_down_pressed@2x.png000066400000000000000000000017041526321767600302530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+vIDATxœí˜MˆE†Ÿ·Çx ‚ x= ™�!�ÍaT†€‘€–™]qAðÿ@B0‚ij »ÎæàI¢ñ ¢Dâ53#xŠäbb<ézÉŒ°»Øýå0+ÌT×8?Û=£¦žc}]UïûuWu}�@ �@ �; ¹ ·ì´Þ2(  ›…°Ìˆ±E¼]+êLءް¿ ÓS8=qµ¤»zÛ"÷¡ÿöëþg|ÞR ΢ÿaºžÎ¦›=l4­’�{œ�Iöê2%"í« <]+é²û°7õ–IøÚà~'ôïM‚ˆ°~O‚M"ªEµ|]|K€jQ­æ�›î4Òà~3Ãcø%†ùAæ»Ý†°~Å’øxÔéÙýf½[tøÌÿdÆ‘¥²ÜØÇÐ7¹TÖÍqXÐì Â( OaÎ�ùÆŽ8<Ì<Œ�€•9mÆÛ<�ñ�WÀlþóÊ¥d›'Wæ´9Ê #¯ååyµù“c&>ó„ ¦é} »sù´_hß˱åyµGk¬Í¬VÑÖ�6'€57&#bI’yu¯íÿ™/?¢íñ†›3S½É*p*‰òªvÏõ©9á\mŽ×%�=ïžÞX½a¯¬zB YŸª˜¼V-éÜäÃî‘õ¦=/ãCÜå”e%é7Ÿ^¨–”ZŽã �õ†7ø¸Û eqjômw0ž«•ua�cg·i­]±§"ñ9°ß™Á°‰“�2/è`õ’uDoŽ{heˆÊ¦½íg¨¬¹B8Í0í'�ûÅ$*A8o¢toë.¢�óÌÂÇQÒ´wî¶"ÏÇG ¼Ì¦&o lØVzû£u:�Ÿæ„¬¼ÿ+Ÿ“dŒ²%…E¾ùìýïÆ/s‚�ùü SüIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_left@2x.png000066400000000000000000000020711526321767600265070ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ëIDATxœí›Mh\UÇg2¤-E[u^l5�‰DãÌH±n$ŠV‹X´‚®Š( ºAªXAp!¢7.,ꪴ*‚1™Qf’mÞDi?¢53ï¸ òî šâ½÷]uþËó‡{ÎýÝ�wÞ¼úꫯ¾þ*Ëû£ÑêjTª¶ Åò“¶Æ[¹T¡tÙ5Bîþ¬7‰µcçm âRQ±¼d’ÔbiÎÖøÖr¡h¤r ÂQà,ÃJlåvDÅñ ¦@¶t»¢¶ò¹ £;ÎE¦€m®s`ËØØFÑöÛÀ˜�|Alv–µ-o*ùS+\k8ŠÅKÏT(¤ð͉CÀ­é°:�<`¸T~V”»�°‚8�<ð.VSx´‡å|ò�1€¨T¹Wá`«ã«†ÌŽ@T¬Þ¼Üí¨—•_S&†‹•ë=Ü�_›]Þzä@aûåW* ËûäÁóP’£(g¦ÿ+¿&o¢í—^„LçVf“OÎ/Uσä=àÃJpØæ®GÎ‹WlÊ¡ï€\œvTÉxòàÀÖ­W�1Äï“ÀÃòÒå­GîLLäÛ~~áê´á¾¿?¹ºrÑ×'^öñ`V~M.v€DÅÊsÀ�F<¨•_“uQ©ú8ÂÃ=¬à&–DÅò} O¥£ _nNWÖF+y©Û ëÌ›² Ç@£ów²yzló çX ¢Ò5c â'·¿’µ[õ¹7Ux ‡eå#¦+Y]¡V½ö¢*û{XÁB°¾E[ µ /øÈeC.ŠÒV£öÂkF\åûGrUPo¼Kà-#.6¿íÛ�»b¦§WueðvÐ�Ò†Ái!q<½²¡“¿a&íH0ÇÁyÍæg?´Û�†% ™ÿ�’—Uø®9ßêäåz…¥´#¹¬!xÛ†Ë_Ì.*rð}ÚÉ‚×s¸Ü˜�Ë 7+i';Þ/¢ãõÚÇHn¯ÀjÚÉB&7q\Ÿyt½_ž¼BÈìQ´Ô˜{¸¿ÛñÛ#dú,޵Cˆ<‘Ž x|yʼ‰ë³Ï <ßÃòR[æ�j�¯q/Ýb’xÛæ{&�¸s¡€cÇÚC�Ÿî>4§Â4›ÍßNɯ{€O ËÙ£1('ëõd7ð¥�|ÁXnÌ~KÒÞw�+Hñâç_©tv!œìvíµÌÁhÕç絓Û�ò‹aý?þe µ8ó‰À-¤Þì}o ÀÒBí}¨ÒQ¥<�uM}õÕ×C>òk ¯± IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_left_disabled.png000066400000000000000000000011001526321767600277540ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+òIDATX…å—¿kSQÇ?ß©JÅ_ ‚âèЩ�©i*BJ‡8)¸¹ýÄAÜE;™Á¥tHEÚ´ö;©dDAê¢ÅR ä‡W\ûî»— z¶ ïœïçžïá\üï¡ØÓ4=Ü·Ò{V?7zh»ïwÅo·ß ÷ÝæØË™“ÄïõzC»‡7ŸŸ¼(­V«ôõÛ�ÇÀ¤on0€™éØñ“WÌáv`)}uÇÐ ‡‘×þp€…Ýi3nýÇO<`q¹{Up@È™ç̓—_N!Hr†/ÐYYGj%ÀÌŠ‹{,¬¬ž1s³À2¿½&> Óéž’¹6°Er®âçizÂÏ€£sA}÷(¹ä�I{.ší"¯o�­ÎÇ�\ƒÄ]>€$1ßð\ªÕÏ0 ¬ÈP´W4w¡z½òΔ4€u0 «Èù±‘×R2üÌ Â3ïõ±‘%ÌšÀ�¤ ‘(tƒ‰ÚÙYŒëf–Q¸…µÊŒŒi2ŠŠAyX¯UîKÜÍN–±#xˆÆ«£·1=pοÁ’líËÇ›O$¶ìØA€f³98rpß5`Þ÷W'ÚF+—Ëý_{/Ý¿ÐhœÞJÜ%ÁºßcÖþwã7ØÅ¥þõ³!�IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_left_disabled@2x.png000066400000000000000000000022231526321767600303350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+EIDATxœí›OˆEƯg6Ùƒ êEÔ“(ÞãîìÎf'5ÄàГˆ¢ QATˆ�ˆ"ðâÁ žÂ‚F7ÆÎÎÎÌîJññ ˆÁ¸8;ýy˜ÕÔt0l°º»4ó¿ý^}õªÞ«®na„.dXÙl �•}Hϧ’EâÆä >žûŸàD{968®3ñ¦;gêÏŽ|<$O$í•0§áÉòwÐ$Ýîu†Ž¹¼™¥¾|+ÀââÉ«,�æ�K³6Iòå'HZ­Öe}[›®ÌÛW5oç‹v»½m�ê‡ÀµEø *’$_£z¨¹¼�·”Ï"’$©ÚØøa`—ËHàmÓË"$™mÚrìN—73‘ãà!�=`¡³ò2ð Ë™!)ßÁC°°¸ô ðt– >·¥ÿ7JàDgéa™fÐ/*†Òø´³|7²7Ï2X”{Ú»(E€dqé¦Hvý‹õ×c—·.@«Û�0³#À&—7³Ôg‹»QZZ­åëÓ”£ÀV—7£”ÁC�ït®Nň43FÅ‹úTZ� ‚ ("8™�ˆNs“*¢¡0�½|0‘ì“)˜°Ï>[3ÿãúá¬u¾};ëÌhª©¦6³$ëþ­º_[FõEEÔ.n{ÖÇuÿvgo0b>e¹^[È·ø¸¶ñq‘4Õ3º¸ÇˆgÕ` ê­î¨t¹Ú{Øê:b}åˆÀ®bõ åÌpi[}å‰@׳ÛZh�@äò´sE çõÅó©Ë=!òEàª7§Ï©×íqQÙ“°¼Mù¤¢°wX[Ûjç¸Ñ1¼mzIÅ@Uª�óEàN'.(šÞÍC$ ¥…@p‚‚¢þŽ»³)s]¥…'žXc(6Å¥ÿ�2Ð]šëôH«ª†ÖP‰’*”æïVu£ `C¶(™Ì€Biî&àØšü*$ýy¿JÁt�Í^rhOXvùÈ ª ºFg¯QkNç%,Kˆ¯�‚Ø9vòJ1f¸Ø14»›‡@›àî£s9cåc 3ae2íW+õ°«xêBcäC �°” G~E©ØñÒO[ZLmáÚ„•êóýz”€½ÃÚºekû;(×'¬hnÒ0¬¦ºca 8àÄSîì6"ÿT¥»sáE”û�x€În#ò PšJá1'¨JŒ7ž�ÁBi~8ìUA$Xs³^y›…ÒÜàh+Ê‘_‘Ç%�x¡ j‘°ÍÍzå €H¸Þ§¼°*��|²1±ÿúè @e ÷žˆ<´ÆPm‰‚×c°ÜŸ{UaØ�Êß"•÷ç€Jîè+nT@²ÛHþ‹ÑÉjþQàm'®HtÒ)hDìšë}ß5TR˹A¥VÌ׃RûCë÷_$,‰i9¤ZÈì`çR­­ývà[ÇP¢™ ©1Ó{ÑoµšÜ L%,Éü€ 2 3ææŒèÍÀI×QCÆj›†?ôwL[£·úkƒ2ƒtNõu|g­Ü,­©C³�|#ª å¿T¸ ¨9†`–�É Êd'® ä?ÑûXûZÜ a!dv•û;ÞE9èF×”éY<9˜/ŠèÓNPÂ6O™?Œ”ûòÏ ¼ìe¥yJ5d-Ws�#¼åÄÁã7ÁgSöFÄvþœëÆNê}C€ÏFäL­mé^ÐÏ#å¾!3½;Oëé¶À7 +µÍ *•‡/ùÝÖu¿B9D¾èLìX¨›ú> šv®(L÷]ö£Z»8ÕÀö¶$¢PÚþ½»øÓu6É_fÊ}Û¿½Ãý–hüefµ&:>å� u…:bŸËº¦¦šjêÿ¡¿êj3�¬°ñ¶IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_left_pressed.png000066400000000000000000000010211526321767600276540ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÃIDATX…å–¿kTA…¿³Ï5 h‘Æ*…� Í.ÁÂ2‚’&ŦJâëlùÄBÒ‹ ØÏÄÊ-l‚…±³a·IBº€¤ÐÆÎÀ¢‰y{,6[ûæÍ  ·š�¹÷|sïü¸ð¿›R|¹å«ÙŸçM]ùÝús)Å×w=Qó¸\Õ§‘J¼³ïñò„·ˆé¿$�޳þwÖ�æ `[ý)žóƒ? °Öã ððl:€°D=¯X<@ (Pô¼<‰ãpñÚE׳@+^ àU×w # Pt}Ëb8ϰÞA'>  Øöuà=pIJ#^`mË×Èø€˜ØN#ÿ‚ÁŸGc'ÚùȪ–`/¥h0@ã'÷‡Jø�UXº­/œ2ƒùj�”¢r |ZÀ]àÈF©2$oiGføáa7 àAK1m „âÚºZ;È[ÚrLýeíæM½Æ¬Àðf¸f&¢j˜·ôLf@®}ˆ–š<–yÔ*G4€$_¯hŒÏzÀë9„¸%²nÑË+ ¶µa2÷¤}�¡¸ÎC$vxh¥= »àÎCÚ?<�÷‹œöiU  =ç�˜}iÏ€ [V•8xÜ÷!ÞL{î­õIaKþyTI)<9ç[ ‡È €z%n™ý/L÷PMÓ¾+è<” àÀ¾>�£ÀÚ´oH°¾_�J°ÞWi€àâ´o‘¨‚‘_R)Þ:áËê a.ÏTÝÈ/©p_´¸À˜kr!‡<ÖþS àðg¾pÐL 6æB…—¸+UaÆg=pz ï7gЧóP€q»¶a-ûÛ2aJ*qWªàlëê¯ FÒ¾"ì<P NuxÖðdÆto¯ÝV�íŽ1ì͘½ÓMi‡›Õ*€öœ÷aÞXø »…›Ê~ЀêêûÕ(ä+°|šGÝõž‚�yœ\—5E~û Àè� Ëû6õ˜¯`ƒî£M½.3ž÷c†¼i²x-í �«ÿ{>OJ’O5xñvÚÿëz;:…$´[J` x/ŠBaÉìjèÜ‚¸_p,Š B¡‰ìj謸 q"ŠBáIŒmÔo$Ü|— U¿7”2 cCú©žpðc&`jUC(mnߤ“]¸ók&ÐÛ+ƒPê{¸£©¯kæNàì²<*š ¥/D#›ô¹kÜ œË*z*Y‰[7éC›‡Èžœ”ÿ:T¶µ†ô®áÑ´'±´&”¦J÷âVSÀs³!ÈÏ`W¢Ê‹‘Ñ/ ^͘©œÜ* É'<…™Jû6 ù›à¿Så wx:u††é´_Æ 2 »‡µ¨Ó<|š ©È×!cÃúcM—mÀ|Ú_úŸ@Š Àƒ›õ{}�­À·e´€í7èçn�-ˆŠn+J;nÔ÷^d ð˲`À’9Z­Íú¦[�3™@Àj1j#MÍ%ænR?™yÓ=€‡‡ô±`½ë·®Ä‹UçÔW_}ý7ô'�-ÙR¾OTIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_right.png000066400000000000000000000010241526321767600263150ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÆIDATX…íÖ±kÔ`Çñï“+T\ŽX½;B�utp”.u*ÅEÐÕAúˆˆÿ€(8‹8âvˆÅÑÁY#B{Wð¼rK¥CÁ“Ëû8$isIx3è3¿ïóû¼ïóÿzI‘E~'ü©¨x“¤=Æ{uœbËô”ÀÉéœÛk…á|€´®9æmÇdŒå½‰÷ÖÜjô–ßýúŒ‚o¨F€(¨¦¹çw.?² ÈP€~;\· @ALæyâwoÛdR„Ê‹V{qÅ6 C¨®#òÆ¿^· …Çq´·p1X² ÒQ(pÂ÷ýÙNе øÑJp?œ»tõŒm@Ž8?M¦ïš•r¥ @ÞoÇó¼…"¼šÃ»$7¾ÛÙäáûŽ1ËÃA¼5ËÆŠ¥yø/ŒÜü1øòy–ÝUo@@HŒêÚx°ùqÖn@åp¿èÝq?ê•éRp.èúîVôªdŸ2€üäðx´=-3¿�ôäªÏGýèa•ð€4\Ñ×»ýè>ÙoQ•*3‚�ÓsæGß}{…OfÞY�ãøwáPp û€x“de¸Ôþ¿þ+ƒŽi‰ZP IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_right@2x.png000066400000000000000000000021131526321767600266670ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ýIDATxœí›_hWÆ¿3‘M[IA íÎJh²;š »+hékEªEÁVBA-|j)‚}PAK¡-ô-ôAZôÉJQ‰>(HKM6 :YƒµîDÐ`UL›ÌTÔ¹7˜Å{Ï\ao;„û}÷›sÏÜ;›Z´hÑÂùby·_ªNùAu2_,ïÊÚÏL!Sù¥J À{ð‘™xyÖL�o ïé2Søñ±ˆ˜Žø¥ÊRsãÛÁ`HRŸ;>^è©öÔ0ŽÁˆ5×:Ùã…R¹ËœŽYLVÀtt1Q¿¿pi§€VÓH0^Güÿ±ÎÞÞ½&°@zI¼‘›Ê‚ Ý¢fÓØ A*–ßá—~Ʋe³,ê6…í%�œªîó/ßø÷ Ï‚@ ¥@¼9_ªì·¯ýtdš ºGÛ ¥Êv!ýi‘ âô>+Õ-‚$ÀJ%0ów~±Ü'ëãÂkBð@ôK¡Xy[ÖËCqqˆ¡ö„‡ó=‹ß”v“Aî?ž �0›¼ä¨¿ ¼HÒHVº€yHè„ß³è5)Yºž0Þ¬þWKÕW$ d4Æô¹a¡>67^¶­î@€v·,iç�tww¿`SÙ‘hOÞšhë8hóðäR€&Þõÿ¾þ,yu-@_ ýbåsX8Aº 9<�ð±Tw˜r5ˆ•B`Þç—*šq9@W À7ù ú¾)ÇОˆ˜¿2¥àx€¾ï±±Çâs€ê‘‰~45¸3og§¡-}�‰¶Eáàצ®V'ì49yÀÙØS×>}� í5­äâðzröŒ�úàGPwˆ&Ä\‚=¤n=ýÖ˜“Ûýžà™q¨X½óÀIobö:„§&m©:€fò„³InÍø•Swm*»¥'Ï@˜ÄüÎø¥?nÚϸ0¥=0pqÛŠk—jc2 €  ´þ8È[�þ5*å"«ÔÉ3î$D«£ðì°¤‘ PËž€IxÜ7ž–v#ܵeÏ ñ†(¬õËz¹�ô—£:½­QX;$ëã’(‡Úú^Ѓ‚ÔPƒf|Ñ©eþo2 Ùß?5êCŸÀÂá¦Yl ÛßÿzµkÞp`ò€Ý% Üyíñ­õš²¨Û6HOþÏÿèî{�ÑÑ ‹šM#õ¸�€VÝÃ…ôfŒÄSà 8^1V?wM@«iLþbD÷ÿ:<^Ù¨Ÿ»lNÇ,&+ æmædUtqø¼A ã˜üÅÈãïìØcZՇϘß&›à>fÄ̈‰°çŸúàïÇnÑ¢E +ÜéØälIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_right_disabled.png000066400000000000000000000010661526321767600301520ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+èIDATX…íÖ=kQàsnÖMðA‰ Ár!vcfG²+„m’*Á´)B~�ˆøDÁZÄBVìq±X—��Y»À–VB~„�Üc1³YË™ÙáZèÛÌ÷½ï3g.Ãÿz1É¢VØÝÁQÏø¾ÿ5O€I²HÐyHç­©7ÛãÎÔÜØ™_¯{½Þèß@Du÷Û÷çµZmÄ9€€)·/MN=‘”è å HŠ4Zkuºœú6¾¿×jom¸@‚HÚHƒGÍÎÖ§€¡…gÍvwÑ) �(#¤^½»7�b† c€êÍÎÇëŽ'q–²o›››×\ÀA—iÍ»0 ¯8DØønú…7NÈÉÇqÖ) kâë玮&é+ähÀŽŒ]üàK’¾¼ˆ† ûV¬V|ÿSÒÆ<0ˆÞÀÈ¥[�·�¶9s‘d<üXâJ9ðÚi÷ÈœAJ2 bµxõ,ûdJ€…h8¨�J鯋,ûd�¤}Ë¥¹ÇY‡g�ÖöŸOçKÞýa†§2$áå¼ï­Ga W©!Ph\¼0q·ÿ32l¥=~ž^.‹‡y ’& ì“à)cËÕÙy ÿ_ðl ¢BtI]ºIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_right_disabled@2x.png000066400000000000000000000022001526321767600305130ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+2IDATxœíšMˆ[U†ß÷ޤƟv¡Å�wþl5$7$c&C§RÁ‚à ])RPD[P þ¡àB]Õ"S™ÒÞ‰“4™©.D""(ˆX,£dr_“‘ñž[™ØsN.˜g‘Å œ÷;ïýÎ9ßwï¦L™ò†¶Š»«Ï"IžH�<Ò¬WŸ³5¶K¬°Üé£A•Hs­™Ú²­ñ]¸KI?½Ò¿ÙâøN°fÉ$uiw@|zºsöz[.°f€$e\Þ`x²Ý^ÛgKÇ66—À…ا0YŠãÏ÷zÐÀ ,nœèt:»=éí‡0½$Ê([\\¼Ä�æø84@ �´ s—í¹òý8Ž îtÇÃõHH#P,½!ÉZ r185@$$H™@ðÁv§ÿ‚Kí�âa ¥k€<¼Ü]=ì^ÿßñu ÀÐØ¤ãNï!�1ø4 “´ ßlwz ^ãØ†_‘A’ʃ@àñJo¿×X¶Ä} jsûOï »HûìÌ™Šïx¼0B0›§Ë“$Xl÷z7ú dR’H#®Ò�'Ou»×ú cr� Œ6úšPáR·Û½ÚG 5ø»�NW‹× žè÷û{\ëOÜ `ö ÂMy<Žã’Kí\0J�„ü§ ’š,^ú¡Ëæ)l!!�¹î@±ô¶$'±æÊÍL x»³ö’‹2h” é< owמ´-—?¶04Ÿ²êh»³úˆ]™¼¢ÌGíôzÜíßmK&¿€$À0�^µ%‘o€ôä-¬‹¹6€™1Š|Ç–FnžÎf! 4Î=áP«Q}Í–F.3`4é0ã¯gfg"k“rhÀæäiÆ%¼Ò¬W�ØÖË� Á¨øÞk6ª�e¼c¸hrf£Ü¥>¹¢Tx «&°A. Í8€yçWvQ÷”Ëå�+í\œÚ¼éÉ9(nŸ-—×]jO<Hæä¿Ý(àÖùrù7×ú5€$3úüj~ýä#†‰-Y“ÿ5Ap`®VùÎW“É’2KÜón›kT¾òŠw.�ö ­FÔ÷�ï—£”¤v<º¯Y�–¼Æ2ÂóËÑ$«Ä}´Ù¨}ä5Žmø4 Ìø2÷©Ù™è-�1x0€ 3tÄ—›õêÄ?“qz ró'�Œ[ÿn³QyÂEs3.®3Àhn|¬ÁúÃy˜<àöCÉ@æ¢_Në÷¶Z­ wºãáp ¤ÛZ|Q qgÔhýáNs||�ß1<EÑ9Oz;Æ}/ ü¢0_oD?;×úX3`Tâ¦/ÿ‚ÌÔÊßÛÒ±�52êûßÁà`³VùÚ–† ìíÛ>x"¨$ îš­WÎZßö â(€!„¡=?wK唵±§L™2ÅÍSž"sßIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_right_focus.png000066400000000000000000000010361526321767600275170ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÐIDATX…í–¿kQ…¿;k–ˆ i2% º£ ¢¶)%M¬DmDwýQHþñ‹M )$b·ˆbia­HŠÝl”͆-İ’w,f²l93;< =ðºwïùÞáòÞƒ]–eS­ošÉ&lpx½>û£L€ Ë&CSˆ}¿Um�\éíñ0”8ókË^_ûTý[óƒÍp…5Uü€Ã�™.Eýø1R¦*À.ÍAÜŽ–ãû~v À�@Ü�š½E¿‰„Ì¥DkK—}Œ$&žEÍÞ‚_€DJWìÅÑ¥xÎ7$)˜”ÔŠšñiߣ{A¯�,Ç5ß D23�ÓÛcO¿ð @rKà�Ûv¯üÀèûzÊ?€¤_‚Jp0KÉ®í„.°³�ëÓß²•ež½oŽùÏõ°›µ°ŒvÌ·Ìì\ûVø!oñ8²tmƒ.´Ỽ ÆIÀH ãZ·±¿U¤IцæÈ»�™Õ‚} hÄÜxй>*jž@¦ ñæI§ÞÇòÎÀð¢±çí¯Ów0“_€Do&¦â«Üݸæ�ÿSú~÷¤Î¯_<1(ò'З°j0XøxeögYæÿð+0�SÀã§IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_right_focus@2x.png000066400000000000000000000021611526321767600300710ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+#IDATxœí›_hUÆ¿3cÚ¢¤¶Ùݸ-ÙÝÔW_•b+üCñAµ³m )(b ¶ >D°n6QDѧZÄJŠðE¤²;5E’˜Ý¥ˆRm5;÷óaSmfFÍÚ{ïÞâþÞvXîwη÷Ï93³@Ÿ>}þψ®�J•Ö‹õ¼@‘#µ`hBר&Ñf@aª à­~$Eí ƒá9]ã›Âû÷¯¬/K„Þ‰‘jë6]ã›B›€¨Ø…A�êÓљ֨> ýh4L¹¶Uµ£S#o-nÓ¨£�¤#²Íkû³¥ÊâVãZÿód‡òü“£3­A;zëǤk–„Pn�"u¼0YßhP³kL  1€�²qó{wæ5u»Âì`ÒÆ–ò­7Aj«A®ó{E!¶>Y¬6_6®½,l‚€x�‡Š•Æ!óúÿŒ¥S%®^)U–÷ZŒ!�MRÅë%ŠTŠÕƘÕ8.î"\ÝÖÆ@¼_œZ¾Ûj,ŠÛF@0±'läxiú‡;l‡cß«GcÜ„ëHï“bu雡ôƀə@lýSÛ§—n²D/ ø»å�÷•?;rl9c#„Þ\Zñ’¹äùr²0yn³iùÞÐ!Q-¸U6­œ¸ùíùM&…]1 1äÎ�•k?0Ù<¹d¦Í„ûolNã0�Äê˜RÚh�òÍWMt�.Ði£ï¢1^šn<«[ÊM@$Š›@ÊÑb¥±O§Œ»€ ѤKÂm:§B¼P|]—‚ã¤CBÛ±x )1rF×èÎÜ�M H?þü–ÀSa9÷†.wg@Jò ^ËYmÉîà%’NÖË™#„Cà!–½ïÖ²OCâ½Â•ãÚà�‰ŸþãA =�‰Ä½D-¸c€¤%�Ï/œÿíáú¸¬˜’uÅ€´ä¿Ž8pßÂxö‚Ia $ßU Û‚{æË×ÿdZ¼×› ¤Ä°äGj×|�mØ —$’ðGBíþöÀðY[Aôj ¤ýò¿(Á½a0ü�Í@ìϦ&¿Bb, r_ØÇò  t �5{ y4Ü—™µKˤtvÂýa�ýÐnas øñ y®ä¦,Æ�À‚r©¾_�×jÁPÏ_“±ð¢$Óª¼wÂ óŒ‰æ¦[Ì�Rß ðQ~1¸�<`Ö€´Înî÷�_™›�¶AÝ®0i@|ÚÅ‹þgß~Ñ f×X9 ÔqÏ™ƒ[~¶¡× 6ŽÁÅö®3rM Z]£s$\ ÎÑîïÊùï5êhEã H<¾>/T{êÁ §õièÇÌ_fÅkåá/õ�o}ˆ:J ¢ â¥ÚþÜgÚÆîÓ§OCü›°8Ýê‚oVIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_right_pressed.png000066400000000000000000000010211526321767600300370ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÃIDATX…íÖ½kAÆñï3ë+µbÄRP<¯P°”4±µ½˜4’¿@$øˆ‚•æBH!'éQ,-„ ',-R 6JŠøn‹]ÏNn7Ë\¡¿jæ7Ïggg–…½4Ê öº¿ìp|þ¼>× #Ž;{é®lxbç?Xë¼÷¾±0 ¦·¿±Òé8Kp J¸öuŠG¶GÚCµd�1XÜ^^g1)@`±¸¹Ûîy!)c4DéûDjx¸G3óúé;O¦ä ÌTˆ¼ÿ¹85@€ØŒÇ’$ùÿŧ�¸8wFS‚�€­™žoèè�{ê'òï.Í5µQ¶¹z á®Ì6ô¦ìÕB8ï·iÝj¨[ešª¯`.±0ÛÔjÅy*­€†}æ~ë¬V / 0È¿{ÄãV“{» / ÀŇžm6¸#Éo¨ æÕÄAn.Jq·á¥†·Ù~._=©Ÿu„ȧÀbKFq‡™Mm×þ¿~ÁQ�Q=†ÈfIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_right_pressed@2x.png000066400000000000000000000021121526321767600304130ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+üIDATxœí›Oh\EÇ?ß·šŠm¼X¼H1§ª§‚›,Ú‹´ØJ­)B|«– ž)(b ¶ *¨•fKiÑS-b%EZÐCÉn =ˆ ªˆ  þ«¨Í¾ýyHKͼHÒ™yÜÏñæû›oæÍÌÎBŸ>}þÏÈWCSm{ãE ³„½Íº&|µoZmË €„™±¹9¢Ó¾ÚEâ«!ý§-3Ÿ>ku_í‡Â›DÏy2H�O&Ûv»·Œø`Xþk8ÙšµuÞr<ãOÀ⬓˜9бµ²–M w¬2NL~nƒ‘ò–L8Z8$ †“ŽíÿÚVË\á=pæ±yðWŽì9e×Ë]&¡‡@O®ZÃ;fæm r-ŸŒ‚7ž˜êðjèì¥kt×vO·mw¤üE‰%A澯µ:öd¬Šˆ&À hµˆŒS³6«—h4¿Zt%$ˆ£“³v_ÌZ®†Ç§HÂ@"޽׶FìbÊ`Ãau>>tÖîŒYHYÀ0ËK¸93N¨Ò�àÞX1>»±ËŽt£æB†–ŽŠ:/Î_JxpÇFý2»|BFnÌÓírÿ®aý:¾\BX®†¬Ë–�wëÇ%”6Hnç�_[Ó{t!V¥0tþ¤Æi]_Ĭ¥ E�Ÿ“Më:»˜¨s€�,ßy“1–k&f-Wˆùó8@"çTOÆSiCĪÃ%æÏã5÷Dӌ҆Þ�UCQH…9o4GÊ¿&|TÁú1�Öy.Äæf¹„~w•|xávV¡óö¢d~}§¹È£›Ô –»L ÷µ‡s×glÛ¤¿ƒe®€X ¡¯jlÛ ß#å-™“à÷[Æ7è§ÐY+ÁŸ¹×£ø9IØ:^×wÞr<ãó Ú\ÄØ6^×—Þ2àó+põÌNÆÃ͆ÚÛ‚Ïÿ í2 ¼’6ô©·¶ûôéÓ'ÿ "óv~«QIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_up.png000066400000000000000000000010211526321767600256210ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÃIDATX…í•ÏkA€¿7›D(šþ‚¦›”Ò¤©‡mÒ¼Y ^‹=‰ ‚ààÍ?À›wožz«�Š´·@z‚‚'¥ÁС¥¨ÉÌxÈDVkº¡ö²ìagß¼÷ÍÛabbbb®‰:qîf%§�y‹¥’H$r_>ø%�ŠT¼°º¤µ©a©t»Ý½¹Å ø_rKÁª]Bà ¯–Ë/W.UÀϯ¬ãU�°Ðî±@Æ(Uõó+ë—"�)”6QvH÷ Š }6Nbewg ¥»Ãæõ† ò‹¥G‚¼R®�fém꤈<¸1™Ù?i·>�,�],=y ¨^ÛePñ�„…p/=5stÜn½�* Ùbù™Ež»wbÿ%Š��ôô¬V/* ²…ò O]gûÿø‚Xî\ŸÊLŸ´[;ƒrœ9ˆ‚ Hµx[ÀC7±øïüý�¾ÝœH=¦^ïüUÀ÷o�1öó5°áV0dÛÏÃí‰ï8MÝo6ë§gæçË“�$o€Ûnh”•Ÿ#!{×´Úl4>~HôC:I€ñЬHÇô`Â�¶kß=Ý&þ(b£ßK# ÅÄÄÄ\1¿vR~Ì*[Ü6IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_up@2x.png000066400000000000000000000017461526321767600262110ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+˜IDATxœí™KhQ†ÿ“„ÖG0©ÍL´3Ѷ: ˆºR4*ЏP[pãÆ…¸—âJq%ˆ+7*ЏSW-ˆZPãÆ¨(•>ª±˜Eâ«´s]$ÕdæÖ¤“™´êù �ɹ�ÿüÜ{ç\0 Ã0 Ã0 Ã0 Ã0ÿ4S«šÞK ³ð8?2üüèLèðÎĤª–8Ð%~!å]áóÇ'ÍÖÒt"±ÄNúúv‚áo…|.ÝL=Í4€"Zò” ûC›­�`ÇüB>w«Y¢šc@*åS|m¬Ý˜ÖùCáÎbrE?²YÃmi®‚ÑhtÎoÛU»­Qa”%x$]¯·Nöf³ÙïnêsÕ€`<hónb“$dž~rNÝo\1@�­XòÞÐe µöµG¢kˆ ¶¾~ñÆ)�•“9ŠºLïyÓ°—<Êm„é·.J«ÑD·+qÔ%¶r- º`±)Toò“€0›Ð /î«1}MC"M8fÀ¢Xr ‘ç€�)4ÝäË�Ì„ˆÃZr³=•V1@�é}‰~”ÊÚJl&?‰Ô¿b@Õô^ûãþ¦áB(×÷t€¯:" €ÌâmðkŒÊƒÑ ОÀ‚Ž·…|îi#£7d€¢%8Ë©íTòUc ÊyD»üÁŽ/Å|î�ÝQí@Š–8IÀqkÈ�ä�’Ç@ mþPxnñsî¶�Q§o@*åS=�sD8d º•ü$dùR~XßìXTÌoì^NkþiB¥º>p}Ö¨ÛÉWÍEIpº6Ÿ¾îÍd2?ê©nÚ»ºÚZÆ[nÀô (�Ö–âÅeä&àö¸o¬·ÞûC]¨ËW·cbl€¬™ª®o²müÞ–#¯�Öê\Ó€ˆ¦w ¢›0—¡ ¾ãEvxå!Úö.óìm­ŽS¢FÝ”žåÉòÒ¹Ç"Yš4ßIª˜r¨1} µ›B³-ùJ$+AŒ´}døùã©:XP´•›@4ø—%Ho’Ô`P‰ë)YË¢h‰£º UÒžP2m6d«º•@ûüÁ°QÌçBՒ〘‘ÿ ܇&F†ŸUÝY¬ïQËYòï ËÍbN`vïs»å܆a†a†a†a˜ÿšŸæ6÷ì‡Ñq(IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_up_disabled.png000066400000000000000000000010221526321767600274510ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÄIDATX…픿jQÆgvÜ,Œ6Z¤I¡õ*L!f#¤SÚˆ‚ ê+è#|AÁÆBAff™™ÝÙr{­¬,‚ˆÙ½ŸÅÌÆÅì&:lb3\8pþ|¿{á\¨T©R¥ÿ,+Ûø¾ÓY®9ï-Ðô.·Z­ÏeæxešÚíÞ…šó  0ÄOÃNçü±„釋ª‘+ òÊ9/ÙŽ³æ‘DI¶frmà¬�ÀFùAÀ9µ£$[;€0Î6@[À)0nœ3p`ÂXmm§Ùõ¹„iï¶™^ @ §‰|ËaÓ^·“î­¹Di÷¾‰g@­0p”»âujžGi÷^iI%½GȘ™;Ä|ÜéŠZ�m†q÷¡¤™ë>5!É‹ÒlÓàn^dNHÓjg63I^Þ¯'WW/?Ø;`0Ô¿|ÛyЏ™ÂIü“ùoL*^Ùx±¸àß ‚`w&@¿ß?¹ócø¸&åæPÎ|ÒCàFïþ� ¾ïˆãøÌˆúLWŠŒ£äÍ÷EœºÝ…�õõK_üqш1-íu©Ü7=M¬ìªÕ~NÃÄÌåª äŽÓ­R¥J•Ñ/{°%âú»UIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_up_disabled@2x.png000066400000000000000000000020151526321767600300260ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¿IDATxœí˜¿o›EÆŸçâD‰TX6ÊJ™IÛ�š$oQå©é�¡Tü@ÅPE©âÇŒTµ� 1€ –"‘³ã7µ ¡ˆ HZû»Âï�ĉóÚå>ãÝ}¿÷|Ÿ»÷|gÀãñx<�Çãñx<�Çóÿ‚Ú¸T©/�ú€!qsîìôÕa芥Íêeˆ×˜‡m‚.ùçV­Åt’-åJõ Äñ¹ Þ,mÖß´ž�íIÜØ¬¿'àµ.Cߟ;{æ I B×@ °Ö昛¸â¥}éþ_¯AÐè³´þ`­çØÄ'ÎG:ÐЂLR‰¾Ðƒ�‹AìôS__ ¨Õj�ï4p @éƒ&nrFRR¬çÐ8ŸÏçÿè—Æ¾°±±ñ„3cEÏv¶·jgSH~âFRmw¿0;;ûK?töÅ€Jeû©&kžŽÎFAr{‰i ÅuÝaÓ¼87wúnÖZ37 \­>£×@<™¨]|·£�­ÁFIîʸÅ`fæ»,õfj@isë䊎Ç&‘€]W> a¯Ïù3Û‡Sú/™]„Ö7¶^€Ü:ų‡â@HÇ Ùòf}¡g¡121 V/ã¾p,ÚCµ é ¶Œ‹›pLR±T©/õš·“CPë—~ `¬³�¤ºó{ÑŽu­\Æ@}V®Ô^>Dz‡4 Ö_´ÏCÐIÊì*+I)&Ú°Öíj½'=‚’Xkï€L<^:!»â#¹[JbÑD¾;?súÍ^Þ6ÀZ›Ãèøu‚—""f»ò©�”d’¹úóOß¿º¼¼Ü1TÈ´jNd¶? Û´ý¦÷ÅöÜ^è©ý\Nv·IJJJÊqå&Ñ—°4Ñ IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_up_focus@2x.png000066400000000000000000000017541526321767600274070ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+žIDATxœí—?lSWÆ¿sŸƒ"í�JCmül˜¡{ "aèÀF¢àN�Ú2¡UB-lH•ì÷B˜ª­ S#E*©ìmþTT¥&vL—VªJãw¿6`?ߨ®ýüàþFŸwîýÎçóÞ=°X,‹Åb±X,‹Åb±¼^ÈvmœöJ“¾ ñW/ì»´:¶Å€´Wœ!$@=Bάdßš‹[‹jÿH´¤¼�‹„xá½)â»ùÒ§q뉯Hqý�«>ný®­^Øw"ŒCV,ŒÏ2Qx»äAä|gœ)ìÏþxY*ýUƒ‡o>LlîþZ€3MARWˆéU¼µ9ð÷¹_Ï¿óO?õõÕ€Ôõ?ÞPƒÁm‚'#D :‹†¶"ÀÖÅ¿Pe0��‰‰•ìðÏIñ�öÖßœ»h*�_}ZWsê¥ îeråã= ­#2Ò¹âû„ºb("ЦíÍhHÈbH+½”ñ‹'»Õ&\¿t–J¾°'ê¶øgÙÍ�ìÑ”…´WšìzÝ:z6 å§A|`WcD4z)þ¦uvø6åmLõºxO¸~é¡ÌÖÑ£eM�¤¼áz¥Ö£uº3€×+}âjsÌØ¶Q°ÕëtÍõŠŸƒìêDûßIã³L<)çN7iøpE�ÀðÇQdníÍ䇸À0dµY¬cß|88ðïî¯ 8Útõ¬�ÖLÉ'¾ãÓ?Ï­}ä>ít¥Ž ÈÜ(ï }[€Æ#ˆµâcº¾Öm,ÆK”à¥Ôd§÷‡Ž Hç ÃZ9 BiBX»Ôl'¤ —!÷…›§W²#OÚ¥·5`l¾0ª*Î" GB™íçú¸0�Î�Ÿ(ÎÄÚÌÐï­S[�Î?9BT!2 õ6àDŽBƒ øM9jby:¹¼Uæ–Ç`&W>N î6/;¬x zÕ0ž@‡t ï�ùåcÆ4laÀX~ý„Vz À°a§V|ædXQ/¥üõqSJÓ+àæË— ú²)ö’CPÍ®f“ŸÕÿhè€`¯^ñ µÚ0œ£¯bí5 µ ÐW°ã>r‘ kµY,‹Åb±X,‹Åb±X^kþ0+>%†óIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/arrow_up_pressed.png000066400000000000000000000007731526321767600273630ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+­IDATX…픿kA†Ÿw/ÁÂh‹4¦ŽÊ� ¤bJ›  ’"…¨‚æO0Ør{!J@,P$éFäÜ+"ö±ì¬"—óZÜÞ¹z z›“ئٙùÞg¾Ù]((((8b”wãü{�„2o0c¡ÄÈô%}ÍS'ʳ)þàÑPæf ¬?kø|žZ=w ®û°‚þcê[LL_ÖF/õzê@Üð8b 1,0°—g£ˆµ¸áñÿ"Pmx’À*pJ†�™CVk‰¯÷U Z÷-–€AÀöoá-ZÏ Ú,×ê¾Ù�Zâû @) èÿE[¢dñ]ಙiºb@±¢GóÜÌt9¤ôì.]�´™ c„½Nž;À¹hŸÀ5Ķ¢ŒŸm�‹3“öo–ú25àû'zs#Ç=ƒÉØÄFCÚþ�D.@T—,®è`0Â=Œö#Hl}ð“üËi øÅ=gªÛûCW|[×èkbYÐ^„l&¿§%—&FóÏ¢¶aœ½T°¿»‰Ñ‘RUcf<ÚÊP3¤þÎøÔ0#�ÚsüÖhpfþû³ãØN�a]ÇÙ¼ÔŒEõZÝe†‘x‰úÝÁ™¹q{ºÓ¸ë€ÅUL–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý Ì�Õ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ—� ´/Imеá–]ÃtåH½I±Î¿� ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ �º ¦®œfÚ×â=åï1ChLûc @P× �Þ¹‚2Û ‚ú»56î{½ýÊ�Ž|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>�kÏ–¼¿Ú…í QW Ömõ°gÀ0�}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!�{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þ�o2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕì�Ëiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/base_icon@2x.png000066400000000000000000000063261526321767600262740ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{�ý£}*P´A�6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„�ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w�¾ÑþÜ©�*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾�£ 4�Šï?÷4Tý÷%p—§P9òmS¨ �ŸÿÄÿŸòmh§¾})è{îq1o…R’-� ��@V�1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö �?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0�ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "�œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r Î�›B}�oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™�~‘ �ßx+¶ŠQ@ɘµ¯² ®�]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö�¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=zá�ê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§�.Hxfû:VîGèÊ­c �¨/’Ñgîä§ñcXy .*P�FÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦�U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ�¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ ò�ÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t�˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'�Y 1a5rIH™Gƒ�eOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàK�ª'à%¸C4Ós–�ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤�)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·º�ôHe H .åã( ¾óGF{e%´ò�œ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 �1�œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! �Ñ$ À£ý2b…»}�4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌò�š¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa(�[9ÆHrç9my"è“Þ')ƒ�óIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ù�æ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡Á�ÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœ�á%^œ(Ιew1,S|¼’…œYµp†*—rA†8î�»÷O·ýWÐ8Ósúc�¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ�×í+rJØîí°õKU\²8ž¯/Î�]�I�#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— �—¤ NÑøü=/„a‰!­5 �ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N�÷óÖJ>dŒ¡C� #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ�¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ�¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf�"NT€ì£µ?÷Æ— hÝF�›%à¹î°œ�Ÿ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿ�FfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­�À}LÁÑ÷Ùë9qž¶øÌ�“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­ä�Ÿ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ� /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ�¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/base_icon_disabled.png000066400000000000000000000023501526321767600275420ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿ�r1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDY�Ø !Œ�qÏ¥¬�¬•Q¹ �Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý Ì�Õ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ—� ´/Imеá–]ÃtåH½I±Î¿� ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ �º ¦®œfÚ×â=åï1ChLûc @P× �Þ¹‚2Û ‚ú»56î{½ýÊ�Ž|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>�kÏ–¼¿Ú…í QW Ömõ°gÀ0�}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!�{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þ�o2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕì�Ëiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/base_icon_disabled@2x.png000066400000000000000000000063261526321767600301230ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{�ý£}*P´A�6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„�ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w�¾ÑþÜ©�*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾�£ 4�Šï?÷4Tý÷%p—§P9òmS¨ �ŸÿÄÿŸòmh§¾})è{îq1o…R’-� ��@V�1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö �?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0�ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "�œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r Î�›B}�oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™�~‘ �ßx+¶ŠQ@ɘµ¯² ®�]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö�¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=zá�ê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§�.Hxfû:VîGèÊ­c �¨/’Ñgîä§ñcXy .*P�FÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦�U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ�¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ ò�ÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t�˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'�Y 1a5rIH™Gƒ�eOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàK�ª'à%¸C4Ós–�ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤�)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·º�ôHe H .åã( ¾óGF{e%´ò�œ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 �1�œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! �Ñ$ À£ý2b…»}�4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌò�š¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa(�[9ÆHrç9my"è“Þ')ƒ�óIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ù�æ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡Á�ÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœ�á%^œ(Ιew1,S|¼’…œYµp†*—rA†8î�»÷O·ýWÐ8Ósúc�¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ�×í+rJØîí°õKU\²8ž¯/Î�]�I�#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— �—¤ NÑøü=/„a‰!­5 �ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N�÷óÖJ>dŒ¡C� #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ�¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ�¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf�"NT€ì£µ?÷Æ— hÝF�›%à¹î°œ�Ÿ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿ�FfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­�À}LÁÑ÷Ùë9qž¶øÌ�“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­ä�Ÿ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ� /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ�¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/base_icon_focus.png000066400000000000000000000023501526321767600271120ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿ�r1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDY�Ø !Œ�qÏ¥¬�¬•Q¹ �Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý Ì�Õ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ—� ´/Imеá–]ÃtåH½I±Î¿� ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ �º ¦®œfÚ×â=åï1ChLûc @P× �Þ¹‚2Û ‚ú»56î{½ýÊ�Ž|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>�kÏ–¼¿Ú…í QW Ömõ°gÀ0�}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!�{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þ�o2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕì�Ëiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/base_icon_focus@2x.png000066400000000000000000000063261526321767600274730ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{�ý£}*P´A�6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„�ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w�¾ÑþÜ©�*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾�£ 4�Šï?÷4Tý÷%p—§P9òmS¨ �ŸÿÄÿŸòmh§¾})è{îq1o…R’-� ��@V�1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö �?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0�ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "�œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r Î�›B}�oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™�~‘ �ßx+¶ŠQ@ɘµ¯² ®�]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö�¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=zá�ê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§�.Hxfû:VîGèÊ­c �¨/’Ñgîä§ñcXy .*P�FÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦�U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ�¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ ò�ÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t�˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'�Y 1a5rIH™Gƒ�eOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàK�ª'à%¸C4Ós–�ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤�)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·º�ôHe H .åã( ¾óGF{e%´ò�œ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 �1�œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! �Ñ$ À£ý2b…»}�4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌò�š¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa(�[9ÆHrç9my"è“Þ')ƒ�óIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ù�æ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡Á�ÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœ�á%^œ(Ιew1,S|¼’…œYµp†*—rA†8î�»÷O·ýWÐ8Ósúc�¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ�×í+rJØîí°õKU\²8ž¯/Î�]�I�#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— �—¤ NÑøü=/„a‰!­5 �ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N�÷óÖJ>dŒ¡C� #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ�¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ�¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf�"NT€ì£µ?÷Æ— hÝF�›%à¹î°œ�Ÿ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿ�FfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­�À}LÁÑ÷Ùë9qž¶øÌ�“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­ä�Ÿ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ� /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ�¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/base_icon_pressed.png000066400000000000000000000023501526321767600274400ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+šIDATX…Å—ÙvâF†¿f`PœÄžñ$9YÞÿ�r1žIÏl#$¨\Ôߨ‘qr—Ô9‰V×ö×Ö X øÏÉX¤| ¬!X÷‘K –%ï“DJ\³dm›¬íô~zò—À:ôÀ0ªDY�Ø !Œ�qÏ¥¬�¬•Q¹ �Kþ#0–òàÞ²ûDù‘q÷èÌLÊô˾¦€Ùx|”ŽAûNÿ+ص¾ý Ì�Õ J\p¨Ï`s Åó¥Òó€'ôxÂãÿ °‚°%Üc)Ïåݸ’Å9”O‚qf$åÀ³”•B8îððdž;(ÜR›À˵ƒ \Hh¤9†¹øú×"mÄ»“¬Û÷JÌcîżsA0ýŒÇ²–õ#ÁVCu Óµ#uŽl!™50•SºÒIöÁ—� ´/Imеá–]ÃtåH½I±Î¿� ‰X¶-<6xèú!hJXäxÒü%Á…úAîIg³î?ž7_as)Þ<‘ ,žIB ȼ‹‘ ÆR´b\á‰ö Hs=ƒ �º ¦®œfÚ×â=åï1ChLûc @P× �Þ¹‚2Û ‚ú»56î{½ýÊ�Ž|´`{†Ø3^†º$?©‚aRßI“©Ó=Úǽ{cé0»KŠ”NYÉ UçlÇ0‚ñ!ñ†ä½M„Œ€Æ=·5êLxF[ÒRJx5=És†¹O‡žÀ>�kÏ–¼¿Ú…í QW Ömõ°gÀ0�}¥ß2™'}ƒOFnߘ”¡U)õ¬-úußâ §ybÛ¾¦;D ¯ß­;î‹9`ÊpSÎ4XÀK³”âo¹j6–BÜßJ¸I¶!; 2vù¢;C•ÛÖ$4þßÀ3#!Ÿÿaî8žvÖ%,ï:yÀK8îÙÁIÆuâõ5 Q/?Éós™~´@~€åS·¼*¤7l¼‰_ ãê²c¢ö†ù->ÝúgÁ”"Ôàí6ø³L†W6“1'!Øûæâì†nàøIæw<ž{ t¤êA— õPÕ!�{Æ»ŸŽw,¡¸•Ìmjn@xÐÅ|$o6`-ð áå<6w ƒëg|–l$såùÓE1 Aã“-te}r1ùíÌÅäØÛ÷‚m +3þ�o2y0„qz÷Ëu0n}ÔŽj¼gìÅÛÐ ¦5ÉÕì�Ëiôâ˜pÃä}¢÷ l5;&•”ÝåT¹°óžÃkøŸ¯çˆ|Ó;í2OßIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/base_icon_pressed@2x.png000066400000000000000000000063261526321767600300210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ˆIDATxœå›[o[Ç€¿%EŠ”(‰’­»dÉNšÂAà&EÑ H ô©}é{�ý£}*P´A�6NR i’Æ–lÉ7]HI¤.äôaöîÙ3‡¤äôÉ$w÷ÌÎÌîÎmç²âxã@œòžþx“„�ãùMB–W—íàðœ<Ün%`2‹/m¯ ¡fàbȘs g´w�¾ÑþÜ©�*Ï£5d¸í =^ø‰§€9ß.ÀYÐ>ëÛú¾�£ 4�Šï?÷4Tý÷%p—§P9òmS¨ �ŸÿÄÿŸòmh§¾})è{îq1o…R’-� ��@V�1k Fûȼÿ=rä®ÿ̀ܲ#¤îÇ,¨àå®Ç1áûç@6óGUší ¿)_óˆËÈŸõÁ\ß6HÅhÛ?·â'[ŽðÝsr<ã%ÿÛyF¶ uKÛå-ƒÙ2ÈOŒö �?Ú¼ð‘0’š¬0Ƕí–íkLN`¢âöYN{IçËõ—³Ï¥»¹ò«q'ßlûPcÊÈmcü*Ⱥ}M|ó^y^dV·¼Ù7òdÑèkúg#Ë&›úÉ‚q&äà> þ'Ê£ì!£«py *_ád xZЗÚá< ðºO ö*hë(]”É)¼˜7˜0�ÆÄ4Pæ Z½íÇl/T¡ñÄ,ùÿ‰éJ4xØFÐö %† ‚2¼çŸ]~|Ì "�œÙŒ ÔÌ$ÿ7€6¸]?Q5]›À×à®ô|¹r Î�›B}�oG˜ŸøÙE`5©{ö³Ò†ú ÔŸX~€Ï€ç€·<ìøç{ªÛÜUÑÄ[ó&[YÍ)^|)FËL.¡¦rF?7YõÊx=kUÒþ™�~‘ �ßx+¶ŠQ@ɘµ¯² ®�]þÜ „¬ÌaSçÜSß7檛àŸuO€Å}ØÌ÷‹Ö�¿÷²sºžò"ëGÀÀp1zæ¿ó[é1Y! ¹ÙWÆÝåø<Ž îRq7ûÑn=¼ð=zá�ê)NÇX-%8çW/ÙF•L)0wÀ}àÒ›«Wèî MžŸÐÜ%èúãV;Äö÷§�.Hxfû:VîGèÊ­c �¨/’Ñgîä§ñcXy .*P�FÓ)ƒ­½ üøKt桞?>N¨ùÎyÔRøÕ9‡úád]Ô<þø$ Ù+Ïz ¸ r-fn%bÄÑá]`&ªtûÙá²ü pŒ C€îm¨M@ý%¸NCGÙ¿Rà¢Õ“¼ÖN}“¿kàö‚Î6È ºcßöžkB[ŸèØÇ:  œû î¡«ò…M³,¡Û¾‡­¦�U¨µU‰2o€ëè3Õ¶2«0ª£‡ú+ˆ¾ñcîùç:d¹"+Àð õŒ|غພàH1ÍC»†®ÂùX<Ûp<…ö$/`‡´]àLçŒÁ�¡‹úƒç)Ç‹%€ê=-æ·|Í)p­l["„Ë÷a®³¯ÌGo³¯`öRq[G͵`® a5ß-ÔÂeÀÀ4ª= ”š,£nªÇM¨|Ì3~ì=ˆ ò�ÎaÂsÛYr—@Ü1º¸° ¨iÙ) d¶ó2¥d"¬`ëÚnû”J^¿Äî”6±x:Ô#4Ú ”ƒL¿}Õ²á*Ì‚t�˜ÙúZÀ»ÀÒŒN’Ô¨OaåçÐ@çý- ;sä?#Á¦}dѸcï'�Y 1a5rIH™Gƒ�eOd„œtf¡~ÄAÆ#OÐ×Áä+@:gPßtoA-É/>óßÎÏùš+ átf ž-œ·‰*¾¾î†TW%yËLÂÆZ™EàK�ª'à%¸C4Ós–�ü¤õ2¸çyT‚g~8FWìcwµýø2ºâžŽÿh_.z;ñ¦ÏgCšd˜šlOà¤�)²á±©J¨oƒÛ ì÷-lå7 Gih¥ÍônO‡‡Ä©/ g‡R'¾½_Ÿ¹r'¨·º�ôHe H .åã( ¾óGF{e%´ò�œ³”›:QxŸaß?„´ 7N|j|Íêµ°Xöߺ„V$4 �1�œ“ó.ŒÔ{Š„iÑú C`GàZáì(Áô;§0”6<<×…ê¨|Û5r î Uæˆ0AqTw›^ƒndÞb! ½±¹©Qô\®=¶ËpeióÀ?È´—ìöšP{fÐ! �Ñ$ À£ý2b…»}�4sÐÃÎÖŽŠz˜¸ÎöOìuôGô¿&ÔÅGp¬y#”Ÿ¡ö7ÆÕ³ŽÌò�š¤ÒmÿÈFX‡B(@Û³ÌÍë€.Q¼@³Ã¿ÊÏŸùQÖa(�[9ÆHrç9my"è“Þ')ƒ�óIbt|Û2zÑ Ž<½ìg·± ¹CYÏæÓs÷Opí`Ž‚<£š8Ù�æ\Ó`-a< ‡Å¡»ú8Û ¶2Ùéø„W×ì¡Á�ÏÈVàoe_ûn0¶+æ$“ÀË„ä:>£8‹”à…m ]_‰²êmÜÐòg0ÉÛ¿ó BhÝF$VN²Ð÷-£Öh,%ØFí¥?ûmnd_8ƒÆ2œœ�á%^œ(Ιew1,S|¼’…œYµp†*—rA†8î�»÷O·ýWÐ8Ósúc�¬*N¾Âô¥­®-t™ƒ³.ÊSNxEù€Äf¾mÔ«8’êOÓmžfa.NÖ&°SÓOˆpAš4pÞtɺ�×í+rJØîí°õKU\²8ž¯/Î�]�I�#<ó¡(«vúÔ4_TÀ}ëêDV 6ƒñ•Ó'h9À2Z'ÔÆ]¿E¯Ç— �—¤ NÑøü=/„a‰!­5 �ºÑVMÏ%ð{àS—£‰LÊk'õf;…ÃÝgÙB ¶†÷7¢ö¤oÍVCܨF0}~óREªh íÈ»¶N�÷óÖJ>dŒ¡C� #ëNफõ€)¢ðŠºîê%¾³ã‚Ì )ûïÑÌÏyŸ�¦àà žän"–º@•LIìÌ ¨LzÉ…´ûЪªÎ¸V]î˜ eÅݪ�¯úc{º2_*¨nËÕ(X±@ Üžnyy( §¨Fîÿ ˜$?wà”„¿¡ |H¼¿U”ѧ0'Q¿9ÆûÐh‘¹¾“ŠÒãv@îÌfà%i.Àí¢u6ÉÖTñTÈf�"NT€ì£µ?÷Æ— hÝF�›%à¹î°œ�Ÿ&]Õã&ºêeTyvÐÚæ%eÐËØŒ3íwš WÝZÿ�FfŸ£Bxç'P=R" Í[_çh$›I€ƒ ¿»ªÉ !{f¼©3ËeÅ/Ko#|<À½ Æ—ã{FëÄÌt=!Ñ‚EÐ+ïeß¾´ b÷‹ƒê¤g°SàÅ­�À}LÁÑ÷Ùë9qž¶øÌ�“B“;ç'S._ÏZðfè}ìDI2æÿP.ºòó¼ù•¦ZŠ\¹ü̲^ùÇØ/L¬’{aBú‚…ñC:f{̉CœψCßù¥ÑWÎú+©ªŒÿÂDŠèONÈF^òúÊJî¥^ë•™´­ä�Ÿ·@Þ1œŸ²¥å=óÈã+ž<‘ZY¥{€àw‚q}-~kÞÓO+tž*Œ~ijÊ� /+ ^¾*z9j3f‘-ÏC)¿›bD†“#›¨¶õ5º´üïjæzrÁ൹@ 7 åÄ)JJd{Áÿäö&ym.(—Méëúq5a§þ÷$ªÄ}T¡ÎxöN“íÀ�¸¢ŽA&0JÍ<ž:y-¿8YB¯Ê’#Teà_à™8$kó¬'…Aâ3£´6}¬ˆÇ7÷ÕY«á € Ïoó ¨þ´ ý~Ï"[ÂIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_closed.png000066400000000000000000000006211526321767600265560ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+CIDATX…í’±JAEÏ$�T*$»ÚD7�lü-,-¬´í,ü++¿@$…­Š�¶‚~�²MŒÕ&6+„Èî<«-w¶qO5fî;<rrrþ;*í}×ó5@9)Nw»÷¶…´£Ã°˜D°QÌZ@‹bs\ï)ÎZ€ÞKpr8ÊŽç?Ø­p½ßLVªËÀ¼‚êDÅqQÿÚ¤+í'üƒëùò+î†íà$S àz~2N¬„ÏÁ]ªK—“‰qâ6m�­3ð tMßÛ ¨hXj5 �Žk™ ÌÖ [À°¾>¾¥í0þ„Ž×ØVÈ) µÈz¿Óº2é1ÚÀÜBcU!MDöL‡ 8õ¥E­ä( …�Ö±ép¥DŸS‚:뵃}›á¥´‚R�rü¹h[�œœœœË×`ƵÄ|IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_closed@2x.png000066400000000000000000000015061526321767600271330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+øIDATxœí™ÏKaÇ¿ï¼ë®né¦Ñ®SêìR„³— #óR�¼dDD§¡K@P‡ºEÐ=(!AQ A�¢ �Ðݲ•tsT,Ã-ºî¼]:쎣‹àûŽÐó9~Øï÷}æÝ}Ÿw ‚ ‚ ‚ âƒÉ6Ð sÀÀµ+Õ/Ûs;Hm@kkkí*¯/”kΙëë�Lßí Éüð•p8àÖ´wÑ„Ù.Ów;¨ø /½Xk˜Ïd–dûWCêÛ:ºa@ÍzpQ…5x^Ze…ˆWE7Ì’|ÿ­Qò~e³‹¥„WM7’TdØ e[0o}Ëj‚�ÛX]�ä}U9Üp•fK ³¹†¦ØO=®Ò©úÆXvya.¥2 àðB7Ì~Wݺp´Î™ÜÈg•Y|iè†iØ0�CS™/ÓªrøÖ`ó�¯î çóŸ ^µ�Æ×sØÞ zé¥Ðò(z8þ"ÃÃEð௒n˜ *"ø>‰ÙãÃó˜éQŠ4Ég²ý}oÌZ£iÆÐëÖÄeÙÞ»¢ Ö‘ñÃ×󢢚h[G ƒ¥�²½}ߺ~<Ì9^�¡ÍUºk[©.Ùþ>7àGxm‚�pÙVꎊ¾6@7Æ8ï’ߨ‡÷ßà9$í4þ�ÂíÉ›`âa…È0RäkÝ*ßùt기.ÿ<çÚÉüøÈ•Y”7 –HvjŽPW&/qGœÎçÒ£ªó(ý ˆ&ÌvͯQ¹øu戋~,PØ€––cMÜÁ €ŠÙŸ Ñ7�K¿U•Ã�’ÄãñP)Ä_8â*Ý›žH?V‘a3TL‚ÚŠ¨{ »BxjO¤n+ðßé; Ù0oá߃e¼ß£®CÑY¿RO�x<Zu¿Ô–Éc5EtMN¦”Ü÷«!ud#@±Lš%Þ³[È~-nÛN}c4†³›Ò´R¯=‘ú.Õ“ ‚ ‚ ‚ ¢ ›'ËÐwœIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_closed_disabled.png000066400000000000000000000006341526321767600304110ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+NIDATX…í’½JQFÏ¬Š•ˆE,,Ä^lL †¸XZØÙ‰v>� XÙøФ°5bg²²bbç ˆV"*ˆ?ÑÜÏF#Øí]ØÆ=ÝÀÌ7‡{rrrþ;–¤Y’Egm �Á‘0œ~L+$ìï ÛÀûC½^ïËTÀ̲¥Ÿztlü3S€¹JñH²íŸº·.3+ÅM ñ]NEñù®¯@¢#üK3n©Wˆµ¹Ji?SIAtÖîöÂ,¨VË3§I2¼¾àw¡9}¼ý ¹(iF*€B¡Ð®}çS H²û§ç0Üu­;‘©@3nm!–�'æË囤ÞGÅí¡ÀI¶VŠ'>9^/Ð8½˜ª[÷]î%Ј/&sÇ@?ÒN8[Üó]žX@’¸:ưà°:[ÚH³ ?é€I· ¸¢ó¶jf.­@NNNÎjõq¯†ô«“IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_closed_disabled@2x.png000066400000000000000000000015031526321767600307570ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+õIDATxœí™MhQ…Ï�Œý ÒB¡uQ,ˆ+wc3�LÒ¤ ‚›êJÄ… ‚ ˆw‚.t'‚{A»�"A\ ‚Ú$dšLK7Š í¢ZlK3�ëB*Étb,ô½)ø¾å¹�srçýÜL…B¡P( …B¡P(ÿ$Ú 8å�ƒq˜øB>=4&Ús;m@¡Pè =�«!y$g›‘¾ÛAüùz„6Y.Ï öýgÄo×ã(]‡ßeÛö²hÿVˆ^X˜ÿµ àC_bfáþ­¾Àó¼®5?¢j9Û”’¡Rž€išK¬£j%×sedh†´%˜·¬÷A  ë ¤K®wGVŽ0R÷àHvðƒ®„u®•ÜêY™Y6‰eÿÜê�Î…uM RYËš‘™%¶¨èzl™tøý¶mÏËÊë ÜlFhÓ‚¤eYá R±ÞÃ{;ô¶(}=ÐV˜YÊɵ†aÔ¸¦÷FÕJîô7bŸÄòyc‘)qxK�Ð]p½Ç¢ýcoäÓGÞ„“a�€Ó¢½wE€(˜‹ÃwW4à¥çí£@s¶˜*¢½coÀììlR¯á€¡Ò­\&•ík&&&?×üq ŒûÃéÔMbm@oÿþ» Œ6ªôœýÕËD9$í4±M‚¥²w• ÷Bòk~F曢XP,OŸñ“Æç�D`µ¬/2³HoÀd¹šÒˆ :ëäe-€�ÍšodçIÈ4+—g@4  »NöŒg̪Ì,›H;+•JÏÀ ³?1.åló…¬a"ߨî4Žã´¯ÚS‡êu"ܶÍ224Cø `f-ÙÝó@&Tz”µR7Dû·Bø (MM_~ÿ7XGqeéëEYwýßz 8ŽÓžìêù ã�Èx—@-�Éd¤üÞo…Ð-Ð×רÕI ¬ó‰ÝòåÁ 0 £FàóÌ1iÇóCCEz* …B¡P( …B¡P´âª¹Òqšær;IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_closed_focus.png000066400000000000000000000006261526321767600277620ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+HIDATX…í“¡NÃP†¿SØ!ë&'è �€A"p8$l< L`x¶2�e‡&áÐ%0IJµ†[éÁl4Áõ6©¡Ÿ;ɽÿùrî¹�““óß‘D§UŹ"€Y¡X–&i¬D§ÏcáÂlúA_—²hK¤*»‹Ò™a¶ÀK˾CäâWÂõŸ3ðö©Âã¼Üp\ÿÊT ÙþÁq}�“´å5ªnÒ £ ,ð†v¼„*]§lf*@[¢ÂLVâ4}ÊV L��éõtªNÊ= ø¡õ]K±œ¦Ý ÎTؾ"±¶ßŽ*ïI3ŒA½ì«è �îxÍêƒIŽÑÔ;ã-íÍËcÓæ`ðkîh]‘ûùÝK¯Yé˜6‡¤PÁꫪrë í“4ÍÁd …*¯añó€¶¥ÈÉÉÉùa�e¨ÚŠ|IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_closed_focus@2x.png000066400000000000000000000015111526321767600303260ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ûIDATxœí™QHSQÆ¿ÿÝšsÕ”j›Ë‚”Ý‚ × Ì—‚^*‚"z¨pº*ˆÞ‚|¨··m™>„DD�Qö=>Ams¥±;…DC³m÷ô’±Ý]‚ç\¡ÿïñûþï~÷Ü�³;€a†a†a†a˜ÿ ’m 'Œa§þØ�Ët‡d{®©ìüä]Wð-”k¦0dcáQ™¾+A“ùá¾ùõî*CÒ^è¹V™¾+AÅ# ìtÍ¥ùS��9Ùþµ�º Ó¬Z`–ÌYô éþµ�à•ÄOwƒÝHoΗ¤û×@É¿¸yÖÔH·›EÆ+–CÙÌFƒãdŠƒV�€v=aÜT•ÊÒg0}¾é9 º`3ºI§UfYBú.`‡ž4† p¦*Œf¶¥£á7*³8Rèq# BÕy@siÍ©ÎÀ7U9+XþŒ°ðã—oâòö»Ùjãè>ìA��^¿Á3!”ÜG ‹Q�D1`7Ó“ùï*28~KÇš§MMì±5Dâùû²ý/²Ñ¦÷‚ÄQ«N$NÊö^€fºSŽø:aj¥%i„•F¬:¯e{;^@8>és <ÐR1 \Ow‡Úeû;[ÀáÚHîa{Ëe$3Ñ`ŸŠŽ ÏLÝÀ‘r�O·M{Ad{HZmœ; 'r—ºm‘ßj.­Cå›"G Ø™0Ž à¡Å‚J®}éž-“*³(/@�çÚ@4  ¾LžÓûS]¡wªó(ýÐr­ z‚Ê‹/‚p܉‹°ûÎ×M(Ò€Š³¿Å2]¡gªrXQR@¤?SW0=�@ØU9¡ãÝÁ»*2,‡üú„F^ÿ €Žr™îeºפû×@zúÖüUüýop zi.ÎFUíõÿBê.éÏÔ‘×?À[fùa±èiÿÒÛ¨ä÷~-¤®€†ºˆ  P&å]¥Òáµrñ€äÆbTá,€i¤:ô±'üY¦'Ã0 Ã0 Ã0 Ã0L-~Çd¯bIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_closed_pressed.png000066400000000000000000000006051526321767600303050ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+7IDATX…퓽JQFÏl¶±±°�µ ¨«¥�¥…��˜!…O šÂÆð‡ànkÄÎZ°MÒø’Tb¥M"HÜÏÆ„`·waïéæçpg.x<žÿŽeI–dI—€�ùêŠ}ä²$ŸN �xoµT*T a–bìŽãÁ"£Bª‘Ý ÎÆqÜÑs¡µu;F<þ†ËqG®™Žð/qGš4õʆ]gíáôcz“#”q•´µY¨@Ã,Î0;%ñT¨À|aô\ës H²Á'MDxû.Q.T érìC Ø>Xµ~Öοফ} �*`§¶f.}B—¢¤­-DSÆ¡ëppXAÒÖ’Œ{A(8¯Fvé:<³€$S@ ˜nûGy†ƒË Ä«‰ ¨4ÌÒ¼�Çó¦|`’R?IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_closed_pressed@2x.png000066400000000000000000000014441526321767600306610ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÖIDATxœí™MHTQ†Ÿïú3¦¥H‹6&D«Z¤£æÏ&‚ ME`„Á8(A´iä¢v„»0� BB¢@‚([„ÔÌ´(‚‹\T‹2E-Ç™¯•63^„ιBçY¾ÌûÞ÷ž;çÌp8‡Ãáp8‡Ãñ¿!¦ âIQ8 €�6IÜ´çf0Z@l\+ØÎR®æ G"�2nÒw3x&?|±–ÒB-«<Jh½IßÍ`üˆ%Uýôì/ª{ÚeÞ´1Œ®€ªOëW€b®_Õ¸1Œèì”LY†¿Y]ŠŒiÿbX¹çZd.ã±ÏoKê 6ÂÚìm�¢õµÅSzÝVŽB¬>ƒÝMòTáB¡®Ê¥xB»lfYÅø.àG,¡q„H¡îAs$, ›Y) –Ô�Àºó@¶„==‡ä«­�ŸªÒTv¶Ê’ßì_è>¼,”ûé e,ªª•›h}�’^jýfñßmdü$Ö×(38à3ª‰%õžiÿÀ è Ë;…“>£3¦½·D"Lá»% |©»QÆ|F¦½/àVJ+KKxìÍ(W£ai3íh££ZR®ŒMya°;L¿� �°PÏ àD�üxzžó"â{Hú×wNèE„›y¢ð&û“›oŠ)àÎ+=•õ¸Ÿë/ðYÒ´DZå‹Í,Ö Ni³(ãÀ¶yÞóh�4È[Ûy¬~ %´^”Gä\¼À p:ˆ‹‹ÜžÐ]ž0ùg…¾hXžØÊQˆ•¦4TRÊ`®.ʵhX†mdØãô«zÕ³Ä:ru�»‘0WLûÃxu¯¹¼ößàžÏí¤×Ö^ÿ7ŒîSÚ1Ë,P±ª)¼…hë:(V~ïÃè ý ¤×囬p|«\<. ¯QÒ(Ý3À$p,zX¦Mz:‡Ãáp8‡Ãápã7/œ¾l1`IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_end.png000066400000000000000000000002241526321767600260520ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+FIDATX…íα A‚˜"uê¬3±`ÂHiþz[?†À#�Gåc*ã €  =`©Uµ=²-àš™xš=ëšqqO4IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_end@2x.png000066400000000000000000000003161526321767600264260ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+€IDATxœíÙÁ € A° Μí¿›Â2ÖÄ™þˆc„Ö¾ÏÚ÷)7\åñ/ P P P P P P P P P P P P P Pû}€Y¯¿ÆÇ¨_À†2¾� €Ú^õÀÝ¿Èê x¶­ß¶rúÜ 2Ú U…IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_end_disabled@2x.png000066400000000000000000000003151526321767600302540ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÙ± €0Á‡þ‹r@€hÊ”±HÌ4ð§•3Ï„ÖuïuÝ»Üp–Ç¿@€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@M€z@í÷Žòxý5>S¿€=Ozþáñ© êŒ)%uIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_end_focus.png000066400000000000000000000002301526321767600272460ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+JIDATX…íÎA ! DÑÒ ¥6µ�«šDÌ&½üwŸÉ7DÖŠ¬¥|¸2þ@´Lõàû"«'à˜o¿G¹ý$˜ Mòo;¯IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_end_focus@2x.png000066400000000000000000000003141526321767600276230ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+~IDATxœíÙA À AZ/˜FR�T•±M˜1ð_6Ü#4×»çzw¹á.�ÿ�õ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€šõ€Úñ®òxý5>Fÿžø>œàÎÑÿ.ÚOhIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_end_pressed.png000066400000000000000000000002231526321767600275760ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+EIDATX…íÎA Qpì-Mè` BaaFûî|V¤À#Í#­²1*Ç € àyÀlØXù& U¶Þÿ8A­ ‘uËwIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_end_pressed@2x.png000066400000000000000000000003121526321767600301470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+|IDATxœíÙQ €0ÁÿêDKÒ÷²é_gBëÝ{½{—îòøP¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨ P¨à*�×_ã3ý xâûp‚‘w BdâæsIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_line.png000066400000000000000000000002061526321767600262330ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íα01.cPS3#£g(õ½}ŠX”Õ“Õ³ùx›ñEH©Ó+/˜IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_line@2x.png000066400000000000000000000003601526321767600266060ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¢IDATxœíÐ1 Ä@‚ ffüËÇÐ3ðÍ�­}îÚçʆ)ÇÐ:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZèícIO7�}LIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_line_disabled.png000066400000000000000000000002061526321767600300620ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íα01.“³ke(õ½}ŠXT=Y=¹ùx›ñEtöÑGTIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_line_disabled@2x.png000066400000000000000000000003601526321767600304350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¢IDATxœíÐ1 Ä@‚Q ¸ÇÐ3ðÍ�­}îÚçʆ)ÇÐ:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZèíêHŠOIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_line_focus.png000066400000000000000000000002071526321767600274330ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÎ10A&bЉ $â"" Üëÿg#eOeOm>Þf|Àz”�ä¢?IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_line_focus@2x.png000066400000000000000000000003571526321767600300130ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¡IDATxœíÐA Ã0/˜Æ!*@Fx4ÖÛÐÚç®}®l˜rü ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€ÐKºÍ¼ê® IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_line_pressed.png000066400000000000000000000002061526321767600277600ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íÎ10A&Êq‚ DPîõÿ³‹ª'«'7o3¾àl‚†I#…IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_line_pressed@2x.png000066400000000000000000000003571526321767600303410ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¡IDATxœíÐA Ä@‚BÔ!cxt l³kAçΜ;#¶ÿAè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´ÐZè­t€Ö:@ë u€Ð:@h ´q¢Oz2T‡IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_more.png000066400000000000000000000002471526321767600262530ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+YIDATX…c` H©è5H©è5Pb%š©F0ê€QŒ:`Ô£p°PjÀ†ÿ”TÉC?<»s©�\ý£uÀ¨F0ê€Q ¸£g è¥ñ\IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_more@2x.png000066400000000000000000000004071526321767600266230ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¹IDATxœíÙ± ƒ`Åà#b jjö$ujÆ€1¾H¿½ÀYÖënrœ×sœ×#>òø?P- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhÍò6y\¿ÆgZÀìZ`fæþ}Ù—_@´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4ËxÇÉP+ igIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_more_disabled.png000066400000000000000000000002401526321767600300730ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+RIDATX…íÕ± DQ—²t³l¦�"k¹ƒ ä_áqMJqd«ÉVÏ�ê)GH´€Óó’¿Xà¬Ñ嵜¾�¸  ÕëÁ9êIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_more_disabled@2x.png000066400000000000000000000004051526321767600304500ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+·IDATxœíÙ± ƒ`Åà ÊP)(�‚‚­ÈÒo/p–õº›�œ×ýœ×ýH‡MКhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð,à#�ë×øL ˜¯˜™9ö[âò (€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€fù=š ¨P„¿IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_more_focus.png000066400000000000000000000002501526321767600274440ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ZIDATX…c` ¨Í|Ù 6óe%f0Q¢™`Ô£uÀ¨F0ê€w ¥ügøï@I•<ôC€‘�ñÀ­tñrõxŒ:`Ô£uÀ¨F0àè “ ‹pøIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_more_focus@2x.png000066400000000000000000000004071526321767600300220ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¹IDATxœíÙQ ƒPÑ-ÁC` QXC*¨ŒÓäÍØÉäþí 丞÷¸žW:lòø?P- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhÍò>ò¸~�Ï´€ÙµÀÌÌ}~Ù—_@´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4Ëø:Ý Îu�ñIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_more_pressed.png000066400000000000000000000002421526321767600277730ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+TIDATX…c` Ì?ý¿aþéÿ ”˜ÁD‰fj€QŒ:`Ô£uÀ¨Ü,T0Ã�’*yX„À�DSÆr5xŒ:`Ô£uÀ¨F0à+l «­þIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_more_pressed@2x.png000066400000000000000000000004031526321767600303440ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+µIDATxœíÙA Ã@ÅÐIJTd´ 60^¥µ ŒeýÛÌ@žµ÷³ö–yü(€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€æø—<®_ã3-`n-03óû^l‰Ç/ Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4Кã¼ê^ P\û•IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_open.png000066400000000000000000000006701526321767600262520ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+jIDATX…íÒ1K[QÆñÿ{/ˆ´©¨�Þ›‚bn„.ñÐM\2‰ÖA(ÝâÚN~ !_Bœ2thGEÚAH)tÕ¤“&ª½h ¡&‚CrßÍ B<‰.BÏo<<<¼s8щœžhe1ÞKs¹Ÿ§6Ö¸1*$n¬µ'šß€á7ƒ9TÌ_<óoòœ¡Ñ=b¼³Àß(okìzþ§_VÀ# Z-Ývúz>Z¥#¤ÿQy¹«×)Õ*ó?¬'+žyÎÂ|Ä�‹á;cEž/ä~¼VïÐP.—ëµÊÂDw¯Exºa$"ìï‰mßr«²0É}>“Njä°�ùØìMp;z xåüR˜�C]ÀL­2?Ù‹€}4½heoO,>Ü÷ÐæÓ‹‹‹k¾ëÄL¿-Âø_{™ñBnøh­öeØŸÖðÞ÷â¤Òcbøa‹ïg§¬Ž•×/]º àºntqÙ~ÏÀ_„ÁÈ›…üÌx«:¶týC£�c¼3Ís¹.Œ­z�76ÉÊ)àߥwÀ¼RÈ]œhe¿–/ 1èî@ì³Àžõ]anxb½8?;ómK‹Æ?Áu(ä³Wî˜è^“ÿ|¶¹lã=ÙŽ›‡6- ’Ÿ^ŠuÖ÷ïßç´o°;Ÿº–Ëζ«W+¾«T*Õk•…Ïzú€LÓÐpÊ^é:8÷ë÷ÕvvjëîºUžÿª;¶}dðŒp¼˜»p¬Z½èýÿO&I&“›þëJ)¥”RJ)¥”RJ)¥Ôâwöômá…IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_open_disabled.png000066400000000000000000000006311526321767600300760ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+KIDATX…í‘¡Ka‡Ÿ÷¦ˆ2d hÕ¾ œ²á1‡K¢®Yg1L° 6 Š`l¢eÁ`Äàív;·³ f‹�¬©Ûk™`™·]üžøòãù~?>0 ÃG¢n½q.ˆ­’(-; ÏýHÝFcÆjKEá-ïdÖED{e­(™…¤€9Ñvàa!*ï7miKSÁ˜ˆöG0luJ(×À¸ªÞz~¸Ùóñ \³„0 ¸��‘•ßÖC_ ªV-Ov»§ƒ¼“9ü)wëá¶ gÝQ•ÉTr+�N¿G¹û*ð�ç7wT8,”ËäèPÙ¶ívõáñXT÷D8ZZÌìG-�U ê7Šˆ\c€´€UàS”r>—½Ä7p·Î zLuO-6òNönPW¬žÎjB_€×ŽJ±�Ë<ÅuÅFUEUc�0 ßà ÖÊk%§!ôIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_open_disabled@2x.png000066400000000000000000000014751526321767600304570ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ïIDATxœíÖOH“qðïónóЍƒF§ ½Ã鿦 $Jº„iAD:D„+ð"ôçT‡ #R»Ø»ïÜBê²SB!ˆ\be¦n{ŸSÚ^ÌÌ÷Ý‚|>·½Ïû~ÏïyÙo„B!„B!„B±U�Ù€p8¾_WðÀn€î4{ëo[ÐÛš‚‘Ä1úsŸôó-M�cfòL �‡øóíÜæ`ÁWB¡Ä^¶ñ€}†ÒGEçÃ~ã›Íä†Ã“Õº-󌃆Ҭ®óÑV£¶©†óX2ˆÅb;–ueùçAÎw�èx«×=ò7y¯¢¯kdGª1”ÞÛ˜Ú}>÷;S ¯°â x<žÙ…¯³‡@xl(U)ÌσÚDïF³BZ¢Ua]3nž€„¢/7Xµù•Lk1³Ò7\Y£Üßìu_&"ýwχ"‰n&~ÀaHvV8º\.ׂ•ýZ>€UÁHü,ƒl†%Ÿpz¡',æ_ef i‰k®³˜00óaúbgggÖê>‹6F'Úz  Ê°¨–vPG›Ûý’ÉdYjnþ.€S†&Æ…f_Ã@±z,ê ‹`]PmXy*‹l»^^žr,f†´]Ó‰Ÿ{¸˜ý}‰LÖd)3  vƒ�¤8hjˆ³/ÀÂ_�õø|®ét…ÝKÌã¼™0ÅŠÞXŠÍç–+¡d2Y63÷í�zÖ¼�)Æ[G àJ•ª§’È�öÁh¼�ˆú *³éÝ�çG)û)ùV£‰ûŸÀLt»ÅSu½ÿÿ%UUíªªVüë>„B!„B!„Bˆ-â'éù˜S®F IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_open_focus.png000066400000000000000000000006521526321767600274510ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+\IDATX…íÒ=(…QÇñïÿ¹ "¹�’"÷ŨØl&yÙ”‰R¸·l›I&“÷)ƒÁ¤”,ДŠLî%åí¾,tÕ-/ço1 xÜ»ÉùŒ§_¿~§sÀ²,ËúïÄ/Id—m7Ž��ÖŸþ¦´uá®é%ଠú�sûÑﲎ_™¢Õ@›cä0ꥻüò-^®ý5à t‚Ôúå}Ÿ†€M Ê¨ìD¼ÌðwÙðR®×Q³¸‚ì=—Wtÿtû_ ¸žl,$o‚ƒÀP®ÊZ(‘™FõÓó…™8b¶€JQÖ˪³Ý—#5÷~ý¾ࣈ—�PÕyÀAuµ 7v|Ëk¸!3 2õ^9“«›ö»yIBËé~1²T y�àE‘Xj<¸RL_Ñ¢‹¹ã˜m ø~”We sw‹í*i@ÔK7• T¯D¥ÿ,îž”ÚU:Uùú-˲¬?ç †þuhR÷ôIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_open_focus@2x.png000066400000000000000000000015051526321767600300210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+÷IDATxœíÖMˆwÇñï3IŠ èRHveÕº’ÝÅÕ‹žÔƒø† bK/ŠõbVÁT$ ZÁƒbvÄz¬b)míµÂ{Гˆn¶êÁu7‰]_W“8�WH¦ZíÎ$}>Çÿ3ÿg~ÿg˜IÀcŒ1ÆcŒ1ÆcŒ1 Ú yb¨Kù^DZŽäR‰ÃˆháÞ¤£'ÿ¥Â!A¾éO'.éxínþw”ÅU OG›Š©ëëæ–‚ö®¡*I·¸[Ðo«VMÖDüJ·”ÇÛÖ ¬¶‡Âו‡‰ßfž|и÷˜%�¶»…ã¾ÃC0ð^ œñ•&"ÞOÉl~Ûûöêt‡— N0ÃWúScÞ‚éxм¯…ò ÔȨ“lÍdï?jʡܽĈ÷¶ín~ƒ*½@ÌWºðD+뇺[Ÿ†7üŒiw‡Ó¨"µ7Ô³¥ØèÆ;›ÛžÕlP•¤[Ø/pà 1�æšâ»X'/ÂÎY·tôV)ú0±z]¡/Z*qcû´¿ºÎ^û¤ü0ž6ùZ(èŽ\ºåh½2ÖuÉÞÂ<ñô`ª¯”Se•Gì~DÊ瀾ú3�¯úÓÍ꙯œ‘è¯Àœ÷Ür_E×li¹\Ï\РÌÊŽL‰8åó(ËßqiÎsdõ_©Ä@#r…ö3ø.·º?}›R\�pêm×ü!ZYÔ¨Ã�ݳÁT¥£§�Q!㫜}RÚpwçôÑFÆiüÆ$Ý‚+ª›yõ¥ÿ.7ؼïßþ|�–d4:óäí ÿwcŒ1ÆcŒ1ÆcŒ1æ#ñ¨³ônö©¬IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_open_pressed.png000066400000000000000000000006171526321767600300000ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+AIDATX…íÒ1/CQÆñÿ{Õ D$Öú¤·‘°™t¦Ò†¤ÀÖIL&3½—t0˜$±HˆÐÞv�˜$fÒA„Þ×b@R§½›8¿ñäÍsž“ó‚eY–õ߉iÀ tH6!»’’ÛvB½+M£ <ç\fED[Í:mä £]pYªë”iدk’×À$0hš7è}#+pôKȉèbËËk:£!çÀ°Â1Ò¿½¾­óòrï² ÂЭ°çWµ¨ªß¾Ï«éª*G@\ Ü×C:?&O¦|ã|度° 8Þ«PxLÒLl"¬ˆ²±”¢hzy¤^U3@å¡L ¼+ò))u’×q€ÝŠºŽpŒ0ôyÔa.çÊi§Y‘ ìWt¤ép<„!™åq¹‰š™ªÊÏe´,˲þœÿObÅXÓúÕIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/branch_open_pressed@2x.png000066400000000000000000000014121526321767600303440ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¼IDATxœíÖKHTqÇñï¹ÙsZ¸ Š rT›jlr‚Àˆ ¢¢�‹(GC²-"ˆ bZ=ÀEBzÇ�EôÚ„ꌶi•aÑ*„èeó:mn7³òÞ™ Ïgù?ÿ{îïî½Ì€1ÆcŒ1ÆcŒ1Æc¦ Ú ½WWˆC'ÂbàBC”s"¢!d›PªOwÎ8p8Q-÷ƒô <€Ž´>6z–®FæÒT·J²A{{©ª¸C9ãY~Ÿ4G%7Õ¾NÐ`òs�}¿ð ã©Ví=.Ù­n†6ßá¿ß>˜ÀÈÃ!”·Þ5�Z ô\Ô¥Aû_|¦ó—ÍçpÐWúв7ÈÓ‡&ÐÙ§U‡ûÀr_é� Û÷Gep*}¯ftQ^¹¬ñ•Fv6TKÏTúz~êcò²�#<ö•ŠòØÍèö¿íéöëʼÒËχvŠÔ„qxiMqýPÉ�k¾RD•Ûí=ô§½Út“ =À_©Og°>“ç�Ê'à•Tuª8­Ê‰ Êg_E9Þ"RüÕõnZë®3½ë*ÜÌÁÞæ¨|3oèçöëÚ€Þuºä‰ÆZûa]URiN©Ð2AÊÖÈ0Gëê¤vÎ’ •Ö­E¸D|¥§È®DLÞt=ÓYŸÆ¸„ÒàÛ§(G×Ik©2–t©´®.Â]`‘ïÎC[¿ÂÈlå†ÂfߥcN‘=‰˜Ü,e¾’ •Ñ%Eå°òOö Œ¨ÃŽÆµÒ[âháý L&•×Yaðð·›…¡¼CM9e@sTÞGæ² %5ɶ'Yˆ7­•åÊU–OÀKUÅÍ�’¾ 7æå¨¯‹Ë—ræ)ûƹýzY…FUåü«jNNöÿà¿”ìÖŠŽn�ó¯scŒ1ÆcŒ1ÆcŒ1ÓÄ7‘ŸßYy·ØÇIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_checked.png000066400000000000000000000013171526321767600272270ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+�IDATX…å—ÍkAÆŸw6–B$¥)1›´—|@‚¦ëQA‘ê5ëQAZ´'OZÿ€žZð `Ñ‚žëµð¢A©×ÐJ¦)ÍWµH-ÛÌë!»šïÍ&Ûô9 ï¼3Ï�gvøßEõèÔ9Ét—ˆÎðØäSbæA<û%½ö¦%€ŠÝ&Ð\30›$<�O¯ÞkðOŸÉ×¾ƒø–²'Ùìûov¸ŽŒœt—ûEL¸òB}Pƒ±%_h”}áØU;L›I i×|¡QVƒ±%£&Œ�~æPödâ°”c¿º×™èή؛éóúúW}x¨9ì6ñc—¢(3ß(l¬>o×o+€7¢Ä>/2àÄßn�h7iQBðSPżãEv¹«am ÀXuM2Í €7¢Hò\m•–óÉÇGÐ=cW:0@š-6½„f·Z kS`«®1èN!•ÌtDoÖ -0àcÀ'@‹Þˆø×CôÔî §8À}]OÑ2=É4CÄó+|Q j7!@½DoÈ4�Jœ´\]#âyb~XÛi-úŽHéÀ»-;ºˆÞ ©d†M·ö·½%ÈH>ª?ŠŠº‹Þ2šEÑw€B*™Ñ8€M› ï6zC–?ǹtò€€ic‡ªN T�vm^¯áhtH˜yÊý"~Xåý¾¸îõΨ)ÆÀåö|è:@—Ž»ÕÜ€w0»³µõÓãáhtÈ9à¿BàûúñäÎvéÐüÇdö¾”ªÕðc¢TÏþØ.¾u¹=/™á!¢AÀÚóª�ŠÌüJOæÒkÏlÚóÑo^]þJPÖU÷IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_checked@2x.png000066400000000000000000000024611526321767600276020ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ãIDATxœí›MoU†ß33©RBÚ$6‘ØUD°ÒH鮲T`S袂šT•øl`‰4DB¨eÅ/ ‚T5lªt,¬6°@©‘1 ²•*8¸6©»hÚ*‘g‹xÒñÌØ3î|†ø‘¼˜{ÏÌ=÷è=÷úèСÃA†lY¥ÓRl}ó �eà€<ë©gí³ `ƒ€ef¾Z軎L¦fõ’e^L½Á} à7¼ô‘)üá?kÙ[‰-ê(–�á €~W]ó‡~MuõFv¶ª•Ÿ›5 @,9: æÏ¼ñÍOèTWod{«ZY2­5+¬Ëþ]ñ}fd‰n”W‡×�k²ë¾:bBŒ¯ˆ5>ÍÀ€#ÚZRøM³t0 �–bß[AcÎÿ$+4vÌêý ¤¯â82¤™¦ku’¿E:Ý\eJ_Å…1@Ý¢šr"VÜü¨Ye�ÒWñ~dš�&FSúâ ¥¯â†,  à¯R!ÒWq&å€ ³†TƒôUàn>—ѧ–†õT‹ôU\Jñ£—ܶ0;$0¾ˆçà }wÁL¦¦€.À*ˆÇÀ8nñ5_¤¯âÚ,P.¬dm¥‚>I_ÅÕiÐf*´Â7髸»°› æø*}×BO� >K_Å“•àS¤‚ïÒWñf)Ü^*"}Ïö¶S! é«xº²‘ �I_ÅÛÝ`&S!¿Àì�źùý ¤¯âùv¸XÈ墓D´à1€ÇD´(�´û—™—ør>`#¿Rð¶mµK8þ³l7>N´:Or ¾oë-̰¡}ˆ¯¸é’Ÿè}' ¨·1”–µÏb�O»ïš?ˆ5å-]‘aJ6”d¾Úð ÌESQ—}óœÈ`*Êh\ˆéû˜ 4ÐwÀŸš¢#¢@óû)šÃÒÚã¹zß0pwî(Ý=‘¿@4¥)ˆ>è>yt8òü¿ï½öȱû®;aBŒK/?×Ó?ED ^ÕÖ’Âçüö«aÝÑôÊÌÿçÂâéR>û¹YUÓ)n«Z^êê�ltÊ;Ï<‡Á˜.²—š´œã·ª•¥îžÈ/ Çþ»7”#…'KkÙ¯[µ}mÀxýÔuè®ÍÕçùÛí\›ëСÃÁæ?0 òr.Ê™ÑIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_checked_disabled.png000066400000000000000000000012321526321767600310520ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+LIDATX…í—±nÓP†¿ã´Y*1P�T¶<…Chê±µbêT‚N�hx€N©Ä@%*@ u鉡"rBîS´s+�º¤Ê= ±ƒë&qœ¸,ðMWÇçÞóû?Wö½ð¯#ñÀדï�Çy AïeTæèXkk�W~) Ñê¼Ø&,#¬(U¯\|uC@£ÙYáø…²�ÏÙz©Tú™EÕv»}·ÛsÖö�;ÖêJèÄÜ@‰HTP¶WËÅÃ, ‡/rè7�¨è§ ÅOœH^ Ÿ³õ,‹G¹Ê¬­n‹èo¸¬lÆ×ý ¹¹SÓhšu} *Ï*e÷ó¸üLø¾)¨è°y0nŽ3îaTÕÑœ~ ‹OJfü–ÙV¯EwÿŠß7„½X¸á•Šïn]Àë/¥'›"b“æ'n¤]í·ÌrÃúÏ+žNò‰Å—€%=ò}SŸÁú‰ÄXМ~PUgVëC’¿¢»¨D"¿ÝyŽ™Åú�D;ׂ*ob©©¬ŸX€ˆXéÉ&p9&-µõ ð<÷¥:2AtÇóÜTÖ§à-»o‰·¢ÏTÖ§0¢S[ŸZô[¡j7€3àLÕnLk}Hêßq¥\ú'$â€\@ÿ™ÕâqŽ�Y †çCÐèöœµÛ0ß%X[L´ÀZ[sYGØ÷›F®òÔ#g¸™86fq¾ËšŠ¾î—²µðÙ°‹I� *1F_LBþ\ÍÔ%rz�‘s3ìjöŸß ãðöMY0ºIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_checked_disabled@2x.png000066400000000000000000000023661526321767600314350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¨IDATxœí›OoÜDÆŸ±½mÚ[O«ªU{ =PU*RC±â¨­KÊ¥%PÑVý\@$IˆT åŸ$"P—r‰ÒKšl›]¹4½ —rh”–½5iwí—Ãf„×kÇv<þ²?i¿»óúÙç�­ G�»%ˆs®)¥¾‚ò@;ÐÞ´“‹{Ѐ-38·œæÆ¬iš­Ðo…,.Y@ø /ËI43V|pnHÿy« %è±Å¥ûãæwàÅÀqó‹KÖþÑ�Tk¿Žt=•Ô²å³jíþÇA'}•Y\².˜÷4?%° ÅÆ�Fãñêèè¨-3ˤT*µ\>zÄQq‘�¦ð„¼áW]pÎ5¦íûÍcû…–†ËúÞ�œw*,XVYkaÀ°«y…šë'½cW (¥¾ÏÅÿSböû;åâ`X×- — +¯=8ÐTÚýRιÆÈþ@i«8ý˜´¯B ÁúðBuØÍ¤}N€ÖŸ:sF_IÚ_¡ˆj}ËÔ\ÿRFŸ… ªõ(×¢¼ðŒBaˆcýóC§ÿ�Õo!ÈÃú)Ï¿Ôj/©¤N@LL~"æL›ƒƒ�¢|¿m}Šdýó’¬/Hì^¯÷«¤Þpb®N¸Âånµj ý~NÖ$€‘2�€¹:©øžsè²<­/H>ü÷ˆêÇ+íû0èd£¾—,Á©¶Í;ÉÛúÜ9¿‡‘ý�»Š`}Ab_xÖQ E°¾ ±íù8û4Bè¯=8Që ¤ŒÔ|vÀÃ�°=ŒìïÙ3(€õR0M³EL½†ðRxÀÉ�˜L¬/�v0�W�X adb}�ÔÛ`ÄR؊̬/�*@ŒRð#Së ¤O„”B¦Ö¤2ÜF)dn}A*Ä,…\¬/HíY F)äb}AªCJ!7ë RÀ4Í)λù,² URœ÷ò²¾ õÇaspðiÌ£9ëÖÁhŽ4fD}e–&™¬0u} À›Yô—B¼Î¿ERÏÝG•JEÍ*ÙtçÞym€ÿ"©'î£rùè¹ie‡OîkÞ?,»�¥f•!¤9—8Í�Yþt5ÐZ˜ÙI"¸K»WŒ¯8Í�Yol¬åò`4ÉZÊ\‘—Ë“æ\Úüç··\^ÐÞ-ò¿Ø0ãç†ô~'çg�Ó7Œ§–R6ÆÎ¯}mÓðÚ{pv‘6MmcÛN8\ÌmsXð0ζ¹=zìnþã4ê”ZÂ×ÛIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_checked_focus.png000066400000000000000000000012701526321767600304240ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+jIDATX…í—ÏJQ‡¿sÕ¸º¨­m5Ò°ÐRZè.Ò•o FÅUÕ¥ˆ«º¨X©‰Š �î„BA_ 4mŠB­$‘ºpaÄ{º˜L:jþM2®ÚfÎ=wÎo~g˜¹þuäb ºž¿gÏdÑ»@O@uŽPÙ1mšÈLô~¬*`0™<¯$, ¬(s_¦z_\0´V¸¯¢€ß 3!SLš¸ý+ˆªwÖ¿_/ÚPL`¸f \'ÚÝ$…9@f²ñÞÍ »”ds(•UÞÚ3™ž˜r–ÓsB¦˜²¸srš.Õ)Ç<ã=µWÂç§·~–NÃn¬½JnÓ &s£ IçJã_ã}ïjå* šÊE¬ÊÐåD$ ôךcj úbA�U³ñ·xcæÀÀÍÂ4ðÐSe©Þ¼@ˆ¦rq>`eÙΆ׮^@eë�Eì8‹bëM¯Û‚zouëg3ñ¾½úêr@’À ç�­h*qGZ±ÞÅïKØ¥jÞ° �¬m€6e}ÃTYaµ|�>è/L!-XïR·ÙÃðš ÛÞ˜«¯ÎÅ|Zß°ÅŠØqà¸F–oëd&ûöJ¿ëЍ2›™ôg½/Ùá×[Í[ï[@•V4m½8­°VÆ€}`ßZkÖzß?£oÓá÷@¤nbƒx8gÔÍ/2¼rÐ]:-\ ²P´¡ØU °�±R­]7Vn�iÓ„µŒ ,¥òbNNÓž5\K ¯tÛÎŽ˜*/kÚ4áŽUÚ˜$r¥tžêÏÖlÏêµE ¨ìVÚšýç²§ôût8IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_checked_focus@2x.png000066400000000000000000000023761526321767600310060ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+°IDATxœí›OlEÆ¿76EꥪP½umUJ�¸"ªT$rëÅàÒÒ ˆ‚h«âRn\¨H$â$Ên[‰ÔR.Uz ªöš^5ØŠÙQÖ‘Zõ„R%ó8¸Syÿe×Ý¿!þI9ìÎ[Ï›/ßÛ�µg€ìfÈKP©Âév¾sš˜Ï0Ó9/†œ[¿l€Ñ&âE&ºžkenÝ™¡M·‹\©ê¯ƒé€_&ÏȨƒðÑ?eí·í‚„c 3«k“`,ìÀÁÀ( Åï:`vüG; P¬éÌôY8¹Eƒ?/V×?qj·U¦k{,ùXL‘�·ìÓVðm�¬/npêècý0Kq$g´ßÐNxî,”*œnçÖÿ0Ùþ÷MÂÙ岦Ÿyð Uu-͘ðZÏéz®�9n¾1ZJ �ïœ6 þ¡Üâ÷wÊà`¹¬é›„³~Ôsz´;6#ˆùŒñ˜*ÍvBÈ3T–˚ΕÞsæ±60Ó˜á"!oŸ^4’ó½Ç zÕc¹ª;Éyƃ}ÚJà™E„MîysŒÝcÐ8ÃKÚݾ¬¹[f¯Î¡]B:î¼P¨u†S’§x ¸ Ælã­é÷³ï€#×:#Bò]ÎØ `/ç‰p¯Pë ûýüD Pªp:%äϲ6ÍY’ü©ß>-Àj^¿ ›G—‚€·ýö‘X µµcÌ4v?‰ Tá´�øÀ Û~ñÛW"p³þSžð–¼ê·¯Ä àÕúšn\ÊÖýö—(¼ZŸ‰µ|DŸ‰À«õÁ|ÁËž^HŒ}Yÿbö¯ úM„qX_È»Àð·z„)51!à×-A³ÍñLÃËõ«yý28Zë+|; Pë áçñt®ÎÀ9!ùî‘k�÷ë㱾·)ÉSp˜«‹”ü©TaG—Åi}…oÔ+ªÄ4¶š[ÿØ©=Ž»¾™Ðo‚ ž.ÔÖŽ™ÏÇm}E¸é²‡ß÷–B¬¯ðï)¿ðd»s)$Áú ß4.eëD<ã§J!)ÖWr8ÔÒ®|ß%l��ô£�4‡X_ˆwfhS \€K)xÀq—˜H¬¯ì)Ð?ø§—Rp#*ë+} z,G¢´¾"Pú(;"µ¾"ð‰Ðó–BÔÖW„2ì·â°¾"ú,…X¬¯í]Àk)Äe}E¨/Cn¥§õ¡ Ð-ñ.»E+L⽸¬¯ýu¸9ži0¥O4àßîÍ3¥OxýÊ,L"YÐ(¿Ôðf}õK"¾Ž;6 G78M*!`Í}Ãb€Ñî=<úX?lVÑa“{Ëc](I¼Ø{ÌRœ 8¯È�,Nõ“Í#ÙºP’èºáÉÙ¡ª®ž]È Uu� 1ËØ`#@®•¹ÐßÏ.íO3æv’j±´iÅx½;6#}-—gˆŠ 9Ÿäåò’Å)‚œyîåòŠbumòÿ°a4¹t1sÅ®Íq°4®]!ÐdxiE3ÓÄRùÀN7Mák£�¦>ž6Mõ¿m®ûƒFIÜ6´|¿Ÿms ØÝü×Òóy(�IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_checked_pressed.png000066400000000000000000000012151526321767600307510ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+?IDATX…í—MOQ†Ÿ3Ö‰ &¸‘þ†ZKÔMÜAX±F£¬X). aU’HÄHÓ– ?À&îHH0Œ¿�²…hâ‚ö�[ÆÒv>:u£ÏnΜ¹ç�÷Ìǹð¯#í�²§÷^ãÀHJuN�}�âl^öº (}Ó—"¼é$,%ŒK³·åí%›zßQv�ŸÀbãœÚ³»ò#�ªŸ¾êõ+W™Ö€k¬›ä(K¾ Å¹¼l¥QØâßÈVÙSQ¨ø-žpyã�sji"Æ_[)ØXPÀH@í@xR�ïM%ܰ±L×ì„”uR ÔáùÓœ|ª€ª«Ù†að…Üìu�Óëd–U�†CÉ�JjÆ<€‡Á˜ «E@ÕÕ,ÍØEqØ9α1p]¬?ËæWDLØõ¡aØS=æ±€\²þÕLAŽ¢Ü@¨~ñQ`T ÛUW³ö\?Ö[⾆C¿6—U4’[Y€ «¢¬Ûc�G·y!éÇzKh Žsl(ìc¢¬#¼ÿ£xLë# X1Ã^ÍÎI…´Hß!”gÀú?ÜEY­bÖhÂ7¦0C ¤ïJÆ{%o TIàM”Ž*6±Hß!´U`°[~ÅG*T#.é;„º úLO┾C¨¨!܈Uú¡BM…¸¥ïI%Xk*$!}‡HPc*$"}‡ÈÞü¦BRÒwˆôe¨Z*$)}‡H0Þ+yËä=pÝd±™7x?)é;Dþ:<Ø)�óçE™žÏD™Ï[œ÷ûÉ,Jbù,>Ô#[À;qÌU+©ø*œ$nØ-nÌΪ“/¡ãâûn¹�[ž7ž·r:L§âÄÅ÷­r›Ê�’ÂJq;op1d¿bÃ2¹TÜV©\’+7JÚÜ+i+“KÚ¾{Ñ2¹¤-Ø¥…Xù½�KÖw˜Søýÿ«8Ñ`2s˜‚àl–.Ù1.¬­ï0Wn[Óvy ²¦Å|š·Ë[&—°?ðvy‡Âi‘C`@•‘›çäŽÛ˜g0ÐÅUF¢s+aøF7Ÿyø:4…ðeá ÎáÁç¡©ƒ›ëä¿]×i<6·¥Âj-ÇæêÔ©s´ùWÄÔðÿ�PIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_indeterminate.png000066400000000000000000000010141526321767600304630ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¾IDATX…í—¿KqÆŸ÷®"°ŒõÌ–¼©³Æ‚¢¡Õ¹± p jŠêO¨ !ƒþ‡VÁ±† ¨5,¡,õìqAQxoC'D^ÙiQ>ÓË{/ïóá}ßá¾À½OtÉý#:Ó" ðØäSdæ�xå2}¼÷!€$+óZ5³I:ƒòéäZ€?88 ÒwÜ�xN|ÔÙìÉ�®ÝÝ}®R«S €“ �½Ÿ¤ ÷Ëaö÷*“v˜šI’¦ür˜¥ /ç„r`ì⣞¨€Øü”0¼†*`œ]c7ÓE*um„^3€Q ðãMŸH½3ļ  ý‹½5&ZÊŸmZYNÀÛ£øˆy£ sh'昷GñU PY¨™d�‰fhUôÖ˜hNÍ$ VEŸÞ€±CË=~G¿{ €@½ŠÀëd­Ì¡�ÛÕ f>€R«©@é¹%bx–sb9pºŠtƇA¸ ÕWi�¡DCM-æïù|îq¹¤²D:ãÃ`¾Pm�„4µ˜…ù|n³×+hßö÷…ð΃t7;Ý5Ü*ú®UŠ~#Ü5Ýn,ðQÎØàì%‹{=nz{ƒ‘7Ÿ§PúÌ?,Z<˜K%²~Ë®fG,lè&€ƒŽp2³­e�81Ä‹#sŸúài©…o¶†š‘2 �žüÊ S25d`Щtzò«L éGàÃìÔ(ˆ�€iËÖ[ ÂKù0;5*[Ì—÷{=–^“U 'AÕT£ P-@5ÚÕT£ P-@5ÚÕT£ P-@5Ú�X¡´Ù_i?ñ2Ç¥½ fxðÎÙwM·û)©‘ˆÚ x+æ¸7JÏ�mc��ú/­1 Ö1!ôBÌqo”d+içÍŽXØgmuÇ숅tÎÇx�iß4à•#´ÁÐÍ•d‚c³´sÇxÒ[ î .�¶šCæk 9¢ÛD'›7š?×™m|ÞÿH6âû_ôá®`t}¨uˆˆnØíì%‹�Ÿ|6#^UöWÖÿs`ñpf&qÑ««ì7ŸÏN4µ˜€ÔOYÝa0†3³‰Kå*®ñóùÜDsÈ|¢¬¼sCI²x0“Jܨ”Tõ±9=ö®ëewlÎ^ç_TslN£Ñ¬nþhwzFIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_indeterminate_disabled.png000066400000000000000000000007351526321767600323230ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+�IDATX…í—Á.Q†¿3è®�Ò«”Fº«x‰®¤<‚J,Tb/ž¡»FQêΣhC"Ý�ô^‹Î0aŒh§HÌ¿º¹srþïžs3¹þ»äýÆÅõÝŠã8{€»��MÐÆ˜ÚÆÚòí§­½+p–�ŒXªëuô ÕÖ«"\OX*™)ÓÈçó�I¸v:�9oà”êÀ¬1v-¨Äô+‰H¬`© ê< ã@þAίڮX±g~‹·œPœÈL™F’æa=gðsÛ\°^¸¤Ê¥R.÷à/#~G)@ ðëÓ_\¶õ6Â�ýfî>–ýbA�ÆÅV ©õÂÉæY„zS륑~B±%¥î±ìýr÷±TJJÝÇ}yüÆöqýí¤)ÀH†ÈI™5]wÞ_v#ÐÞÀ)O `ÆÃÏ-n°÷ú#2ÆÔG6êWmWž34Bo¸±ÔtÝù�²{<´2µà[Ô`RcrwãóÁ$ÐÛhfs„^¯cª âF�f©^fµ„Mz{3IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_indeterminate_disabled@2x.png000066400000000000000000000016651526321767600327000ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+gIDATxœí›?OÛ@ÆŸs5ZÁ”¡æ2”"Pq•H!R€ÄH‡"ñ P·†¢"µT�úç ±�Á�äD ªS�h;ÐC:ÄÒ $~;$HŽã”$çøHs¿í^¿¹<÷ؾ;%÷‰¤“aõ$麮*þÀ4AyÐ0Àît«Õâƒ]t °=sÝÌç6¢ÑháÚO]—�Lc |Ã}w„zÆ!€g£aíó¿’”Zˆˆ%Ó™E;m8xè°“L DTóF×4 µûu ×-‘æ-oR»™µ.::“Lcvlá3{©±•ÍÏÌÌÝTÉK<÷ƒ}½¦“ ´  Û–2îô:T ëºÊÔÛ?l�}¢ b6¦iY—u·„„aÕÖÄ,áCÊÿ°OŒU¯€âLÛÿÛÏŠOÛeðÓ´lAÅ,€3K¸_ñ¦í¹U”–:k›-…B¡_îËl-1M˂ђ5fà8 ÒpEB[n‹ó VP6m¡!{Žƒìžµ•Í»ªÊC´÷Øsœž€ŠÞM›í¡Z{õîµæ> S�ˆ i€h¢‘ˆ i€h¢‘ˆ i€h¢QÝè$µkŒá€¨ó¿ÀwÆð<Òì¿[6 ÷�Jg戰 `­<Êßñ�Û©tfŽ·3.tý ‹@ŸxE4 �>êúAO\0î1€;<}pr·¬¡i:~ä2€ò�/.\ÒÒ e MÃe@4:xÎÀæyúà��ÍG£ƒç<}p¿‘ðÈ*c˜ð ¥%ªÕ\-ƒ‘ðÈ*og®ìÊë1÷š,9 Š i€h¢‘ˆ i€h¢‘ˆ i€h¢‘T‡Ø¥µ�Ç}^‰q›jí•cœI�Z[Á`_¯»²¼ÃAû‰=Çé Ø³¶L&]Uå!¤šS¶Ð¾=§Ês½²MË Ãº¬­å$ #b¯¬1ûØÌ|n„Ÿ–P·ZÀZ;™`9,m=1~hæsö܆ŽËƒÑ+(›7ù¸<©æTùÎ7w\þŠRµÈQ0‹£amÅéBÍ}@$ôhÀbË$ya!y[+¡¾¢)à=J58íD]ESM”Ía@ÏÍ,›Ã €ýFÊæ$Igóé| ì6åÎIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_indeterminate_focus.png000066400000000000000000000007651526321767600316760ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+§IDATX…í—ÏJ#A‡¿êÄxÒƒâÎE‚ÅPPö²ìSødÍi1>‚ö`AãE|†¼€° /°¨ôÒ‘]Xr2b—‡Ì„ÁÄ‘M&*8¿SS]ôï›®f¨‚�.y˜<°sîA ˆÎ#1ùÜ¢rbRZ<_ð~= ðyßþ6Û�Å$'ÊÚŲ÷³ »W�WÑcàŸB>cê•ß cãp�>¸ª»LN  ×à&ÒA’ ùË%ï(ã@þ‡eËVT9tR¾˜fV£ædL½§yXæî¾â{Í4c¡ý‘mOtö}ô�¿üÔàM”$o�~)abß®lÿyvMaýrÉÛ�Jм�ñ²õ¶;0(�—­×1Àk(àjѳ «@­ƒ³k ù«EÏF%½øüFÖ±½ï$ ÀkÜB£�ì•ÙÔÎͰ¿¬¶¨œÔ]&×+×ß—ó½NƒXóGdRZtޝ¥lÙŠ¹»¯„z¸®4µs3ìúûrªlΤ´ìµLŠôîmaèÆ8€ÛyÝ át¨Éþat¼éšL§-ùßæ>ß;-ÉÀRT7öÝÞÈënÌæfÅa1wYÛÿõðrÆ�¾²Õ †Ïï³ç¸ÀLÍ–Iš9ã½¼ò ‘9�ßfÐMGŒcVö�sÈb•¾â¹²2ᢽÆã¶ ZOx'ík_ NíŽÓkáƒÐA [€l”²ÈF [€l”²ÈF [€l”²È&àÅ"WFŒV"¼pÇü_ƒ à+3ÿìÓ“GF�ðÉôa@üO¹ß¸A„ÙÈH¦Gt1!êF7ª™ø­¨ˆRaâ7u£Õ"kpnw÷€ "kr1§¡dÎüGPÈ€?••Ÿl{¤¥¶sJFÈ€åÞà&1õ‹¬!1õ/÷7EÖ~R}¡1f´ø‚ìå7Û`[ª/4&º˜'ç€Ü~,¼'Ë@}e ��2@¶Ù(d ��2@¶Ù(d ��2@¶Ù(\úv,­I®(�pjß±‡8 `¤ó› [F­·ªÊ‡‹öU{Œ³P’x.¿Í¦Öî±®²a²Ö‘ß&ð¼=ÆY(I4aé s¨>aèž«ó™ú„¡ÌÁü>Gnp1 ¼šèûá$P0À?M&KÛ*Ʋ¹Y)ª\ž¡Å52§Or¹¼ÉZÁ,¹\þ€Hb-ö?\˜ÅRBÃncÏ©ûú0�bþÉ* ÌL©è¥…Žyi ¯4z*ÍŽuiªøksÙ’óœÄksÀ*�狹6§P(Î6Ð~(MS‹%IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_indeterminate_pressed.png000066400000000000000000000007141526321767600322160ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+~IDATX…í—ÍJQ€¿3ÙÒ‰ù"™RÑ ½B ¹ rÖ#dÐ"ƒ6ö£ø ¾@PøÓ‹¨„KqN gl(Ig4h¾ååpÎ7÷\†sà¿#ßÊ-ÝQ8’@Ô£:] .PHÇåy¢ÀCSOE¸'æ¦ùô¦\ý¸Õ]Cy>€Ü Oíh[Þ½¨z÷¢ë+«¤€"°&°gßDÈ2”¼%”ËÄ¥êEaëCªå–ŠBÅjñ€áˆK úÔ¼,îDL+·’°ÏœQ‡­/&ämhÂÆ8�¥KM xlê1ÂþeîÊyfKnÝ‚\o T×ÂÍ ÅÂÅR]c3 ,W�lRÚ('@o†Ü=”\6)m· ©oÀê¡kçáo· -Ð…áéW±JC#(�qukzõ5¬ÜBÃ>ýˆ û@±ÜR“Úh†›“JC#j�R¸L�‚£îÖbRÀ¿·1y1±­fJÂ9½Î…ÒAhŒ[Í>Dr ´PéIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_indeterminate_pressed@2x.png000066400000000000000000000016571526321767600325770ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+aIDATxœí›=LSQÇçµ~$¨Ñ‰¬:ˆÆjp4$Œ8hHX�›Â`‰bœüI($.2@G‰Ôø1à FÔhH$Ò ¾¾¾ ô¾×KÃým÷¾ónÿ÷ßÞ�¤ç€ÃáØÉÈf‚Ò/4Ù\G‡z\%4{â•¶eV€Ï*d%ÏÓ…e&ÎÊêF/mh@fNÛ ‰DfµæQntŸ’gÿ óÊ=PUÉÌi?0Ss“PŽ3#¯´OUË~Ñe ÍÒ܉C[5ánfŽ[eŸ‡ufæ´ ˜)êT¾©p;™gjï";;%­T3ÆÇ5ñ«‰ÆU�‹¢ " „œ[%¤_h²iïý?{�ç¿s\ém•¥´GÎð¬ÖïJðDáÜz§0¿ð“–àÆX²šëè¬ù¯Þn.×Êäz[eéwŽ+(ßÖ;•£ÍutcK P�KEmH_m‘/±(�‘ÞVYÂ#íï Î B (œóë$óLE/¯:$rLúÛ¢œ Æ„� þÆÞE>F¬«j„h?Œ 3 è†·Ývû­¢½äöZö°SpØ`g€m¶qØ`g€m¶qØ`g€m¶IF1ÈhVÏ+ÜG9Æ&ÿk0@�w"ÜìJÉ̆Ñ`ü Éê5U¦QZˆò>ã¸*Ó#Y½f:˜‘™7zP”Ǧ"*E”G™7zÐd #¼UÎûMÆ0ä@ACÅìøMÐÈ€|’—À�ˆ´TÂ�‚†Š12 û„|WáºÉ&¨p½û„|7Ãx ô¤dL„ À[þQq£ïD¸Ð“’1ÓÁ"¹Îcã3Ùn´-À6ÎÛlã °-À6ÎÛlã °-À6ÎÛlã é[ñ7ÆÇ5Q%-‘¢}%fÀgãW�QŠª&!Ú?cJ%…¬¿½êq1b]U#— ÝßVáu0¦4Q2ÏÓ¢¶28<«õÑË‹—áY­'Ï€¿/871`a™ …ÿÞâЮOjÉ„µd颌qa~a™‰`ì–ÒåñH'rLnçtù\‚vò Tœ.¿F¡Z¤æ &Téï9-CaÏÊÞºR ©ÒŸ¬ª }ݧ¸W.`SES 58µÃ&‹¦*)›;É߬ëíX6÷I…×[)›s8;›?ÀW ÀT‰IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_unchecked.png000066400000000000000000000006011526321767600275650ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+3IDATX…í×±NÂPÆñÿ¹$0R—6Œ¦,M´l}xžgu�ž‚g0&>A7qèbg 8Bb� ¤Ú8x¿ñ,ßï¶Ë9ðß#ùA«Ýé’e·à”Ô³B‰1f4{}> hù×CàX£’ úQJ½JÑhÃYúöP´ü°ú¼dHžN¥”ïâù¡kÐ pƒ˜ÞþK˜ƒRÀºŠr€y:]dHØ Ÿƒýü"T’*Ê� HT€SÚ?ÿ-Ê ¸ø ð'± ° ° ° 8¬PiVÞ(8À²PbDÏݪº=?tQи0f4 :©á^^y»µ¼ŽÔÆûyþ0yî� B²[ Ï�àl_N�S‡É7¢Ýén÷v‰8Ú^ÏÌ4Fjãüifó‚f1§ ×IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_unchecked@2x.png000066400000000000000000000015271526321767600301470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœí›±NÛP†ÿcK"šØÚ©R öÂÚ¾E¡*RéVÔJÐŽðí •JÇ©•€· +‹ b¨@b &R*e K9°Á±’R’ãˆûM¾÷\[ÿùsoîr P(n3ÔÉ¢œmgôžfÂsL]UöïÔìcól˜ÖKŽSm÷R;(_°g5ðGŒ‘Ù#ð Åã}g _±®““ƒF¥¶`® úzÉW/;4�ííÓ¤`«mLF¥öÀ›È¼ â_Ü c"4nTæ �4΃é)+š3*5xÀ[$ì„Ä�/سþšúCŒ…â�û3é#)ƒÌ1ë%–Ü &ôúxßù[�ÈÙvF¯òïË3ÏåÓú™]>Üóº(úƹÿØÐ€F€�"gèQô�Q‹¾¨Ÿðtø�˜Þ÷[òP>ÜóÀô!`R•§¢ëbøW]€ëoû¾Ä;ppƒ1í Àù=þóÒ毂ý|h<º É3xh€J]‘ÕCšsà{Ñx’WcÚ®ºëÉ!ví'p«PH �F -@e€´i”Ò¤QH �F -@e€´i”Ò¤QH �F -@e€´i”Ò¤QH �F -@e€´i”Ò¤QH �&É€zðÀÜÿEr¨GãI /ƒœë†¨^ÒœÅãqv‚&z†{ R ù9øðntAÌbl††–Y˜˜îŠ´`ìUŽ3°]3àl˜Ö ¸¨ fÐÊ݇}wF<É3x9ûÅÒí (9NµZ K×È5ǬôÇq sÌšÐuÀhhz)©…¦UBd¬/ˆw‹¸Ä¼Õ•ÒVEÊ Mçü3o5GiÕÛwÞ!¡î¹UÇ{Ù¡y£RšM°˜ÈJã6 8ñ÷¤U/;¸€Eß�4M½ÒÀŸú­iŠ�"@K×oš ‘³í Uyê¼ÞžÆýªë¶ÍÑÀ» lp†6:i›S(·›¿ÄÅàºC–8eIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_unchecked_disabled.png000066400000000000000000000006161526321767600314220ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+@IDATX…í—?NQ‡¿y <Ã^�kaŒ Ü�S`­ÒÃ)8ƒ1!¨Ñ%Ë^`ï@–@vÇÂ]‚ü±ÐÝXø¾rÞËû}™×ÌÀG¶ £ñ¤i½@5§œ9&Fz—g'�^ü «Ê È4‘÷<ÒUõÄ­Ý‹óÓ»�§×qKÄ<Ã’ÄmÏó¦y„gø¾__©3®#­¬fm"¦²("Àó¼iIâ6°tbídu³q§¾)D*4ö Tóúóï‘9PÛ'ð'X+`¬€°VÀ l Ì?§×bQÕ*0Û'‚¸¾ï׋ OßvE w#=ÐÊJ�Aà 8NÇòrìH?«YLžß‚{àXQ:@þš´í.PæÐb’1OšN¬�tt®mŸÿ�™(aìH{5³|=§q6!¶ÈVIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_unchecked_disabled@2x.png000066400000000000000000000015721526321767600317760ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+,IDATxœí›½OQÅÏÙð!,Vjìmi6h²2–ü‚ÑDí$š€–úh &j©&’ˆÿÀ&&ÊgX² •µ‹$Zñ�›= Ë0;|Hœ½»áýª—ûîLÎ;óÞ¼æ^Àápœfxœ¤Tj.^ß´Ñá& v€­j"Öö¯äe.€ø´µÚð±§§sí¨‡5@ǧfï z å¿I-KŸz×»Þ“ÔAI�ÉdjW6sÃú£ÑW¼9{¦f ‘Hü ›ÝÆ’86�~IàAàmó'Aý””�@ï‰!ƒxÐuÅ8п²™ƒ¤‡a;!tŒM¤ï‰zë ý&8è%»FÛN•Àα½-hÀ¹Ý8Åû7º¯¾ æ—�JÍÅëãß±wæÅò5Wø~xWÛâÀóK„žøB­uMë½Á¼ W]q<ï%»F"QX¼äµ…ÿVŠÇ0j÷ÍNTú™? ’B ¾P[0'͇ÂrÂÊÊþ5\ N‡°w5VÚUwk(¹öà 8U8¬Xã °`�3ÀZ€5ÎkÖ8¬Xã °`�3ÀZ€5ÎkÖ8¬Xã °`�3ÀZ€5ÎkÖ8¬Xã °`�3ÀZ€5ÎkÖ8¬Xf@nw@²ê ¬!œ+“Ëî=�æ(D••ýkøœ+“[(óè–t¬ž‚JD‘G·/´Ì)5€øäwŒOÍôE¢® |�NßòWŽ‹ æ”°µÚð@±6Xˆ ž™©º£ðåËìEŠC¾Pv{µñhzz:×(>Ý‹èBMŽóc“é;Õp$ql2}‡µúèÂnœâ³°šÐIâשô«’na1L@X®´*R’1ÍÈ£Û¿í€Ðk/yíQXÝshÇIe2™�•Íö™@t@…—“¸„’OJèuüLíàAEßG7MMÎÞõÕ×4•¥øìÄMS~R©¹x]ÓzïN½} Uר6‡E�n¯6ާmÎápœnþÅ傸½4IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_unchecked_focus.png000066400000000000000000000006001526321767600307630ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+2IDATX…í—±NÂP†¿sI`´.”Õ C_ O`"ïÀ¬ #Îê ;Œ˜ycâô:(;íB!�ã@k*Û8xÿñææ|_î]Îÿ=²p>‰®npJâ$@ 0|¿q_Ž \Lâè°BÐ�rørx@aðví>´ŸâŽ1ú ¼n7Ú�÷Zq9ðtþxÑ45™— �ì%LvÁí«*àó^+Þn´ ¬ú_ÜÜ«€ç%€PP¿HÀ)ïÏŠ&Šœ üI¬€°VÀ X+`òIº½Vq] €×/šU¡ÓÙž"Á�€Âh˜šÌª�8›Fnº–×FÙù÷b2�Qî�5»b’”ƒ‡]1©-&YÒjÖÔÏo¯¿Â£KE…Ñ~5³ùÀe9xê¥IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/checkbox_unchecked_focus@2x.png000066400000000000000000000015511526321767600313430ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›OOA‡Ÿw�†„‹Ò"^ôÐ&áâU¾…`$/B£‰è>�žA#/b¢‰ð-ðê…bH¨WJ[ôBb€Höõ-Ëvù#ayÛ0Ïivf6ùÍ“Ù�˼àp8®2r–Iýó¥Ží]oõ€Üz€–x£ý7{@tñmþ×å‘î?§½t²UÉÌnލèkàÆ½,6D˜X{šü„ˆ7éX÷rÚº%•i K¼Ë#שÉß³ò7j0z«ÊÖlå-0v¤ò"|S¥$¨ñYÏ�"žݪÜè e·¤ªÏ¢vBäÈÌ•GTù˜õ_Ç c©/'m§†@UÒ³åGx2…r­Ú-“µÑÔ|xz�€þùRÇöŽ8ü浨׿šíÚˆ/õÅs'·ycOüeàúAW1Ñ®™ð�Ñ ¿¸½ë ü᩾l¶Å¬f»6^ºz¶w¼Áð¼:ûGÝAò…±Ô—x"ÆÏÏÑäg…üa�ûç|up©á¿ù“Q–j�HoxJ„zª Ê1E»4‚kP¸�P;í¨;¡5ÔûQ®N€ukœëÖ8Ö¬q¬XãX°Æ °`�`À'À:€5N€ukœëÖ8Ö¬q¬XãX°Æ °`�`À'À:€5N€uk¢ìUŠ4½ ÐöÂãQ ,Sq„ºL‚kX�£+Õ–¨ž©¦ !Qj�è�ð”zâ-֚ЗùPŠ-`ÌdæÊ�Þ÷Âsê$Úü¯@ín°ªLßž+7ݧpë]¥[‘©@W1ÑîŸ.`y¤û��®®%ŸÎ•†›âsP•t®4ÜÚªË@Wµ[„ɨšè©Jz®òžPµˆBÞƒ%Ê�v‹Tσ”¡‚ €™ÂhòyÔ½çèŠíÌé‹-©@@‚@ŸBŸTŸ”ÈT3�š?îÒ÷éES*�UyCóME˜l~奼IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/line_horizontal_pressed@2x.png000066400000000000000000000002121526321767600312630ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/line_vertical_disabled@2x.png000066400000000000000000000003671526321767600310200ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+©IDATxœíС€0ÄPÊTFG تX6øˆÄ�º¼Œ qÝÏúîó˜CxìâôO@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- yjÑ€1‹^ºIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/line_vertical_focus.png000066400000000000000000000002061526321767600300060ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+8IDATX…íÎ10A&^0�CTPîõÿ³‹²z²z6o3¾à9Æ�“ÊÐÒIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/line_vertical_focus@2x.png000066400000000000000000000003711526321767600303630ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+«IDATxœíÐ1€0ÄPЉ*À¢°†T”Ÿ!Ùnº¼Œ q\ÏúîûœCxìâôO@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- y`‘€¢fA$IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/line_vertical_pressed.png000066400000000000000000000002051526321767600303330ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+7IDATX…íÎA@1æü{@¢z"à™ý·“ªE=IO²ùx›ñE+¶ÜuqÍIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/line_vertical_pressed@2x.png000066400000000000000000000003661526321767600307150ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+¨IDATxœíÐ1€@ÄPOB‚u×âàS$ÝT“—9Ï»Öwß׌ð8ÅéŸ(€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@S- )€Ð@ h  4КhM´€¦Z@³l¡€‘Þk:IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_checked.png000066400000000000000000000024151526321767600265370ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¿IDATX…å–MlTUÇç½×)ˆòQ§¥µe:�0N+¦JÂE%E>4ACb$AHŒ &(‘Šuc‚"~„Ä]AB# ’HÊJ ’ FÚ)m_¡†FS„¶3÷¸˜×ñ 3¥�ꎳ{÷�ûÿÿνï¾sán)$¹¬:Z¬6ÈR�  °ººNXj7v%~»ð¿ç>²P,m}jœº§,•-݉³?ý'€¡úi“dè `­—ì*4Gl£‰¤]äÚÎM“J1©*ëY`h¥'q8etýµÎØÕ‚Ê«#áöA`¾g¼Ý­˜ù ÍÍÉ1вÊBu¯¨è@¸l³²»óÜ™qÌ®© ÙFO‚Ì~”›¯]ooÿk 㬇ÃÅLÞ#Êz”bY‹{ÚÏ´Œ PO-ÖÉ?Ð]nGìmÀbî×/ G7£²èN&þqéwןàÜ>£XïÙ QÕ¦ÞD®yYu´‘ ª<<Q.áP2™Ü{›�ºí±†ÒêhdCÀq¾–šwJCÑÇ9ôÝÒ@MâôŸ¾×Vi8ú.*ï“òÖ«ÜÑ÷z:bŸùM"‘H È>ƒ2O•彉ÖÃÑì“�ÒTº#DŽѭi üï2³*ç—Ï \Ÿ^l¾òëCµÛ^ý·¦±Bß( Õ½åq±F„ó@휹×å9Ίtñr(��ŒÏ®© YÂ6¯ÂB?¬xèÑ2ÿ€*Ô¶_Ì–ˆêQ¿ŒmäM…¢B¬=Ø)ÃÃó��=’§óh€Xtf éò‚ÍG¦Š¼�õœ²Iy)H%mÿ1”ÐD€Jÿý΀ë©ÎÁÛP+wNVÈ8rî4ÛC;kºÔ1A_’¸4a#—ý�7RE#Ú=x?¸ €b®Ø†¹Yp˜‰†˜¬¹jYÞvj×ÈX@�f]–-’ú’‰õ‚!ãX{³¤Òí9žà8N“G·œúú̱ëm�Ç>-Ô]Uw^m;ë?Q‚²2 �j̸ÒÖÒ#pdV°xƒ_Ì�x‡B¶BÙß›ˆíð•…ëVà\÷…xæn�õ…5›Ó„º½$žšyqúô°;=°twÞŽ$èN71o­?/‰T5ÝgD¶àkTYÇd ¿¯ç¾™Ô‹Š"ý×öe’]× ô_;:¥$xÀR¸a*é“Ò ú�k½›hÝq×gjðsà9 ÙíhÝê÷Ìù»ÏÕO›d ý‚2å7Ѻiôª×xìO�²"RV]»Iác…ž"ÇyüJ[KÏÀ»Š}¥ä@²8¹®/Å$oD"‘@ÿ ½Øü�ê“n"öëíyyÿr]ñvËX‹€6ЗœAû|Y8ú:K–äÜ ò„ G_î´bžy—ˆ,Îgc4تªÓ­Ô×kFØm¬#I8·†]Ç ˜ARA«c–!¬¯(Ç’&µ®ïb¼w4�quø9áÚEÆÐ€ðÄxò�D7»í±cc%tÅV-¨ˬÑ¥*D(G±�.Ð.„$¥Ñ½Øz¾Ý»;þ_eÍCýcòIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_checked@2x.png000066400000000000000000000053501526321767600271120ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ šIDATxœí[kpÕþΕ,ůν Ì`3ø"ƒNG#.ï9óI&›H õ®x.@³¶4¦!&>Â>0µ±;z÷‡æ[[Þ°Àë÷ؘÖ0°Š€`VN ü¦?íüø#œ[•¹¹=ÁKÜð…9öÝJŒ�Ýó/`çÎx®œæ,.ÏÒ â÷–åÊgD´>ÚÚŒôˆi`A­¿Òf£‡Á¸Á€&¼  ™íIu$Eÿ˜¶Ù�II‰R;‹9,“µ-aB#ßPhàs“X ïýx:ú§WíÙ_B¾Â€[§x˜AoókÂëH{ûg™ø®®n,L8†/"¢+X•¦�Qbº¥»3ô×ìÞ`¨ª \Ï„g8µ¢xÌdžC‡Z²õ¯„Ïçsô�Û~HŒû,Heðoz:ZïÇDOËÙ@¸ë‚�ø^�]üŒ ñ«#áPW~MQq晥öxÁÝDô3%šâWÎä�GÛÚb™øÌ4Âåño!ÐuJ#Ý�âêèÁ½dè/+,ô«%óËHpw�щ•ýáð�U_"“†ÝžÀzíËð~"‘Xvº^Ž„C]¶±’&¶hŠÎ™…¢-Àj›U_–‰Uÿwz\c~Ι^ÝýixЪŸ\ah¨+ëï{yvY個1Õ›—””›èû§?–à®ó/ѫ짌Œz:[Ö &2ÔžS ô½[:Ïõ9—ž´p~I™ë`l w¯Y}Ó1`a}}¹Œì°pªàLÄ.ˆD"£™ˆuŸá? ,®fF�€jÕ'Áè‚@3ïb»x)‹=¹¼�§‰q³Â6ND�ÝáÐ.Êfž'ßrò™�î»}ùáý»»­(óù|Ž�Qû:¾ Œz+uìfà±hGýóÀÖ¤• ^¯×yœ ·8OaÞÕSSþ547§í¥†p×�½$w(L,‰Îë ‡Þ·"Êí \ÅÀðZá§€i�$ü´·#´Ý }A­¿Ò&Ð PÅI�ïìîh},]£1€JËæohÑ” l‰v´hÂT44T–?¢‡ (³"^_\Ü4»ÜEÃý½ÿ�ÉÚÿø`ßñÒy®¸r<°¼¸Æõ§ã½½º¨´Ó ËhhŔē6<`¦yÑ¢À<×àø›Lt»×*˜ùw]àE·»¡ÈŒë”CphÊBb„”ŽŸ6‚ñs峞ì;ÐÒiÔ¸ÏçsÄíx…€o˜ Í„kQ<¶&k—H$2ÊÐüPŒ»Ó­ t�Í_ìs1TÓJ\J~ÈLâÀ˜x„&^ö`º¦Ê0í…ƒ'P˜º½Ÿ\¬ÇÕ €Ýn»Šñ�ÁÛû¶ö5êöúoh­™¸é‚÷WÕt_f [“¶ª+Ê›ô˜ú݉q…ê‘Ä«FÍ¹Ý E`Ú`,*w`ÂF³å®)š/Ó«“€Ê`°ê¹$¯**¿Ê…Rþ¨òî[cDè=ú€²×ÎqÕ~Ò å¥Àù§ L{z:ÛiySXmð3Ź3ÝiB‘`Rýp‚dJž2%ð«"Þ¡å(áòîû:€ù&bò�@uÝ—Ï0"0a‡ú™–j9©cñYj‚j4M��t­¡Ì<"‰ä5FåR£]ýnœðbå“dÎýÈØ)ÿi%âI©Õ^«åè€JUbý>ÓiüT BµQy1F´ÚKµ½iPE" £›€~¶ö´€a€H$2@¹tø|>‡’£R?Pú ÈÊ•"��Ó…‚é:HÏÀ°òY Né6§0±Ï6\!æ†ÙçÅ‹;¡ÌbãmmmãJNJ¬Ê¨J¦¹&"Ž˜”熡’9Ó°–£7~ª"¥Œœ´š”çlØv��ê4¦ˆ–“¦}ªG�ábƒˆ^2*Ï'ˆ„aÛIÖh'´k9©–šÃF^¡å(áH m gŠ<�>í‡v2´ÚejoM @¼P¾G€2}ô•…Þ`Úéf2ñ¬©Þ\ƒðŒSd‚€Ë•)¨9…¤5mk‹1ã=UE)/×òÔbìøÜ�“[¶�?bDpÕ-mМ(õV—}¤åéÎáLê]ˆV5 ï>Ê0ÍåÄ÷uu½wÂ�BB¥™€·ôÒãº(°Û¶@}Ô|‘Ë{ŽáŽ/ZSñ(Àoqrz¾'ܪ=ÔB€ Ú¤IÆsúDLzlS˜œ$Úãp5š›Τý:ûMÄe Þw&‡n…IzÜ]øžæ&]T¾M�k�¦?jZÿ±»ö¬/5‰ìL \†üᣄä«ÌŽã&×ú¿VÚx$ÝéPÚé mg¨C ûz3•}Z:�IÛ¹`èF<0øo¶±’&³Ä, ŽÙn)¶½„þqûø¦t|£� ƒø>µßw{†{p`¢'ô,*ÿ61~�å§uð10¯‹v´^o6è€{IC¿Ty`þí±ýûÓj0=u{‚›¾Qa:œ”¼Üʯ•žàAr=˜n`z²3‰ÏAØ4*:wZš^}>Ÿc`̶ À'm „¢sˌÒ\ À!• óÿŠéÄEápxÌŠ8`2u^8v)]F„…àSç†GAèf`[ËœÉiwm¦þ=ÁMßvòyâ0G¬0»¹béŽP¥7x®`n†âFž‰†[Öb—«« gÍ:*3 ¤\ÞàíÄü„ÒFÄk»Ã­O›Õµ|IÊíõߦÍóSóœÉ;2ýµrªòøï`Ð#PŽg„G{Â-wYq`ùŽP¬¿/TRVYDÀù sÃhR4•ίy=öYψeÙ9€ÏçsØKÝO‚pT?$¿ÝSSq3"Kw3¼&·Úæö´opµ¦ "«z;[Z2ó—&Æ%ùåñý$>v&m+"‘=–/mYîhãØÀ/�w¬„FEÁ\AX[Ræª(.«Üu| ÷xf~­¡ºº±°h~Ù]ü"@gjŠßeÇeу»3Ú”eUÖëÿ˜6qjb2FD�bdc& ±r¥½ª« 3¯‡Þ$ccOgý=Vï)1­ËÒî3M�x @¹NñÀ¯1‰×Æ1²-Ó`ø|>Çਭ‰‰®p%À)Ëpâ ^ge´O‡i_—¯òøkâQ€¿cÐHœ�w@ôoHìœ ³ ~{œb1ljd‘(.MÈøHQK‚–@¢„KÌ6húCëz:ZvNG?˜|‹€ßäʧè&àÁžŽú¿dÓåµÈõ'3Âíñ_ н–çØw'6ÎJ ?�éM#äí£)—÷쥂y ƒWX’¥›(Þ Âs=Zþ‹,¾0Ãiùl®Ê㯑¼@=MœÒÎÁÄÜŽ‰|â‡AÔÎŒvˆÄ;ÑpÛ>äáK±Ì`38‰ÿÐðÁÑëpkIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_checked_disabled.png000066400000000000000000000024131526321767600303640ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+½IDATX…å—]l“eÇçmǦ(3„ T&¸€"©^�­t£]ç„DäC£¢‘„@$^xa‚‚¹ç¼1A ¨!1$\aâ“¡íºµ£-�„¤Œ ›DÔ ØÖö9^¼m÷nÝF‹Þq®žç<çüÏÿùzÿÏ wºI9Ááp¢FÝÙu¨´‚Ôó@-à Ð�HX2Úxþ_ ôôõÕcµÁÒ`õŒ1®-þúoÿ�SÉduÅHæÊ†œk¡S³rÂ…^€ÑÁÑÊJc¥e.¢ ,£+Öósñ]7›Z½ÞßÊ&êë[(YëÂcvaÝ¥£ÃŸƒÁÌt¤UÕ G/"º¨½dÔZÓ²¼á\Éz{µY1q`ŽÀÑJ7¯x½Þ¦+<Ѻºº*ﮞ½ep],³<àó�½%�X,6k8Ãi`‰ {›} oˆˆ)§xÞTUÂÑøv  ¥ßRw½ß_7èŒqOLβXÒÙì«/*'jÔe6OFà¢Âq˸: ˆˆªj{8š¨Et³‘ÌaUm�tB‘x� g@þHW¹=UW÷·c6V8 x¨šbÒ×};àó~ì,’J¥f\ýkè°X`U ÉÛ•³œÙ‚¾o7ÌîIŠÚ¦)0•½=ÑØ~U-LÎãñŒ úŽ�E»s¬@ §'y?ð$ðçœê{?u¢†£ñ�ÀË ”bŠlí‰Ä_wúü�Þà<Âã¡Hâ‰"F2«A8îñxFóþÞÞD-°Óî•þáTá½H$ò@¾/"Šê1Å<[D‹fQùÚ ”±Ìk@EÉ•ÇlfV*¶8bYßäÈ´PjrÌ—¤¬º�â6¤ê3ξ±Ì…\s^1�œS-S¸F¹ÃR{»@æ;{7¯]Ëc?˜?ˆVQ΄b¦1uÝ{ \lI…¬Ì-øD ÈÅÛ'À%g§²º:�=�ÿÀ¨r@TžÒE¹V¸­:.×¥®üvöç}c+ Ò  bV:“,£Ÿåi�}[G%kœà^‘k~WDÀEºÓ’UÉd²píü~ï�•E‘¶@ ¡p£TUÖ¨XEšššrÌæ �¤7;ÁfV¹ß¤¬­Ð/ü¾úÝNOO4¶XüÐì[ZxŒ?ábm·óeW,›•w×ÕÕ¥ï©r¯Sa/ÓoG´í÷�Ëœ*šJ¥f(bëŒêŽ)Õ ‰ô%�£þƆç&Êq(zƃf·Ê˜+ÈEýJÕu ¥iéOãÖBUº£ñ¯Ý�Ɔ–i œJ&«+†31`1*šê·Mõ 9räˆ `ýúõÙÉÆUUÂ}‰m¨~ ¸É,ÍmuÁ&U—P_ßB1V˜ |©é›ƒÁàÐd±SY*•šqõÚÐ>„-À EÁ¦†äĸ)å­·7þHVôð(pE�]&}ãP)�ÒžhìyÙƒ²È~ŠéZ¿Ù÷“ÅO«¯¡ÐÙû¤bø3�ltúA:Áœ0âºPeeGFî2TÞœ«¸æ[ƬY˘~œÔ´µ1¬ÿuª% |w4¾ ÕvÀ_J<ÈYÝhôž¼edi€¶…NŸ^@VÖYЪ`ÿš).„~QúU«e:‚>ßùrpïlû5o쯳…ØŸIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_checked_disabled@2x.png000066400000000000000000000052741526321767600307460ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ nIDATxœí[{l[åÿ�{m'a …QZ©XÙ†@´hŒ´qÛÉíŠ`Ï�::`Œ²166Ø@:[�ÑVH¬Zª± S¡­íø'ÍÊCf±¥¥<ÒÒ´ipÛßo$¥÷^Û÷Ú‰]M[’ÿ¸çû}çœïÜÏßó\à0ã0þŸ!‡ÂHWW×±9ÝÅY9UÀ“!rˆ#èöŽý> È[šÂ?¡kooy¯Ö¾Õ,‰¯z /"q€3Æ©æ=^´'Ú[g÷‰«è"€*€¤DâÝçˆh·0ª©`"Ë&ÕyžnnnÎVKkÕ‰§ h®–Îx_ KBmsVW£GL8¯¤RÓôœ<,à•4  "�-yªëJ>SJÔõá¼H}£Òs“¡d†¢œ"‚¹ÎÐà 3¦ -ž˜óæDüŸPº’É9Ji/8¾Hñ �µøbÖ«½<¿¥eW%º“ÉdÃ0õyBž/À%l ƒrmG°å/ãñ˜@¢ñž+<°®Ð)>¢#·4 î¯~3Òé´o×î}? ànSíå¤Üߘs·ˆ¨JuW’Z4Ñs€;lE �Çéᯠ¿{¥zËA<oÌ‹÷V’¿0ÉR(x�#™« ÃØW‰ÎŠ@R‹Æ{Ö@p™­h‡¦©‹C­­½•è/©T“äð< \yµÞÿ߿·\]Z%†£‰ž%EŸÒ”§ùP5 ¿»OS!BÖXKxæpžk:;;õru•Ý¢ñîïòŒÅø$²Ã7†1\®žj‚¤D“½·�\ s[È;‚sYŽŽ²Ž÷4 Po?ÝÞÖru-Vg•"OýT€åf™P®i¶¬v«ë€WzzŽñdù:€¿½ÌeÚ+}óÑîîÓ˜×.&x†4h�°àv¡l†’ç*Ý�”h¼gß7‰G4Ź¡ÐÜÍNu]I¤V�¸Ö$ÚáAnv ØQŽscSØb npj9uy•¢éÿpÛS .Ì—ScíÚµuG4³ÂÖƒj°™#™Ã0r%-9) ÇRÄL"h5þT9N…»z.�øZ9ü"xMD~ÞÞÖ²±ò+©Ô4OiS¾ oéh›ûH©:%g’"‚ßÙÄkÊi|__Ÿ7’H=*ŸÇøß ¹!ë^BÒuÆšï÷Bà~‹�r׺u¯©T�’JñI”Õ©ÝãæD,;z(“} ÄMnÜr!"÷Dã=íëë;•œÍüà&É”ºIŸÿ°½dtM»Íâø§`pλN¶Óé´//Þ(ò-WGK¡Ôœ"¸th8·Ú­'†1L�õEQn-µ6(ª,î=ŽÀ¹&Q6ë‘ûœ “”�C�9ñ\á0*¸$šèqí…ýn{ ‚wL¢§4�4¿·hÄ—¿£GU£ÏÄÆù~ÿ'NF#Éž+^ïæ\pw8Ö]´1°páÂ<ÈgÍ2�¼¦·xw¢œoyþæd°¯¯ï!–:qª �,s[î*Ú|VXP¬NAÆFÌV³L‡çïNÆ3Ù[a^(Õ‚YÓN8i‘Åø78Øk“�kj:ËÎ+€·a¿€Ï$z-lþÀÎ;€ÎÎN]DûInW$oq*EÐò☗‚sÊ‚è¢fÚTÅì3Ž=~zà±Nœš@0+M}݉¢A³øNMN/䨠§Y ©wìk¹\êX^C( —8´¼ÕwÚÚ†"Ј¯XŒ@sœûµÚŸ—„ÿi3Ô~�Ý÷vNAi´òjÀÉy?;M΄!»ï�vF‘i�V’h%ÏØHj�¢§µ‡t@GGÇ~æ� /�N›ø"ZÖb²ä�G$ÑŠê8Tx'ª¢ˆó2h~ÊÙ{„ cûlÇb�áxú‰DêxL¢‘™3gŽ˜9Âz¢ªkG¹8ñ¡KyÍ .È74L¶‰íœÂAPÃV‹Žœ>˜v*¯%ÅѶ'/'ÛDïÛ9… Þ2? 鲨ÀsN嵄Nåh[,¾²ÅÎ)ü oÚ;Ç •^ ¢Û˜*ak0èÕ‰@Ðê; {kaÈfº¼'¾N¥JN7†a ø„»¿Õ†<æt$?6EŸg­‚ˆ�W€±»µn‹0'çÙy½*{/ˆ=ÎWÛ|Z~¹!šÜt¬7Ê{‘ÍôÙy%æp±ì¢¼ÀÉX(ê§ÀñĨš àÎÖÖÖŒG l>ËËÅŽÇ‹ÀƒìŒ&5¨<¯««ËyǗͬb�#§<ÕÑڲƉBR#aÙ¤ ød1nÑŒ^zÈz“Ê:¥yí×ᆑS¹ºË¼íÄ› RÉÜàvוH]ë%ÌÇ*›Y_Œ[r«”üÞ*‘mH$Nr2lgèÔ 6AèËyp‘Ûu\:�öò‹Pdy©Û¡’0‚³7Â:útêKܼ ç¼Ël�@ш� Ä3>M…Üf `èX·½Ÿy˜]YŠ_2"B’wÚÄWoŒ¥÷àÀhO`6ó!…"ËÏ °“�Åí�–+Ü=‡û¦x—Y&Äo�@Iʹ] â*“h[΃Ùå¼ H$S³Ê³Âk¸ßì±G+Gê=KÏnn.kzM§Ó¾]{†Ö“l7‰ß˜TïivÊ+t @"‘˜š¥þ€i”ä烻æ-X°`9ΣGçCÃÙs \Ê,Nðå17úî±Âg§Õ¸Á¾ksC4Þ½’�M¢¬¦©€[æJ™ )¿@"–Œ0Áãí­-×O$A"™L6 ¨JY ‘Xê&5Ër}{ e•[ݲSd"±ÔUX3.�M™<éæJßVµ0š"“º”å0�g¬høVŽŽŠ²Ä"±î r»E�HT�è—FóÎJtMétÚ×?0ø�\gñ‡X§r™óœ’"̨è8ëÓ�¶Ý ðy³Œd»xs›¢Éä¬JtM‰DbêÎ�}ì�ð¦ÊÕ]Vnã�q$JvvvêSO˜þ ö.–±Ò«åïokkû´R½å ™L6Œ(ýÇïp´­ø¥l½çòrg�˜HªìuW“ûH>Üà•e•$,:!{à­_$�%(vIYöéG[o/7ŸÈŒ %KG½!ŽžÊS¤x7€)x±AÇúJƒ‘N§}ý»C9‚ [†get¡ä:ڗ„Óå£ÑÞéÔÕ ßu eD +áÛPò/]Égš¶Ÿ×ëÍ)ÕèÍi“sºÌЈS5�sYZ%7)ÊâyAÿ?&â?˜èþ6(@PëÁp‡@îýdÇÖ?�§ËÛQíOf´h¼÷Bˆº�ÙÕÔ à]!–©\fU5SsköÑÔÆxïé:Ô"Ž~ìpÊ8Õ| ÁZ�öd¨uv|<߸á�|6�öN‡FƒP§CäT3 œ È‘½¹Ùb/Û@l�Æ-Z^¢Á`Ë[ÿ ¹È‡q‡ñ¿‹ÿ’K×íÒñ;IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_checked_focus.png000066400000000000000000000024141526321767600277350ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¾IDATX…å–[l“eÇÏÛn.¢“àÚ ¶ŽvŒ½QI¼ð„�ƒF1D# ln‘„ ”8 ˆóÆ„I;!áj&.0%ÑÀ•TB‚“­Ëlwh‚¢k¿ïñâ뺯t‡nxÇsÓ¾Ï÷ÿÿÿ{~à~™ xÞÁH©Iä¬]‚RŠP‚`P" aTÎX*í½µþÐÿj ¼µ¶§^ѳ¤='¶½­»¶èû{2PÖtý�Ä�uÉT?J‡ÀI1ôZ»ß{Dz¹ž"Qï\ŒµTTV+Ìqàz"!²áruáठÌk�ŒÍ1Ð@¿ u³"…‡Nï�ĸCªS,|[v!”WÅfUwmá…¬  ”aÉY @à¨ý�÷ížÍ�þ=®ð]h= yïÙÜV#ÏöTùÏOh Ðp-_ò?• {Bß{ì{2â©P•ò–ØVEwa¯šE¿×øúÝïÝ}L^b¯B%*¡¾Lñy#¥ž„·Ê].*³E°U¹‚rÜ‹iMÑnÕú@k¬LT«âbAu ":ê Ìß{Ê6ö9 fiN°·fÆÍÔÇ:5åűýÈcÌ·Qù0ôŽïK·HeÛÅÜø�‚ "²¢»Ú"5`woÛØŸ%}íÌŸ=œœÊ±Ä¦!º'Ø݇jjp�k!ò€­Zïþ–2° )6x ¸ž3=Úäf G·«ðJ¶QlÜìN„ªüí —/oŠ>‘a a¬•€ï\»ph8<0P&°˜ä½)ŸÎ?›5Ò9–äy%Ã*/¨ê·nµå] g2ÒɘfÙvµ;aD¿s¤XœiJr9mª+¦ ž }9�+¡½É¿%£(ðª=rŒT¤lªò¢2ÇÝNÄo soD“ÑËŸ bÆÏÜ#ä €„WŠR çºr®ºÖƒÓ†¹û†/¸”Aþt~y,�CO0ÅP•´¾ÆJ-g8•s¡O'­,K#±u?0•·`ÈcìVwÂcd)€ÀŒ×t8Ьx²ISÇ®§vf'* I;Y««°»«ºhäD©Šª¬rX¤=Ã@×F_Ÿ:Î n­r“åã{ßYŠlo"ýª'ìßéÎZW•Ào¡j_ª6HÛá{+€u�†kùÃù_j$ž¯…k@ö0þr$Tewhzá:÷+ZÙv1W�ÏÔè¶1_C€`óààM�£Ýÿ«ÏqëÀB±¤V„åÀlœu¹ò�ñHc×F_Wúd¨[¢�@ ÈéPµoñ¸œ:pè'� …/z"þ-c$mêœóµb�ú]U‚ÍÑ-Ÿ}ÆcžîÚèësCF]T§Ô³À ”¯s²¾s“ÿÖ¨"cDeÛÅÜ¡¾½ÕÀc›ç»j}?ß�sWU4ÇÊ-µ�!Ì"*ZW.<œMQ(޽&è. „UÍêž߯£ÁÇÝÖsý5='þo3ÈëÉT¡CEObko®Iôßñ#êQžË�r^akOMᩉ “*1*ûç&¼²F”% ¥8/¨çj r5íÝ5—&Ã{ÇÐ0ã×µæIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_checked_focus@2x.png000066400000000000000000000053241526321767600303120ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ †IDATxœí[kpÕþÎê‘8äá�Hv�ic,‰Ó–Г†GÛ�RPÊc€G6áÙ¦…fÀ  8L¦Á±œx �)5S`J‡GfHä- �@© ±%“ØŽ$óð#$Ž%íמÝÕjW²¤L§Í÷Oç~çܳŸ®îÞ{îpGqÿÏ�#щ¿uŸGRÊB!æ©�9"8`9€© !°àÇ"²CÀm¡Êݥέdø›ã5"²à"§Ž3Ìn^Ô';C•ïB„EL@± ¥¦¹ï|‡‚»ž[ÜØh‡"�SUÏ3ïÕK²Xa‹&@Mó¾sE‘G„2¿X1³ K(+:ë<‹1"  º%^á$p­Mð¶BåNŸ¤©|¡¦1ä,K§…2…T¦ YMU‚"<À�”YÄÜF¨Ë¢u³>*$ÿ‚®ß÷]ªÊ‹f™4‘ò2„/9G’¯î¼µêó|bW5î-+;fâyõb‹²ô1 á�‘PåÇ‘>€4Ç®�H+€ Ik¥&¬Ússù—ã�¯ÅܶvwjÀ"yoAäÁH·ç>¬5ߨù Ð@Åï‹? �» -*EZÇÊhhFwÞqsÀ‰ú¦¤Uu¹¿0YÛFàEwR®Ûq‹w>1ó �JÀ×· àU†–^QÔË:—Îz;¯xã„¿åó* ùBÆ„K¼ÏCÎs¢·ÏÌ5–’OÇ�ªÄ “‡ËIeþ‘zxˆ†ft%ؤk|[&¦7¡�Ž\cå<‚-±Ÿ‘ò¬Áû©¤óÀM]Kª‡s�ST�'î„`ôÏòH¤®â×¹„ÈI€×õÍWu€‰cŽÄ3�uÞëK±:Ëþ–ØÏ…²ZkÁ �¡Š�v¾¶ÌùC÷Œ´Ûõ/>�ùí¤ëÀÙù~ó�–Þ“Êeªªœ a•T‘HCA7€nQ±]>Ÿ÷€”@8¾"K4ÖR93ZïÙnåj+@ ÛÈ�S¯âPNï¨õôæ’Ûܶvw²æ272'ïCdM¤Üó4®”t..þ5‘ ÊÄ©[œ¥1o÷õx¿·u¥¤²ùY lN, p›65 ÏŠ†*ßÊ%©`süR àÏ…o‚á/;B•[r!^•¶˜9f¤Ü©÷®Éæ“ý-@ …¿Óš„Ø”ËßÖLW0_KÁ ÿÃÀ·TÊëÁæø 4Ðö�µ;T§ðA�Qxï©cÇdóÉÔßòÙB 4¦$�l°KâOôOT¯¸ÙŽ›+(høšÕÜ3ÉŽ›r\`�Æ4sxXê³ñ³ Hß©KlŽÔVî²ê|n[»{‚ëЋ ~`—è8pÅdqn´ £³è¾(˳­ LƒÍ^›¨ä�)™yÀ2=RF¼kA,´ä†Ëƒ¾„í(Œ”{žј|þþÄ͸¦¸]¼€V±-»Cq«Nýë× ¹Ô.¹BAà¾@8fú0c¸RÒ¤<§5 pƒÕTB.6tú«þf5÷Lb•eRE!�vË]�jÌùB3Ÿ FgLjߥP™ú«Ug“űú…RI!À<ÿ@|±'Ò[ñí¨�Œ�fäe0|gpkLìª÷í1òÆÐF ·Û%]tPî°l_)ª@t_œª:2ê”PÁ)Ë6#G ÿ@ìû<–É”Ì;a]"`I"t¹+àÉFŠÉ '(‘LŽªr…e{ ¡.·jO u¹«Â“Œ³Ip¶îÅòÝ/‚RW�-úfÆoZ‹tRŸ»@ª�œ ˜¢#8Ô~›<ŽØäg‚*ËÖI_és§þÙTƒL!{�mtUfV­=R° kñìC´;A÷ܶvío2¨ß!ŠY çŒúçUV+2\…ÈL^Á�î³d›¯±u¥¤D`¹B,-hY}žýd×N�idÇ•§Œh9™ºŠªšVÊ-S {ló,b)€¤&M38 9f|ª÷aÆÌ©*í–í%múv¤q‚Þ�]FŽÉBˆë?«–‹ ’Ï[µ—TŲoÅCî²3ƒc4DØHY`äh‘rÜ X¼)J>�ÖÍ|ߊ£RWЙ9b2p�È›´çïß=‰1G×’êa‚Of¶”¸Z. [–ä¨p‘Φ¨[�´ vÜâÝÁ›ú¾Ry:8y?€C†–.�Ü{`(¹ÚŠôÅNƒ~�2XÕ]ñ®‘—í®ÛEqôx:+¢7Îê`]1*"¨È=ÝË�?hÉ�C—³€¯š•ÇMPeF/5vÆyþÖ}–;>_�÷q¯YqŠžŽ.õn²$5PTý&M”§Ì¨¦tÔzzE°Ycš ¤ãq¸[WJ*ér_¢Ã29[XÎo�¸ÔÙÇù}‰«µ‡0"ˆ×íÙlÆÍ¾ŒMó÷†´n©^ßûM«Ž»–L&‚ùÜAá»)Á¥vÇqsÛÚÝüVç«bu¶Ó¡¬tÖWl1L†n§êXaÕ9Dj+w%Ýî3˜*>>ȳÃCÉ…v…YH}é­ ]¼}¡8•¦lüì#@„„z�Áz}MKŸå ¾ïOù �¹üÌŸX y®±›ô ØÜ3“Â{µ6!ê¨õdÍÁö] Ç7¸nÌ@îM)rz.ßÔ4żŠSV€¸€íÉÎa ˆ°)¥ºWíª?vÀž>v»�³5æ§Ò;ßê^¡­5M1¯â�Thœþ©ž½=p(—ä€ÑÒùdÅy€ËIÌ“ÑBʱ‡›ûô‚Ü.¢<ç,O¼nܵÙ!Ž7¸IcJŠ¢.°»¹’ÓjÅß;C([¡»ÆÖH¨bi!$ª÷–Mt«ùiš_8~³kµ6 —FC•ì|s^®ùÃñëÐ߸ ®é}·åûm ¤Â}·A¸ÚùŒòx¤Þû‹\Bäµ^ „ã¸Ë�ÅÂô�õ¾Ïò‰U(æ¶µ»SýÞ'Öš^óõx/²º¡E~ ö6:ý‰ç\fhér�‹vÖWþ;¯xãÄáyéÏÐßÀGI—{A×’év…Ü1ä¿ci£#ØŸx”€qˆ%!lRSxð“e•‰¼ã怪ƽeeSÜ· y7!Óµm^Qéº:×·Æ×÷–Íß«J2 “û…xL=älÌç¢Îi ³÷¸øbЬ€Iž@c´Ü{W®÷‰´(hÏX—XŸ1#30¿T!/Aä%tlÎWŒÃïõ…\,”K˜-Ó.Ëe¶Ï†‚7í5­=Ç+IçãüÔ‚–ð†ÿFJ‡¨ˆ¦Ý©/’ÃÇìw§ÒiÅÅ)ª$§‰8«‰tPgr>FÿR“-õwT‘eŸ„<ï’ѪÁpâÇ*ø°óŠ3 zAÜ™î]?ž!oDqË6 T‚¾Ä%„Ü ðô¢Æ&v‰"�#ί6ójnéþ4Þw²@YL`‘ÁñÄAŒäËP•§"û<Ïÿlû(v@3Ô´öïH;Ï%q2€9ª˜†Ñ߸À ƒ÷B¸“ªìÕ7¢õ•ÿ7ÜE>Š£8Šÿ]ü0úÝk¨–æIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_checked_pressed.png000066400000000000000000000022721526321767600302650ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+lIDATX…å—Kl”U†ŸïŸ¶€�` TJi^HuÓR^@ T£5D¤7D&((±°Ö� HÀš–2±«šØ@¥(‰VÐÎ!Aƒ!�‚¥Õ˜Цíœ×Å\˜K/3ÅïæÏù®ï9çûÏwÜë°lŒö¨À<*$–³¸ôœR˜Žšr»ü¿U†Fƒ%Æ šØ^]f?Ü�¦�fL뢢A§Ç<ãJØð ãdÌÂc®s,7c-Pµï S»©Ü~Ëš@óYÍóG žõ½ƒ´î\b#ã‘®—¼Â¯ìŠ�ëα¦n±]Ș@K�Š}F·`&p87̆õåö÷x‰S±÷²¦Üÿ'û�Z`ЃgªJíü„ÚÎhúp§ 0öô.â��f.›ä1H²Ö ÛÌh0èóeoøm Ñ&'ÕiØÇ>Ä s´ä{T€ÇFO¬”˜ƒá€kGs 91�™IRc H±Œ�#Ž6IËÌL£®@K·üžGø}Ș¿ÙoÅtõ’Wä=3>¦Ž1éA3Þ¯ZÄç‰IÚ/*oð.�«jJ­+¦ó½}ŸDiíJM^"`FÃ8Éò%ö ±_R|r•%6„ø :lLÔÅ |ÒC‚€?ò§Ò”µ(ÈÁzD¦Ør(ÈÛ‰‚êR:€KÀ“{x*�@رšÈ–­,±¡˜¼¥GÅ2vÙ�›ÆÇ-çôp|h&ÁÏã¥4ÏG¿ß%ÇáM 7‹Ô1ä{a6%I<¾@,M'^˜«IŒU“Hñ…“ÆC\‰*f§PTèñß(Z,Å“% ;G27gÆc?+D/Í+�Ù6À7^ìdâyÌŠ‰vš9Áµ» p=qpßÍhl£?vÀ%Îî9ŠR‚t1y$ùæºÈvšè‹ÉîÔœŒ*W$:)ÌÀdzÁ�ÏÑœ(pŽåÎ8‘NÀG'Dª¾)¤øoW[n?{c,³@ÆÅÿ£$kÌÑ‘F n¡õ#NfæÂƤ©ï]Dâë^?»E�«£MîÇêRâwƒÔ ß`¢¾íŒ¦Ç„›ý6JëZʪ¥£ù¬æùÝÀƒÀ7·§QõV‰ÝÍv,´_TÞà¿ìCln;Çsu‹-”j7fYºõ¨ó8<†qÃDýÕ[2¹”yE»ó úœ±¶ÖoçF³·®[Ïë†ùãÕ¨q¢SpÌàÊȾi8ÂÌ’Qè9VÖr§GTÕ”Ù¯cåÈìaÒ­§�G#ðl&ö‚óž±­ÚoÇ'²ÍêiÖzZsÉ¡"O3"O3‘•éœ2�Ž¿]Ê&î½�ÿ5…¯’Q*JqIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_checked_pressed@2x.png000066400000000000000000000050241526321767600306350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ ÆIDATxœí›}pTÕÆïÍfc€ˆVÄvÔ‘hetÍ.D†FcÛÑZ?‹“*²QѪ­mmu¦¬:V+RfŠ˜O`Ú®3ÊÔNQfD,cvʼnÇV‚Rj«õ6‰d³÷íðÞ»wï½›ì2�Ê3“?î{žóžç¾{r>Þs.ÆaÆr(iíÕc� u 3€Ó€“ŽB9R La/°Wá]QÞᯆÉÖ³dg©µ•,íI=“˜ —g�ÑÍN„�˜´Ç¢$ED‹©ŠU•ö©p§@}1} ô™Êò´Áº#’.¢ßâ #©õª<¤)–OWý K›jè,F�wÖtéq¡� \çA3QþlÁ`‡Âße„�0ا!2:BUH˜l*ÕLWå<�o•y=*[–ÄfÊãÑ?®t$t¦ €¯¸ïþ$Ê3¢<Û8KþSˆïø6­ s¡*——çiã3…… £òÛÂÕg1æ´%uJ+Pá"jeE^w–|a30ÛbîíO1kY½Œä«ç€–¤Î1”­6m³›j¤+ˆ¨¶¤^)Êà _ ÂwÁkjð£…5²9yM—W^FŸÂ”6n�Ede¾:y0Ú­þ¬0ÇB^‹Ê|?!«“Z†(7Ëú#Üd¡ã>4ÂL[p¶ ¸ñóÎm ê¬/¤3J³Ÿ€õ¯ëÑaec_ ¹:ÉïW'u‚/3Åo€w<*Lɤ¹1=oDø‰íV/š)ïxµïÓðð~6_÷Z ®+�ͪžSwS½|FîuG¾µ�«³¶ný2p±Å”Ng¸ÏS ª òPçÅ'æžÔãß 'ö³áíÏÅq|ê¾áÆu�¦Á<àóˆ)›×Ê¿¼mKp� ×û‰/D¹§¥[]_æ$ƒò¤Õf˜4ºqÝ�Ý‚Zñ¯W'u‚<èÅ)& a¹ßrWÅ®Yá·:9èÜ®±Ï¥ôj¬îp,”J�ƒÕļ»jHÖ^;y¨š'/'æ~j�°ÅôZcDÞuò ×2Qnó•\d(ÜîU>:eÚ~8Sró”9P8ÓaÚêäX1PÍ×€c½8%ÂŒ¶.=Õ‹ âЮœáääŽÂéŽç·s8v\íS^:„˜ëYnÚµ ŽwÃ-Ê4G%ϹŸRg�= šû?m+whW¨vrÜz@•íYùħ‘C9øÙ Ê ž„�íUNŠÛ4h#eLòæØšU uÏÖˆx vû¬;Áp¼O­|nıA …ÈŸðØ‚áæãPA¡|¼>r§Ál>ÿóFÌÜns£ûlÏbI¡xfŸÛ·P¡²˜†Δa+'·(öŒªp”�ˆø -Ä;#•Lv˜ö99¹ëa—õÙÔÜ‘Ó�>Ÿò’A}Ú ';*ô;9ncÀ›ŽJž‹ žò*/)|ÚVáÝ`‡“ã6€ÙElI‘ÜFRlòÏ%Ä®¦^õ"h®öœ“€ÁJ^¬çïç®éÒ¼ÓÍhf¸ÝSjið¸WJ¾YÕ@¹Ôf¶8y9=[{Ùj …Ž0˸øÔ[oQñÞÄ´ýÀ‰i j°¯Qööï%éäå›Ãm»(U.÷jlá¹ò�ªwƨ˜Påî†Ù2äÅìšUxÖ-=õÀÁ ¬À…­½ê¹ãÛ5À ”ç<•k›¢ö3A'šU û&M”7®kF=6YLF&ç8܆eõ2B9×oyñÆ¥‹7øÇU'¸û!Ìûý)ÛûDþ¬°ò+{ÛÜòD¯žäÕpÓ9ò‰©\B ‚ �1¹Òï8.Þ§a~á¨ûh¾Ó¡¼hŒ²Yíƒa¸Ìd©ŸÐE3åBÔ‚{ÄLjßMHSç—˜H qömïG™ý¬ÊÇ÷8¸ÛfT´÷¨ç²=¡?Å·~†Ëò3(>DX‹0ÏoÐX�Ô)¢ö#|X4Gòjr8Ú X�ÃÞÉ òktnשæ~–ªÐøŸìdñ)ʪaƒoŒH é5Þ§á�!6ç[̯ ¯{…¾èÜ®S3üg1oÛwÞvªì"²©ó°ÉÅÀ\„d)_-þa�(½OVVò¼s׿‡¶„®n²˜ÒÌñ»¹è‚D[�Öb²û�°ÖX„ëÇsA"¾M+ß?³�@ºêëÖ›³Ú®�E¥Å¯nàKRm �Øn\(<>©’[ ýµŠU•ŽnUåQìãÙŠ¦¨ü0ˆ�ÀÙœ¦¨¬UxÈj¸a`ˆM«“:%_½R!Þ§áö$kTù5Ö÷PžëOÙv½PP:kÒNîVái‡ùü0$Ú’:£_ãAçv�:8ÄóÀ"GÑ”s�×�' ¾(�kÙ`5+8»XZ•U¡ î_p¶ü»P¿�ÚÞ¦•å|å.„£­e ÓµAg�óUÙö„.RX…#1)�Rx¤<ÃòB.,z¡ù �TEL`iž3ÈåwrgÐûDVŒë²t{·Öi6+sLN¡ò± ÏÏ„3l*4ñ> ï¤Nà2®Ü–ái�%AFû|÷uùÖn=Q„Àwª8‚”’ɘTe &!ªMeº(ç!\éá3!Kb5Ò3ýÅû`"¡ß2á—d¿ *%ö(Ü;i'OŒ¥Ë;QÔOfšU�“»¹Â4¸ ˆÓ7ðŽÀrMÑRèM/”n=ƒØh6iúݼOö£‹Ž�Q^Ë÷~84ŸÍu뉆PoÂÀi’Ý®NŽ©ð©*{ÞSe;áŦY¼ù¿pù0ã0þñ_³tæ9Ê=÷IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_unchecked.png000066400000000000000000000017601526321767600271040ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¢IDATX…å—OheÀof’5"µ�A7Ɇ$›ñÐ1 ‘BÕX‹E¤MTDj¡*z„=(ð¤EÑ«ÁF­,éIJ•غSºÝT»ÉT#]”Ôv“�ïyØIH² Éš]/}§a¾7ï÷{ÃÌ÷nõ�J’[ººÛ€ýÙ-Ð$KaR 'pÚR{(—ýébUâ�÷oKA^gݳ–Ê‘Éìùï6$°%Ù{çm2û>ðl”( 'l£Ù¢]ØÎ cqLØ!b= ôƒ¶G%¾�úc"ý{ʼn.Ï ±�[#ðÑ í®�)®Ñ”Õ’ìyFEß’Ào–1û&'ÆÎ­[àî{SIÛè�&à‹‚ÜxþZ&ó÷à%áºnl††÷D9„r],kçTæÜèš�®»)¦ ßè;Á¥ô+€©¾¸~³Û=€Ê›@n®XÜþ篿‹¬åOÄôöc€§ªÃ„h�I‚~$êçS–5½D 9Ùýè`º@ìÀá [bæ0¸®x2õتˆ¼ èëùì�U€ïû³}­„`�EoaA ©}k3ðµÍ1óAµàódÓCã@ªµó¾ž2�:ÇÙ *_ù¾?[m@U9 ¶ýD™Ð ªßÔ^2@¾�Lv­  mb1Q+ ­ld’XA@aѨQÜáÌ”j ­DbÙ<ð?Ær™PÇÄkE¼ÖÍמ"šcsÀ6tÖJ@-+]åæï-2 ¢{j%-׈ȩ2Çq†#»Çéí­«e_I *¸ratJàHS À6e`z?ÔéïÖûÍ$˜4?œ iX§4$@^u™‰�š¯mf`ÂQm™Öê}ŒcñµZÍh:§�:íÚ{»âc€«Õ%ɘõïþdÄ©×^£÷I�²kˆgü[ß,cT¯Ý®÷IôÔ8‘DFkl³‰`08@ýÉnóx<6µO¢�¶@¦oGÍ& ``D]–‚ Ýf®P]]]õ*0á÷û'Ô>†X³¢*™–æG^þ¥¢b�iDï“h<«q 2Œœs… ÕêLA½�1L§4EÐ5¦ªšAÖi'´ë}Œ�KÝf#oÖûÌH¯]¢MïcH@l¡|‹õþûu+Ü UæËË;‚€ÛÔ)è°ÁIoèóû£ÌxKÓPÊÛô~³GíÚ ºåáHUÉ{z¿„ëLÚ¯(5›+/ÿ �f^ÇáÆ}Œ„ (°ZZ Ýj¾Éá^¿Ü\‰yE€ð%µA2ö&vLÀÕuÿC*S!ɸ~;|Ö⬭ÿ*u*S8¼ªôP"ß«Âôk��ðg͵Ÿ0Gbþ¸:×ÿ¹ÚFÀou E.túÞ`hC ën3Dæ“¡qËwAªÏ^ÂÀ„uâédþ©v†Äh ø†ÓUoXW›-8Wo(càAµ�™Ñú´a VÇ­O¸q²L@ RÜ5Ý¡ÊiéðõJ¢/W™¯�báï0Cg�§Ãán¸àïkŒÄ»Ò9¶“Ö ‘K‘óöÒò³m›Š¬·—T8W9Ëõõõ)«6ªtyàI¨ ¡@Û£I[©HûŒPt ×WTR±ˆ€Tæ cŠh´/_ùjôÃÐhº±ÌÀãñجvç3 <MO俇V–} Á`Zg3ìÂ;,NWû>ÛtAÉhŽt¶¶f/;*\ åòoêíû«œ,T,›ƒÁ÷Ó^ÈM»\ÁÏÑÁ_´/ë·ƒ°IU±T¾STâ([\RñßKƒ‘K™ÅM�ªªM -/ù‘ÿ 5ºêׯØvk¸ëøÅLbfTÖíý6˜žf @W%¢ÇÇ0º'“‹)ij²VžØÉÌ»¡:¯4cO¨³î¾«»Â‘Ó(¾/(MP=ð&q`£‡2M†Çã± �Y™h+€Û6Là ˆ�xWO íÙ,o!÷×X¥Ë»’!žx{Š‹Ä8¢Bâ´`%À‚¬1ŠFm—•Eb±=.cÅ�¢†­†Ä&n°$ť߰+ÔÑz,ý&þa¢þsü @½Y1Á@? uÔý1›.¯Ç쉌pº¼·t?€O𻓠{ÄGž5óŒbÞfr÷ºµ‚y'ƒ›¬Î2L˜ ‰°7t¦õ_ÈâÿÓ1#SÙJ—w¥„ØðZute—¶Wžq+€‹†Á8¢vf´CÄ�„þSÈÃ?Åæ™gžy&ù—4ÚÏm¬ikIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_unchecked_disabled.png000066400000000000000000000017771526321767600307430ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+±IDATX…å—_hÛUÇ?ç¦]ªâ:FÁŠ-›e*–èSm³´KšZ7D¶n ˆÈ Ň½ B‡}phÁ'e(РоZlµÓ‰¦IÛ4É‚EˆP*hÖ*«R×?ùå~Im›µKIê˾O‡û;¿óýÜËïÞß¹p«Kv’�¦šµ&•^�f  ÔW�,"Qqt(òÿXU€X<Þn­Âå•Õ+ÖzÎ÷Û¿©àëtº¾vÅyå™ÂÐ<ˆæå’�…ÕùU¯×šœ4"zÐX=ŠÐ(ä�:5œíõûÛ1@$?$y3Œð k¬ººüA8v¶ƒVU�H=�è ôg«æDÏ‘ŽïËOµäÅ&��ϼ5<ç÷ûÿÞÎx³FGG½·×ïå,ð�{$Lß ‘Hì]v˜ZUx³;Ðñ’ˆØ�˜¥ª�Lö¯¡d�Ö´ƒmóësÌæ—–ó\ZAF*1 uv ‚¼�Ðd�ó±ªn˜ô€ÈD² å4ȵ\�çt%æë!öÝq˜zb“ÉÇ·ôu7°¯>ÖÖöW¥æEù|¾UA_Pepý*¬Äbé»�G�?êï|·ZæE;ýCÀ ÂC‘‰ÔÃ%Vœã€ |áóùV« "Šê0€`O•`è•/«m¾aÌW˜žR¥@…Ÿv À;[›J ƒjì†}ZM--,kßSüKÎ�ÿQÄý¥B^wËÑ[__¬=Wÿ;H‘}JãÐèliix«ÜÚÊfÀÎXì KI,ðåQ¦y ‚×õ›–ƹ{D„.Jà²$%íºND­`º™`"k'Ty^©««K¹•Õ5ÂÑ„ ` €:·ræÁÛYÕÜTÿ’#¢dv$—iyBÀo¦Ä„²?CýoCË ­UŸa dDª'j#] -Ó5e†æ¸@Í09;5Ôòù�ú½¥è/É€Žx¼^kµÀgs4÷تÀ-)¯z}ACÃñbrÇãñšó…\,À’<Çå®Ö`ÃoG£(Á€H´û6/¬Êŧ ¤ ƒ'G›ßŠd2é;~òÌ2 0ÅÙNÊêÖ@ý#"¢‹Í]´$U$Öý(€•Ž& È‹ôðG¦ßÿN±y A4�˜ïý$0ÁÖ(ØÌsý·›¦y¦˜œE@RE¢Ý!¸ÅÑÔ«”¾±¹±±§˜|£E(‘˜*ilBÖ„+©ö°Õï÷Ÿ.4—*æÀ‘X÷ª�O(í©«TçÀôûßñ)ÝLÈF{ ¿2�áÆööv£Ð\�€H´ë„üÎv8pR÷˜¦9Ph7AR"ñžA>k_È5­Áy?($GA„¢Ýuv¨¶Ð¯´45ÜQŽ»³bŠ&¾'À:+'”;[‚ /�´ïˆ—ÀŽîîKÜ k牦ú—�…Î@kSÃS ~må(|®££kÎHûŽh€'Í5®°P½IßøI û\~Ðwb9(q íÓ†< …<Ãí;¬¡ÎDÄ]оzK\,\¸p0íåMŽ}DsÄW}ïpûå5€¤ˆàgz£ð'JRZF,ðûXm#)oÛö·‹òí“×€PgW3€€…JT?,Ye¹‘êàA 3¹jÂßΞ×C©­Ûþ2¬Ó‰e…išØOåþ|÷9 …z.'ðU •JyäQ÷d–GÿsèeÞ°PWLžzå‚\±9 _æ6 -U m»øý‡Ý•Y>´µµe@þÞÊ)òÎ\±¹/ÊbÛ&ðG×ÔUšÍ s]YœŸ1­œÏŸÜXn˜ÿn�ZAíåS§^ãŒË2À[3èà³P ë:ãÆ:DD´�8f$k�2ËCôlGªN·ÅU ʦ�JfeÇ8 _²¢ßpÆ\0P»v:ú†(âóÖm 5æÿûóAzœÚ§;c² d¢�ÈèSîʪ$Î:µOtFäø¤=HTQklc ­­­ƒÒÊ—L&­|„¶E9&žùË…#@ú¬[i爸€‡«X×ÎÍž=ûœ5&Ë!ì+ª†º¸,ê*€LMM­ƒêsÆdO‚ ¬ÛÂì™óB�'#W9¨·�1Ùû¬ÛB~Ñ]Y•ƒhØ´²ß“} {gÌ…‚vídÒ“=Rý]>~ÿNÌ %SË ¯¬ © Xd#ag\–çß­uÙÈ´,rÆ�uD⻯�ý�òi¤ú÷8ãò,‰‰í)JÀ%nŠ«Ú¡Y^7M3íŒËi€©�*jøpçù—ºª°Œ ©HÜlåÜ�+6§Cëþ²Ý’²J+¯óuø˜EG,q+€™ê=�êßž+6練Öò ;#ßÙ‹]é†Àr"™Lúù‰�Y—køÃ`çî‚}2ô4V¹!²œ8zêì·`ì=áaj}¾ø¼ˆI>ä ïØÕ™ÈZW+…öLða+'ÄO�@Ö-ð‡öÝ œ†àek¼lÚ‘H\V¢VבL&}Ê—ùì5D¿¨Æóôpû�øv؋̰®®Ó<)yuëÖ­Îâ¨OÇOõ=E²ÅB¥”ÒËF*ªÑ€¦¦¦#¾ÈàG¤°ñSµŸy†dEj�GB¸3q/!÷X9�,/¤l§à„;·C`¯¸üjrí„ûœÏØ•ÂP‰Lâ>PÖÁr2x²%àÿ~!9Š:ƒáήÇ!²Â–@$¢Ï7›fݱ|û•ÉdÒwôTß3¹Û¦‡Ø¦Óý‹òýí9QT•Ø‘w=p“•#Ù"ÞôîH<~u1¹JA,›rìÔ™�ÎÎØ«ÓU·Úy`…’íííÆ”ÏMû9 Î!–±Þ«2«›ššŽ›·ÄãñšsÚø.À•>íh~-Uí¹õÚºº÷‹ÉYJ©ìÝ×ð:šÎ�|¢Æ+k‹)X¡PÈoõR�¬‚½^i”µGÞ=°¢­­-Slî’fñH¬§™Ô¯¸$GóI[(ØRc`{±f$“IßÑ“}ÍY Á r݆§²¼%ÐðÂ(äp¡\>é™FC? à¦aÂR"€„´ðŸÐò/CË ¥Ïx½ÞÌY­'zÓª6mÈtEÌô<@®0)JîÖ”åóƒþ?—¢ßÅ&º®åqÊ=ö äLJ{T¥ñdºCÑw�¸_ÍÖ_c¡äì3ÿSášP,  ¢£­¡.é"±Ÿ¢:gÒs6žH?ª°H»ø÷•Ÿ%\�jØÖØ—~vQkìÑìSïLÄÖÞ,ž�á½[fy ÀªvÍ~ y�Í=éuÀ3ÀõÀšTO¹à¹k©êϾ…‡{R8ÆÝˆÀWÃ{·Ì”[ðÚ<_ €ÊSªúMÙá9˜è·Šm…Pë È••G'²ÍÈB¿Ú9ë´œádn寮É}ˆûÀÿo3W@!àø¥z¥˜îÝ÷äÆžÌí1yAþð®<¸RÆ•úl3žïËßUʪì\)Ÿ‘ß¿ôDxî‘ ”�®*ª²ÛCH�À僡IõÌ*o’j)7?zrjÐü2ÖÊ×sV�ÁvˆÐí¾¶ª\ð¦Ó—‚‚P£‡¼]q�Ñ×Ö]>¦Âù„N-}™ªJæF¨¯¾?þrö퀫�vÐ…æhMê½’$T¥¡7õ&&�O^™={X¤$óêA=¬Eù<àÈþáöª[Ű›N_ ÎÜh¦�5O^n ý8?oÑ¢tSoºÑU;€°H¨hg$þx9Ei´&ý‚ G€ ®jšÇc¡ŸJ_²,¯;õçš@æß^�³]q„A=ƒÕ‰ q’Ó¾{mpÆ­¶â®7°S•æl5 p6“‘ý¿µW]]Œ±¬ƒIôÄÔc⣠å‰åä£\Tè�…ÏÞ.µ¨£Ù¦ãÉ:Ç/{DÙR‹÷õám­qAΡ¦4V9R̸wvüw¦c?êz,3IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_unchecked_focus@2x.png000066400000000000000000000042471526321767600306600ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+YIDATxœí[opTÕ=çíf!Ò(ìf!aJÌfÅ Îi§: §mPZ‡V;*—P§u”�Ñ@+­Ò”i…$eÚ‰­2¥£–†¶:þ™vÚIv�BþlB‚˜d÷Ý_?¤tÞ{û6Ù;�I›óí�û»¿wîy÷Ýw÷Þ»À$&1‰ÿgp,n¨ïð2®-¡à:Î'q Ó\ ÀA/ˆ^§9Fò(!GšCþ“ÙÖ–55]%$ײÀõ£Ls’À›€z©%äÿ¤8(€Óˆ°¤¦û—† Yæln4Bcõ•ÊûʇŒ9•Ö1Jj:–QãV 9•3 Z)ÜԲֻ׉‘±Åu]nÁ³¾7L˜ð‡ ¤ Àq]´sJGŸ;W×)ÌÑò)R,ŠARnðu¹Ãä<"P•‘µ³?ÊDFwu|Y”¶Àl›â>¾Ê÷`ì­¦‡Š>N'wQõéÜÜiSoÕ +“Ü£”ûÃ!ÿ¯G!@”ÖtÞ²À”QÀö�ø”§O­›~~´ù�(khôÄ/øB"ò$_B¹%Üæ}›©ÒÍ�¾U¢ »ž"¸ÑR¢„¬\›#¡™miçMWïîÎÓ•z”‚Ç|ÎX&À~OŒw]ﻘNÎô ¨­´°{ ßµ”´SS«Z˜ý^ZùF‰@ÝÇE@ìõ„Wð7p/�<2³7Õ\Z:7.-Šn²iü»nÑ�Uã šÙÖß[`Ÿ©€ø"§êûÐ ®Ts¥Ü‚u�ßáo,µ÷ÄÜ—l½¯¸?Õ<ŽB„¥µÑÇA< s[¶†×ü0•)põÎîEJSGLýoEÁ+-k}÷dcv–.u�ß§p›‘#qoK¨`ïHuG|æÿ²m¦ÒÔ~à½AÏ¥Ðxh<D(x"/9ÔjºŽTwDt�{+€BÕ®¹´UŸY··)2ÐWIà¯ÖCªº¥Uâ®ê°k¢‹Þo D(ßn.÷¶g¢7ˆ©„þ¸ñZ 5árÿ‰Ì%fCcMJ€G“Í l ˜÷«¨à­*¦“O9¨3«O÷¾ l  =ѯÙÅÚàÉ‘»{ûd¨ Ë9‰YÆjê"|ÕH¸×.ÔÖW˜¯ñ{çÔ� eÕüM»× Á€¡Sn2rJâpX_Ön/x€±×æ{;o°Æ%Ð _à1P?QQxÊ7î±™Š éÁ)åJX§L0@4\kaŽ8­mÌ 0i× ¬!6c¯±„„c&tŠI»¢\c�±ç™®„ãþÛŸ z̬�`±5&Áy¦—êq^ÚáŠOÌÚÅÜ6ÀÆe1@âHk�m<¡uͼqå)kh4ð6=@Ì‹$ta\üæÏÇ }¦k&v›‰‚y/µN`\<ºúÚAcL¢ÓŠªÒµéYQ7`üŠ|3ay¸°7à_æ:’0rN¸t\e"DZ­16!9f¾V¥N +h.X´³)!ÆJ4o6 [c& ”˜t ÂFkL‚9ƒ|€qÿ}áÐNÌC•h–›8M²†%pt½ï"ˆwŒ%¾Ü7Þ,ì¼æåÞ¢¶‚¬qÉ–ÄL¿¢dh{zBAà2i&ä­C›·ÆÙ iÚ> jøOeܨïð:®2[¨ Pw˜8j{ìBm h.÷¶“8h ¦hqͺ>n(ŒÞ pþåk�sÚ¼íb“ï èò ã¥ë‹wµÁ1•YBYC£‡ÀOŒœ(l³ëþÀ0´T¼m =nåÚäŒÌì!~Þ·€qòvNsk;’Å'ï¤Ô�,ì=%uÝ ëjãÁš3³„ò„‘£à§ÍåÞ„)ðe »7 Í>Dàec¼¦ô×‹ëº 2Ôê8Ê=B×oa>Cô�<ø¶WoäÝa]ƒqu•œ›#x-°=l=õ™"Öã}àW�5éP刯ôG…r;€�Ëœ7qjÞ “³Æ#!PÛµÀƒFN(•©ÛI¹�Ú®» ˜O\jsft?lý�=faim÷àlƒña Ÿ Wø~�JŠ´ž`im×36XT¦èw´Tžµ­”%”54zâ=¾Rn)úcáßòdŸ=+Òë â*퉾 `•¥¤Õ%²²©ÂÿÏ´ò�%;:}š‹¿ƒyû>Šåx·Þ7#å…Üôßáq{¢?ÀÚÅb ìPql9^é�¦�7UŸÎÍÍó°Ñ~X6À‘sjó�IAðEM–W_é´¿—^h/iõ�òÐÌyðDO‡MÝ`ô¬Ö¤Wq±ãý+�ñú~3WŽxÞ$ÙHŒA3Þ1HøF¸;dÉboa£´Ï!Ä`¢q3S_C&†MǨ¤}À‘I…€nà÷”Ñ]‰x1D}={�‹›�ÆyvQßãÝ\+ÞÞ²¿*ÏÛÎvK!Þ >‡Šg¡ðòi\k3bøãŽ:Öîl·Tµ ·ŽÆù xÈ9ÉGEa²ŽmÐWՇܯŒxÏçËç�ñtðü¦Úâóø±¹š¼,—WJßRLç^h*PPèÉ’–U²« …¾ïË/Ä’}àÿ²·‚˜ÈEÔÒ¸R¢õWƒ¾�ÙüS<¿È±n¥jm&ù²ù5§‚Ê­+à[œq²ÀgÀŒçÇUSmqI†ÇvsŒ• ¯õ¾c¸øüz={ÛíZ9âÇ.¨vî_!v×�ã©��_è·hR�ÔÎcxcÆDäò5¢ËIJ×ÅxA÷$œÑÕ²ïoæ¿dZ>2¥»IóÆ‹�s1!8n0�É�ôëpdi”Ñâ9¶ ºÈeÃ'=}aûu1�å]L&õ¸óž\Ž¿`Ê3{CvâV¾e]ÍFΨ•Uì€ÜÕŒÜÕÌ'73 Áióë ÙÅrú½½í?!ÍJïõÔƒ¼IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/radio_unchecked_pressed@2x.png000066400000000000000000000040371526321767600312030ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÑIDATxœí›lUåÇ?ÏéåÖ ,¢nQ"ÅH\@Íh •´f‹Û¢8ÝÒùcÐR:—Í8L´°‰ÛØá�1Vé�,é!c™Žd‚Áaí-l.u°°Ù S³¡–ÒRoïùî�;çܽ·=·+ŸÿÎó>ïs¾ïsÞóžsÞ÷=p‘‹\äÿ‹“4ÒeN‚E‚ë�뀙S“ =@�ฉÃfüÙqÙ¿t¾uå[[ÞÐÜ¡kp©‘±¸a„aº0^Ä¥¹¦œ3S˜!äH²æ·ÉxÌ 2ÌØ�®Xwx~E™ÅCŒ-ª”X'( +fJŒnÁêÚR¶…Ñ#F�€†6]‰ð âþ n.â÷À>ŽþfƒœÄá”"$4HqĘâŠfIÜdðY (mD±ß`eÍ<{s4úG•€–˜æ¹° ødŠâSÀoLì6ñRõ|ûW.±[¨¨/Ê­w‹ÓœãŒ`Ù²rûyîê‡qš:t¢(L!jSa!?¸ÿ{¤ñ½´v*Ú×O�Ä“—Ëk�•ñä37ר9' ^rJò”Ī@‘k¢1®ÂÞÎ5n6l}UÅN!�<*˜(ÞÕWÄ’‡æXo.1sJ@½äÌè`pO è„wU—[{.ñFJC›®šPÀÎà€+øC4Á-_­°žlc9¹œxFŒÕ/Ú"FÙX5 ®ÂÞþXœE;¼vƒO:ìhmUA¶±²N@c»¾‚ñ„Ï(Z8Må’2ûG¶q¢j�õ×”²Äà;ÀùÇ¡ŒÛ{Kx:Û8YÝ[_W™ã°¸ÄSñùê2–æãí,Wšbú&°Ák3¨®)·mÃÕ¶´¼®K�vái<Ю^êÆCãjÊØhÐäµ ;4w¸ºÃ&ÀuX‡¸Òc:ápWm¥��Ö¼`fê™ÊJà€Ç5ÑP¿W‘Lu3&`k‡Ë<&áð¥åsíÄÈ忇o\kƒ î6ø§Ç<·¤˜3ÕK›IV ¾ïµì¨-µ¶QjÍuö®`­Ï(žØö†&¦«“6M1 zLñ„¨½Ì<ÓËO�ãçÓqV¤sO›3¾í;†-ËçÙ[¡ˆÌ#µ•v†ä õHºwƒ” hj×'€ÏyLñx‚§BÒ˜w&v³ãèyƒ¸²÷>“Ê7up¸øOÆÄËuön¸2óGU•%¿ðÚ—êT¾©0ô êåWáH;d~Í‚/¤º ’pvÄ\àsrøuè ó̱Rb€·×Né/¡4è—”w€ ê1ý±ºÌŽýÆ;gç|εäyʤæLûÕ6vÈÚÅì Oò`|*p|4ÉçBÁõk7m#UÄŒ@¥qÿìOGP» $蓪ûŽÅa 3N'i/º¤z úœ.9ͱ�'jnaÀ`ÐcжvÊ;À''À“$‘ãâ›?_$?‡æóÏ#7¹Û\(4ï£Pà�ø¨jŽ}äõIîÂ?£jLÍ�¼ü3XÄ”€éTÐ'ù=À8æ=v•ƒèú¤*]²®1CN@»Ã‘ Oª§€o±ÑÌ7)rA¡dí�AŸ¤ôñà]ŸÛЦ«BÖ–wê%q»Ïhì ú%%àìÚÚk^[$t0#F)þåžî:‚~é¦Ä|_Q‹CÔ6&~Í2^ZSiƒA¿” p Øœ_j6¸µñ�. ]ež¨—_öÚL´¤òM™€³óþ{<¦B'‘´>n)‰q/C»ÑÎñNw¯¯=çI?+,~ì=<ôÜ!]ŽÄüÑÚ©¨ŒïymRuÈ�€êr^–0Œ¸¬GfþèíçüŸ½'lNçŸa]Àdð¸Ï(–6TÒ¼ÚxaK‡¦™üKøf<½|¡%½Ÿ#ãÚ`m¹í¶{ýå²³¡MWŒJihíT4*~ØCô§Ø”©Þ°«ÃQÅ?»:=RÀ ›Ž*¸9ê¿Êé~67{Lqê†ÛT9l–ÞhïáðE`Àc^Pü?‘4&{�‡£©]_óÚ Vf³m'ë4Å´ðí¸ülR¿±Ç IÖr�‡%6࿘ÏÖ–Û·²‰‘õ¡ÚrÛ.X絇ÇËvÜ‹\ä"ÿ›ü™•< ¶7IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal.png000066400000000000000000000002311526321767600307260ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+KIDATX…í×± 0Q YÂÚÚ2xÀÕ²�‰’ò®ü ¼V*¦æ¡æñºßš Ã*îi£sô3è|F»¸SÚ­ÁÓsƒo€IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal@2x.png000066400000000000000000000004621526321767600313060ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+äIDATxœíб Â0Ño†ˆDKÍ4¬@ÅDlÁ4Ôi` SQAe;‡Ä½Ê…•|_"韕Ñ?Øîö‡”rN’Ôzºß®—ž÷[mF~Àë1ŸÎ½î7Y#ÀO3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ €@3=€¶F€Ç—s¯ûM†¨5Ç$s’y9w½/I-žÎŸ"0�íªIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_disabled.png000066400000000000000000000002301526321767600325540ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+JIDATX…í×± 0Q ,ƒ´°p¬l`¢¤¼+?¯U„Š™‡š‡¾î·fðŠ{Úèý :ŸÑ.î”vçé_Ï~ß/IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_disabled@2x.png000066400000000000000000000004641526321767600331370ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+æIDATxœí�± 1Å^âvABbV b"¶`$$ö¸Š-BqÐA•䌄]ýâ+ñw""ÿLýÁõv?Ô”óòY=íwÛKÏýV6#O’×1S’é}XÏýV†Èŗ¹×~køi @ Ѐ 1-@cZ€Æ´�hÐ4 h @ Ѐ 1-@cZ€Æ´�hÐ4 h @ Ѐ 1-@cZ€Æ´�hÐ4 h @ ЬàñeîµßÄð%9&uNê¼Ì}÷EDZxL"0W)IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_focus.png000066400000000000000000000002331526321767600321270ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+MIDATX…í×Á Fa‰Vq�æt– }\¢6°”Žï¾«"”LÍ—š¯×ýVÏöÈíq­rô3(|F2“;…¦J ÑLZ´IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_focus@2x.png000066400000000000000000000004631526321767600325060ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+åIDATxœí’± Â0Ÿ"LÀB¬Q0;°U˜ŠDT©°�CâNŠäâ+¾r""ÿLé}Ááú<æ•ËrÛù~ÚßZÎײëùó$Y–’ ŸÅZÎWÒ?À¼ÌÚ¹Õ|[øi @ Ѐ 1-@cZ€Æ´�hÐ4 h @ Ѐ 1-@cZ€Æ´�hÐ4 h @ Ѐ 1-@cZ€Æ´�hÐ4 h @ ÐtPJ¦µs«ùZ6xeLò˜¿2¶Ÿùž7ñ8>‡±IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_pressed.png000066400000000000000000000002321526321767600324540ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+LIDATX…í×Á Fa‹kS À¡lƒLéøÞñá»*BÉÔ|«ù~Ý£FÁ0“ûµ^9ú¤?£&²2;E¦Õ5ŽIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_horizontal_pressed@2x.png000066400000000000000000000004611526321767600330320ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ãIDATxœíÒÁ Â@Ñ¿‘R,Ä$'+ÊÑ,Ä2<ÙE<¸àA¼¸»ÁyH`ÑŸ!‰¤VFÿÁùº’,õñtÜ—KÏó­v#¼ZR2¥dÊëÅzžo2>ÀóEÞï{�o´ÅðÓ @ €@3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ €@3=€fzÍôšè4Ðh Ð @ màþá¾×ù&[˜“Üê58/I_{½8¬ÞÜIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_vertical.png000066400000000000000000000002161526321767600303510ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+@IDATX…íÓ¡À Ñ….Ðèô€¡kfRD4:m �X¾Ù§Î­:�$K{”ú¼@»Ôÿü:@¾”Ž|�$Iáp�  –ÇIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_vertical@2x.png000066400000000000000000000003211526321767600307200ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ƒIDATxœí×± Â@À}Š@�S -¹"wB#äÄ/7ñ¤ÈOjŒì™puÁÞe—°eœ/×[J“W賤ÚZîõõ||†‡nl›Ë'É©”Œó°?ÀÎôhmH2ý¾ÊâjkÖ.ü¿@7¶Íå¿Àw~vâ �) fšŒ¥IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_disabled.png000066400000000000000000000002111526321767600321730ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+;IDATX…íÓ!ÑáT‚ ¸µ÷‚cI¢J™Ÿ¶MZ�$}Îsu <ê¶’Sˆ�‚Ò•/�$é» ? ÿ!û–IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_disabled@2x.png000066400000000000000000000003231526321767600325510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+…IDATxœí×± Â@À}Š@”B€D´@äŠÜ 9’[±hâIÑ›ÔzdÏ„« ö.»€ý(mð|M·š2&9v賦¹$÷ëåüøíÔF—O’SMÛpq€½Y ¤IÞº¬m.)CïÀÿð ´S]>ñ üæ`'>^“�8ÎIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_focus.png000066400000000000000000000002201526321767600315430ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+BIDATX…c`£`Œ‚Q0À€ÆP�õj?Ã:Ù»çvš¸+�,£'Í£`Œ‚Q0 FÁ€ŽÆ ºµIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_focus@2x.png000066400000000000000000000003251526321767600321230ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+‡IDATxœí×± ÂP Ð3CD,ÀB¬€(2Q ö`&,ñiQ"Ê”¼Wž\œÝ9`?jœnÏsZ†$Ý }S•1©ËãÚÝ?óÃlrƒË'Ik9¶Ö†i>?ÀÎÌP铼~_eYU«ª_»ð?ü³É .Ÿø¾ò °oŒ"œ›Ñ-IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_pressed.png000066400000000000000000000002131526321767600320730ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+=IDATX…íÓ¡EÑÇNºb›YÄ90I)ï¦ß^ú Iú,œÑæ@~í5…_¥_ IÒw0§ ùFƪIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_move_vertical_pressed@2x.png000066400000000000000000000003161526321767600324510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+€IDATxœí×± ÂP Ðû �X„EØQe¢”lÁLe‰Ð¢Èmʯ<¹8»s@?Ú:x¾—[’1-çúliJò¸_Ûë;<ƒG\>I.IÆuX +Õ†,™Þd{S’aïÀÿð ƒG\>ñ Ôütâ#¹6+ÐIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal.png000066400000000000000000000002241526321767600317620ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+FIDATX…í×± Qb\‚šÚÜ„Õâì¼ëùy-ÊZ�µšlLhØð> @€ @€ýŒÎÅ×]Èȇ̜ÚIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal@2x.png000066400000000000000000000004401526321767600323340ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÒIDATxœíСÂPDÑ Ed‹¦Z@Q]P ]A6‡ö¨çþþ›TÕ?ÔÃÛÝþ�a8'Iæùt¿]/bÇF<š$ËçÇ$ã;à¼>ÿé^• ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ð@Ðd€Ç—{U,À<ç˜dJ2-wUÕêž ÞP{3‡ÖIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal_disabled.png000066400000000000000000000002231526321767600336100ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+EIDATX…í×± QbÌÁM° `,‡8;ïz~^K„�Nužê$¼�A @€ €F?£ýDñuåÜM p°IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal_disabled@2x.png000066400000000000000000000004421526321767600341650ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÔIDATxœíб ÂP…чÈ.‚à®`åDná‚à©Ü"ÑNÛÁ{ª¿{÷}IUý³A=|½Ýs†ó2b>íwۋر�&Éëóc’ñB`²|þÓ½*à'4€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ É�/÷ªX€!9&ó”ÌÓrWU­ï Ë�PìôðIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal_focus.png000066400000000000000000000002271526321767600331640ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IIDATX…í×A Á ÁJ} ³ZHê§&@Äñc÷ßË|+‘QdWd—³1=ÂYÞ½4Üp3?#í'Н»Ec�ÅæIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal_focus@2x.png000066400000000000000000000004421526321767600335350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÔIDATxœíÒ± Â0DÑ3CÀ,Ä ˆ‚‰(Ø�…è¨` (Q¥ÎCâžÉ�Ï_IªêŸ uñþú:ä�˼â|?ínbÇF\š$óã·I¶ß€ 0=~é¼*à'4€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ 5€ ±cä¹t^üÆ1ÉcúÆÑí¨ªö¦øTºIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal_pressed.png000066400000000000000000000002261526321767600335110ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+HIDATX…í×± AƒŒM³RÈPaÓñßǺ6EuFu:Ë4ló^Ó7ë3Òyù· Dúˆ�ÿýáIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_horizontal_pressed@2x.png000066400000000000000000000004421526321767600340630ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÔIDATxœíÒ±mÂPFÑß Á(„ �+&¢Ì„1¨Ø‚±D¥õ‰Ä=’¥çê}¾òL’w¶¨‹?oÏÓÌ\·×Ëùcù;âÒÍu–9Î2Çy…Ø� ðóá¿Ï;“À¿P=@+€ @Ð  hдèZô­z€V=@+€ @Ð  hдèZô­z€V=@+€ @Ð  hдèZô­z€V=@“œw%¬3sßžîHòƾ³Þ T {IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical.png000066400000000000000000000002111526321767600313760ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+;IDATX…íÍ!Ñá²ìÊÞzßsYv ITóÓ´I’^v¤\P/}ÿ9ú/ %I’ŽÀIªv žIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical@2x.png000066400000000000000000000003021526321767600317510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+tIDATxœíб Â@À}Š@�S -¹"wB#äÄ–›8Rä�mKx&\]°· pm\o÷GZ“œw賦©*Ïéó~ý†§îì?ŸO’Kk—a?ÀÁôT Iæí«¬nªÊ°w `{_ç­úbìòIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_disabled.png000066400000000000000000000002051526321767600332300ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+7IDATX…íÍ!ÀÐq*APÜÚ{Á±$QUì§µ�$I¿ 'Æ\(�¾­äT⣡$IÒÕ“¨‚!�ãIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_disabled@2x.png000066400000000000000000000003051526321767600336030ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+wIDATxœíÐÁ ÂPÐY‹Kñ ؃-xJEéÄ» ¤•`ß«üœcÀ¼wö0; °ÕÏ×tk©1Éqƒ>kš+¹_/çÇwxè¯þôù$9µ´±ìÍb€J’¼7è²¶¹RÃÖ%€ßû(Ï |lMIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_focus.png000066400000000000000000000002151526321767600326010ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+?IDATX…c`£`Œ‚Q0 F:`„1Tg½ÚÏÀðß�Nöî¹�&îÊÀÀÀÀD' GÁ(£`Œ‚Q0 pOsÐÃïÉIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_focus@2x.png000066400000000000000000000003071526321767600331550ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+yIDATxœíб Â@À=аh€†h¸"ôA1T`hâI‘?¶-á™puÁÞ&ÀÔ2¸<Þ×´LI†ú¬¦*sR·×}xþæ§îòŸO’Örn­M˼à`ú*c’ÏöUÖU•¹ªÆ½{Ûû-fÏ5ÔIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_pressed.png000066400000000000000000000002071526321767600331300ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+9IDATX…íÍ¡Ñc']±‡Í,â=Š¤ŠŠûéÚ�$I¿ 'Ú\È�¦½¦Pâ‹¡$IÒÍ \˜ª¶QIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/toolbar_separator_vertical_pressed@2x.png000066400000000000000000000003001526321767600334740ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+rIDATxœíб ƒ@À}аÜ�Ð�刊é‚"¨¹ Hú�ÌL¸º`oà Ê1çµK2¤äuCŸ3-I¾Ÿ¶Lû°©þãóIòN2ÃÚ�R ÏšßåMη$éï.\o±õ D-ÚQIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/transparent.png000066400000000000000000000001501526321767600263260ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/transparent@2x.png000066400000000000000000000001651526321767600267060ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@�òÉQIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/transparent_disabled.png000066400000000000000000000001501526321767600301550ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/transparent_disabled@2x.png000066400000000000000000000001651526321767600305350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@�òÉQIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/transparent_focus.png000066400000000000000000000001501526321767600275250ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/transparent_focus@2x.png000066400000000000000000000001651526321767600301050ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@�òÉQIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/transparent_pressed.png000066400000000000000000000001501526321767600300530ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+IDATX…íÁ‚ ÿ¯nH@ï G ˆIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/transparent_pressed@2x.png000066400000000000000000000001651526321767600304330ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+'IDATxœíÁ  ÷Om7 €w@@�òÉQIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_close.png000066400000000000000000000014561526321767600264730ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+àIDATX…åÖOoÚvÇñ÷‡ä°UI$ Gàèäì)LZ› &©T%é){•övìm‡­[´õß2õYôž&$i·@ÛM �bm»”ïÔÄ`cìŽË´ßÉØæ÷~ùg0Àÿ}Èß(–ÝO }cð±Ì¾j6jϦ*”ÜU“¾ü-z_ž×�ŸdüLúXT�ö‹ew}Zñbyyi_P\Sæ[ÿØ€ñQà=C�¦�(–—7 {8ÒºÐ= 7MD±ì®‡âÐ3qÏ1ãoxÝÖéBÖù ±ÂÕgC •…ë¹W—Ýöqú¸�Æ‘m]œÕž„—ÝV-‘I‹x82ÙVó¬öSðÜFF‘?‹BÌ-æ^z�x„Sq×è_ùÄx$ �hE!„VãNÅ]“…â6.>à#æ³ù:âf„SYº%Óãˆøæ¸x,À‹EäO½Nûä*Nê8�IcG¡âÞÁ´Çð'ú�‰Ûcâ[ͳÚ�“æNˆAôÀ÷%ŽÃ„[^§}8¿˜k€FŸÁ‹HO ê#ˆAÜÐöEý(q†—3Ùèeþ³ˆ#†ø3ít©V PZ®"{ŠzŸÕ¹EçÄë´N¦(”ÜUÄS`6°Û_‰ÀW”ê|Ö9öº­Ó$ó&ºý¸BqCw m 3ÈžJËÕ$sO\�BÙ]Aú9*~Q?Üóº­s×�7‚;”l%b…²»Qq>¿¨íù;b«óYç$10!þÃèù}DþmZD$ P^º ÚO¿B´Æ#rÇ^·B„ý8¡¸Œ/š�ññ b!›ÿñÙ0BÕ(Ä XYºü?o}?)î�ˈÀ)¹Ÿ‚žýÛø0"÷R±°è\vZ¿öwøG¤ûá¸í|HÜç�Ú™í0üœ˜µžÝt5,ø—ü}¼öàCãq@CÐD¶5�x�lÓà㵡ÝiÍýßÿ$±‹¥N~5íIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_close@2x.png000066400000000000000000000032771526321767600270500ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+qIDATxœíš]s[W†Ÿµ•Д´N?œJ¶Ã…e¥™‰e©iCK��ÆIã„Ú ?€áGpU.à‚ÉEoú7úh:‰eÙ()P –äÌ0ÖDZl7'©ãíÅ…­ÔÖç>Ò9¶™ú½Üg�µ×ój-�££{ÚÓž¾É’F‹áDâ <Ô_L€kvŸ|°üÏLi{ËëLác‰AóDßÞ©êåÊûá­7ÔÆÖÐ{ìØóûŸ|ëSàDÍ¡{ÖÈØò|æÏÁ”í�"ÑáphËav�ÕÝÍçW6/›ÚûŸìŸzx€CÆêdøhâ-? öSMá”ä3<ûËÚå:@.´Ø£g·šÐ¾*åbíR�϶٫ÇX�Œ &ßô\e@ê‹ÆO¶…PÔ.Õ èg{öˆ±©Ý`B_4~‘)ÚÁ¯«Ž­Î€�î»ÜsH¶ã&x„_ úMíb�7‹×çÕš³¸›°#ã°ß¾í×µbEÆn¯Ï×hxL¾)Ʀ€‡ î©Úw—ŠsuˆíZ}C#oSÀ á÷­ÈÙå|æóF›»Ó?á¡�°»LðÞlÕRiö/ÖÈY`¥],pHĤú¢ñ“±žÔK¼¤p„7ÂX;xp耪ÂGo«“8vªg‹¹/\ó·R,ñºªN/:„ß7ÂØB>{Í%·³áXâ{Fõ*Ûh‚WxAÏ• ¹?¹æ÷d<5axÞ!ü?¨¾Û© á:æ:0:0Î,²ó²ÇvÀC‡@°&ôÇ’'Tmš€áÁá*ÐLËùÌçFî;„¿Lm\ÆZÊ;¼õ4óµê¸ªˆ�¼m•«øÐ �ÁϹüxkªŽ; ª…|öš çpï„ÔÆ5}‹úcÉŠužyÔœï|耪ú‡âßWä*ðœCø¿EäL9Ÿù;ÀÀÑã¯Y ¥Q^j{¦ò̹Åâì»,ðÑèÌ‘'v§àÁgÀ£ ¢+ª‚¸ÜXÐ?4üÅ\Á­ÚKyˆÊùÅRæ¾äÛ¤@ M|¸ 4S¹0÷jÎuF8KyHˆŸv@U}ÑäÁ^A8èéÄ*ü|ö÷•lƒ°n‚`'UÚ>rß�>ÂÈXÐðàlVH++Vä±k¼Š<6T\Àt­À 82OTŒL êòôQz¬†ÒG�¿dmðTá�—;J Ü5R9½0㺿•}­À:`ž4�Â(/Y ¥‡“þU¶U�t@8:2bD§Az}I(Ü5;ºPš›õ%ß–Ô>˼®m”ñŒCê;ÆÚÓ~›àëxüäWU8Çú#÷¯â_¶Æø>¾u@x(7Øgxì{K…¹€HläÇ¢||ÛáÜ;!«£7K¹LWoȺ�¯j§Lèz¼Â[d¼`)ŸýTEßÃq*F¦� Æž ®QW¬Ã»Ï¼EÆ— ™éfKùÜï¼™@º[:6àkx;„¯•‰VðUm2aµ}Zé­ÒáèȈC �3trR$–µ3¸Á?2*ã ÅLÚÛñwDåÚ¿³èm«2º\Ìf½ì°ðO÷>%˜Ëh‚'6à§�W»‚º§W0§– ™œk~çï¯ð¢Lt °T˜›±È8Žß ;JÄ]ó;u@$vü¸hhðåbvʵ…‡£ýŸ;¡mx†·zÁox€åBfÚ¨LàÜ :íÒ ­_’ê¾”K9Äv¬�hâ´ýêßúl [mÕ M;`Þyæ½4<ÀB1“6*ãÀ#‡ðÃ�ŽÄ’ÃÍvÀ&ø°Ã&kˆ^XÌç&b}“×NP1§–ò³sµê 8òjr R±_‡Ä;_UtäŒ ¿ÅÍ„/=Y.äþµy±n*û+þàÊÅì”(¸�Ã+ ¿®]lôðŽC²5Ä\ÜIøªÊÅì”X½€ƒ ‚œª]kd@¥Mž øÙ«Ž5®r)—r1A°Õ ´úT×@~º›à«*—r)D/ÒÒ¹R»Rg€Ù÷ßK…g¯Ã2uIv‹ó¹É¦&(%•Ð¥ÚåPíÂýÛ·WŸ;ü��ÄV"+¤�ÈÏ ÁýKë—Üý²p¨·÷²ª‰/‚ÜÕ�ÔìÿÙRþ·vº¾=íiO»KÿŠö)ve]6IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_close_disabled.png000066400000000000000000000013741526321767600303210ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+®IDATX…å–ÍRÓ`†ŸX¨×áR×mmk [*Œ†2ƒÀŒ×à’� ~ùÓqÆ=ÛÐö&t§w .l^ÐNHš6ÁnÏ*“œï}žœïë4ð¿—u/¼ÓÓ[ê8¯0®zá– F òÍ)a/A¿‚€ç“· >€ÓmPà¬aÜ® ;ðÍê¨àÇ~kFØpì†ãØj÷™ê»ºv„íŒBâØo͘x{‘¥k1�ÀX‚QJx�f5'@ÎrL`²˜�ìi‰·—‘ðͪ°�(\F­RÎÄ*åÜ»>cY%Îá±7—Q›(æß„{�>å5Ú�…¶#C�ÝRaüáù›� ƒ' \V".³ýàDÂ/”[Êíš%¾;^£ù0ÚRo?È ‡è–×h>¶‘í {Ô=L'õöLï²ÂS û­§&6ûIœ¥ÄáˆZ¥œß–�J QÂ,0@RX,5<“@HbkÀºLðÌ= ØB±µ2Ùœ[ÎmeÉKü$•à§aŠÞ7L�£Yó2MàÈoM;bOhéȘ™(æG.pþ¾�Ë0„Â9�À¨NóïÓä¦Ú‚ðyÄÞ’1Gìù­é4ÙC'pRoßÇ´ßî–r›g‚íšÐF$/Õ$N .ÓBà–r›†ÍŸÄî°I$ ‚O ¯£ýn)·)ÓBDb|˜Dß-8þܾgŽÒÂ/¬õ›s&[�dÿ6Tí÷¡H‚c<«óƒàÝ:ñ[óˆµ4ŽüÖ]Gþ <«Dïá‘ß¾ãHGï–Wo-ÈX�J MUÊ…O:„ŽX‰ÂM,^à–óë&‰LÌVzÜÞmSøËG&Ýr~ý²ð!�¸€X¾ßµQÀÃ2f�oÀW3[Uö¿_¬3vÔl=ØXIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_close_disabled@2x.png000066400000000000000000000031741526321767600306730ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+.IDATxœíšËsÕ‡¿s*&2BR•U¶‰y1ÓóìéAXæ!›¿%+² Ê‹l²LþŽTÀÄzÍH=o™¤âß§{»{F §9Íi¾Í‘aƒËË7Ï~çìÝŸƒ.¡rC[î˯|?óñ¬œ$››ÝŸè#ú6–,¢÷DÌ5»ûÕ¯ƒ ø²F£ñø}Ý}ñ�Ê-‹.VŠÙn‚½O��æÖËX»Šp®ïÐÍ3�PòS1•Q+áá¯ÉíÃW�:ôuO„+~Þ[q˜;u¢J°HP)¤ÿ>ôè°Áhð²#¢—gßK\¬·Z?NYó!ð#‡ÂÇßK­Þ^‘÷p’À§²gæ}?ýÏ£ƒAcÍ/ùÀÅ욪.±ý—g4¥ïô¾, åñµdÇšÙíùQ9¸ã\ÆMBÐ?0ì6¸7ºÆ>|%—Yvip9¸ó8Hжa+`Ä_UvT÷Þ:Ið½” ÞªW%A¹Þ?4 àëGå*È??½sENJü¼·2BÂÇFw¯öXÈd>ׯSžÂo€O€O�ßks'¾?ï­¨˜,Â üÖØÝL©Túì¸û;ÍiNs²ò?c�/ø/IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_close_focus.png000066400000000000000000000013141526321767600276630ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+~IDATX…å–IrÓ@†¿ggÀÊY+¸W` ƒ¤â$xà©â ,³ÃR2&Uœ�C«`’Ø ¢Ç‘ñ É’ã Å[I­îÿû¤V«ÿ{ItpÓöXŽð²S7ÞMTvüy”W(¿ E^|ª Q‡º)p0QÚ–ãU¦·lo¥ ˜·ÂP7þr{%×úÆTåp–í-(r0ĺ#ÀNSÂr¼Ê(œPUÖF: ã ÑʼnƒI$,Ç«¨Êá\¨ºÍR{D SŸ=Š‘(數„�Þ¹PuëÆ~_!¦Ê-ï)"{CŠFâbD Ô°‰òøÖÝR¯�èî¢_�/Ñæ´²ÿýúDf€r¬.IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_close_focus@2x.png000066400000000000000000000032551526321767600302430ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+_IDATxœí›Ës[E‡¿ÓÎP<&‰%¹˜Í”+ÅäA Ô !N Nò7¤"ÛUP,XÁTlXÎ`YžÍü¯JlKÞoŠç¶d¨Ô,,[¼bl« Y H²ÔWº×öÔø[ö=:Ý¿ÏÝÒÕðÁü?#µwÿ+wÃü¼<ŽH¯¢×ŠòŽ1úìD<òÍj/°bÉÜŸ­•'T8 È‚Š¾rÍyî?�„.UÖV ˆý3“]²¯!ì­¸tÕžLä½ÀVîÝCÓw*fØ\qéS]Øô×ìc[çÊMeƒÂ’>Q#<ÀfDF¶'rû}\¯¯Ô °Ç\÷Ë“•ƒU=QgŽöõ*¡AxTÍÉʱ*×5˜«‘‘îáé»<¯2 bƒù}�ÂÑk+Gª(¼å0g»Z3º$Äóû¬±c4 ¢ÕÙªX+g�‹s¯¹/á�¹%•g*«|=ʈ±Gp—°&Ça9¼Ã¶`NE{¾e*/Լ螾K­Ú&¸(Ø'û:?p¨m™®dþ£v ¸Ù¡ü'=’�GÞ­uqE°>%ø€õ%ÁïðPëe°‚É3�ï£z˜kT lVÌhl0¿Ï¡ÖÑDþö6-ŒâÞÒÓ(<8ì€Û¹ýˆŒà¸Œ5‡':>tí_�h"»‘˜"t(/†¿ãÒÛY@4™»[TγŠ¼†·ptª/ü¶kOà7 #ÀMå?klV‚Çð—,ôx M﬘ÃSñŽ�<ͱ á¡I¬„èðì^cm*èðàð*°Ùxä]µô?9”ßlÔŽu%ów4*ôÞog¾’¦w@‰èàÌ1œÇ‡�ÐLø‰3a—7o+Ò²€®¡™{ œÃA‚ ?Xm;œíïø¸|<:<»W¬Ž[¦¼$*Ç&ûCo6¹ä²õøÄ²„óÀ��'½ZÂö¡ÙÛ@S¸…¿,*Gý_\‹�4#ADíZ…/®Ãg¼HæTAÄéÆÊ÷ð€€Øð̽Ör7 .\‘c“ñÐ>õû�@€¯ -Ü4bâLø-Q9T}á�ËXy(¨ðà(Ñ�˜½OEÏ7x|èe¬<”½ĺJ.–% #¹—XÀJOÐá!À#PŽ�ÃÈç¨\Á8}Ó2� ˆ%gv[H£êòémÑvÐTñ)X=¿‡gk“-¾y ÓúÄ×…•؈%gv[%ÕBx€- ©îÁ™=¾-¬‚@ìHävY%ló¡Ý5¤ƒ’ເ‰Ü®‚H·ð‹ ‹u[´�@v‚¯<†ŸW±G±æðsÃjekü{;<œÛi¬ŒãÞª}xª¿s :”ÿ›`_®oøHá;‡&âáÏZ[q©�´¾ÄZIhùx oD�W†Èöu¼¦bÆñ8XHÇ’3»½¯øjZ°ÞùÌÑãñHz¥‚l¼óßž$(©V%4- ,|‡Cù¼Xí­¾D™„y‡¾Û¬’Ú‘Èír¨­Is_Œ MÿE0㸅_«Ç'")Os$§ï5¯‚Ó¨oÛT}ÕùÜËÐÄX�ðPÜ VÝwBA$ÝÌNðöåh1|9”7¾œ®ÄôA#æw‚5zpêLä ×þμ†íÍôEÆ\û×#–̲*/€§#œ¾u­ÂLÄ#i#zÇã`¬Œw çvºôn( :8}«3ŽkxᄟáKLÄ#i±Ú‹»„´‹„ºG ©ðñð¨CmÓtæP#/U¿ú¬AÞ=Tï8¬(`9|;L´ ÊÉlxÄ¡¶e¼JPìÁl_ç—µ.Öà1ü¢*'V+| ¿$T è~þÛ[ØTøP•ˆCã5 _bûPî0ÈK¸I˜µ›–öM�¾å¿åƒÕ?–n+<õ¿ ød«½À‚CyH xºr°úU@¹ß¡Ù¢²zg¾™¾È $ˆêÁʱZÿ/PhЧ¾/|Þy•“‰‡G]$(ÕÙjì©÷W]´VN­§ð%2ñð¨*'©#AŠ_Ñ]E•€¶_®œ¦j<~ÑZ955ªj²^Èö‡GêHøFÛôlå`•€¯ýÓw¢Kw«òw� À,𢪹g=‡/Q|^’ /3þ¡›ìþìéÎüZ¯oƒ 6X_ü LF ëÓÝIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_close_pressed.png000066400000000000000000000013121526321767600302070ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+|IDATX…å—;rÓP†¿#SëH �­‚-P@Â#!dbIÉLX@fXe: �í<�fXEä¬:ØPÿ–3zY²S0œÊ²î=ß§s¯|�á›|#Ý3ãµÁ-‰—¾k êDZ1ãð xáµì3€seb¼î –0a¤Õ…Á‡ZÖwo&÷®0n&æ8f/B¢3Ôp”bÁ휀‰]`´H‰xn>ÂØÍ x-{/Ø(�8šG"Œ´jÆq.Ñö›6È -;)�hÔ•ˆá¹'—h®&ÇѹÐ:â “àÒĺçÚY¼驯OÞ¨‚O˜Wb \›EðR�8ásû³Ht.ôqR^)P&�ñl²™æ…Ï$FÚ0£W$1Fåá@ÛoÙAUIÈÙ—›^K !±_2¯2¿U¸v(±icPnàÕ�×pŒŸ²C#øQ;_�ÁÝ¡ýÌš�C8ýp¨ÇE iè n¤°éj4 ú±èââfâ4 —á›ðHàtV‰J�Þ¹–§Áƒ¦õ¼–íËðç•(è�kYg¹²‹ hZoòEд^‘3,ÇT�2¸ïZ7;>hZ$%â¹¥ÓŽã‡&³ÂSs#ya2·Áo‰Õ¢F7W�ip‰­*8€ïZWb‹L%Ì8�ߤT¤*õÀ�wEðÀµN<•+’wÚ¥•¸ºÙ½Ð}ÄÇEÀ'Ñ*`Ü‚g%V|×>Aòd{¹5‡íyá~ËB`›ìÆ4ö&×ÉÿÉFTÀvœàZQ$ap™p`ø|g|¤^ž”�ؾ_G;‹ÊýïÇiàeÕæ÷IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_close_pressed@2x.png000066400000000000000000000031541526321767600305670ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœí›ËsSuÇ?çG@¤ :ãÊ-T^yt”w ”ÂàØ$uçÎ.tá°pãRWôþG…�>y´Iëˆ�•ã0Œ+EPÊ«ò;.štJ’öþnroÇ~—¿{î9çûéùýn’&°¤%-éÿ,©´x憮Î?åC”cÀJ…ë –ÏÞKÈÍî¯*�ÕןN ì&�³�VñùMò 4¶ @×]#+¸$°£äÒ=ZÒQ ©ï@Ô“ÕB?°ö¹ Â�åÏxûÝf™˜½lJ˜œ¬``­(}Ýcš´ã5§yeÛSÃG¥ËeÚç©ÑX¯æ5_� ÇK×Ê(¬ò¨Õ(J_&§qÿm†£®Q�z™XYºV ÀU‡š�úëBרF�aóRÁ[ùÈs ¸çP{Ñ!ø1LhžOKˤšåW‡p‡°(Û¡`Þsì šÀÐ’j–_K/T|�ÉiÜB?ÐèPàÊÁT\r±5«w\#jÖ9„ßÇp(‘‘Jçõ !Hóàê BÐæ¡ÂPªŽ˜dU8LxÅkú»F5êëKÝcºSóôãhÞXZ¼ÌƒÃÌj !JŽ“`-:2æšß£öN± ¼ä~ßXZ:rÝ%·ç•ŽÊ(†'Á‚˜¿æUiu5>& ¨žqmÆÒ¬qÿÇZV; ~Ì <°JK:.×üÔð üCÃ�dDÆýÔXó…{«S˜29Ýa•Á°Íƒ�3 T©ˆŒK pß!|�ZzÇ5âè×<ÐZ­ùBŽÚ”Õ]Öp�&¡óɘ¸¼y›SUO@Q ¹®J+®“�§¿{Lw–^Èät‡Å}Ïç…õš/ä FÝYÝm„ /z+«á@:*ßôdu; °Þ¡ÔC+´vFåJ�-€ê ˆÅ.–yø†0QèÀåÕeàæ!½9}8ïÁM1NE什òÍ((„ÐÌCO�¹”ŒÉÕ¼p¸ð¸ªVE9–yqŠêÓ·ŒrXíóÖ‡¢IÆår}:(@°ô!ž¹OK™h Û<„¸f«A˜ÀðÄ5^„'êö¶»f… 3®[­euúô…F„Áž¬n³7y ̘‡ U¦¸‹²?—‚ìk¶B›€Ì¸nUË Õ›X�0Ø5ªÛ‚ê«T¡L@Ϙ¾!Ê�ÂÆ€RÞµ–}� ¹P¾>~Ì«0L9¤]oL8“(ŸùÇ¢´Šrxä¿! �8�Ó&?æ�p4“‹É¸\Vå> dÆuk�íÎ(�3àtN›`Ø�ùލ Ï^ìÎê;"œ^pÈqÇöuDäǪž¥š'À¯y5´•šHÇåpÇI°–¡ &¡&§sÚ´ ÷±WC[:"Cs¤brÔÖ¾ªÞEóÀËá�E9–ŒË KîžœîÎáýuþRa_**?¹ä®p¿õfu‹ ø™Ÿ¥ÍÕ|Q Á7€…0_TfL÷Zå,!Bðuôfu‹º�}Mæ:¢2l„£Àc¯X…�¢ �Îi“ŸÎfÌ ›Â'­�=?Ÿ:¢2¬†6!4À°NºGt³_ó�qpmÂKéˆ …Áó èÑÍbv5´§bÒïRܯz³º_…op8€ÛyØ÷~L~ž/h^õd¾¨„o©ð­Ï ò„0'€îÝ,Ë^q(4)ÂñdTúbk–_¢ìMÆå—J+ði~J„ö…2_TPÊd®ékv9cÀ«‰Å|Q]Y=`¦ÏoÊŸ Ñt\~Ÿ½\ö°Ëù˜ÿ€y€Î¸ Øé_µLz › |Rº\é1¸Ç¡ö”š…Ûóó©ð¸mÇ‚ {K×Êy�¤O,M²�Ƚy۔ŀêO”,´p%ZŸšù^ë­oÌZô#¨ãûJÏv¯Ëm/ºð¨lðhlñ(\ðà\ñ |ð`lñìlš*ô#Èû¦,rЈñ9p ÍüQ<ð `YÁ­Yó>\®·e±;*@(Ü+€#¾Î�— Éë¸s€Ð¸S€8X¾[<M2,vÀO”Ì]ðΞøªBf‡p§N otÂA�¸¹¿:acqóÑVüÀÅlï„øXí+�û^L©‡Æ¿ëÚvÈ�J”¾Ð› Mø~ž$�S˜à¡ ®ÀC\‚Ë\ƒ‹\„ØÈúÇyʼ(ŽûQxš%ËxØ„ïe„Ã\‡ƒ|€C|�|‚Í|ƒ�|„M|… ìÁK»]œeÍ+õ=Qòr¼¥yMÐuø� Þ%g˜Xô%o™Ã˜kIÌyøÝÆŠ8¼ž5A/à…wñ<-k‚>ç½"/ü:ì:|e·qˆð~:oö+òBà¼J�Ÿ÷Ü0·¬Á#G½èâ�§÷»áGWòR+‚-Z­MWóªÕêM�yëZ×5®¿pˆÊn2ÄIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_grip_disabled.png000066400000000000000000000006551526321767600301560ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+_IDATX…åÖ±NÃ0Æñÿ¥Ny:ð…‰‰HíÐv$xRÄ‚DÕN•²Ê0ÀÄž´Ç@ƒÔ4%v°Ã€Gû¤ß'ût2ü÷%mbÓ4íÅ9w ¯£ar µ‰›Œ¹Â…ÀI±ßJ€G裼d†ëâ,ø”ñMӛȋpÁMÎ̯ Ð_ŲWáN“0 n9 áÛÞØ�„{Mè„Õýˆï7æî0ŠÊÅŽxXå†Ê†³iLÙ)nˆÛÔº¡@U#“ñX‡«ª˜\ïëðrÝ!ü;Àö.ŽP–5?é¢,áUu6óU�Tµv0©ªø¬ûóõ ßoÔŠcÃW5IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_grip_disabled@2x.png000066400000000000000000000013331526321767600305220ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+�IDATxœíš½nÓP†Ÿ/¡* l½–”¦Q®€”Р++wŒü”T0 –¬ni£&’7® ) "ù*¤`œ¦±Ï9>ÇÉ;ÚŸ_�ç‘ãXG†uÖYg•#E/Àv¢¯£;RÑç¨ü�êäqsgçÛìùkE-ÌE¢Á°#ª@QtR}Ôgg*Å,Í~.เÿ™ÞLΕR@* ;ˆ‚n�n!¼NÎx#À|JßñB€#ø©0}’œ-\€;x}ØÜ½õ19_èCÐ1üAÚ5… ð à < À'xp,À7xp(ÀGxp$À¼,Óe]€Ïð`Y€ïð`Q@ð`I@(ð`A@Hð`X@hð`P@ˆð`H@¨ð`à39Wð¨ì7µÞ²}ǧg÷”Ê Àüž KøVøh0ÜW¤geO0xQÞ°€1“ßá�OÏöRàÍì †¯ÈÛdŸ‘=ÁÀáóí ú?º¯è»dߢ¿Î+ (+<\A€+xöÚõíÃeûòÀÃe‡‡Køt2ê"ú>Ù·ìÏ(UÀªÀCŠ€‹wgéa~N_ŽÛ>½/ëôqoü<ÿý¸1s83üœ¾Ìð¦û ñ&8�«ÀæÌ¡\Ÿ¥¤ôåZ¬é>Hh·Ûçˆ>~c:y¾ÉIö ÚͳXÓ}sÓï÷7ã8Þðµ/Š¢ë&ûÖYg…ó¾UïºIæ{IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_grip_focus.png000066400000000000000000000006531526321767600275240ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+]IDATX…åÖOJÃ@ðïMC½A#¸*®ÔUW® èTx°¶øîõGO)¹‘¯çó^DNxGf 4Ø-÷“VqàÄ=5OÊoÞWà‹kÍ£×ËíÏ_…{pÄçö<è%³*î 4î Xþ¶xœ§Š˜Ùâ€Å ¸à‰#n à‰?ê%‡ëp§I·�„‘ð¢1+“°À /ëšñZcnš„¾øB�ù6¦ü,�›O¨hÂU‡˜¤$”^­kÂWеEànãKæ °[Ô5àkêlæ0¢iͤ­ûëõ ³:õ†¡ùDIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_grip_focus@2x.png000066400000000000000000000013501526321767600300710ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+šIDATxœíš½nAFÏu¡�.‰K�Œ_ %/ACd“€D›‚–Ž–@ ±N�øqA�xG"¥m)‚!‘K‘fY¯cïîÌìÌÚ·œ½ûiÎÑìßhaYËZÖ"—”=ÛÕŒFwUx.ð£¦úø[·þ5~üJYsQÍÞ°¥Ðj œ‹¼îÄ{j¥ÌÌA]ÀKŸ£*7’}•�üÕš>KöVNÀTx•öÉ^ýK²¿R7ÁKởÒΩŒ€<ðPyᡊÀCàŠÂCÀLÀC LÁC€LÂC`LÃC@lÀC lÁClƒçlÃÇ\Àƒ§\Áƒ‡LÃ7¢ñ=} Ð=îl~Ž÷jCÄ4|³7l‰è°¬+DÉoØ€OÉ›(/8‚?WäI²·tîàyxÒÙø˜ì/õ&è~³ŸvNi|€‡’ø%ð  ð  ð=]Á£ú <8X.áÝúAÖ<«|‡‹B€KB� B‚ÃBƒƒB„CB…œÁ‹îöê‡Yó½ñ¶ /Áž ÷ðû£]A±±'¼ò–Œ¹xßí¤À›Ù Þ%óŒì † Ÿþ•8÷ ðþv4¼Ÿ?ëy®<"ï'òæxo˜¹\Á ºãf¬—ðÇ�úQÖ¼¢ðp‰ïá÷‡mT>$ó²^F©`%9Ðè�·� ÁOÉË ñn?™—÷úß ØŠtõ§ŒÏ€ë±áÜðSòrÛ΃ÄSàìêé °*ô[JJ^¡ÉšÎƒ„€ÓG·~£òøüR‘V‘r&ò�v‘ɚΛZ�ƒµ­HW}Í»ùæû5“yËZÖ×?ø¢‰<$ã……IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_grip_pressed.png000066400000000000000000000006701526321767600300510ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+jIDATX…åÖ1NÃ0Æñÿ‹C¸8Aa@ ¬-@‚ $ÎQîÑ� $¤víŠ å 01—V��‰â4vj‡�ö“Ÿlç)ð߇4‰ ÆÚJ 7ÀËyGN’&qcÀv1Ÿ6‰ ´ž Ž‹µèW`Á»—‡òÚH€*>ýë´� ˆN7IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_grip_pressed@2x.png000066400000000000000000000013071526321767600304210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+yIDATxœíš½nÔ@FÏ]HB]ÞÄ�‚Š7 í’ðã4PÐÒÑò$¶‰ÃOØ ÄÐﺣä��Ò $öR@a&v6¶gÆ3^ßÒ¾þ4çH�® C 5Ô:—t½×•åzx†òáQšÈ×âý‹­ËKe £#”WÀõbϨƒuy©l¡c(ÀW̾^ (ƒ~/á©ÙÛ»W  a²ŸÈg³¿W›àYði"Ëžé�€&ðÐMá¡ÚÀCäÚÂCÄlÀC¤lÁC„lÂCdlÃCD\ÀC$\ÁC\ÂCà\ÃCÀ|ÀC |ÁC€lÃg¹ÞBy 0Zòðþ5ùT¼ÔDÈ:üß™à1° l/GLÍž`8�?�wª‚à ~)Êc³·sáï=¸*ÌþN7AÏðGeÏt& xèH@(ðÐ�€�àÁ³€ÐàÁ£€áÁ“_ðwÓDÞ×Ér. dxp, txp( xp$ xp &x°, 6x°( Fx°$ Vx°ð��/x…½ýDfuóçz[…à`&è~§>üÁ\÷T˜áb&¼¯YÁØH@èð‡sÝ-�·3Œ^…7fž•™`äðíf‚¡Ãg¹ÞAykæ­útžK@_áá¼r`7Ý‘ãÚy-àa…€¾ÃÃB‡?XèDà�™W÷5*°.ðP"àßÙy†%øŠ¼ÆðUyM7ÐÿLsÝØT¾— —ÃWä5†·�ÆIpó„ ÀVáR«ßRJòZ-ÖvÒòS„'À/àDaÜæŸ3O”I›ÅÚΫ¬çßtkšëF¨yÙ½d3o¨¡Ö¸þÿ0¬ôwVj÷IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_minimize.png000066400000000000000000000003101526321767600271730ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+zIDATX…íÒ!1„áÿuï@�ÜCô&Ì �æ È=ݤw Õš&¸¶f>7ÉKfÄ‘ɬÉ1.]�ã x3`½l1¸=Î]@»¦Ïûê·û€r€ø£„ðïr„:ÀÍwƒ4 3cáVÂô'™î¬ š�7^IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_minimize@2x.png000066400000000000000000000005161526321767600275550ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíÖ1JQEáó2B,,D ;‹`'º€tº×aãÄdö)í²l„€‚ hÀÂBdòlå�b•pÎWÞŠ;·™I’$I’$I’$©Ÿ÷~¿ÈÒdQF£90ÿíüã›Û{ëT³„#`eQÝ2™âEY´�ﮟÒcm€µ^oµ»7ÀVŽvMªyÜy¹¿}þ¶Ò§:tÏø/°Qa�†µˆd©³ ‘Ã4ªÐ0õWKè‘Gà2�jÌø8rôÉlRUñ$ k¼ŽÇo­öç>Äsà=KµÅšâ°,ËÝô þI’$I’$I’$IMñ›§6ÝÌ®aIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_minimize_disabled.png000066400000000000000000000003161526321767600310300ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+€IDATX…íÒ1 Â@„á6w¼Š lNbaã‘,¬=ƒ� )r!w0Ï*Aì²ÛÌ× <˜)˜™™5¦ï*¥t[æœß’âgÀs³¤;°ßr0Ȩþxx¤u‰t­P°“Òm éße 뀈¸¯ �Óœt^Bó'433kî„ì!'¹¯IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_minimize_disabled@2x.png000066400000000000000000000005151526321767600314030ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÿIDATxœíÖ!NÄP…ási'$x6@‚@˜Å߀Ǵµ>Í�€=%{¾ûzðsIò1C9@í¯#øÕeç€ðÔ[†Î= ;Bñ')î GQ UøD|IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_minimize_focus@2x.png000066400000000000000000000005151526321767600307530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ÿIDATxœíÖ±.Q…ñïÎlB6Z…è$  ã¼�h·ñìl³�V¯”Ðy¥DBC"�Bc®Vî ›»‰ù~åùOqæ43 I’$I’$I’$uBøócØ>¦ÌÔ¥WP3 õo÷X?yX®Co`Xh«\&Sà¼(‹ÁÍ~ÿ1=6X?/†ùêXÍP.§Iظ;XyúéSaîsÈÿ{y€~/2JÃÆv²Ô™…Àn5è˜æ‘ËôÈ#r‘F�â[yÜçè“Ù¤ ¦ac€ÛÁÒKùþ±áxÍR­]Sà¬(‹Íô þI’$I’$I’$I]ñ|ô4Cå꿤IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_minimize_pressed.png000066400000000000000000000003121526321767600307220ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+|IDATX…íÒ± Ã0„áÿ);¼ˆkobB�á1RÜe†”î3H@;„K%Ò)jîë=¸+fff�E$ÅzpjY¸N¼#B_ö§&à - 20_Æx¤êéÖ¼ 8“ØJL¿nÿ¡°¯æ�"+¸–Øýš™™u÷T� ¹„µ²IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_minimize_pressed@2x.png000066400000000000000000000005071526321767600313020ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ùIDATxœíÖ!NÄ@…ño¶]ƒ@�ç$„ VâàHÁb8ìöX‚E’€C"0ÜEBÖ!È&Ûv°dp�Mè÷“ï_ñúL ’$I’$I’$IÒ „¿Ž1ÆpùHUªL/öé¦!t¿�àê9nŒ#³GÀZoåÊXw]ÅÙÉnxK�Ù7Oq}YóBd«D»‚æMËöé$¼GéSËŠé?|y€Íºf–†ÙÊôY�Èae M6@€‡U)"pŸFÙã– ¯E •5oÎÓ0àx>F-{®�Ï"Õúµn»Š�ô þI’$I’$I’$ICñ̓7¿ YQIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_undock.png000066400000000000000000000010121526321767600266350ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¼IDATX…í–1KÃ@Çÿ/­)¸ÖTPh¶bRpAü RéâÐEqéÔÁAt)~'‘~A .‚¥E#„BãÐE©-hÛç iMlÚ„3´ÿé.÷îý¹{w0î¢aƒ1E‰ Î�( ð‚G+ Ì´"Y]¿kŽˆ)JThrŒ”7c+Jx�¬‚]œÐàœïæÀHaú#×ó± $JûnÞϽa4ÃöQæ=×ÕòÐz%Q’yPnûø'MþÔ€˜HÎCÖÀæïqIÞµKÒ%ê Ü)ÕÔä-pÙq`*¬YiqŸ@GƒÀêæ³ÝÞªk�ºuÀ\„ý¢îmA<¡dtìÁV§Âá `3ätB€�Æ&ˆ¸ô°ì4¸ÿ·Ä¦[�gN“0aÀœÑïR( èÀRµç²mÑYOÈ`ŽјŸ®À�á`8€—[ÏV äEIÎÛG�f´‚YæBp„Z‘l¤�qúûEüÍó#Q’_ÌøãÅÛúSåÜIhˆ¯|1ÚĸvÜ ÆÀu¯î >¬©•ªk€šZ©°â€7÷¾tO Ì‹Z9q9wÌõ¬DÙÓ_Ä:IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_undock@2x.png000066400000000000000000000016131526321767600272160ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+=IDATxœíšÁOAÆ¿·[„h)"’ÒJ"Ðõ@-Ä£g�=x3bbBbÔðþ¼Ðè�£1z�ƒzÓ„˜˜Z‰‡V6@K‘jÀ²û¼»Û-ÝÝéXwÇÙé{ß|��}™ ÀÏ�ÛÝÉd¸eKcÂ%)­îe¹b@†3å6}jua¡d×Ù•ñþÔVh@¯›8É“Á£K‹™—Õ:¨N#ÇR£¬ÐNc4€ˆF"�Ñ/›ëÅVÍ€˜–: ¦YŠ+y�C'ƒÏ[Í„º èN&ámõ€#žHkù�V}°rM¨ûlÙRÇÐ|ƒ€Þ]íQ·»«}Sb¥ÝÉ;œò@‹,LÚC‚Ø~ç—si×µ…b‰!¶ylÒÞ,«¸0d �M`€l² �-@6¾7 f!tøè`¬%ºà4Q»*≡¬S1Àäôâý|°–Í~wk¯ØVmqmø"3Oè-ÄcÑPh¤��Ÿ«çg5*AS¥Zõèц&˜ùd ý ó›Ø@ê¦È4–Ä©Ëĸ-2ñQA4Õ†OŠJ`2 §ïDƒŠJèU1øÑ!M‹ˆn2€T}€�dŽ!ôïãý7D„¶z.ˆHä ÑeeÀ?¹ÅÍ‚tÕ½!¢B?&BˆŽ�ðlµçЇ8VÔm@>·à¸Ð±£7‘„îü˜Â1¾/…d �M`€l² �-@6�²È&0@¶ÙÈ '÷¤À@¢ÖŽïØ®lðÛ ÈT6øÊbÌT¶ùÉ€|¹MŸªlô‹:Ï¿m@¾€€óxõØúá`©IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_undock_disabled.png000066400000000000000000000010031526321767600304640ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+µIDATX…íV±NÂP=·�(�89˜õHLCÿÀh‚añt11Æ…‰ÁÁèBü'Iøâ@JRù ‹ÆÀB{°@+-mŠv€3½×wß;çÝ{ÞM�E¹-Öj­øJ¼WèÀN@®6˜ª‰X¤(Šbo¦€!y¿ �ØŽVb5ºgŠœ¢†7Ÿ;9$¿úzÉœ8 øIû߀øÈF]Â,5Ï¥%W¿Ì‚¢j<íl— ü–~y ÑxÙÖ1�íßëêó™Ó!ÄlÌ­î{GËçóºcÕUí‚€ëiÂ<¢!ÑãlV|³/ØL82õ¨Jã¹@ÀMrÈÂà±R©D¼n{€ø2±EÄúÆ–ä5xò¶–®ÇÀ½×C8°i΢$€¦_?ì§%GÓÙQW5pjΙÈóë ý.,„. H×s�ËŠª•]BÚæ œ 0UÃÐJÄ"Å0´Át7ùG L´_EÕ>¬Í…Šq’ËH^BG ài.äÀ€ Añ<.�.œèe'Æ•,§:¾ÈrªCº°K@À§O^ðÊ„‚œ‘n}î]p|x0pÝþçóIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_undock_disabled@2x.png000066400000000000000000000015611526321767600310470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+#IDATxœíšËkQÆ¿3�X¥¸± ‹u!º;mÓ6ñUtáN îZ•îÜ”þ¶K¡EtÑ¥›º¡|LÒN› ¸ºp¡è" ".)&s\´RÌL’ÎLNoÓ¹¿åÍÍ9ßý2÷æpç�&ÎPÔ–eµ‰Öq&ºPÀû!,<´ð1Ï»¥âl:�þQsv”TÛ¹ÆíQâˆÁ(€0–JšÏ«M1ÂÆÎ.;cžíÚÅØÔ¶˜YqF«O AvŹČED0p‡)¸ì÷$6À²¬6Úwà-€ã�P¶c0 \ú}ºòLü ‰Öq4Ûâ€Ð¾©ý?°qÚ7'~ÚCìaêj„5xµ'‚©ý?ŸJš‘k‹(dl‡«êÕÞ,§¸ÚÕT£ P-@5ÚÕT{êBKK¯�¹Fé6˜Îƒp¨QgÈØùwáå0(´Ðšà¦i~k{Ô¬Ú²vî*ƒæ–âî§“¦äKµ+Ao¥Zu X+ù)=�šÅ@¶eçoI&ñ5 kçFˆyB2ñ6i!ðŒe;¦T�V.w‚A¥† …€GŽã’î1€\š ’,ÅÝ”ìÝ.®H$Š‹èò°{oyEt¾aÃ=%!et‹Õ'�ÈEK`Ò}} �êX««€+¹6±/…µª¨F Z€j´ª¨F Z€j´ª¨F Z€jBô¨‚OÖ»ñ­­WŽÄì àµÊ‘X@Ìó•cñ1€QpKÅÙÊá¸Pa̯o¸‰ÁДA¸‘ê÷ïÞÛük–®²x`O°Õ._üupfx¸ûgÍÙ•Ñÿk¥ ÷©dOg££ú‚ô¥ÑIã³DXŸ7CüB"Qdˆ_J„õàº4 à�D²|5ÜÄ}‰ÀÎ ô¼h7ôlÁ<:8xæ“DhßBh¨ÿì=0K$ S©�Þ§Rñ} "w(Ù3ШڌoJš“’iê¾q}µœï6 žÓ€�HаQ¼X`ƒï¦{{?ŠçÓh4±æ/b#Ô½Gœ¤IEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_undock_focus.png000066400000000000000000000010231526321767600300360ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+ÅIDATX…í–±KQÇ?¿ä¶@6›!P¡ôì–@'Jÿ…¢`qqp0ƒ.…".NŠ.â�tK'…ü.B tl&iÕ!ˆ˜K;´¢6Ãù~z’¤¹x׋É�|§÷Þýî÷ý¼÷~÷ã`Ø%ÝfеD£!ëÀ´ÂxD£ª�Ò¥ºkg¹ôÕƒ™b-ñ·!e Ÿƒ*êNy1¿¨»�÷Ú ›kÝ›øÓ�`î™ÎxcË/¨ýÎS]ëå!ÙG;åîv}ÑàŸx–?}ëuûúD¾¾ì—ĈšxŒÊ÷䓯ÌÊõØç=𡘊nù%À°׿XùŸorcgAî¯ÀþT›>v2¡W®˜v5••Æ-/Îë“Aƒ›wÛÒõTÙšD„7@Ú›_²@9,@K£9Ê¥|‹®]Ïó",yó˜Jà¯kàŸá`0p€(]ÏW*ºeœn­»ê�rJƒ¨\ª»Öw�ªÂfóñÝú­ì‚óHöÂLaþh1õ9Hló ìõÂpÕr÷ƒßË}üŠê.ÊêñBú$4ÀñBúÄXîKn+ô<¤¯ß�û‘Km„|wÈu´Ô‚Ô¹ÓËIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_undock_focus@2x.png000066400000000000000000000015541526321767600304210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+IDATxœíš=LAÇÿoáü ±!Ü‘BÂ.BbkïG¢…�!±0�p|„ĆPZ‰¥† ²g(m°1&`¢v¶¢„;¢Å)·G(4Çí³��x»·Ç~ ñó+çÞ½÷ŸÿíÌ¾Ì  P(â …MП-·í$0I°o4àdºÂ° ð C[“z]/@ šY7ËÃ`¼ÂÑ�<t�±läÊCõ=ú¼u�Ëaà!SáºÛ“àÛ€þl¹­’àUç"‘vxê«Ý|ÿ‚; L¢ù&]{Úÿ÷ÿvûæÄM{€5LQˆ‘ƒS{k€,žïùüh*toôØãc‡öfÙÅ…¡ �-@6ÊÙd£ �-@6±7 a#Ô7¿Ù¹«ÙĸÌ@ªQ¼aZ…z "ˆ—øOë|ánûϹ„gצ›¥›D´F»h!.|aâÛ…Lú½Ÿ/5è�jÝ%`˜¥½�4yè&¦w†i�‹,âj@o®4ДȤÀ¬ž+]UÀaÀ…¹�óÌdŠ*€bz¦?Þ:+"¹Ã€ª¦MR,ÝtzwLDbç ÜQ(4LBt¹íGô”—…èò} bkdˆ‚]èšÆËBZ|°>’ ÓèÔ¥çi°Edö&ö­°2@¶Ù(d ��2@¶Ù(d ��2@¶Ù(d �M�û²èitâ{¶kböðJíH¬ `h‹µcq2 x¢‚lí`\ ¨‚0ìvo¸™6Á TA”Ég’®÷…�»{—¥Ý'Oö¯ËŸ9eÏ~¼“þíì8jŽà]+ŠõühJ�:©Û&¸u‘( À‘×Í€7" …… oEäu@6¨ˆ(ÂV«­Í‰Hí0`m<õ�™�ÂÝ€}˜xèóXdžˆÜ®�Pá{ê€ç" ú…ˆg #é—¢ò»w‚÷ÉÎK2ó=È[?4¸–IO‹,Òð×Þ'ÖEÖ0à €‘bö(‚±ÔbÛV':¿B=…BcþŒÑÊÊË hIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_undock_pressed.png000066400000000000000000000007631526321767600303760ustar00rootroot00000000000000‰PNG  IHDR szzô pHYsÄÄ•+¥IDATX…í–¿JÃP‡¿£â à þyAÚ"‚ø ¢ 8(¶‹ƒ.‚ˆ‹SÑ¥¸¶¨“‚Oà"ˆ ¦ƒy)\\tˆ5Ç!¦´Ñ¤IMÛÁþ¦{““ûûr ÿ]ôòÔÔAÛ"«0ŒþÑ«\ZÂÞzBÞœš:øùÁ-ÊÄ�ë%˜L»=~q¶E6vse¢_ɺS_€ï´·J î / ¨nÏÓI ¬—F*ª¿­í›�v© ð£NŠ:b+³ÞçyC7ýÅÁxänqQ>›Èßë¶*û¿� ä|WPàmŒ›³¢.­$ä),@u ò†.‹p Á'#XÂLÅæüâB{#ì4mì�xg*lxíßz»ÞqÓ9”awªN½� P×hÒIñ-:¯ †lT$üéêø1ìt:Ð|× �@®`¨ëvî‡@ç2péZ’�@9—Ò=wÚÎ ”€£Ú±Ãó­‚¡/ÀPLf«é¤œ… ¬ÍÀUÎU®ÃÆWTÙxŽ�`7“’rd€LJʶ2‰S¡¯mx–×rñÛ®/!`t×vz�ôIEND®B`‚epasveer-seer-97076f1/src/resources/qdarkstyle/light/rc/window_undock_pressed@2x.png000066400000000000000000000015271526321767600307470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYsÄÄ•+ IDATxœíš=hAÇo/ÁÄFDD ƒ±)òa¬ý-ìB@Tب¨¤³ )­Œ¥� ŠÞ›Øˆ�j'sI!¤°P¢p "Š Éí³HT¸Ý»ËÞîdrîþÊÙ¹÷þó¿™�aöAJJJ’‘¨FçtGóxô"´ÛbÐ…e”9Æ›h“_•:G2 —×Y…ýQâ˜B  ÐïvÉ‹r}œZƒçòÚ<ߪƒX×6™�V·\ŸšfÀØŒžTe’n2EàTÐLmÀúš�²/i›„@aa;‡Kß ¡ÿÁæ%êmð°¶š—(m?…=zcQdƒíá XÛêê“í 5„©¸Ï»]ùl…\^µÂcŸözy‹#5À¶Û¤Ø`›ÔÛl“xª„ÎèÞU�kÇ€=Õúçòú¡V1ªP&‹Ü=×#?k�"gyÆòzF! ì2-$€yκ2æGUN‚¾“jÙ%�›Öa…§Ø<@ ¯s3zÕd’@²ÓÚ‡0h2ñÉ ŒäfµÇTŸ¹7z@„{¦Ö@�Ç�¦t§‰à>´�!ÀH²´¬d¸b"°ÏN›HFtùgÀ½åCºB_ˆ™’)ÒŠ0Yî¹Æð'ˆÐ\ê�š:•¸?«d<‘+“ø£pj€m¶I °-À6©¶Ø&5À¶Û¤Ø`›ÔÛlSK}€-V»ñÝË¥ ÉšÊ\iS² p÷7%�Âb£¥íI1 ¨ÐT7œŠª\.W/\O»@hþK÷w—/–þ ø[.ï42r¡]*uö]5ǰךâ£Û%­q z|‹;IL|5Ôg€ÀK‰"£¼2Ög@Ñã°b"Y¾78Ü1ØgÀÅ#òNÙµÿPÜó�òÅDèÀsÀçNn <1‘04ʰÛ-ÏL…4à†ˆ7ßIŸÂuì-‡¢ô¹Ý2d2IÕ/®Þj{ÆaPá8°Û¤˜uA&d•›îQùd:_JJJ²ù �N¶laXIEND®B`‚epasveer-seer-97076f1/src/resources/seergdb.desktop000066400000000000000000000002411526321767600223700ustar00rootroot00000000000000[Desktop Entry] Name=SeerGdb GenericName=Debugger Comment=GUI frontend to gdb. Exec=seergdb Icon=seergdb Terminal=false Type=Application Categories=Development; epasveer-seer-97076f1/src/resources/seergdb.metainfo.xml000066400000000000000000000020751526321767600233270ustar00rootroot00000000000000 seergdb.desktop SeerGdb

A modern GDB front-end CC0-1.0 GPL-3.0-or-later AND LGPL-3.0-or-later AND BSD-2-Clause AND MIT AND CC-BY-3.0 AND CC-BY-4.0 https://github.com/epasveer/seer

Seer is a graphical user interface to the GNU Debugger (gdb) for Linux.

It provides a simple yet visually pleasing interface to gdb, making it easier to debug applications without using the command line directly.

seergdb.desktop https://github.com/epasveer/seer https://github.com/epasveer/seer/issues epasveer-seer-97076f1/src/resources/thenounproject/000077500000000000000000000000001526321767600224345ustar00rootroot00000000000000epasveer-seer-97076f1/src/resources/thenounproject/assembly.svg000066400000000000000000000124131526321767600247750ustar00rootroot00000000000000 image/svg+xml epasveer-seer-97076f1/src/resources/thenounproject/configure.svg000066400000000000000000000637061526321767600251520ustar00rootroot00000000000000 image/svg+xml epasveer-seer-97076f1/src/resources/thenounproject/fortune-teller.readme000066400000000000000000000013261526321767600265640ustar00rootroot00000000000000 The Seer icon is from: https://thenounproject.com/icon/fortune-teller-3505303/ noun-fortune-teller-3505303.svg https://creativecommons.org/licenses/by/3.0/ Convert to png and resize. mv noun-fortune-teller-3505303.svg fortune-teller.svg convert -background transparent -resize 32x32 fortune-teller.svg ../seergdb_32x32.png convert -background transparent -resize 64x64 fortune-teller.svg ../seergdb_64x64.png convert -background transparent -resize 128x128 fortune-teller.svg ../seergdb_128x128.png convert -background transparent -resize 256x256 fortune-teller.svg ../seergdb_256x256.png convert -background transparent -resize 515x512 fortune-teller.svg ../seergdb_512x512.png epasveer-seer-97076f1/src/resources/thenounproject/fortune-teller.svg000066400000000000000000000322301526321767600261240ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/thenounproject/keyboard.svg000066400000000000000000000407241526321767600247640ustar00rootroot00000000000000 epasveer-seer-97076f1/src/resources/thenounproject/memory.svg000066400000000000000000000431711526321767600244730ustar00rootroot00000000000000 image/svg+xml epasveer-seer-97076f1/src/resources/thenounproject/preferences.svg000066400000000000000000000016341526321767600254620ustar00rootroot00000000000000Created by Blair Adamsfrom the Noun Project epasveer-seer-97076f1/src/resources/thenounproject/source.svg000066400000000000000000000561541526321767600244700ustar00rootroot00000000000000 image/svg+xml epasveer-seer-97076f1/src/resources/thenounproject/stop.svg000066400000000000000000000542461526321767600241550ustar00rootroot00000000000000 image/svg+xml epasveer-seer-97076f1/src/seergdb.cpp000066400000000000000000000354551526321767600175060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 Ernie Pasveer // // SPDX-License-Identifier: GPL-3.0-or-later #include "SeerMainWindow.h" #include "SeerUtl.h" #include "QProcessInfo.h" #include #include #include #include #include #include #include #include #include #include #include #include static void seerhelp() { QString text; QString fileName(":/seer/resources/help/seergdb.hlp"); QFile file(fileName); if (file.open(QIODevice::ReadOnly) == false) { text = "seer: no help available.\n"; }else{ text = file.readAll(); } file.close(); QTextStream(stdout) << text; exit(0); } int main (int argc, char* argv[]) { // // Set up logging and message formats. // QLoggingCategory::setFilterRules("*.debug=false\n" "*.info=false\n" "*.warning=false\n" "*.critical=true"); qSetMessagePattern("[%{time hh:mm:ss}][%{function}:%{line}][%{category}] %{message}"); // // Set the app's names. These are static and are safe to set before the app is created. // QCoreApplication::setApplicationName("seergdb"); QCoreApplication::setOrganizationName("seergdb"); QCoreApplication::setApplicationVersion(Seer::version() + " - Ernie Pasveer (c)2021 - 2026"); // // Parse arguments. // QCommandLineParser parser; parser.setApplicationDescription("\nSeer - A gui frontend for gdb."); parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments); // Treat all arguments after the executable name as positional arguments too. parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); // Treat all arguments long options. parser.addVersionOption(); // Run or start options. QCommandLineOption runOption(QStringList() << "r" << "run"); parser.addOption(runOption); QCommandLineOption startOption(QStringList() << "s" << "start"); parser.addOption(startOption); QCommandLineOption startiOption(QStringList() << "si" << "starti"); parser.addOption(startiOption); QCommandLineOption attachOption(QStringList() << "attach", "", "pid"); parser.addOption(attachOption); QCommandLineOption connectOption(QStringList() << "connect", "", "medium"); parser.addOption(connectOption); QCommandLineOption rrOption(QStringList() << "rr", "", "hostport"); parser.addOption(rrOption); QCommandLineOption corefileOption(QStringList() << "core", "", "corefile"); parser.addOption(corefileOption); QCommandLineOption projectOption(QStringList() << "project", "", "project"); parser.addOption(projectOption); QCommandLineOption configOption(QStringList() << "config"); parser.addOption(configOption); QCommandLineOption workingdirOption(QStringList() << "cwd" << "working-dir", "", "workingdirectory"); parser.addOption(workingdirOption); QCommandLineOption symbolfileOption(QStringList() << "sym" << "symbol-file", "", "symbolfile"); parser.addOption(symbolfileOption); QCommandLineOption breakfileOption(QStringList() << "bl" << "break-load", "", "breakpointfile"); parser.addOption(breakfileOption); QCommandLineOption breakfunctionOption(QStringList() << "bf" << "break-function", "", "breakpointfunction"); parser.addOption(breakfunctionOption); QCommandLineOption breaksourceOption(QStringList() << "bs" << "break-source", "", "breakpointsource"); parser.addOption(breaksourceOption); QCommandLineOption showAssemblyTabOption(QStringList() << "sat" << "show-assembly-tab", "", "showassemblytab"); parser.addOption(showAssemblyTabOption); QCommandLineOption startAddressRandomizeOption(QStringList() << "sar" << "start-address-randomize", "", "startaddressrandomize"); parser.addOption(startAddressRandomizeOption); QCommandLineOption nonStopModeOption(QStringList() << "nsm" << "non-stop-mode", "", "nonstopmode"); parser.addOption(nonStopModeOption); QCommandLineOption gdbProgramOption(QStringList() << "gdb-program", "", "gdbprogram"); parser.addOption(gdbProgramOption); QCommandLineOption gdbArgumentsOption(QStringList() << "gdb-arguments", "", "gdbarguments"); parser.addOption(gdbArgumentsOption); QCommandLineOption xxxdebugOption(QStringList() << "xxx-debug"); parser.addOption(xxxdebugOption); QCommandLineOption xxxresourcesOption(QStringList() << "xxx-resources"); parser.addOption(xxxresourcesOption); QCommandLineOption xxxstylesOption(QStringList() << "xxx-styles"); parser.addOption(xxxstylesOption); QCommandLineOption helpOption(QStringList() << "h" << "help"); parser.addOption(helpOption); // A positional argument for executable name. // All other arguments after that are treated as positional arguments for the executable. parser.addPositionalArgument("executableandarguments", ""); #if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) // // Make sure there's a display to connect to. Otherwise Qt aborts with a // cryptic message (its "could not connect to display" warning is filtered out above). // Skip the check if the user has explicitly picked a platform (offscreen, vnc, eglfs, ...). // bool platformSpecified = qEnvironmentVariableIsSet("QT_QPA_PLATFORM"); for (int i=1; i 0) { executableName = positionalArguments.takeFirst(); } // Get launch mode. QString launchMode = "none"; QString breakMode = "none"; int executablePid = -1; QString executableConnectHostPort; QString executableRRTraceDirectory; QString executableWorkingDirectory; QString executableSymbolFilename; QString executableBreakpointsFilename; QString executableBreakpointFunctionName; QString executableBreakpointSourceFilenameAndLineno; QString executableShowAssemblyTab; QString executableStartAddressRandomize; QString executableNonStopMode; QString executableCoreFilename; QString projectFilename; QString gdbProgram; QString gdbArguments; if (parser.isSet(runOption)) { launchMode = "run"; breakMode = "none"; } if (parser.isSet(startOption)) { launchMode = "run"; breakMode = "inmain"; } if (parser.isSet(startiOption)) { launchMode = "run"; breakMode = "firstinstruction"; } if (parser.isSet(workingdirOption)) { executableWorkingDirectory = parser.value(workingdirOption); } if (parser.isSet(symbolfileOption)) { executableSymbolFilename = parser.value(symbolfileOption); } if (parser.isSet(breakfileOption)) { executableBreakpointsFilename = parser.value(breakfileOption); } if (parser.isSet(breakfunctionOption)) { executableBreakpointFunctionName = parser.value(breakfunctionOption); breakMode = "infunction"; } if (parser.isSet(breaksourceOption)) { executableBreakpointSourceFilenameAndLineno = parser.value(breaksourceOption); breakMode = "insource"; } if (parser.isSet(showAssemblyTabOption)) { executableShowAssemblyTab = parser.value(showAssemblyTabOption); } if (parser.isSet(startAddressRandomizeOption)) { executableStartAddressRandomize = parser.value(startAddressRandomizeOption); } if (parser.isSet(nonStopModeOption)) { executableNonStopMode = parser.value(nonStopModeOption); } if (parser.isSet(attachOption)) { launchMode = "attach"; QString pid = parser.value(attachOption); executablePid = pid.toInt(); if (executableName == "") { QProcessInfo info = QProcessInfo::populate(executablePid); executableName = info.path() + "/" + info.name(); } } if (parser.isSet(connectOption)) { launchMode = "connect"; executableConnectHostPort = parser.value(connectOption); } if (parser.isSet(rrOption)) { launchMode = "rr"; executableRRTraceDirectory = parser.value(rrOption); } if (parser.isSet(corefileOption)) { launchMode = "corefile"; executableCoreFilename = parser.value(corefileOption); } if (parser.isSet(projectOption)) { launchMode = "project"; projectFilename = parser.value(projectOption); } if (parser.isSet(configOption)) { launchMode = "configdialog"; } if (parser.isSet(gdbProgramOption)) { gdbProgram = parser.value(gdbProgramOption); } if (parser.isSet(gdbArgumentsOption)) { gdbArguments = parser.value(gdbArgumentsOption); } // // Start Seer // SeerMainWindow seer; seer.setExecutableName(executableName); seer.setExecutableWorkingDirectory(executableWorkingDirectory); seer.setExecutableSymbolName(executableSymbolFilename); seer.setExecutableArguments(positionalArguments); if (executableBreakpointsFilename != "") { seer.setExecutableBreakpointsFilename(executableBreakpointsFilename); } if (executableBreakpointFunctionName != "") { seer.setExecutableBreakpointFunctionName(executableBreakpointFunctionName); } if (executableBreakpointSourceFilenameAndLineno != "") { seer.setExecutableBreakpointSourceName(executableBreakpointSourceFilenameAndLineno); } if (executableShowAssemblyTab != "") { if (executableShowAssemblyTab == "yes") { seer.setExecutableShowAssemblyTabMode("always"); }else if (executableShowAssemblyTab == "no") { seer.setExecutableShowAssemblyTabMode("never"); }else if (executableShowAssemblyTab == "auto") { seer.setExecutableShowAssemblyTabMode("auto"); }else{ printf("%s: Unknown --show-assembly-tab option '%s'\n", qPrintable(QCoreApplication::applicationName()), qPrintable(executableShowAssemblyTab)); return 1; } } if (executableStartAddressRandomize != "") { if (executableStartAddressRandomize == "yes") { seer.setExecutableRandomizeStartAddress(true); }else if (executableStartAddressRandomize == "no") { seer.setExecutableRandomizeStartAddress(false); }else{ printf("%s: Unknown --start-address-randomize option '%s'\n", qPrintable(QCoreApplication::applicationName()), qPrintable(executableStartAddressRandomize)); return 1; } } if (executableNonStopMode != "") { if (executableNonStopMode == "yes") { seer.setExecutableNonStopMode(true); }else if (executableNonStopMode == "no") { seer.setExecutableNonStopMode(false); }else{ printf("%s: Unknown --non-stop-mode option '%s'\n", qPrintable(QCoreApplication::applicationName()), qPrintable(executableNonStopMode)); return 1; } } if (gdbProgram != "") { seer.setGdbProgramOverride(gdbProgram); } if (gdbArguments != "") { seer.setGdbArgumentsOverride(gdbArguments); } qDebug() << "EXECUTABLENAME" << executableName; qDebug() << "WORKINGDIRECTORY" << executableWorkingDirectory; qDebug() << "SYMBOLNAME" << executableSymbolFilename; qDebug() << "PID" << executablePid; qDebug() << "CONNECTHOST" << executableConnectHostPort; qDebug() << "RRTRACEDIRECTORY" << executableRRTraceDirectory; qDebug() << "COREFILENAME" << executableCoreFilename; qDebug() << "PROJECTFILE" << projectFilename; qDebug() << "ARGUMENTS" << positionalArguments; seer.setExecutablePid(executablePid); seer.setExecutableConnectHostPort(executableConnectHostPort); seer.setExecutableRRTraceDirectory(executableRRTraceDirectory); seer.setExecutableCoreFilename(executableCoreFilename); seer.setProjectFilename(projectFilename); seer.launchExecutable(launchMode, breakMode); seer.show(); seer.activateWindow(); return app.exec(); } epasveer-seer-97076f1/src/seerutl_test.cpp000066400000000000000000000004611526321767600206020ustar00rootroot00000000000000#include "SeerUtl.h" #include int main (int argc, char* argv[]) { Q_UNUSED(argc); Q_UNUSED(argv); QString text("Function\\n1"); QString result; result = Seer::filterEscapes(text); qDebug().noquote() << text; qDebug().noquote() << result; return 1; }