Compare commits
	
		
			22 Commits
		
	
	
		
			dev-dadc72
			...
			toxcore_us
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c3a7d1521a | |||
| fc994ab758 | |||
| 605a730b59 | |||
| 3e15798afc | |||
| cf697622cb | |||
| 05b0a2f514 | |||
| c887fdac8a | |||
| 4b0d9595ac | |||
| 5ac318d1bf | |||
| eaa8f1dd16 | |||
| b88fffd959 | |||
| 858b9dfcfa | |||
| bc8b631b84 | |||
| 52278f6726 | |||
| 29fd1bfb62 | |||
| 998000aa3a | |||
| e66f4651d0 | |||
| 854d09f05c | |||
| 2d6a9acbb6 | |||
| b7f0ad6c9a | |||
| 43f8c22570 | |||
| 3c7bd2e2cb | 
							
								
								
									
										24
									
								
								.github/workflows/cd.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								.github/workflows/cd.yml
									
									
									
									
										vendored
									
									
								
							@@ -7,7 +7,7 @@ on:
 | 
			
		||||
    branches: [ master ]
 | 
			
		||||
 | 
			
		||||
env:
 | 
			
		||||
  BUILD_TYPE: Release
 | 
			
		||||
  BUILD_TYPE: RelWithDebInfo
 | 
			
		||||
  BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
@@ -17,7 +17,7 @@ jobs:
 | 
			
		||||
    runs-on: ubuntu-20.04
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
      with:
 | 
			
		||||
        submodules: recursive
 | 
			
		||||
 | 
			
		||||
@@ -63,20 +63,23 @@ jobs:
 | 
			
		||||
    runs-on: windows-2019
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
      with:
 | 
			
		||||
        submodules: recursive
 | 
			
		||||
 | 
			
		||||
    - name: Install Dependencies
 | 
			
		||||
      run: vcpkg install libsodium:x64-windows-static pthreads:x64-windows-static
 | 
			
		||||
      run: vcpkg install libsodium:x64-windows-static pthreads:x64-windows-static pkgconf:x64-windows
 | 
			
		||||
 | 
			
		||||
    # setup vs env
 | 
			
		||||
    - uses: ilammy/msvc-dev-cmd@v1
 | 
			
		||||
      with:
 | 
			
		||||
        arch: amd64
 | 
			
		||||
 | 
			
		||||
    ## sdl_image vendored needs nasm for dav1d
 | 
			
		||||
    #- uses: ilammy/setup-nasm@v1
 | 
			
		||||
 | 
			
		||||
    - name: Configure CMake
 | 
			
		||||
      run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static
 | 
			
		||||
      run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static -DSDL3IMAGE_VENDORED=ON -DSDL3IMAGE_DEPS_SHARED=ON -DSDL3IMAGE_JXL=OFF -DSDL3IMAGE_AVIF=OFF -DPKG_CONFIG_EXECUTABLE=C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe
 | 
			
		||||
 | 
			
		||||
    - name: Build
 | 
			
		||||
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
 | 
			
		||||
@@ -114,20 +117,23 @@ jobs:
 | 
			
		||||
    runs-on: windows-2019
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
      with:
 | 
			
		||||
        submodules: recursive
 | 
			
		||||
 | 
			
		||||
    - name: Install Dependencies
 | 
			
		||||
      run: vcpkg install libsodium:x64-windows-static pthreads:x64-windows-static
 | 
			
		||||
      run: vcpkg install libsodium:x64-windows-static pthreads:x64-windows-static pkgconf:x64-windows
 | 
			
		||||
 | 
			
		||||
    # setup vs env
 | 
			
		||||
    - uses: ilammy/msvc-dev-cmd@v1
 | 
			
		||||
      with:
 | 
			
		||||
        arch: amd64
 | 
			
		||||
 | 
			
		||||
    ## sdl_image vendored needs nasm for dav1d
 | 
			
		||||
    #- uses: ilammy/setup-nasm@v1
 | 
			
		||||
 | 
			
		||||
    - name: Configure CMake
 | 
			
		||||
      run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static -DTOMATO_ASAN=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded
 | 
			
		||||
      run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static -DTOMATO_ASAN=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DSDL3IMAGE_VENDORED=ON -DSDL3IMAGE_DEPS_SHARED=ON -DSDL3IMAGE_JXL=OFF -DSDL3IMAGE_AVIF=OFF -DPKG_CONFIG_EXECUTABLE=C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe
 | 
			
		||||
 | 
			
		||||
    - name: Build
 | 
			
		||||
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4
 | 
			
		||||
@@ -172,7 +178,7 @@ jobs:
 | 
			
		||||
      contents: write
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
      with:
 | 
			
		||||
        submodules: recursive
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -16,7 +16,7 @@ jobs:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
      with:
 | 
			
		||||
        submodules: recursive
 | 
			
		||||
 | 
			
		||||
@@ -35,7 +35,7 @@ jobs:
 | 
			
		||||
    runs-on: macos-latest
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
      with:
 | 
			
		||||
        submodules: recursive
 | 
			
		||||
 | 
			
		||||
@@ -49,25 +49,28 @@ jobs:
 | 
			
		||||
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4
 | 
			
		||||
 | 
			
		||||
  windows:
 | 
			
		||||
    timeout-minutes: 10
 | 
			
		||||
    timeout-minutes: 15
 | 
			
		||||
 | 
			
		||||
    runs-on: windows-latest
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
      with:
 | 
			
		||||
        submodules: recursive
 | 
			
		||||
 | 
			
		||||
    - name: Install Dependencies
 | 
			
		||||
      run: vcpkg install libsodium:x64-windows-static pthreads:x64-windows-static
 | 
			
		||||
      run: vcpkg install libsodium:x64-windows-static pthreads:x64-windows-static pkgconf:x64-windows
 | 
			
		||||
 | 
			
		||||
    # setup vs env
 | 
			
		||||
    - uses: ilammy/msvc-dev-cmd@v1
 | 
			
		||||
      with:
 | 
			
		||||
        arch: amd64
 | 
			
		||||
 | 
			
		||||
    ## sdl_image vendored needs nasm for dav1d
 | 
			
		||||
    #- uses: ilammy/setup-nasm@v1
 | 
			
		||||
 | 
			
		||||
    - name: Configure CMake
 | 
			
		||||
      run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static
 | 
			
		||||
      run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static -DSDL3IMAGE_VENDORED=ON -DSDL3IMAGE_DEPS_SHARED=ON -DSDL3IMAGE_JXL=OFF -DSDL3IMAGE_AVIF=OFF -DPKG_CONFIG_EXECUTABLE=C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe
 | 
			
		||||
 | 
			
		||||
    - name: Build
 | 
			
		||||
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								external/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								external/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							@@ -21,4 +21,5 @@ add_subdirectory(./imgui)
 | 
			
		||||
add_subdirectory(./stb)
 | 
			
		||||
add_subdirectory(./libwebp)
 | 
			
		||||
add_subdirectory(./qoi)
 | 
			
		||||
add_subdirectory(./sdl_image)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								external/sdl_image/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								external/sdl_image/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
cmake_minimum_required(VERSION 3.16...3.24 FATAL_ERROR)
 | 
			
		||||
 | 
			
		||||
include(FetchContent)
 | 
			
		||||
 | 
			
		||||
if (NOT TARGET SDL3_image::SDL3_image)
 | 
			
		||||
	set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
 | 
			
		||||
	# TODO: make pr to make this an option
 | 
			
		||||
	set(SDL3IMAGE_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
 | 
			
		||||
	set(SDL3IMAGE_BACKEND_STB OFF CACHE BOOL "" FORCE) # important for security
 | 
			
		||||
	set(SDL3IMAGE_BACKEND_IMAGEIO OFF CACHE BOOL "" FORCE) # some funky apple cmake bug
 | 
			
		||||
	#set(SDL3IMAGE_JXL ON CACHE BOOL "" FORCE) # default to off
 | 
			
		||||
	set(SDL3IMAGE_QOI OFF CACHE BOOL "" FORCE) # we have our own
 | 
			
		||||
	set(SDL3IMAGE_WEBP OFF CACHE BOOL "" FORCE) # we have our own
 | 
			
		||||
 | 
			
		||||
	FetchContent_Declare(SDL3_image
 | 
			
		||||
		GIT_REPOSITORY https://github.com/libsdl-org/SDL_image
 | 
			
		||||
		# waiting on the imgui pr to get merged so i can update sdl <.<
 | 
			
		||||
		GIT_TAG a45d6e5b84ccc0f3faae6ba7d561709ed600eee7 # tip last check
 | 
			
		||||
		FIND_PACKAGE_ARGS # for the future
 | 
			
		||||
	)
 | 
			
		||||
	FetchContent_MakeAvailable(SDL3_image)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								external/solanaceae_contact
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								external/solanaceae_contact
									
									
									
									
										vendored
									
									
								
							 Submodule external/solanaceae_contact updated: e40271670b...e8b069c803
									
								
							
							
								
								
									
										2
									
								
								external/solanaceae_message3
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								external/solanaceae_message3
									
									
									
									
										vendored
									
									
								
							 Submodule external/solanaceae_message3 updated: f9f70a05b1...96b76dc67f
									
								
							
							
								
								
									
										2
									
								
								external/solanaceae_message_serializer
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								external/solanaceae_message_serializer
									
									
									
									
										vendored
									
									
								
							 Submodule external/solanaceae_message_serializer updated: 1409485ef1...e574c4f779
									
								
							
							
								
								
									
										2
									
								
								external/solanaceae_tox
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								external/solanaceae_tox
									
									
									
									
										vendored
									
									
								
							 Submodule external/solanaceae_tox updated: 25857b8aa7...2807239dea
									
								
							
							
								
								
									
										250
									
								
								external/toxcore/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										250
									
								
								external/toxcore/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							@@ -1,214 +1,62 @@
 | 
			
		||||
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
 | 
			
		||||
cmake_minimum_required(VERSION 3.9...3.16 FATAL_ERROR)
 | 
			
		||||
 | 
			
		||||
set(EXPERIMENTAL_API ON CACHE BOOL "" FORCE)
 | 
			
		||||
set(UNITTEST OFF CACHE BOOL "" FORCE)
 | 
			
		||||
set(BOOTSTRAP_DAEMON OFF CACHE BOOL "" FORCE)
 | 
			
		||||
 | 
			
		||||
add_subdirectory(./c-toxcore)
 | 
			
		||||
 | 
			
		||||
# the ideal case
 | 
			
		||||
#add_library(toxcore ALIAS toxcore_static)
 | 
			
		||||
 | 
			
		||||
# the sad case
 | 
			
		||||
add_library(toxcore INTERFACE)
 | 
			
		||||
 | 
			
		||||
target_link_libraries(toxcore INTERFACE toxcore_static)
 | 
			
		||||
 | 
			
		||||
# HACK: "install" api headers into binary dir
 | 
			
		||||
configure_file(
 | 
			
		||||
	./c-toxcore/toxcore/tox.h
 | 
			
		||||
	${CMAKE_CURRENT_BINARY_DIR}/include/tox/tox.h
 | 
			
		||||
	@ONLY
 | 
			
		||||
)
 | 
			
		||||
configure_file(
 | 
			
		||||
	./c-toxcore/toxcore/tox_events.h
 | 
			
		||||
	${CMAKE_CURRENT_BINARY_DIR}/include/tox/tox_events.h
 | 
			
		||||
	@ONLY
 | 
			
		||||
)
 | 
			
		||||
configure_file(
 | 
			
		||||
	./c-toxcore/toxcore/tox_private.h
 | 
			
		||||
	${CMAKE_CURRENT_BINARY_DIR}/include/tox/tox_private.h
 | 
			
		||||
	@ONLY
 | 
			
		||||
)
 | 
			
		||||
configure_file(
 | 
			
		||||
	./c-toxcore/toxencryptsave/toxencryptsave.h
 | 
			
		||||
	${CMAKE_CURRENT_BINARY_DIR}/include/tox/toxencryptsave.h
 | 
			
		||||
	@ONLY
 | 
			
		||||
)
 | 
			
		||||
configure_file(
 | 
			
		||||
	./c-toxcore/toxav/toxav.h
 | 
			
		||||
	${CMAKE_CURRENT_BINARY_DIR}/include/tox/toxav.h
 | 
			
		||||
	@ONLY
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
target_include_directories(toxcore INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/include/)
 | 
			
		||||
 | 
			
		||||
# HACK: support old libsodium find
 | 
			
		||||
# libs should handle this case themselfs
 | 
			
		||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
 | 
			
		||||
 | 
			
		||||
set(TOX_DIR "${CMAKE_CURRENT_SOURCE_DIR}/c-toxcore/")
 | 
			
		||||
 | 
			
		||||
# TODO: shared
 | 
			
		||||
add_library(toxcore STATIC
 | 
			
		||||
	${TOX_DIR}third_party/cmp/cmp.c
 | 
			
		||||
	${TOX_DIR}third_party/cmp/cmp.h
 | 
			
		||||
 | 
			
		||||
	${TOX_DIR}toxcore/announce.c
 | 
			
		||||
	${TOX_DIR}toxcore/announce.h
 | 
			
		||||
	${TOX_DIR}toxcore/bin_pack.c
 | 
			
		||||
	${TOX_DIR}toxcore/bin_pack.h
 | 
			
		||||
	${TOX_DIR}toxcore/bin_unpack.c
 | 
			
		||||
	${TOX_DIR}toxcore/bin_unpack.h
 | 
			
		||||
	${TOX_DIR}toxcore/ccompat.c
 | 
			
		||||
	${TOX_DIR}toxcore/ccompat.h
 | 
			
		||||
	${TOX_DIR}toxcore/crypto_core.c
 | 
			
		||||
	${TOX_DIR}toxcore/crypto_core.h
 | 
			
		||||
	${TOX_DIR}toxcore/crypto_core_pack.c
 | 
			
		||||
	${TOX_DIR}toxcore/crypto_core_pack.h
 | 
			
		||||
	${TOX_DIR}toxcore/DHT.c
 | 
			
		||||
	${TOX_DIR}toxcore/DHT.h
 | 
			
		||||
	${TOX_DIR}toxcore/events/conference_connected.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/conference_invite.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/conference_message.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/conference_peer_list_changed.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/conference_peer_name.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/conference_title.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/dht_get_nodes_response.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/events_alloc.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/events_alloc.h
 | 
			
		||||
	${TOX_DIR}toxcore/events/file_chunk_request.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/file_recv.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/file_recv_chunk.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/file_recv_control.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/friend_connection_status.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/friend_lossless_packet.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/friend_lossy_packet.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/friend_message.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/friend_name.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/friend_read_receipt.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/friend_request.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/friend_status.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/friend_status_message.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/friend_typing.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/self_connection_status.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_custom_packet.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_custom_private_packet.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_invite.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_join_fail.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_message.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_moderation.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_password.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_peer_exit.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_peer_join.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_peer_limit.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_peer_name.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_peer_status.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_privacy_state.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_private_message.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_self_join.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_topic.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_topic_lock.c
 | 
			
		||||
	${TOX_DIR}toxcore/events/group_voice_state.c
 | 
			
		||||
	${TOX_DIR}toxcore/forwarding.c
 | 
			
		||||
	${TOX_DIR}toxcore/forwarding.h
 | 
			
		||||
	${TOX_DIR}toxcore/friend_connection.c
 | 
			
		||||
	${TOX_DIR}toxcore/friend_connection.h
 | 
			
		||||
	${TOX_DIR}toxcore/friend_requests.c
 | 
			
		||||
	${TOX_DIR}toxcore/friend_requests.h
 | 
			
		||||
	${TOX_DIR}toxcore/group.c
 | 
			
		||||
	${TOX_DIR}toxcore/group.h
 | 
			
		||||
	${TOX_DIR}toxcore/group_announce.c
 | 
			
		||||
	${TOX_DIR}toxcore/group_announce.h
 | 
			
		||||
	${TOX_DIR}toxcore/group_moderation.c
 | 
			
		||||
	${TOX_DIR}toxcore/group_moderation.h
 | 
			
		||||
	${TOX_DIR}toxcore/group_chats.c
 | 
			
		||||
	${TOX_DIR}toxcore/group_chats.h
 | 
			
		||||
	${TOX_DIR}toxcore/group_common.h
 | 
			
		||||
	${TOX_DIR}toxcore/group_connection.c
 | 
			
		||||
	${TOX_DIR}toxcore/group_connection.h
 | 
			
		||||
	${TOX_DIR}toxcore/group_onion_announce.c
 | 
			
		||||
	${TOX_DIR}toxcore/group_onion_announce.h
 | 
			
		||||
	${TOX_DIR}toxcore/group_pack.c
 | 
			
		||||
	${TOX_DIR}toxcore/group_pack.h
 | 
			
		||||
	${TOX_DIR}toxcore/LAN_discovery.c
 | 
			
		||||
	${TOX_DIR}toxcore/LAN_discovery.h
 | 
			
		||||
	${TOX_DIR}toxcore/list.c
 | 
			
		||||
	${TOX_DIR}toxcore/list.h
 | 
			
		||||
	${TOX_DIR}toxcore/logger.c
 | 
			
		||||
	${TOX_DIR}toxcore/logger.h
 | 
			
		||||
	${TOX_DIR}toxcore/Messenger.c
 | 
			
		||||
	${TOX_DIR}toxcore/Messenger.h
 | 
			
		||||
	${TOX_DIR}toxcore/mem.c
 | 
			
		||||
	${TOX_DIR}toxcore/mem.h
 | 
			
		||||
	${TOX_DIR}toxcore/mono_time.c
 | 
			
		||||
	${TOX_DIR}toxcore/mono_time.h
 | 
			
		||||
	${TOX_DIR}toxcore/net_crypto.c
 | 
			
		||||
	${TOX_DIR}toxcore/net_crypto.h
 | 
			
		||||
	${TOX_DIR}toxcore/network.c
 | 
			
		||||
	${TOX_DIR}toxcore/network.h
 | 
			
		||||
	${TOX_DIR}toxcore/onion_announce.c
 | 
			
		||||
	${TOX_DIR}toxcore/onion_announce.h
 | 
			
		||||
	${TOX_DIR}toxcore/onion.c
 | 
			
		||||
	${TOX_DIR}toxcore/onion_client.c
 | 
			
		||||
	${TOX_DIR}toxcore/onion_client.h
 | 
			
		||||
	${TOX_DIR}toxcore/onion.h
 | 
			
		||||
	${TOX_DIR}toxcore/ping_array.c
 | 
			
		||||
	${TOX_DIR}toxcore/ping_array.h
 | 
			
		||||
	${TOX_DIR}toxcore/ping.c
 | 
			
		||||
	${TOX_DIR}toxcore/ping.h
 | 
			
		||||
	${TOX_DIR}toxcore/shared_key_cache.c
 | 
			
		||||
	${TOX_DIR}toxcore/shared_key_cache.h
 | 
			
		||||
	${TOX_DIR}toxcore/state.c
 | 
			
		||||
	${TOX_DIR}toxcore/state.h
 | 
			
		||||
	${TOX_DIR}toxcore/TCP_client.c
 | 
			
		||||
	${TOX_DIR}toxcore/TCP_client.h
 | 
			
		||||
	${TOX_DIR}toxcore/TCP_common.c
 | 
			
		||||
	${TOX_DIR}toxcore/TCP_common.h
 | 
			
		||||
	${TOX_DIR}toxcore/TCP_connection.c
 | 
			
		||||
	${TOX_DIR}toxcore/TCP_connection.h
 | 
			
		||||
	${TOX_DIR}toxcore/TCP_server.c
 | 
			
		||||
	${TOX_DIR}toxcore/TCP_server.h
 | 
			
		||||
	${TOX_DIR}toxcore/timed_auth.c
 | 
			
		||||
	${TOX_DIR}toxcore/timed_auth.h
 | 
			
		||||
	${TOX_DIR}toxcore/tox_api.c
 | 
			
		||||
	${TOX_DIR}toxcore/tox.c
 | 
			
		||||
	${TOX_DIR}toxcore/tox_dispatch.c
 | 
			
		||||
	${TOX_DIR}toxcore/tox_dispatch.h
 | 
			
		||||
	${TOX_DIR}toxcore/tox_event.c
 | 
			
		||||
	${TOX_DIR}toxcore/tox_event.h
 | 
			
		||||
	${TOX_DIR}toxcore/tox_events.c
 | 
			
		||||
	${TOX_DIR}toxcore/tox_events.h
 | 
			
		||||
	${TOX_DIR}toxcore/tox.h
 | 
			
		||||
	${TOX_DIR}toxcore/tox_private.c
 | 
			
		||||
	${TOX_DIR}toxcore/tox_private.h
 | 
			
		||||
	${TOX_DIR}toxcore/tox_pack.h
 | 
			
		||||
	${TOX_DIR}toxcore/tox_pack.c
 | 
			
		||||
	${TOX_DIR}toxcore/tox_unpack.c
 | 
			
		||||
	${TOX_DIR}toxcore/tox_unpack.h
 | 
			
		||||
	${TOX_DIR}toxcore/util.c
 | 
			
		||||
	${TOX_DIR}toxcore/util.h
 | 
			
		||||
 | 
			
		||||
	${TOX_DIR}toxencryptsave/defines.h
 | 
			
		||||
	${TOX_DIR}toxencryptsave/toxencryptsave.c
 | 
			
		||||
	${TOX_DIR}toxencryptsave/toxencryptsave.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# HACK: "install" api headers into self
 | 
			
		||||
# this is dirty, should be binary dir
 | 
			
		||||
# TODO: add the others
 | 
			
		||||
configure_file(
 | 
			
		||||
	${TOX_DIR}toxcore/tox.h
 | 
			
		||||
	${TOX_DIR}tox/tox.h
 | 
			
		||||
	@ONLY
 | 
			
		||||
)
 | 
			
		||||
configure_file(
 | 
			
		||||
	${TOX_DIR}toxcore/tox_events.h
 | 
			
		||||
	${TOX_DIR}tox/tox_events.h
 | 
			
		||||
	@ONLY
 | 
			
		||||
)
 | 
			
		||||
configure_file(
 | 
			
		||||
	${TOX_DIR}toxcore/tox_private.h
 | 
			
		||||
	${TOX_DIR}tox/tox_private.h
 | 
			
		||||
	@ONLY
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
target_include_directories(toxcore PRIVATE "${TOX_DIR}toxcore")
 | 
			
		||||
target_include_directories(toxcore PUBLIC "${TOX_DIR}")
 | 
			
		||||
 | 
			
		||||
target_compile_definitions(toxcore PUBLIC USE_IPV6=1)
 | 
			
		||||
#target_compile_definitions(toxcore PUBLIC MIN_LOGGER_LEVEL=LOGGER_LEVEL_DEBUG)
 | 
			
		||||
target_compile_definitions(toxcore PUBLIC MIN_LOGGER_LEVEL=LOGGER_LEVEL_INFO)
 | 
			
		||||
 | 
			
		||||
find_package(unofficial-sodium CONFIG QUIET)
 | 
			
		||||
find_package(sodium QUIET)
 | 
			
		||||
if(unofficial-sodium_FOUND) # vcpkg
 | 
			
		||||
	if(TARGET unofficial-sodium::sodium)
 | 
			
		||||
		target_link_libraries(toxcore unofficial-sodium::sodium)
 | 
			
		||||
		target_link_libraries(toxcore INTERFACE unofficial-sodium::sodium)
 | 
			
		||||
	endif()
 | 
			
		||||
	if(TARGET unofficial-sodium::sodium_config_public)
 | 
			
		||||
		target_link_libraries(toxcore unofficial-sodium::sodium_config_public)
 | 
			
		||||
		target_link_libraries(toxcore INTERFACE unofficial-sodium::sodium_config_public)
 | 
			
		||||
	endif()
 | 
			
		||||
elseif(sodium_FOUND)
 | 
			
		||||
	target_link_libraries(toxcore sodium)
 | 
			
		||||
	target_link_libraries(toxcore INTERFACE sodium)
 | 
			
		||||
else()
 | 
			
		||||
	message(SEND_ERROR "missing libsodium")
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(WIN32)
 | 
			
		||||
	target_link_libraries(toxcore ws2_32 iphlpapi)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
find_package(pthreads QUIET)
 | 
			
		||||
if(TARGET PThreads4W::PThreads4W)
 | 
			
		||||
	target_link_libraries(toxcore PThreads4W::PThreads4W)
 | 
			
		||||
else()
 | 
			
		||||
	set(THREADS_PREFER_PTHREAD_FLAG ON)
 | 
			
		||||
	find_package(Threads REQUIRED)
 | 
			
		||||
	target_link_libraries(toxcore Threads::Threads)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
add_executable(DHT_Bootstrap EXCLUDE_FROM_ALL
 | 
			
		||||
	${TOX_DIR}other/DHT_bootstrap.c
 | 
			
		||||
	${TOX_DIR}other/bootstrap_node_packets.h
 | 
			
		||||
	${TOX_DIR}other/bootstrap_node_packets.c
 | 
			
		||||
	${TOX_DIR}testing/misc_tools.h
 | 
			
		||||
	${TOX_DIR}testing/misc_tools.c
 | 
			
		||||
)
 | 
			
		||||
target_link_libraries(DHT_Bootstrap toxcore)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										32
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							@@ -5,11 +5,11 @@
 | 
			
		||||
        "systems": "systems"
 | 
			
		||||
      },
 | 
			
		||||
      "locked": {
 | 
			
		||||
        "lastModified": 1694529238,
 | 
			
		||||
        "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
 | 
			
		||||
        "lastModified": 1710146030,
 | 
			
		||||
        "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
 | 
			
		||||
        "owner": "numtide",
 | 
			
		||||
        "repo": "flake-utils",
 | 
			
		||||
        "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
 | 
			
		||||
        "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      },
 | 
			
		||||
      "original": {
 | 
			
		||||
@@ -20,11 +20,11 @@
 | 
			
		||||
    },
 | 
			
		||||
    "nixpkgs": {
 | 
			
		||||
      "locked": {
 | 
			
		||||
        "lastModified": 1709953752,
 | 
			
		||||
        "narHash": "sha256-LW84B4vM1cn7E6cDNQn2LndT9iJXI1dRE5fwbNFbQa8=",
 | 
			
		||||
        "lastModified": 1713189761,
 | 
			
		||||
        "narHash": "sha256-MPp1dBhlY066IeBo+EPGEUN+s+aSUA+LWkvnzKh+rts=",
 | 
			
		||||
        "owner": "NixOS",
 | 
			
		||||
        "repo": "nixpkgs",
 | 
			
		||||
        "rev": "fcaa81ed3c273237217330cf342ef1873b77c80a",
 | 
			
		||||
        "rev": "ff44be4d8ff33f797ff3e3f87153d4f3b6a85ffb",
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      },
 | 
			
		||||
      "original": {
 | 
			
		||||
@@ -56,7 +56,8 @@
 | 
			
		||||
        "flake-utils": "flake-utils",
 | 
			
		||||
        "nixpkgs": "nixpkgs",
 | 
			
		||||
        "nlohmann-json": "nlohmann-json",
 | 
			
		||||
        "sdl3": "sdl3"
 | 
			
		||||
        "sdl3": "sdl3",
 | 
			
		||||
        "sdl3_image": "sdl3_image"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "sdl3": {
 | 
			
		||||
@@ -76,6 +77,23 @@
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "sdl3_image": {
 | 
			
		||||
      "flake": false,
 | 
			
		||||
      "locked": {
 | 
			
		||||
        "lastModified": 1712700609,
 | 
			
		||||
        "narHash": "sha256-PVPH1uJ6g65SzHUboeQE6ZkC+72doMz9t9SG2LBo+7I=",
 | 
			
		||||
        "owner": "libsdl-org",
 | 
			
		||||
        "repo": "SDL_image",
 | 
			
		||||
        "rev": "a45d6e5b84ccc0f3faae6ba7d561709ed600eee7",
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      },
 | 
			
		||||
      "original": {
 | 
			
		||||
        "owner": "libsdl-org",
 | 
			
		||||
        "repo": "SDL_image",
 | 
			
		||||
        "rev": "a45d6e5b84ccc0f3faae6ba7d561709ed600eee7",
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "systems": {
 | 
			
		||||
      "locked": {
 | 
			
		||||
        "lastModified": 1681028828,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								flake.nix
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								flake.nix
									
									
									
									
									
								
							@@ -14,9 +14,13 @@
 | 
			
		||||
      url = "github:libsdl-org/SDL/0429f5d6a36fc35b551bcc2acd4a40c2db6dab82"; # keep in sync this cmake
 | 
			
		||||
      flake = false;
 | 
			
		||||
    };
 | 
			
		||||
    sdl3_image = {
 | 
			
		||||
      url = "github:libsdl-org/SDL_image/a45d6e5b84ccc0f3faae6ba7d561709ed600eee7";
 | 
			
		||||
      flake = false;
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  outputs = { self, nixpkgs, flake-utils, nlohmann-json, sdl3 }:
 | 
			
		||||
  outputs = { self, nixpkgs, flake-utils, nlohmann-json, sdl3, sdl3_image }:
 | 
			
		||||
    flake-utils.lib.eachDefaultSystem (system:
 | 
			
		||||
    let
 | 
			
		||||
      pkgs = import nixpkgs { inherit system; };
 | 
			
		||||
@@ -57,6 +61,13 @@
 | 
			
		||||
          libGL
 | 
			
		||||
 | 
			
		||||
          pipewire
 | 
			
		||||
 | 
			
		||||
          # sdl3_image:
 | 
			
		||||
          libpng
 | 
			
		||||
          libjpeg
 | 
			
		||||
          libjxl
 | 
			
		||||
          libavif
 | 
			
		||||
          #libwebp # still using our own loader
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        buildInputs = with pkgs; [
 | 
			
		||||
@@ -74,6 +85,8 @@
 | 
			
		||||
          "-DFETCHCONTENT_SOURCE_DIR_ZSTD=${pkgs.zstd.src}" # we dont care about the version (we use 1.4.x features)
 | 
			
		||||
          "-DFETCHCONTENT_SOURCE_DIR_LIBWEBP=${pkgs.libwebp.src}"
 | 
			
		||||
          "-DFETCHCONTENT_SOURCE_DIR_SDL3=${sdl3}"
 | 
			
		||||
          "-DFETCHCONTENT_SOURCE_DIR_SDL3_IMAGE=${sdl3_image}"
 | 
			
		||||
          "-DSDL3IMAGE_JXL=ON"
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        # TODO: replace with install command
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,8 @@ add_executable(tomato
 | 
			
		||||
	./image_loader_webp.cpp
 | 
			
		||||
	./image_loader_qoi.hpp
 | 
			
		||||
	./image_loader_qoi.cpp
 | 
			
		||||
	./image_loader_sdl_image.hpp
 | 
			
		||||
	./image_loader_sdl_image.cpp
 | 
			
		||||
 | 
			
		||||
	./texture_uploader.hpp
 | 
			
		||||
	./sdlrenderer_texture_uploader.hpp
 | 
			
		||||
@@ -50,14 +52,16 @@ add_executable(tomato
 | 
			
		||||
	./sdl_clipboard_utils.hpp
 | 
			
		||||
	./sdl_clipboard_utils.cpp
 | 
			
		||||
 | 
			
		||||
	./file_selector.hpp
 | 
			
		||||
	./file_selector.cpp
 | 
			
		||||
 | 
			
		||||
	./send_image_popup.hpp
 | 
			
		||||
	./send_image_popup.cpp
 | 
			
		||||
 | 
			
		||||
	./settings_window.hpp
 | 
			
		||||
	./settings_window.cpp
 | 
			
		||||
	./chat_gui/theme.hpp
 | 
			
		||||
	./chat_gui/theme.cpp
 | 
			
		||||
	./chat_gui/contact_list.hpp
 | 
			
		||||
	./chat_gui/contact_list.cpp
 | 
			
		||||
	./chat_gui/file_selector.hpp
 | 
			
		||||
	./chat_gui/file_selector.cpp
 | 
			
		||||
	./chat_gui/send_image_popup.hpp
 | 
			
		||||
	./chat_gui/send_image_popup.cpp
 | 
			
		||||
	./chat_gui/settings_window.hpp
 | 
			
		||||
	./chat_gui/settings_window.cpp
 | 
			
		||||
 | 
			
		||||
	./tox_ui_utils.hpp
 | 
			
		||||
	./tox_ui_utils.cpp
 | 
			
		||||
@@ -98,5 +102,6 @@ target_link_libraries(tomato PUBLIC
 | 
			
		||||
	webpdemux
 | 
			
		||||
	libwebpmux # the f why (needed for anim encode)
 | 
			
		||||
	qoi
 | 
			
		||||
	SDL3_image::SDL3_image
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										314
									
								
								src/chat_gui/contact_list.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								src/chat_gui/contact_list.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,314 @@
 | 
			
		||||
#include "./contact_list.hpp"
 | 
			
		||||
 | 
			
		||||
#include <solanaceae/contact/components.hpp>
 | 
			
		||||
 | 
			
		||||
#include <imgui/imgui.h>
 | 
			
		||||
//#include <imgui/imgui_internal.h>
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
static void drawIconDirectLines(
 | 
			
		||||
	const ImVec2 p0,
 | 
			
		||||
	const ImVec2 p1_o,
 | 
			
		||||
	const ImU32 col,
 | 
			
		||||
	const float thickness
 | 
			
		||||
) {
 | 
			
		||||
#define PLINE(x0, y0, x1, y1) \
 | 
			
		||||
		ImGui::GetWindowDrawList()->AddLine( \
 | 
			
		||||
			{p0.x + p1_o.x*(x0), p0.y + p1_o.y*(y0)}, \
 | 
			
		||||
			{p0.x + p1_o.x*(x1), p0.y + p1_o.y*(y1)}, \
 | 
			
		||||
			col, \
 | 
			
		||||
			thickness \
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		// arrow 1
 | 
			
		||||
		// (3,1) -> (9,7)
 | 
			
		||||
		PLINE(0.3f, 0.1f, 0.9f, 0.7f)
 | 
			
		||||
		// (9,7) -> (9,5)
 | 
			
		||||
		PLINE(0.9f, 0.7f, 0.9f, 0.5f)
 | 
			
		||||
		// (9,7) -> (7,7)
 | 
			
		||||
		PLINE(0.9f, 0.7f, 0.7f, 0.7f)
 | 
			
		||||
 | 
			
		||||
		// arrow 2
 | 
			
		||||
		// (7,9) -> (1,3)
 | 
			
		||||
		PLINE(0.7f, 0.9f, 0.1f, 0.3f)
 | 
			
		||||
		// (1,3) -> (3,3)
 | 
			
		||||
		PLINE(0.1f, 0.3f, 0.3f, 0.3f)
 | 
			
		||||
		// (1,3) -> (1,5)
 | 
			
		||||
		PLINE(0.1f, 0.3f, 0.1f, 0.5f)
 | 
			
		||||
#undef PLINE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void drawIconDirect(
 | 
			
		||||
	const ImVec2 p0,
 | 
			
		||||
	const ImVec2 p1_o,
 | 
			
		||||
	const ImU32 col_main,
 | 
			
		||||
	const ImU32 col_back
 | 
			
		||||
) {
 | 
			
		||||
	// dark background
 | 
			
		||||
	// the circle looks bad in light mode
 | 
			
		||||
	//ImGui::GetWindowDrawList()->AddCircleFilled({p0.x + p1_o.x*0.5f, p0.y + p1_o.y*0.5f}, p1_o.x*0.5f, col_back);
 | 
			
		||||
	drawIconDirectLines(p0, p1_o, col_back, 4.0f);
 | 
			
		||||
	drawIconDirectLines(p0, p1_o, col_main, 1.5f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void drawIconCloud(
 | 
			
		||||
	const ImVec2 p0,
 | 
			
		||||
	const ImVec2 p1_o,
 | 
			
		||||
	const ImU32 col_main,
 | 
			
		||||
	const ImU32 col_back
 | 
			
		||||
) {
 | 
			
		||||
	std::array<ImVec2, 19> points {{
 | 
			
		||||
		{0.2f, 0.9f},
 | 
			
		||||
		{0.8f, 0.9f},
 | 
			
		||||
		{0.9f, 0.8f},
 | 
			
		||||
		{0.9f, 0.7f},
 | 
			
		||||
		{0.7f, 0.7f},
 | 
			
		||||
		{0.9f, 0.5f},
 | 
			
		||||
		{0.9f, 0.4f},
 | 
			
		||||
		{0.8f, 0.2f},
 | 
			
		||||
		{0.6f, 0.2f},
 | 
			
		||||
		{0.5f, 0.3f},
 | 
			
		||||
		{0.5f, 0.5f},
 | 
			
		||||
		{0.4f, 0.4f},
 | 
			
		||||
		{0.3f, 0.4f},
 | 
			
		||||
		{0.2f, 0.5f},
 | 
			
		||||
		{0.2f, 0.6f},
 | 
			
		||||
		{0.3f, 0.7f},
 | 
			
		||||
		{0.1f, 0.7f},
 | 
			
		||||
		{0.1f, 0.8f},
 | 
			
		||||
		{0.2f, 0.9f},
 | 
			
		||||
	}};
 | 
			
		||||
	for (auto& v : points) {
 | 
			
		||||
		v.y -= 0.1f;
 | 
			
		||||
		v = {p0.x + p1_o.x*v.x, p0.y + p1_o.y*v.y};
 | 
			
		||||
	}
 | 
			
		||||
	// the circle looks bad in light mode
 | 
			
		||||
	//ImGui::GetWindowDrawList()->AddCircleFilled({p0.x + p1_o.x*0.5f, p0.y + p1_o.y*0.5f}, p1_o.x*0.5f, col_back);
 | 
			
		||||
	ImGui::GetWindowDrawList()->AddPolyline(points.data(), points.size(), col_back, ImDrawFlags_None, 4.f);
 | 
			
		||||
	ImGui::GetWindowDrawList()->AddPolyline(points.data(), points.size(), col_main, ImDrawFlags_None, 1.5f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void renderAvatar(
 | 
			
		||||
	const Theme& th,
 | 
			
		||||
	ContactTextureCache& contact_tc,
 | 
			
		||||
	const Contact3Handle c,
 | 
			
		||||
	ImVec2 box
 | 
			
		||||
) {
 | 
			
		||||
	// deploy dummy of same size and check visibility
 | 
			
		||||
	const auto orig_curser_pos = ImGui::GetCursorPos();
 | 
			
		||||
	ImGui::Dummy(box);
 | 
			
		||||
	if (ImGui::IsItemVisible()) {
 | 
			
		||||
		ImGui::SetCursorPos(orig_curser_pos); // reset for actual img
 | 
			
		||||
 | 
			
		||||
		ImVec4 color_current = th.getColor<ThemeCol_Contact::avatar_offline>();
 | 
			
		||||
		if (c.all_of<Contact::Components::ConnectionState>()) {
 | 
			
		||||
			const auto c_state = c.get<Contact::Components::ConnectionState>().state;
 | 
			
		||||
			if (c_state == Contact::Components::ConnectionState::State::direct) {
 | 
			
		||||
				color_current = th.getColor<ThemeCol_Contact::avatar_online_direct>();
 | 
			
		||||
			} else if (c_state == Contact::Components::ConnectionState::State::cloud) {
 | 
			
		||||
				color_current = th.getColor<ThemeCol_Contact::avatar_online_cloud>();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// avatar
 | 
			
		||||
		const auto [id, width, height] = contact_tc.get(c);
 | 
			
		||||
		ImGui::Image(
 | 
			
		||||
			id,
 | 
			
		||||
			box,
 | 
			
		||||
			{0, 0},
 | 
			
		||||
			{1, 1},
 | 
			
		||||
			{1, 1, 1, 1},
 | 
			
		||||
			color_current
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool renderContactBig(
 | 
			
		||||
	const Theme& th,
 | 
			
		||||
	ContactTextureCache& contact_tc,
 | 
			
		||||
	const Contact3Handle c,
 | 
			
		||||
	int line_height,
 | 
			
		||||
	const bool unread,
 | 
			
		||||
	const bool selectable,
 | 
			
		||||
	const bool selected
 | 
			
		||||
) {
 | 
			
		||||
	ImGui::BeginGroup();
 | 
			
		||||
	if (line_height < 1) {
 | 
			
		||||
		line_height = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// we dont need ### bc there is no named prefix
 | 
			
		||||
	auto label = "##" + std::to_string(entt::to_integral(c.entity()));
 | 
			
		||||
 | 
			
		||||
	const bool request_incoming = c.all_of<Contact::Components::RequestIncoming>();
 | 
			
		||||
	const bool request_outgoing = c.all_of<Contact::Components::TagRequestOutgoing>();
 | 
			
		||||
 | 
			
		||||
	ImVec2 orig_curser_pos = ImGui::GetCursorPos();
 | 
			
		||||
	// HACK: fake selected to make it draw a box for us
 | 
			
		||||
	const bool show_selected = request_incoming || request_outgoing || selected;
 | 
			
		||||
	if (request_incoming) {
 | 
			
		||||
		ImGui::PushStyleColor(
 | 
			
		||||
			ImGuiCol_Header,
 | 
			
		||||
			th.getColor<ThemeCol_Contact::request_incoming>()
 | 
			
		||||
		);
 | 
			
		||||
	} else if (request_outgoing) {
 | 
			
		||||
		ImGui::PushStyleColor(
 | 
			
		||||
			ImGuiCol_Header,
 | 
			
		||||
			th.getColor<ThemeCol_Contact::request_outgoing>()
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
 | 
			
		||||
 | 
			
		||||
	bool got_selected = false;
 | 
			
		||||
	if (selectable) {
 | 
			
		||||
		got_selected = ImGui::Selectable(label.c_str(), show_selected, ImGuiSelectableFlags_None, {0, line_height*TEXT_BASE_HEIGHT});
 | 
			
		||||
	} else {
 | 
			
		||||
		got_selected = ImGui::InvisibleButton(label.c_str(), {-FLT_MIN, line_height*TEXT_BASE_HEIGHT});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (request_incoming || request_outgoing) {
 | 
			
		||||
		ImGui::PopStyleColor();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const auto* cstate = c.try_get<Contact::Components::ConnectionState>();
 | 
			
		||||
	if (ImGui::BeginItemTooltip()) {
 | 
			
		||||
		if (cstate != nullptr) {
 | 
			
		||||
			ImGui::Text("Connection state: %s",
 | 
			
		||||
				(cstate->state == Contact::Components::ConnectionState::disconnected)
 | 
			
		||||
				? "offline"
 | 
			
		||||
				: (cstate->state == Contact::Components::ConnectionState::direct)
 | 
			
		||||
				? "online (direct)"
 | 
			
		||||
				: "online (cloud)"
 | 
			
		||||
			);
 | 
			
		||||
		} else {
 | 
			
		||||
			ImGui::TextUnformatted("Connection state: unknown");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (
 | 
			
		||||
			const auto* slt = c.try_get<Contact::Components::StatusText>();
 | 
			
		||||
			slt != nullptr &&
 | 
			
		||||
			!slt->text.empty()
 | 
			
		||||
		) {
 | 
			
		||||
			ImGui::SeparatorText("Status Text");
 | 
			
		||||
			//ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
 | 
			
		||||
			ImGui::TextUnformatted(slt->text.c_str());
 | 
			
		||||
			//ImGui::PopStyleColor();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO: add a whole bunch more info
 | 
			
		||||
		ImGui::EndTooltip();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ImVec2 post_curser_pos = ImGui::GetCursorPos();
 | 
			
		||||
 | 
			
		||||
	ImVec2 img_curser {
 | 
			
		||||
		orig_curser_pos.x + ImGui::GetStyle().FramePadding.x,
 | 
			
		||||
		orig_curser_pos.y + ImGui::GetStyle().FramePadding.y
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	float img_y {TEXT_BASE_HEIGHT*line_height - ImGui::GetStyle().FramePadding.y*2};
 | 
			
		||||
 | 
			
		||||
	ImGui::SetCursorPos(img_curser);
 | 
			
		||||
 | 
			
		||||
	renderAvatar(th, contact_tc, c, {img_y, img_y});
 | 
			
		||||
 | 
			
		||||
	const float same_line_spacing = ImGui::GetStyle().ItemSpacing.x*0.5f;
 | 
			
		||||
	ImGui::SameLine(0.f, same_line_spacing);
 | 
			
		||||
	ImGui::BeginGroup();
 | 
			
		||||
	{
 | 
			
		||||
		{ // line 1
 | 
			
		||||
			if (line_height == 1 && cstate != nullptr) {
 | 
			
		||||
				// icon pos
 | 
			
		||||
				auto p0 = ImGui::GetCursorScreenPos();
 | 
			
		||||
				p0.y += ImGui::GetStyle().FramePadding.y;
 | 
			
		||||
				ImVec2 p1_o = {img_y, img_y}; // img_y is 1 line_height in this case
 | 
			
		||||
 | 
			
		||||
				const ImU32 col_back = ImGui::GetColorU32(th.getColor<ThemeCol_Contact::icon_backdrop>());
 | 
			
		||||
				if (cstate->state == Contact::Components::ConnectionState::direct) { // direct icon
 | 
			
		||||
					drawIconDirect(
 | 
			
		||||
						p0,
 | 
			
		||||
						p1_o,
 | 
			
		||||
						ImGui::GetColorU32(th.getColor<ThemeCol_Contact::avatar_online_direct>()),
 | 
			
		||||
						col_back
 | 
			
		||||
					);
 | 
			
		||||
				} else if (cstate->state == Contact::Components::ConnectionState::cloud) { // cloud icon
 | 
			
		||||
					drawIconCloud(
 | 
			
		||||
						p0,
 | 
			
		||||
						p1_o,
 | 
			
		||||
						ImGui::GetColorU32(th.getColor<ThemeCol_Contact::avatar_online_cloud>()),
 | 
			
		||||
						col_back
 | 
			
		||||
					);
 | 
			
		||||
				}
 | 
			
		||||
				ImGui::Dummy(p1_o);
 | 
			
		||||
				ImGui::SameLine(0.f, same_line_spacing);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ImGui::Text("%s%s", unread?"* ":"", (c.all_of<Contact::Components::Name>() ? c.get<Contact::Components::Name>().name.c_str() : "<unk>"));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// line 2
 | 
			
		||||
		if (line_height >= 2) {
 | 
			
		||||
			if (request_incoming) {
 | 
			
		||||
				ImGui::TextUnformatted("Incoming request/invite");
 | 
			
		||||
			} else if (request_outgoing) {
 | 
			
		||||
				ImGui::TextUnformatted("Outgoing request/invite");
 | 
			
		||||
			} else {
 | 
			
		||||
				if (cstate != nullptr) {
 | 
			
		||||
					// icon pos
 | 
			
		||||
					auto p0 = ImGui::GetCursorScreenPos();
 | 
			
		||||
					p0.y += ImGui::GetStyle().FramePadding.y;
 | 
			
		||||
					const float box_hight = TEXT_BASE_HEIGHT - ImGui::GetStyle().FramePadding.y*2;
 | 
			
		||||
					ImVec2 p1_o = {box_hight, box_hight};
 | 
			
		||||
 | 
			
		||||
					const ImU32 col_back = ImGui::GetColorU32(th.getColor<ThemeCol_Contact::icon_backdrop>());
 | 
			
		||||
					if (cstate->state == Contact::Components::ConnectionState::direct) { // direct icon
 | 
			
		||||
						drawIconDirect(
 | 
			
		||||
							p0,
 | 
			
		||||
							p1_o,
 | 
			
		||||
							ImGui::GetColorU32(th.getColor<ThemeCol_Contact::avatar_online_direct>()),
 | 
			
		||||
							col_back
 | 
			
		||||
						);
 | 
			
		||||
					} else if (cstate->state == Contact::Components::ConnectionState::cloud) { // cloud icon
 | 
			
		||||
						drawIconCloud(
 | 
			
		||||
							p0,
 | 
			
		||||
							p1_o,
 | 
			
		||||
							ImGui::GetColorU32(th.getColor<ThemeCol_Contact::avatar_online_cloud>()),
 | 
			
		||||
							col_back
 | 
			
		||||
						);
 | 
			
		||||
					}
 | 
			
		||||
					ImGui::Dummy(p1_o);
 | 
			
		||||
					ImGui::SameLine(0.f, same_line_spacing);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (
 | 
			
		||||
					const auto* slt = c.try_get<Contact::Components::StatusText>();
 | 
			
		||||
					slt != nullptr &&
 | 
			
		||||
					!slt->text.empty() &&
 | 
			
		||||
					slt->first_line_length > 0 &&
 | 
			
		||||
					slt->first_line_length <= slt->text.size()
 | 
			
		||||
				) {
 | 
			
		||||
					ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
 | 
			
		||||
					ImGui::TextUnformatted(slt->text.c_str(), slt->text.c_str() + slt->first_line_length);
 | 
			
		||||
					ImGui::PopStyleColor();
 | 
			
		||||
				} else {
 | 
			
		||||
					ImGui::TextDisabled(""); // or dummy?
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// line 3
 | 
			
		||||
			//if (line_height >= 3) {
 | 
			
		||||
			//	constexpr std::string_view test_text{"text"};
 | 
			
		||||
			//	ImGui::RenderTextEllipsis(ImGui::GetWindowDrawList(), ImVec2{}, ImVec2{}, 1.f, 1.f, test_text.data(), test_text.data()+test_text.size(), nullptr);
 | 
			
		||||
			//}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	ImGui::EndGroup();
 | 
			
		||||
 | 
			
		||||
	ImGui::SetCursorPos(post_curser_pos);
 | 
			
		||||
 | 
			
		||||
	ImGui::EndGroup();
 | 
			
		||||
	return got_selected;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										43
									
								
								src/chat_gui/contact_list.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/chat_gui/contact_list.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "./texture_cache_defs.hpp"
 | 
			
		||||
 | 
			
		||||
#include "./theme.hpp"
 | 
			
		||||
 | 
			
		||||
#include <solanaceae/contact/contact_model3.hpp>
 | 
			
		||||
 | 
			
		||||
enum class ThemeCol_Contact {
 | 
			
		||||
	request_incoming,
 | 
			
		||||
	request_outgoing,
 | 
			
		||||
 | 
			
		||||
	avatar_online_direct,
 | 
			
		||||
	avatar_online_cloud,
 | 
			
		||||
	avatar_offline,
 | 
			
		||||
 | 
			
		||||
	icon_backdrop,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void renderAvatar(
 | 
			
		||||
	const Theme& th,
 | 
			
		||||
	ContactTextureCache& contact_tc,
 | 
			
		||||
	const Contact3Handle c,
 | 
			
		||||
	ImVec2 box
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// returns true if clicked, if selectable, will highlight on hover and respect selected
 | 
			
		||||
// TODO: refine
 | 
			
		||||
// +------+
 | 
			
		||||
// |	  | *Name (Alias?)
 | 
			
		||||
// |Avatar| Satus Message <-- richpresence interface?
 | 
			
		||||
// |	  | user status (online/away/busy)-direct/relayed / offline <-- last text?
 | 
			
		||||
// +------+
 | 
			
		||||
bool renderContactBig(
 | 
			
		||||
	const Theme& th,
 | 
			
		||||
	ContactTextureCache& contact_tc,
 | 
			
		||||
	const Contact3Handle c,
 | 
			
		||||
	int line_height = 3,
 | 
			
		||||
	const bool unread = false,
 | 
			
		||||
	const bool selectable = false,
 | 
			
		||||
	const bool selected = false
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@@ -1,9 +1,10 @@
 | 
			
		||||
#include "./send_image_popup.hpp"
 | 
			
		||||
 | 
			
		||||
#include "./image_loader_sdl_bmp.hpp"
 | 
			
		||||
#include "./image_loader_stb.hpp"
 | 
			
		||||
#include "./image_loader_webp.hpp"
 | 
			
		||||
#include "./image_loader_qoi.hpp"
 | 
			
		||||
#include "../image_loader_sdl_bmp.hpp"
 | 
			
		||||
#include "../image_loader_stb.hpp"
 | 
			
		||||
#include "../image_loader_webp.hpp"
 | 
			
		||||
#include "../image_loader_qoi.hpp"
 | 
			
		||||
#include "../image_loader_sdl_image.hpp"
 | 
			
		||||
 | 
			
		||||
#include <imgui/imgui.h>
 | 
			
		||||
 | 
			
		||||
@@ -16,7 +17,7 @@ SendImagePopup::SendImagePopup(TextureUploaderI& tu) : _tu(tu) {
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSDLBMP>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderQOI>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderWebP>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSTB>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSDLImage>());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SendImagePopup::reset(void) {
 | 
			
		||||
@@ -5,8 +5,8 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "./image_loader.hpp"
 | 
			
		||||
#include "./texture_cache.hpp"
 | 
			
		||||
#include "../image_loader.hpp"
 | 
			
		||||
#include "../texture_cache.hpp"
 | 
			
		||||
 | 
			
		||||
struct SendImagePopup {
 | 
			
		||||
	TextureUploaderI& _tu;
 | 
			
		||||
							
								
								
									
										12
									
								
								src/chat_gui/texture_cache_defs.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/chat_gui/texture_cache_defs.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <solanaceae/message3/registry_message_model.hpp>
 | 
			
		||||
 | 
			
		||||
#include "../texture_cache.hpp"
 | 
			
		||||
#include "../tox_avatar_loader.hpp"
 | 
			
		||||
#include "../message_image_loader.hpp"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
using ContactTextureCache = TextureCache<void*, Contact3, ToxAvatarLoader>;
 | 
			
		||||
using MessageTextureCache = TextureCache<void*, Message3Handle, MessageImageLoader>;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										62
									
								
								src/chat_gui/theme.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/chat_gui/theme.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
#include "./theme.hpp"
 | 
			
		||||
 | 
			
		||||
// HACK: includes everything and sets theme defaults
 | 
			
		||||
#include "./contact_list.hpp"
 | 
			
		||||
 | 
			
		||||
//#include <iostream>
 | 
			
		||||
 | 
			
		||||
//enum class TestThemeSet {
 | 
			
		||||
	//Value1,
 | 
			
		||||
//};
 | 
			
		||||
 | 
			
		||||
//// specialization
 | 
			
		||||
////template<>
 | 
			
		||||
////std::string typeValueName(TestThemeSet v) {
 | 
			
		||||
	////switch (v) {
 | 
			
		||||
		////case TestThemeSet::Value1: return "Value1";
 | 
			
		||||
		////default: return "unk";
 | 
			
		||||
	////}
 | 
			
		||||
////}
 | 
			
		||||
 | 
			
		||||
Theme::Theme(void) {
 | 
			
		||||
	load();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Theme::update(void) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Theme::load(void) {
 | 
			
		||||
	name = "Default";
 | 
			
		||||
 | 
			
		||||
	//setColor<TestThemeSet::Value1>(ImVec4{});
 | 
			
		||||
	//std::cout << "test value name: " << getColorName<TestThemeSet::Value1>() << "\n";
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Theme::store(void) {
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Theme getDefaultThemeDark(void) {
 | 
			
		||||
	Theme t;
 | 
			
		||||
 | 
			
		||||
	t.setColor<ThemeCol_Contact::request_incoming			>({0.98f, 0.41f, 0.26f, 0.52f});
 | 
			
		||||
	t.setColor<ThemeCol_Contact::request_outgoing			>({0.98f, 0.26f, 0.41f, 0.52f});
 | 
			
		||||
 | 
			
		||||
	t.setColor<ThemeCol_Contact::avatar_online_direct	>({0.3f, 1.0f, 0.0f, 1.0f});
 | 
			
		||||
	t.setColor<ThemeCol_Contact::avatar_online_cloud	>({0.0f, 1.0f, 0.8f, 1.0f});
 | 
			
		||||
	t.setColor<ThemeCol_Contact::avatar_offline		>({0.4f, 0.4f, 0.4f, 1.0f});
 | 
			
		||||
 | 
			
		||||
	t.setColor<ThemeCol_Contact::icon_backdrop				>({0.0f, 0.0f, 0.0f, 0.4f});
 | 
			
		||||
 | 
			
		||||
	return t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Theme getDefaultThemeLight(void) {
 | 
			
		||||
	// HACK: inherit dark and only diff
 | 
			
		||||
	Theme t = getDefaultThemeDark();
 | 
			
		||||
 | 
			
		||||
	return t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										76
									
								
								src/chat_gui/theme.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/chat_gui/theme.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <imgui/imgui.h>
 | 
			
		||||
 | 
			
		||||
#include <entt/container/dense_map.hpp>
 | 
			
		||||
#include <entt/core/type_info.hpp>
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
 | 
			
		||||
// default is resolving to its value
 | 
			
		||||
template<typename T>
 | 
			
		||||
std::string typeValueName(T V) {
 | 
			
		||||
	return std::to_string(static_cast<std::underlying_type_t<T>>(V));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// stores theming values and colors not expressed by imgui directly
 | 
			
		||||
struct Theme {
 | 
			
		||||
	using key_type = entt::id_type;
 | 
			
		||||
 | 
			
		||||
	entt::dense_map<key_type, ImVec4> colors;
 | 
			
		||||
	entt::dense_map<key_type, std::string> colors_name;
 | 
			
		||||
 | 
			
		||||
	// TODO: spec out dependencies
 | 
			
		||||
 | 
			
		||||
	// TODO: what for
 | 
			
		||||
	entt::dense_map<key_type, float> single_values;
 | 
			
		||||
 | 
			
		||||
	std::string name; // theme name
 | 
			
		||||
 | 
			
		||||
	Theme(void);
 | 
			
		||||
 | 
			
		||||
	// call when any color changed, so dependencies can be resolved
 | 
			
		||||
	void update(void);
 | 
			
		||||
 | 
			
		||||
	template<auto V>
 | 
			
		||||
	void setColor(ImVec4 color) {
 | 
			
		||||
		constexpr auto key = entt::type_hash<entt::tag<static_cast<entt::id_type>(V)>>::value();
 | 
			
		||||
		colors[key] = color;
 | 
			
		||||
 | 
			
		||||
		if (!colors_name.contains(key)) {
 | 
			
		||||
			std::string key_name = static_cast<std::string>(
 | 
			
		||||
				entt::type_name<decltype(V)>::value()
 | 
			
		||||
			) + ":" + typeValueName(V);
 | 
			
		||||
			colors_name[key] = key_name;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	template<auto V>
 | 
			
		||||
	ImVec4 getColor(void) const {
 | 
			
		||||
		constexpr auto key = entt::type_hash<entt::tag<static_cast<entt::id_type>(V)>>::value();
 | 
			
		||||
		const auto it = colors.find(key);
 | 
			
		||||
		if (it != colors.end()) {
 | 
			
		||||
			return it->second;
 | 
			
		||||
		} else {
 | 
			
		||||
			return {}; // TODO: pink as default?
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<auto V>
 | 
			
		||||
	std::string_view getColorName(void) const {
 | 
			
		||||
		constexpr auto key = entt::type_hash<entt::tag<static_cast<entt::id_type>(V)>>::value();
 | 
			
		||||
		if (colors_name.contains(key)) {
 | 
			
		||||
			return colors_name.at(key);
 | 
			
		||||
		} else {
 | 
			
		||||
			return "unk";
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: actually serialize from config?
 | 
			
		||||
	bool load(void);
 | 
			
		||||
	bool store(void);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Theme getDefaultThemeDark(void);
 | 
			
		||||
Theme getDefaultThemeLight(void);
 | 
			
		||||
 | 
			
		||||
@@ -1,7 +1,5 @@
 | 
			
		||||
#include "./chat_gui4.hpp"
 | 
			
		||||
 | 
			
		||||
#include "./file_selector.hpp"
 | 
			
		||||
 | 
			
		||||
#include <solanaceae/message3/components.hpp>
 | 
			
		||||
#include <solanaceae/tox_messages/components.hpp>
 | 
			
		||||
#include <solanaceae/contact/components.hpp>
 | 
			
		||||
@@ -15,6 +13,8 @@
 | 
			
		||||
 | 
			
		||||
#include <SDL3/SDL.h>
 | 
			
		||||
 | 
			
		||||
#include "./chat_gui/contact_list.hpp"
 | 
			
		||||
 | 
			
		||||
#include "./media_meta_info_loader.hpp"
 | 
			
		||||
#include "./sdl_clipboard_utils.hpp"
 | 
			
		||||
 | 
			
		||||
@@ -145,8 +145,9 @@ ChatGui4::ChatGui4(
 | 
			
		||||
	Contact3Registry& cr,
 | 
			
		||||
	TextureUploaderI& tu,
 | 
			
		||||
	ContactTextureCache& contact_tc,
 | 
			
		||||
	MessageTextureCache& msg_tc
 | 
			
		||||
) : _conf(conf), _rmm(rmm), _cr(cr), _contact_tc(contact_tc), _msg_tc(msg_tc), _sip(tu) {
 | 
			
		||||
	MessageTextureCache& msg_tc,
 | 
			
		||||
	Theme& theme
 | 
			
		||||
) : _conf(conf), _rmm(rmm), _cr(cr), _contact_tc(contact_tc), _msg_tc(msg_tc), _theme(theme), _sip(tu) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ChatGui4::~ChatGui4(void) {
 | 
			
		||||
@@ -197,16 +198,42 @@ float ChatGui4::render(float time_delta) {
 | 
			
		||||
				sub_contacts = &_cr.get<Contact::Components::ParentOf>(*_selected_contact).subs;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (ImGui::BeginChild(chat_label.c_str(), {0, 0}, true)) {
 | 
			
		||||
				//if (_cr.all_of<Contact::Components::ParentOf>(*_selected_contact)) {
 | 
			
		||||
				if (sub_contacts != nullptr) {
 | 
			
		||||
			const bool highlight_private {!_cr.all_of<Contact::Components::TagPrivate>(*_selected_contact)};
 | 
			
		||||
 | 
			
		||||
			if (ImGui::BeginChild(chat_label.c_str(), {0, 0}, ImGuiChildFlags_Border, ImGuiWindowFlags_MenuBar)) {
 | 
			
		||||
				if (ImGui::BeginMenuBar()) {
 | 
			
		||||
					if (ImGui::BeginMenu("debug")) {
 | 
			
		||||
						ImGui::Checkbox("show extra info", &_show_chat_extra_info);
 | 
			
		||||
						ImGui::Checkbox("show avatar transfers", &_show_chat_avatar_tf);
 | 
			
		||||
 | 
			
		||||
						ImGui::SeparatorText("tox");
 | 
			
		||||
 | 
			
		||||
						// TODO: cheese it and rename to copy id?
 | 
			
		||||
						if (_cr.all_of<Contact::Components::ToxGroupPersistent>(*_selected_contact)) {
 | 
			
		||||
							if (ImGui::MenuItem("copy ngc chatid")) {
 | 
			
		||||
								const auto& chat_id = _cr.get<Contact::Components::ToxGroupPersistent>(*_selected_contact).chat_id.data;
 | 
			
		||||
								const auto chat_id_str = bin2hex(std::vector<uint8_t>{chat_id.begin(), chat_id.end()});
 | 
			
		||||
								ImGui::SetClipboardText(chat_id_str.c_str());
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						ImGui::EndMenu();
 | 
			
		||||
					}
 | 
			
		||||
					ImGui::EndMenuBar();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				renderContactBig(_theme, _contact_tc, {_cr, *_selected_contact}, 3, false, false, false);
 | 
			
		||||
				ImGui::Separator();
 | 
			
		||||
 | 
			
		||||
				if (sub_contacts != nullptr && !_cr.all_of<Contact::Components::TagPrivate>(*_selected_contact) && _cr.all_of<Contact::Components::TagGroup>(*_selected_contact)) {
 | 
			
		||||
					if (!sub_contacts->empty()) {
 | 
			
		||||
						if (ImGui::BeginChild("subcontacts", {150, -100}, true)) {
 | 
			
		||||
						if (ImGui::BeginChild("subcontacts", {TEXT_BASE_WIDTH * 18.f, -100.f}, true)) {
 | 
			
		||||
							ImGui::Text("subs: %zu", sub_contacts->size());
 | 
			
		||||
							ImGui::Separator();
 | 
			
		||||
							for (const auto& c : *sub_contacts) {
 | 
			
		||||
								// TODO: can a sub be selected? no
 | 
			
		||||
								if (renderSubContactListContact(c, _selected_contact.has_value() && *_selected_contact == c)) {
 | 
			
		||||
								//if (renderSubContactListContact(c, _selected_contact.has_value() && *_selected_contact == c)) {
 | 
			
		||||
								if (renderContactBig(_theme, _contact_tc, {_cr, c}, 1)) {
 | 
			
		||||
									_text_input_buffer.insert(0, (_cr.all_of<Contact::Components::Name>(c) ? _cr.get<Contact::Components::Name>(c).name : "<unk>") + ": ");
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
@@ -257,27 +284,11 @@ float ChatGui4::render(float time_delta) {
 | 
			
		||||
					ImGui::EndChild();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (ImGui::BeginChild("message_log", {0, -100}, false, ImGuiWindowFlags_MenuBar)) {
 | 
			
		||||
					if (ImGui::BeginMenuBar()) {
 | 
			
		||||
						if (ImGui::BeginMenu("debug")) {
 | 
			
		||||
							ImGui::Checkbox("show extra info", &_show_chat_extra_info);
 | 
			
		||||
							ImGui::Checkbox("show avatar transfers", &_show_chat_avatar_tf);
 | 
			
		||||
 | 
			
		||||
							ImGui::SeparatorText("tox");
 | 
			
		||||
 | 
			
		||||
							// TODO: cheese it and rename to copy id?
 | 
			
		||||
							if (_cr.all_of<Contact::Components::ToxGroupPersistent>(*_selected_contact)) {
 | 
			
		||||
								if (ImGui::MenuItem("copy ngc chatid")) {
 | 
			
		||||
									const auto& chat_id = _cr.get<Contact::Components::ToxGroupPersistent>(*_selected_contact).chat_id.data;
 | 
			
		||||
									const auto chat_id_str = bin2hex(std::vector<uint8_t>{chat_id.begin(), chat_id.end()});
 | 
			
		||||
									ImGui::SetClipboardText(chat_id_str.c_str());
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							ImGui::EndMenu();
 | 
			
		||||
						}
 | 
			
		||||
						ImGui::EndMenuBar();
 | 
			
		||||
					}
 | 
			
		||||
				if (ImGui::BeginChild("message_log", {0, -100}, ImGuiChildFlags_None)) {
 | 
			
		||||
					// TODO: background image?
 | 
			
		||||
					//auto p_min = ImGui::GetCursorScreenPos();
 | 
			
		||||
					//auto a_max = ImGui::GetContentRegionAvail();
 | 
			
		||||
					//ImGui::GetWindowDrawList()->AddImage(0, p_min, {p_min.x+a_max.x, p_min.y+a_max.y});
 | 
			
		||||
 | 
			
		||||
					auto* msg_reg_ptr = _rmm.get(*_selected_contact);
 | 
			
		||||
 | 
			
		||||
@@ -287,7 +298,7 @@ float ChatGui4::render(float time_delta) {
 | 
			
		||||
						ImGuiTableFlags_SizingFixedFit
 | 
			
		||||
					;
 | 
			
		||||
					if (msg_reg_ptr != nullptr && ImGui::BeginTable("chat_table", 5, table_flags)) {
 | 
			
		||||
						ImGui::TableSetupColumn("name", 0, TEXT_BASE_WIDTH * 15.f);
 | 
			
		||||
						ImGui::TableSetupColumn("name", 0, TEXT_BASE_WIDTH * 16.f);
 | 
			
		||||
						ImGui::TableSetupColumn("message", ImGuiTableColumnFlags_WidthStretch);
 | 
			
		||||
						ImGui::TableSetupColumn("delivered/read");
 | 
			
		||||
						ImGui::TableSetupColumn("timestamp");
 | 
			
		||||
@@ -315,7 +326,7 @@ float ChatGui4::render(float time_delta) {
 | 
			
		||||
							msg_reg.view<Components::UnreadFade>().each([&to_remove, time_delta](const Message3 e, Components::UnreadFade& fade) {
 | 
			
		||||
								// TODO: configurable
 | 
			
		||||
								const float fade_duration = 7.5f;
 | 
			
		||||
								fade.fade -= 1.f/fade_duration * std::min<float>(time_delta, 1.f/10.f); // fps but not below 10 for smooth fade
 | 
			
		||||
								fade.fade -= 1.f/fade_duration * std::min<float>(time_delta, 1.f/8.f); // fps but not below 8 for smooth-ish fade
 | 
			
		||||
								if (fade.fade <= 0.f) {
 | 
			
		||||
									to_remove.push_back(e);
 | 
			
		||||
								}
 | 
			
		||||
@@ -375,6 +386,10 @@ float ChatGui4::render(float time_delta) {
 | 
			
		||||
 | 
			
		||||
							// name
 | 
			
		||||
							if (ImGui::TableNextColumn()) {
 | 
			
		||||
								const float img_y {TEXT_BASE_HEIGHT - ImGui::GetStyle().FramePadding.y*2};
 | 
			
		||||
								renderAvatar(_theme, _contact_tc, {_cr, c_from.c}, {img_y, img_y});
 | 
			
		||||
								ImGui::SameLine(0.f, ImGui::GetStyle().ItemSpacing.x*0.5f);
 | 
			
		||||
 | 
			
		||||
								if (_cr.all_of<Contact::Components::Name>(c_from.c)) {
 | 
			
		||||
									ImGui::TextUnformatted(_cr.get<Contact::Components::Name>(c_from.c).name.c_str());
 | 
			
		||||
								} else {
 | 
			
		||||
@@ -417,7 +432,7 @@ float ChatGui4::render(float time_delta) {
 | 
			
		||||
								std::optional<ImVec4> row_bg;
 | 
			
		||||
 | 
			
		||||
								// private group message
 | 
			
		||||
								if (_cr.any_of<Contact::Components::TagSelfWeak, Contact::Components::TagSelfStrong>(c_to.c)) {
 | 
			
		||||
								if (highlight_private && _cr.any_of<Contact::Components::TagSelfWeak, Contact::Components::TagSelfStrong>(c_to.c)) {
 | 
			
		||||
									const ImVec4 priv_msg_hi_col = ImVec4(0.5f, 0.2f, 0.5f, 0.35f);
 | 
			
		||||
									ImU32 row_bg_color = ImGui::GetColorU32(priv_msg_hi_col);
 | 
			
		||||
									ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg1, row_bg_color);
 | 
			
		||||
@@ -456,8 +471,11 @@ float ChatGui4::render(float time_delta) {
 | 
			
		||||
							if (ImGui::TableNextColumn()) {
 | 
			
		||||
								// TODO: theming for hardcoded values
 | 
			
		||||
 | 
			
		||||
								if (msg_reg.all_of<Message::Components::Remote::TimestampReceived>(e)) {
 | 
			
		||||
									const auto list = msg_reg.get<Message::Components::Remote::TimestampReceived>(e).ts;
 | 
			
		||||
								if (!msg_reg.all_of<Message::Components::ReceivedBy>(e)) {
 | 
			
		||||
									// TODO: dedup?
 | 
			
		||||
									ImGui::TextDisabled("_");
 | 
			
		||||
								} else {
 | 
			
		||||
									const auto list = msg_reg.get<Message::Components::ReceivedBy>(e).ts;
 | 
			
		||||
									// wrongly assumes contacts never get removed from a group
 | 
			
		||||
									if (sub_contacts != nullptr && list.size() < sub_contacts->size()) {
 | 
			
		||||
										// if partically delivered
 | 
			
		||||
@@ -471,6 +489,7 @@ float ChatGui4::render(float time_delta) {
 | 
			
		||||
										std::string synced_by_text {"delivery confirmed by:"};
 | 
			
		||||
										const int64_t now_ts_s = int64_t(Message::getTimeMS() / 1000u);
 | 
			
		||||
 | 
			
		||||
										size_t other_contacts {0};
 | 
			
		||||
										for (const auto& [c, syned_ts] : list) {
 | 
			
		||||
											if (_cr.all_of<Contact::Components::TagSelfStrong>(c)) {
 | 
			
		||||
												//synced_by_text += "\n sself(!)"; // makes no sense
 | 
			
		||||
@@ -480,23 +499,26 @@ float ChatGui4::render(float time_delta) {
 | 
			
		||||
											} else {
 | 
			
		||||
												synced_by_text += "\n >" + (_cr.all_of<Contact::Components::Name>(c) ? _cr.get<Contact::Components::Name>(c).name : "<unk>");
 | 
			
		||||
											}
 | 
			
		||||
											other_contacts += 1;
 | 
			
		||||
											const int64_t seconds_ago = (int64_t(syned_ts / 1000u) - now_ts_s) * -1;
 | 
			
		||||
											synced_by_text += " (" + std::to_string(seconds_ago) + "sec ago)";
 | 
			
		||||
										}
 | 
			
		||||
 | 
			
		||||
										ImGui::Text("%s", synced_by_text.c_str());
 | 
			
		||||
										if (other_contacts > 0) {
 | 
			
		||||
											ImGui::Text("%s", synced_by_text.c_str());
 | 
			
		||||
										} else {
 | 
			
		||||
											ImGui::TextUnformatted("no delivery confirmation");
 | 
			
		||||
										}
 | 
			
		||||
 | 
			
		||||
										ImGui::EndTooltip();
 | 
			
		||||
									}
 | 
			
		||||
								} else {
 | 
			
		||||
									ImGui::TextDisabled("_");
 | 
			
		||||
								}
 | 
			
		||||
 | 
			
		||||
								ImGui::SameLine();
 | 
			
		||||
 | 
			
		||||
								// TODO: dedup
 | 
			
		||||
								if (msg_reg.all_of<Message::Components::Remote::TimestampRead>(e)) {
 | 
			
		||||
									const auto list = msg_reg.get<Message::Components::Remote::TimestampRead>(e).ts;
 | 
			
		||||
								if (msg_reg.all_of<Message::Components::ReadBy>(e)) {
 | 
			
		||||
									const auto list = msg_reg.get<Message::Components::ReadBy>(e).ts;
 | 
			
		||||
									// wrongly assumes contacts never get removed from a group
 | 
			
		||||
									if (sub_contacts != nullptr && list.size() < sub_contacts->size()) {
 | 
			
		||||
										// if partially read
 | 
			
		||||
@@ -1045,13 +1067,13 @@ void ChatGui4::renderMessageExtra(Message3Registry& reg, const Message3 e) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: remove?
 | 
			
		||||
	if (reg.all_of<Message::Components::Remote::TimestampReceived>(e)) {
 | 
			
		||||
	if (reg.all_of<Message::Components::ReceivedBy>(e)) {
 | 
			
		||||
		std::string synced_by_text {"receivedBy:"};
 | 
			
		||||
		const int64_t now_ts_s = int64_t(Message::getTimeMS() / 1000u);
 | 
			
		||||
 | 
			
		||||
		for (const auto& [c, syned_ts] : reg.get<Message::Components::Remote::TimestampReceived>(e).ts) {
 | 
			
		||||
		for (const auto& [c, syned_ts] : reg.get<Message::Components::ReceivedBy>(e).ts) {
 | 
			
		||||
			if (_cr.all_of<Contact::Components::TagSelfStrong>(c)) {
 | 
			
		||||
				synced_by_text += "\n sself(!)"; // makes no sense
 | 
			
		||||
				synced_by_text += "\n sself"; // required (except when synced externally)
 | 
			
		||||
			} else if (_cr.all_of<Contact::Components::TagSelfWeak>(c)) {
 | 
			
		||||
				synced_by_text += "\n wself";
 | 
			
		||||
			} else {
 | 
			
		||||
@@ -1069,7 +1091,18 @@ void ChatGui4::renderContactList(void) {
 | 
			
		||||
	if (ImGui::BeginChild("contacts", {TEXT_BASE_WIDTH*35, 0})) {
 | 
			
		||||
		//for (const auto& c : _cm.getBigContacts()) {
 | 
			
		||||
		for (const auto& c : _cr.view<Contact::Components::TagBig>()) {
 | 
			
		||||
			if (renderContactListContactBig(c, _selected_contact.has_value() && *_selected_contact == c)) {
 | 
			
		||||
			const bool selected = _selected_contact.has_value() && *_selected_contact == c;
 | 
			
		||||
 | 
			
		||||
			// TODO: is there a better way?
 | 
			
		||||
			// maybe cache mm?
 | 
			
		||||
			bool has_unread = false;
 | 
			
		||||
			if (const auto* mm = _rmm.get(c); mm != nullptr) {
 | 
			
		||||
				if (const auto* unread_storage = mm->storage<Message::Components::TagUnread>(); unread_storage != nullptr && !unread_storage->empty()) {
 | 
			
		||||
					has_unread = true;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (renderContactBig(_theme, _contact_tc, {_cr, c}, 2, has_unread, true, selected)) {
 | 
			
		||||
				_selected_contact = c;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -1077,121 +1110,6 @@ void ChatGui4::renderContactList(void) {
 | 
			
		||||
	ImGui::EndChild();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ChatGui4::renderContactListContactBig(const Contact3 c, const bool selected) {
 | 
			
		||||
	// TODO:
 | 
			
		||||
	// - unread message
 | 
			
		||||
	// - avatar img
 | 
			
		||||
	// - connection status
 | 
			
		||||
	// - user status
 | 
			
		||||
	// - status message
 | 
			
		||||
	// - context menu n shit?
 | 
			
		||||
 | 
			
		||||
	// +------+
 | 
			
		||||
	// |	  | *Name (Alias?)
 | 
			
		||||
	// |Avatar| Satus Message
 | 
			
		||||
	// |	  | user status (online/away/busy)-direct/relayed / offline
 | 
			
		||||
	// +------+
 | 
			
		||||
 | 
			
		||||
	auto label = "###" + std::to_string(entt::to_integral(c));
 | 
			
		||||
 | 
			
		||||
	const bool request_incoming = _cr.all_of<Contact::Components::RequestIncoming>(c);
 | 
			
		||||
	const bool request_outgoing = _cr.all_of<Contact::Components::TagRequestOutgoing>(c);
 | 
			
		||||
 | 
			
		||||
	ImVec2 orig_curser_pos = ImGui::GetCursorPos();
 | 
			
		||||
	// HACK: fake selected to make it draw a box for us
 | 
			
		||||
	const bool show_selected = request_incoming || request_outgoing || selected;
 | 
			
		||||
	if (request_incoming) {
 | 
			
		||||
		// TODO: theming
 | 
			
		||||
		ImGui::PushStyleColor(ImGuiCol_Header, {0.98f, 0.41f, 0.26f, 0.52f});
 | 
			
		||||
	} else if (request_outgoing) {
 | 
			
		||||
		// TODO: theming
 | 
			
		||||
		ImGui::PushStyleColor(ImGuiCol_Header, {0.98f, 0.26f, 0.41f, 0.52f});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const bool got_selected = ImGui::Selectable(label.c_str(), show_selected, 0, {0,3*TEXT_BASE_HEIGHT});
 | 
			
		||||
 | 
			
		||||
	if (request_incoming || request_outgoing) {
 | 
			
		||||
		ImGui::PopStyleColor();
 | 
			
		||||
	}
 | 
			
		||||
	ImVec2 post_curser_pos = ImGui::GetCursorPos();
 | 
			
		||||
 | 
			
		||||
	ImVec2 img_curser {
 | 
			
		||||
		orig_curser_pos.x + ImGui::GetStyle().FramePadding.x,
 | 
			
		||||
		orig_curser_pos.y + ImGui::GetStyle().FramePadding.y
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	float img_y {
 | 
			
		||||
		//(post_curser_pos.y - orig_curser_pos.y) - ImGui::GetStyle().FramePadding.y*2
 | 
			
		||||
		TEXT_BASE_HEIGHT*3 - ImGui::GetStyle().FramePadding.y*2
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	ImGui::SetCursorPos(img_curser);
 | 
			
		||||
	const ImVec4 color_online_direct{0.3, 1, 0, 1};
 | 
			
		||||
	const ImVec4 color_online_cloud{0, 1, 0.8, 1};
 | 
			
		||||
	const ImVec4 color_offline{0.4, 0.4, 0.4, 1};
 | 
			
		||||
 | 
			
		||||
	ImVec4 color_current = color_offline;
 | 
			
		||||
	if (_cr.all_of<Contact::Components::ConnectionState>(c)) {
 | 
			
		||||
		const auto c_state = _cr.get<Contact::Components::ConnectionState>(c).state;
 | 
			
		||||
		if (c_state == Contact::Components::ConnectionState::State::direct) {
 | 
			
		||||
			color_current = color_online_direct;
 | 
			
		||||
		} else if (c_state == Contact::Components::ConnectionState::State::cloud) {
 | 
			
		||||
			color_current = color_online_cloud;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// avatar
 | 
			
		||||
	const auto [id, width, height] = _contact_tc.get(c);
 | 
			
		||||
	ImGui::Image(
 | 
			
		||||
		id,
 | 
			
		||||
		ImVec2{img_y, img_y},
 | 
			
		||||
		{0, 0},
 | 
			
		||||
		{1, 1},
 | 
			
		||||
		{1, 1, 1, 1},
 | 
			
		||||
		color_current
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	// TODO: move this out of chat gui
 | 
			
		||||
	any_unread = false;
 | 
			
		||||
 | 
			
		||||
	ImGui::SameLine();
 | 
			
		||||
	ImGui::BeginGroup();
 | 
			
		||||
	{
 | 
			
		||||
		// TODO: is there a better way?
 | 
			
		||||
		// maybe cache mm?
 | 
			
		||||
		bool has_unread = false;
 | 
			
		||||
		if (const auto* mm = _rmm.get(c); mm != nullptr) {
 | 
			
		||||
			if (const auto* unread_storage = mm->storage<Message::Components::TagUnread>(); unread_storage != nullptr && !unread_storage->empty()) {
 | 
			
		||||
#if 0
 | 
			
		||||
				assert(unread_storage.size() == 0);
 | 
			
		||||
				assert(unread_storage.cbegin() == unread_storage.cend());
 | 
			
		||||
				std::cout << "UNREAD ";
 | 
			
		||||
				for (const auto e : mm->view<Message::Components::TagUnread>()) {
 | 
			
		||||
					std::cout << entt::to_integral(e) << " ";
 | 
			
		||||
				}
 | 
			
		||||
				std::cout << "\n";
 | 
			
		||||
#endif
 | 
			
		||||
				has_unread = true;
 | 
			
		||||
				any_unread = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ImGui::Text("%s%s", has_unread?"* ":"", (_cr.all_of<Contact::Components::Name>(c) ? _cr.get<Contact::Components::Name>(c).name.c_str() : "<unk>"));
 | 
			
		||||
		if (request_incoming) {
 | 
			
		||||
			ImGui::TextUnformatted("Incoming request/invite");
 | 
			
		||||
		} else if (request_outgoing) {
 | 
			
		||||
			ImGui::TextUnformatted("Outgoing request/invite");
 | 
			
		||||
		}
 | 
			
		||||
		//ImGui::Text("status message...");
 | 
			
		||||
		//ImGui::TextDisabled("hi");
 | 
			
		||||
		//ImGui::RenderTextEllipsis
 | 
			
		||||
	}
 | 
			
		||||
	ImGui::EndGroup();
 | 
			
		||||
 | 
			
		||||
	ImGui::SetCursorPos(post_curser_pos);
 | 
			
		||||
	return got_selected;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ChatGui4::renderContactListContactSmall(const Contact3 c, const bool selected) const {
 | 
			
		||||
	std::string label;
 | 
			
		||||
 | 
			
		||||
@@ -1202,6 +1120,7 @@ bool ChatGui4::renderContactListContactSmall(const Contact3 c, const bool select
 | 
			
		||||
	return ImGui::Selectable(label.c_str(), selected);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
bool ChatGui4::renderSubContactListContact(const Contact3 c, const bool selected) const {
 | 
			
		||||
	std::string label;
 | 
			
		||||
 | 
			
		||||
@@ -1224,6 +1143,7 @@ bool ChatGui4::renderSubContactListContact(const Contact3 c, const bool selected
 | 
			
		||||
 | 
			
		||||
	return ImGui::Selectable(label.c_str(), selected);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void ChatGui4::pasteFile(const char* mime_type) {
 | 
			
		||||
	size_t data_size = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,12 +3,14 @@
 | 
			
		||||
#include <solanaceae/message3/registry_message_model.hpp>
 | 
			
		||||
#include <solanaceae/util/config_model.hpp>
 | 
			
		||||
 | 
			
		||||
#include "./chat_gui/theme.hpp"
 | 
			
		||||
 | 
			
		||||
#include "./texture_uploader.hpp"
 | 
			
		||||
#include "./texture_cache.hpp"
 | 
			
		||||
#include "./tox_avatar_loader.hpp"
 | 
			
		||||
#include "./message_image_loader.hpp"
 | 
			
		||||
#include "./file_selector.hpp"
 | 
			
		||||
#include "./send_image_popup.hpp"
 | 
			
		||||
#include "./chat_gui/file_selector.hpp"
 | 
			
		||||
#include "./chat_gui/send_image_popup.hpp"
 | 
			
		||||
 | 
			
		||||
#include <entt/container/dense_map.hpp>
 | 
			
		||||
 | 
			
		||||
@@ -29,6 +31,8 @@ class ChatGui4 {
 | 
			
		||||
	ContactTextureCache& _contact_tc;
 | 
			
		||||
	MessageTextureCache& _msg_tc;
 | 
			
		||||
 | 
			
		||||
	Theme& _theme;
 | 
			
		||||
 | 
			
		||||
	FileSelector _fss;
 | 
			
		||||
	SendImagePopup _sip;
 | 
			
		||||
 | 
			
		||||
@@ -57,7 +61,8 @@ class ChatGui4 {
 | 
			
		||||
			Contact3Registry& cr,
 | 
			
		||||
			TextureUploaderI& tu,
 | 
			
		||||
			ContactTextureCache& contact_tc,
 | 
			
		||||
			MessageTextureCache& msg_tc
 | 
			
		||||
			MessageTextureCache& msg_tc,
 | 
			
		||||
			Theme& theme
 | 
			
		||||
		);
 | 
			
		||||
		~ChatGui4(void);
 | 
			
		||||
 | 
			
		||||
@@ -65,8 +70,6 @@ class ChatGui4 {
 | 
			
		||||
		float render(float time_delta);
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		bool any_unread {false};
 | 
			
		||||
 | 
			
		||||
		void sendFilePath(const char* file_path);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
@@ -75,9 +78,8 @@ class ChatGui4 {
 | 
			
		||||
		void renderMessageExtra(Message3Registry& reg, const Message3 e);
 | 
			
		||||
 | 
			
		||||
		void renderContactList(void);
 | 
			
		||||
		bool renderContactListContactBig(const Contact3 c, const bool selected);
 | 
			
		||||
		bool renderContactListContactSmall(const Contact3 c, const bool selected) const;
 | 
			
		||||
		bool renderSubContactListContact(const Contact3 c, const bool selected) const;
 | 
			
		||||
		//bool renderSubContactListContact(const Contact3 c, const bool selected) const;
 | 
			
		||||
 | 
			
		||||
		void pasteFile(const char* mime_type);
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										118
									
								
								src/image_loader_sdl_image.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								src/image_loader_sdl_image.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
#include "./image_loader_sdl_image.hpp"
 | 
			
		||||
 | 
			
		||||
#include <SDL3_image/SDL_image.h>
 | 
			
		||||
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
static std::optional<const char*> getExt(SDL_IOStream* ios) {
 | 
			
		||||
	if (IMG_isAVIF(ios)) {
 | 
			
		||||
		return "avif";
 | 
			
		||||
	} else if (IMG_isCUR(ios)) {
 | 
			
		||||
		return "cur";
 | 
			
		||||
	} else if (IMG_isICO(ios)) {
 | 
			
		||||
		return "ico";
 | 
			
		||||
	} else if (IMG_isBMP(ios)) {
 | 
			
		||||
		return "bmp";
 | 
			
		||||
	} else if (IMG_isGIF(ios)) {
 | 
			
		||||
		return "gif";
 | 
			
		||||
	} else if (IMG_isJPG(ios)) {
 | 
			
		||||
		return "jpg";
 | 
			
		||||
	} else if (IMG_isJXL(ios)) {
 | 
			
		||||
		return "jxl";
 | 
			
		||||
	} else if (IMG_isLBM(ios)) {
 | 
			
		||||
		return "lbm";
 | 
			
		||||
	} else if (IMG_isPCX(ios)) {
 | 
			
		||||
		return "pcx";
 | 
			
		||||
	} else if (IMG_isPNG(ios)) {
 | 
			
		||||
		return "png";
 | 
			
		||||
	} else if (IMG_isPNM(ios)) {
 | 
			
		||||
		return "pnm";
 | 
			
		||||
	} else if (IMG_isSVG(ios)) {
 | 
			
		||||
		return "svg";
 | 
			
		||||
	} else if (IMG_isTIF(ios)) {
 | 
			
		||||
		return "tiff";
 | 
			
		||||
	} else if (IMG_isXCF(ios)) {
 | 
			
		||||
		return "xcf";
 | 
			
		||||
	} else if (IMG_isXPM(ios)) {
 | 
			
		||||
		return "xpm";
 | 
			
		||||
	} else if (IMG_isXV(ios)) {
 | 
			
		||||
		return "xv";
 | 
			
		||||
	} else if (IMG_isWEBP(ios)) {
 | 
			
		||||
		return "webp";
 | 
			
		||||
	} else if (IMG_isQOI(ios)) {
 | 
			
		||||
		return "qoi";
 | 
			
		||||
	} else {
 | 
			
		||||
		return std::nullopt;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ImageLoaderSDLImage::ImageInfo ImageLoaderSDLImage::loadInfoFromMemory(const uint8_t* data, uint64_t data_size) {
 | 
			
		||||
	ImageInfo res;
 | 
			
		||||
 | 
			
		||||
	auto* ios = SDL_IOFromConstMem(data, data_size);
 | 
			
		||||
 | 
			
		||||
	// we ignore tga
 | 
			
		||||
	auto ext_opt = getExt(ios);
 | 
			
		||||
	if (!ext_opt.has_value()) {
 | 
			
		||||
		return res;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SDL_Surface* surf = IMG_Load_IO(ios, SDL_TRUE);
 | 
			
		||||
	if (surf == nullptr) {
 | 
			
		||||
		return res;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res.width = surf->w;
 | 
			
		||||
	res.height = surf->h;
 | 
			
		||||
	res.file_ext = ext_opt.value();
 | 
			
		||||
 | 
			
		||||
	SDL_DestroySurface(surf);
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ImageLoaderSDLImage::ImageResult ImageLoaderSDLImage::loadFromMemoryRGBA(const uint8_t* data, uint64_t data_size) {
 | 
			
		||||
	ImageResult res;
 | 
			
		||||
 | 
			
		||||
	auto* ios = SDL_IOFromConstMem(data, data_size);
 | 
			
		||||
 | 
			
		||||
	// we ignore tga
 | 
			
		||||
	auto ext_opt = getExt(ios);
 | 
			
		||||
	if (!ext_opt.has_value()) {
 | 
			
		||||
		return res;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	IMG_Animation* anim = IMG_LoadAnimation_IO(ios, SDL_TRUE);
 | 
			
		||||
	if (anim == nullptr) {
 | 
			
		||||
		return res;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < anim->count; i++) {
 | 
			
		||||
		SDL_Surface* conv_surf = SDL_ConvertSurfaceFormat(anim->frames[i], SDL_PIXELFORMAT_RGBA32);
 | 
			
		||||
		if (conv_surf == nullptr) {
 | 
			
		||||
			return res;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		SDL_LockSurface(conv_surf);
 | 
			
		||||
 | 
			
		||||
		auto& new_frame = res.frames.emplace_back();
 | 
			
		||||
		new_frame.ms = anim->delays[i];
 | 
			
		||||
		new_frame.data.insert(new_frame.data.cbegin(), (const uint8_t*)conv_surf->pixels, ((const uint8_t*)conv_surf->pixels) + (anim->w*anim->h*4));
 | 
			
		||||
 | 
			
		||||
		SDL_UnlockSurface(conv_surf);
 | 
			
		||||
		SDL_DestroySurface(conv_surf);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res.width = anim->w;
 | 
			
		||||
	res.height = anim->h;
 | 
			
		||||
	res.file_ext = ext_opt.value();
 | 
			
		||||
 | 
			
		||||
	IMG_FreeAnimation(anim);
 | 
			
		||||
 | 
			
		||||
	std::cout << "IL_SDLI: loaded img " << res.width << "x" << res.height << "\n";
 | 
			
		||||
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								src/image_loader_sdl_image.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/image_loader_sdl_image.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "./image_loader.hpp"
 | 
			
		||||
 | 
			
		||||
struct ImageLoaderSDLImage : public ImageLoaderI {
 | 
			
		||||
	ImageInfo loadInfoFromMemory(const uint8_t* data, uint64_t data_size) override;
 | 
			
		||||
	ImageResult loadFromMemoryRGBA(const uint8_t* data, uint64_t data_size) override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
#include <imgui/backends/imgui_impl_sdlrenderer3.h>
 | 
			
		||||
 | 
			
		||||
#include "./theme.hpp"
 | 
			
		||||
#include "./chat_gui/theme.hpp"
 | 
			
		||||
 | 
			
		||||
#include "./start_screen.hpp"
 | 
			
		||||
 | 
			
		||||
@@ -58,11 +59,14 @@ int main(int argc, char** argv) {
 | 
			
		||||
	IMGUI_CHECKVERSION();
 | 
			
		||||
	ImGui::CreateContext();
 | 
			
		||||
 | 
			
		||||
	Theme theme;
 | 
			
		||||
	if (SDL_GetSystemTheme() == SDL_SYSTEM_THEME_LIGHT) {
 | 
			
		||||
		ImGui::StyleColorsLight();
 | 
			
		||||
		theme = getDefaultThemeLight();
 | 
			
		||||
	} else {
 | 
			
		||||
		//ImGui::StyleColorsDark();
 | 
			
		||||
		setThemeGreen();
 | 
			
		||||
		theme = getDefaultThemeDark();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
@@ -85,7 +89,7 @@ int main(int argc, char** argv) {
 | 
			
		||||
	ImGui_ImplSDL3_InitForSDLRenderer(window.get(), renderer.get());
 | 
			
		||||
	ImGui_ImplSDLRenderer3_Init(renderer.get());
 | 
			
		||||
 | 
			
		||||
	std::unique_ptr<Screen> screen = std::make_unique<StartScreen>(renderer.get());
 | 
			
		||||
	std::unique_ptr<Screen> screen = std::make_unique<StartScreen>(renderer.get(), theme);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	bool quit = false;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
 | 
			
		||||
MainScreen::MainScreen(SDL_Renderer* renderer_, std::string save_path, std::string save_password, std::vector<std::string> plugins) :
 | 
			
		||||
MainScreen::MainScreen(SDL_Renderer* renderer_, Theme& theme_, std::string save_path, std::string save_password, std::string new_username, std::vector<std::string> plugins) :
 | 
			
		||||
	renderer(renderer_),
 | 
			
		||||
	rmm(cr),
 | 
			
		||||
	msnj{cr, {}, {}},
 | 
			
		||||
@@ -24,6 +24,7 @@ MainScreen::MainScreen(SDL_Renderer* renderer_, std::string save_path, std::stri
 | 
			
		||||
	tmm(rmm, cr, tcm, tc, tc),
 | 
			
		||||
	ttm(rmm, cr, tcm, tc, tc),
 | 
			
		||||
	tffom(cr, rmm, tcm, tc, tc),
 | 
			
		||||
	theme(theme_),
 | 
			
		||||
	mmil(rmm),
 | 
			
		||||
	tam(rmm, cr, conf),
 | 
			
		||||
	sdlrtu(renderer_),
 | 
			
		||||
@@ -31,7 +32,7 @@ MainScreen::MainScreen(SDL_Renderer* renderer_, std::string save_path, std::stri
 | 
			
		||||
	contact_tc(tal, sdlrtu),
 | 
			
		||||
	mil(),
 | 
			
		||||
	msg_tc(mil, sdlrtu),
 | 
			
		||||
	cg(conf, rmm, cr, sdlrtu, contact_tc, msg_tc),
 | 
			
		||||
	cg(conf, rmm, cr, sdlrtu, contact_tc, msg_tc, theme),
 | 
			
		||||
	sw(conf),
 | 
			
		||||
	tuiu(tc, conf),
 | 
			
		||||
	tdch(tpi)
 | 
			
		||||
@@ -44,9 +45,10 @@ MainScreen::MainScreen(SDL_Renderer* renderer_, std::string save_path, std::stri
 | 
			
		||||
	conf.set("tox", "save_file_path", save_path);
 | 
			
		||||
 | 
			
		||||
	{ // name stuff
 | 
			
		||||
		// a new profile will not have this set
 | 
			
		||||
		auto name = tc.toxSelfGetName();
 | 
			
		||||
		if (name.empty()) {
 | 
			
		||||
			name = "tomato";
 | 
			
		||||
			name = new_username;
 | 
			
		||||
		}
 | 
			
		||||
		conf.set("tox", "name", name);
 | 
			
		||||
		tc.setSelfName(name); // TODO: this is ugly
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
#include "./message_image_loader.hpp"
 | 
			
		||||
 | 
			
		||||
#include "./chat_gui4.hpp"
 | 
			
		||||
#include "./settings_window.hpp"
 | 
			
		||||
#include "./chat_gui/settings_window.hpp"
 | 
			
		||||
#include "./tox_ui_utils.hpp"
 | 
			
		||||
#include "./tox_dht_cap_histo.hpp"
 | 
			
		||||
#include "./tox_friend_faux_offline_messaging.hpp"
 | 
			
		||||
@@ -62,6 +62,8 @@ struct MainScreen final : public Screen {
 | 
			
		||||
	ToxTransferManager ttm;
 | 
			
		||||
	ToxFriendFauxOfflineMessaging tffom;
 | 
			
		||||
 | 
			
		||||
	Theme& theme;
 | 
			
		||||
 | 
			
		||||
	MediaMetaInfoLoader mmil;
 | 
			
		||||
	ToxAvatarManager tam;
 | 
			
		||||
 | 
			
		||||
@@ -89,7 +91,7 @@ struct MainScreen final : public Screen {
 | 
			
		||||
	uint64_t _window_hidden_ts {0};
 | 
			
		||||
	float _time_since_event {0.f};
 | 
			
		||||
 | 
			
		||||
	MainScreen(SDL_Renderer* renderer_, std::string save_path, std::string save_password, std::vector<std::string> plugins);
 | 
			
		||||
	MainScreen(SDL_Renderer* renderer_, Theme& theme_, std::string save_path, std::string save_password, std::string new_username, std::vector<std::string> plugins);
 | 
			
		||||
	~MainScreen(void);
 | 
			
		||||
 | 
			
		||||
	bool handleEvent(SDL_Event& e) override;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
#include "./image_loader_webp.hpp"
 | 
			
		||||
#include "./image_loader_sdl_bmp.hpp"
 | 
			
		||||
#include "./image_loader_qoi.hpp"
 | 
			
		||||
#include "./image_loader_stb.hpp"
 | 
			
		||||
#include "./image_loader_sdl_image.hpp"
 | 
			
		||||
 | 
			
		||||
#include <solanaceae/message3/components.hpp>
 | 
			
		||||
 | 
			
		||||
@@ -79,7 +79,7 @@ MediaMetaInfoLoader::MediaMetaInfoLoader(RegistryMessageModel& rmm) : _rmm(rmm)
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderWebP>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSDLBMP>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderQOI>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSTB>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSDLImage>());
 | 
			
		||||
 | 
			
		||||
	_rmm.subscribe(this, RegistryMessageModel_Event::message_construct);
 | 
			
		||||
	_rmm.subscribe(this, RegistryMessageModel_Event::message_updated);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,8 @@
 | 
			
		||||
 | 
			
		||||
#include "./image_loader_sdl_bmp.hpp"
 | 
			
		||||
#include "./image_loader_qoi.hpp"
 | 
			
		||||
#include "./image_loader_stb.hpp"
 | 
			
		||||
#include "./image_loader_webp.hpp"
 | 
			
		||||
#include "./image_loader_sdl_image.hpp"
 | 
			
		||||
#include "./media_meta_info_loader.hpp"
 | 
			
		||||
 | 
			
		||||
#include <solanaceae/message3/components.hpp>
 | 
			
		||||
@@ -22,7 +22,7 @@ MessageImageLoader::MessageImageLoader(void) {
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSDLBMP>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderQOI>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderWebP>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSTB>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSDLImage>());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::optional<TextureEntry> MessageImageLoader::load(TextureUploaderI& tu, Message3Handle m) {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,10 +5,11 @@
 | 
			
		||||
#include <imgui/imgui.h>
 | 
			
		||||
#include <imgui/misc/cpp/imgui_stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include <cctype>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
 | 
			
		||||
StartScreen::StartScreen(SDL_Renderer* renderer) : _renderer(renderer) {
 | 
			
		||||
StartScreen::StartScreen(SDL_Renderer* renderer, Theme& theme) : _renderer(renderer), _theme(theme) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Screen* StartScreen::render(float, bool&) {
 | 
			
		||||
@@ -33,13 +34,13 @@ Screen* StartScreen::render(float, bool&) {
 | 
			
		||||
				_fss.requestFile(
 | 
			
		||||
					[](const auto& path) -> bool { return std::filesystem::is_regular_file(path); },
 | 
			
		||||
					[this](const auto& path) {
 | 
			
		||||
						tox_profile_path = path.string();
 | 
			
		||||
						_tox_profile_path = path.string();
 | 
			
		||||
					},
 | 
			
		||||
					[](){}
 | 
			
		||||
				);
 | 
			
		||||
			}
 | 
			
		||||
			ImGui::SameLine();
 | 
			
		||||
			ImGui::TextUnformatted(tox_profile_path.c_str());
 | 
			
		||||
			ImGui::TextUnformatted(_tox_profile_path.c_str());
 | 
			
		||||
 | 
			
		||||
			ImGui::TextUnformatted("password:");
 | 
			
		||||
			ImGui::SameLine();
 | 
			
		||||
@@ -56,8 +57,22 @@ Screen* StartScreen::render(float, bool&) {
 | 
			
		||||
		if (ImGui::BeginTabItem("create profile")) {
 | 
			
		||||
			_new_save = true;
 | 
			
		||||
 | 
			
		||||
			ImGui::TextUnformatted("TODO: profile path");
 | 
			
		||||
			ImGui::TextUnformatted("TODO: profile name");
 | 
			
		||||
			ImGui::TextUnformatted("username:");
 | 
			
		||||
			ImGui::SameLine();
 | 
			
		||||
			if (ImGui::InputText("##user_name", &_user_name)) {
 | 
			
		||||
				std::string tmp_copy = _user_name;
 | 
			
		||||
				for (auto& c : tmp_copy) {
 | 
			
		||||
					if (!std::isalnum(static_cast<unsigned char>(c)) && c != '-' && c != '.') {
 | 
			
		||||
						c = '_';
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (tmp_copy.empty()) {
 | 
			
		||||
					tmp_copy = "unnamed-tomato";
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				_tox_profile_path = tmp_copy + ".tox";
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ImGui::TextUnformatted("password:");
 | 
			
		||||
			ImGui::SameLine();
 | 
			
		||||
@@ -69,6 +84,8 @@ Screen* StartScreen::render(float, bool&) {
 | 
			
		||||
			ImGui::SameLine();
 | 
			
		||||
			ImGui::Checkbox("show password", &_show_password);
 | 
			
		||||
 | 
			
		||||
			ImGui::TextUnformatted("TODO: profile path (current path for now)");
 | 
			
		||||
 | 
			
		||||
			ImGui::EndTabItem();
 | 
			
		||||
		}
 | 
			
		||||
		if (ImGui::BeginTabItem("plugins")) {
 | 
			
		||||
@@ -81,7 +98,6 @@ Screen* StartScreen::render(float, bool&) {
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				ImGui::SameLine();
 | 
			
		||||
 | 
			
		||||
				ImGui::TextUnformatted(it->c_str());
 | 
			
		||||
 | 
			
		||||
				ImGui::PopID();
 | 
			
		||||
@@ -105,7 +121,7 @@ Screen* StartScreen::render(float, bool&) {
 | 
			
		||||
 | 
			
		||||
	ImGui::Separator();
 | 
			
		||||
 | 
			
		||||
	if (!_new_save && !std::filesystem::is_regular_file(tox_profile_path)) {
 | 
			
		||||
	if (!_new_save && !std::filesystem::is_regular_file(_tox_profile_path)) {
 | 
			
		||||
		// load but file missing
 | 
			
		||||
 | 
			
		||||
		ImGui::BeginDisabled();
 | 
			
		||||
@@ -115,7 +131,7 @@ Screen* StartScreen::render(float, bool&) {
 | 
			
		||||
		if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_AllowWhenDisabled)) {
 | 
			
		||||
			ImGui::SetTooltip("file does not exist");
 | 
			
		||||
		}
 | 
			
		||||
	} else if (_new_save && std::filesystem::exists(tox_profile_path)) {
 | 
			
		||||
	} else if (_new_save && std::filesystem::exists(_tox_profile_path)) {
 | 
			
		||||
		// new but file exists
 | 
			
		||||
 | 
			
		||||
		ImGui::BeginDisabled();
 | 
			
		||||
@@ -127,7 +143,7 @@ Screen* StartScreen::render(float, bool&) {
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if (ImGui::Button("load", {60, 25})) {
 | 
			
		||||
			auto new_screen = std::make_unique<MainScreen>(_renderer, tox_profile_path, _password, queued_plugin_paths);
 | 
			
		||||
			auto new_screen = std::make_unique<MainScreen>(_renderer, _theme, _tox_profile_path, _password, _user_name, queued_plugin_paths);
 | 
			
		||||
			return new_screen.release();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,8 @@
 | 
			
		||||
 | 
			
		||||
#include "./screen.hpp"
 | 
			
		||||
 | 
			
		||||
#include "./file_selector.hpp"
 | 
			
		||||
#include "./chat_gui/theme.hpp"
 | 
			
		||||
#include "./chat_gui/file_selector.hpp"
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
@@ -14,18 +15,20 @@ extern "C" {
 | 
			
		||||
 | 
			
		||||
struct StartScreen final : public Screen {
 | 
			
		||||
	SDL_Renderer* _renderer;
 | 
			
		||||
	Theme& _theme;
 | 
			
		||||
	FileSelector _fss;
 | 
			
		||||
 | 
			
		||||
	bool _new_save {false};
 | 
			
		||||
	std::string _user_name {"unnamed-tomato"};
 | 
			
		||||
 | 
			
		||||
	bool _show_password {false};
 | 
			
		||||
	std::string _password;
 | 
			
		||||
 | 
			
		||||
	std::string tox_profile_path {"tomato.tox"};
 | 
			
		||||
	std::string _tox_profile_path {"unnamed-tomato.tox"};
 | 
			
		||||
	std::vector<std::string> queued_plugin_paths;
 | 
			
		||||
 | 
			
		||||
	StartScreen(void) = delete;
 | 
			
		||||
	StartScreen(SDL_Renderer* renderer);
 | 
			
		||||
	StartScreen(SDL_Renderer* renderer, Theme& theme);
 | 
			
		||||
	~StartScreen(void) = default;
 | 
			
		||||
 | 
			
		||||
	// return nullptr if not next
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,8 @@
 | 
			
		||||
 | 
			
		||||
#include "./image_loader_sdl_bmp.hpp"
 | 
			
		||||
#include "./image_loader_qoi.hpp"
 | 
			
		||||
#include "./image_loader_stb.hpp"
 | 
			
		||||
#include "./image_loader_webp.hpp"
 | 
			
		||||
#include "./image_loader_sdl_image.hpp"
 | 
			
		||||
 | 
			
		||||
#include <solanaceae/contact/components.hpp>
 | 
			
		||||
#include <solanaceae/tox_contacts/components.hpp>
 | 
			
		||||
@@ -24,7 +24,7 @@ ToxAvatarLoader::ToxAvatarLoader(Contact3Registry& cr) : _cr(cr) {
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSDLBMP>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderQOI>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderWebP>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSTB>());
 | 
			
		||||
	_image_loaders.push_back(std::make_unique<ImageLoaderSDLImage>());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static float getHue_6bytes(const uint8_t* data) {
 | 
			
		||||
@@ -187,7 +187,8 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
 | 
			
		||||
	if (!_cr.any_of<
 | 
			
		||||
		Contact::Components::ToxFriendPersistent,
 | 
			
		||||
		Contact::Components::ToxGroupPersistent,
 | 
			
		||||
		Contact::Components::ToxGroupPeerPersistent
 | 
			
		||||
		Contact::Components::ToxGroupPeerPersistent,
 | 
			
		||||
		Contact::Components::ID
 | 
			
		||||
	>(c)) {
 | 
			
		||||
		return std::nullopt;
 | 
			
		||||
	}
 | 
			
		||||
@@ -199,6 +200,12 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
 | 
			
		||||
		pixels = generateToxIdenticon(_cr.get<Contact::Components::ToxGroupPersistent>(c).chat_id);
 | 
			
		||||
	} else if (_cr.all_of<Contact::Components::ToxGroupPeerPersistent>(c)) {
 | 
			
		||||
		pixels = generateToxIdenticon(_cr.get<Contact::Components::ToxGroupPeerPersistent>(c).peer_key);
 | 
			
		||||
	} else if (_cr.all_of<Contact::Components::ID>(c)) {
 | 
			
		||||
		// TODO: should we really use toxidenticons for other protocols?
 | 
			
		||||
		// (this is required for self)
 | 
			
		||||
		auto id_copy = _cr.get<Contact::Components::ID>(c).data;
 | 
			
		||||
		id_copy.resize(32);
 | 
			
		||||
		pixels = generateToxIdenticon(id_copy);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TextureEntry new_entry;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
// meh, change this
 | 
			
		||||
#include <exception>
 | 
			
		||||
#include <system_error>
 | 
			
		||||
#include <toxencryptsave/toxencryptsave.h>
 | 
			
		||||
#include <tox/toxencryptsave.h>
 | 
			
		||||
 | 
			
		||||
#include <sodium.h>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -107,6 +107,12 @@ ToxFriendFauxOfflineMessaging::dfmc_Ret ToxFriendFauxOfflineMessaging::doFriendM
 | 
			
		||||
 | 
			
		||||
	const uint64_t ts_now = Message::getTimeMS();
 | 
			
		||||
 | 
			
		||||
	if (!_cr.all_of<Contact::Components::Self>(c)) {
 | 
			
		||||
		return dfmc_Ret::NO_MSG; // error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const auto self_c = _cr.get<Contact::Components::Self>(c).self;
 | 
			
		||||
 | 
			
		||||
	// filter for unconfirmed messages
 | 
			
		||||
 | 
			
		||||
	// we assume sorted
 | 
			
		||||
@@ -127,9 +133,8 @@ ToxFriendFauxOfflineMessaging::dfmc_Ret ToxFriendFauxOfflineMessaging::doFriendM
 | 
			
		||||
			continue; // skip
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// exclude
 | 
			
		||||
		if (mr->any_of<
 | 
			
		||||
				Message::Components::Remote::TimestampReceived // this acts like a tag, which is wrong in groups
 | 
			
		||||
		if (!mr->any_of<
 | 
			
		||||
				Message::Components::ReceivedBy
 | 
			
		||||
			>(msg)
 | 
			
		||||
		) {
 | 
			
		||||
			continue; // skip
 | 
			
		||||
@@ -139,6 +144,16 @@ ToxFriendFauxOfflineMessaging::dfmc_Ret ToxFriendFauxOfflineMessaging::doFriendM
 | 
			
		||||
			continue; // not outbound (in private)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const auto& ts_received = mr->get<Message::Components::ReceivedBy>(msg).ts;
 | 
			
		||||
		// not target
 | 
			
		||||
		if (ts_received.contains(c)) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		// needs to contain self
 | 
			
		||||
		if (!ts_received.contains(self_c)) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		valid_unsent = true;
 | 
			
		||||
 | 
			
		||||
		uint64_t msg_ts = msg_view.get<Message::Components::Timestamp>(msg).ts;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user