wxWidgets based Stable Diffusion C++ GUi
Ferenc Szontágh
2024-02-04 1683c8a090c3efc51c43107d5ede0dcd5d506e3b
added better queue manager, some clean-up and new feature: model management (wip), progressbar
16 files modified
3 files added
3375 ■■■■■ changed files
CMakeLists.txt 6 ●●●● patch | view | raw | blame | history
README.md 21 ●●●●● patch | view | raw | blame | history
external/ggml/Debug/ggml.pdb patch | view | raw | blame | history
external/stable-diffusion.cpp/Debug/stable-diffusion.pdb patch | view | raw | blame | history
external/stable-diffusion.cpp/include/stable-diffusion.h 11 ●●●● patch | view | raw | blame | history
picosha2.h 377 ●●●●● patch | view | raw | blame | history
rest-client/civitai.hpp 16 ●●●●● patch | view | raw | blame | history
ui/MainWindow.cpp 211 ●●●●● patch | view | raw | blame | history
ui/MainWindow.h 11 ●●●● patch | view | raw | blame | history
ui/MainWindowImageViewer.h 8 ●●●●● patch | view | raw | blame | history
ui/MainWindowSettings.h 8 ●●●●● patch | view | raw | blame | history
ui/MainWindowUI.cpp 1159 ●●●● patch | view | raw | blame | history
ui/MainWindowUI.h 17 ●●●●● patch | view | raw | blame | history
ui/QueueManager.cpp 106 ●●●●● patch | view | raw | blame | history
ui/QueueManager.h 37 ●●●●● patch | view | raw | blame | history
ui/sha512.hpp 337 ●●●●● patch | view | raw | blame | history
ui/utils.hpp 77 ●●●●● patch | view | raw | blame | history
ui/windows.fbp 970 ●●●● patch | view | raw | blame | history
vcpkg.json 3 ●●●● patch | view | raw | blame | history
CMakeLists.txt
@@ -39,7 +39,7 @@
    
    if(NOT CMAKE_BUILD_TYPE)
        set(CMAKE_BUILD_TYPE Release)
        set(CMAKE_BUILD_TYPE Debug)
    endif()
    set(STABLE_DIFFUSION_LIB ${CMAKE_SOURCE_DIR}/external/stable-diffusion.cpp/${CMAKE_BUILD_TYPE}/lib/stable-diffusion.lib)
@@ -72,7 +72,6 @@
        $<TARGET_FILE_DIR:sd.ui>)                 # <--this is out-file path0
ENDIF(MSVC)
set(OpenCV_DIR "${VCPKG_INSTALLED_DIR}/x64-windows/share/opencv4")
@@ -90,6 +89,7 @@
  # target_link_libraries(sd.ui ${OpenCV_LIBS} )
endif()
find_package(restclient-cpp CONFIG REQUIRED)
find_package(fmt CONFIG REQUIRED)
find_package(wxWidgets CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
@@ -104,7 +104,7 @@
target_link_libraries(sd.ui ${CUDA_LIBRARIES})
target_link_libraries(sd.ui PRIVATE ${OpenCV_LIBS} nlohmann_json::nlohmann_json fmt::fmt wx::core wx::base wx::xrc wx::adv wx::richtext wx::aui SDLIB GGMLLIB CUDA::cudart CUDA::cublas CUDA::cublasLt CUDA::cuda_driver)
target_link_libraries(sd.ui PRIVATE restclient-cpp ${OpenCV_LIBS} nlohmann_json::nlohmann_json fmt::fmt wx::core wx::base wx::xrc wx::adv wx::richtext wx::aui SDLIB GGMLLIB CUDA::cudart CUDA::cublas CUDA::cublasLt CUDA::cuda_driver)
include_directories(ui)
README.md
@@ -43,6 +43,27 @@
## - TO-DOs
See @git.spamming.hu ticketing system
### Hash generation from binary
Repo: [okdshin/PicoSHA2](https://github.com/okdshin/PicoSHA2)
RAW file: [picosha2.h](https://raw.githubusercontent.com/okdshin/PicoSHA2/master/picosha2.h)
Example:
```C++
std::ifstream f("file.txt", std::ios::binary);
std::vector<unsigned char> s(picosha2::k_digest_size);
picosha2::hash256(f, s.begin(), s.end());
```
### restclient-cpp
Curl wrapper to civiati api:
[repo](https://github.com/mrtazz/restclient-cpp)
installed via vcpkg as cmake dependency
[CivitAi API docs](https://github.com/civitai/civitai/wiki/REST-API-Reference#get-apiv1models-versionsby-hashhash)
### - IDE
Use the vscode... Install the extensions which is recommended by the workspace
external/ggml/Debug/ggml.pdb
Binary files differ
external/stable-diffusion.cpp/Debug/stable-diffusion.pdb
Binary files differ
external/stable-diffusion.cpp/include/stable-diffusion.h
@@ -88,8 +88,10 @@
};
typedef void (*sd_log_cb_t)(enum sd_log_level_t level, const char* text, void* data);
typedef void (*sd_progress_cb_t)(int step,int steps,float time, void* data);
SD_API void sd_set_log_callback(sd_log_cb_t sd_log_cb, void* data);
SD_API void sd_set_progress_callback(sd_progress_cb_t cb, void* data);
SD_API int32_t get_num_physical_cores();
SD_API const char* sd_get_system_info();
@@ -105,14 +107,17 @@
SD_API sd_ctx_t* new_sd_ctx(const char* model_path,
                            const char* vae_path,
                            const char* taesd_path,
                            const char* control_net_path_c_str,
                            const char* lora_model_dir,
                            const char* embed_dir_c_str,
                            bool vae_decode_only,
                            bool vae_tiling,
                            bool free_params_immediately,
                            int n_threads,
                            enum sd_type_t wtype,
                            enum rng_type_t rng_type,
                            enum schedule_t s);
                            enum schedule_t s,
                            bool keep_control_net_cpu);
SD_API void free_sd_ctx(sd_ctx_t* sd_ctx);
@@ -126,7 +131,9 @@
                           enum sample_method_t sample_method,
                           int sample_steps,
                           int64_t seed,
                           int batch_count);
                           int batch_count,
                           const sd_image_t* control_cond,
                           float control_strength);
SD_API sd_image_t* img2img(sd_ctx_t* sd_ctx,
                           sd_image_t init_image,
picosha2.h
New file
@@ -0,0 +1,377 @@
/*
The MIT License (MIT)
Copyright (C) 2017 okdshin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef PICOSHA2_H
#define PICOSHA2_H
// picosha2:20140213
#ifndef PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR
#define PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR \
    1048576  //=1024*1024: default is 1MB memory
#endif
#include <algorithm>
#include <cassert>
#include <iterator>
#include <sstream>
#include <vector>
#include <fstream>
namespace picosha2 {
typedef unsigned long word_t;
typedef unsigned char byte_t;
static const size_t k_digest_size = 32;
namespace detail {
inline byte_t mask_8bit(byte_t x) { return x & 0xff; }
inline word_t mask_32bit(word_t x) { return x & 0xffffffff; }
const word_t add_constant[64] = {
    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
    0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
    0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
    0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
    0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
    0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
const word_t initial_message_digest[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372,
                                          0xa54ff53a, 0x510e527f, 0x9b05688c,
                                          0x1f83d9ab, 0x5be0cd19};
inline word_t ch(word_t x, word_t y, word_t z) { return (x & y) ^ ((~x) & z); }
inline word_t maj(word_t x, word_t y, word_t z) {
    return (x & y) ^ (x & z) ^ (y & z);
}
inline word_t rotr(word_t x, std::size_t n) {
    assert(n < 32);
    return mask_32bit((x >> n) | (x << (32 - n)));
}
inline word_t bsig0(word_t x) { return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); }
inline word_t bsig1(word_t x) { return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); }
inline word_t shr(word_t x, std::size_t n) {
    assert(n < 32);
    return x >> n;
}
inline word_t ssig0(word_t x) { return rotr(x, 7) ^ rotr(x, 18) ^ shr(x, 3); }
inline word_t ssig1(word_t x) { return rotr(x, 17) ^ rotr(x, 19) ^ shr(x, 10); }
template <typename RaIter1, typename RaIter2>
void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last) {
    assert(first + 64 == last);
    static_cast<void>(last);  // for avoiding unused-variable warning
    word_t w[64];
    std::fill(w, w + 64, word_t(0));
    for (std::size_t i = 0; i < 16; ++i) {
        w[i] = (static_cast<word_t>(mask_8bit(*(first + i * 4))) << 24) |
               (static_cast<word_t>(mask_8bit(*(first + i * 4 + 1))) << 16) |
               (static_cast<word_t>(mask_8bit(*(first + i * 4 + 2))) << 8) |
               (static_cast<word_t>(mask_8bit(*(first + i * 4 + 3))));
    }
    for (std::size_t i = 16; i < 64; ++i) {
        w[i] = mask_32bit(ssig1(w[i - 2]) + w[i - 7] + ssig0(w[i - 15]) +
                          w[i - 16]);
    }
    word_t a = *message_digest;
    word_t b = *(message_digest + 1);
    word_t c = *(message_digest + 2);
    word_t d = *(message_digest + 3);
    word_t e = *(message_digest + 4);
    word_t f = *(message_digest + 5);
    word_t g = *(message_digest + 6);
    word_t h = *(message_digest + 7);
    for (std::size_t i = 0; i < 64; ++i) {
        word_t temp1 = h + bsig1(e) + ch(e, f, g) + add_constant[i] + w[i];
        word_t temp2 = bsig0(a) + maj(a, b, c);
        h = g;
        g = f;
        f = e;
        e = mask_32bit(d + temp1);
        d = c;
        c = b;
        b = a;
        a = mask_32bit(temp1 + temp2);
    }
    *message_digest += a;
    *(message_digest + 1) += b;
    *(message_digest + 2) += c;
    *(message_digest + 3) += d;
    *(message_digest + 4) += e;
    *(message_digest + 5) += f;
    *(message_digest + 6) += g;
    *(message_digest + 7) += h;
    for (std::size_t i = 0; i < 8; ++i) {
        *(message_digest + i) = mask_32bit(*(message_digest + i));
    }
}
}  // namespace detail
template <typename InIter>
void output_hex(InIter first, InIter last, std::ostream& os) {
    os.setf(std::ios::hex, std::ios::basefield);
    while (first != last) {
        os.width(2);
        os.fill('0');
        os << static_cast<unsigned int>(*first);
        ++first;
    }
    os.setf(std::ios::dec, std::ios::basefield);
}
template <typename InIter>
void bytes_to_hex_string(InIter first, InIter last, std::string& hex_str) {
    std::ostringstream oss;
    output_hex(first, last, oss);
    hex_str.assign(oss.str());
}
template <typename InContainer>
void bytes_to_hex_string(const InContainer& bytes, std::string& hex_str) {
    bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str);
}
template <typename InIter>
std::string bytes_to_hex_string(InIter first, InIter last) {
    std::string hex_str;
    bytes_to_hex_string(first, last, hex_str);
    return hex_str;
}
template <typename InContainer>
std::string bytes_to_hex_string(const InContainer& bytes) {
    std::string hex_str;
    bytes_to_hex_string(bytes, hex_str);
    return hex_str;
}
class hash256_one_by_one {
   public:
    hash256_one_by_one() { init(); }
    void init() {
        buffer_.clear();
        std::fill(data_length_digits_, data_length_digits_ + 4, word_t(0));
        std::copy(detail::initial_message_digest,
                  detail::initial_message_digest + 8, h_);
    }
    template <typename RaIter>
    void process(RaIter first, RaIter last) {
        add_to_data_length(static_cast<word_t>(std::distance(first, last)));
        std::copy(first, last, std::back_inserter(buffer_));
        std::size_t i = 0;
        for (; i + 64 <= buffer_.size(); i += 64) {
            detail::hash256_block(h_, buffer_.begin() + i,
                                  buffer_.begin() + i + 64);
        }
        buffer_.erase(buffer_.begin(), buffer_.begin() + i);
    }
    void finish() {
        byte_t temp[64];
        std::fill(temp, temp + 64, byte_t(0));
        std::size_t remains = buffer_.size();
        std::copy(buffer_.begin(), buffer_.end(), temp);
        temp[remains] = 0x80;
        if (remains > 55) {
            std::fill(temp + remains + 1, temp + 64, byte_t(0));
            detail::hash256_block(h_, temp, temp + 64);
            std::fill(temp, temp + 64 - 4, byte_t(0));
        } else {
            std::fill(temp + remains + 1, temp + 64 - 4, byte_t(0));
        }
        write_data_bit_length(&(temp[56]));
        detail::hash256_block(h_, temp, temp + 64);
    }
    template <typename OutIter>
    void get_hash_bytes(OutIter first, OutIter last) const {
        for (const word_t* iter = h_; iter != h_ + 8; ++iter) {
            for (std::size_t i = 0; i < 4 && first != last; ++i) {
                *(first++) = detail::mask_8bit(
                    static_cast<byte_t>((*iter >> (24 - 8 * i))));
            }
        }
    }
   private:
    void add_to_data_length(word_t n) {
        word_t carry = 0;
        data_length_digits_[0] += n;
        for (std::size_t i = 0; i < 4; ++i) {
            data_length_digits_[i] += carry;
            if (data_length_digits_[i] >= 65536u) {
                carry = data_length_digits_[i] >> 16;
                data_length_digits_[i] &= 65535u;
            } else {
                break;
            }
        }
    }
    void write_data_bit_length(byte_t* begin) {
        word_t data_bit_length_digits[4];
        std::copy(data_length_digits_, data_length_digits_ + 4,
                  data_bit_length_digits);
        // convert byte length to bit length (multiply 8 or shift 3 times left)
        word_t carry = 0;
        for (std::size_t i = 0; i < 4; ++i) {
            word_t before_val = data_bit_length_digits[i];
            data_bit_length_digits[i] <<= 3;
            data_bit_length_digits[i] |= carry;
            data_bit_length_digits[i] &= 65535u;
            carry = (before_val >> (16 - 3)) & 65535u;
        }
        // write data_bit_length
        for (int i = 3; i >= 0; --i) {
            (*begin++) = static_cast<byte_t>(data_bit_length_digits[i] >> 8);
            (*begin++) = static_cast<byte_t>(data_bit_length_digits[i]);
        }
    }
    std::vector<byte_t> buffer_;
    word_t data_length_digits_[4];  // as 64bit integer (16bit x 4 integer)
    word_t h_[8];
};
inline void get_hash_hex_string(const hash256_one_by_one& hasher,
                                std::string& hex_str) {
    byte_t hash[k_digest_size];
    hasher.get_hash_bytes(hash, hash + k_digest_size);
    return bytes_to_hex_string(hash, hash + k_digest_size, hex_str);
}
inline std::string get_hash_hex_string(const hash256_one_by_one& hasher) {
    std::string hex_str;
    get_hash_hex_string(hasher, hex_str);
    return hex_str;
}
namespace impl {
template <typename RaIter, typename OutIter>
void hash256_impl(RaIter first, RaIter last, OutIter first2, OutIter last2, int,
                  std::random_access_iterator_tag) {
    hash256_one_by_one hasher;
    // hasher.init();
    hasher.process(first, last);
    hasher.finish();
    hasher.get_hash_bytes(first2, last2);
}
template <typename InputIter, typename OutIter>
void hash256_impl(InputIter first, InputIter last, OutIter first2,
                  OutIter last2, int buffer_size, std::input_iterator_tag) {
    std::vector<byte_t> buffer(buffer_size);
    hash256_one_by_one hasher;
    // hasher.init();
    while (first != last) {
        int size = buffer_size;
        for (int i = 0; i != buffer_size; ++i, ++first) {
            if (first == last) {
                size = i;
                break;
            }
            buffer[i] = *first;
        }
        hasher.process(buffer.begin(), buffer.begin() + size);
    }
    hasher.finish();
    hasher.get_hash_bytes(first2, last2);
}
}
template <typename InIter, typename OutIter>
void hash256(InIter first, InIter last, OutIter first2, OutIter last2,
             int buffer_size = PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR) {
    picosha2::impl::hash256_impl(
        first, last, first2, last2, buffer_size,
        typename std::iterator_traits<InIter>::iterator_category());
}
template <typename InIter, typename OutContainer>
void hash256(InIter first, InIter last, OutContainer& dst) {
    hash256(first, last, dst.begin(), dst.end());
}
template <typename InContainer, typename OutIter>
void hash256(const InContainer& src, OutIter first, OutIter last) {
    hash256(src.begin(), src.end(), first, last);
}
template <typename InContainer, typename OutContainer>
void hash256(const InContainer& src, OutContainer& dst) {
    hash256(src.begin(), src.end(), dst.begin(), dst.end());
}
template <typename InIter>
void hash256_hex_string(InIter first, InIter last, std::string& hex_str) {
    byte_t hashed[k_digest_size];
    hash256(first, last, hashed, hashed + k_digest_size);
    std::ostringstream oss;
    output_hex(hashed, hashed + k_digest_size, oss);
    hex_str.assign(oss.str());
}
template <typename InIter>
std::string hash256_hex_string(InIter first, InIter last) {
    std::string hex_str;
    hash256_hex_string(first, last, hex_str);
    return hex_str;
}
inline void hash256_hex_string(const std::string& src, std::string& hex_str) {
    hash256_hex_string(src.begin(), src.end(), hex_str);
}
template <typename InContainer>
void hash256_hex_string(const InContainer& src, std::string& hex_str) {
    hash256_hex_string(src.begin(), src.end(), hex_str);
}
template <typename InContainer>
std::string hash256_hex_string(const InContainer& src) {
    return hash256_hex_string(src.begin(), src.end());
}
template<typename OutIter>void hash256(std::ifstream& f, OutIter first, OutIter last){
    hash256(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>(), first,last);
}
}// namespace picosha2
#endif  // PICOSHA2_H
rest-client/civitai.hpp
New file
@@ -0,0 +1,16 @@
#ifndef __SD_GUI_CIVITAI_CLIENT__
#define __SD_GUI_CIVITAI_CLIENT__
#include <string>
#include <nlohmann/json.hpp>
namespace civitai
{
    class Client
    {
    private:
        std::string endpoint;
    }
};
#endif
ui/MainWindow.cpp
@@ -7,20 +7,20 @@
#include "MainWindow.h"
#include "embended_files/cube.png.h"
#include "embended_files/disk.png.h"
#include "embended_files/file_import.png.h"
#include "embended_files/forward.png.h"
#include "embended_files/images.png.h"
#include "embended_files/palette.png.h"
#include "embended_files/pause.png.h"
#include "embended_files/picture.png.h"
#include "embended_files/play.png.h"
#include "embended_files/refresh.png.h"
#include "embended_files/replace.png.h"
#include "embended_files/settings.png.h"
#include "embended_files/text_box_dots.png.h"
#include "embended_files/trash.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/cube.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/disk.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/file_import.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/forward.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/images.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/palette.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/pause.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/picture.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/play.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/refresh.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/replace.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/settings.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/text_box_dots.png.h"
#include "../../sd.cpp.ui2/ui/embended_files/trash.png.h"
///////////////////////////////////////////////////////////////////////////
@@ -42,47 +42,44 @@
    m_settings = new wxButton( m_all_panel, wxID_ANY, wxT("Settings"), wxDefaultPosition, wxDefaultSize, 0 );
    m_settings->SetBitmap( settings_png_to_wx_bitmap() );
    m_settings->SetMinSize( wxSize( 70,-1 ) );
    sizer0021->Add( m_settings, 0, wxALL, 5 );
    m_refresh = new wxButton( m_all_panel, wxID_ANY, wxT("Refresh"), wxDefaultPosition, wxDefaultSize, 0 );
    m_refresh->SetBitmap( refresh_png_to_wx_bitmap() );
    m_refresh->SetMinSize( wxSize( 70,-1 ) );
    sizer0021->Add( m_refresh, 0, wxALL, 5 );
    m_staticText160 = new wxStaticText( m_all_panel, wxID_ANY, wxT("Model"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText160 = new wxStaticText( m_all_panel, wxID_ANY, wxT("Model:"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL );
    m_staticText160->Wrap( 0 );
    m_staticText160->SetMinSize( wxSize( 50,-1 ) );
    sizer0021->Add( m_staticText160, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    wxArrayString m_modelChoices;
    m_model = new wxChoice( m_all_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_modelChoices, 0 );
    m_model->SetSelection( 0 );
    m_model->Enable( false );
    m_model->SetMinSize( wxSize( 200,-1 ) );
    sizer0021->Add( m_model, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_staticText161 = new wxStaticText( m_all_panel, wxID_ANY, wxT("Vae"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText161 = new wxStaticText( m_all_panel, wxID_ANY, wxT("Vae:"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL );
    m_staticText161->Wrap( 0 );
    m_staticText161->SetMinSize( wxSize( 50,-1 ) );
    sizer0021->Add( m_staticText161, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    wxArrayString m_vaeChoices;
    m_vae = new wxChoice( m_all_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_vaeChoices, 0 );
    m_vae->SetSelection( 0 );
    m_vae->Enable( false );
    m_vae->SetMinSize( wxSize( 200,-1 ) );
    sizer0021->Add( m_vae, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_staticText163 = new wxStaticText( m_all_panel, wxID_ANY, wxT("Sampler"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText163->Wrap( 0 );
    m_staticText163->SetToolTip( wxT("sampling method (default: \"euler_a\")") );
    sizer0021->Add( m_staticText163, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    wxArrayString m_samplerChoices;
    m_sampler = new wxChoice( m_all_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_samplerChoices, 0 );
    m_sampler->SetSelection( 0 );
    m_sampler->SetToolTip( wxT("sampling method (default: \"euler_a\")") );
    sizer0021->Add( m_sampler, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    sizer0002->Add( sizer0021, 0, wxALL|wxEXPAND, 5 );
@@ -94,15 +91,19 @@
    m_staticText231->Wrap( 0 );
    sizer0003->Add( m_staticText231, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_cfg = new wxSpinCtrlDouble( m_all_panel, wxID_ANY, wxT("7.0"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL|wxSP_ARROW_KEYS, 0, 15, 0, 0.1 );
    m_cfg = new wxSpinCtrlDouble( m_all_panel, wxID_ANY, wxT("7.0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 15, 0, 0.1 );
    m_cfg->SetDigits( 1 );
    m_cfg->SetMinSize( wxSize( 45,-1 ) );
    sizer0003->Add( m_cfg, 0, wxALL, 5 );
    m_staticText233 = new wxStaticText( m_all_panel, wxID_ANY, wxT("Seed:"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText233->Wrap( 0 );
    sizer0003->Add( m_staticText233, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_seed = new wxSpinCtrl( m_all_panel, wxID_ANY, wxT("44"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 9999999, 44 );
    m_seed = new wxSpinCtrl( m_all_panel, wxID_ANY, wxT("44"), wxDefaultPosition, wxDefaultSize, 0, -1, 99999999999, 44 );
    m_seed->SetMinSize( wxSize( 80,-1 ) );
    sizer0003->Add( m_seed, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_staticText234 = new wxStaticText( m_all_panel, wxID_ANY, wxT("Clip skip:"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -113,6 +114,7 @@
    m_clip_skip = new wxSpinCtrl( m_all_panel, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, -1, 2, 0 );
    m_clip_skip->SetToolTip( wxT("ignore last layers of CLIP network; 1 ignores none, 2 ignores one layer (default: -1)\n<= 0 represents unspecified, will be 1 for SD1.x, 2 for SD2.x") );
    m_clip_skip->SetMinSize( wxSize( 45,-1 ) );
    sizer0003->Add( m_clip_skip, 0, wxALL, 5 );
@@ -124,6 +126,7 @@
    m_steps = new wxSpinCtrl( m_all_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 100, 0 );
    m_steps->SetToolTip( wxT("number of sample steps (default: 20)") );
    m_steps->SetMinSize( wxSize( 45,-1 ) );
    sizer0003->Add( m_steps, 0, wxALL, 5 );
@@ -253,10 +256,24 @@
    bSizer9->Add( m_staticText15, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_batch_count = new wxSpinCtrl( m_all_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 10, 0 );
    m_batch_count = new wxSpinCtrl( m_all_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 1000, 1 );
    m_batch_count->SetToolTip( wxT("number of images to generate.") );
    bSizer9->Add( m_batch_count, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_staticText163 = new wxStaticText( m_all_panel, wxID_ANY, wxT("Sampler"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText163->Wrap( 0 );
    m_staticText163->SetToolTip( wxT("sampling method (default: \"euler_a\")") );
    bSizer9->Add( m_staticText163, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    wxArrayString m_samplerChoices;
    m_sampler = new wxChoice( m_all_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_samplerChoices, 0 );
    m_sampler->SetSelection( 0 );
    m_sampler->SetToolTip( wxT("sampling method (default: \"euler_a\")") );
    m_sampler->SetMinSize( wxSize( 100,-1 ) );
    bSizer9->Add( m_sampler, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_staticline5 = new wxStaticLine( m_all_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
    bSizer9->Add( m_staticline5, 0, wxEXPAND | wxALL, 5 );
@@ -317,14 +334,16 @@
    m_refresh->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onModelsRefresh ), NULL, this );
    m_model->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( UI::onModelSelect ), NULL, this );
    m_vae->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( UI::onVaeSelect ), NULL, this );
    m_sampler->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( UI::onSamplerSelect ), NULL, this );
    m_button7->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onResolutionSwap ), NULL, this );
    m_start_jobs->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onJobsStart ), NULL, this );
    m_pause_jobs->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onJobsPause ), NULL, this );
    m_delete_all_jobs->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onJobsDelete ), NULL, this );
    m_joblist->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( UI::onJoblistItemActivated ), NULL, this );
    m_joblist->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( UI::onContextMenu ), NULL, this );
    m_joblist->Connect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( UI::onJoblistSelectionChanged ), NULL, this );
    m_data_model_list->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( UI::onContextMenu ), NULL, this );
    m_generate->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onGenerate ), NULL, this );
    m_sampler->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( UI::onSamplerSelect ), NULL, this );
    m_save_preset->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onSavePreset ), NULL, this );
    m_load_preset->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onLoadPreset ), NULL, this );
    m_preset_list->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( UI::onSelectPreset ), NULL, this );
@@ -338,14 +357,16 @@
    m_refresh->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onModelsRefresh ), NULL, this );
    m_model->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( UI::onModelSelect ), NULL, this );
    m_vae->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( UI::onVaeSelect ), NULL, this );
    m_sampler->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( UI::onSamplerSelect ), NULL, this );
    m_button7->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onResolutionSwap ), NULL, this );
    m_start_jobs->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onJobsStart ), NULL, this );
    m_pause_jobs->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onJobsPause ), NULL, this );
    m_delete_all_jobs->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onJobsDelete ), NULL, this );
    m_joblist->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( UI::onJoblistItemActivated ), NULL, this );
    m_joblist->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( UI::onContextMenu ), NULL, this );
    m_joblist->Disconnect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( UI::onJoblistSelectionChanged ), NULL, this );
    m_data_model_list->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( UI::onContextMenu ), NULL, this );
    m_generate->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onGenerate ), NULL, this );
    m_sampler->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( UI::onSamplerSelect ), NULL, this );
    m_save_preset->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onSavePreset ), NULL, this );
    m_load_preset->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( UI::onLoadPreset ), NULL, this );
    m_preset_list->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( UI::onSelectPreset ), NULL, this );
@@ -365,98 +386,110 @@
    wxBoxSizer* sizer2011;
    sizer2011 = new wxBoxSizer( wxVERTICAL );
    wxGridSizer* sizer2012;
    sizer2012 = new wxGridSizer( 0, 2, 0, 0 );
    wxBoxSizer* bSizer16;
    bSizer16 = new wxBoxSizer( wxHORIZONTAL );
    m_staticText172410 = new wxStaticText( m_path_panel, wxID_ANY, wxT("Models path"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText172410->Wrap( 0 );
    sizer2012->Add( m_staticText172410, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_staticText172410->SetMinSize( wxSize( 150,-1 ) );
    bSizer16->Add( m_staticText172410, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_model_dir = new wxDirPickerCtrl( m_path_panel, wxID_ANY, wxEmptyString, wxT("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_SMALL|wxDIRP_DEFAULT_STYLE );
    m_model_dir->SetMinSize( wxSize( 200,-1 ) );
    sizer2012->Add( m_model_dir, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
    bSizer16->Add( m_model_dir, 1, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
    sizer2011->Add( sizer2012, 0, wxEXPAND, 5 );
    sizer2011->Add( bSizer16, 0, wxEXPAND, 5 );
    wxGridSizer* sizer2013;
    sizer2013 = new wxGridSizer( 0, 2, 0, 0 );
    m_staticText18013 = new wxStaticText( m_path_panel, wxID_ANY, wxT("Vae path"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText18013->Wrap( 0 );
    sizer2013->Add( m_staticText18013, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_vae_dir = new wxDirPickerCtrl( m_path_panel, wxID_ANY, wxEmptyString, wxT("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_SMALL|wxDIRP_DEFAULT_STYLE );
    m_vae_dir->SetMinSize( wxSize( 200,-1 ) );
    sizer2013->Add( m_vae_dir, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
    sizer2011->Add( sizer2013, 0, wxEXPAND, 5 );
    wxGridSizer* sizer2014;
    sizer2014 = new wxGridSizer( 0, 2, 0, 0 );
    m_staticText1801317202731 = new wxStaticText( m_path_panel, wxID_ANY, wxT("Embedding path"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText1801317202731->Wrap( 0 );
    sizer2014->Add( m_staticText1801317202731, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_embedding_dir = new wxDirPickerCtrl( m_path_panel, wxID_ANY, wxEmptyString, wxT("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_SMALL|wxDIRP_DEFAULT_STYLE );
    m_embedding_dir->SetMinSize( wxSize( 200,-1 ) );
    sizer2014->Add( m_embedding_dir, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
    sizer2011->Add( sizer2014, 0, wxEXPAND, 5 );
    wxGridSizer* sizer2015;
    sizer2015 = new wxGridSizer( 0, 2, 0, 0 );
    wxBoxSizer* bSizer19;
    bSizer19 = new wxBoxSizer( wxHORIZONTAL );
    m_staticText18013172027 = new wxStaticText( m_path_panel, wxID_ANY, wxT("Lora path"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText18013172027->Wrap( 0 );
    sizer2015->Add( m_staticText18013172027, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_staticText18013172027->SetMinSize( wxSize( 150,-1 ) );
    bSizer19->Add( m_staticText18013172027, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_lora_dir = new wxDirPickerCtrl( m_path_panel, wxID_ANY, wxEmptyString, wxT("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_SMALL|wxDIRP_DEFAULT_STYLE );
    m_lora_dir->SetMinSize( wxSize( 200,-1 ) );
    sizer2015->Add( m_lora_dir, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
    bSizer19->Add( m_lora_dir, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
    sizer2011->Add( sizer2015, 0, wxEXPAND, 5 );
    sizer2011->Add( bSizer19, 0, wxEXPAND, 5 );
    wxGridSizer* gSizer8;
    gSizer8 = new wxGridSizer( 0, 2, 0, 0 );
    wxBoxSizer* bSizer17;
    bSizer17 = new wxBoxSizer( wxHORIZONTAL );
    m_staticText18013 = new wxStaticText( m_path_panel, wxID_ANY, wxT("Vae path"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText18013->Wrap( 0 );
    m_staticText18013->SetMinSize( wxSize( 150,-1 ) );
    bSizer17->Add( m_staticText18013, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_vae_dir = new wxDirPickerCtrl( m_path_panel, wxID_ANY, wxEmptyString, wxT("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_SMALL|wxDIRP_DEFAULT_STYLE );
    m_vae_dir->SetMinSize( wxSize( 200,-1 ) );
    bSizer17->Add( m_vae_dir, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
    sizer2011->Add( bSizer17, 0, wxEXPAND, 5 );
    wxBoxSizer* bSizer18;
    bSizer18 = new wxBoxSizer( wxHORIZONTAL );
    m_staticText1801317202731 = new wxStaticText( m_path_panel, wxID_ANY, wxT("Embedding path"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText1801317202731->Wrap( 0 );
    m_staticText1801317202731->SetMinSize( wxSize( 150,-1 ) );
    bSizer18->Add( m_staticText1801317202731, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_embedding_dir = new wxDirPickerCtrl( m_path_panel, wxID_ANY, wxEmptyString, wxT("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_SMALL|wxDIRP_DEFAULT_STYLE );
    m_embedding_dir->SetMinSize( wxSize( 200,-1 ) );
    bSizer18->Add( m_embedding_dir, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
    sizer2011->Add( bSizer18, 0, wxEXPAND, 5 );
    wxBoxSizer* bSizer20;
    bSizer20 = new wxBoxSizer( wxHORIZONTAL );
    m_staticText19 = new wxStaticText( m_path_panel, wxID_ANY, wxT("Presets path"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText19->Wrap( -1 );
    gSizer8->Add( m_staticText19, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_staticText19->SetMinSize( wxSize( 150,-1 ) );
    bSizer20->Add( m_staticText19, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_presets_dir = new wxDirPickerCtrl( m_path_panel, wxID_ANY, wxEmptyString, wxT("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DEFAULT_STYLE|wxDIRP_SMALL );
    m_presets_dir->SetMinSize( wxSize( 200,-1 ) );
    gSizer8->Add( m_presets_dir, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
    bSizer20->Add( m_presets_dir, 1, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
    sizer2011->Add( gSizer8, 0, wxEXPAND, 5 );
    sizer2011->Add( bSizer20, 0, wxEXPAND, 5 );
    m_staticLine223 = new wxStaticLine( m_path_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
    sizer2011->Add( m_staticLine223, 0, wxALL|wxEXPAND, 5 );
    wxGridSizer* sizer2016;
    sizer2016 = new wxGridSizer( 0, 2, 0, 0 );
    wxBoxSizer* bSizer21;
    bSizer21 = new wxBoxSizer( wxHORIZONTAL );
    m_staticText180131720 = new wxStaticText( m_path_panel, wxID_ANY, wxT("Images output"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText180131720->Wrap( 0 );
    sizer2016->Add( m_staticText180131720, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_staticText180131720->SetMinSize( wxSize( 150,-1 ) );
    bSizer21->Add( m_staticText180131720, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    m_images_output = new wxDirPickerCtrl( m_path_panel, wxID_ANY, wxEmptyString, wxT("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_SMALL|wxDIRP_DEFAULT_STYLE );
    m_images_output->SetMinSize( wxSize( 200,-1 ) );
    sizer2016->Add( m_images_output, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
    bSizer21->Add( m_images_output, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
    sizer2011->Add( sizer2016, 0, wxEXPAND, 5 );
    sizer2011->Add( bSizer21, 0, wxEXPAND, 5 );
    m_path_panel->SetSizer( sizer2011 );
@@ -472,6 +505,8 @@
    m_keep_model_in_memory = new wxCheckBox( m_settings, wxID_ANY, wxT("Keep model in memory"), wxDefaultPosition, wxDefaultSize, 0 );
    m_keep_model_in_memory->SetValue(true);
    m_keep_model_in_memory->SetMinSize( wxSize( 230,-1 ) );
    sizer2018->Add( m_keep_model_in_memory, 0, wxALIGN_LEFT|wxALL, 5 );
@@ -482,6 +517,8 @@
    m_save_all_image = new wxCheckBox( m_settings, wxID_ANY, wxT("Save all images (intermediat images)"), wxDefaultPosition, wxDefaultSize, 0 );
    m_save_all_image->SetValue(true);
    m_save_all_image->SetMinSize( wxSize( 230,-1 ) );
    sizer2019->Add( m_save_all_image, 0, wxALIGN_LEFT|wxALL, 5 );
@@ -490,15 +527,17 @@
    wxBoxSizer* bSizer10;
    bSizer10 = new wxBoxSizer( wxHORIZONTAL );
    m_staticText16 = new wxStaticText( m_settings, wxID_ANY, wxT("Output images type"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText16 = new wxStaticText( m_settings, wxID_ANY, wxT("Output images format"), wxDefaultPosition, wxDefaultSize, 0 );
    m_staticText16->Wrap( -1 );
    m_staticText16->SetMinSize( wxSize( 230,-1 ) );
    bSizer10->Add( m_staticText16, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    wxString m_choice4Choices[] = { wxT(".png"), wxT(".jpg") };
    int m_choice4NChoices = sizeof( m_choice4Choices ) / sizeof( wxString );
    m_choice4 = new wxChoice( m_settings, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choice4NChoices, m_choice4Choices, 0 );
    m_choice4->SetSelection( 0 );
    bSizer10->Add( m_choice4, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
    bSizer10->Add( m_choice4, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
    sizer2017->Add( bSizer10, 0, wxEXPAND, 5 );
ui/MainWindow.h
@@ -51,8 +51,6 @@
        wxChoice* m_model;
        wxStaticText* m_staticText161;
        wxChoice* m_vae;
        wxStaticText* m_staticText163;
        wxChoice* m_sampler;
        wxStaticText* m_staticText231;
        wxSpinCtrlDouble* m_cfg;
        wxStaticText* m_staticText233;
@@ -83,6 +81,8 @@
        wxButton* m_generate;
        wxStaticText* m_staticText15;
        wxSpinCtrl* m_batch_count;
        wxStaticText* m_staticText163;
        wxChoice* m_sampler;
        wxStaticLine* m_staticline5;
        wxStaticText* m_staticText17;
        wxButton* m_save_preset;
@@ -97,14 +97,15 @@
        virtual void onModelsRefresh( wxCommandEvent& event ) { event.Skip(); }
        virtual void onModelSelect( wxCommandEvent& event ) { event.Skip(); }
        virtual void onVaeSelect( wxCommandEvent& event ) { event.Skip(); }
        virtual void onSamplerSelect( wxCommandEvent& event ) { event.Skip(); }
        virtual void onResolutionSwap( wxCommandEvent& event ) { event.Skip(); }
        virtual void onJobsStart( wxCommandEvent& event ) { event.Skip(); }
        virtual void onJobsPause( wxCommandEvent& event ) { event.Skip(); }
        virtual void onJobsDelete( wxCommandEvent& event ) { event.Skip(); }
        virtual void onJoblistItemActivated( wxDataViewEvent& event ) { event.Skip(); }
        virtual void onContextMenu( wxDataViewEvent& event ) { event.Skip(); }
        virtual void onJoblistSelectionChanged( wxDataViewEvent& event ) { event.Skip(); }
        virtual void onGenerate( wxCommandEvent& event ) { event.Skip(); }
        virtual void onSamplerSelect( wxCommandEvent& event ) { event.Skip(); }
        virtual void onSavePreset( wxCommandEvent& event ) { event.Skip(); }
        virtual void onLoadPreset( wxCommandEvent& event ) { event.Skip(); }
        virtual void onSelectPreset( wxCommandEvent& event ) { event.Skip(); }
@@ -131,12 +132,12 @@
        wxPanel* m_path_panel;
        wxStaticText* m_staticText172410;
        wxDirPickerCtrl* m_model_dir;
        wxStaticText* m_staticText18013172027;
        wxDirPickerCtrl* m_lora_dir;
        wxStaticText* m_staticText18013;
        wxDirPickerCtrl* m_vae_dir;
        wxStaticText* m_staticText1801317202731;
        wxDirPickerCtrl* m_embedding_dir;
        wxStaticText* m_staticText18013172027;
        wxDirPickerCtrl* m_lora_dir;
        wxStaticText* m_staticText19;
        wxDirPickerCtrl* m_presets_dir;
        wxStaticLine* m_staticLine223;
ui/MainWindowImageViewer.h
@@ -34,6 +34,14 @@
};
#endif // __MainWindowImageViewer__
ui/MainWindowSettings.h
@@ -60,6 +60,14 @@
};
#endif // __MainWindowSettings__
ui/MainWindowUI.cpp
@@ -6,20 +6,23 @@
    this->ini_path = wxStandardPaths::Get().GetUserConfigDir() + wxFileName::GetPathSeparator() + "sd.ui.config.ini";
    this->sd_params = new sd_gui_utils::SDParams;
    this->notification = new wxNotificationMessage();
    this->JobTableItems = new std::map<int, QM::QueueItem>();
    // this->JobTableItems = new std::map<int, QM::QueueItem>();
    this->notification->SetParent(this);
    // prepare data list views
    this->m_data_model_list->AppendTextColumn("Name", wxDATAVIEW_CELL_INERT, 200);
    this->m_data_model_list->AppendTextColumn("Size");
    this->m_data_model_list->AppendTextColumn("Hash");
    this->m_joblist->AppendTextColumn("Id");
    this->m_joblist->AppendTextColumn("Created");
    this->m_joblist->AppendTextColumn("Created at");
    this->m_joblist->AppendTextColumn("Model");
    this->m_joblist->AppendTextColumn("Sampler");
    this->m_joblist->AppendTextColumn("Seed");
    this->m_joblist->AppendTextColumn("Status");
    this->m_joblist->AppendProgressColumn("Progress"); // progressbar
    this->m_joblist->AppendTextColumn("Speed");        // speed
    this->m_joblist->AppendTextColumn("Status");       // status
    this->SetTitle(this->GetTitle() + SD_GUI_VERSION);
@@ -30,7 +33,7 @@
    this->qmanager = new QM::QueueManager(this->GetEventHandler(), this->cfg->jobs);
    // set SD logger
    sd_set_log_callback(MainWindowUI::HandleSDLog, (void *)this);
    sd_set_log_callback(MainWindowUI::HandleSDLog, (void *)this->GetEventHandler());
    // load
    this->LoadPresets();
@@ -102,11 +105,6 @@
    }
}
void MainWindowUI::onSamplerSelect(wxCommandEvent &event)
{
    this->sd_params->sample_method = (sample_method_t)this->m_sampler->GetSelection();
}
void MainWindowUI::onResolutionSwap(wxCommandEvent &event)
{
    auto oldW = this->m_width->GetValue();
@@ -136,6 +134,16 @@
    // TODO: Implement onJoblistItemActivated
}
void MainWindowUI::onContextMenu(wxDataViewEvent &event)
{
    wxMenu menu;
    menu.Append(0, "Calculate Hash");
    menu.Append(1, "Download info from CivitAi.com");
    PopupMenu(&menu);
}
void MainWindowUI::onJoblistSelectionChanged(wxDataViewEvent &event)
{
    // TODO: Implement onJoblistSelectionChanged
@@ -162,9 +170,22 @@
    this->sd_params->width = this->m_width->GetValue();
    this->sd_params->height = this->m_height->GetValue();
    QM::QueueItem item;
    item.params = *this->sd_params;
    item.model = this->m_model->GetStringSelection().ToStdString();
    if (item.params.seed == -1)
    {
        item.params.seed = sd_gui_utils::generateRandomInt(100000000, 999999999);
    }
    // add the queue item
    auto id = this->qmanager->AddItem(this->sd_params);
    auto id = this->qmanager->AddItem(item);
}
void MainWindowUI::onSamplerSelect(wxCommandEvent &event)
{
    this->sd_params->sample_method = (sample_method_t)this->m_sampler->GetSelection();
}
void MainWindowUI::onSavePreset(wxCommandEvent &event)
@@ -258,30 +279,596 @@
        this->LoadPresets();
    }
}
/*
    this->m_joblist->AppendTextColumn("Id");
    this->m_joblist->AppendTextColumn("Created");
    this->m_joblist->AppendTextColumn("Model");
    this->m_joblist->AppendTextColumn("Sampler");
    this->m_joblist->AppendTextColumn("Seed");
    this->m_joblist->AppendTextColumn("Status");
void MainWindowUI::HandleSDLog(sd_log_level_t level, const char *text, void *data)
{
    if (level == sd_log_level_t::SD_LOG_INFO || level == sd_log_level_t::SD_LOG_ERROR)
    {
        auto *eventHandler = (wxEvtHandler *)data;
        wxThreadEvent *e = new wxThreadEvent();
        e->SetString(wxString::Format("SD_MESSAGE:%s", text));
        e->SetPayload(level);
        wxQueueEvent(eventHandler, e);
    }
}
void MainWindowUI::OnQueueItemManagerItemStatusChanged(QM::QueueItem item)
{
    auto store = this->m_joblist->GetStore();
    int lastCol = this->m_joblist->GetColumnCount() - 1;
    for (unsigned int i = 0; i < store->GetItemCount(); i++)
    {
        auto _item = store->GetItem(i);
        auto _item_data = store->GetItemData(_item);
        auto *_qitem = reinterpret_cast<QM::QueueItem *>(_item_data);
        if (_qitem->id == item.id)
        {
            store->SetValueByRow(wxVariant(QM::QueueStatus_str[item.status]), i, lastCol);
            this->m_joblist->Refresh();
            break;
        }
    }
}
void MainWindowUI::loadModelList()
{
    this->m_sampler->Clear();
    for (auto sampler : sd_gui_utils::sample_method_str)
    {
        int _u = this->m_sampler->Append(sampler);
        if (sampler == sd_gui_utils::sample_method_str[this->sd_params->sample_method])
        {
            this->m_sampler->Select(_u);
        }
    }
    this->LoadFileList(sd_gui_utils::DirTypes::CHECKPOINT);
    for (auto model : this->ModelFiles)
    {
        // auto size = sd_gui_utils::HumanReadable{std::filesystem::file_size(model.second)};
        uintmax_t size = std::filesystem::file_size(model.second);
        auto humanSize = sd_gui_utils::humanReadableFileSize(size);
        auto hs = wxString::Format("%.1f %s", humanSize.first, humanSize.second);
        wxVector<wxVariant> data;
        data.push_back(wxVariant(model.first));
        data.push_back(hs);
        data.push_back("--");
        this->m_data_model_list->AppendItem(data);
    }
    this->m_data_model_list->Refresh();
}
void MainWindowUI::StartGeneration(QM::QueueItem myJob)
{
    // here starts the trhead
    // this->threads.push_back(std::thread(std::bind(&MainWindowUI::Generate, this, this->GetEventHandler(), myJob)));
    // this->threads.emplace_back(std::thread(std::bind(&MainWindowUI::Generate, this, this->GetEventHandler(), myJob)));
    // this->threads.emplace_back(std::thread(&MainWindowUI::Generate, this, this->GetEventHandler(), myJob));
    std::thread(&MainWindowUI::Generate, this, this->GetEventHandler(), myJob);
}
void MainWindowUI::HandleSDProgress(int step, int steps, float time, void *data)
{
    sd_gui_utils::VoidHolder *objs = (sd_gui_utils::VoidHolder *)data;
    wxEvtHandler *eventHandler = (wxEvtHandler *)objs->p1;
    QM::QueueItem *myItem = (QM::QueueItem *)objs->p2;
    myItem->step = step;
    myItem->steps = steps;
    myItem->time = time;
    /*
        format it/s
        time > 1.0f ? "\r%s %i/%i - %.2fs/it" : "\r%s %i/%i - %.2fit/s",
               progress.c_str(), step, steps,
               time > 1.0f || time == 0 ? time : (1.0f / time)
*/
    wxThreadEvent *e = new wxThreadEvent();
    e->SetString(wxString::Format("GENERATION_PROGRESS:%d/%d", step, steps));
    e->SetPayload(myItem);
    wxQueueEvent(eventHandler, e);
}
void MainWindowUI::Generate(wxEvtHandler *eventHandler, QM::QueueItem myItem)
{
    sd_gui_utils::VoidHolder *vparams = new sd_gui_utils::VoidHolder;
    vparams->p1 = (void *)this->GetEventHandler();
    vparams->p2 = (void *)&myItem;
    sd_set_progress_callback(MainWindowUI::HandleSDProgress, (void *)vparams);
    if (!this->modelLoaded)
    {
        this->sd_ctx = this->LoadModelv2(eventHandler, myItem);
        this->currentModel = myItem.params.model_path;
    }
    else
    {
        if (myItem.params.model_path != this->currentModel)
        {
            free_sd_ctx(this->sd_ctx);
            this->sd_ctx = this->LoadModelv2(eventHandler, myItem);
        }
    }
    if (!this->modelLoaded || this->sd_ctx == nullptr)
    {
        wxThreadEvent *f = new wxThreadEvent();
        f->SetString("GENERATION_ERROR:Model load failed...");
        f->SetPayload(myItem);
        wxQueueEvent(eventHandler, f);
        return;
    }
    auto start = std::chrono::system_clock::now();
    wxThreadEvent *e = new wxThreadEvent();
    e->SetString(wxString::Format("GENERATION_START:%s", this->sd_params->model_path));
    e->SetPayload(myItem);
    wxQueueEvent(eventHandler, e);
    sd_image_t *control_image = NULL;
    sd_image_t *results;
    // std::lock_guard<std::mutex> guard(this->sdMutex);
    results = txt2img(this->sd_ctx,
                      myItem.params.prompt.c_str(),
                      myItem.params.negative_prompt.c_str(),
                      myItem.params.clip_skip,
                      myItem.params.cfg_scale,
                      myItem.params.width,
                      myItem.params.height,
                      myItem.params.sample_method,
                      myItem.params.sample_steps,
                      myItem.params.seed,
                      myItem.params.batch_count,
                      control_image,
                      myItem.params.control_strength);
    if (results == NULL)
    {
        wxThreadEvent *f = new wxThreadEvent();
        f->SetString("GENERATION_ERROR:Something wrong happened at image generation...");
        f->SetPayload(myItem);
        wxQueueEvent(eventHandler, f);
        return;
    }
    if (!std::filesystem::exists(this->cfg->output))
    {
        std::filesystem::create_directories(this->cfg->output);
    }
    /* save image(s) */
    const auto p1 = std::chrono::system_clock::now();
    auto ctime = std::chrono::duration_cast<std::chrono::seconds>(p1.time_since_epoch()).count();
    for (int i = 0; i < this->sd_params->batch_count; i++)
    {
        if (results[i].data == NULL)
        {
            continue;
        }
        // handle data??
        wxImage *img = new wxImage(results[i].width, results[i].height, results[i].data);
        std::string filename = this->cfg->output;
        std::string extension = ".png";
        if (this->sd_params->batch_count > 1)
        {
            filename = filename + wxFileName::GetPathSeparator() + std::to_string(ctime) + "_" + std::to_string(i) + extension;
        }
        else
        {
            filename = filename + wxFileName::GetPathSeparator() + std::to_string(ctime) + extension;
        }
        if (!img->SaveFile(filename))
        {
            wxThreadEvent *g = new wxThreadEvent();
            g->SetString(wxString::Format("GENERATION_ERROR:Failed to save image into %s", filename));
            g->SetPayload(myItem);
            wxQueueEvent(eventHandler, g);
        }
        else
        {
            myItem.images.emplace_back(filename);
        }
        // handle data??
    }
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    // send to notify the user...
    wxThreadEvent *h = new wxThreadEvent();
    auto msg = fmt::format("MESSAGE:Image generation done in {}s. Saved into {}", elapsed_seconds.count(), this->cfg->output);
    h->SetString(wxString(msg.c_str()));
    // h->SetPayload(myItem);
    wxQueueEvent(eventHandler, h);
    wxThreadEvent *i = new wxThreadEvent();
    i->SetString(wxString::Format("GENERATION_DONE:ok"));
    i->SetPayload(results);
    wxQueueEvent(eventHandler, i);
    // send to the queue manager
    wxThreadEvent *j = new wxThreadEvent();
    j->SetString(wxString::Format("QUEUE:%d", QM::QueueEvents::ITEM_FINISHED));
    j->SetPayload(myItem);
    wxQueueEvent(eventHandler, j);
}
void MainWindowUI::initConfig()
{
    wxString datapath = wxStandardPaths::Get().GetUserDataDir() + wxFileName::GetPathSeparator() + "sd_ui_data" + wxFileName::GetPathSeparator();
    wxString imagespath = wxStandardPaths::Get().GetDocumentsDir() + wxFileName::GetPathSeparator() + "sd_ui_output" + wxFileName::GetPathSeparator();
    wxString model_path = datapath;
    model_path.append("checkpoints");
    wxString vae_path = datapath;
    vae_path.append("vae");
    wxString lora_path = datapath;
    lora_path.append("lora");
    wxString embedding_path = datapath;
    embedding_path.append("embedding");
    wxString presets_path = datapath;
    presets_path.append("presets");
    wxString jobs_path = datapath;
    jobs_path.append("queue_jobs");
    this->cfg->lora = this->fileConfig->Read("/paths/lora", lora_path).ToStdString();
    this->cfg->model = this->fileConfig->Read("/paths/model", model_path).ToStdString();
    this->cfg->vae = this->fileConfig->Read("/paths/vae", vae_path).ToStdString();
    this->cfg->embedding = this->fileConfig->Read("/paths/embedding", embedding_path).ToStdString();
    this->cfg->presets = this->fileConfig->Read("/paths/presets", presets_path).ToStdString();
    this->cfg->jobs = this->fileConfig->Read("/paths/presets", jobs_path).ToStdString();
    this->cfg->output = this->fileConfig->Read("/paths/output", imagespath).ToStdString();
    this->cfg->keep_model_in_memory = this->fileConfig->Read("/keep_model_in_memory", this->cfg->keep_model_in_memory);
    this->cfg->save_all_image = this->fileConfig->Read("/save_all_image", this->cfg->save_all_image);
    // populate data from sd_params as default...
    if (!this->modelLoaded)
    {
        this->m_cfg->SetValue(static_cast<double>(this->sd_params->cfg_scale));
        this->m_seed->SetValue(static_cast<int>(this->sd_params->seed));
        this->m_clip_skip->SetValue(this->sd_params->clip_skip);
        this->m_steps->SetValue(this->sd_params->sample_steps);
        this->m_width->SetValue(this->sd_params->width);
        this->m_height->SetValue(this->sd_params->height);
        this->m_batch_count->SetValue(this->sd_params->batch_count);
    }
}
void MainWindowUI::OnCloseSettings(wxCloseEvent &event)
{
    this->initConfig();
    this->settingsWindow->Destroy();
}
void MainWindowUI::OnThreadMessage(wxThreadEvent &e)
{
    if (e.GetSkipped() == false)
    {
        e.Skip();
    }
    auto msg = e.GetString().ToStdString();
    std::string token = msg.substr(0, msg.find(":"));
    std::string content = msg.substr(msg.find(":") + 1);
    // this->logs->AppendText(fmt::format("Got thread message: {}\n", e.GetString().ToStdString()));
    if (token == "QUEUE")
    {
        // only numbers here...
        QM::QueueEvents event = (QM::QueueEvents)std::stoi(content);
        // only handle the QUEUE messages, what this class generate
        // alway QM::EueueItem the payload, with the new data
        QM::QueueItem payload;
        payload = e.GetPayload<QM::QueueItem>();
        switch (event)
        {
            // new item added
        case QM::QueueEvents::ITEM_ADDED:
            this->OnQueueItemManagerItemAdded(payload);
            break;
            // item status changed
        case QM::QueueEvents::ITEM_STATUS_CHANGED:
            this->OnQueueItemManagerItemStatusChanged(payload);
            break;
            // item updated... ? ? ?
        case QM::QueueEvents::ITEM_UPDATED:
            this->OnQueueItemManagerItemUpdated(payload);
            break;
        case QM::QueueEvents::ITEM_START:
            this->StartGeneration(payload);
            break;
        default:
            break;
        }
    }
    if (token == "MODEL_LOAD_DONE")
    {
        // this->m_generate->Enable();
        // this->m_model->Enable();
        // this->m_vae->Enable();
        // this->m_refresh->Enable();
        // this->logs->AppendText(fmt::format("Model loaded: {}\n", content));
        this->modelLoaded = true;
        // std::lock_guard<std::mutex> guard(this->sdMutex);
        // this->sd_ctx = e.GetPayload<sd_ctx_t *>();
        if (!this->IsShownOnScreen())
        {
            this->notification->SetFlags(wxICON_INFORMATION);
            this->notification->SetTitle("SD Gui");
            this->notification->SetMessage(content);
            this->notification->Show(5000);
        }
    }
    if (token == "MODEL_LOAD_START")
    {
        // this->m_generate->Disable();
        // this->m_model->Disable();
        // this->m_vae->Disable();
        // this->m_refresh->Disable();
        this->logs->AppendText(fmt::format("Model load start: {}\n", content));
    }
    if (token == "MODEL_LOAD_ERROR")
    {
        // this->m_generate->Disable();
        // this->m_model->Enable();
        // this->m_vae->Disable();
        // this->m_refresh->Enable();
        this->logs->AppendText(fmt::format("Model load error: {}\n", content));
        this->modelLoaded = false;
        if (!this->IsShownOnScreen())
        {
            this->notification->SetFlags(wxICON_ERROR);
            this->notification->SetTitle("SD Gui - error");
            this->notification->SetMessage(content);
            this->notification->Show(5000);
        }
    }
    if (token == "GENERATION_START")
    {
        auto myjob = e.GetPayload<QM::QueueItem>();
        // this->m_generate->Disable();
        // this->m_model->Disable();
        // this->m_vae->Disable();
        // this->m_refresh->Disable();
        this->logs->AppendText(fmt::format("Diffusion started. Seed: {} Batch: {} {}x{}px Cfg: {} Steps: {}\n",
                                           myjob.params.seed,
                                           myjob.params.batch_count,
                                           myjob.params.width,
                                           myjob.params.height,
                                           myjob.params.cfg_scale,
                                           myjob.params.sample_steps));
    }
    // in the original SD.cpp the progress callback is not implemented... :(
    if (token == "GENERATION_PROGRESS")
    {
        QM::QueueItem *myjob = e.GetPayload<QM::QueueItem *>();
        // update column
        auto store = this->m_joblist->GetStore();
        // -1 the last (status)
        // -2 ...      (speed)
        // -3 ...      (progressbar)
        // it/s format
        /*
        time > 1.0f ? "\r%s %i/%i - %.2fs/it" : "\r%s %i/%i - %.2fit/s",
               progress.c_str(), step, steps,
               time > 1.0f || time == 0 ? time : (1.0f / time)
        */
        wxString speed = wxString::Format(myjob->time > 1.0f ? "%.2fs/it" : "%.2fit/s", myjob->time > 1.0f || myjob->time == 0 ? myjob->time : (1.0f / myjob->time));
        int progressCol = this->m_joblist->GetColumnCount() - 3;
        int speedCol = this->m_joblist->GetColumnCount() - 2;
        float current_progress = 100.f * (static_cast<float>(myjob->step) / static_cast<float>(myjob->steps));
        if (current_progress < 2.f)
        {
            return;
        }
        for (unsigned int i = 0; i < store->GetItemCount(); i++)
        {
            auto _item = store->GetItem(i);
            auto _item_data = store->GetItemData(_item);
            auto *_qitem = reinterpret_cast<QM::QueueItem *>(_item_data);
            if (_qitem->id == myjob->id)
            {
                store->SetValueByRow(static_cast<int>(current_progress), i, progressCol);
                store->SetValueByRow(speed, i, speedCol);
                this->m_joblist->Refresh();
                break;
            }
        }
        return;
        for (auto it = this->JobTableItems.begin(); it != this->JobTableItems.end(); ++it)
        {
            if (it->second->id == myjob->id)
            {
                // store->SetValueByRow(wxVariant(QM::QueueStatus_str[item.status]), it->first, progressCol);
                store->SetValueByRow(static_cast<int>(current_progress), it->first, progressCol);
                store->SetValueByRow(speed, it->first, speedCol);
                this->m_joblist->Refresh();
                break;
            }
        }
        // update column
    }
    if (token == "GENERATION_DONE")
    {
        // this->m_generate->Enable();
        // this->m_model->Enable();
        // this->m_vae->Enable();
        // this->m_refresh->Enable();
        // sd_image_t *results = e.GetPayload<sd_image_t *>();
        // show images in new window...
        /* for (int i = 0; i < this->sd_params->batch_count; i++)
         {
             MainWindowImageViewer *imgWindow = new MainWindowImageViewer(this);
             // wxBitmap *img = new wxBitmap(results[i].data, (int)results[i].width, (int)results[i].height, (int)results[i].channel);
             wxImage img(results[i].width, results[i].height, results[i].data);
             wxBitmapBundle wxBmapB(img);
             imgWindow->m_bitmap->SetBitmap(wxBmapB);
             imgWindow->m_bitmap->SetSize(results[i].width, results[i].height);
             imgWindow->SetSize(results[i].width + 200, results[i].height);
             std::string details = fmt::format("Prompt:\n\n{}\n\nNegative prompt: \n\n{}\n\nSeed: {} \nCfg scale: {}\nClip skip: {}\nSampler: {}\nSteps: {}\nWidth: {} Height: {}",
                                               this->sd_params->prompt, this->sd_params->negative_prompt,
                                               this->sd_params->seed + i, this->sd_params->cfg_scale,
                                               this->sd_params->clip_skip, sd_gui_utils::sample_method_str[this->sd_params->sample_method], this->sd_params->sample_steps,
                                               results[i].width, results[i].height);
             imgWindow->m_textCtrl4->AppendText(wxString(details));
             imgWindow->Show();
             // imgWindow->m_bitmap->SetBitmap(img);
             /// imgWindow->m_bitmap->Set
         }*/
    }
    if (token == "GENERATION_ERROR")
    {
        this->logs->AppendText(fmt::format("Generation error: {}\n", content));
        if (!this->IsShownOnScreen())
        {
            this->notification->SetFlags(wxICON_ERROR);
            this->notification->SetTitle("SD Gui - error");
            this->notification->SetMessage(content);
            this->notification->Show(5000);
        }
    }
    if (token == "SD_MESSAGE")
    {
        if (content.length() < 1)
        {
            return;
        }
        this->logs->AppendText(fmt::format("{}", content));
    }
    if (token == "MESSAGE")
    {
        this->logs->AppendText(fmt::format("{}\n", content));
        if (!this->IsShownOnScreen())
        {
            this->notification->SetFlags(wxICON_INFORMATION);
            this->notification->SetTitle("SD Gui");
            this->notification->SetMessage(content);
            this->notification->Show(5000);
        }
    }
}
sd_ctx_t *MainWindowUI::LoadModelv2(wxEvtHandler *eventHandler, QM::QueueItem myItem)
{
    wxThreadEvent *e = new wxThreadEvent();
    e->SetString(wxString::Format("MODEL_LOAD_START:%s", myItem.params.model_path));
    e->SetPayload(myItem);
    wxQueueEvent(eventHandler, e);
    // std::lock_guard<std::mutex> guard(this->sdMutex);
    sd_ctx_t *sd_ctx_ = new_sd_ctx(
        myItem.params.model_path.c_str(),
        myItem.params.vae_path.c_str(),
        myItem.params.taesd_path.c_str(),
        myItem.params.controlnet_path.c_str(),
        myItem.params.lora_model_dir.c_str(),
        myItem.params.embeddings_path.c_str(),
        true, false, false,
        myItem.params.n_threads,
        myItem.params.wtype,
        myItem.params.rng_type,
        myItem.params.schedule, false);
    if (sd_ctx_ == NULL)
    {
        wxThreadEvent *c = new wxThreadEvent();
        c->SetString(wxString::Format("MODEL_LOAD_ERROR:%s", myItem.params.model_path));
        c->SetPayload(myItem);
        wxQueueEvent(eventHandler, c);
        this->modelLoaded = false;
        return nullptr;
    }
    else
    {
        wxThreadEvent *c = new wxThreadEvent();
        c->SetString(wxString::Format("MODEL_LOAD_DONE:%s", myItem.params.model_path));
        wxQueueEvent(eventHandler, c);
        this->modelLoaded = true;
        this->currentModel = myItem.params.model_path;
    }
    return sd_ctx_;
}
void MainWindowUI::LoadPresets()
{
    this->LoadFileList(sd_gui_utils::DirTypes::PRESETS);
}
void MainWindowUI::OnQueueItemManagerItemUpdated(QM::QueueItem item)
{
}
void MainWindowUI::loadVaeList()
{
    if (!std::filesystem::exists(this->cfg->vae))
    {
        std::filesystem::create_directories(this->cfg->vae);
    }
    this->LoadFileList(sd_gui_utils::DirTypes::VAE);
}
MainWindowUI::~MainWindowUI()
{
    // this->Hide();
    for (int i = 0; i < this->threads.size(); i++)
    {
        if (this->threads.at(i).joinable())
        {
            this->threads.at(i).join();
        }
    }
}
void MainWindowUI::OnQueueItemManagerItemAdded(QM::QueueItem item)
{
    wxVector<wxVariant> data;
    auto created_at = sd_gui_utils::formatUnixTimestampToDate(item.created_at);
    data.push_back(wxVariant(std::to_string(item.id)));
    data.push_back(wxVariant(std::to_string(item.created_at)));
    data.push_back(wxVariant(item.params.model_path));
    data.push_back(wxVariant(created_at));
    data.push_back(wxVariant(item.model));
    data.push_back(wxVariant(sd_gui_utils::sample_method_str[(int)item.params.sample_method]));
    data.push_back(wxVariant(std::to_string(item.params.seed)));
    data.push_back(wxVariant(QM::QueueStatus_str[item.status]));
    this->m_joblist->AppendItem(data);
    data.push_back(item.status == QM::QueueStatus::DONE ? 100 : 1); // progressbar
    data.push_back(wxString("-.--it/s"));                           // speed
    data.push_back(wxVariant(QM::QueueStatus_str[item.status]));    // status
    auto store = this->m_joblist->GetStore();
    (*this->JobTableItems)[store->GetCount() - 1] = item;
    QM::QueueItem *nItem = new QM::QueueItem(item);
    this->JobTableItems[item.id] = nItem;
    //  store->AppendItem(data, wxUIntPtr(this->JobTableItems[item.id]));
    store->PrependItem(data, wxUIntPtr(this->JobTableItems[item.id]));
}
void MainWindowUI::LoadFileList(sd_gui_utils::DirTypes type)
@@ -334,7 +921,7 @@
        if (type == sd_gui_utils::DirTypes::CHECKPOINT || type == sd_gui_utils::DirTypes::VAE)
        {
            if (ext != ".safetensors" && ext != ".cptk")
            if (ext != ".safetensors" && ext != ".ckpt")
            {
                continue;
            }
@@ -403,528 +990,4 @@
            this->m_preset_list->Enable();
        }
    }
}
void MainWindowUI::LoadPresets()
{
    this->LoadFileList(sd_gui_utils::DirTypes::PRESETS);
}
void MainWindowUI::OnThreadMessage(wxThreadEvent &e)
{
    e.Skip();
    auto msg = e.GetString().ToStdString();
    std::string token = msg.substr(0, msg.find(":"));
    std::string content = msg.substr(msg.find(":") + 1);
    // this->logs->AppendText(fmt::format("Got thread message: {}\n", e.GetString().ToStdString()));
    if (token == "QUEUE")
    {
        // only numbers here...
        QM::QueueEvents event = (QM::QueueEvents)std::stoi(content);
        // only handle the QUEUE messages, what this class generate
        // alway QM::EueueItem the payload, with the new data
        QM::QueueItem payload;
        payload = e.GetPayload<QM::QueueItem>();
        switch (event)
        {
            // new item added
        case QM::QueueEvents::ITEM_ADDED:
            this->OnQueueItemManagerItemAdded(payload);
            break;
            // item status changed
        case QM::QueueEvents::ITEM_STATUS_CHANGED:
            this->OnQueueItemManagerItemStatusChanged(payload);
            break;
            // item updated... ? ? ?
        case QM::QueueEvents::ITEM_UPDATED:
            this->OnQueueItemManagerItemUpdated(payload);
            break;
        case QM::QueueEvents::ITEM_START:
            this->StartGeneration(payload);
            break;
        default:
            break;
        }
    }
    if (token == "MODEL_LOAD_DONE")
    {
        // this->m_generate->Enable();
        // this->m_model->Enable();
        // this->m_vae->Enable();
        // this->m_refresh->Enable();
        // this->logs->AppendText(fmt::format("Model loaded: {}\n", content));
        this->modelLoaded = true;
        this->sd_ctx = e.GetPayload<sd_ctx_t *>();
        if (!this->IsShownOnScreen())
        {
            this->notification->SetFlags(wxICON_INFORMATION);
            this->notification->SetTitle("SD Gui");
            this->notification->SetMessage(content);
            this->notification->Show(5000);
        }
    }
    if (token == "MODEL_LOAD_START")
    {
        // this->m_generate->Disable();
        // this->m_model->Disable();
        // this->m_vae->Disable();
        // this->m_refresh->Disable();
        this->logs->AppendText(fmt::format("Model load start: {}\n", content));
    }
    if (token == "MODEL_LOAD_ERROR")
    {
        // this->m_generate->Disable();
        // this->m_model->Enable();
        // this->m_vae->Disable();
        // this->m_refresh->Enable();
        this->logs->AppendText(fmt::format("Model load error: {}\n", content));
        this->modelLoaded = false;
        if (!this->IsShownOnScreen())
        {
            this->notification->SetFlags(wxICON_ERROR);
            this->notification->SetTitle("SD Gui - error");
            this->notification->SetMessage(content);
            this->notification->Show(5000);
        }
    }
    if (token == "GENERATION_START")
    {
        auto myjob = e.GetPayload<QM::QueueItem>();
        // this->m_generate->Disable();
        // this->m_model->Disable();
        // this->m_vae->Disable();
        // this->m_refresh->Disable();
        this->logs->AppendText(fmt::format("Diffusion started. Seed: {} Batch: {} {}x{}px Cfg: {} Steps: {}\n",
                                           myjob.params.seed,
                                           myjob.params.batch_count,
                                           myjob.params.width,
                                           myjob.params.height,
                                           myjob.params.cfg_scale,
                                           myjob.params.sample_steps));
    }
    // never, not implemented in sd.cpp
    if (token == "GENERATION_PROGRESS")
    {
        // this->m_generate->Disable();
        // this->logs->AppendText(fmt::format("Generation progress: {}\n", content));
    }
    if (token == "GENERATION_DONE")
    {
        // this->m_generate->Enable();
        // this->m_model->Enable();
        // this->m_vae->Enable();
        // this->m_refresh->Enable();
        // sd_image_t *results = e.GetPayload<sd_image_t *>();
        // show images in new window...
        /* for (int i = 0; i < this->sd_params->batch_count; i++)
         {
             MainWindowImageViewer *imgWindow = new MainWindowImageViewer(this);
             // wxBitmap *img = new wxBitmap(results[i].data, (int)results[i].width, (int)results[i].height, (int)results[i].channel);
             wxImage img(results[i].width, results[i].height, results[i].data);
             wxBitmapBundle wxBmapB(img);
             imgWindow->m_bitmap->SetBitmap(wxBmapB);
             imgWindow->m_bitmap->SetSize(results[i].width, results[i].height);
             imgWindow->SetSize(results[i].width + 200, results[i].height);
             std::string details = fmt::format("Prompt:\n\n{}\n\nNegative prompt: \n\n{}\n\nSeed: {} \nCfg scale: {}\nClip skip: {}\nSampler: {}\nSteps: {}\nWidth: {} Height: {}",
                                               this->sd_params->prompt, this->sd_params->negative_prompt,
                                               this->sd_params->seed + i, this->sd_params->cfg_scale,
                                               this->sd_params->clip_skip, sd_gui_utils::sample_method_str[this->sd_params->sample_method], this->sd_params->sample_steps,
                                               results[i].width, results[i].height);
             imgWindow->m_textCtrl4->AppendText(wxString(details));
             imgWindow->Show();
             // imgWindow->m_bitmap->SetBitmap(img);
             /// imgWindow->m_bitmap->Set
         }*/
    }
    if (token == "GENERATION_ERROR")
    {
        // this->m_generate->Enable();
        // this->m_model->Enable();
        // this->m_vae->Enable();
        this->logs->AppendText(fmt::format("Generation error: {}\n", content));
        if (!this->IsShownOnScreen())
        {
            this->notification->SetFlags(wxICON_ERROR);
            this->notification->SetTitle("SD Gui - error");
            this->notification->SetMessage(content);
            this->notification->Show(5000);
        }
    }
    if (token == "SD_MESSAGE")
    {
        if (content.length() < 1)
        {
            return;
        }
        this->logs->AppendText(fmt::format("{}", content));
    }
    if (token == "MESSAGE")
    {
        this->logs->AppendText(fmt::format("{}\n", content));
        if (!this->IsShownOnScreen())
        {
            this->notification->SetFlags(wxICON_INFORMATION);
            this->notification->SetTitle("SD Gui");
            this->notification->SetMessage(content);
            this->notification->Show(5000);
        }
    }
}
void MainWindowUI::LoadModel(wxEvtHandler *eventHandler, QM::QueueItem myItem)
{
    wxThreadEvent *e = new wxThreadEvent();
    e->SetString(wxString::Format("MODEL_LOAD_START:%s", this->sd_params->model_path));
    e->SetPayload(myItem);
    wxQueueEvent(eventHandler, e);
    /*this->sd_ctx = new_sd_ctx(this->sd_params->model_path.c_str(),
                              this->sd_params->vae_path.c_str(),
                              this->sd_params->taesd_path.c_str(),
                              this->sd_params->controlnet_path.c_str(),
                              std::string(this->sd_params->lora_model_dir + "\\").c_str(),
                              this->sd_params->embeddings_path.c_str(),
                              true, // vae decode only
                              true ,
                              !this->cfg->keep_model_in_memory,
                              this->sd_params->n_threads,
                              this->sd_params->wtype ,
                              this->sd_params->rng_type,
                              this->sd_params->schedule,
                              this->sd_params->control_net_cpu);*/
    // this->sd_ctx = new_sd_ctx(this->sd_params->model_path.c_str(), this->sd_params->vae_path.c_str(), this->sd_params->taesd_path.c_str(), this->sd_params->lora_model_dir.c_str(), true, false, false, this->sd_params->n_threads, this->sd_params->wtype, this->sd_params->rng_type, this->sd_params->schedule);
    this->sd_ctx = new_sd_ctx(myItem.params.model_path.c_str(), myItem.params.vae_path.c_str(), myItem.params.taesd_path.c_str(), myItem.params.lora_model_dir.c_str(), true, false, false, myItem.params.n_threads, myItem.params.wtype, myItem.params.rng_type, myItem.params.schedule);
    if (this->sd_ctx == NULL)
    {
        wxThreadEvent *c = new wxThreadEvent();
        c->SetString(wxString::Format("MODEL_LOAD_ERROR:%s", this->sd_params->model_path));
        c->SetPayload(myItem);
        wxQueueEvent(eventHandler, c);
        this->modelLoaded = false;
        return;
    }
    else
    {
        wxThreadEvent *c = new wxThreadEvent();
        c->SetString(wxString::Format("MODEL_LOAD_DONE:%s", this->sd_params->model_path));
        c->SetPayload(this->sd_ctx);
        wxQueueEvent(eventHandler, c);
        this->modelLoaded = true;
        return;
    }
    return;
}
void MainWindowUI::initConfig()
{
    wxString datapath = wxStandardPaths::Get().GetUserDataDir() + wxFileName::GetPathSeparator() + "sd_ui_data" + wxFileName::GetPathSeparator();
    wxString imagespath = wxStandardPaths::Get().GetDocumentsDir() + wxFileName::GetPathSeparator() + "sd_ui_output" + wxFileName::GetPathSeparator();
    wxString model_path = datapath;
    model_path.append("checkpoints");
    wxString vae_path = datapath;
    vae_path.append("vae");
    wxString lora_path = datapath;
    lora_path.append("lora");
    wxString embedding_path = datapath;
    embedding_path.append("embedding");
    wxString presets_path = datapath;
    presets_path.append("presets");
    wxString jobs_path = datapath;
    jobs_path.append("queue_jobs");
    this->cfg->lora = this->fileConfig->Read("/paths/lora", lora_path).ToStdString();
    this->cfg->model = this->fileConfig->Read("/paths/model", model_path).ToStdString();
    this->cfg->vae = this->fileConfig->Read("/paths/vae", vae_path).ToStdString();
    this->cfg->embedding = this->fileConfig->Read("/paths/embedding", embedding_path).ToStdString();
    this->cfg->presets = this->fileConfig->Read("/paths/presets", presets_path).ToStdString();
    this->cfg->jobs = this->fileConfig->Read("/paths/presets", jobs_path).ToStdString();
    this->cfg->output = this->fileConfig->Read("/paths/output", imagespath).ToStdString();
    this->cfg->keep_model_in_memory = this->fileConfig->Read("/keep_model_in_memory", this->cfg->keep_model_in_memory);
    this->cfg->save_all_image = this->fileConfig->Read("/save_all_image", this->cfg->save_all_image);
    // populate data from sd_params as default...
    if (!this->modelLoaded)
    {
        this->m_cfg->SetValue(static_cast<double>(this->sd_params->cfg_scale));
        this->m_seed->SetValue(static_cast<int>(this->sd_params->seed));
        this->m_clip_skip->SetValue(this->sd_params->clip_skip);
        this->m_steps->SetValue(this->sd_params->sample_steps);
        this->m_width->SetValue(this->sd_params->width);
        this->m_height->SetValue(this->sd_params->height);
        this->m_batch_count->SetValue(this->sd_params->batch_count);
    }
}
void MainWindowUI::StartGeneration(QM::QueueItem myJob)
{
    this->threads.push_back(std::thread(std::bind(&MainWindowUI::Generate, this, this->GetEventHandler(), myJob)));
}
void MainWindowUI::OnCloseSettings(wxCloseEvent &event)
{
    this->initConfig();
    this->settingsWindow->Destroy();
}
void MainWindowUI::loadModelList()
{
    this->m_sampler->Clear();
    for (auto sampler : sd_gui_utils::sample_method_str)
    {
        int _u = this->m_sampler->Append(sampler);
        if (sampler == sd_gui_utils::sample_method_str[this->sd_params->sample_method])
        {
            this->m_sampler->Select(_u);
        }
    }
    this->LoadFileList(sd_gui_utils::DirTypes::CHECKPOINT);
    for (auto model : this->ModelFiles)
    {
        // auto size = sd_gui_utils::HumanReadable{std::filesystem::file_size(model.second)};
        auto size = std::filesystem::file_size(model.second);
        wxVector<wxVariant> data;
        data.push_back(wxVariant(model.first));
        data.push_back(wxVariant(std::to_string(size)));
        this->m_data_model_list->AppendItem(data);
    }
    this->m_data_model_list->Refresh();
}
void MainWindowUI::Generate(wxEvtHandler *eventHandler, QM::QueueItem myItem)
{
    // @brief model loading is done in the same thread which generating stuffs... no need new thread
    // @brief to load the model if no model loaded, or the loaded model is different from the job's model...
    // @brief if all second job have different model, it will be slower than same model on all jobs
    // TODO: abort job if model can not be loaded...
    if (!this->modelLoaded)
    {
        this->LoadModel(eventHandler, myItem);
        this->currentModel = myItem.params.model_path;
    }
    else
    {
        if (myItem.params.model_path != this->currentModel)
        {
            free_sd_ctx(this->sd_ctx);
            this->LoadModel(eventHandler, myItem);
        }
    }
    if (!this->modelLoaded)
    {
        wxThreadEvent *f = new wxThreadEvent();
        f->SetString("GENERATION_ERROR:Model load failed...");
        f->SetPayload(myItem);
        wxQueueEvent(eventHandler, f);
        return;
    }
    auto start = std::chrono::system_clock::now();
    wxThreadEvent *e = new wxThreadEvent();
    e->SetString(wxString::Format("GENERATION_START:%s", this->sd_params->model_path));
    e->SetPayload(myItem);
    wxQueueEvent(eventHandler, e);
    sd_image_t *control_image = NULL;
    sd_image_t *results;
    results = txt2img(this->sd_ctx,
                      this->sd_params->prompt.c_str(), this->sd_params->negative_prompt.c_str(), this->sd_params->clip_skip, this->sd_params->cfg_scale, this->sd_params->width, this->sd_params->height, this->sd_params->sample_method, this->sd_params->sample_steps, this->sd_params->seed, this->sd_params->batch_count);
    if (results == NULL)
    {
        wxThreadEvent *f = new wxThreadEvent();
        f->SetString("GENERATION_ERROR:Something wrong happened at image generation...");
        f->SetPayload(myItem);
        wxQueueEvent(eventHandler, f);
        return;
    }
    if (!std::filesystem::exists(this->cfg->output))
    {
        std::filesystem::create_directories(this->cfg->output);
    }
    /* save image(s) */
    const auto p1 = std::chrono::system_clock::now();
    auto ctime = std::chrono::duration_cast<std::chrono::seconds>(p1.time_since_epoch()).count();
    for (int i = 0; i < this->sd_params->batch_count; i++)
    {
        if (results[i].data == NULL)
        {
            continue;
        }
        // handle data??
        wxImage *img = new wxImage(results[i].width, results[i].height, results[i].data);
        std::string filename = this->cfg->output;
        std::string extension = ".png";
        if (this->sd_params->batch_count > 1)
        {
            filename = filename + wxFileName::GetPathSeparator() + std::to_string(ctime) + "_" + std::to_string(i) + extension;
        }
        else
        {
            filename = filename + wxFileName::GetPathSeparator() + std::to_string(ctime) + extension;
        }
        if (!img->SaveFile(filename))
        {
            wxThreadEvent *g = new wxThreadEvent();
            g->SetString(wxString::Format("GENERATION_ERROR:Failed to save image into %s", filename));
            g->SetPayload(myItem);
            wxQueueEvent(eventHandler, g);
        }
        else
        {
            myItem.images.emplace_back(filename);
        }
        // handle data??
    }
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    // send to notify the user...
    wxThreadEvent *h = new wxThreadEvent();
    auto msg = fmt::format("MESSAGE:Image generation done in {}s. Saved into {}", elapsed_seconds.count(), this->cfg->output);
    h->SetString(wxString(msg.c_str()));
    h->SetPayload(myItem);
    wxQueueEvent(eventHandler, h);
    wxThreadEvent *i = new wxThreadEvent();
    i->SetString(wxString::Format("GENERATION_DONE:ok"));
    i->SetPayload(results);
    wxQueueEvent(eventHandler, i);
    // send to the queue manager
    wxThreadEvent *j = new wxThreadEvent();
    j->SetString(wxString::Format("QUEUE:%d", QM::QueueEvents::ITEM_FINISHED));
    j->SetPayload(myItem);
    wxQueueEvent(eventHandler, j);
    return;
}
void MainWindowUI::HandleSDLog(sd_log_level_t level, const char *text, void *data)
{
    if (level != sd_log_level_t::SD_LOG_INFO)
    {
        return;
    }
    // wxEvtHandler *eventHandler = (wxEvtHandler *)data;
    MainWindowUI *ui = (MainWindowUI *)data;
    wxEvtHandler *eventHandler = ui->GetEventHandler();
    wxThreadEvent *e = new wxThreadEvent();
    e->SetString(wxString::Format("SD_MESSAGE:%s", text));
    e->SetPayload(level);
    wxQueueEvent(eventHandler, e);
}
void MainWindowUI::OnQueueItemManagerItemStatusChanged(QM::QueueItem item)
{
    /*
    this->m_joblist->AppendTextColumn("Id");
    this->m_joblist->AppendTextColumn("Created");
    this->m_joblist->AppendTextColumn("Model");
    this->m_joblist->AppendTextColumn("Sampler");
    this->m_joblist->AppendTextColumn("Seed");
    this->m_joblist->AppendTextColumn("Status");
    */
    // TODO: how to update an item in the table...
    // auto item = this->m_joblist->RowToItem();
    auto store = this->m_joblist->GetStore();
    for (auto it = this->JobTableItems->begin(); it != this->JobTableItems->end(); ++it)
    {
        if (it->second.id == item.id)
        {
            // auto store = *this->m_joblist()->GetStore();
            int lastCol = this->m_joblist->GetColumnCount();
            // always update the last col, so the last col is always need to be the status
            store->SetValueByRow(wxVariant(QM::QueueStatus_str[item.status]), it->first, lastCol - 1);
            this->m_joblist->Refresh();
            break;
        }
    }
}
MainWindowUI::~MainWindowUI()
{
    // clean up things...
    if (this->modelLoaded)
    {
        free_sd_ctx(this->sd_ctx);
    }
    for (int i = 0; i < this->threads.size(); i++)
    {
        this->threads.at(i).join();
    }
    this->threads.clear();
    this->Destroy();
    exit(0);
}
void MainWindowUI::loadVaeList()
{
    if (!std::filesystem::exists(this->cfg->vae))
    {
        std::filesystem::create_directories(this->cfg->vae);
    }
    this->LoadFileList(sd_gui_utils::DirTypes::VAE);
}
void MainWindowUI::OnQueueItemManagerItemUpdated(QM::QueueItem item)
{
}
void MainWindowUI::StartLoadModel()
{
    // prepare
    auto selection = this->m_model->GetStringSelection();
    if (selection == "-none-")
    {
        free_sd_ctx(this->sd_ctx);
        return;
    }
    if (this->modelLoaded)
    {
        free_sd_ctx(this->sd_ctx);
    }
    // disable ui
    this->m_model->Disable();
    this->m_vae->Disable();
    this->m_refresh->Disable();
    this->sd_params->model_path = this->ModelFiles.at(selection.ToStdString());
    this->sd_params->lora_model_dir = this->fileConfig->Read("/paths/lora", "").ToStdString();
    // this->threads.push_back(std::thread(std::bind(&MainWindowUI::LoadModel, this, this->GetEventHandler())));
}
ui/MainWindowUI.h
@@ -19,6 +19,7 @@
#include <thread>
#include <vector>
#include <fstream>
#include <mutex>
#include <fmt/format.h>
#include "utils.hpp"
@@ -29,6 +30,7 @@
#include <wx/event.h>
#include <wx/notifmsg.h>
#include <wx/textdlg.h>
#include <wx/menu.h>
/** Implementing UI */
class MainWindowUI : public UI
@@ -39,19 +41,19 @@
    void onModelsRefresh(wxCommandEvent &event);
    void onModelSelect(wxCommandEvent &event);
    void onVaeSelect(wxCommandEvent &event);
    void onSamplerSelect(wxCommandEvent &event);
    void onResolutionSwap(wxCommandEvent &event);
    void onJobsStart(wxCommandEvent &event);
    void onJobsPause(wxCommandEvent &event);
    void onJobsDelete(wxCommandEvent &event);
    void onJoblistItemActivated(wxDataViewEvent &event);
        void onContextMenu( wxDataViewEvent& event );
    void onJoblistSelectionChanged(wxDataViewEvent &event);
    void onGenerate(wxCommandEvent &event);
        void onSamplerSelect( wxCommandEvent& event );
    void onSavePreset(wxCommandEvent &event);
    void onLoadPreset(wxCommandEvent &event);
    void onSelectPreset(wxCommandEvent &event);
    void onDeletePreset(wxCommandEvent &event);
public:
    /** Constructor */
    MainWindowUI(wxWindow *parent);
@@ -60,6 +62,7 @@
    void OnThreadMessage(wxThreadEvent &e);
private:
    std::mutex sdMutex;
    wxFileConfig *fileConfig;
    sd_gui_utils::config *cfg;
    wxString ini_path;
@@ -79,7 +82,8 @@
    std::vector<std::thread> threads;
    // row,QueueItem
    std::map<int, QM::QueueItem> *JobTableItems;
    std::map<int, QM::QueueItem*> JobTableItems;
    std::map<int, wxDataViewColumn *> *JobTableColumns;
    void initConfig();
    void loadModelList();
@@ -89,14 +93,13 @@
    void LoadPresets();
    static void HandleSDLog(sd_log_level_t level, const char *text, void *data);
    static void HandleSDProgress(int step, int steps, float time, void *data);
    // load the model in a new thread
    void LoadModel(wxEvtHandler *eventHandler, QM::QueueItem myItem);
    sd_ctx_t *LoadModelv2(wxEvtHandler *eventHandler, QM::QueueItem myItem);
    // generate in another thread
    void Generate(wxEvtHandler *eventHandler, QM::QueueItem myItem);
    // start a thread for model loading...
    void StartLoadModel();
    // start a thread to generate image
    void StartGeneration(QM::QueueItem myJob);
@@ -106,6 +109,8 @@
    void OnQueueItemManagerItemStatusChanged(QM::QueueItem item);
    wxNotificationMessage *notification;
};
#endif // __MainWindowUI__
ui/QueueManager.cpp
@@ -7,21 +7,33 @@
    this->eventHandler->Bind(wxEVT_THREAD, &QueueManager::OnThreadMessage, this);
    this->jobsDir = jobsdir;
    this->QueueList = std::map<int, QM::QueueItem>();
    this->LoadJobListFromDir();
}
QM::QueueManager::~QueueManager()
{
}
int QM::QueueManager::AddItem(QM::QueueItem item)
{
    if (!item.id)
    if (item.id == 0)
    {
        item.id = this->GetCurrentUnixTimestamp();
        item.id = this->GetAnId();
    }
    if (item.created_at == 0)
    {
        item.created_at = this->GetCurrentUnixTimestamp();
    }
    this->QueueList[item.id] = item;
    this->SendEventToMainWindow(QM::QueueEvents::ITEM_ADDED, item);
    if (this->isRunning == false)
    if (this->isRunning == false && item.status == QM::QueueStatus::PENDING)
    {
        this->SendEventToMainWindow(QM::QueueEvents::ITEM_START, item);
        this->isRunning = true;
    }
    this->SaveJobToFile(item);
    return item.id;
}
@@ -29,7 +41,6 @@
{
    QM::QueueItem item;
    item.params = *params;
    item.created_at = item.id = this->GetCurrentUnixTimestamp();
    return this->AddItem(item);
}
@@ -37,7 +48,6 @@
{
    QM::QueueItem item;
    item.params = params;
    item.created_at = item.id = this->GetCurrentUnixTimestamp();
    return this->AddItem(item);
}
@@ -85,6 +95,12 @@
    if (this->QueueList.find(id) != this->QueueList.end())
    {
        this->QueueList[id].status = status;
        this->QueueList[id].updated_at = this->GetCurrentUnixTimestamp();
        if (status == QM::QueueStatus::DONE)
        {
            this->QueueList[id].finished_at = this->GetCurrentUnixTimestamp();
        }
        this->SaveJobToFile(this->QueueList[id]);
        this->SendEventToMainWindow(QM::QueueEvents::ITEM_STATUS_CHANGED, this->QueueList[id]);
    }
}
@@ -112,7 +128,10 @@
void QM::QueueManager::OnThreadMessage(wxThreadEvent &e)
{
    if (e.GetSkipped() == false)
    {
    e.Skip();
    }
    auto msg = e.GetString().ToStdString();
    std::string token = msg.substr(0, msg.find(":"));
@@ -128,6 +147,7 @@
        {
            this->SetStatus(QM::QueueStatus::RUNNING, payload.id);
            this->isRunning = true;
            return;
        }
        if (event == QM::QueueEvents::ITEM_FINISHED)
        {
@@ -147,7 +167,7 @@
                    break;
                }
            }
            // move finished job into another list - ??
            return;
        }
    }
@@ -177,10 +197,26 @@
        this->SetStatus(QM::QueueStatus::RUNNING, payload.id);
        this->isRunning = true;
    }
    // nothing to todo here, the payload is the generated image list
    // nothing to todo here, the payload is the generated image list, we can't find whitch item was it...
    // TODO: use struct to payload, and store multiple items in it...
    if (token == "GENERATION_DONE")
    {
    }
}
void QM::QueueManager::SaveJobToFile(int id)
{
    auto item = this->GetItem(id);
    this->SaveJobToFile(item);
}
void QM::QueueManager::SaveJobToFile(QM::QueueItem item)
{
    nlohmann::json jsonfile(item);
    std::string filename = this->jobsDir + "/" + std::to_string(item.id) + ".json";
    std::ofstream file(filename);
    file << jsonfile;
    file.close();
}
int QM::QueueManager::GetCurrentUnixTimestamp()
@@ -189,6 +225,62 @@
    return static_cast<int>(std::chrono::duration_cast<std::chrono::seconds>(p1.time_since_epoch()).count());
}
void QM::QueueManager::LoadJobListFromDir()
{
    if (!std::filesystem::exists(this->jobsDir))
    {
        std::filesystem::create_directories(this->jobsDir);
    }
    int i = 0;
    for (auto const &dir_entry : std::filesystem::recursive_directory_iterator(this->jobsDir))
    {
        if (!dir_entry.exists() || !dir_entry.is_regular_file() || !dir_entry.path().has_extension())
        {
            continue;
        }
        std::filesystem::path path = dir_entry.path();
        std::string ext = path.extension().string();
        if (ext != ".json")
        {
            continue;
        }
        std::string name = path.filename().replace_extension("").string();
        std::ifstream f(path.string());
        try
        {
            nlohmann::json data = nlohmann::json::parse(f);
            auto item = data.get<QM::QueueItem>();
            if (item.status == QM::QueueStatus::RUNNING)
            {
                item.status = QM::QueueStatus::FAILED;
            }
            this->AddItem(item);
        }
        catch (const std::exception &e)
        {
            std::cerr << e.what() << '\n';
        }
    }
}
int QM::QueueManager::GetAnId()
{
    int id = this->GetCurrentUnixTimestamp();
    while (id <= this->lastId)
    {
        id++;
    }
    this->lastId = id;
    return id;
}
void QM::QueueManager::onItemAdded(QM::QueueItem item)
{
    // this->parent->m_joblist
ui/QueueManager.h
@@ -1,6 +1,7 @@
#ifndef __SD_GUI_QUEUE_MANAGER
#define __SD_GUI_QUEUE_MANAGER
#include <fstream>
#include <map>
#include <chrono>
#include <nlohmann/json.hpp>
@@ -27,8 +28,7 @@
        "paused",
        "failed",
        "model loading...",
        "finished"
        };
        "finished"};
    enum QueueEvents
    {
@@ -44,7 +44,7 @@
        QueueItem() = default;
        QueueItem(const QueueItem &other)
            : id(other.id), created_at(other.created_at), updated_at(other.updated_at),
              finished_at(other.finished_at), params(other.params), status(other.status), images(other.images) {}
              finished_at(other.finished_at), params(other.params), status(other.status), images(other.images), step(other.step), steps(other.steps), time(other.time), model(other.model) {}
        QueueItem &operator=(const QueueItem &other)
        {
@@ -55,18 +55,22 @@
                updated_at = other.updated_at;
                finished_at = other.finished_at;
                images = other.images;
                // Másolatot készítünk a params referenciáról
                // Ha a params referenciához tartozó SDParams objektum módosulna,
                // akkor ebben az esetben másolatban marad az eredeti QueueItem-ben
                params = other.params;
                status = other.status;
                step = other.step;
                steps = other.steps;
                time = other.time;
                model = other.model;
            }
            return *this;
        }
        int id, created_at = 0, updated_at = 0, finished_at = 0;
        int id = 0, created_at = 0, updated_at = 0, finished_at = 0;
        int step = 0, steps = 0;
        float time = 0;
        sd_gui_utils::SDParams params;
        QM::QueueStatus status = QM::QueueStatus::PENDING;
        std::vector<std::string> images;
        std::string model;
    };
    inline void to_json(nlohmann::json &j, const QueueItem &p)
@@ -77,8 +81,11 @@
            {"updated_at", p.updated_at},
            {"finished_at", p.finished_at},
            {"images", p.images},
            //   {"params", p.params},
            {"status", (int)p.status}};
            {"status", (int)p.status},
            {"model", p.model},
            {"params", p.params},
        };
    }
    inline void from_json(const nlohmann::json &j, QueueItem &p)
@@ -88,7 +95,8 @@
        j.at("updated_at").get_to(p.updated_at);
        j.at("images").get_to(p.images);
        j.at("finished_at").get_to(p.finished_at);
        //  j.at("params").get_to(p.params);
        j.at("model").get_to(p.model);
        j.at("params").get_to(p.params);
        p.status = j.at("status").get<QM::QueueStatus>();
    }
@@ -96,6 +104,7 @@
    {
    public:
        QueueManager(wxEvtHandler *eventHandler, std::string jobsdir);
        ~QueueManager();
        int AddItem(QM::QueueItem item);
        int AddItem(sd_gui_utils::SDParams *params);
        int AddItem(sd_gui_utils::SDParams params);
@@ -108,14 +117,18 @@
        void PauseAll();
        void SendEventToMainWindow(QM::QueueEvents eventType, QM::QueueItem item = QM::QueueItem());
        void OnThreadMessage(wxThreadEvent &e);
        void SaveJobToFile(int id);
        void SaveJobToFile(QM::QueueItem item);
    private:
        int GetCurrentUnixTimestamp();
        void LoadJobListFromDir();
        std::string jobsDir;
        int lastId = 0;
        int GetAnId();
        // thread events handler, toupdate main window data table
        void onItemAdded(QM::QueueItem item);
        void LodJobsFromFile();
        void SaveJobsToFile();
        // @brief check if something is running or not
        bool isRunning = false;
ui/sha512.hpp
New file
@@ -0,0 +1,337 @@
/**
 * @file sha512.hh
 * @author Stefan Wilhelm (stfwi)
 * @ccflags
 * @ldflags
 * @platform linux, bsd, windows
 * @standard >= c++98
 *
 * SHA512 calculation class template.
 *
 * -------------------------------------------------------------------------------------
 * +++ BSD license header +++
 * Copyright (c) 2010, 2012, Stefan Wilhelm (stfwi, <cerbero s@atwilly s.de>)
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met: (1) Redistributions
 * of source code must retain the above copyright notice, this list of conditions
 * and the following disclaimer. (2) Redistributions in binary form must reproduce
 * the above copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the distribution.
 * (3) Neither the name of the project nor the names of its contributors may be
 * used to endorse or promote products derived from this software without specific
 * prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
 * AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 * -------------------------------------------------------------------------------------
 * 01-2013: (stfwi) Class to template class, reformatting
 */
#ifndef SHA512_HH
#define SHA512_HH
#if defined(OS_WIN) || defined(_WINDOWS_) || defined(_WIN32) || defined(__MSC_VER)
#include <inttypes.h>
#else
#include <stdint.h>
#endif
#include <sstream>
#include <iomanip>
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
namespace sw
{
  namespace detail
  {
    /**
     * @class basic_sha512
     * @template
     */
    template <typename Char_Type = char>
    class basic_sha512
    {
    public:
      /**
       * Types
       */
      typedef std::basic_string<Char_Type> str_t;
    public:
      /**
       * Constructor
       */
      basic_sha512()
      {
        clear();
      }
      /**
       * Destructor
       */
      ~basic_sha512()
      {
        ;
      }
    public:
      /**
       * Clear/reset all internal buffers and states.
       */
      void clear()
      {
        sum_[0] = 0x6a09e667f3bcc908;
        sum_[1] = 0xbb67ae8584caa73b;
        sum_[2] = 0x3c6ef372fe94f82b;
        sum_[3] = 0xa54ff53a5f1d36f1;
        sum_[4] = 0x510e527fade682d1;
        sum_[5] = 0x9b05688c2b3e6c1f;
        sum_[6] = 0x1f83d9abfb41bd6b;
        sum_[7] = 0x5be0cd19137e2179;
        sz_ = 0;
        iterations_ = 0;
        memset(&block_, 0, sizeof(block_));
      }
      /**
       * Push new binary data into the internal buf_ and recalculate the checksum.
       * @param const void* data
       * @param size_t size
       */
      void update(const void *data, size_t size)
      {
        unsigned nb, n, n_tail;
        const uint8_t *p;
        n = 128 - sz_;
        n_tail = size < n ? size : n;
        memcpy(&block_[sz_], data, n_tail);
        if (sz_ + size < 128)
        {
          sz_ += size;
          return;
        }
        n = size - n_tail;
        nb = n >> 7;
        p = (const uint8_t *)data + n_tail;
        transform(block_, 1);
        transform(p, nb);
        n_tail = n & 0x7f;
        memcpy(block_, &p[nb << 7], n_tail);
        sz_ = n_tail;
        iterations_ += (nb + 1) << 7;
      }
      /**
       * Finanlise checksum, return hex string.
       * @return str_t
       */
      str_t final_data()
      {
#if (defined(BYTE_ORDER)) && (defined(BIG_ENDIAN)) && ((BYTE_ORDER == BIG_ENDIAN))
#define U32_B(x, b)                  \
  *((b) + 0) = (uint8_t)((x));       \
  *((b) + 1) = (uint8_t)((x) >> 8);  \
  *((b) + 2) = (uint8_t)((x) >> 16); \
  *((b) + 3) = (uint8_t)((x) >> 24);
#else
#define U32_B(x, b)                  \
  *((b) + 3) = (uint8_t)((x));       \
  *((b) + 2) = (uint8_t)((x) >> 8);  \
  *((b) + 1) = (uint8_t)((x) >> 16); \
  *((b) + 0) = (uint8_t)((x) >> 24);
#endif
        unsigned nb, n;
        uint64_t n_total;
        nb = 1 + ((0x80 - 17) < (sz_ & 0x7f));
        n_total = (iterations_ + sz_) << 3;
        n = nb << 7;
        memset(block_ + sz_, 0, n - sz_);
        block_[sz_] = 0x80;
        U32_B(n_total, block_ + n - 4);
        transform(block_, nb);
        std::basic_stringstream<Char_Type> ss; // hex string
        for (unsigned i = 0; i < 8; ++i)
        {
          ss << std::hex << std::setfill('0') << std::setw(16) << (sum_[i]);
        }
        clear();
        return ss.str();
#undef U32_B
      }
    public:
      /**
       * Calculates the SHA256 for a given string.
       * @param const str_t & s
       * @return str_t
       */
      static str_t calculate(const str_t &s)
      {
        basic_sha512 r;
        r.update(s.data(), s.length());
        return r.final_data();
      }
      /**
       * Calculates the SHA256 for a given C-string.
       * @param const char* s
       * @return str_t
       */
      static str_t calculate(const void *data, size_t size)
      {
        basic_sha512 r;
        r.update(data, size);
        return r.final_data();
      }
      /**
       * Calculates the SHA256 for a stream. Returns an empty string on error.
       * @param std::istream & is
       * @return str_t
       */
      static str_t calculate(std::istream &is)
      {
        basic_sha512 r;
        char data[64];
        while (is.good() && is.read(data, sizeof(data)).good())
        {
          r.update(data, sizeof(data));
        }
        if (!is.eof())
          return str_t();
        if (is.gcount())
          r.update(data, is.gcount());
        return r.final_data();
      }
      /**
       * Calculates the SHA256 checksum for a given file, either read binary or as text.
       * @param const str_t & path
       * @param bool binary = true
       * @return str_t
       */
      static str_t file(const str_t &path, bool binary = true)
      {
        std::ifstream fs;
        fs.open(path.c_str(), binary ? (std::ios::in | std::ios::binary) : (std::ios::in));
        str_t s = calculate(fs);
        fs.close();
        return s;
      }
    private:
      /**
       * Performs the SHA256 transformation on a given block
       * @param uint32_t *block
       */
      void transform(const uint8_t *data, size_t size)
      {
#define SR(x, n) (x >> n)
#define RR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define RL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
#define CH(x, y, z) ((x & y) ^ (~x & z))
#define MJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define F1(x) (RR(x, 28) ^ RR(x, 34) ^ RR(x, 39))
#define F2(x) (RR(x, 14) ^ RR(x, 18) ^ RR(x, 41))
#define F3(x) (RR(x, 1) ^ RR(x, 8) ^ SR(x, 7))
#define F4(x) (RR(x, 19) ^ RR(x, 61) ^ SR(x, 6))
#if (defined(BYTE_ORDER)) && (defined(BIG_ENDIAN)) && ((BYTE_ORDER == BIG_ENDIAN))
#define B_U64(b, x) *(x) = ((uint64_t) * ((b) + 0)) | ((uint64_t) * ((b) + 1) << 8) |                                         \
                           ((uint64_t) * ((b) + 2) << 16) | ((uint64_t) * ((b) + 3) << 24) | ((uint64_t) * ((b) + 4) << 32) | \
                           ((uint64_t) * ((b) + 5) << 40) | ((uint64_t) * ((b) + 6) << 48) | ((uint64_t) * ((b) + 7) << 56);
#else
#define B_U64(b, x) *(x) = ((uint64_t) * ((b) + 7)) | ((uint64_t) * ((b) + 6) << 8) |                                         \
                           ((uint64_t) * ((b) + 5) << 16) | ((uint64_t) * ((b) + 4) << 24) | ((uint64_t) * ((b) + 3) << 32) | \
                           ((uint64_t) * ((b) + 2) << 40) | ((uint64_t) * ((b) + 1) << 48) | ((uint64_t) * ((b) + 0) << 56);
#endif
        uint64_t t, u, v[8], w[80];
        const uint8_t *tblock;
        unsigned j;
        for (unsigned i = 0; i < size; ++i)
        {
          tblock = data + (i << 7);
          for (j = 0; j < 16; ++j)
            B_U64(&tblock[j << 3], &w[j]);
          for (j = 16; j < 80; ++j)
            w[j] = F4(w[j - 2]) + w[j - 7] + F3(w[j - 15]) + w[j - 16];
          for (j = 0; j < 8; ++j)
            v[j] = sum_[j];
          for (j = 0; j < 80; ++j)
          {
            t = v[7] + F2(v[4]) + CH(v[4], v[5], v[6]) + lut_[j] + w[j];
            u = F1(v[0]) + MJ(v[0], v[1], v[2]);
            v[7] = v[6];
            v[6] = v[5];
            v[5] = v[4];
            v[4] = v[3] + t;
            v[3] = v[2];
            v[2] = v[1];
            v[1] = v[0];
            v[0] = t + u;
          }
          for (j = 0; j < 8; ++j)
            sum_[j] += v[j];
        }
#undef SR
#undef RR
#undef RL
#undef CH
#undef MJ
#undef F1
#undef F2
#undef F3
#undef F4
#undef B_U64
      }
    private:
      uint64_t iterations_; // Number of iterations
      uint64_t sum_[8];     // Intermediate checksum buffer
      unsigned sz_;         // Number of currently stored bytes in the block
      uint8_t block_[256];
      static const uint64_t lut_[80]; // Lookup table
    };
    template <typename CT>
    const uint64_t basic_sha512<CT>::lut_[80] = {
        0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
        0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
        0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
        0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
        0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
        0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
        0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
        0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
        0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
        0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
        0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
        0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
        0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
        0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
        0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
        0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
        0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
        0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
        0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
        0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817};
  }
}
namespace sw
{
  typedef detail::basic_sha512<> sha512;
}
#endif
ui/utils.hpp
@@ -3,6 +3,8 @@
#include <string>
#include <filesystem>
#include <iostream>
#include <random>
#include <opencv2/opencv.hpp>
#include <stable-diffusion.h>
@@ -10,6 +12,47 @@
namespace sd_gui_utils
{
    typedef struct VoidHolder
    {
        void *p1;
        void *p2;
    } VoidHolder;
    struct ModelFileInfo
    {
        std::string name;
        std::string path;
        std::string url;
        std::string poster;
        std::string sha256;
        uintmax_t size;
        std::string size_f;
    };
    inline void to_json(nlohmann::json &j, const ModelFileInfo &p)
    {
        j = nlohmann::json{
            {"name", p.name},
            {"path", p.path},
            {"url", p.url},
            {"poster", p.poster},
            {"sha256", p.sha256},
            {"size", p.size},
            {"size_f", p.size_f}
        };
    }
    inline void from_json(const nlohmann::json &j, ModelFileInfo &p)
    {
        j.at("name").get_to(p.name);
        j.at("path").get_to(p.path);
        j.at("url").get_to(p.url);
        j.at("poster").get_to(p.poster);
        j.at("sha256").get_to(p.sha256);
        j.at("size").get_to(p.size);
        j.at("size_f").get_to(p.size_f);
    }
    enum THREAD_STATUS_MESSAGES
    {
@@ -49,7 +92,17 @@
        bool keep_model_in_memory = true;
        bool save_all_image = true;
    };
    inline std::string formatUnixTimestampToDate(long timestamp)
    {
        std::time_t time = static_cast<std::time_t>(timestamp);
        std::tm *timeinfo = std::localtime(&time);
        std::ostringstream oss;
        oss << (timeinfo->tm_year + 1900) << "-" << std::setw(2) << std::setfill('0') << (timeinfo->tm_mon + 1) << "-" << std::setw(2) << std::setfill('0') << timeinfo->tm_mday
            << " " << std::setw(2) << std::setfill('0') << timeinfo->tm_hour << ":" << std::setw(2) << std::setfill('0') << timeinfo->tm_min;
        return oss.str();
    }
    enum DirTypes
    {
        LORA,
@@ -277,6 +330,7 @@
            {"clip_skip", p.clip_skip},
            {"width", p.width},
            {"height", p.height},
            {"batch_count", p.batch_count},
            {"sample_method", (int)p.sample_method},
            {"schedule", (int)p.schedule},
            {"sample_steps", p.sample_steps},
@@ -377,6 +431,29 @@
        cv::resize(img, square(roi), roi.size());
        return square;
    };
    inline const unsigned int generateRandomInt(unsigned int min, unsigned int max)
    {
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<unsigned int> dis(min, max);
        return dis(gen);
    };
    inline std::pair<double, std::string> humanReadableFileSize(double bytes)
    {
        static const char *sizes[] = {"B", "KB", "MB", "GB", "TB"};
        int div = 0;
        double size = bytes;
        while (size >= 1024 && div < (sizeof(sizes) / sizeof(*sizes)))
        {
            size /= 1024;
            div++;
        }
        return std::make_pair(size, sizes[div]);
    }
};
ui/windows.fbp
@@ -124,11 +124,11 @@
              <property name="name">sizer0002</property>
              <property name="orient">wxVERTICAL</property>
              <property name="permission">none</property>
              <object class="sizeritem" expanded="false">
              <object class="sizeritem" expanded="true">
                <property name="border">5</property>
                <property name="flag">wxALL|wxEXPAND</property>
                <property name="proportion">0</property>
                <object class="wxBoxSizer" expanded="false">
                <object class="wxBoxSizer" expanded="true">
                  <property name="minimum_size"></property>
                  <property name="name">sizer0021</property>
                  <property name="orient">wxHORIZONTAL</property>
@@ -180,7 +180,7 @@
                      <property name="maximum_size"></property>
                      <property name="min_size"></property>
                      <property name="minimize_button">0</property>
                      <property name="minimum_size"></property>
                      <property name="minimum_size">70,-1</property>
                      <property name="moveable">1</property>
                      <property name="name">m_settings</property>
                      <property name="pane_border">1</property>
@@ -255,7 +255,7 @@
                      <property name="maximum_size"></property>
                      <property name="min_size"></property>
                      <property name="minimize_button">0</property>
                      <property name="minimum_size"></property>
                      <property name="minimum_size">70,-1</property>
                      <property name="moveable">1</property>
                      <property name="name">m_refresh</property>
                      <property name="pane_border">1</property>
@@ -316,14 +316,14 @@
                      <property name="gripper">0</property>
                      <property name="hidden"></property>
                      <property name="id">wxID_ANY</property>
                      <property name="label">Model</property>
                      <property name="label">Model:</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="minimum_size">50,-1</property>
                      <property name="moveable">1</property>
                      <property name="name">m_staticText160</property>
                      <property name="pane_border">1</property>
@@ -335,7 +335,7 @@
                      <property name="resize">Resizable</property>
                      <property name="show">1</property>
                      <property name="size"></property>
                      <property name="style"></property>
                      <property name="style">wxALIGN_CENTER_HORIZONTAL</property>
                      <property name="subclass">; ; forward_declare</property>
                      <property name="toolbar_pane">0</property>
                      <property name="tooltip"></property>
@@ -384,7 +384,7 @@
                      <property name="maximum_size"></property>
                      <property name="min_size"></property>
                      <property name="minimize_button">0</property>
                      <property name="minimum_size"></property>
                      <property name="minimum_size">200,-1</property>
                      <property name="moveable">1</property>
                      <property name="name">m_model</property>
                      <property name="pane_border">1</property>
@@ -444,14 +444,14 @@
                      <property name="gripper">0</property>
                      <property name="hidden"></property>
                      <property name="id">wxID_ANY</property>
                      <property name="label">Vae</property>
                      <property name="label">Vae:</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="minimum_size">50,-1</property>
                      <property name="moveable">1</property>
                      <property name="name">m_staticText161</property>
                      <property name="pane_border">1</property>
@@ -463,7 +463,7 @@
                      <property name="resize">Resizable</property>
                      <property name="show">1</property>
                      <property name="size"></property>
                      <property name="style"></property>
                      <property name="style">wxALIGN_CENTER_HORIZONTAL</property>
                      <property name="subclass">; ; forward_declare</property>
                      <property name="toolbar_pane">0</property>
                      <property name="tooltip"></property>
@@ -512,7 +512,7 @@
                      <property name="maximum_size"></property>
                      <property name="min_size"></property>
                      <property name="minimize_button">0</property>
                      <property name="minimum_size"></property>
                      <property name="minimum_size">200,-1</property>
                      <property name="moveable">1</property>
                      <property name="name">m_vae</property>
                      <property name="pane_border">1</property>
@@ -539,141 +539,13 @@
                      <event name="OnChoice">onVaeSelect</event>
                    </object>
                  </object>
                  <object class="sizeritem" expanded="false">
                    <property name="border">5</property>
                    <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
                    <property name="proportion">0</property>
                    <object class="wxStaticText" expanded="false">
                      <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="drag_accept_files">0</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"></property>
                      <property name="id">wxID_ANY</property>
                      <property name="label">Sampler</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">m_staticText163</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">sampling method (default: &quot;euler_a&quot;)</property>
                      <property name="window_extra_style"></property>
                      <property name="window_name"></property>
                      <property name="window_style"></property>
                      <property name="wrap">0</property>
                    </object>
                  </object>
                  <object class="sizeritem" expanded="false">
                    <property name="border">5</property>
                    <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
                    <property name="proportion">0</property>
                    <object class="wxChoice" expanded="false">
                      <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="choices"></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="drag_accept_files">0</property>
                      <property name="enabled"></property>
                      <property name="fg"></property>
                      <property name="floatable">1</property>
                      <property name="font"></property>
                      <property name="gripper">0</property>
                      <property name="hidden"></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_sampler</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="selection">0</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">sampling method (default: &quot;euler_a&quot;)</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="OnChoice">onSamplerSelect</event>
                    </object>
                  </object>
                </object>
              </object>
              <object class="sizeritem" expanded="false">
              <object class="sizeritem" expanded="true">
                <property name="border">5</property>
                <property name="flag">wxALL|wxEXPAND</property>
                <property name="proportion">0</property>
                <object class="wxBoxSizer" expanded="false">
                <object class="wxBoxSizer" expanded="true">
                  <property name="minimum_size"></property>
                  <property name="name">sizer0003</property>
                  <property name="orient">wxHORIZONTAL</property>
@@ -783,7 +655,7 @@
                      <property name="min">0</property>
                      <property name="min_size"></property>
                      <property name="minimize_button">0</property>
                      <property name="minimum_size"></property>
                      <property name="minimum_size">45,-1</property>
                      <property name="moveable">1</property>
                      <property name="name">m_cfg</property>
                      <property name="pane_border">1</property>
@@ -795,7 +667,7 @@
                      <property name="resize">Resizable</property>
                      <property name="show">1</property>
                      <property name="size"></property>
                      <property name="style">wxALIGN_CENTER_HORIZONTAL|wxSP_ARROW_KEYS</property>
                      <property name="style">wxSP_ARROW_KEYS</property>
                      <property name="subclass">; ; forward_declare</property>
                      <property name="toolbar_pane">0</property>
                      <property name="tooltip"></property>
@@ -901,14 +773,14 @@
                      <property name="hidden"></property>
                      <property name="id">wxID_ANY</property>
                      <property name="initial">44</property>
                      <property name="max">9999999</property>
                      <property name="max">99999999999</property>
                      <property name="max_size"></property>
                      <property name="maximize_button">0</property>
                      <property name="maximum_size"></property>
                      <property name="min">0</property>
                      <property name="min">-1</property>
                      <property name="min_size"></property>
                      <property name="minimize_button">0</property>
                      <property name="minimum_size"></property>
                      <property name="minimum_size">80,-1</property>
                      <property name="moveable">1</property>
                      <property name="name">m_seed</property>
                      <property name="pane_border">1</property>
@@ -920,7 +792,7 @@
                      <property name="resize">Resizable</property>
                      <property name="show">1</property>
                      <property name="size"></property>
                      <property name="style">wxSP_ARROW_KEYS</property>
                      <property name="style"></property>
                      <property name="subclass">; ; forward_declare</property>
                      <property name="toolbar_pane">0</property>
                      <property name="tooltip"></property>
@@ -1033,7 +905,7 @@
                      <property name="min">-1</property>
                      <property name="min_size"></property>
                      <property name="minimize_button">0</property>
                      <property name="minimum_size"></property>
                      <property name="minimum_size">45,-1</property>
                      <property name="moveable">1</property>
                      <property name="name">m_clip_skip</property>
                      <property name="pane_border">1</property>
@@ -1158,7 +1030,7 @@
                      <property name="min">0</property>
                      <property name="min_size"></property>
                      <property name="minimize_button">0</property>
                      <property name="minimum_size"></property>
                      <property name="minimum_size">45,-1</property>
                      <property name="moveable">1</property>
                      <property name="name">m_steps</property>
                      <property name="pane_border">1</property>
@@ -1685,11 +1557,11 @@
                        <property name="name">bSizer17</property>
                        <property name="orient">wxVERTICAL</property>
                        <property name="permission">none</property>
                        <object class="sizeritem" expanded="false">
                        <object class="sizeritem" expanded="true">
                          <property name="border">5</property>
                          <property name="flag">wxEXPAND</property>
                          <property name="proportion">0</property>
                          <object class="wxBoxSizer" expanded="false">
                          <object class="wxBoxSizer" expanded="true">
                            <property name="minimum_size"></property>
                            <property name="name">bSizer18</property>
                            <property name="orient">wxHORIZONTAL</property>
@@ -1921,11 +1793,11 @@
                            </object>
                          </object>
                        </object>
                        <object class="sizeritem" expanded="true">
                        <object class="sizeritem" expanded="false">
                          <property name="border">5</property>
                          <property name="flag">wxALL|wxEXPAND</property>
                          <property name="proportion">1</property>
                          <object class="wxDataViewListCtrl" expanded="true">
                          <object class="wxDataViewListCtrl" expanded="false">
                            <property name="bg"></property>
                            <property name="context_help"></property>
                            <property name="context_menu">1</property>
@@ -1948,17 +1820,18 @@
                            <property name="window_name"></property>
                            <property name="window_style"></property>
                            <event name="OnDataViewListCtrlItemActivated">onJoblistItemActivated</event>
                            <event name="OnDataViewListCtrlItemContextMenu">onContextMenu</event>
                            <event name="OnDataViewListCtrlSelectionChanged">onJoblistSelectionChanged</event>
                          </object>
                        </object>
                      </object>
                    </object>
                  </object>
                  <object class="notebookpage" expanded="false">
                  <object class="notebookpage" expanded="true">
                    <property name="bitmap">Load From Embedded File; icons/16/text_box_dots.png</property>
                    <property name="label">Text2IMG</property>
                    <property name="select">1</property>
                    <object class="wxPanel" expanded="false">
                    <object class="wxPanel" expanded="true">
                      <property name="BottomDockable">1</property>
                      <property name="LeftDockable">1</property>
                      <property name="RightDockable">1</property>
@@ -2010,7 +1883,7 @@
                      <property name="window_extra_style"></property>
                      <property name="window_name"></property>
                      <property name="window_style">wxTAB_TRAVERSAL</property>
                      <object class="wxBoxSizer" expanded="false">
                      <object class="wxBoxSizer" expanded="true">
                        <property name="minimum_size">-1,120</property>
                        <property name="name">sizer0004</property>
                        <property name="orient">wxHORIZONTAL</property>
@@ -2206,11 +2079,11 @@
                      <property name="window_style">wxTAB_TRAVERSAL</property>
                    </object>
                  </object>
                  <object class="notebookpage" expanded="false">
                  <object class="notebookpage" expanded="true">
                    <property name="bitmap">Load From Embedded File; icons/16/cube.png</property>
                    <property name="label">Models</property>
                    <property name="select">0</property>
                    <object class="wxPanel" expanded="false">
                    <object class="wxPanel" expanded="true">
                      <property name="BottomDockable">1</property>
                      <property name="LeftDockable">1</property>
                      <property name="RightDockable">1</property>
@@ -2262,7 +2135,7 @@
                      <property name="window_extra_style"></property>
                      <property name="window_name"></property>
                      <property name="window_style">wxTAB_TRAVERSAL</property>
                      <object class="wxBoxSizer" expanded="false">
                      <object class="wxBoxSizer" expanded="true">
                        <property name="minimum_size"></property>
                        <property name="name">bSizer20</property>
                        <property name="orient">wxVERTICAL</property>
@@ -2293,6 +2166,7 @@
                            <property name="window_extra_style"></property>
                            <property name="window_name"></property>
                            <property name="window_style">wxFULL_REPAINT_ON_RESIZE</property>
                            <event name="OnDataViewListCtrlItemContextMenu">onContextMenu</event>
                          </object>
                        </object>
                      </object>
@@ -2359,11 +2233,11 @@
                  <property name="window_style"></property>
                </object>
              </object>
              <object class="sizeritem" expanded="false">
              <object class="sizeritem" expanded="true">
                <property name="border">5</property>
                <property name="flag">wxEXPAND</property>
                <property name="proportion">0</property>
                <object class="wxBoxSizer" expanded="false">
                <object class="wxBoxSizer" expanded="true">
                  <property name="minimum_size"></property>
                  <property name="name">bSizer9</property>
                  <property name="orient">wxHORIZONTAL</property>
@@ -2538,12 +2412,12 @@
                      <property name="gripper">0</property>
                      <property name="hidden">0</property>
                      <property name="id">wxID_ANY</property>
                      <property name="initial">0</property>
                      <property name="max">10</property>
                      <property name="initial">1</property>
                      <property name="max">1000</property>
                      <property name="max_size"></property>
                      <property name="maximize_button">0</property>
                      <property name="maximum_size"></property>
                      <property name="min">0</property>
                      <property name="min">1</property>
                      <property name="min_size"></property>
                      <property name="minimize_button">0</property>
                      <property name="minimum_size"></property>
@@ -2566,6 +2440,134 @@
                      <property name="window_extra_style"></property>
                      <property name="window_name"></property>
                      <property name="window_style"></property>
                    </object>
                  </object>
                  <object class="sizeritem" expanded="false">
                    <property name="border">5</property>
                    <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
                    <property name="proportion">0</property>
                    <object class="wxStaticText" expanded="false">
                      <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="drag_accept_files">0</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"></property>
                      <property name="id">wxID_ANY</property>
                      <property name="label">Sampler</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">m_staticText163</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">sampling method (default: &quot;euler_a&quot;)</property>
                      <property name="window_extra_style"></property>
                      <property name="window_name"></property>
                      <property name="window_style"></property>
                      <property name="wrap">0</property>
                    </object>
                  </object>
                  <object class="sizeritem" expanded="false">
                    <property name="border">5</property>
                    <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
                    <property name="proportion">0</property>
                    <object class="wxChoice" expanded="false">
                      <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="choices"></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="drag_accept_files">0</property>
                      <property name="enabled"></property>
                      <property name="fg"></property>
                      <property name="floatable">1</property>
                      <property name="font"></property>
                      <property name="gripper">0</property>
                      <property name="hidden"></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">100,-1</property>
                      <property name="moveable">1</property>
                      <property name="name">m_sampler</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="selection">0</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">sampling method (default: &quot;euler_a&quot;)</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="OnChoice">onSamplerSelect</event>
                    </object>
                  </object>
                  <object class="sizeritem" expanded="false">
@@ -3233,14 +3235,11 @@
                    <property name="border">5</property>
                    <property name="flag">wxEXPAND</property>
                    <property name="proportion">0</property>
                    <object class="wxGridSizer" expanded="true">
                      <property name="cols">2</property>
                      <property name="hgap">0</property>
                    <object class="wxBoxSizer" expanded="true">
                      <property name="minimum_size"></property>
                      <property name="name">sizer2012</property>
                      <property name="name">bSizer16</property>
                      <property name="orient">wxHORIZONTAL</property>
                      <property name="permission">none</property>
                      <property name="rows">0</property>
                      <property name="vgap">0</property>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
@@ -3281,7 +3280,7 @@
                          <property name="maximum_size"></property>
                          <property name="min_size"></property>
                          <property name="minimize_button">0</property>
                          <property name="minimum_size"></property>
                          <property name="minimum_size">150,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_staticText172410</property>
                          <property name="pane_border">1</property>
@@ -3306,7 +3305,7 @@
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL</property>
                        <property name="proportion">0</property>
                        <property name="proportion">1</property>
                        <object class="wxDirPickerCtrl" expanded="false">
                          <property name="BottomDockable">1</property>
                          <property name="LeftDockable">1</property>
@@ -3374,296 +3373,11 @@
                    <property name="border">5</property>
                    <property name="flag">wxEXPAND</property>
                    <property name="proportion">0</property>
                    <object class="wxGridSizer" expanded="true">
                      <property name="cols">2</property>
                      <property name="hgap">0</property>
                    <object class="wxBoxSizer" expanded="true">
                      <property name="minimum_size"></property>
                      <property name="name">sizer2013</property>
                      <property name="name">bSizer19</property>
                      <property name="orient">wxHORIZONTAL</property>
                      <property name="permission">none</property>
                      <property name="rows">0</property>
                      <property name="vgap">0</property>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
                        <property name="proportion">0</property>
                        <object class="wxStaticText" expanded="false">
                          <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="drag_accept_files">0</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"></property>
                          <property name="id">wxID_ANY</property>
                          <property name="label">Vae path</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">m_staticText18013</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="window_extra_style"></property>
                          <property name="window_name"></property>
                          <property name="window_style"></property>
                          <property name="wrap">0</property>
                        </object>
                      </object>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND</property>
                        <property name="proportion">0</property>
                        <object class="wxDirPickerCtrl" expanded="false">
                          <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="drag_accept_files">0</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"></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="message">Select a folder</property>
                          <property name="min_size"></property>
                          <property name="minimize_button">0</property>
                          <property name="minimum_size">200,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_vae_dir</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">wxDIRP_SMALL|wxDIRP_DEFAULT_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="value"></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="true">
                    <property name="border">5</property>
                    <property name="flag">wxEXPAND</property>
                    <property name="proportion">0</property>
                    <object class="wxGridSizer" expanded="true">
                      <property name="cols">2</property>
                      <property name="hgap">0</property>
                      <property name="minimum_size"></property>
                      <property name="name">sizer2014</property>
                      <property name="permission">none</property>
                      <property name="rows">0</property>
                      <property name="vgap">0</property>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
                        <property name="proportion">0</property>
                        <object class="wxStaticText" expanded="false">
                          <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="drag_accept_files">0</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"></property>
                          <property name="id">wxID_ANY</property>
                          <property name="label">Embedding path</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">m_staticText1801317202731</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="window_extra_style"></property>
                          <property name="window_name"></property>
                          <property name="window_style"></property>
                          <property name="wrap">0</property>
                        </object>
                      </object>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND</property>
                        <property name="proportion">0</property>
                        <object class="wxDirPickerCtrl" expanded="false">
                          <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="drag_accept_files">0</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"></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="message">Select a folder</property>
                          <property name="min_size"></property>
                          <property name="minimize_button">0</property>
                          <property name="minimum_size">200,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_embedding_dir</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">wxDIRP_SMALL|wxDIRP_DEFAULT_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="value"></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="true">
                    <property name="border">5</property>
                    <property name="flag">wxEXPAND</property>
                    <property name="proportion">0</property>
                    <object class="wxGridSizer" expanded="true">
                      <property name="cols">2</property>
                      <property name="hgap">0</property>
                      <property name="minimum_size"></property>
                      <property name="name">sizer2015</property>
                      <property name="permission">none</property>
                      <property name="rows">0</property>
                      <property name="vgap">0</property>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
@@ -3704,7 +3418,7 @@
                          <property name="maximum_size"></property>
                          <property name="min_size"></property>
                          <property name="minimize_button">0</property>
                          <property name="minimum_size"></property>
                          <property name="minimum_size">150,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_staticText18013172027</property>
                          <property name="pane_border">1</property>
@@ -3729,7 +3443,7 @@
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND</property>
                        <property name="proportion">0</property>
                        <property name="proportion">1</property>
                        <object class="wxDirPickerCtrl" expanded="false">
                          <property name="BottomDockable">1</property>
                          <property name="LeftDockable">1</property>
@@ -3797,14 +3511,287 @@
                    <property name="border">5</property>
                    <property name="flag">wxEXPAND</property>
                    <property name="proportion">0</property>
                    <object class="wxGridSizer" expanded="true">
                      <property name="cols">2</property>
                      <property name="hgap">0</property>
                    <object class="wxBoxSizer" expanded="true">
                      <property name="minimum_size"></property>
                      <property name="name">gSizer8</property>
                      <property name="name">bSizer17</property>
                      <property name="orient">wxHORIZONTAL</property>
                      <property name="permission">none</property>
                      <property name="rows">0</property>
                      <property name="vgap">0</property>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
                        <property name="proportion">0</property>
                        <object class="wxStaticText" expanded="false">
                          <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="drag_accept_files">0</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"></property>
                          <property name="id">wxID_ANY</property>
                          <property name="label">Vae path</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">150,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_staticText18013</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="window_extra_style"></property>
                          <property name="window_name"></property>
                          <property name="window_style"></property>
                          <property name="wrap">0</property>
                        </object>
                      </object>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND</property>
                        <property name="proportion">1</property>
                        <object class="wxDirPickerCtrl" expanded="false">
                          <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="drag_accept_files">0</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"></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="message">Select a folder</property>
                          <property name="min_size"></property>
                          <property name="minimize_button">0</property>
                          <property name="minimum_size">200,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_vae_dir</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">wxDIRP_SMALL|wxDIRP_DEFAULT_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="value"></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="true">
                    <property name="border">5</property>
                    <property name="flag">wxEXPAND</property>
                    <property name="proportion">0</property>
                    <object class="wxBoxSizer" expanded="true">
                      <property name="minimum_size"></property>
                      <property name="name">bSizer18</property>
                      <property name="orient">wxHORIZONTAL</property>
                      <property name="permission">none</property>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
                        <property name="proportion">0</property>
                        <object class="wxStaticText" expanded="false">
                          <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="drag_accept_files">0</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"></property>
                          <property name="id">wxID_ANY</property>
                          <property name="label">Embedding path</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">150,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_staticText1801317202731</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="window_extra_style"></property>
                          <property name="window_name"></property>
                          <property name="window_style"></property>
                          <property name="wrap">0</property>
                        </object>
                      </object>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND</property>
                        <property name="proportion">1</property>
                        <object class="wxDirPickerCtrl" expanded="false">
                          <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="drag_accept_files">0</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"></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="message">Select a folder</property>
                          <property name="min_size"></property>
                          <property name="minimize_button">0</property>
                          <property name="minimum_size">200,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_embedding_dir</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">wxDIRP_SMALL|wxDIRP_DEFAULT_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="value"></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="true">
                    <property name="border">5</property>
                    <property name="flag">wxEXPAND</property>
                    <property name="proportion">0</property>
                    <object class="wxBoxSizer" expanded="true">
                      <property name="minimum_size"></property>
                      <property name="name">bSizer20</property>
                      <property name="orient">wxHORIZONTAL</property>
                      <property name="permission">none</property>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
@@ -3845,7 +3832,7 @@
                          <property name="maximum_size"></property>
                          <property name="min_size"></property>
                          <property name="minimize_button">0</property>
                          <property name="minimum_size"></property>
                          <property name="minimum_size">150,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_staticText19</property>
                          <property name="pane_border">1</property>
@@ -3870,7 +3857,7 @@
                      <object class="sizeritem" expanded="true">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL</property>
                        <property name="proportion">0</property>
                        <property name="proportion">1</property>
                        <object class="wxDirPickerCtrl" expanded="true">
                          <property name="BottomDockable">1</property>
                          <property name="LeftDockable">1</property>
@@ -3997,14 +3984,11 @@
                    <property name="border">5</property>
                    <property name="flag">wxEXPAND</property>
                    <property name="proportion">0</property>
                    <object class="wxGridSizer" expanded="true">
                      <property name="cols">2</property>
                      <property name="hgap">0</property>
                    <object class="wxBoxSizer" expanded="true">
                      <property name="minimum_size"></property>
                      <property name="name">sizer2016</property>
                      <property name="name">bSizer21</property>
                      <property name="orient">wxHORIZONTAL</property>
                      <property name="permission">none</property>
                      <property name="rows">0</property>
                      <property name="vgap">0</property>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
@@ -4045,7 +4029,7 @@
                          <property name="maximum_size"></property>
                          <property name="min_size"></property>
                          <property name="minimize_button">0</property>
                          <property name="minimum_size"></property>
                          <property name="minimum_size">150,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_staticText180131720</property>
                          <property name="pane_border">1</property>
@@ -4070,7 +4054,7 @@
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND</property>
                        <property name="proportion">0</property>
                        <property name="proportion">1</property>
                        <object class="wxDirPickerCtrl" expanded="false">
                          <property name="BottomDockable">1</property>
                          <property name="LeftDockable">1</property>
@@ -4137,11 +4121,11 @@
                </object>
              </object>
            </object>
            <object class="notebookpage" expanded="false">
            <object class="notebookpage" expanded="true">
              <property name="bitmap">Load From Embedded File; icons/16/palette.png</property>
              <property name="label">Diffusion</property>
              <property name="select">0</property>
              <object class="wxPanel" expanded="false">
              <object class="wxPanel" expanded="true">
                <property name="BottomDockable">1</property>
                <property name="LeftDockable">1</property>
                <property name="RightDockable">1</property>
@@ -4193,16 +4177,16 @@
                <property name="window_extra_style"></property>
                <property name="window_name"></property>
                <property name="window_style">wxTAB_TRAVERSAL</property>
                <object class="wxBoxSizer" expanded="false">
                <object class="wxBoxSizer" expanded="true">
                  <property name="minimum_size"></property>
                  <property name="name">sizer2017</property>
                  <property name="orient">wxVERTICAL</property>
                  <property name="permission">none</property>
                  <object class="sizeritem" expanded="false">
                  <object class="sizeritem" expanded="true">
                    <property name="border">5</property>
                    <property name="flag">wxALL|wxEXPAND</property>
                    <property name="proportion">0</property>
                    <object class="wxGridSizer" expanded="false">
                    <object class="wxGridSizer" expanded="true">
                      <property name="cols">2</property>
                      <property name="hgap">0</property>
                      <property name="minimum_size"></property>
@@ -4250,7 +4234,7 @@
                          <property name="maximum_size"></property>
                          <property name="min_size"></property>
                          <property name="minimize_button">0</property>
                          <property name="minimum_size"></property>
                          <property name="minimum_size">230,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_keep_model_in_memory</property>
                          <property name="pane_border">1</property>
@@ -4277,11 +4261,11 @@
                      </object>
                    </object>
                  </object>
                  <object class="sizeritem" expanded="false">
                  <object class="sizeritem" expanded="true">
                    <property name="border">5</property>
                    <property name="flag">wxALL|wxEXPAND</property>
                    <property name="proportion">0</property>
                    <object class="wxGridSizer" expanded="false">
                    <object class="wxGridSizer" expanded="true">
                      <property name="cols">2</property>
                      <property name="hgap">0</property>
                      <property name="minimum_size"></property>
@@ -4329,7 +4313,7 @@
                          <property name="maximum_size"></property>
                          <property name="min_size"></property>
                          <property name="minimize_button">0</property>
                          <property name="minimum_size"></property>
                          <property name="minimum_size">230,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_save_all_image</property>
                          <property name="pane_border">1</property>
@@ -4356,11 +4340,11 @@
                      </object>
                    </object>
                  </object>
                  <object class="sizeritem" expanded="false">
                  <object class="sizeritem" expanded="true">
                    <property name="border">5</property>
                    <property name="flag">wxEXPAND</property>
                    <property name="proportion">0</property>
                    <object class="wxBoxSizer" expanded="false">
                    <object class="wxBoxSizer" expanded="true">
                      <property name="minimum_size"></property>
                      <property name="name">bSizer10</property>
                      <property name="orient">wxHORIZONTAL</property>
@@ -4398,14 +4382,14 @@
                          <property name="gripper">0</property>
                          <property name="hidden">0</property>
                          <property name="id">wxID_ANY</property>
                          <property name="label">Output images type</property>
                          <property name="label">Output images format</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="minimum_size">230,-1</property>
                          <property name="moveable">1</property>
                          <property name="name">m_staticText16</property>
                          <property name="pane_border">1</property>
@@ -4429,7 +4413,7 @@
                      </object>
                      <object class="sizeritem" expanded="false">
                        <property name="border">5</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
                        <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND</property>
                        <property name="proportion">0</property>
                        <object class="wxChoice" expanded="false">
                          <property name="BottomDockable">1</property>
vcpkg.json
@@ -4,6 +4,7 @@
    "wxwidgets",
    "cuda",
    "nlohmann-json",
    "opencv4"
    "opencv4",
    "restclient-cpp"
  ]
}