re-work build/package; add prefs dlg; add config.h generation

This commit is contained in:
Christopher A. Mosher 2022-12-04 16:33:27 -05:00
parent dd6f36048d
commit 3301251d90
34 changed files with 1826 additions and 164 deletions

View File

@ -7,7 +7,6 @@ on:
env:
name: "epple2"
desc: "Apple ][ emulator"
deb_depends: "libsdl2-2.0-0"
jobs:
"build-roms":
@ -24,7 +23,7 @@ jobs:
- name: "Build"
run: |
set -x
cd rom
cd share/Resources/rom
mkdir build
cd build
cmake ..
@ -33,174 +32,234 @@ jobs:
- uses: "actions/upload-artifact@v3"
with:
name: "epple2-roms"
path: "./rom/*.a65"
path: "share/Resources/rom/*.a65"
"build-epple2-ubuntu":
needs: "build-roms"
runs-on: "ubuntu-latest"
"build":
strategy:
matrix:
include:
- os: "ubuntu-22.04"
shell: "bash"
- os: "macos-12"
shell: "bash"
- os: "windows-latest"
shell: "msys2 {0}"
runs-on: "${{ matrix.os }}"
defaults:
run:
shell: "${{ matrix.shell }}"
steps:
- name: "Prepare runner"
run: |
set -x
sudo apt-get update -qqqq
sudo apt-get install -qqqq libsdl2-dev tree
- uses: "actions/checkout@v3"
- name: "Build"
run: |
set -x
mkdir build
cd build
cmake ..
cmake --build .
- uses: "msys2/setup-msys2@v2"
if: ${{ runner.os == 'Windows' }}
with:
update: true
pacboy: >-
toolchain:p
cmake:p
ninja:p
boost:p
wxwidgets3.2-msw:p
SDL2:p
- name: "Set up environment"
run: "./bin/${{ runner.os }}/setup.sh"
- uses: "actions/download-artifact@v3"
with:
name: "epple2-roms"
path: "build/epple2-roms"
- name: "Stage"
run: |
set -x
pwd
cd build
mkdir -p stage/usr/local/bin
mkdir -p stage/usr/local/etc/epple2
mkdir -p stage/usr/local/lib/epple2/system
mkdir -p stage/usr/local/lib/epple2/cards
cp src/epple2 stage/usr/local/bin/
cp conf/*.conf stage/usr/local/etc/epple2/
cp epple2-roms/epple2sys.a65 stage/usr/local/lib/epple2/system/
cp epple2-roms/stdout.a65 stage/usr/local/lib/epple2/cards/
cp epple2-roms/stdin.a65 stage/usr/local/lib/epple2/cards/
cp epple2-roms/clock.a65 stage/usr/local/lib/epple2/cards/
tree stage
- name: "Package"
uses: "jiro4989/build-deb-action@v2"
with:
package: "${{ env.name }}"
desc: "${{ env.desc }}"
maintainer: "${{ github.repository_owner }}"
version: "${{ github.ref }}"
arch: "amd64"
package_root: "build/stage"
depends: "${{ env.deb_depends }}"
- uses: "softprops/action-gh-release@v1"
with:
files: |
*.deb
"build-epple2-macos":
needs: "build-roms"
runs-on: "macos-latest"
steps:
- name: "Prepare runner"
run: |
set -x
HOMEBREW_NO_AUTO_UPDATE=1 brew install sdl2 tree
- uses: "actions/checkout@v3"
path: "share/Resources/rom"
- name: "Build"
run: |
set -x
mkdir build
cd build
cmake ..
cmake --build .
- uses: "actions/download-artifact@v3"
with:
name: "epple2-roms"
path: "build/epple2-roms"
- name: "Stage"
run: |
set -x
pwd
cd build
mkdir -p stage/local/bin
mkdir -p stage/local/etc/epple2
mkdir -p stage/local/lib/epple2/system
mkdir -p stage/local/lib/epple2/cards
cp src/epple2 stage/local/bin/
cp conf/*.conf stage/local/etc/epple2/
cp epple2-roms/epple2sys.a65 stage/local/lib/epple2/system/
cp epple2-roms/stdout.a65 stage/local/lib/epple2/cards/
cp epple2-roms/stdin.a65 stage/local/lib/epple2/cards/
cp epple2-roms/clock.a65 stage/local/lib/epple2/cards/
cp /usr/local/lib/libSDL2.dylib stage/local/bin/
tree stage
- name: "Package"
run: |
set -x
pkgbuild --identifier nu.mine.mosher.$name --root build/stage --install-location /usr $name.pkg
run: "./bin/build.sh"
- uses: "softprops/action-gh-release@v1"
with:
draft: true
prerelease: true
tag_name: "${{ env.git_tag }}"
files: |
*.pkg
tmp/cpack/*.zip
tmp/cpack/*.tar.gz
tmp/cpack/*.7z
tmp/cpack/*.deb
tmp/cpack/*.dmg
tmp/cpack/*.exe
"build-epple2-windows":
needs: "build-roms"
runs-on: "windows-latest"
steps:
- name: "Prepare runner"
run: |
Invoke-WebRequest -Uri "https://github.com/libsdl-org/SDL/releases/download/release-2.24.2/SDL2-devel-2.24.2-VC.zip" -OutFile "C:/Program Files/SDL2-devel-VC.zip"
Expand-Archive -LiteralPath "C:/Program Files/SDL2-devel-VC.zip" -DestinationPath "C:/Program Files/"
- uses: "actions/checkout@v3"
- name: "Build"
shell: "bash"
run: |
set -x
mkdir build
cd build
cmake ..
cmake --build .
- uses: "actions/download-artifact@v3"
with:
name: "epple2-roms"
path: "build/epple2-roms"
- name: "Stage"
shell: "bash"
run: |
set -x
pwd
cd build
mkdir -p stage/epple2/etc/epple2
mkdir -p stage/epple2/lib/epple2/system
mkdir -p stage/epple2/lib/epple2/cards
cp src/Debug/epple2.exe stage/epple2/
cp conf/*.conf stage/epple2/etc/epple2/
cp epple2-roms/epple2sys.a65 stage/epple2/lib/epple2/system/
cp epple2-roms/stdout.a65 stage/epple2/lib/epple2/cards/
cp epple2-roms/stdin.a65 stage/epple2/lib/epple2/cards/
cp epple2-roms/clock.a65 stage/epple2/lib/epple2/cards/
cp "C:/Program Files/SDL2-2.24.2/lib/x64/SDL2.dll" stage/epple2/
- name: "Package"
uses: "thedoctor0/zip-release@main"
with:
directory: "build/stage"
path: "${{ env.name }}"
filename: "${{ env.name }}-windows.zip"
- uses: "softprops/action-gh-release@v1"
with:
files: |
build/stage/*.zip
# "build-epple2-ubuntu":
# needs: "build-roms"
# runs-on: "ubuntu-latest"
# steps:
# - name: "Prepare runner"
# run: |
# set -x
# sudo apt-get update -qqqq
# sudo apt-get install -qqqq libsdl2-dev tree
#
# - uses: "actions/checkout@v3"
#
# - name: "Build"
# run: |
# set -x
# mkdir build
# cd build
# cmake ..
# cmake --build .
#
# - uses: "actions/download-artifact@v3"
# with:
# name: "epple2-roms"
# path: "build/epple2-roms"
#
# - name: "Stage"
# run: |
# set -x
# pwd
# cd build
# mkdir -p stage/usr/local/bin
# mkdir -p stage/usr/local/etc/epple2
# mkdir -p stage/usr/local/lib/epple2/system
# mkdir -p stage/usr/local/lib/epple2/cards
# cp src/epple2 stage/usr/local/bin/
# cp conf/*.conf stage/usr/local/etc/epple2/
# cp epple2-roms/epple2sys.a65 stage/usr/local/lib/epple2/system/
# cp epple2-roms/stdout.a65 stage/usr/local/lib/epple2/cards/
# cp epple2-roms/stdin.a65 stage/usr/local/lib/epple2/cards/
# cp epple2-roms/clock.a65 stage/usr/local/lib/epple2/cards/
# tree stage
#
# - name: "Package"
# uses: "jiro4989/build-deb-action@v2"
# with:
# package: "${{ env.name }}"
# desc: "${{ env.desc }}"
# maintainer: "${{ github.repository_owner }}"
# version: "${{ github.ref }}"
# arch: "amd64"
# package_root: "build/stage"
# depends: "${{ env.deb_depends }}"
#
# - uses: "softprops/action-gh-release@v1"
# with:
# files: |
# *.deb
#
#
#
# "build-epple2-macos":
# needs: "build-roms"
# runs-on: "macos-latest"
# steps:
# - name: "Prepare runner"
# run: |
# set -x
# HOMEBREW_NO_AUTO_UPDATE=1 brew install sdl2 tree
#
# - uses: "actions/checkout@v3"
#
# - name: "Build"
# run: |
# set -x
# mkdir build
# cd build
# cmake ..
# cmake --build .
#
# - uses: "actions/download-artifact@v3"
# with:
# name: "epple2-roms"
# path: "build/epple2-roms"
#
# - name: "Stage"
# run: |
# set -x
# pwd
# cd build
# mkdir -p stage/local/bin
# mkdir -p stage/local/etc/epple2
# mkdir -p stage/local/lib/epple2/system
# mkdir -p stage/local/lib/epple2/cards
# cp src/epple2 stage/local/bin/
# cp conf/*.conf stage/local/etc/epple2/
# cp epple2-roms/epple2sys.a65 stage/local/lib/epple2/system/
# cp epple2-roms/stdout.a65 stage/local/lib/epple2/cards/
# cp epple2-roms/stdin.a65 stage/local/lib/epple2/cards/
# cp epple2-roms/clock.a65 stage/local/lib/epple2/cards/
# cp /usr/local/lib/libSDL2.dylib stage/local/bin/
# tree stage
#
# - name: "Package"
# run: |
# set -x
# pkgbuild --identifier nu.mine.mosher.$name --root build/stage --install-location /usr $name.pkg
#
# - uses: "softprops/action-gh-release@v1"
# with:
# files: |
# *.pkg
#
#
#
# "build-epple2-windows":
# needs: "build-roms"
# runs-on: "windows-latest"
# steps:
# - name: "Prepare runner"
# run: |
# Invoke-WebRequest -Uri "https://github.com/libsdl-org/SDL/releases/download/release-2.24.2/SDL2-devel-2.24.2-VC.zip" -OutFile "C:/Program Files/SDL2-devel-VC.zip"
# Expand-Archive -LiteralPath "C:/Program Files/SDL2-devel-VC.zip" -DestinationPath "C:/Program Files/"
#
# - uses: "actions/checkout@v3"
#
# - name: "Build"
# shell: "bash"
# run: |
# set -x
# mkdir build
# cd build
# cmake ..
# cmake --build .
#
# - uses: "actions/download-artifact@v3"
# with:
# name: "epple2-roms"
# path: "build/epple2-roms"
#
# - name: "Stage"
# shell: "bash"
# run: |
# set -x
# pwd
# cd build
# mkdir -p stage/epple2/etc/epple2
# mkdir -p stage/epple2/lib/epple2/system
# mkdir -p stage/epple2/lib/epple2/cards
# cp src/Debug/epple2.exe stage/epple2/
# cp conf/*.conf stage/epple2/etc/epple2/
# cp epple2-roms/epple2sys.a65 stage/epple2/lib/epple2/system/
# cp epple2-roms/stdout.a65 stage/epple2/lib/epple2/cards/
# cp epple2-roms/stdin.a65 stage/epple2/lib/epple2/cards/
# cp epple2-roms/clock.a65 stage/epple2/lib/epple2/cards/
# cp "C:/Program Files/SDL2-2.24.2/lib/x64/SDL2.dll" stage/epple2/
#
# - name: "Package"
# uses: "thedoctor0/zip-release@main"
# with:
# directory: "build/stage"
# path: "${{ env.name }}"
# filename: "${{ env.name }}-windows.zip"
#
# - uses: "softprops/action-gh-release@v1"
# with:
# files: |
# build/stage/*.zip

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
# cmake
/build/
/tmp/
# netbeans
/nbproject/

View File

@ -3,10 +3,13 @@ cmake_minimum_required(VERSION 3.22.1)
set(CMAKE_VERBOSE_MAKEFILE TRUE CACHE BOOL "Echo make commands.")
set(PACKAGE_SUITE TRUE CACHE BOOL "Build entire suite of packages; otherwise just ZIP file.")
#set(CMAKE_BUILD_TYPE RelWithDebInfo)
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_BUILD_TYPE RelWithDebInfo)
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
set(APP_NAME epple2)
project(${APP_NAME}
@ -100,6 +103,7 @@ paddlebuttonstates.cpp
paddles.cpp
picturegenerator.cpp
powerupreset.cpp
PreferencesDialog.cpp
screenimage.cpp
SegmentCache.cpp
slots.cpp
@ -123,10 +127,24 @@ wozfile.cpp
list(TRANSFORM sources PREPEND "src/")
set(resources
#epple2.xrc
#epple2.png
epple2.xrc
epple2.png
conf/epple2.conf
conf/epple2.rev0bare.conf
conf/epple2.a2bare.conf
conf/epple2.a2dos31.conf
conf/epple2.a2dos33.conf
conf/epple2.a2loaded.conf
conf/epple2.a2pbare.conf
conf/epple2.a2pdos33.conf
conf/epple2.a2ploaded.conf
conf/epple2.visual6502.conf
rom/epple2sys.a65
rom/stdout.a65
rom/clock.a65
rom/stdin.a65
)
list(TRANSFORM resources PREPEND "share/Resources/")
add_executable(${APP_NAME} WIN32 MACOSX_BUNDLE ${sources} ${resources})
@ -158,6 +176,12 @@ target_link_libraries(${APP_NAME} PRIVATE ${wxWidgets_LIBRARIES})
configure_file(src/config.h.in config.h)
include_directories(${PROJECT_BINARY_DIR})
# TODO: can we remove this without being too backwardly incompatible?
target_compile_definitions(${APP_NAME} PRIVATE ETCDIR="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}")
@ -165,3 +189,53 @@ target_compile_definitions(${APP_NAME} PRIVATE ETCDIR="${CMAKE_INSTALL_PREFIX}/$
set_target_properties(${APP_NAME} PROPERTIES RESOURCE "${resources}")
include(InstallRequiredSystemLibraries)
if(APPLE)
set_target_properties(${APP_NAME} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${PROJECT_BINARY_DIR}/Info.plist)
install(TARGETS ${APP_NAME}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
BUNDLE DESTINATION .)
configure_file(share/FixBundle.cmake.in ${PROJECT_BINARY_DIR}/FixBundle.cmake @ONLY)
install(SCRIPT ${PROJECT_BINARY_DIR}/FixBundle.cmake)
elseif(WIN32)
install(TARGETS ${APP_NAME}
RUNTIME_DEPENDENCIES
DIRECTORIES ${CMAKE_SYSTEM_LIBRARY_PATH}
PRE_EXCLUDE_REGEXES "api-ms-" "ext-ms-"
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
BUNDLE DESTINATION .
RESOURCE DESTINATION share/Resources)
else()
install(TARGETS ${APP_NAME}
RUNTIME_DEPENDENCIES
DIRECTORIES ${CMAKE_SYSTEM_LIBRARY_PATH}
RESOURCE DESTINATION share/Resources)
endif()
set(CPACK_GENERATOR ZIP)
if(PACKAGE_SUITE)
set(CPACK_GENERATOR ${CPACK_GENERATOR} TGZ 7Z)
if(APPLE)
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}-macOS")
configure_file(share/Info.plist.in ${PROJECT_BINARY_DIR}/Info.plist)
set(CPACK_GENERATOR ${CPACK_GENERATOR} DragNDrop)
elseif(WIN32)
set(CPACK_GENERATOR ${CPACK_GENERATOR} NSIS)
else()
set(CPACK_GENERATOR ${CPACK_GENERATOR} DEB)
endif()
endif()
include(CPack)

10
bin/Linux/setup.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
echo "::group::configure kinetic"
sudo add-apt-repository "deb http://mirror.math.princeton.edu/pub/ubuntu kinetic main universe"
echo "::endgroup::"
echo "::group::install dependencies"
sudo apt-get -qqqq update
sudo apt-get -qqqq install libboost-all-dev libwxgtk3.2-dev libsdl2-dev
echo "::endgroup::"

3
bin/Windows/setup.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
exit 0

32
bin/build.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/sh
set -e
if [ -e "$1/CMakeCache.txt" ] ; then
builddir="$1"
else
mkdir -p tmp
builddir=$(mktemp -d tmp/tmp.XXXXXXXXXX)
fi
cd $builddir
# TODO: fix version number
if [ "$GITHUB_ENV" != "" ] ; then
echo "git_tag=2.0.0-$(date +%Y%m%d.%H%M%S)" >>$GITHUB_ENV
fi
echo "::group::cmake"
cmake ../..
echo "::endgroup::"
echo "::group::cmake --build"
cmake --build .
echo "::endgroup::"
if [ "$1" = "-n" ] ; then
exit 0
fi
echo "::group::cpack"
cpack -B ../cpack/
echo "::endgroup::"

6
bin/macOS/setup.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
echo "::group::install dependencies"
export HOMEBREW_NO_AUTO_UPDATE=1
brew install boost wxwidgets sdl2
echo "::endgroup::"

16
share/FixBundle.cmake.in Normal file
View File

@ -0,0 +1,16 @@
include(BundleUtilities)
# Set bundle to the full path name of the executable already
# existing in the install tree:
set(bundle "${CMAKE_INSTALL_PREFIX}/@APP_NAME@.app")
# Set other_libs to a list of full path names to additional
# libraries that cannot be reached by dependency analysis.
# (Dynamically loaded PlugIns, for example.)
set(other_libs "")
# Set dirs to a list of directories where prerequisite libraries
# may be found:
set(dirs "@CMAKE_RUNTIME_OUTPUT_DIRECTORY@" "@CMAKE_LIBRARY_OUTPUT_DIRECTORY@")
fixup_bundle("${bundle}" "${other_libs}" "${dirs}")

22
share/Info.plist.in Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist>
<dict>
<key>CFBundleName</key>
<string>@CMAKE_PROJECT_NAME@</string>
<key>CFBundleDisplayName</key>
<string>@CMAKE_PROJECT_NAME@</string>
<key>CFBundleIdentifier</key>
<string>@CPACK_PACKAGE_VENDOR@.@CMAKE_PROJECT_NAME@</string>
<key>CFBundleVersion</key>
<string>@PROJECT_VERSION@</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>@PROJECT_FOURCC@</string>
<key>CFBundleExecutable</key>
<string>@CMAKE_PROJECT_NAME@</string>
<key>CFBundleIconFile</key>
<string>@CMAKE_PROJECT_NAME@</string>
</dict>
</plist>

879
share/Resources/epple2.fbp Normal file
View File

@ -0,0 +1,879 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="16" />
<object class="Project" expanded="1">
<property name="class_decoration">; </property>
<property name="code_generation">XRC</property>
<property name="disconnect_events">1</property>
<property name="disconnect_mode">source_name</property>
<property name="disconnect_php_events">0</property>
<property name="disconnect_python_events">0</property>
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="event_generation">connect</property>
<property name="file">epple2</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="image_path_wrapper_function_name"></property>
<property name="indent_with_spaces"></property>
<property name="internationalize">0</property>
<property name="name">epple2</property>
<property name="namespace"></property>
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="relative_path">1</property>
<property name="skip_lua_events">1</property>
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_array_enum">0</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<object class="Dialog" expanded="1">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
<property name="bg"></property>
<property name="center">wxBOTH</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="enabled">1</property>
<property name="event_handler">impl_virtual</property>
<property name="extra_style"></property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">Preferences</property>
<property name="pos"></property>
<property name="size">1024,768</property>
<property name="style">wxCAPTION|wxCLOSE_BOX|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU</property>
<property name="subclass">; ; forward_declare</property>
<property name="title">Preferences</property>
<property name="tooltip"></property>
<property name="two_step_creation">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">szrvTop</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">10</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">szrvMain</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxSplitterWindow" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_pane_size">0</property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_splitter1</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="sashgravity">0.25</property>
<property name="sashpos">0</property>
<property name="sashsize">-1</property>
<property name="show">1</property>
<property name="size"></property>
<property name="splitmode">wxSPLIT_VERTICAL</property>
<property name="style">wxSP_LIVE_UPDATE</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<object class="splitteritem" expanded="1">
<object class="wxPanel" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_panel1</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">szrvItemTree</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxTreeCtrl" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">treItems</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxTR_FULL_ROW_HIGHLIGHT|wxTR_HAS_BUTTONS|wxTR_HAS_VARIABLE_ROW_HEIGHT|wxTR_LINES_AT_ROOT|wxTR_TWIST_BUTTONS</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxHSCROLL|wxVSCROLL</property>
</object>
</object>
</object>
</object>
</object>
<object class="splitteritem" expanded="1">
<object class="wxPanel" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_panel2</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">szrvCurrentItem</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">szrvItemFields</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">0</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">szrhItemControl</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Active</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">chkActive</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">25</property>
<property name="flag">wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Duplicate</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">btnDuplicate</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">0</property>
<property name="flag"></property>
<property name="proportion">0</property>
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Delete</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">btnDelete</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxEXPAND|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticBoxSizer" expanded="1">
<property name="id">wxID_ANY</property>
<property name="label">name</property>
<property name="minimum_size"></property>
<property name="name">szrsName</property>
<property name="orient">wxHORIZONTAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">7</property>
<property name="flag">wxLEFT|wxTOP</property>
<property name="proportion">1</property>
<object class="wxStaticText" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Example text here</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">txtName</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxST_ELLIPSIZE_MIDDLE</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxEXPAND|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Rename</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">btnRename</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxEXPAND|wxTOP</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">szrhConfig</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxTextCtrl" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="maxlength"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,-1</property>
<property name="moveable">1</property>
<property name="name">txtConfig</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size">-1,-1</property>
<property name="style">wxTE_DONTWRAP|wxTE_MULTILINE|wxTE_PROCESS_TAB</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">0</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">szrhControl</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">0</property>
<property name="flag">wxALIGN_BOTTOM</property>
<property name="proportion">1</property>
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">0</property>
<property name="flag">wxALIGN_BOTTOM|wxALL</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">1</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Close</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">wxID_OK</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">m_btnCloseOnButtonClick</event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</wxFormBuilder_Project>

BIN
share/Resources/epple2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

181
share/Resources/epple2.xrc Normal file
View File

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<resource xmlns="http://www.wxwidgets.org/wxxrc" version="2.5.3.0">
<object class="wxDialog" name="Preferences">
<style>wxCAPTION|wxCLOSE_BOX|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU</style>
<size>1024,768</size>
<title>Preferences</title>
<centered>1</centered>
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>10</border>
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>1</option>
<flag>wxEXPAND</flag>
<border>5</border>
<object class="wxSplitterWindow" name="m_splitter1">
<style>wxSP_LIVE_UPDATE</style>
<sashpos>0</sashpos>
<gravity>0.25</gravity>
<minsize>0</minsize>
<orientation>vertical</orientation>
<object class="wxPanel" name="m_panel1">
<style>wxTAB_TRAVERSAL</style>
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxTreeCtrl" name="treItems">
<style>wxTR_FULL_ROW_HIGHLIGHT|wxTR_HAS_BUTTONS|wxTR_HAS_VARIABLE_ROW_HEIGHT|wxTR_LINES_AT_ROOT|wxTR_TWIST_BUTTONS|wxHSCROLL|wxVSCROLL</style>
</object>
</object>
</object>
</object>
<object class="wxPanel" name="m_panel2">
<style>wxTAB_TRAVERSAL</style>
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>0</option>
<flag>wxEXPAND</flag>
<border>5</border>
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>0</option>
<flag>wxEXPAND</flag>
<border>0</border>
<object class="wxBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="sizeritem">
<option>0</option>
<flag>wxALIGN_CENTER_VERTICAL|wxLEFT</flag>
<border>5</border>
<object class="wxCheckBox" name="chkActive">
<label>Active</label>
<checked>0</checked>
</object>
</object>
<object class="spacer">
<option>1</option>
<flag>wxEXPAND</flag>
<border>5</border>
<size>0,0</size>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxRIGHT</flag>
<border>25</border>
<object class="wxButton" name="btnDuplicate">
<label>Duplicate</label>
<default>0</default>
<auth_needed>0</auth_needed>
<markup>0</markup>
<bitmap />
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag></flag>
<border>0</border>
<object class="wxButton" name="btnDelete">
<label>Delete</label>
<default>0</default>
<auth_needed>0</auth_needed>
<markup>0</markup>
<bitmap />
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxBOTTOM|wxEXPAND|wxLEFT</flag>
<border>5</border>
<object class="wxStaticBoxSizer">
<orient>wxHORIZONTAL</orient>
<label>name</label>
<object class="sizeritem">
<option>1</option>
<flag>wxLEFT|wxTOP</flag>
<border>7</border>
<object class="wxStaticText" name="txtName">
<style>wxST_ELLIPSIZE_MIDDLE</style>
<label>Example text here</label>
<wrap>-1</wrap>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxBOTTOM|wxEXPAND|wxRIGHT</flag>
<border>5</border>
<object class="wxButton" name="btnRename">
<label>Rename</label>
<default>0</default>
<auth_needed>0</auth_needed>
<markup>0</markup>
<bitmap />
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<flag>wxBOTTOM|wxEXPAND|wxTOP</flag>
<border>5</border>
<object class="wxBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="sizeritem">
<option>1</option>
<flag>wxEXPAND</flag>
<border>5</border>
<object class="wxTextCtrl" name="txtConfig">
<style>wxTE_DONTWRAP|wxTE_MULTILINE|wxTE_PROCESS_TAB</style>
<value></value>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxEXPAND</flag>
<border>0</border>
<object class="wxBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="spacer">
<option>1</option>
<flag>wxALIGN_BOTTOM</flag>
<border>0</border>
<size>0,0</size>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxALIGN_BOTTOM|wxALL</flag>
<border>0</border>
<object class="wxButton" name="wxID_OK">
<label>Close</label>
<default>1</default>
<auth_needed>0</auth_needed>
<markup>0</markup>
<bitmap />
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</resource>

View File

@ -20,7 +20,7 @@
#include "E2wxFrame.h"
#include "E2wxApp.h"
//#include "PreferencesDialog.h"
#include "PreferencesDialog.h"
#include <wx/persist/toplevel.h>
@ -90,7 +90,7 @@ void E2wxFrame::OnAbout(wxCommandEvent& event) {
}
void E2wxFrame::OnPreferences(wxCommandEvent& event) {
// PreferencesDialog *dlg = new PreferencesDialog(this);
// dlg->OnInit();
// dlg->ShowModal();
PreferencesDialog *dlg = new PreferencesDialog(this);
dlg->OnInit();
dlg->ShowModal();
}

335
src/PreferencesDialog.cpp Normal file
View File

@ -0,0 +1,335 @@
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include "PreferencesDialog.h"
#include "E2wxApp.h"
#include <wx/msgdlg.h>
#include <wx/treectrl.h>
#include <wx/textctrl.h>
#include <wx/checkbox.h>
#include <wx/textdlg.h>
#include <wx/xrc/xmlres.h>
#include <wx/config.h>
#include <wx/dir.h>
#include <wx/filename.h>
#include <boost/log/trivial.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
#include <ostream>
#include <fstream>
#include <sstream>
#define CTRL(t,n) t* n = XRCCTRL(*this, #n, t)
static const wxSize& SIZ_DLG = wxSize(1024,768);
wxBEGIN_EVENT_TABLE(PreferencesDialog, wxDialog)
EVT_CLOSE(PreferencesDialog::OnClose)
EVT_BUTTON(wxID_OK, PreferencesDialog::OnCloseButton)
EVT_TREE_SEL_CHANGED(XRCID("treItems"), PreferencesDialog::OnTreeSelectionChanged)
EVT_CHECKBOX(XRCID("chkActive"), PreferencesDialog::OnActive)
EVT_BUTTON(XRCID("btnDuplicate"), PreferencesDialog::OnDuplicate)
EVT_BUTTON(XRCID("btnDelete"), PreferencesDialog::OnDelete)
EVT_BUTTON(XRCID("btnRename"), PreferencesDialog::OnRename)
wxEND_EVENT_TABLE()
class TreeItemData : public wxTreeItemData {
const std::filesystem::path *m_path;
const bool m_editable;
public:
TreeItemData() : m_path(NULL), m_editable(false) {}
TreeItemData(const std::filesystem::path& path, bool editable) :
m_path(new std::filesystem::path(path)),
m_editable(editable) {
}
virtual bool isFile() const { return true; }
bool isEditable() const { return m_editable; }
const std::filesystem::path path() const { return *m_path; }
};
class EmptyTreeItem : public TreeItemData {
virtual bool isFile() const { return false; }
};
class TreeSink : public wxDirTraverser {
public:
TreeSink(wxTreeCtrl *tree, wxTreeItemId parent, const std::filesystem::path& dir, bool editable) :
m_tree(tree), m_parent(parent), m_dir(dir), m_editable(editable) {
}
wxDirTraverseResult OnFile(const wxString& filename) {
wxFileName n = wxFileName::FileName(filename);
if (n.GetExt() == "conf") {
const std::filesystem::path& full = std::filesystem::path(n.GetFullName().t_str());
const std::filesystem::path path = m_dir / full;
m_tree->AppendItem(m_parent, n.GetName(), -1, -1, new TreeItemData(path, m_editable));
}
return wxDIR_CONTINUE;
}
wxDirTraverseResult OnDir(const wxString& dirname) {
return wxDIR_CONTINUE;
}
private:
wxTreeCtrl *m_tree;
const wxTreeItemId m_parent;
const std::filesystem::path& m_dir;
const bool m_editable;
};
PreferencesDialog::PreferencesDialog(wxWindow* parent) : parent(parent) {
}
PreferencesDialog::~PreferencesDialog() {
}
void PreferencesDialog::OnClose(wxCloseEvent& event) {
CTRL(wxTreeCtrl, treItems);
const TreeItemData *data = (TreeItemData*)treItems->GetItemData(treItems->GetSelection());
if (data->isFile()) {
if (data->isEditable()) {
Save(data->path());
}
}
EndModal(wxID_OK);
}
static void fillDir(wxTreeCtrl *treItems, wxTreeItemId item, const std::filesystem::path& dir, bool editable = false) {
TreeSink sink(treItems, item, dir, editable);
wxDir dirBuiltIn = wxDir(dir.c_str());
dirBuiltIn.Traverse(sink, wxEmptyString, wxDIR_FILES | wxDIR_HIDDEN);
}
void PreferencesDialog::BuildItemTree() {
CTRL(wxTreeCtrl, treItems);
treItems->DeleteAllItems();
wxTreeItemId configs = treItems->AddRoot(wxT("configurations"), -1, -1, new EmptyTreeItem());
wxTreeItemId user = treItems->AppendItem(configs, wxT("user"), -1, -1, new EmptyTreeItem());
fillDir(treItems, user, wxGetApp().GetConfigDir(), true);
treItems->SortChildren(user);
wxTreeItemId built_in = treItems->AppendItem(configs, wxT("built-in"), -1, -1, new EmptyTreeItem());
fillDir(treItems, built_in, wxGetApp().GetResDir());
treItems->SortChildren(built_in);
treItems->ExpandAll();
this->GetSizer()->Layout();
}
void PreferencesDialog::OnInit() {
wxConfigBase *appconf = wxConfigBase::Get();
if (!appconf->Read(wxT("/ActivePreferences/name"), &this->active)) {
// TODO what to do when no config?
this->active = ".template";
appconf->Write(wxT("/ActivePreferences/name"), this->active);
appconf->Flush();
}
wxXmlResource::Get()->LoadDialog(this, this->parent, "Preferences");
SetSize(SIZ_DLG);
BuildItemTree();
CTRL(wxTreeCtrl, treItems);
treItems->SetFocus();
treItems->SelectItem(treItems->GetRootItem());
}
void PreferencesDialog::Save(const std::filesystem::path& to) {
CTRL(wxTextCtrl, txtConfig);
const wxString sConfig = txtConfig->GetValue();
if (sConfig != this->sOrigConfig) {
std::ofstream out(to);
out << sConfig;
this->sOrigConfig = sConfig;
}
}
void PreferencesDialog::OnTreeSelectionChanged(wxTreeEvent& evt) {
// note: we don't get the first select upon dialog creation,
// nor the final de-select upon dialog destruction
CTRL(wxTreeCtrl, treItems);
CTRL(wxStaticText, txtName);
CTRL(wxTextCtrl, txtConfig);
CTRL(wxCheckBox, chkActive);
const TreeItemData *dataOld = (TreeItemData*)treItems->GetItemData(evt.GetOldItem());
wxString pathOld = "(not a file)";
if (dataOld->isFile()) {
pathOld = dataOld->path().c_str();
Save(dataOld->path());
}
const TreeItemData *dataNew = (TreeItemData*)treItems->GetItemData(evt.GetItem());
wxString pathNew = "(not a file)";
if (dataNew->isFile()) {
pathNew = dataNew->path().c_str();
std::ifstream t(dataNew->path());
std::stringstream buffer;
buffer << t.rdbuf();
this->sOrigConfig = buffer.str();
txtConfig->SetValue(this->sOrigConfig);
wxString name = wxFileName::FileName(dataNew->path().c_str()).GetName();
txtName->SetLabel(name);
chkActive->SetValue(name == this->active);
} else {
this->sOrigConfig = wxEmptyString;
txtConfig->SetValue(this->sOrigConfig);
txtName->SetLabel(wxEmptyString);
chkActive->SetValue(false);
}
}
void PreferencesDialog::PreSelectUserConfigItemName(const std::filesystem::path& n) {
CTRL(wxTreeCtrl, treItems);
wxTreeItemId id = treItems->GetRootItem();
wxTreeItemIdValue ctx;
wxTreeItemId i = treItems->GetFirstChild(id, ctx);
while (i.IsOk() && treItems->GetItemText(i) != wxT("user")) {
i = treItems->GetNextChild(id, ctx);
}
if (!i.IsOk()) {
return;
}
id = i;
i = treItems->GetFirstChild(id, ctx);
while (i.IsOk() && treItems->GetItemText(i) != wxFileName::FileName(n.c_str()).GetName()) {
i = treItems->GetNextChild(id, ctx);
}
if (!i.IsOk()) {
return;
}
treItems->SelectItem(i);
treItems->SetFocus();
}
const std::filesystem::path BuildNewConfFilePath() {
std::filesystem::path f = wxGetApp().GetConfigDir();
wxString ts = to_iso_string(boost::posix_time::microsec_clock::universal_time());
ts.Replace(wxT("."), wxT("_"));
f /= (wxT("Untitled_") + ts + wxT(".conf")).t_str();
BOOST_LOG_TRIVIAL(info) << "will create file: " << f.c_str();
return f;
}
void PreferencesDialog::OnActive(wxCommandEvent& evt) {
if (evt.IsChecked()) {
CTRL(wxTreeCtrl, treItems);
const TreeItemData *data = (TreeItemData*)treItems->GetItemData(treItems->GetSelection());
if (data->isFile()) {
const std::filesystem::path p = data->path();
wxString name = wxFileName::FileName(p.c_str()).GetName();
this->active = name;
wxConfigBase::Get()->Write(wxT("/ActivePreferences/name"), this->active);
BuildItemTree(); // invalidates "data" pointer variable
PreSelectUserConfigItemName(p);
}
} else {
// TODO what if they uncheck the active checkbox?
}
}
void PreferencesDialog::OnDuplicate(wxCommandEvent& evt) {
CTRL(wxTreeCtrl, treItems);
const TreeItemData *data = (TreeItemData*)treItems->GetItemData(treItems->GetSelection());
if (data->isFile()) {
if (data->isEditable()) {
Save(data->path());
}
const std::filesystem::path f = BuildNewConfFilePath();
BOOST_LOG_TRIVIAL(info) << "copy from: " << data->path().c_str();
if (!std::filesystem::exists(f)) {
std::filesystem::copy_file(data->path(), f, std::filesystem::copy_options::skip_existing);
BuildItemTree();
PreSelectUserConfigItemName(f);
} else {
BOOST_LOG_TRIVIAL(error) << "file already exists: " << f.c_str();
}
}
}
void PreferencesDialog::OnDelete(wxCommandEvent& evt) {
CTRL(wxTreeCtrl, treItems);
CTRL(wxStaticText, txtName);
CTRL(wxTextCtrl, txtConfig);
const TreeItemData *data = (TreeItemData*)treItems->GetItemData(treItems->GetSelection());
if (data->isFile()) {
if (data->isEditable()) {
if (wxMessageBox(
wxT("Are you sure to want to permanently DELETE this configuration file?"),
wxT("Delete"), wxYES_NO|wxCENTER, this) == wxYES) {
std::filesystem::remove(data->path());
BuildItemTree();
treItems->SetFocus();
treItems->SelectItem(treItems->GetRootItem());
// clear out fields (TODO is there a better way?)
this->sOrigConfig = wxEmptyString;
txtConfig->SetValue(this->sOrigConfig);
txtName->SetLabel(wxEmptyString);
}
}
}
}
void PreferencesDialog::OnRename(wxCommandEvent& evt) {
CTRL(wxTreeCtrl, treItems);
const TreeItemData *data = (TreeItemData*)treItems->GetItemData(treItems->GetSelection());
if (data->isFile()) {
if (data->isEditable()) {
Save(data->path());
wxString name = wxFileName::FileName(data->path().c_str()).GetName();
wxString newname = wxGetTextFromUser(wxT("new name:"), wxT("Rename configuration"), name, this, -1, -1, true);
if (!newname.IsEmpty() && newname != name) {
wxFileName fn(data->path().c_str());
fn.SetName(newname);
// TODO should we check for existence of name in built-in (to prevent override)?
if (fn.Exists()) {
wxMessageBox(wxT("That name is already being used."), wxT("File exists"), wxOK|wxCENTER, this);
} else {
const std::filesystem::path newpath(fn.GetFullPath().t_str());
std::filesystem::rename(data->path(), newpath);
BuildItemTree();
PreSelectUserConfigItemName(newpath);
}
}
}
}
}
void PreferencesDialog::OnCloseButton(wxCommandEvent& evt) {
CTRL(wxTreeCtrl, treItems);
const TreeItemData *data = (TreeItemData*)treItems->GetItemData(treItems->GetSelection());
if (data->isFile()) {
if (data->isEditable()) {
Save(data->path());
}
}
EndModal(wxID_OK);
}

35
src/PreferencesDialog.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef PREFERENCESDIALOG_H
#define PREFERENCESDIALOG_H
#include <wx/event.h>
#include <wx/dialog.h>
#include <wx/treectrl.h>
#include <filesystem>
class PreferencesDialog : public wxDialog {
wxWindow *parent;
wxString sOrigConfig;
wxString active;
void BuildItemTree();
void PreSelectUserConfigItemName(const std::filesystem::path& n);
void Save(const std::filesystem::path& to);
void OnClose(wxCloseEvent& event);
void OnCloseButton(wxCommandEvent& evt);
void OnTreeSelectionChanged(wxTreeEvent& evt);
void OnActive(wxCommandEvent& evt);
void OnDuplicate(wxCommandEvent& evt);
void OnDelete(wxCommandEvent& evt);
void OnRename(wxCommandEvent& evt);
wxDECLARE_EVENT_TABLE();
public:
PreferencesDialog(wxWindow *parent);
~PreferencesDialog();
void OnInit();
};
#endif /* PREFERENCESDIALOG_H */

9
src/config.h.in Normal file
View File

@ -0,0 +1,9 @@
#ifndef CONFIG_H
#define CONFIG_H
#cmakedefine PROJECT_VENDOR @PROJECT_VENDOR@
#cmakedefine PROJECT_NAME @PROJECT_NAME@
#cmakedefine PROJECT_VERSION @PROJECT_VERSION@
#cmakedefine PROJECT_DESCRIPTION "@PROJECT_DESCRIPTION@"
#endif /* CONFIG_H */