NX-Shell(Deko3D): Initial commit
46
.gitignore
vendored
@ -1,13 +1,39 @@
|
||||
*~
|
||||
*.exe
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
test
|
||||
tahoma12.c
|
||||
tahoma24.c
|
||||
*.zip
|
||||
build
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# NX-Shell
|
||||
*.nro
|
||||
*.elf
|
||||
*.nso
|
||||
*.pfs0
|
||||
*.nacp
|
||||
*.nro
|
||||
build/
|
||||
res/shaders
|
94
Makefile
@ -39,39 +39,39 @@ include $(DEVKITPRO)/libnx/switch_rules
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := libs/imgui libs/imgui/misc/freetype libs/libnsbmp libs/libnsgif source source/windows source/popups
|
||||
SOURCES := libs/imgui libs/imgui/misc/freetype libs/libnsbmp libs/libnsgif source source/imgui_nx source/popups source/tabs
|
||||
DATA := data
|
||||
INCLUDES := libs/imgui libs/libnsbmp libs/libnsgif include
|
||||
ROMFS := romfs
|
||||
INCLUDES := include include/imgui_nx libs/imgui libs/imgui/misc/freetype libs/libnsbmp libs/libnsgif libs/
|
||||
ROMFS := res
|
||||
|
||||
VERSION_MAJOR := 3
|
||||
VERSION_MINOR := 2
|
||||
VERSION_MICRO := 0
|
||||
# Output folders for autogenerated files in romfs
|
||||
OUT_SHADERS := shaders
|
||||
|
||||
APP_TITLE := NX-Shell
|
||||
APP_AUTHOR := Joel16
|
||||
APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}
|
||||
VERSION_MAJOR := 3
|
||||
VERSION_MINOR := 2
|
||||
VERSION_MICRO := 0
|
||||
|
||||
APP_TITLE := NX-Shell
|
||||
APP_AUTHOR := Joel16
|
||||
APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections $(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||
CFLAGS += `sdl2-config --cflags` `freetype-config --cflags`
|
||||
CFLAGS += `freetype-config --cflags`
|
||||
CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) -DVERSION_MINOR=$(VERSION_MINOR) -DVERSION_MICRO=$(VERSION_MICRO)
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -std=gnu++17 -fno-exceptions -fno-rtti -DIMGUI_IMPL_OPENGL_LOADER_GLAD \
|
||||
-DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_ENABLE_FREETYPE
|
||||
CXXFLAGS := $(CFLAGS) -std=gnu++17 -fno-exceptions -fno-rtti
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := `curl-config --libs` `freetype-config --libs` -lzzip -ljansson -lturbojpeg -ljpeg -lpng -lwebp \
|
||||
`sdl2-config --libs` -lglad -lEGL -lglapi -ldrm_nouveau -lnx -lm -lz
|
||||
LIBS := `curl-config --libs` `freetype-config --libs` -lturbojpeg -ljpeg -lpng -lwebp -ljansson -ldeko3dd -lnx
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
@ -98,6 +98,7 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
GLSLFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.glsl)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
@ -119,6 +120,18 @@ export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
ifneq ($(strip $(ROMFS)),)
|
||||
ROMFS_TARGETS :=
|
||||
ROMFS_FOLDERS :=
|
||||
ifneq ($(strip $(OUT_SHADERS)),)
|
||||
ROMFS_SHADERS := $(ROMFS)/$(OUT_SHADERS)
|
||||
ROMFS_TARGETS += $(patsubst %.glsl, $(ROMFS_SHADERS)/%.dksh, $(GLSLFILES))
|
||||
ROMFS_FOLDERS += $(ROMFS_SHADERS)
|
||||
endif
|
||||
|
||||
export ROMFS_DEPS := $(foreach file,$(ROMFS_TARGETS),$(CURDIR)/$(file))
|
||||
endif
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
@ -167,22 +180,55 @@ ifneq ($(ROMFS),)
|
||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
.PHONY: all clean
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
all: $(ROMFS_TARGETS) | $(BUILD)
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
@mkdir -p $@
|
||||
|
||||
ifneq ($(strip $(ROMFS_TARGETS)),)
|
||||
|
||||
$(ROMFS_TARGETS): | $(ROMFS_FOLDERS)
|
||||
|
||||
$(ROMFS_FOLDERS):
|
||||
@mkdir -p $@
|
||||
|
||||
$(ROMFS_SHADERS)/%_vsh.dksh: %_vsh.glsl
|
||||
@echo {vert} $(notdir $<)
|
||||
@uam -s vert -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_tcsh.dksh: %_tcsh.glsl
|
||||
@echo {tess_ctrl} $(notdir $<)
|
||||
@uam -s tess_ctrl -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_tesh.dksh: %_tesh.glsl
|
||||
@echo {tess_eval} $(notdir $<)
|
||||
@uam -s tess_eval -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_gsh.dksh: %_gsh.glsl
|
||||
@echo {geom} $(notdir $<)
|
||||
@uam -s geom -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_fsh.dksh: %_fsh.glsl
|
||||
@echo {frag} $(notdir $<)
|
||||
@uam -s frag -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%.dksh: %.glsl
|
||||
@echo {comp} $(notdir $<)
|
||||
@uam -s comp -o $@ $<
|
||||
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||
@rm -fr $(BUILD) $(ROMFS_FOLDERS) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||
else
|
||||
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
|
||||
@rm -fr $(BUILD) $(ROMFS_FOLDERS) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
|
||||
endif
|
||||
|
||||
|
||||
@ -200,9 +246,9 @@ ifeq ($(strip $(APP_JSON)),)
|
||||
all : $(OUTPUT).nro
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp $(ROMFS_DEPS)
|
||||
else
|
||||
$(OUTPUT).nro : $(OUTPUT).elf
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(ROMFS_DEPS)
|
||||
endif
|
||||
|
||||
else
|
||||
|
@ -1,9 +1,9 @@
|
||||
# NX-Shell (Next) [![Build Status](https://travis-ci.org/joel16/NX-Shell.svg?branch=master)](https://travis-ci.org/joel16/NX-Shell) ![Github latest downloads](https://img.shields.io/github/downloads/joel16/NX-Shell/total.svg)
|
||||
# NX-Shell (Deko3D) ![Github latest downloads](https://img.shields.io/github/downloads/joel16/NX-Shell/total.svg)
|
||||
|
||||
NX Shell is a multi-purpose file manager for the Nintendo Switch that aims towards handling various file types while keeping the basic necessities of a standard file manager. Initially the project was inspired by LineageOS/CyanogenMod's file manager for android, and even had a similar design approach to that of the famous Android file manager. However, it has been re-written from scratch, now using more up to date tools and libraries.
|
||||
|
||||
<p align="center">
|
||||
<img src="https://i.imgur.com/FfkFEkA.jpg" alt="NX-Shell (next) Screenshot" width="640" height="360"/>
|
||||
<img src="https://i.imgur.com/FfkFEkA.jpg" alt="NX-Shell (Deko3D) Screenshot" width="640" height="360"/>
|
||||
</p>
|
||||
|
||||
# Features:
|
||||
@ -21,3 +21,4 @@ NX Shell is a multi-purpose file manager for the Nintendo Switch that aims towar
|
||||
- **Preetisketch** for the banner.
|
||||
- **Dear ImGui developers and contributors** for the GUI.
|
||||
- **devkitPro maintainers and contributors** for libnx, devkitA64, and many other packages used by this project.
|
||||
- **mtheall/averne** for imgui::deko3d and imgui::nx used by this project.
|
||||
|
@ -15,7 +15,7 @@ typedef struct {
|
||||
extern config_t cfg;
|
||||
|
||||
namespace Config {
|
||||
int Save(config_t config);
|
||||
int Save(config_t &config);
|
||||
int Load(void);
|
||||
}
|
||||
|
||||
|
11
include/fs.h
@ -2,8 +2,8 @@
|
||||
#define NX_SHELL_FS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
|
||||
extern FsFileSystem *fs;
|
||||
extern FsFileSystem devices[4];
|
||||
@ -11,7 +11,6 @@ extern FsFileSystem devices[4];
|
||||
typedef enum FileType {
|
||||
FileTypeNone,
|
||||
FileTypeArchive,
|
||||
FileTypeAudio,
|
||||
FileTypeImage,
|
||||
FileTypeText
|
||||
} FileType;
|
||||
@ -21,7 +20,7 @@ namespace FS {
|
||||
bool DirExists(const char path[FS_MAX_PATH]);
|
||||
std::string GetFileExt(const std::string &filename);
|
||||
FileType GetFileType(const std::string &filename);
|
||||
Result GetDirList(char path[FS_MAX_PATH], std::vector<FsDirectoryEntry> &entries);
|
||||
Result GetDirList(const char path[FS_MAX_PATH], std::vector<FsDirectoryEntry> &entries);
|
||||
Result ChangeDirNext(const char path[FS_MAX_PATH], std::vector<FsDirectoryEntry> &entries);
|
||||
Result ChangeDirPrev(std::vector<FsDirectoryEntry> &entries);
|
||||
Result GetTimeStamp(FsDirectoryEntry *entry, FsTimeStampRaw *timestamp);
|
||||
@ -32,9 +31,9 @@ namespace FS {
|
||||
Result Paste(void);
|
||||
Result Move(void);
|
||||
Result GetFileSize(const char path[FS_MAX_PATH], s64 *size);
|
||||
Result GetFreeStorageSpace(s64 *size);
|
||||
Result GetTotalStorageSpace(s64 *size);
|
||||
Result GetUsedStorageSpace(s64 *size);
|
||||
Result GetFreeStorageSpace(s64 &size);
|
||||
Result GetTotalStorageSpace(s64 &size);
|
||||
Result GetUsedStorageSpace(s64 &size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,59 +1,20 @@
|
||||
#ifndef NX_SHELL_GUI_H
|
||||
#define NX_SHELL_GUI_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <SDL.h>
|
||||
#include <switch.h>
|
||||
#include <deko3d.hpp>
|
||||
|
||||
#include "textures.h"
|
||||
|
||||
enum MENU_STATES {
|
||||
MENU_STATE_FILEBROWSER,
|
||||
MENU_STATE_OPTIONS,
|
||||
MENU_STATE_DELETE,
|
||||
MENU_STATE_PROPERTIES,
|
||||
MENU_STATE_SETTINGS,
|
||||
MENU_STATE_IMAGEVIEWER,
|
||||
MENU_STATE_ARCHIVEEXTRACT,
|
||||
MENU_STATE_TEXTREADER
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
MENU_STATES state = MENU_STATE_FILEBROWSER;
|
||||
int selected = 0;
|
||||
std::vector<FsDirectoryEntry> entries;
|
||||
std::vector<bool> checked;
|
||||
std::vector<bool> checked_copy;
|
||||
std::string checked_cwd;
|
||||
int checked_count = 0;
|
||||
s64 used_storage = 0;
|
||||
s64 total_storage = 0;
|
||||
std::vector<Tex> textures;
|
||||
long unsigned int frame_count = 0;
|
||||
float zoom_factor = 1.0f;
|
||||
} MenuItem;
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
size_t buf_size;
|
||||
} TextReader;
|
||||
|
||||
extern SDL_Window *window;
|
||||
extern MenuItem item;
|
||||
extern TextReader text_reader;
|
||||
extern dk::UniqueDevice s_device;
|
||||
extern dk::UniqueQueue s_queue;
|
||||
extern dk::UniqueMemBlock s_imageMemBlock;
|
||||
extern dk::UniqueCmdBuf s_cmdBuf[2u];
|
||||
extern dk::SamplerDescriptor *s_samplerDescriptors;
|
||||
extern dk::ImageDescriptor *s_imageDescriptors;
|
||||
|
||||
namespace GUI {
|
||||
inline void ResetCheckbox(void) {
|
||||
item.checked.clear();
|
||||
item.checked_copy.clear();
|
||||
item.checked.resize(item.entries.size());
|
||||
item.checked.assign(item.checked.size(), false);
|
||||
item.checked_cwd.clear();
|
||||
item.checked_count = 0;
|
||||
};
|
||||
|
||||
int RenderLoop(void);
|
||||
bool Init(void);
|
||||
bool Loop(void);
|
||||
void Render(void);
|
||||
void Exit(void);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
87
include/imgui_nx/imgui_deko3d.h
Normal file
@ -0,0 +1,87 @@
|
||||
// ftpd is a server implementation based on the following:
|
||||
// - RFC 959 (https://tools.ietf.org/html/rfc959)
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (C) 2020 Michael Theall
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef CLASSIC
|
||||
#include <deko3d.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace imgui
|
||||
{
|
||||
namespace deko3d
|
||||
{
|
||||
/// \brief Initialize deko3d
|
||||
/// \param device_ deko3d device (used to allocate vertex/index and font texture buffers)
|
||||
/// \param queue_ deko3d queue (used to run command lists)
|
||||
/// \param cmdBuf_ Command buffer (used to build command lists)
|
||||
/// \param[out] samplerDescriptor_ Sampler descriptor for font texture
|
||||
/// \param[out] imageDescriptor_ Image descriptor for font texture
|
||||
/// \param fontTextureHandle_ Texture handle that references samplerDescriptor_ and imageDescriptor_
|
||||
/// \param imageCount_ Images in the swapchain
|
||||
void init (dk::UniqueDevice &device_,
|
||||
dk::UniqueQueue &queue_,
|
||||
dk::UniqueCmdBuf &cmdBuf_,
|
||||
dk::SamplerDescriptor &samplerDescriptor_,
|
||||
dk::ImageDescriptor &imageDescriptor_,
|
||||
DkResHandle fontTextureHandle_,
|
||||
unsigned imageCount_);
|
||||
|
||||
/// \brief Deinitialize deko3d
|
||||
void exit ();
|
||||
|
||||
/// \brief Render ImGui draw list
|
||||
/// \param device_ deko3d device (used to reallocate vertex/index buffers)
|
||||
/// \param queue_ deko3d queue (used to run command lists)
|
||||
/// \param cmdBuf_ Command buffer (used to build command lists)
|
||||
/// \param slot_ Image slot
|
||||
void render (dk::UniqueDevice &device_,
|
||||
dk::UniqueQueue &queue_,
|
||||
dk::UniqueCmdBuf &cmdBuf_,
|
||||
unsigned slot_);
|
||||
|
||||
/// \brief Make ImGui texture id from deko3d texture handle
|
||||
/// \param handle_ Texture handle
|
||||
inline void *makeTextureID (DkResHandle handle_)
|
||||
{
|
||||
return reinterpret_cast<void *> (static_cast<std::uintptr_t> (handle_));
|
||||
}
|
||||
|
||||
/// \brief Align power-of-two value
|
||||
/// \tparam T Value type
|
||||
/// \tparam U Alignment type
|
||||
/// \param size_ Value to align
|
||||
/// \param align_ Alignment
|
||||
template <typename T, typename U>
|
||||
constexpr inline std::uint32_t align (T const &size_, U const &align_)
|
||||
{
|
||||
return static_cast<std::uint32_t> (size_ + align_ - 1) & ~(align_ - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
38
include/imgui_nx/imgui_nx.h
Normal file
@ -0,0 +1,38 @@
|
||||
// ftpd is a server implementation based on the following:
|
||||
// - RFC 959 (https://tools.ietf.org/html/rfc959)
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (C) 2020 Michael Theall
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace imgui::nx {
|
||||
|
||||
bool init();
|
||||
void exit();
|
||||
std::uint64_t newFrame();
|
||||
|
||||
} // namespace imgui::nx
|
15
include/tabs.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef NX_SHELL_TABS_H
|
||||
#define NX_SHELL_TABS_H
|
||||
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
|
||||
#include "imgui.h"
|
||||
#include "windows.h"
|
||||
|
||||
namespace Tabs {
|
||||
void FileBrowser(WindowData &data);
|
||||
void Settings(WindowData &data);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,14 +1,14 @@
|
||||
#ifndef NX_SHELL_TEXTURES_H
|
||||
#define NX_SHELL_TEXTURES_H
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <string>
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
|
||||
#define NUM_FILE_ICONS 5
|
||||
#define NUM_FILE_ICONS 4
|
||||
|
||||
typedef struct {
|
||||
GLuint id = 0;
|
||||
u32 image_id = 1;
|
||||
u32 sampler_id = 1;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int delay = 0;
|
||||
|
@ -1,24 +1,33 @@
|
||||
#ifndef NX_SHELL_WINDOWS_H
|
||||
#define NX_SHELL_WINDOWS_H
|
||||
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
typedef struct {
|
||||
std::vector<FsDirectoryEntry> entries;
|
||||
std::vector<bool> checked;
|
||||
std::vector<bool> checked_copy;
|
||||
int checked_count = 0;
|
||||
s64 used_storage = 0;
|
||||
s64 total_storage = 0;
|
||||
} WindowData;
|
||||
|
||||
namespace Windows {
|
||||
inline void SetupWindow(void) {
|
||||
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiCond_Once);
|
||||
ImGui::SetNextWindowSize(ImVec2(1280.0f, 720.0f), ImGuiCond_Once);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
};
|
||||
|
||||
|
||||
inline void ExitWindow(void) {
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar();
|
||||
};
|
||||
|
||||
void FileBrowserWindow(bool *focus, bool *first_item);
|
||||
void ImageWindow(void);
|
||||
void SettingsWindow(void);
|
||||
void TextReaderWindow(void);
|
||||
|
||||
void MainWindow(WindowData &data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2021 Omar Cornut
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -27,23 +27,26 @@
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows.
|
||||
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
|
||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
|
||||
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty.
|
||||
#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
|
||||
#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty.
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. (imm32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||
#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||
#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||
#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
|
||||
#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
@ -58,7 +61,7 @@
|
||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
|
||||
//---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||
@ -67,8 +70,8 @@
|
||||
|
||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||
|
1171
libs/imgui/imgui.cpp
@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.82
|
||||
// dear imgui, v1.84
|
||||
// (headers)
|
||||
|
||||
// Help:
|
||||
@ -11,9 +11,9 @@
|
||||
// - FAQ http://dearimgui.org/faq
|
||||
// - Homepage & latest https://github.com/ocornut/imgui
|
||||
// - Releases & changelog https://github.com/ocornut/imgui/releases
|
||||
// - Gallery https://github.com/ocornut/imgui/issues/3488 (please post your screenshots/video there!)
|
||||
// - Gallery https://github.com/ocornut/imgui/issues/4451 (please post your screenshots/video there!)
|
||||
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
|
||||
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
|
||||
// - Wiki https://github.com/ocornut/imgui/wiki
|
||||
// - Issues & support https://github.com/ocornut/imgui/issues
|
||||
// - Discussions https://github.com/ocornut/imgui/discussions
|
||||
|
||||
@ -60,8 +60,8 @@ Index of this file:
|
||||
|
||||
// Version
|
||||
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
|
||||
#define IMGUI_VERSION "1.82"
|
||||
#define IMGUI_VERSION_NUM 18200
|
||||
#define IMGUI_VERSION "1.84.2"
|
||||
#define IMGUI_VERSION_NUM 18405
|
||||
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
|
||||
#define IMGUI_HAS_TABLE
|
||||
|
||||
@ -89,18 +89,31 @@ Index of this file:
|
||||
#endif
|
||||
|
||||
// Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions.
|
||||
#if !defined(IMGUI_USE_STB_SPRINTF) && defined(__clang__)
|
||||
#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1)))
|
||||
#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0)))
|
||||
#elif !defined(IMGUI_USE_STB_SPRINTF) && defined(__GNUC__) && defined(__MINGW32__)
|
||||
#if !defined(IMGUI_USE_STB_SPRINTF) && defined(__MINGW32__)
|
||||
#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1)))
|
||||
#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0)))
|
||||
#elif !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__))
|
||||
#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1)))
|
||||
#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0)))
|
||||
#else
|
||||
#define IM_FMTARGS(FMT)
|
||||
#define IM_FMTLIST(FMT)
|
||||
#endif
|
||||
|
||||
// Disable some of MSVC most aggressive Debug runtime checks in function header/footer (used in some simple/low-level functions)
|
||||
#if defined(_MSC_VER) && !defined(__clang__) && !defined(IMGUI_DEBUG_PARANOID)
|
||||
#define IM_MSVC_RUNTIME_CHECKS_OFF __pragma(runtime_checks("",off)) __pragma(check_stack(off)) __pragma(strict_gs_check(push,off))
|
||||
#define IM_MSVC_RUNTIME_CHECKS_RESTORE __pragma(runtime_checks("",restore)) __pragma(check_stack()) __pragma(strict_gs_check(pop))
|
||||
#else
|
||||
#define IM_MSVC_RUNTIME_CHECKS_OFF
|
||||
#define IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||
#endif
|
||||
|
||||
// Warnings
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6).
|
||||
#endif
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
@ -147,7 +160,7 @@ struct ImGuiTextBuffer; // Helper to hold and append into a text buf
|
||||
struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]")
|
||||
struct ImGuiViewport; // A Platform Window (always only one in 'master' branch), in the future may represent Platform Monitor
|
||||
|
||||
// Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file)
|
||||
// Enums/Flags (declared as int for compatibility with old C++, to allow using as flags without overhead, and to not pollute the top of this file)
|
||||
// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists!
|
||||
// In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||
// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
|
||||
@ -187,27 +200,22 @@ typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: f
|
||||
typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport
|
||||
typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild()
|
||||
|
||||
// Other types
|
||||
#ifndef ImTextureID // ImTextureID [configurable type: override in imconfig.h with '#define ImTextureID xxx']
|
||||
typedef void* ImTextureID; // User data for rendering backend to identify a texture. This is whatever to you want it to be! read the FAQ about ImTextureID for details.
|
||||
#endif
|
||||
typedef unsigned int ImGuiID; // A unique ID used by widgets, typically hashed from a stack of string.
|
||||
typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); // Callback function for ImGui::InputText()
|
||||
typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints()
|
||||
typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions()
|
||||
typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions()
|
||||
|
||||
// Character types
|
||||
// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display)
|
||||
typedef unsigned short ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings.
|
||||
typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings.
|
||||
#ifdef IMGUI_USE_WCHAR32 // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16]
|
||||
typedef ImWchar32 ImWchar;
|
||||
#else
|
||||
typedef ImWchar16 ImWchar;
|
||||
// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type]
|
||||
// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file.
|
||||
// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details.
|
||||
#ifndef ImTextureID
|
||||
typedef void* ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that)
|
||||
#endif
|
||||
|
||||
// Basic scalar data types
|
||||
// ImDrawIdx: vertex index. [Compile-time configurable type]
|
||||
// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended).
|
||||
// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file.
|
||||
#ifndef ImDrawIdx
|
||||
typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends)
|
||||
#endif
|
||||
|
||||
// Scalar data types
|
||||
typedef unsigned int ImGuiID;// A unique ID used by widgets (typically the result of hashing a stack of string)
|
||||
typedef signed char ImS8; // 8-bit signed integer
|
||||
typedef unsigned char ImU8; // 8-bit unsigned integer
|
||||
typedef signed short ImS16; // 16-bit signed integer
|
||||
@ -226,7 +234,25 @@ typedef signed long long ImS64; // 64-bit signed integer (post C++11)
|
||||
typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11)
|
||||
#endif
|
||||
|
||||
// 2D vector (often used to store positions or sizes)
|
||||
// Character types
|
||||
// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display)
|
||||
typedef unsigned short ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings.
|
||||
typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings.
|
||||
#ifdef IMGUI_USE_WCHAR32 // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16]
|
||||
typedef ImWchar32 ImWchar;
|
||||
#else
|
||||
typedef ImWchar16 ImWchar;
|
||||
#endif
|
||||
|
||||
// Callback and functions types
|
||||
typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); // Callback function for ImGui::InputText()
|
||||
typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints()
|
||||
typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions()
|
||||
typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions()
|
||||
|
||||
// ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type]
|
||||
// This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type.
|
||||
IM_MSVC_RUNTIME_CHECKS_OFF
|
||||
struct ImVec2
|
||||
{
|
||||
float x, y;
|
||||
@ -239,7 +265,7 @@ struct ImVec2
|
||||
#endif
|
||||
};
|
||||
|
||||
// 4D vector (often used to store floating-point colors)
|
||||
// ImVec4: 4D vector used to store clipping rectangles, colors etc. [Compile-time configurable type]
|
||||
struct ImVec4
|
||||
{
|
||||
float x, y, z, w;
|
||||
@ -249,6 +275,7 @@ struct ImVec4
|
||||
IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4.
|
||||
#endif
|
||||
};
|
||||
IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Dear ImGui end-user API functions
|
||||
@ -328,7 +355,8 @@ namespace ImGui
|
||||
IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x)
|
||||
IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y)
|
||||
|
||||
// Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin).
|
||||
// Window manipulation
|
||||
// - Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin).
|
||||
IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0, 0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc.
|
||||
IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin()
|
||||
IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Sizes will be rounded down. Use callback to apply non-trivial programmatic constraints.
|
||||
@ -340,7 +368,7 @@ namespace ImGui
|
||||
IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects.
|
||||
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed().
|
||||
IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus().
|
||||
IMGUI_API void SetWindowFontScale(float scale); // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes().
|
||||
IMGUI_API void SetWindowFontScale(float scale); // [OBSOLETE] set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes().
|
||||
IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position.
|
||||
IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis.
|
||||
IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state
|
||||
@ -376,7 +404,7 @@ namespace ImGui
|
||||
IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame().
|
||||
IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. always use this if you modify the style after NewFrame().
|
||||
IMGUI_API void PopStyleVar(int count = 1);
|
||||
IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets
|
||||
IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // == tab stop enable. Allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets
|
||||
IMGUI_API void PopAllowKeyboardFocus();
|
||||
IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame.
|
||||
IMGUI_API void PopButtonRepeat();
|
||||
@ -390,6 +418,7 @@ namespace ImGui
|
||||
IMGUI_API void PopTextWrapPos();
|
||||
|
||||
// Style read access
|
||||
// - Use the style editor (ShowStyleEditor() function) to interactively see what the colors are)
|
||||
IMGUI_API ImFont* GetFont(); // get current font
|
||||
IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied
|
||||
IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API
|
||||
@ -430,11 +459,15 @@ namespace ImGui
|
||||
IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets)
|
||||
|
||||
// ID stack/scopes
|
||||
// - Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most
|
||||
// likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them.
|
||||
// - The resulting ID are hashes of the entire stack.
|
||||
// Read the FAQ (docs/FAQ.md or http://dearimgui.org/faq) for more details about how ID are handled in dear imgui.
|
||||
// - Those questions are answered and impacted by understanding of the ID stack system:
|
||||
// - "Q: Why is my widget not reacting when I click on it?"
|
||||
// - "Q: How can I have widgets with an empty label?"
|
||||
// - "Q: How can I have multiple widgets with the same label?"
|
||||
// - Short version: ID are hashes of the entire ID stack. If you are creating widgets in a loop you most likely
|
||||
// want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them.
|
||||
// - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others.
|
||||
// - In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID,
|
||||
// - In this header file we use the "label"/"name" terminology to denote a string that will be displayed + used as an ID,
|
||||
// whereas "str_id" denote a string that is only used as an ID and not normally displayed.
|
||||
IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string).
|
||||
IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string).
|
||||
@ -507,8 +540,8 @@ namespace ImGui
|
||||
IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0);
|
||||
IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0);
|
||||
IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL, ImGuiSliderFlags flags = 0);
|
||||
IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0);
|
||||
IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0);
|
||||
IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0);
|
||||
IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0);
|
||||
|
||||
// Widgets: Regular Sliders
|
||||
// - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds.
|
||||
@ -597,7 +630,7 @@ namespace ImGui
|
||||
IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1);
|
||||
|
||||
// Widgets: Data Plotting
|
||||
// - Consider using ImPlot (https://github.com/epezent/implot)
|
||||
// - Consider using ImPlot (https://github.com/epezent/implot) which is much better!
|
||||
IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
|
||||
IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));
|
||||
IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
|
||||
@ -614,13 +647,14 @@ namespace ImGui
|
||||
// - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar.
|
||||
// - Use BeginMainMenuBar() to create a menu bar at the top of the screen and append to it.
|
||||
// - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it.
|
||||
// - Not that MenuItem() keyboardshortcuts are displayed as a convenience but _not processed_ by Dear ImGui at the moment.
|
||||
IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window).
|
||||
IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true!
|
||||
IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar.
|
||||
IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true!
|
||||
IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true!
|
||||
IMGUI_API void EndMenu(); // only call EndMenu() if BeginMenu() returns true!
|
||||
IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment
|
||||
IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated.
|
||||
IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL
|
||||
|
||||
// Tooltips
|
||||
@ -638,30 +672,36 @@ namespace ImGui
|
||||
// - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered().
|
||||
// - IMPORTANT: Popup identifiers are relative to the current ID stack, so OpenPopup and BeginPopup generally needs to be at the same level of the stack.
|
||||
// This is sometimes leading to confusing mistakes. May rework this in the future.
|
||||
|
||||
// Popups: begin/end functions
|
||||
// - BeginPopup(): query popup state, if open start appending into the window. Call EndPopup() afterwards. ImGuiWindowFlags are forwarded to the window.
|
||||
// - BeginPopupModal(): block every interactions behind the window, cannot be closed by user, add a dimming background, has a title bar.
|
||||
IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it.
|
||||
IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // return true if the modal is open, and you can start outputting to it.
|
||||
IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true!
|
||||
|
||||
// Popups: open/close functions
|
||||
// - OpenPopup(): set popup state to open. ImGuiPopupFlags are available for opening options.
|
||||
// - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
|
||||
// - CloseCurrentPopup(): use inside the BeginPopup()/EndPopup() scope to close manually.
|
||||
// - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options).
|
||||
// - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup().
|
||||
// - Use IsWindowAppearing() after BeginPopup() to tell if a window just opened.
|
||||
IMGUI_API void OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0); // call to mark popup as open (don't call every frame!).
|
||||
IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. return true when just opened. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors)
|
||||
IMGUI_API void OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags = 0); // id overload to facilitate calling from nested stacks
|
||||
IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. Default to ImGuiPopupFlags_MouseButtonRight == 1. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors)
|
||||
IMGUI_API void CloseCurrentPopup(); // manually close the popup we have begin-ed into.
|
||||
|
||||
// Popups: open+begin combined functions helpers
|
||||
// - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking.
|
||||
// - They are convenient to easily create context menus, hence the name.
|
||||
// - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future.
|
||||
// - IMPORTANT: we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight.
|
||||
IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp!
|
||||
IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked on last item. Use str_id==NULL to associate the popup to previous item. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp!
|
||||
IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);// open+begin popup when clicked on current window.
|
||||
IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked in void (where there are no windows).
|
||||
// Popups: test function
|
||||
|
||||
// Popups: query functions
|
||||
// - IsPopupOpen(): return true if the popup is open at the current BeginPopup() level of the popup stack.
|
||||
// - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId: return true if any popup is open at the current BeginPopup() level of the popup stack.
|
||||
// - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId + ImGuiPopupFlags_AnyPopupLevel: return true if any popup is open.
|
||||
@ -697,6 +737,7 @@ namespace ImGui
|
||||
IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row.
|
||||
IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last column). Return true when column is visible.
|
||||
IMGUI_API bool TableSetColumnIndex(int column_n); // append into the specified column. Return true when column is visible.
|
||||
|
||||
// Tables: Headers & Columns declaration
|
||||
// - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc.
|
||||
// - Use TableHeadersRow() to create a header row and automatically submit a TableHeader() for each column.
|
||||
@ -709,6 +750,7 @@ namespace ImGui
|
||||
IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled.
|
||||
IMGUI_API void TableHeadersRow(); // submit all headers cells based on data provided to TableSetupColumn() + submit context menu
|
||||
IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used)
|
||||
|
||||
// Tables: Sorting
|
||||
// - Call TableGetSortSpecs() to retrieve latest sort specs for the table. NULL when not sorting.
|
||||
// - When 'SpecsDirty == true' you should sort your data. It will be true when sorting specs have changed
|
||||
@ -716,6 +758,7 @@ namespace ImGui
|
||||
// wastefully sort your data every frame!
|
||||
// - Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable().
|
||||
IMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs(); // get latest sort specs for the table (NULL if not sorting).
|
||||
|
||||
// Tables: Miscellaneous functions
|
||||
// - Functions args 'int column_n' treat the default value of -1 as the same as passing the current column index.
|
||||
IMGUI_API int TableGetColumnCount(); // return number of columns (value passed to BeginTable)
|
||||
@ -723,9 +766,10 @@ namespace ImGui
|
||||
IMGUI_API int TableGetRowIndex(); // return current row index.
|
||||
IMGUI_API const char* TableGetColumnName(int column_n = -1); // return "" if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column.
|
||||
IMGUI_API ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1); // return column flags so you can query their Enabled/Visible/Sorted/Hovered status flags. Pass -1 to use current column.
|
||||
IMGUI_API void TableSetColumnEnabled(int column_n, bool v);// change user accessible enabled/disabled state of a column. Set to false to hide the column. User can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody)
|
||||
IMGUI_API void TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n = -1); // change the color of a cell, row, or column. See ImGuiTableBgTarget_ flags for details.
|
||||
|
||||
// Legacy Columns API (2020: prefer using Tables!)
|
||||
// Legacy Columns API (prefer using Tables!)
|
||||
// - You can also use SameLine(pos_x) to mimic simplified columns.
|
||||
IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true);
|
||||
IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished
|
||||
@ -767,6 +811,12 @@ namespace ImGui
|
||||
IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true!
|
||||
IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type.
|
||||
|
||||
// Disabling [BETA API]
|
||||
// - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors)
|
||||
// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it.
|
||||
IMGUI_API void BeginDisabled(bool disabled = true);
|
||||
IMGUI_API void EndDisabled();
|
||||
|
||||
// Clipping
|
||||
// - Mouse hovering is affected by ImGui::PushClipRect() calls, unlike direct calls to ImDrawList::PushClipRect() which are render only.
|
||||
IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect);
|
||||
@ -777,7 +827,7 @@ namespace ImGui
|
||||
IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window.
|
||||
IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget.
|
||||
|
||||
// Item/Widgets Utilities
|
||||
// Item/Widgets Utilities and Query Functions
|
||||
// - Most of the functions are referring to the previous Item that has been submitted.
|
||||
// - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions.
|
||||
IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options.
|
||||
@ -802,7 +852,7 @@ namespace ImGui
|
||||
// - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows.
|
||||
// - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports.
|
||||
// - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode.
|
||||
IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport.
|
||||
IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport. This can never be NULL.
|
||||
|
||||
// Miscellaneous Utilities
|
||||
IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped.
|
||||
@ -866,12 +916,14 @@ namespace ImGui
|
||||
// Settings/.Ini Utilities
|
||||
// - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini").
|
||||
// - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually.
|
||||
// - Important: default value "imgui.ini" is relative to current working dir! Most apps will want to lock this to an absolute path (e.g. same path as executables).
|
||||
IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename).
|
||||
IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source.
|
||||
IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename); // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext).
|
||||
IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings.
|
||||
|
||||
// Debug Utilities
|
||||
// - This is used by the IMGUI_CHECKVERSION() macro.
|
||||
IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx); // This is called by IMGUI_CHECKVERSION() macro.
|
||||
|
||||
// Memory Allocators
|
||||
@ -912,7 +964,7 @@ enum ImGuiWindowFlags_
|
||||
ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient)
|
||||
ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window
|
||||
ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB)
|
||||
ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker.
|
||||
ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
|
||||
ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
|
||||
ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse,
|
||||
ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
|
||||
@ -952,10 +1004,7 @@ enum ImGuiInputTextFlags_
|
||||
ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID().
|
||||
ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input)
|
||||
ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this)
|
||||
ImGuiInputTextFlags_CallbackEdit = 1 << 19, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)
|
||||
// [Internal]
|
||||
ImGuiInputTextFlags_Multiline = 1 << 20, // For internal use by InputTextMultiline()
|
||||
ImGuiInputTextFlags_NoMarkEdited = 1 << 21 // For internal use by functions using InputText() before reformatting data
|
||||
ImGuiInputTextFlags_CallbackEdit = 1 << 19 // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)
|
||||
|
||||
// Obsolete names (will be removed soon)
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
@ -1053,7 +1102,7 @@ enum ImGuiTabBarFlags_
|
||||
enum ImGuiTabItemFlags_
|
||||
{
|
||||
ImGuiTabItemFlags_None = 0,
|
||||
ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. Also: tab is selected on closure and closure is deferred by one frame to allow code to undo it without flicker.
|
||||
ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Display a dot next to the title + tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
|
||||
ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programmatically make the tab selected when calling BeginTabItem()
|
||||
ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
|
||||
ImGuiTabItemFlags_NoPushId = 1 << 3, // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem()
|
||||
@ -1147,28 +1196,30 @@ enum ImGuiTableColumnFlags_
|
||||
{
|
||||
// Input configuration flags
|
||||
ImGuiTableColumnFlags_None = 0,
|
||||
ImGuiTableColumnFlags_DefaultHide = 1 << 0, // Default as a hidden/disabled column.
|
||||
ImGuiTableColumnFlags_DefaultSort = 1 << 1, // Default as a sorting column.
|
||||
ImGuiTableColumnFlags_WidthStretch = 1 << 2, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _SizingStretchSame or _SizingStretchProp).
|
||||
ImGuiTableColumnFlags_WidthFixed = 1 << 3, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _SizingFixedFit and table is resizable).
|
||||
ImGuiTableColumnFlags_NoResize = 1 << 4, // Disable manual resizing.
|
||||
ImGuiTableColumnFlags_NoReorder = 1 << 5, // Disable manual reordering this column, this will also prevent other columns from crossing over this column.
|
||||
ImGuiTableColumnFlags_NoHide = 1 << 6, // Disable ability to hide/disable this column.
|
||||
ImGuiTableColumnFlags_NoClip = 1 << 7, // Disable clipping for this column (all NoClip columns will render in a same draw command).
|
||||
ImGuiTableColumnFlags_NoSort = 1 << 8, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table).
|
||||
ImGuiTableColumnFlags_NoSortAscending = 1 << 9, // Disable ability to sort in the ascending direction.
|
||||
ImGuiTableColumnFlags_NoSortDescending = 1 << 10, // Disable ability to sort in the descending direction.
|
||||
ImGuiTableColumnFlags_NoHeaderWidth = 1 << 11, // Disable header text width contribution to automatic column width.
|
||||
ImGuiTableColumnFlags_PreferSortAscending = 1 << 12, // Make the initial sort direction Ascending when first sorting on this column (default).
|
||||
ImGuiTableColumnFlags_PreferSortDescending = 1 << 13, // Make the initial sort direction Descending when first sorting on this column.
|
||||
ImGuiTableColumnFlags_IndentEnable = 1 << 14, // Use current Indent value when entering cell (default for column 0).
|
||||
ImGuiTableColumnFlags_IndentDisable = 1 << 15, // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes _within_ the cell will still be honored.
|
||||
ImGuiTableColumnFlags_Disabled = 1 << 0, // Overriding/master disable flag: hide column, won't show in context menu (unlike calling TableSetColumnEnabled() which manipulates the user accessible state)
|
||||
ImGuiTableColumnFlags_DefaultHide = 1 << 1, // Default as a hidden/disabled column.
|
||||
ImGuiTableColumnFlags_DefaultSort = 1 << 2, // Default as a sorting column.
|
||||
ImGuiTableColumnFlags_WidthStretch = 1 << 3, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _SizingStretchSame or _SizingStretchProp).
|
||||
ImGuiTableColumnFlags_WidthFixed = 1 << 4, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _SizingFixedFit and table is resizable).
|
||||
ImGuiTableColumnFlags_NoResize = 1 << 5, // Disable manual resizing.
|
||||
ImGuiTableColumnFlags_NoReorder = 1 << 6, // Disable manual reordering this column, this will also prevent other columns from crossing over this column.
|
||||
ImGuiTableColumnFlags_NoHide = 1 << 7, // Disable ability to hide/disable this column.
|
||||
ImGuiTableColumnFlags_NoClip = 1 << 8, // Disable clipping for this column (all NoClip columns will render in a same draw command).
|
||||
ImGuiTableColumnFlags_NoSort = 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table).
|
||||
ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction.
|
||||
ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction.
|
||||
ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will not submit label for this column. Convenient for some small columns. Name will still appear in context menu.
|
||||
ImGuiTableColumnFlags_NoHeaderWidth = 1 << 13, // Disable header text width contribution to automatic column width.
|
||||
ImGuiTableColumnFlags_PreferSortAscending = 1 << 14, // Make the initial sort direction Ascending when first sorting on this column (default).
|
||||
ImGuiTableColumnFlags_PreferSortDescending = 1 << 15, // Make the initial sort direction Descending when first sorting on this column.
|
||||
ImGuiTableColumnFlags_IndentEnable = 1 << 16, // Use current Indent value when entering cell (default for column 0).
|
||||
ImGuiTableColumnFlags_IndentDisable = 1 << 17, // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes _within_ the cell will still be honored.
|
||||
|
||||
// Output status flags, read-only via TableGetColumnFlags()
|
||||
ImGuiTableColumnFlags_IsEnabled = 1 << 20, // Status: is enabled == not hidden by user/api (referred to as "Hide" in _DefaultHide and _NoHide) flags.
|
||||
ImGuiTableColumnFlags_IsVisible = 1 << 21, // Status: is visible == is enabled AND not clipped by scrolling.
|
||||
ImGuiTableColumnFlags_IsSorted = 1 << 22, // Status: is currently part of the sort specs
|
||||
ImGuiTableColumnFlags_IsHovered = 1 << 23, // Status: is hovered by mouse
|
||||
ImGuiTableColumnFlags_IsEnabled = 1 << 24, // Status: is enabled == not hidden by user/api (referred to as "Hide" in _DefaultHide and _NoHide) flags.
|
||||
ImGuiTableColumnFlags_IsVisible = 1 << 25, // Status: is visible == is enabled AND not clipped by scrolling.
|
||||
ImGuiTableColumnFlags_IsSorted = 1 << 26, // Status: is currently part of the sort specs
|
||||
ImGuiTableColumnFlags_IsHovered = 1 << 27, // Status: is hovered by mouse
|
||||
|
||||
// [Internal] Combinations and masks
|
||||
ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed,
|
||||
@ -1355,13 +1406,12 @@ enum ImGuiNavInput_
|
||||
|
||||
// [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them.
|
||||
// Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[].
|
||||
ImGuiNavInput_KeyMenu_, // toggle menu // = io.KeyAlt
|
||||
ImGuiNavInput_KeyLeft_, // move left // = Arrow keys
|
||||
ImGuiNavInput_KeyRight_, // move right
|
||||
ImGuiNavInput_KeyUp_, // move up
|
||||
ImGuiNavInput_KeyDown_, // move down
|
||||
ImGuiNavInput_COUNT,
|
||||
ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyMenu_
|
||||
ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyLeft_
|
||||
};
|
||||
|
||||
// Configuration flags stored in io.ConfigFlags. Set by user/application.
|
||||
@ -1460,6 +1510,7 @@ enum ImGuiStyleVar_
|
||||
{
|
||||
// Enum name --------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions)
|
||||
ImGuiStyleVar_Alpha, // float Alpha
|
||||
ImGuiStyleVar_DisabledAlpha, // float DisabledAlpha
|
||||
ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding
|
||||
ImGuiStyleVar_WindowRounding, // float WindowRounding
|
||||
ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize
|
||||
@ -1531,13 +1582,13 @@ enum ImGuiColorEditFlags_
|
||||
|
||||
// Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably don't want to
|
||||
// override them in most of your calls. Let the user choose via the option menu and/or call SetColorEditOptions() once during startup.
|
||||
ImGuiColorEditFlags__OptionsDefault = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar,
|
||||
ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar,
|
||||
|
||||
// [Internal] Masks
|
||||
ImGuiColorEditFlags__DisplayMask = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex,
|
||||
ImGuiColorEditFlags__DataTypeMask = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float,
|
||||
ImGuiColorEditFlags__PickerMask = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar,
|
||||
ImGuiColorEditFlags__InputMask = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV
|
||||
ImGuiColorEditFlags_DisplayMask_ = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex,
|
||||
ImGuiColorEditFlags_DataTypeMask_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float,
|
||||
ImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar,
|
||||
ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV
|
||||
|
||||
// Obsolete names (will be removed)
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
@ -1631,6 +1682,7 @@ template<typename T> void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p
|
||||
// Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IM_MSVC_RUNTIME_CHECKS_OFF
|
||||
template<typename T>
|
||||
struct ImVector
|
||||
{
|
||||
@ -1647,7 +1699,11 @@ struct ImVector
|
||||
inline ImVector() { Size = Capacity = 0; Data = NULL; }
|
||||
inline ImVector(const ImVector<T>& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
|
||||
inline ImVector<T>& operator=(const ImVector<T>& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
|
||||
inline ~ImVector() { if (Data) IM_FREE(Data); }
|
||||
inline ~ImVector() { if (Data) IM_FREE(Data); } // Important: does not destruct anything
|
||||
|
||||
inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } // Important: does not destruct anything
|
||||
inline void clear_delete() { for (int n = 0; n < Size; n++) IM_DELETE(Data[n]); clear(); } // Important: never called automatically! always explicit.
|
||||
inline void clear_destruct() { for (int n = 0; n < Size; n++) Data[n].~T(); clear(); } // Important: never called automatically! always explicit.
|
||||
|
||||
inline bool empty() const { return Size == 0; }
|
||||
inline int size() const { return Size; }
|
||||
@ -1657,7 +1713,6 @@ struct ImVector
|
||||
inline T& operator[](int i) { IM_ASSERT(i >= 0 && i < Size); return Data[i]; }
|
||||
inline const T& operator[](int i) const { IM_ASSERT(i >= 0 && i < Size); return Data[i]; }
|
||||
|
||||
inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } }
|
||||
inline T* begin() { return Data; }
|
||||
inline const T* begin() const { return Data; }
|
||||
inline T* end() { return Data + Size; }
|
||||
@ -1689,6 +1744,7 @@ struct ImVector
|
||||
inline bool find_erase_unsorted(const T& v) { const T* it = find(v); if (it < Data + Size) { erase_unsorted(it); return true; } return false; }
|
||||
inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; return (int)off; }
|
||||
};
|
||||
IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] ImGuiStyle
|
||||
@ -1701,6 +1757,7 @@ struct ImVector
|
||||
struct ImGuiStyle
|
||||
{
|
||||
float Alpha; // Global alpha applies to everything in Dear ImGui.
|
||||
float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha.
|
||||
ImVec2 WindowPadding; // Padding within a window.
|
||||
float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
|
||||
float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
|
||||
@ -1763,7 +1820,7 @@ struct ImGuiIO
|
||||
ImVec2 DisplaySize; // <unset> // Main display size, in pixels (generally == GetMainViewport()->Size)
|
||||
float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds.
|
||||
float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds.
|
||||
const char* IniFilename; // = "imgui.ini" // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory.
|
||||
const char* IniFilename; // = "imgui.ini" // Path to .ini file (important: default "imgui.ini" is relative to current working dir!). Set NULL to disable automatic .ini loading/saving or if you want to manually call LoadIniSettingsXXX() / SaveIniSettingsXXX() functions.
|
||||
const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
|
||||
float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds.
|
||||
float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels.
|
||||
@ -1831,6 +1888,7 @@ struct ImGuiIO
|
||||
IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue new character input from an UTF-16 character, it can be a surrogate
|
||||
IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string
|
||||
IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually
|
||||
IMGUI_API void AddFocusEvent(bool focused); // Notifies Dear ImGui when hosting platform windows lose or gain input focus
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Output - Updated by NewFrame() or EndFrame()/Render()
|
||||
@ -1845,7 +1903,7 @@ struct ImGuiIO
|
||||
bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving!
|
||||
bool NavActive; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag.
|
||||
bool NavVisible; // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events).
|
||||
float Framerate; // Application framerate estimate, in frame per second. Solely for convenience. Rolling average estimation based on io.DeltaTime over 120 frames.
|
||||
float Framerate; // Rough estimate of application framerate, in frame per second. Solely for convenience. Rolling average estimation based on io.DeltaTime over 120 frames.
|
||||
int MetricsRenderVertices; // Vertices output during last call to Render()
|
||||
int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3
|
||||
int MetricsRenderWindows; // Number of visible windows
|
||||
@ -1858,6 +1916,7 @@ struct ImGuiIO
|
||||
//------------------------------------------------------------------
|
||||
|
||||
ImGuiKeyModFlags KeyMods; // Key mods flags (same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags), updated by NewFrame()
|
||||
ImGuiKeyModFlags KeyModsPrev; // Previous key mods
|
||||
ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid)
|
||||
ImVec2 MouseClickedPos[5]; // Position at time of clicking
|
||||
double MouseClickedTime[5]; // Time of last click (used to figure out double-click)
|
||||
@ -2224,14 +2283,10 @@ struct ImDrawCmd
|
||||
void* UserCallbackData; // 4-8 // The draw callback code can access this.
|
||||
|
||||
ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed
|
||||
};
|
||||
|
||||
// Vertex index, default to 16-bit
|
||||
// To allow large meshes with 16-bit indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer backend (recommended).
|
||||
// To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in imconfig.h.
|
||||
#ifndef ImDrawIdx
|
||||
typedef unsigned short ImDrawIdx;
|
||||
#endif
|
||||
// Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature)
|
||||
inline ImTextureID GetTexID() const { return TextureId; }
|
||||
};
|
||||
|
||||
// Vertex layout
|
||||
#ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT
|
||||
@ -2436,6 +2491,7 @@ struct ImDrawList
|
||||
IMGUI_API void _ResetForNewFrame();
|
||||
IMGUI_API void _ClearFreeMemory();
|
||||
IMGUI_API void _PopUnusedDrawCmd();
|
||||
IMGUI_API void _TryMergeDrawCmds();
|
||||
IMGUI_API void _OnChangedClipRect();
|
||||
IMGUI_API void _OnChangedTextureID();
|
||||
IMGUI_API void _OnChangedVtxOffset();
|
||||
@ -2586,7 +2642,7 @@ struct ImFontAtlas
|
||||
IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions.
|
||||
IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel
|
||||
IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel
|
||||
bool IsBuilt() const { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); }
|
||||
bool IsBuilt() const { return Fonts.Size > 0 && TexReady; } // Bit ambiguous: used to detect when user didn't built texture but effectively we should check TexID != 0 except that would be backend dependent...
|
||||
void SetTexID(ImTextureID id) { TexID = id; }
|
||||
|
||||
//-------------------------------------------
|
||||
@ -2636,6 +2692,7 @@ struct ImFontAtlas
|
||||
|
||||
// [Internal]
|
||||
// NB: Access texture data via GetTexData*() calls! Which will setup a default font for you.
|
||||
bool TexReady; // Set when texture was built matching current font input
|
||||
bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format.
|
||||
unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight
|
||||
unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4
|
||||
@ -2658,7 +2715,7 @@ struct ImFontAtlas
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+
|
||||
typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+
|
||||
//typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -2680,8 +2737,9 @@ struct ImFont
|
||||
ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into
|
||||
const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData
|
||||
short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont.
|
||||
ImWchar FallbackChar; // 2 // in // = '?' // Replacement character if a glyph isn't found. Only set via SetFallbackChar()
|
||||
ImWchar EllipsisChar; // 2 // out // = -1 // Character used for ellipsis rendering.
|
||||
ImWchar FallbackChar; // 2 // out // = FFFD/'?' // Character used if a glyph isn't found.
|
||||
ImWchar EllipsisChar; // 2 // out // = '...' // Character used for ellipsis rendering.
|
||||
ImWchar DotChar; // 2 // out // = '.' // Character used for ellipsis rendering (if a single '...' character isn't found)
|
||||
bool DirtyLookupTables; // 1 // out //
|
||||
float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale()
|
||||
float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize]
|
||||
@ -2711,7 +2769,6 @@ struct ImFont
|
||||
IMGUI_API void AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x);
|
||||
IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built.
|
||||
IMGUI_API void SetGlyphVisible(ImWchar c, bool visible);
|
||||
IMGUI_API void SetFallbackChar(ImWchar c);
|
||||
IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last);
|
||||
};
|
||||
|
||||
@ -2719,7 +2776,7 @@ struct ImFont
|
||||
// [SECTION] Viewports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Flags stored in ImGuiViewport::Flags
|
||||
// Flags stored in ImGuiViewport::Flags, giving indications to the platform backends.
|
||||
enum ImGuiViewportFlags_
|
||||
{
|
||||
ImGuiViewportFlags_None = 0,
|
||||
@ -2788,8 +2845,18 @@ namespace ImGui
|
||||
static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); }
|
||||
// OBSOLETED in 1.70 (from May 2019)
|
||||
static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; }
|
||||
// OBSOLETED in 1.69 (from Mar 2019)
|
||||
static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); }
|
||||
|
||||
// Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE)
|
||||
//static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } // OBSOLETED in 1.69 (from Mar 2019)
|
||||
//static inline void SetScrollHere(float ratio = 0.5f) { SetScrollHereY(ratio); } // OBSOLETED in 1.66 (from Nov 2018)
|
||||
//static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } // OBSOLETED in 1.63 (from Aug 2018)
|
||||
//static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } // OBSOLETED in 1.60 (from Apr 2018)
|
||||
//static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018)
|
||||
//static inline void ShowTestWindow() { return ShowDemoWindow(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)
|
||||
//static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)
|
||||
//static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)
|
||||
//static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)
|
||||
//static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)
|
||||
}
|
||||
|
||||
// OBSOLETED in 1.82 (from Mars 2021): flags for AddRect(), AddRectFilled(), AddImageRounded(), PathRect()
|
||||
@ -2818,6 +2885,10 @@ enum ImDrawCornerFlags_
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
// Include imgui_user.h at the end of imgui.h (convenient for user to only explicitly include vanilla imgui.h)
|
||||
#ifdef IMGUI_INCLUDE_IMGUI_USER_H
|
||||
#include "imgui_user.h"
|
||||
|
@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.82
|
||||
// dear imgui, v1.84
|
||||
// (drawing and font code)
|
||||
|
||||
/*
|
||||
@ -54,9 +54,12 @@ Index of this file:
|
||||
|
||||
// Visual Studio warnings
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable: 4127) // condition expression is constant
|
||||
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
||||
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
|
||||
#pragma warning (disable: 4127) // condition expression is constant
|
||||
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
||||
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
|
||||
#pragma warning (disable: 6255) // [Static Analyzer] _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead.
|
||||
#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
|
||||
#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer)
|
||||
#endif
|
||||
|
||||
// Clang/GCC warnings with -Weverything
|
||||
@ -105,6 +108,9 @@ namespace IMGUI_STB_NAMESPACE
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration
|
||||
#pragma warning (disable: 6011) // (stb_rectpack) Dereferencing NULL pointer 'cur->next'.
|
||||
#pragma warning (disable: 6385) // (stb_truetype) Reading invalid data from 'buffer': the readable size is '_Old_3`kernel_width' bytes, but '3' bytes may be read.
|
||||
#pragma warning (disable: 28182) // (stb_rectpack) Dereferencing NULL pointer. 'cur' contains the same NULL value as 'cur->next' did.
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
@ -145,7 +151,7 @@ namespace IMGUI_STB_NAMESPACE
|
||||
#define STBTT_sqrt(x) ImSqrt(x)
|
||||
#define STBTT_pow(x,y) ImPow(x,y)
|
||||
#define STBTT_fabs(x) ImFabs(x)
|
||||
#define STBTT_ifloor(x) ((int)ImFloorStd(x))
|
||||
#define STBTT_ifloor(x) ((int)ImFloorSigned(x))
|
||||
#define STBTT_iceil(x) ((int)ImCeil(x))
|
||||
#define STBTT_STATIC
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
@ -485,6 +491,18 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
|
||||
#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset
|
||||
#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset
|
||||
|
||||
// Try to merge two last draw commands
|
||||
void ImDrawList::_TryMergeDrawCmds()
|
||||
{
|
||||
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
||||
ImDrawCmd* prev_cmd = curr_cmd - 1;
|
||||
if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL)
|
||||
{
|
||||
prev_cmd->ElemCount += curr_cmd->ElemCount;
|
||||
CmdBuffer.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack.
|
||||
// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only.
|
||||
void ImDrawList::_OnChangedClipRect()
|
||||
@ -687,9 +705,11 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c
|
||||
}
|
||||
|
||||
// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds.
|
||||
// Those macros expects l-values.
|
||||
#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0)
|
||||
#define IM_FIXNORMAL2F(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 < 0.5f) d2 = 0.5f; float inv_lensq = 1.0f / d2; VX *= inv_lensq; VY *= inv_lensq; } while (0)
|
||||
// - Those macros expects l-values and need to be used as their own statement.
|
||||
// - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to runtime with debug compilers.
|
||||
#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } (void)0
|
||||
#define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366)
|
||||
#define IM_FIXNORMAL2F(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } (void)0
|
||||
|
||||
// TODO: Thickness anti-aliased lines cap are missing their AA fringe.
|
||||
// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
|
||||
@ -1037,7 +1057,6 @@ void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_
|
||||
_Path.push_back(center);
|
||||
return;
|
||||
}
|
||||
IM_ASSERT(a_min_sample <= a_max_sample);
|
||||
|
||||
// Calculate arc auto segment step size
|
||||
if (a_step <= 0)
|
||||
@ -1046,17 +1065,7 @@ void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_
|
||||
// Make sure we never do steps larger than one quarter of the circle
|
||||
a_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4);
|
||||
|
||||
// Normalize a_min_sample to always start lie in [0..IM_DRAWLIST_ARCFAST_SAMPLE_MAX] range.
|
||||
if (a_min_sample < 0)
|
||||
{
|
||||
int normalized_sample = a_min_sample % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||
if (normalized_sample < 0)
|
||||
normalized_sample += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||
a_max_sample += (normalized_sample - a_min_sample);
|
||||
a_min_sample = normalized_sample;
|
||||
}
|
||||
|
||||
const int sample_range = a_max_sample - a_min_sample;
|
||||
const int sample_range = ImAbs(a_max_sample - a_min_sample);
|
||||
const int a_next_step = a_step;
|
||||
|
||||
int samples = sample_range + 1;
|
||||
@ -1082,16 +1091,40 @@ void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_
|
||||
ImVec2* out_ptr = _Path.Data + (_Path.Size - samples);
|
||||
|
||||
int sample_index = a_min_sample;
|
||||
for (int a = a_min_sample; a <= a_max_sample; a += a_step, sample_index += a_step, a_step = a_next_step)
|
||||
if (sample_index < 0 || sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)
|
||||
{
|
||||
// a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more
|
||||
if (sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)
|
||||
sample_index -= IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||
sample_index = sample_index % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||
if (sample_index < 0)
|
||||
sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||
}
|
||||
|
||||
const ImVec2 s = _Data->ArcFastVtx[sample_index];
|
||||
out_ptr->x = center.x + s.x * radius;
|
||||
out_ptr->y = center.y + s.y * radius;
|
||||
out_ptr++;
|
||||
if (a_max_sample >= a_min_sample)
|
||||
{
|
||||
for (int a = a_min_sample; a <= a_max_sample; a += a_step, sample_index += a_step, a_step = a_next_step)
|
||||
{
|
||||
// a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more
|
||||
if (sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)
|
||||
sample_index -= IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||
|
||||
const ImVec2 s = _Data->ArcFastVtx[sample_index];
|
||||
out_ptr->x = center.x + s.x * radius;
|
||||
out_ptr->y = center.y + s.y * radius;
|
||||
out_ptr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int a = a_min_sample; a >= a_max_sample; a -= a_step, sample_index -= a_step, a_step = a_next_step)
|
||||
{
|
||||
// a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more
|
||||
if (sample_index < 0)
|
||||
sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||
|
||||
const ImVec2 s = _Data->ArcFastVtx[sample_index];
|
||||
out_ptr->x = center.x + s.x * radius;
|
||||
out_ptr->y = center.y + s.y * radius;
|
||||
out_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
if (extra_max_sample)
|
||||
@ -1116,7 +1149,6 @@ void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, fl
|
||||
_Path.push_back(center);
|
||||
return;
|
||||
}
|
||||
IM_ASSERT(a_min <= a_max);
|
||||
|
||||
// Note that we are adding a point at both a_min and a_max.
|
||||
// If you are trying to draw a full closed circle you don't want the overlapping points!
|
||||
@ -1136,7 +1168,6 @@ void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_
|
||||
_Path.push_back(center);
|
||||
return;
|
||||
}
|
||||
IM_ASSERT(a_min_of_12 <= a_max_of_12);
|
||||
_PathArcToFastEx(center, radius, a_min_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, a_max_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, 0);
|
||||
}
|
||||
|
||||
@ -1147,7 +1178,6 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa
|
||||
_Path.push_back(center);
|
||||
return;
|
||||
}
|
||||
IM_ASSERT(a_min <= a_max);
|
||||
|
||||
if (num_segments > 0)
|
||||
{
|
||||
@ -1158,28 +1188,33 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa
|
||||
// Automatic segment count
|
||||
if (radius <= _Data->ArcFastRadiusCutoff)
|
||||
{
|
||||
const bool a_is_reverse = a_max < a_min;
|
||||
|
||||
// We are going to use precomputed values for mid samples.
|
||||
// Determine first and last sample in lookup table that belong to the arc.
|
||||
const int a_min_sample = (int)ImCeil(IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f));
|
||||
const int a_max_sample = (int)( IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f));
|
||||
const int a_mid_samples = ImMax(a_max_sample - a_min_sample, 0);
|
||||
const float a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f);
|
||||
const float a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f);
|
||||
|
||||
const int a_min_sample = a_is_reverse ? (int)ImFloorSigned(a_min_sample_f) : (int)ImCeil(a_min_sample_f);
|
||||
const int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloorSigned(a_max_sample_f);
|
||||
const int a_mid_samples = a_is_reverse ? ImMax(a_min_sample - a_max_sample, 0) : ImMax(a_max_sample - a_min_sample, 0);
|
||||
|
||||
const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||
const float a_max_segment_angle = a_max_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||
const bool a_emit_start = (a_min_segment_angle - a_min) > 0.0f;
|
||||
const bool a_emit_end = (a_max - a_max_segment_angle) > 0.0f;
|
||||
const bool a_emit_start = (a_min_segment_angle - a_min) != 0.0f;
|
||||
const bool a_emit_end = (a_max - a_max_segment_angle) != 0.0f;
|
||||
|
||||
_Path.reserve(_Path.Size + (a_mid_samples + 1 + (a_emit_start ? 1 : 0) + (a_emit_end ? 1 : 0)));
|
||||
if (a_emit_start)
|
||||
_Path.push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius));
|
||||
if (a_max_sample >= a_min_sample)
|
||||
if (a_mid_samples > 0)
|
||||
_PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0);
|
||||
if (a_emit_end)
|
||||
_Path.push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius));
|
||||
}
|
||||
else
|
||||
{
|
||||
const float arc_length = a_max - a_min;
|
||||
const float arc_length = ImAbs(a_max - a_min);
|
||||
const int circle_segment_count = _CalcCircleAutoSegmentCount(radius);
|
||||
const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), (int)(2.0f * IM_PI / arc_length));
|
||||
_PathArcToN(center, radius, a_min, a_max, arc_segment_count);
|
||||
@ -1444,24 +1479,22 @@ void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int nu
|
||||
if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f)
|
||||
return;
|
||||
|
||||
// Obtain segment count
|
||||
if (num_segments <= 0)
|
||||
{
|
||||
// Automatic segment count
|
||||
num_segments = _CalcCircleAutoSegmentCount(radius);
|
||||
// Use arc with automatic segment count
|
||||
_PathArcToFastEx(center, radius - 0.5f, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);
|
||||
_Path.Size--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
|
||||
num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
|
||||
|
||||
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
||||
const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
|
||||
PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
|
||||
}
|
||||
|
||||
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
||||
const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
|
||||
if (num_segments == 12)
|
||||
PathArcToFast(center, radius - 0.5f, 0, 12 - 1);
|
||||
else
|
||||
PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
|
||||
PathStroke(col, ImDrawFlags_Closed, thickness);
|
||||
}
|
||||
|
||||
@ -1470,24 +1503,22 @@ void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col,
|
||||
if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f)
|
||||
return;
|
||||
|
||||
// Obtain segment count
|
||||
if (num_segments <= 0)
|
||||
{
|
||||
// Automatic segment count
|
||||
num_segments = _CalcCircleAutoSegmentCount(radius);
|
||||
// Use arc with automatic segment count
|
||||
_PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);
|
||||
_Path.Size--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
|
||||
num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
|
||||
|
||||
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
||||
const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
|
||||
PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
|
||||
}
|
||||
|
||||
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
||||
const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
|
||||
if (num_segments == 12)
|
||||
PathArcToFast(center, radius, 0, 12 - 1);
|
||||
else
|
||||
PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
|
||||
PathFillConvex(col);
|
||||
}
|
||||
|
||||
@ -1967,6 +1998,7 @@ void ImFontAtlas::ClearInputData()
|
||||
ConfigData.clear();
|
||||
CustomRects.clear();
|
||||
PackIdMouseCursors = PackIdLines = -1;
|
||||
TexReady = false;
|
||||
}
|
||||
|
||||
void ImFontAtlas::ClearTexData()
|
||||
@ -1979,14 +2011,14 @@ void ImFontAtlas::ClearTexData()
|
||||
TexPixelsAlpha8 = NULL;
|
||||
TexPixelsRGBA32 = NULL;
|
||||
TexPixelsUseColors = false;
|
||||
// Important: we leave TexReady untouched
|
||||
}
|
||||
|
||||
void ImFontAtlas::ClearFonts()
|
||||
{
|
||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||
for (int i = 0; i < Fonts.Size; i++)
|
||||
IM_DELETE(Fonts[i]);
|
||||
Fonts.clear();
|
||||
Fonts.clear_delete();
|
||||
TexReady = false;
|
||||
}
|
||||
|
||||
void ImFontAtlas::Clear()
|
||||
@ -2000,11 +2032,7 @@ void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_wid
|
||||
{
|
||||
// Build atlas on demand
|
||||
if (TexPixelsAlpha8 == NULL)
|
||||
{
|
||||
if (ConfigData.empty())
|
||||
AddFontDefault();
|
||||
Build();
|
||||
}
|
||||
|
||||
*out_pixels = TexPixelsAlpha8;
|
||||
if (out_width) *out_width = TexWidth;
|
||||
@ -2063,6 +2091,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
|
||||
new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar;
|
||||
|
||||
// Invalidate texture
|
||||
TexReady = false;
|
||||
ClearTexData();
|
||||
return new_font_cfg.DstFont;
|
||||
}
|
||||
@ -2134,7 +2163,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float si
|
||||
IM_ASSERT(font_cfg.FontData == NULL);
|
||||
font_cfg.FontData = ttf_data;
|
||||
font_cfg.FontDataSize = ttf_size;
|
||||
font_cfg.SizePixels = size_pixels;
|
||||
font_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels;
|
||||
if (glyph_ranges)
|
||||
font_cfg.GlyphRanges = glyph_ranges;
|
||||
return AddFont(&font_cfg);
|
||||
@ -2225,6 +2254,10 @@ bool ImFontAtlas::Build()
|
||||
{
|
||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||
|
||||
// Default font is none are specified
|
||||
if (ConfigData.Size == 0)
|
||||
AddFontDefault();
|
||||
|
||||
// Select builder
|
||||
// - Note that we do not reassign to atlas->FontBuilderIO, since it is likely to point to static data which
|
||||
// may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are
|
||||
@ -2546,9 +2579,8 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup temporary (ImVector doesn't honor destructor)
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
src_tmp_array[src_i].~ImFontBuildSrcData();
|
||||
// Cleanup
|
||||
src_tmp_array.clear_destruct();
|
||||
|
||||
ImFontAtlasBuildFinish(atlas);
|
||||
return true;
|
||||
@ -2764,22 +2796,7 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
|
||||
if (atlas->Fonts[i]->DirtyLookupTables)
|
||||
atlas->Fonts[i]->BuildLookupTable();
|
||||
|
||||
// Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
|
||||
// However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
|
||||
// FIXME: Also note that 0x2026 is currently seldom included in our font ranges. Because of this we are more likely to use three individual dots.
|
||||
for (int i = 0; i < atlas->Fonts.size(); i++)
|
||||
{
|
||||
ImFont* font = atlas->Fonts[i];
|
||||
if (font->EllipsisChar != (ImWchar)-1)
|
||||
continue;
|
||||
const ImWchar ellipsis_variants[] = { (ImWchar)0x2026, (ImWchar)0x0085 };
|
||||
for (int j = 0; j < IM_ARRAYSIZE(ellipsis_variants); j++)
|
||||
if (font->FindGlyphNoFallback(ellipsis_variants[j]) != NULL) // Verify glyph exists
|
||||
{
|
||||
font->EllipsisChar = ellipsis_variants[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
atlas->TexReady = true;
|
||||
}
|
||||
|
||||
// Retrieve list of range (2 int per range, values are inclusive)
|
||||
@ -2800,6 +2817,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesKorean()
|
||||
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||
0x3131, 0x3163, // Korean alphabets
|
||||
0xAC00, 0xD7A3, // Korean characters
|
||||
0xFFFD, 0xFFFD, // Invalid
|
||||
0,
|
||||
};
|
||||
return &ranges[0];
|
||||
@ -2814,6 +2832,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull()
|
||||
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
||||
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
||||
0xFF00, 0xFFEF, // Half-width characters
|
||||
0xFFFD, 0xFFFD, // Invalid
|
||||
0x4e00, 0x9FAF, // CJK Ideograms
|
||||
0,
|
||||
};
|
||||
@ -2890,7 +2909,8 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
|
||||
0x2000, 0x206F, // General Punctuation
|
||||
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
||||
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
||||
0xFF00, 0xFFEF // Half-width characters
|
||||
0xFF00, 0xFFEF, // Half-width characters
|
||||
0xFFFD, 0xFFFD // Invalid
|
||||
};
|
||||
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };
|
||||
if (!full_ranges[0])
|
||||
@ -2979,7 +2999,8 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
|
||||
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
||||
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
||||
0xFF00, 0xFFEF // Half-width characters
|
||||
0xFF00, 0xFFEF, // Half-width characters
|
||||
0xFFFD, 0xFFFD // Invalid
|
||||
};
|
||||
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 };
|
||||
if (!full_ranges[0])
|
||||
@ -3078,8 +3099,9 @@ ImFont::ImFont()
|
||||
{
|
||||
FontSize = 0.0f;
|
||||
FallbackAdvanceX = 0.0f;
|
||||
FallbackChar = (ImWchar)'?';
|
||||
FallbackChar = (ImWchar)-1;
|
||||
EllipsisChar = (ImWchar)-1;
|
||||
DotChar = (ImWchar)-1;
|
||||
FallbackGlyph = NULL;
|
||||
ContainerAtlas = NULL;
|
||||
ConfigData = NULL;
|
||||
@ -3110,6 +3132,14 @@ void ImFont::ClearOutputData()
|
||||
MetricsTotalSurface = 0;
|
||||
}
|
||||
|
||||
static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count)
|
||||
{
|
||||
for (int n = 0; n < candidate_chars_count; n++)
|
||||
if (font->FindGlyphNoFallback(candidate_chars[n]) != NULL)
|
||||
return candidate_chars[n];
|
||||
return (ImWchar)-1;
|
||||
}
|
||||
|
||||
void ImFont::BuildLookupTable()
|
||||
{
|
||||
int max_codepoint = 0;
|
||||
@ -3152,9 +3182,31 @@ void ImFont::BuildLookupTable()
|
||||
SetGlyphVisible((ImWchar)' ', false);
|
||||
SetGlyphVisible((ImWchar)'\t', false);
|
||||
|
||||
// Setup fall-backs
|
||||
// Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
|
||||
// However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
|
||||
// FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots.
|
||||
const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 };
|
||||
const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };
|
||||
if (EllipsisChar == (ImWchar)-1)
|
||||
EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars));
|
||||
if (DotChar == (ImWchar)-1)
|
||||
DotChar = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars));
|
||||
|
||||
// Setup fallback character
|
||||
const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };
|
||||
FallbackGlyph = FindGlyphNoFallback(FallbackChar);
|
||||
FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f;
|
||||
if (FallbackGlyph == NULL)
|
||||
{
|
||||
FallbackChar = FindFirstExistingGlyph(this, fallback_chars, IM_ARRAYSIZE(fallback_chars));
|
||||
FallbackGlyph = FindGlyphNoFallback(FallbackChar);
|
||||
if (FallbackGlyph == NULL)
|
||||
{
|
||||
FallbackGlyph = &Glyphs.back();
|
||||
FallbackChar = (ImWchar)FallbackGlyph->Codepoint;
|
||||
}
|
||||
}
|
||||
|
||||
FallbackAdvanceX = FallbackGlyph->AdvanceX;
|
||||
for (int i = 0; i < max_codepoint + 1; i++)
|
||||
if (IndexAdvanceX[i] < 0.0f)
|
||||
IndexAdvanceX[i] = FallbackAdvanceX;
|
||||
@ -3179,12 +3231,6 @@ void ImFont::SetGlyphVisible(ImWchar c, bool visible)
|
||||
glyph->Visible = visible ? 1 : 0;
|
||||
}
|
||||
|
||||
void ImFont::SetFallbackChar(ImWchar c)
|
||||
{
|
||||
FallbackChar = c;
|
||||
BuildLookupTable();
|
||||
}
|
||||
|
||||
void ImFont::GrowIndex(int new_size)
|
||||
{
|
||||
IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
|
||||
@ -3469,6 +3515,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
|
||||
return text_size;
|
||||
}
|
||||
|
||||
// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
|
||||
void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const
|
||||
{
|
||||
const ImFontGlyph* glyph = FindGlyph(c);
|
||||
@ -3483,6 +3530,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
||||
draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);
|
||||
}
|
||||
|
||||
// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
|
||||
void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
|
||||
{
|
||||
if (!text_end)
|
||||
@ -3684,6 +3732,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
||||
// - RenderMouseCursor()
|
||||
// - RenderArrowPointingAt()
|
||||
// - RenderRectFilledRangeH()
|
||||
// - RenderRectFilledWithHole()
|
||||
//-----------------------------------------------------------------------------
|
||||
// Function in need of a redesign (legacy mess)
|
||||
// - RenderColorRectWithAlphaCheckerboard()
|
||||
@ -3752,7 +3801,7 @@ void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, Im
|
||||
if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))
|
||||
{
|
||||
pos -= offset;
|
||||
const ImTextureID tex_id = font_atlas->TexID;
|
||||
ImTextureID tex_id = font_atlas->TexID;
|
||||
draw_list->PushTextureID(tex_id);
|
||||
draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow);
|
||||
draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow);
|
||||
|
@ -1,719 +0,0 @@
|
||||
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
|
||||
// - Desktop GL: 2.x 3.x 4.x
|
||||
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
|
||||
// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
|
||||
// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
|
||||
// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
|
||||
// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
|
||||
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
|
||||
// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
|
||||
// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
|
||||
// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
|
||||
// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
|
||||
// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
|
||||
// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
|
||||
// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
|
||||
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
|
||||
// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
|
||||
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
|
||||
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
|
||||
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
|
||||
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
|
||||
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
|
||||
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
|
||||
// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
|
||||
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
|
||||
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.
|
||||
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
|
||||
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
|
||||
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
|
||||
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
|
||||
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
|
||||
|
||||
//----------------------------------------
|
||||
// OpenGL GLSL GLSL
|
||||
// version version string
|
||||
//----------------------------------------
|
||||
// 2.0 110 "#version 110"
|
||||
// 2.1 120 "#version 120"
|
||||
// 3.0 130 "#version 130"
|
||||
// 3.1 140 "#version 140"
|
||||
// 3.2 150 "#version 150"
|
||||
// 3.3 330 "#version 330 core"
|
||||
// 4.0 400 "#version 400 core"
|
||||
// 4.1 410 "#version 410 core"
|
||||
// 4.2 420 "#version 410 core"
|
||||
// 4.3 430 "#version 430 core"
|
||||
// ES 2.0 100 "#version 100" = WebGL 1.0
|
||||
// ES 3.0 300 "#version 300 es" = WebGL 2.0
|
||||
//----------------------------------------
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include <stdio.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||
#include <stddef.h> // intptr_t
|
||||
#else
|
||||
#include <stdint.h> // intptr_t
|
||||
#endif
|
||||
|
||||
// GL includes
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <GLES2/gl2.h>
|
||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
|
||||
#else
|
||||
#include <GLES3/gl3.h> // Use GL ES 3
|
||||
#endif
|
||||
#else
|
||||
// About Desktop OpenGL function loaders:
|
||||
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
||||
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
|
||||
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
|
||||
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||
#include <GL/gl3w.h> // Needs to be initialized with gl3wInit() in user's code
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
||||
#include <GL/glew.h> // Needs to be initialized with glewInit() in user's code.
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||
#include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code.
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
|
||||
#include <glad/gl.h> // Needs to be initialized with gladLoadGL(...) or gladLoaderLoadGL() in user's code.
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||
#ifndef GLFW_INCLUDE_NONE
|
||||
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||
#endif
|
||||
#include <glbinding/Binding.h> // Needs to be initialized with glbinding::Binding::initialize() in user's code.
|
||||
#include <glbinding/gl/gl.h>
|
||||
using namespace gl;
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||
#ifndef GLFW_INCLUDE_NONE
|
||||
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||
#endif
|
||||
#include <glbinding/glbinding.h>// Needs to be initialized with glbinding::initialize() in user's code.
|
||||
#include <glbinding/gl/gl.h>
|
||||
using namespace gl;
|
||||
#else
|
||||
#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.3+ has glBindSampler()
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_3)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
#endif
|
||||
|
||||
// OpenGL Data
|
||||
static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||
static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings.
|
||||
static GLuint g_FontTexture = 0;
|
||||
static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
|
||||
static GLint g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location
|
||||
static GLuint g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
|
||||
static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||
{
|
||||
// Query for GL version (e.g. 320 for GL 3.2)
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
GLint major = 0;
|
||||
GLint minor = 0;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||
if (major == 0 && minor == 0)
|
||||
{
|
||||
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
|
||||
const char* gl_version = (const char*)glGetString(GL_VERSION);
|
||||
sscanf(gl_version, "%d.%d", &major, &minor);
|
||||
}
|
||||
g_GlVersion = (GLuint)(major * 100 + minor * 10);
|
||||
#else
|
||||
g_GlVersion = 200; // GLES 2
|
||||
#endif
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendRendererName = "imgui_impl_opengl3";
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (g_GlVersion >= 320)
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
#endif
|
||||
|
||||
// Store GLSL version string so we can refer to it later in case we recreate shaders.
|
||||
// Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
if (glsl_version == NULL)
|
||||
glsl_version = "#version 100";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
if (glsl_version == NULL)
|
||||
glsl_version = "#version 300 es";
|
||||
#elif defined(__APPLE__)
|
||||
if (glsl_version == NULL)
|
||||
glsl_version = "#version 150";
|
||||
#else
|
||||
if (glsl_version == NULL)
|
||||
glsl_version = "#version 130";
|
||||
#endif
|
||||
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
|
||||
strcpy(g_GlslVersionString, glsl_version);
|
||||
strcat(g_GlslVersionString, "\n");
|
||||
|
||||
// Debugging construct to make it easily visible in the IDE and debugger which GL loader has been selected.
|
||||
// The code actually never uses the 'gl_loader' variable! It is only here so you can read it!
|
||||
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
|
||||
// you are likely to get a crash below.
|
||||
// You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
|
||||
const char* gl_loader = "Unknown";
|
||||
IM_UNUSED(gl_loader);
|
||||
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||
gl_loader = "GL3W";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
||||
gl_loader = "GLEW";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||
gl_loader = "GLAD";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
|
||||
gl_loader = "GLAD2";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||
gl_loader = "glbinding2";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||
gl_loader = "glbinding3";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
gl_loader = "custom";
|
||||
#else
|
||||
gl_loader = "none";
|
||||
#endif
|
||||
|
||||
// Make an arbitrary GL call (we don't actually need the result)
|
||||
// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
|
||||
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
|
||||
GLint current_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_Shutdown()
|
||||
{
|
||||
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_NewFrame()
|
||||
{
|
||||
if (!g_ShaderHandle)
|
||||
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
||||
{
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
if (g_GlVersion >= 310)
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
#endif
|
||||
#ifdef GL_POLYGON_MODE
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
#endif
|
||||
|
||||
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
|
||||
#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
|
||||
bool clip_origin_lower_left = true;
|
||||
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin);
|
||||
if (current_clip_origin == GL_UPPER_LEFT)
|
||||
clip_origin_lower_left = false;
|
||||
#endif
|
||||
|
||||
// Setup viewport, orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
|
||||
float L = draw_data->DisplayPos.x;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||
float T = draw_data->DisplayPos.y;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||
#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
|
||||
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
|
||||
#endif
|
||||
const float ortho_projection[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
|
||||
};
|
||||
glUseProgram(g_ShaderHandle);
|
||||
glUniform1i(g_AttribLocationTex, 0);
|
||||
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (g_GlVersion >= 330)
|
||||
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
|
||||
#endif
|
||||
|
||||
(void)vertex_array_object;
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
glBindVertexArray(vertex_array_object);
|
||||
#endif
|
||||
|
||||
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
|
||||
glEnableVertexAttribArray(g_AttribLocationVtxPos);
|
||||
glEnableVertexAttribArray(g_AttribLocationVtxUV);
|
||||
glEnableVertexAttribArray(g_AttribLocationVtxColor);
|
||||
glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
|
||||
glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
|
||||
glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
|
||||
}
|
||||
|
||||
// OpenGL3 Render function.
|
||||
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
|
||||
// This is in order to be able to run within an OpenGL engine that doesn't do so.
|
||||
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
||||
if (fb_width <= 0 || fb_height <= 0)
|
||||
return;
|
||||
|
||||
// Backup GL state
|
||||
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
|
||||
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
GLuint last_sampler; if (g_GlVersion >= 330) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
|
||||
#endif
|
||||
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
|
||||
#endif
|
||||
#ifdef GL_POLYGON_MODE
|
||||
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||
#endif
|
||||
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
|
||||
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
|
||||
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
|
||||
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
|
||||
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
|
||||
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
|
||||
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
|
||||
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
GLboolean last_enable_primitive_restart = (g_GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
|
||||
#endif
|
||||
|
||||
// Setup desired GL state
|
||||
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
|
||||
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
|
||||
GLuint vertex_array_object = 0;
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
glGenVertexArrays(1, &vertex_array_object);
|
||||
#endif
|
||||
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||
|
||||
// Render command lists
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
|
||||
// Upload vertex/index buffers
|
||||
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != NULL)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec4 clip_rect;
|
||||
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
|
||||
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
|
||||
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
|
||||
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
|
||||
|
||||
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
|
||||
{
|
||||
// Apply scissor/clipping rectangle
|
||||
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
|
||||
|
||||
// Bind texture, Draw
|
||||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (g_GlVersion >= 320)
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
|
||||
else
|
||||
#endif
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the temporary VAO
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
glDeleteVertexArrays(1, &vertex_array_object);
|
||||
#endif
|
||||
|
||||
// Restore modified GL state
|
||||
glUseProgram(last_program);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (g_GlVersion >= 330)
|
||||
glBindSampler(0, last_sampler);
|
||||
#endif
|
||||
glActiveTexture(last_active_texture);
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
glBindVertexArray(last_vertex_array_object);
|
||||
#endif
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
|
||||
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||
if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
|
||||
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
if (g_GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
|
||||
#endif
|
||||
|
||||
#ifdef GL_POLYGON_MODE
|
||||
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
||||
#endif
|
||||
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
GLint last_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGenTextures(1, &g_FontTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
#ifdef GL_UNPACK_ROW_LENGTH
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
|
||||
|
||||
// Restore state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||
{
|
||||
if (g_FontTexture)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
glDeleteTextures(1, &g_FontTexture);
|
||||
io.Fonts->TexID = 0;
|
||||
g_FontTexture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
|
||||
static bool CheckShader(GLuint handle, const char* desc)
|
||||
{
|
||||
GLint status = 0, log_length = 0;
|
||||
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
||||
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if ((GLboolean)status == GL_FALSE)
|
||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||
fprintf(stderr, "%s\n", buf.begin());
|
||||
}
|
||||
return (GLboolean)status == GL_TRUE;
|
||||
}
|
||||
|
||||
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
|
||||
static bool CheckProgram(GLuint handle, const char* desc)
|
||||
{
|
||||
GLint status = 0, log_length = 0;
|
||||
glGetProgramiv(handle, GL_LINK_STATUS, &status);
|
||||
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if ((GLboolean)status == GL_FALSE)
|
||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||
fprintf(stderr, "%s\n", buf.begin());
|
||||
}
|
||||
return (GLboolean)status == GL_TRUE;
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||
{
|
||||
// Backup GL state
|
||||
GLint last_texture, last_array_buffer;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
GLint last_vertex_array;
|
||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||
#endif
|
||||
|
||||
// Parse GLSL version string
|
||||
int glsl_version = 130;
|
||||
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
|
||||
|
||||
const GLchar* vertex_shader_glsl_120 =
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"attribute vec2 Position;\n"
|
||||
"attribute vec2 UV;\n"
|
||||
"attribute vec4 Color;\n"
|
||||
"varying vec2 Frag_UV;\n"
|
||||
"varying vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_130 =
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"in vec2 Position;\n"
|
||||
"in vec2 UV;\n"
|
||||
"in vec4 Color;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_300_es =
|
||||
"precision mediump float;\n"
|
||||
"layout (location = 0) in vec2 Position;\n"
|
||||
"layout (location = 1) in vec2 UV;\n"
|
||||
"layout (location = 2) in vec4 Color;\n"
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_410_core =
|
||||
"layout (location = 0) in vec2 Position;\n"
|
||||
"layout (location = 1) in vec2 UV;\n"
|
||||
"layout (location = 2) in vec4 Color;\n"
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_120 =
|
||||
"#ifdef GL_ES\n"
|
||||
" precision mediump float;\n"
|
||||
"#endif\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"varying vec2 Frag_UV;\n"
|
||||
"varying vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_130 =
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_300_es =
|
||||
"precision mediump float;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"layout (location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_410_core =
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"layout (location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
// Select shaders matching our GLSL versions
|
||||
const GLchar* vertex_shader = NULL;
|
||||
const GLchar* fragment_shader = NULL;
|
||||
if (glsl_version < 130)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_120;
|
||||
fragment_shader = fragment_shader_glsl_120;
|
||||
}
|
||||
else if (glsl_version >= 410)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_410_core;
|
||||
fragment_shader = fragment_shader_glsl_410_core;
|
||||
}
|
||||
else if (glsl_version == 300)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_300_es;
|
||||
fragment_shader = fragment_shader_glsl_300_es;
|
||||
}
|
||||
else
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_130;
|
||||
fragment_shader = fragment_shader_glsl_130;
|
||||
}
|
||||
|
||||
// Create shaders
|
||||
const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };
|
||||
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
|
||||
glCompileShader(g_VertHandle);
|
||||
CheckShader(g_VertHandle, "vertex shader");
|
||||
|
||||
const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };
|
||||
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
|
||||
glCompileShader(g_FragHandle);
|
||||
CheckShader(g_FragHandle, "fragment shader");
|
||||
|
||||
g_ShaderHandle = glCreateProgram();
|
||||
glAttachShader(g_ShaderHandle, g_VertHandle);
|
||||
glAttachShader(g_ShaderHandle, g_FragHandle);
|
||||
glLinkProgram(g_ShaderHandle);
|
||||
CheckProgram(g_ShaderHandle, "shader program");
|
||||
|
||||
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
|
||||
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
|
||||
g_AttribLocationVtxPos = (GLuint)glGetAttribLocation(g_ShaderHandle, "Position");
|
||||
g_AttribLocationVtxUV = (GLuint)glGetAttribLocation(g_ShaderHandle, "UV");
|
||||
g_AttribLocationVtxColor = (GLuint)glGetAttribLocation(g_ShaderHandle, "Color");
|
||||
|
||||
// Create buffers
|
||||
glGenBuffers(1, &g_VboHandle);
|
||||
glGenBuffers(1, &g_ElementsHandle);
|
||||
|
||||
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
|
||||
// Restore modified GL state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
glBindVertexArray(last_vertex_array);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||
{
|
||||
if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
|
||||
if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
|
||||
if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }
|
||||
if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }
|
||||
if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; }
|
||||
if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; }
|
||||
if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }
|
||||
|
||||
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
|
||||
// - Desktop GL: 2.x 3.x 4.x
|
||||
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// About Desktop OpenGL function loaders:
|
||||
// Modern Desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
||||
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
|
||||
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
|
||||
|
||||
// About GLSL version:
|
||||
// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string.
|
||||
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
|
||||
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
// Backend API
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// (Optional) Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
|
||||
// Specific OpenGL ES versions
|
||||
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
|
||||
//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
|
||||
|
||||
// Attempt to auto-detect the default Desktop GL loader based on available header files.
|
||||
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
|
||||
// you are likely to get a crash in ImGui_ImplOpenGL3_Init().
|
||||
// You can explicitly select a loader by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_ES3) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
|
||||
// Try to detect GLES on matching platforms
|
||||
#if defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
|
||||
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
|
||||
|
||||
// Otherwise try to detect supported Desktop OpenGL loaders..
|
||||
#elif defined(__has_include)
|
||||
#if __has_include(<GL/glew.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
|
||||
#elif __has_include(<glad/glad.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GLAD
|
||||
#elif __has_include(<glad/gl.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GLAD2
|
||||
#elif __has_include(<GL/gl3w.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GL3W
|
||||
#elif __has_include(<glbinding/glbinding.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3
|
||||
#elif __has_include(<glbinding/Binding.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
|
||||
#else
|
||||
#error "Cannot detect OpenGL loader!"
|
||||
#endif
|
||||
#else
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W embedded in our repository
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,370 +0,0 @@
|
||||
// dear imgui: Platform Backend for SDL2
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||
// (Requires: SDL 2.0. Prefer SDL 2.0.4+ for full feature support.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// Missing features:
|
||||
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends.
|
||||
// 2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2).
|
||||
// 2019-12-17: Inputs: On Wayland, use SDL_GetMouseState (because there is no global mouse state).
|
||||
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||
// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
|
||||
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
|
||||
// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
|
||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
|
||||
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
|
||||
// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
|
||||
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
|
||||
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
|
||||
// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
|
||||
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
|
||||
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
|
||||
// SDL
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
#if defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
|
||||
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE SDL_VERSION_ATLEAST(2,0,4)
|
||||
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
|
||||
|
||||
// Data
|
||||
static SDL_Window* g_Window = NULL;
|
||||
static Uint64 g_Time = 0;
|
||||
static bool g_MousePressed[3] = { false, false, false };
|
||||
static SDL_Cursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
|
||||
static char* g_ClipboardTextData = NULL;
|
||||
static bool g_MouseCanUseGlobalState = true;
|
||||
|
||||
static const char* ImGui_ImplSDL2_GetClipboardText(void*)
|
||||
{
|
||||
if (g_ClipboardTextData)
|
||||
SDL_free(g_ClipboardTextData);
|
||||
g_ClipboardTextData = SDL_GetClipboardText();
|
||||
return g_ClipboardTextData;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
|
||||
{
|
||||
SDL_SetClipboardText(text);
|
||||
}
|
||||
|
||||
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
|
||||
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
switch (event->type)
|
||||
{
|
||||
case SDL_MOUSEWHEEL:
|
||||
{
|
||||
if (event->wheel.x > 0) io.MouseWheelH += 1;
|
||||
if (event->wheel.x < 0) io.MouseWheelH -= 1;
|
||||
if (event->wheel.y > 0) io.MouseWheel += 1;
|
||||
if (event->wheel.y < 0) io.MouseWheel -= 1;
|
||||
return true;
|
||||
}
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
{
|
||||
if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true;
|
||||
if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true;
|
||||
if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true;
|
||||
return true;
|
||||
}
|
||||
case SDL_TEXTINPUT:
|
||||
{
|
||||
io.AddInputCharactersUTF8(event->text.text);
|
||||
return true;
|
||||
}
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
{
|
||||
int key = event->key.keysym.scancode;
|
||||
IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown));
|
||||
io.KeysDown[key] = (event->type == SDL_KEYDOWN);
|
||||
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
|
||||
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
|
||||
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
|
||||
#ifdef _WIN32
|
||||
io.KeySuper = false;
|
||||
#else
|
||||
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplSDL2_Init(SDL_Window* window)
|
||||
{
|
||||
g_Window = window;
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
io.BackendPlatformName = "imgui_impl_sdl";
|
||||
|
||||
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||
io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
|
||||
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
|
||||
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
|
||||
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
|
||||
io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT;
|
||||
io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE;
|
||||
io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE;
|
||||
io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN;
|
||||
io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE;
|
||||
io.KeyMap[ImGuiKey_KeyPadEnter] = SDL_SCANCODE_KP_ENTER;
|
||||
io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A;
|
||||
io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C;
|
||||
io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V;
|
||||
io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X;
|
||||
io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z;
|
||||
|
||||
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
|
||||
io.ClipboardUserData = NULL;
|
||||
|
||||
// Load mouse cursors
|
||||
g_MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
|
||||
g_MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
|
||||
g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
||||
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
|
||||
|
||||
// Check and store if we are on Wayland
|
||||
g_MouseCanUseGlobalState = strncmp(SDL_GetCurrentVideoDriver(), "wayland", 7) != 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
SDL_SysWMinfo wmInfo;
|
||||
SDL_VERSION(&wmInfo.version);
|
||||
SDL_GetWindowWMInfo(window, &wmInfo);
|
||||
io.ImeWindowHandle = wmInfo.info.win.window;
|
||||
#else
|
||||
(void)window;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
|
||||
{
|
||||
(void)sdl_gl_context; // Viewport branch will need this.
|
||||
return ImGui_ImplSDL2_Init(window);
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
|
||||
{
|
||||
#if !SDL_HAS_VULKAN
|
||||
IM_ASSERT(0 && "Unsupported");
|
||||
#endif
|
||||
return ImGui_ImplSDL2_Init(window);
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
|
||||
{
|
||||
#if !defined(_WIN32)
|
||||
IM_ASSERT(0 && "Unsupported");
|
||||
#endif
|
||||
return ImGui_ImplSDL2_Init(window);
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
|
||||
{
|
||||
return ImGui_ImplSDL2_Init(window);
|
||||
}
|
||||
|
||||
void ImGui_ImplSDL2_Shutdown()
|
||||
{
|
||||
g_Window = NULL;
|
||||
|
||||
// Destroy last known clipboard data
|
||||
if (g_ClipboardTextData)
|
||||
SDL_free(g_ClipboardTextData);
|
||||
g_ClipboardTextData = NULL;
|
||||
|
||||
// Destroy SDL mouse cursors
|
||||
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||
SDL_FreeCursor(g_MouseCursors[cursor_n]);
|
||||
memset(g_MouseCursors, 0, sizeof(g_MouseCursors));
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||
if (io.WantSetMousePos)
|
||||
SDL_WarpMouseInWindow(g_Window, (int)io.MousePos.x, (int)io.MousePos.y);
|
||||
else
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
|
||||
int mx, my;
|
||||
Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my);
|
||||
io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||
io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
|
||||
io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
|
||||
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
|
||||
|
||||
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
|
||||
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
||||
if (g_Window == focused_window)
|
||||
{
|
||||
if (g_MouseCanUseGlobalState)
|
||||
{
|
||||
// SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?)
|
||||
// The creation of a new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally.
|
||||
// Won't use this workaround when on Wayland, as there is no global mouse position.
|
||||
int wx, wy;
|
||||
SDL_GetWindowPosition(focused_window, &wx, &wy);
|
||||
SDL_GetGlobalMouseState(&mx, &my);
|
||||
mx -= wx;
|
||||
my -= wy;
|
||||
}
|
||||
io.MousePos = ImVec2((float)mx, (float)my);
|
||||
}
|
||||
|
||||
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor.
|
||||
// The function is only supported from SDL 2.0.4 (released Jan 2016)
|
||||
bool any_mouse_button_down = ImGui::IsAnyMouseDown();
|
||||
SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE);
|
||||
#else
|
||||
if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS)
|
||||
io.MousePos = ImVec2((float)mx, (float)my);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_UpdateMouseCursor()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||
return;
|
||||
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
SDL_ShowCursor(SDL_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show OS mouse cursor
|
||||
SDL_SetCursor(g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||
SDL_ShowCursor(SDL_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_UpdateGamepads()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||
return;
|
||||
|
||||
// Get gamepad
|
||||
SDL_GameController* game_controller = SDL_GameControllerOpen(0);
|
||||
if (!game_controller)
|
||||
{
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||
return;
|
||||
}
|
||||
|
||||
// Update gamepad inputs
|
||||
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0) ? 1.0f : 0.0f; }
|
||||
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
|
||||
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
|
||||
MAP_BUTTON(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_B); // Cross / A
|
||||
// MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_A); // Circle / B
|
||||
// MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X
|
||||
MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y
|
||||
MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left
|
||||
MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right
|
||||
MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up
|
||||
MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down
|
||||
MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
|
||||
MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32767);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767);
|
||||
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
#undef MAP_BUTTON
|
||||
#undef MAP_ANALOG
|
||||
}
|
||||
|
||||
void ImGui_ImplSDL2_NewFrame(SDL_Window* window)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)
|
||||
w = h = 0;
|
||||
SDL_GL_GetDrawableSize(window, &display_w, &display_h);
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
if (w > 0 && h > 0)
|
||||
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||
|
||||
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
|
||||
static Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||
Uint64 current_time = SDL_GetPerformanceCounter();
|
||||
io.DeltaTime = g_Time > 0 ? (float)((double)(current_time - g_Time) / frequency) : (float)(1.0f / 60.0f);
|
||||
g_Time = current_time;
|
||||
|
||||
ImGui_ImplSDL2_UpdateMousePosAndButtons();
|
||||
ImGui_ImplSDL2_UpdateMouseCursor();
|
||||
|
||||
// Update game controllers (if enabled and available)
|
||||
ImGui_ImplSDL2_UpdateGamepads();
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// dear imgui: Platform Backend for SDL2
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// Missing features:
|
||||
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct SDL_Window;
|
||||
typedef union SDL_Event SDL_Event;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
|
@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.82
|
||||
// dear imgui, v1.84
|
||||
// (internal structures/api)
|
||||
|
||||
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
|
||||
@ -43,7 +43,7 @@ Index of this file:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef IMGUI_VERSION
|
||||
#error Must include imgui.h before imgui_internal.h
|
||||
#include "imgui.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h> // FILE*, sscanf
|
||||
@ -51,10 +51,21 @@ Index of this file:
|
||||
#include <math.h> // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf
|
||||
#include <limits.h> // INT_MIN, INT_MAX
|
||||
|
||||
// Enable SSE intrinsics if available
|
||||
#if (defined __SSE__ || defined __x86_64__ || defined _M_X64) && !defined(IMGUI_DISABLE_SSE)
|
||||
#define IMGUI_ENABLE_SSE
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
// Visual Studio warnings
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport)
|
||||
#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport)
|
||||
#pragma warning (disable: 26812) // The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer)
|
||||
#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6).
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later
|
||||
#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Clang/GCC warnings with -Weverything
|
||||
@ -64,6 +75,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx'
|
||||
#endif
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok, for ImFloorSigned()
|
||||
#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
@ -76,6 +88,13 @@ Index of this file:
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
|
||||
#endif
|
||||
|
||||
// Helper macros
|
||||
#if defined(__clang__)
|
||||
#define IM_NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
#define IM_NORETURN
|
||||
#endif
|
||||
|
||||
// Legacy defines
|
||||
#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74
|
||||
#error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
|
||||
@ -104,9 +123,9 @@ struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine
|
||||
struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum
|
||||
struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup()
|
||||
struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box
|
||||
struct ImGuiLastItemDataBackup; // Backup and restore IsItemHovered() internal data
|
||||
struct ImGuiLastItemData; // Status storage for last submitted items
|
||||
struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only
|
||||
struct ImGuiNavMoveResult; // Result of a gamepad/keyboard directional navigation move query result
|
||||
struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result
|
||||
struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions
|
||||
struct ImGuiNextWindowData; // Storage for SetNextWindow** functions
|
||||
struct ImGuiNextItemData; // Storage for SetNextItem** functions
|
||||
@ -120,15 +139,17 @@ struct ImGuiTabBar; // Storage for a tab bar
|
||||
struct ImGuiTabItem; // Storage for a tab item (within a tab bar)
|
||||
struct ImGuiTable; // Storage for a table
|
||||
struct ImGuiTableColumn; // Storage for one column of a table
|
||||
struct ImGuiTableTempData; // Temporary storage for one table (one per table in the stack), shared between tables.
|
||||
struct ImGuiTableSettings; // Storage for a table .ini settings
|
||||
struct ImGuiTableColumnsSettings; // Storage for a column .ini settings
|
||||
struct ImGuiWindow; // Storage for one window
|
||||
struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame)
|
||||
struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame, in practice we currently keep it for each window)
|
||||
struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session)
|
||||
|
||||
// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists.
|
||||
typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical
|
||||
typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag()
|
||||
typedef int ImGuiItemAddFlags; // -> enum ImGuiItemAddFlags_ // Flags: for ItemAdd()
|
||||
typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags
|
||||
typedef int ImGuiOldColumnFlags; // -> enum ImGuiOldColumnFlags_ // Flags: for BeginColumns()
|
||||
typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight()
|
||||
@ -227,6 +248,13 @@ namespace ImStb
|
||||
#define IMGUI_CDECL
|
||||
#endif
|
||||
|
||||
// Warnings
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define IM_MSVC_WARNING_SUPPRESS(XXXX) __pragma(warning(suppress: XXXX))
|
||||
#else
|
||||
#define IM_MSVC_WARNING_SUPPRESS(XXXX)
|
||||
#endif
|
||||
|
||||
// Debug Tools
|
||||
// Use 'Metrics->Tools->Item Picker' to break into the call-stack of a specific item.
|
||||
#ifndef IM_DEBUG_BREAK
|
||||
@ -303,17 +331,19 @@ static inline bool ImCharIsBlankA(char c) { return c == ' ' || c =
|
||||
static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; }
|
||||
|
||||
// Helpers: UTF-8 <> wchar conversions
|
||||
IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
|
||||
IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count
|
||||
IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
|
||||
IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count)
|
||||
IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8
|
||||
IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8
|
||||
IMGUI_API const char* ImTextCharToUtf8(char out_buf[5], unsigned int c); // return out_buf
|
||||
IMGUI_API int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
|
||||
IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count
|
||||
IMGUI_API int ImTextStrFromUtf8(ImWchar* out_buf, int out_buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
|
||||
IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count)
|
||||
IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8
|
||||
IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8
|
||||
|
||||
// Helpers: ImVec2/ImVec4 operators
|
||||
// We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.)
|
||||
// We unfortunately don't have a unary- operator for ImVec2 because this would needs to be defined inside the class itself.
|
||||
#ifdef IMGUI_DEFINE_MATH_OPERATORS
|
||||
IM_MSVC_RUNTIME_CHECKS_OFF
|
||||
static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); }
|
||||
static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); }
|
||||
static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
|
||||
@ -329,6 +359,7 @@ static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs)
|
||||
static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); }
|
||||
static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); }
|
||||
static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); }
|
||||
IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||
#endif
|
||||
|
||||
// Helpers: File System
|
||||
@ -354,6 +385,7 @@ IMGUI_API ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 coun
|
||||
IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0);
|
||||
|
||||
// Helpers: Maths
|
||||
IM_MSVC_RUNTIME_CHECKS_OFF
|
||||
// - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy)
|
||||
#ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
|
||||
#define ImFabs(X) fabsf(X)
|
||||
@ -364,16 +396,23 @@ IMGUI_API void* ImFileLoadToMemory(const char* filename, const char*
|
||||
#define ImAcos(X) acosf(X)
|
||||
#define ImAtan2(Y, X) atan2f((Y), (X))
|
||||
#define ImAtof(STR) atof(STR)
|
||||
#define ImFloorStd(X) floorf(X) // We already uses our own ImFloor() { return (float)(int)v } internally so the standard one wrapper is named differently (it's used by e.g. stb_truetype)
|
||||
//#define ImFloorStd(X) floorf(X) // We use our own, see ImFloor() and ImFloorSigned()
|
||||
#define ImCeil(X) ceilf(X)
|
||||
static inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision
|
||||
static inline double ImPow(double x, double y) { return pow(x, y); }
|
||||
static inline float ImLog(float x) { return logf(x); } // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision
|
||||
static inline double ImLog(double x) { return log(x); }
|
||||
static inline int ImAbs(int x) { return x < 0 ? -x : x; }
|
||||
static inline float ImAbs(float x) { return fabsf(x); }
|
||||
static inline double ImAbs(double x) { return fabs(x); }
|
||||
static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : ((x > 0.0f) ? 1.0f : 0.0f); } // Sign operator - returns -1, 0 or 1 based on sign of argument
|
||||
static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : ((x > 0.0) ? 1.0 : 0.0); }
|
||||
#ifdef IMGUI_ENABLE_SSE
|
||||
static inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); }
|
||||
#else
|
||||
static inline float ImRsqrt(float x) { return 1.0f / sqrtf(x); }
|
||||
#endif
|
||||
static inline double ImRsqrt(double x) { return 1.0 / sqrt(x); }
|
||||
#endif
|
||||
// - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double
|
||||
// (Exceptionally using templates here but we could also redefine them for those types)
|
||||
@ -394,14 +433,16 @@ static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t)
|
||||
static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; }
|
||||
static inline float ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); }
|
||||
static inline float ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); }
|
||||
static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return 1.0f / ImSqrt(d); return fail_value; }
|
||||
static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; }
|
||||
static inline float ImFloor(float f) { return (float)(int)(f); }
|
||||
static inline float ImFloorSigned(float f) { return (float)((f >= 0 || (int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf()
|
||||
static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); }
|
||||
static inline int ImModPositive(int a, int b) { return (a + b) % b; }
|
||||
static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; }
|
||||
static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }
|
||||
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
|
||||
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
|
||||
IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||
|
||||
// Helpers: Geometry
|
||||
IMGUI_API ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t);
|
||||
@ -417,6 +458,7 @@ IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy);
|
||||
|
||||
// Helper: ImVec1 (1D vector)
|
||||
// (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches)
|
||||
IM_MSVC_RUNTIME_CHECKS_OFF
|
||||
struct ImVec1
|
||||
{
|
||||
float x;
|
||||
@ -470,6 +512,7 @@ struct IMGUI_API ImRect
|
||||
bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; }
|
||||
ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); }
|
||||
};
|
||||
IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||
|
||||
// Helper: ImBitArray
|
||||
inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; }
|
||||
@ -489,12 +532,12 @@ inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) // Works on ran
|
||||
}
|
||||
|
||||
// Helper: ImBitArray class (wrapper over ImBitArray functions)
|
||||
// Store 1-bit per value. NOT CLEARED by constructor.
|
||||
// Store 1-bit per value.
|
||||
template<int BITCOUNT>
|
||||
struct IMGUI_API ImBitArray
|
||||
{
|
||||
ImU32 Storage[(BITCOUNT + 31) >> 5];
|
||||
ImBitArray() { }
|
||||
ImBitArray() { ClearAllBits(); }
|
||||
void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); }
|
||||
void SetAllBits() { memset(Storage, 255, sizeof(Storage)); }
|
||||
bool TestBit(int n) const { IM_ASSERT(n < BITCOUNT); return ImBitArrayTestBit(Storage, n); }
|
||||
@ -576,20 +619,30 @@ struct IMGUI_API ImPool
|
||||
ImVector<T> Buf; // Contiguous data
|
||||
ImGuiStorage Map; // ID->Index
|
||||
ImPoolIdx FreeIdx; // Next free idx to use
|
||||
ImPoolIdx AliveCount; // Number of active/alive items (for display purpose)
|
||||
|
||||
ImPool() { FreeIdx = 0; }
|
||||
ImPool() { FreeIdx = AliveCount = 0; }
|
||||
~ImPool() { Clear(); }
|
||||
T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Buf[idx] : NULL; }
|
||||
T* GetByIndex(ImPoolIdx n) { return &Buf[n]; }
|
||||
ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Buf.Data && p < Buf.Data + Buf.Size); return (ImPoolIdx)(p - Buf.Data); }
|
||||
T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Buf[*p_idx]; *p_idx = FreeIdx; return Add(); }
|
||||
bool Contains(const T* p) const { return (p >= Buf.Data && p < Buf.Data + Buf.Size); }
|
||||
void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = 0; }
|
||||
T* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); return &Buf[idx]; }
|
||||
void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = AliveCount = 0; }
|
||||
T* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); AliveCount++; return &Buf[idx]; }
|
||||
void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); }
|
||||
void Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); }
|
||||
void Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); AliveCount--; }
|
||||
void Reserve(int capacity) { Buf.reserve(capacity); Map.Data.reserve(capacity); }
|
||||
int GetSize() const { return Buf.Size; }
|
||||
|
||||
// To iterate a ImPool: for (int n = 0; n < pool.GetMapSize(); n++) if (T* t = pool.TryGetMapData(n)) { ... }
|
||||
// Can be avoided if you know .Remove() has never been called on the pool, or AliveCount == GetMapSize()
|
||||
int GetAliveCount() const { return AliveCount; } // Number of active/alive items in the pool (for display purpose)
|
||||
int GetBufSize() const { return Buf.Size; }
|
||||
int GetMapSize() const { return Map.Data.Size; } // It is the map we need iterate to find valid items, since we don't have "alive" storage anywhere
|
||||
T* TryGetMapData(ImPoolIdx n) { int idx = Map.Data[n].val_i; if (idx == -1) return NULL; return GetByIndex(idx); }
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
int GetSize() { return GetMapSize(); } // For ImPlot: should use GetMapSize() from (IMGUI_VERSION_NUM >= 18304)
|
||||
#endif
|
||||
};
|
||||
|
||||
// Helper: ImChunkStream<>
|
||||
@ -687,39 +740,58 @@ struct ImDrawDataBuilder
|
||||
enum ImGuiItemFlags_
|
||||
{
|
||||
ImGuiItemFlags_None = 0,
|
||||
ImGuiItemFlags_NoTabStop = 1 << 0, // false
|
||||
ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
|
||||
ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211
|
||||
ImGuiItemFlags_NoNav = 1 << 3, // false
|
||||
ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false
|
||||
ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window
|
||||
ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets)
|
||||
ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed.
|
||||
ImGuiItemFlags_Default_ = 0
|
||||
ImGuiItemFlags_NoTabStop = 1 << 0, // false // Disable keyboard tabbing (FIXME: should merge with _NoNav)
|
||||
ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
|
||||
ImGuiItemFlags_Disabled = 1 << 2, // false // Disable interactions but doesn't affect visuals. See BeginDisabled()/EndDisabled(). See github.com/ocornut/imgui/issues/211
|
||||
ImGuiItemFlags_NoNav = 1 << 3, // false // Disable keyboard/gamepad directional navigation (FIXME: should merge with _NoTabStop)
|
||||
ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false // Disable item being a candidate for default focus (e.g. used by title bar items)
|
||||
ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // Disable MenuItem/Selectable() automatically closing their popup window
|
||||
ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets)
|
||||
ImGuiItemFlags_ReadOnly = 1 << 7 // false // [ALPHA] Allow hovering interactions but underlying value is not changed.
|
||||
};
|
||||
|
||||
// Flags for ItemAdd()
|
||||
// FIXME-NAV: _Focusable is _ALMOST_ what you would expect to be called '_TabStop' but because SetKeyboardFocusHere() works on items with no TabStop we distinguish Focusable from TabStop.
|
||||
enum ImGuiItemAddFlags_
|
||||
{
|
||||
ImGuiItemAddFlags_None = 0,
|
||||
ImGuiItemAddFlags_Focusable = 1 << 0 // FIXME-NAV: In current/legacy scheme, Focusable+TabStop support are opt-in by widgets. We will transition it toward being opt-out, so this flag is expected to eventually disappear.
|
||||
};
|
||||
|
||||
// Storage for LastItem data
|
||||
enum ImGuiItemStatusFlags_
|
||||
{
|
||||
ImGuiItemStatusFlags_None = 0,
|
||||
ImGuiItemStatusFlags_HoveredRect = 1 << 0,
|
||||
ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, // LastItemDisplayRect is valid
|
||||
ImGuiItemStatusFlags_HoveredRect = 1 << 0, // Mouse position is within item rectangle (does NOT mean that the window is in correct z-order and can be hovered!, this is only one part of the most-common IsItemHovered test)
|
||||
ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, // window->DC.LastItemDisplayRect is valid
|
||||
ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets)
|
||||
ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues.
|
||||
ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected", only state changes, in order to easily handle clipping with less issues.
|
||||
ImGuiItemStatusFlags_ToggledOpen = 1 << 4, // Set when TreeNode() reports toggling their open state.
|
||||
ImGuiItemStatusFlags_HasDeactivated = 1 << 5, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag.
|
||||
ImGuiItemStatusFlags_Deactivated = 1 << 6, // Only valid if ImGuiItemStatusFlags_HasDeactivated is set.
|
||||
ImGuiItemStatusFlags_HoveredWindow = 1 << 7 // Override the HoveredWindow test to allow cross-window hover testing.
|
||||
ImGuiItemStatusFlags_HoveredWindow = 1 << 7, // Override the HoveredWindow test to allow cross-window hover testing.
|
||||
ImGuiItemStatusFlags_FocusedByCode = 1 << 8, // Set when the Focusable item just got focused from code.
|
||||
ImGuiItemStatusFlags_FocusedByTabbing = 1 << 9, // Set when the Focusable item just got focused by Tabbing.
|
||||
ImGuiItemStatusFlags_Focused = ImGuiItemStatusFlags_FocusedByCode | ImGuiItemStatusFlags_FocusedByTabbing
|
||||
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
, // [imgui_tests only]
|
||||
ImGuiItemStatusFlags_Openable = 1 << 10, //
|
||||
ImGuiItemStatusFlags_Opened = 1 << 11, //
|
||||
ImGuiItemStatusFlags_Checkable = 1 << 12, //
|
||||
ImGuiItemStatusFlags_Checked = 1 << 13 //
|
||||
ImGuiItemStatusFlags_Openable = 1 << 20, //
|
||||
ImGuiItemStatusFlags_Opened = 1 << 21, //
|
||||
ImGuiItemStatusFlags_Checkable = 1 << 22, //
|
||||
ImGuiItemStatusFlags_Checked = 1 << 23 //
|
||||
#endif
|
||||
};
|
||||
|
||||
// Extend ImGuiInputTextFlags_
|
||||
enum ImGuiInputTextFlagsPrivate_
|
||||
{
|
||||
// [Internal]
|
||||
ImGuiInputTextFlags_Multiline = 1 << 26, // For internal use by InputTextMultiline()
|
||||
ImGuiInputTextFlags_NoMarkEdited = 1 << 27, // For internal use by functions using InputText() before reformatting data
|
||||
ImGuiInputTextFlags_MergedItem = 1 << 28 // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match.
|
||||
};
|
||||
|
||||
// Extend ImGuiButtonFlags_
|
||||
enum ImGuiButtonFlagsPrivate_
|
||||
{
|
||||
@ -733,7 +805,7 @@ enum ImGuiButtonFlagsPrivate_
|
||||
ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping
|
||||
ImGuiButtonFlags_AllowItemOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap()
|
||||
ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press // [UNUSED]
|
||||
ImGuiButtonFlags_Disabled = 1 << 14, // disable interactions
|
||||
//ImGuiButtonFlags_Disabled = 1 << 14, // disable interactions -> use BeginDisabled() or ImGuiItemFlags_Disabled
|
||||
ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine
|
||||
ImGuiButtonFlags_NoKeyModifiers = 1 << 16, // disable mouse interaction if a key modifier is held
|
||||
ImGuiButtonFlags_NoHoldingActiveId = 1 << 17, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only)
|
||||
@ -743,6 +815,12 @@ enum ImGuiButtonFlagsPrivate_
|
||||
ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease
|
||||
};
|
||||
|
||||
// Extend ImGuiComboFlags_
|
||||
enum ImGuiComboFlagsPrivate_
|
||||
{
|
||||
ImGuiComboFlags_CustomPreview = 1 << 20 // enable BeginComboPreview()
|
||||
};
|
||||
|
||||
// Extend ImGuiSliderFlags_
|
||||
enum ImGuiSliderFlagsPrivate_
|
||||
{
|
||||
@ -755,12 +833,13 @@ enum ImGuiSelectableFlagsPrivate_
|
||||
{
|
||||
// NB: need to be in sync with last value of ImGuiSelectableFlags_
|
||||
ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20,
|
||||
ImGuiSelectableFlags_SelectOnClick = 1 << 21, // Override button behavior to react on Click (default is Click+Release)
|
||||
ImGuiSelectableFlags_SelectOnRelease = 1 << 22, // Override button behavior to react on Release (default is Click+Release)
|
||||
ImGuiSelectableFlags_SpanAvailWidth = 1 << 23, // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus)
|
||||
ImGuiSelectableFlags_DrawHoveredWhenHeld = 1 << 24, // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow.
|
||||
ImGuiSelectableFlags_SetNavIdOnHover = 1 << 25, // Set Nav/Focus ID on mouse hover (used by MenuItem)
|
||||
ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 26 // Disable padding each side with ItemSpacing * 0.5f
|
||||
ImGuiSelectableFlags_SelectOnNav = 1 << 21, // (WIP) Auto-select when moved into. This is not exposed in public API as to handle multi-select and modifiers we will need user to explicitly control focus scope. May be replaced with a BeginSelection() API.
|
||||
ImGuiSelectableFlags_SelectOnClick = 1 << 22, // Override button behavior to react on Click (default is Click+Release)
|
||||
ImGuiSelectableFlags_SelectOnRelease = 1 << 23, // Override button behavior to react on Release (default is Click+Release)
|
||||
ImGuiSelectableFlags_SpanAvailWidth = 1 << 24, // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus)
|
||||
ImGuiSelectableFlags_DrawHoveredWhenHeld = 1 << 25, // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow.
|
||||
ImGuiSelectableFlags_SetNavIdOnHover = 1 << 26, // Set Nav/Focus ID on mouse hover (used by MenuItem)
|
||||
ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 27 // Disable padding each side with ItemSpacing * 0.5f
|
||||
};
|
||||
|
||||
// Extend ImGuiTreeNodeFlags_
|
||||
@ -827,6 +906,7 @@ enum ImGuiInputSource
|
||||
ImGuiInputSource_Keyboard,
|
||||
ImGuiInputSource_Gamepad,
|
||||
ImGuiInputSource_Nav, // Stored in g.ActiveIdSource only
|
||||
ImGuiInputSource_Clipboard, // Currently only used by InputText()
|
||||
ImGuiInputSource_COUNT
|
||||
};
|
||||
|
||||
@ -930,6 +1010,19 @@ struct ImGuiStyleMod
|
||||
ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; }
|
||||
};
|
||||
|
||||
// Storage data for BeginComboPreview()/EndComboPreview()
|
||||
struct IMGUI_API ImGuiComboPreviewData
|
||||
{
|
||||
ImRect PreviewRect;
|
||||
ImVec2 BackupCursorPos;
|
||||
ImVec2 BackupCursorMaxPos;
|
||||
ImVec2 BackupCursorPosPrevLine;
|
||||
float BackupPrevLineTextBaseOffset;
|
||||
ImGuiLayoutType BackupLayout;
|
||||
|
||||
ImGuiComboPreviewData() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Stacked storage data for BeginGroup()/EndGroup()
|
||||
struct IMGUI_API ImGuiGroupData
|
||||
{
|
||||
@ -949,14 +1042,19 @@ struct IMGUI_API ImGuiGroupData
|
||||
// Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper.
|
||||
struct IMGUI_API ImGuiMenuColumns
|
||||
{
|
||||
float Spacing;
|
||||
float Width, NextWidth;
|
||||
float Pos[3], NextWidths[3];
|
||||
ImU32 TotalWidth;
|
||||
ImU32 NextTotalWidth;
|
||||
ImU16 Spacing;
|
||||
ImU16 OffsetIcon; // Always zero for now
|
||||
ImU16 OffsetLabel; // Offsets are locked in Update()
|
||||
ImU16 OffsetShortcut;
|
||||
ImU16 OffsetMark;
|
||||
ImU16 Widths[4]; // Width of: Icon, Label, Shortcut, Mark (accumulators for current frame)
|
||||
|
||||
ImGuiMenuColumns() { memset(this, 0, sizeof(*this)); }
|
||||
void Update(int count, float spacing, bool clear);
|
||||
float DeclColumns(float w0, float w1, float w2);
|
||||
float CalcExtraSpace(float avail_w) const;
|
||||
void Update(float spacing, bool window_reappearing);
|
||||
float DeclColumns(float w_icon, float w_label, float w_shortcut, float w_mark);
|
||||
void CalcNextTotalWidth(bool update_offsets);
|
||||
};
|
||||
|
||||
// Internal state of the currently focused/edited text input box
|
||||
@ -976,7 +1074,7 @@ struct IMGUI_API ImGuiInputTextState
|
||||
bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!)
|
||||
bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
|
||||
bool Edited; // edited this frame
|
||||
ImGuiInputTextFlags UserFlags; // Temporarily set while we call user's callback
|
||||
ImGuiInputTextFlags Flags; // copy of InputText() flags
|
||||
ImGuiInputTextCallback UserCallback; // "
|
||||
void* UserCallbackData; // "
|
||||
|
||||
@ -992,6 +1090,9 @@ struct IMGUI_API ImGuiInputTextState
|
||||
void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); }
|
||||
bool HasSelection() const { return Stb.select_start != Stb.select_end; }
|
||||
void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; }
|
||||
int GetCursorPos() const { return Stb.cursor; }
|
||||
int GetSelectionStart() const { return Stb.select_start; }
|
||||
int GetSelectionEnd() const { return Stb.select_end; }
|
||||
void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; }
|
||||
};
|
||||
|
||||
@ -1009,18 +1110,18 @@ struct ImGuiPopupData
|
||||
ImGuiPopupData() { memset(this, 0, sizeof(*this)); OpenFrameCount = -1; }
|
||||
};
|
||||
|
||||
struct ImGuiNavMoveResult
|
||||
struct ImGuiNavItemData
|
||||
{
|
||||
ImGuiWindow* Window; // Best candidate window
|
||||
ImGuiID ID; // Best candidate ID
|
||||
ImGuiID FocusScopeId; // Best candidate focus scope ID
|
||||
float DistBox; // Best candidate box distance to current NavId
|
||||
float DistCenter; // Best candidate center distance to current NavId
|
||||
float DistAxial;
|
||||
ImRect RectRel; // Best candidate bounding box in window relative space
|
||||
ImGuiWindow* Window; // Init,Move // Best candidate window (result->ItemWindow->RootWindowForNav == request->Window)
|
||||
ImGuiID ID; // Init,Move // Best candidate item ID
|
||||
ImGuiID FocusScopeId; // Init,Move // Best candidate focus scope ID
|
||||
ImRect RectRel; // Init,Move // Best candidate bounding box in window relative space
|
||||
float DistBox; // Move // Best candidate box distance to current NavId
|
||||
float DistCenter; // Move // Best candidate center distance to current NavId
|
||||
float DistAxial; // Move // Best candidate axial distance to current NavId
|
||||
|
||||
ImGuiNavMoveResult() { Clear(); }
|
||||
void Clear() { Window = NULL; ID = FocusScopeId = 0; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); }
|
||||
ImGuiNavItemData() { Clear(); }
|
||||
void Clear() { Window = NULL; ID = FocusScopeId = 0; RectRel = ImRect(); DistBox = DistCenter = DistAxial = FLT_MAX; }
|
||||
};
|
||||
|
||||
enum ImGuiNextWindowDataFlags_
|
||||
@ -1053,7 +1154,7 @@ struct ImGuiNextWindowData
|
||||
ImGuiSizeCallback SizeCallback;
|
||||
void* SizeCallbackUserData;
|
||||
float BgAlphaVal; // Override background alpha
|
||||
ImVec2 MenuBarOffsetMinVal; // *Always on* This is not exposed publicly, so we don't clear it.
|
||||
ImVec2 MenuBarOffsetMinVal; // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?)
|
||||
|
||||
ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); }
|
||||
inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }
|
||||
@ -1078,6 +1179,25 @@ struct ImGuiNextItemData
|
||||
inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } // Also cleared manually by ItemAdd()!
|
||||
};
|
||||
|
||||
// Status storage for the last submitted item
|
||||
struct ImGuiLastItemData
|
||||
{
|
||||
ImGuiID ID;
|
||||
ImGuiItemFlags InFlags; // See ImGuiItemFlags_
|
||||
ImGuiItemStatusFlags StatusFlags; // See ImGuiItemStatusFlags_
|
||||
ImRect Rect;
|
||||
ImRect DisplayRect;
|
||||
|
||||
ImGuiLastItemData() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Data saved for each window pushed into the stack
|
||||
struct ImGuiWindowStackData
|
||||
{
|
||||
ImGuiWindow* Window;
|
||||
ImGuiLastItemData ParentLastItemDataBackup;
|
||||
};
|
||||
|
||||
struct ImGuiShrinkWidthItem
|
||||
{
|
||||
int Index;
|
||||
@ -1180,14 +1300,21 @@ struct ImGuiViewportP : public ImGuiViewport
|
||||
|
||||
ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!)
|
||||
ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height).
|
||||
ImVec2 CurrWorkOffsetMin; // Work Area: Offset being built/increased during current frame
|
||||
ImVec2 CurrWorkOffsetMax; // Work Area: Offset being built/decreased during current frame
|
||||
ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f.
|
||||
ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f.
|
||||
|
||||
ImGuiViewportP() { DrawListsLastFrame[0] = DrawListsLastFrame[1] = -1; DrawLists[0] = DrawLists[1] = NULL; }
|
||||
~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); }
|
||||
ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
|
||||
ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); }
|
||||
void UpdateWorkRect() { WorkPos = ImVec2(Pos.x + WorkOffsetMin.x, Pos.y + WorkOffsetMin.y); WorkSize = ImVec2(ImMax(0.0f, Size.x - WorkOffsetMin.x + WorkOffsetMax.x), ImMax(0.0f, Size.y - WorkOffsetMin.y + WorkOffsetMax.y)); }
|
||||
ImGuiViewportP() { DrawListsLastFrame[0] = DrawListsLastFrame[1] = -1; DrawLists[0] = DrawLists[1] = NULL; }
|
||||
~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); }
|
||||
|
||||
// Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect)
|
||||
ImVec2 CalcWorkRectPos(const ImVec2& off_min) const { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); }
|
||||
ImVec2 CalcWorkRectSize(const ImVec2& off_min, const ImVec2& off_max) const { return ImVec2(ImMax(0.0f, Size.x - off_min.x + off_max.x), ImMax(0.0f, Size.y - off_min.y + off_max.y)); }
|
||||
void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkOffsetMin); WorkSize = CalcWorkRectSize(WorkOffsetMin, WorkOffsetMax); } // Update public fields
|
||||
|
||||
// Helpers to retrieve ImRect (we don't need to store BuildWorkRect as every access tend to change it, hence the code asymmetry)
|
||||
ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
|
||||
ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); }
|
||||
ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkOffsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkOffsetMin, BuildWorkOffsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1311,11 +1438,12 @@ struct ImGuiContext
|
||||
|
||||
// Windows state
|
||||
ImVector<ImGuiWindow*> Windows; // Windows, sorted in display order, back to front
|
||||
ImVector<ImGuiWindow*> WindowsFocusOrder; // Windows, sorted in focus order, back to front. (FIXME: We could only store root windows here! Need to sort out the Docking equivalent which is RootWindowDockStop and is unfortunately a little more dynamic)
|
||||
ImVector<ImGuiWindow*> WindowsFocusOrder; // Root windows, sorted in focus order, back to front.
|
||||
ImVector<ImGuiWindow*> WindowsTempSortBuffer; // Temporary buffer used in EndFrame() to reorder windows so parents are kept before their child
|
||||
ImVector<ImGuiWindow*> CurrentWindowStack;
|
||||
ImVector<ImGuiWindowStackData> CurrentWindowStack;
|
||||
ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow*
|
||||
int WindowsActiveCount; // Number of unique windows submitted by frame
|
||||
ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING)
|
||||
ImGuiWindow* CurrentWindow; // Window being drawn into
|
||||
ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs.
|
||||
ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set.
|
||||
@ -1358,8 +1486,10 @@ struct ImGuiContext
|
||||
float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.
|
||||
|
||||
// Next window/item data
|
||||
ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions
|
||||
ImGuiItemFlags CurrentItemFlags; // == g.ItemFlagsStack.back()
|
||||
ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions
|
||||
ImGuiLastItemData LastItemData; // Storage for last submitted item (setup by ItemAdd)
|
||||
ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions
|
||||
|
||||
// Shared stacks
|
||||
ImVector<ImGuiColorMod> ColorStack; // Stack for PushStyleColor()/PopStyleColor() - inherited by Begin()
|
||||
@ -1407,9 +1537,9 @@ struct ImGuiContext
|
||||
ImGuiKeyModFlags NavMoveRequestKeyMods;
|
||||
ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request
|
||||
ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename?
|
||||
ImGuiNavMoveResult NavMoveResultLocal; // Best move request candidate within NavWindow
|
||||
ImGuiNavMoveResult NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag)
|
||||
ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag)
|
||||
ImGuiNavItemData NavMoveResultLocal; // Best move request candidate within NavWindow
|
||||
ImGuiNavItemData NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag)
|
||||
ImGuiNavItemData NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag)
|
||||
ImGuiWindow* NavWrapRequestWindow; // Window which requested trying nav wrap-around.
|
||||
ImGuiNavMoveFlags NavWrapRequestFlags; // Wrap-around operation flags.
|
||||
|
||||
@ -1428,7 +1558,7 @@ struct ImGuiContext
|
||||
int TabFocusRequestCurrCounterTabStop; // Tab item being requested for focus, stored as an index
|
||||
int TabFocusRequestNextCounterRegular; // Stored for next frame
|
||||
int TabFocusRequestNextCounterTabStop; // "
|
||||
bool TabFocusPressed; //
|
||||
bool TabFocusPressed; // Set in NewFrame() when user pressed Tab
|
||||
|
||||
// Render
|
||||
float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list)
|
||||
@ -1455,8 +1585,9 @@ struct ImGuiContext
|
||||
|
||||
// Table
|
||||
ImGuiTable* CurrentTable;
|
||||
int CurrentTableStackIdx;
|
||||
ImPool<ImGuiTable> Tables;
|
||||
ImVector<ImGuiPtrOrIndex> CurrentTableStack;
|
||||
ImVector<ImGuiTableTempData> TablesTempDataStack;
|
||||
ImVector<float> TablesLastTimeActive; // Last used timestamp of each tables (SOA, for efficient GC)
|
||||
ImVector<ImDrawChannel> DrawChannelsTempMergeBuffer;
|
||||
|
||||
@ -1476,11 +1607,13 @@ struct ImGuiContext
|
||||
float ColorEditLastSat; // Backup of last Saturation associated to LastColor[3], so we can restore Saturation in lossy RGB<>HSV round trips
|
||||
float ColorEditLastColor[3];
|
||||
ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker.
|
||||
ImGuiComboPreviewData ComboPreviewData;
|
||||
float SliderCurrentAccum; // Accumulated slider delta when using navigation controls.
|
||||
bool SliderCurrentAccumDirty; // Has the accumulated slider delta changed since last time we tried to apply it?
|
||||
bool DragCurrentAccumDirty;
|
||||
float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings
|
||||
float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio
|
||||
float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled()
|
||||
float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage?
|
||||
int TooltipOverrideCount;
|
||||
float TooltipSlowDelay; // Time before slow tooltips appears (FIXME: This is temporary until we merge in tooltip timer+priority work)
|
||||
@ -1523,6 +1656,7 @@ struct ImGuiContext
|
||||
// Misc
|
||||
float FramerateSecPerFrame[120]; // Calculate estimate of framerate for user over the last 2 seconds.
|
||||
int FramerateSecPerFrameIdx;
|
||||
int FramerateSecPerFrameCount;
|
||||
float FramerateSecPerFrameAccum;
|
||||
int WantCaptureMouseNextFrame; // Explicit capture via CaptureKeyboardFromApp()/CaptureMouseFromApp() sets those flags
|
||||
int WantCaptureKeyboardNextFrame;
|
||||
@ -1582,6 +1716,8 @@ struct ImGuiContext
|
||||
LastActiveId = 0;
|
||||
LastActiveIdTimer = 0.0f;
|
||||
|
||||
CurrentItemFlags = ImGuiItemFlags_None;
|
||||
|
||||
NavWindow = NULL;
|
||||
NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0;
|
||||
NavJustTabbedId = NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0;
|
||||
@ -1632,11 +1768,12 @@ struct ImGuiContext
|
||||
memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal));
|
||||
|
||||
CurrentTable = NULL;
|
||||
CurrentTableStackIdx = -1;
|
||||
CurrentTabBar = NULL;
|
||||
|
||||
LastValidMousePos = ImVec2(0.0f, 0.0f);
|
||||
TempInputId = 0;
|
||||
ColorEditOptions = ImGuiColorEditFlags__OptionsDefault;
|
||||
ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_;
|
||||
ColorEditLastHue = ColorEditLastSat = 0.0f;
|
||||
ColorEditLastColor[0] = ColorEditLastColor[1] = ColorEditLastColor[2] = FLT_MAX;
|
||||
SliderCurrentAccum = 0.0f;
|
||||
@ -1644,6 +1781,7 @@ struct ImGuiContext
|
||||
DragCurrentAccumDirty = false;
|
||||
DragCurrentAccum = 0.0f;
|
||||
DragSpeedDefaultRatio = 1.0f / 100.0f;
|
||||
DisabledAlphaBackup = 0.0f;
|
||||
ScrollbarClickDeltaToGrabCenter = 0.0f;
|
||||
TooltipOverrideCount = 0;
|
||||
TooltipSlowDelay = 0.50f;
|
||||
@ -1668,7 +1806,7 @@ struct ImGuiContext
|
||||
DebugItemPickerBreakId = 0;
|
||||
|
||||
memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame));
|
||||
FramerateSecPerFrameIdx = 0;
|
||||
FramerateSecPerFrameIdx = FramerateSecPerFrameCount = 0;
|
||||
FramerateSecPerFrameAccum = 0.0f;
|
||||
WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1;
|
||||
memset(TempBuffer, 0, sizeof(TempBuffer));
|
||||
@ -1698,16 +1836,10 @@ struct IMGUI_API ImGuiWindowTempData
|
||||
ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API.
|
||||
ImVec1 GroupOffset;
|
||||
|
||||
// Last item status
|
||||
ImGuiID LastItemId; // ID for last item
|
||||
ImGuiItemStatusFlags LastItemStatusFlags; // Status flags for last item (see ImGuiItemStatusFlags_)
|
||||
ImRect LastItemRect; // Interaction rect for last item
|
||||
ImRect LastItemDisplayRect; // End-user display rect for last item (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect)
|
||||
|
||||
// Keyboard/Gamepad navigation
|
||||
ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1)
|
||||
int NavLayerActiveMask; // Which layers have been written to (result from previous frame)
|
||||
int NavLayerActiveMaskNext; // Which layers have been written to (accumulator for current frame)
|
||||
short NavLayersActiveMask; // Which layers have been written to (result from previous frame)
|
||||
short NavLayersActiveMaskNext;// Which layers have been written to (accumulator for current frame)
|
||||
ImGuiID NavFocusScopeIdCurrent; // Current focus scope ID while appending
|
||||
bool NavHideHighlightOneFrame;
|
||||
bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f)
|
||||
@ -1729,7 +1861,6 @@ struct IMGUI_API ImGuiWindowTempData
|
||||
|
||||
// Local parameters stacks
|
||||
// We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings.
|
||||
ImGuiItemFlags ItemFlags; // == g.ItemFlagsStack.back()
|
||||
float ItemWidth; // Current item width (>0.0: width in pixels, <0.0: align xx pixels to the right of window).
|
||||
float TextWrapPos; // Current text wrap pos.
|
||||
ImVector<float> ItemWidthStack; // Store item widths to restore (attention: .back() is not == ItemWidth)
|
||||
@ -1774,8 +1905,9 @@ struct IMGUI_API ImGuiWindow
|
||||
bool HasCloseButton; // Set when the window has a close button (p_open != NULL)
|
||||
signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3)
|
||||
short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
|
||||
short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0.
|
||||
short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues.
|
||||
short BeginOrderWithinParent; // Begin() order within immediate parent window, if we are a child window. Otherwise 0.
|
||||
short BeginOrderWithinContext; // Begin() order within entire imgui context. This is mostly used for debugging submission order related issues.
|
||||
short FocusOrder; // Order within WindowsFocusOrder[], altered when windows are focused.
|
||||
ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)
|
||||
ImS8 AutoFitFramesX, AutoFitFramesY;
|
||||
ImS8 AutoFitChildAxises;
|
||||
@ -1784,6 +1916,7 @@ struct IMGUI_API ImGuiWindow
|
||||
ImS8 HiddenFramesCanSkipItems; // Hide the window for N frames
|
||||
ImS8 HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size
|
||||
ImS8 HiddenFramesForRenderOnly; // Hide the window until frame N at Render() time only
|
||||
ImS8 DisableInputsFrames; // Disable window interactions for N frames
|
||||
ImGuiCond SetWindowPosAllowFlags : 8; // store acceptable condition flags for SetNextWindowPos() use.
|
||||
ImGuiCond SetWindowSizeAllowFlags : 8; // store acceptable condition flags for SetNextWindowSize() use.
|
||||
ImGuiCond SetWindowCollapsedAllowFlags : 8; // store acceptable condition flags for SetNextWindowCollapsed() use.
|
||||
@ -1849,19 +1982,6 @@ public:
|
||||
ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); }
|
||||
};
|
||||
|
||||
// Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data.
|
||||
struct ImGuiLastItemDataBackup
|
||||
{
|
||||
ImGuiID LastItemId;
|
||||
ImGuiItemStatusFlags LastItemStatusFlags;
|
||||
ImRect LastItemRect;
|
||||
ImRect LastItemDisplayRect;
|
||||
|
||||
ImGuiLastItemDataBackup() { Backup(); }
|
||||
void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; }
|
||||
void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Tab bar, Tab item support
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1877,11 +1997,12 @@ enum ImGuiTabBarFlagsPrivate_
|
||||
// Extend ImGuiTabItemFlags_
|
||||
enum ImGuiTabItemFlagsPrivate_
|
||||
{
|
||||
ImGuiTabItemFlags_SectionMask_ = ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing,
|
||||
ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout)
|
||||
ImGuiTabItemFlags_Button = 1 << 21 // Used by TabItemButton, change the tab item behavior to mimic a button
|
||||
};
|
||||
|
||||
// Storage for one active tab item (sizeof() 28~32 bytes)
|
||||
// Storage for one active tab item (sizeof() 40 bytes)
|
||||
struct ImGuiTabItem
|
||||
{
|
||||
ImGuiID ID;
|
||||
@ -1891,12 +2012,12 @@ struct ImGuiTabItem
|
||||
float Offset; // Position relative to beginning of tab
|
||||
float Width; // Width currently displayed
|
||||
float ContentWidth; // Width of label, stored during BeginTabItem() call
|
||||
ImS16 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames
|
||||
ImS32 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames
|
||||
ImS16 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable
|
||||
ImS16 IndexDuringLayout; // Index only used during TabBarLayout()
|
||||
bool WantClose; // Marked as closed by SetTabItemClosed()
|
||||
|
||||
ImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; NameOffset = BeginOrder = IndexDuringLayout = -1; }
|
||||
ImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; BeginOrder = IndexDuringLayout = -1; }
|
||||
};
|
||||
|
||||
// Storage for a tab bar (sizeof() 152 bytes)
|
||||
@ -1922,7 +2043,7 @@ struct ImGuiTabBar
|
||||
float ScrollingRectMinX;
|
||||
float ScrollingRectMaxX;
|
||||
ImGuiID ReorderRequestTabId;
|
||||
ImS8 ReorderRequestDir;
|
||||
ImS16 ReorderRequestOffset;
|
||||
ImS8 BeginCount;
|
||||
bool WantLayout;
|
||||
bool VisibleTabWasSubmitted;
|
||||
@ -1938,7 +2059,7 @@ struct ImGuiTabBar
|
||||
int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); }
|
||||
const char* GetTabName(const ImGuiTabItem* tab) const
|
||||
{
|
||||
IM_ASSERT(tab->NameOffset != -1 && (int)tab->NameOffset < TabsNames.Buf.Size);
|
||||
IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size);
|
||||
return TabsNames.Buf.Data + tab->NameOffset;
|
||||
}
|
||||
};
|
||||
@ -1947,8 +2068,6 @@ struct ImGuiTabBar
|
||||
// [SECTION] Table support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef IMGUI_HAS_TABLE
|
||||
|
||||
#define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color.
|
||||
#define IMGUI_TABLE_MAX_COLUMNS 64 // sizeof(ImU64) * 8. This is solely because we frequently encode columns set in a ImU64.
|
||||
#define IMGUI_TABLE_MAX_DRAW_CHANNELS (4 + 64 * 2) // See TableSetupDrawChannels()
|
||||
@ -1987,10 +2106,11 @@ struct ImGuiTableColumn
|
||||
ImGuiTableColumnIdx NextEnabledColumn; // Index of next enabled/visible column within Columns[], -1 if last enabled/visible column
|
||||
ImGuiTableColumnIdx SortOrder; // Index of this column within sort specs, -1 if not sorting on this column, 0 for single-sort, may be >0 on multi-sort
|
||||
ImGuiTableDrawChannelIdx DrawChannelCurrent; // Index within DrawSplitter.Channels[]
|
||||
ImGuiTableDrawChannelIdx DrawChannelFrozen;
|
||||
ImGuiTableDrawChannelIdx DrawChannelUnfrozen;
|
||||
bool IsEnabled; // Is the column not marked Hidden by the user? (even if off view, e.g. clipped by scrolling).
|
||||
bool IsEnabledNextFrame;
|
||||
ImGuiTableDrawChannelIdx DrawChannelFrozen; // Draw channels for frozen rows (often headers)
|
||||
ImGuiTableDrawChannelIdx DrawChannelUnfrozen; // Draw channels for unfrozen rows
|
||||
bool IsEnabled; // IsUserEnabled && (Flags & ImGuiTableColumnFlags_Disabled) == 0
|
||||
bool IsUserEnabled; // Is the column not marked Hidden by the user? (unrelated to being off view, e.g. clipped by scrolling).
|
||||
bool IsUserEnabledNextFrame;
|
||||
bool IsVisibleX; // Is actually in view (e.g. overlapping the host window clipping rectangle, not scrolled).
|
||||
bool IsVisibleY;
|
||||
bool IsRequestOutput; // Return value for TableSetColumnIndex() / TableNextColumn(): whether we request user to output contents or not.
|
||||
@ -2025,12 +2145,13 @@ struct ImGuiTableCellData
|
||||
ImGuiTableColumnIdx Column; // Column number
|
||||
};
|
||||
|
||||
// FIXME-TABLE: transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData
|
||||
// FIXME-TABLE: more transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData
|
||||
struct ImGuiTable
|
||||
{
|
||||
ImGuiID ID;
|
||||
ImGuiTableFlags Flags;
|
||||
void* RawData; // Single allocation to hold Columns[], DisplayOrderToIndex[] and RowCellData[]
|
||||
ImGuiTableTempData* TempData; // Transient data while table is active. Point within g.CurrentTableStack[]
|
||||
ImSpan<ImGuiTableColumn> Columns; // Point within RawData[]
|
||||
ImSpan<ImGuiTableColumnIdx> DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1)
|
||||
ImSpan<ImGuiTableCellData> RowCellData; // Point within RawData[]. Store cells background requests for current row.
|
||||
@ -2082,22 +2203,13 @@ struct ImGuiTable
|
||||
ImRect Bg0ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG0/1 channel. This tends to be == OuterWindow->ClipRect at BeginTable() because output in BG0/BG1 is cpu-clipped
|
||||
ImRect Bg2ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG2 channel. This tends to be a correct, tight-fit, because output to BG2 are done by widgets relying on regular ClipRect.
|
||||
ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window.
|
||||
ImRect HostBackupWorkRect; // Backup of InnerWindow->WorkRect at the end of BeginTable()
|
||||
ImRect HostBackupParentWorkRect; // Backup of InnerWindow->ParentWorkRect at the end of BeginTable()
|
||||
ImRect HostBackupInnerClipRect; // Backup of InnerWindow->ClipRect during PushTableBackground()/PopTableBackground()
|
||||
ImVec2 HostBackupPrevLineSize; // Backup of InnerWindow->DC.PrevLineSize at the end of BeginTable()
|
||||
ImVec2 HostBackupCurrLineSize; // Backup of InnerWindow->DC.CurrLineSize at the end of BeginTable()
|
||||
ImVec2 HostBackupCursorMaxPos; // Backup of InnerWindow->DC.CursorMaxPos at the end of BeginTable()
|
||||
ImVec2 UserOuterSize; // outer_size.x passed to BeginTable()
|
||||
ImVec1 HostBackupColumnsOffset; // Backup of OuterWindow->DC.ColumnsOffset at the end of BeginTable()
|
||||
float HostBackupItemWidth; // Backup of OuterWindow->DC.ItemWidth at the end of BeginTable()
|
||||
int HostBackupItemWidthStackSize;// Backup of OuterWindow->DC.ItemWidthStack.Size at the end of BeginTable()
|
||||
ImGuiWindow* OuterWindow; // Parent window for the table
|
||||
ImGuiWindow* InnerWindow; // Window holding the table data (== OuterWindow or a child window)
|
||||
ImGuiTextBuffer ColumnsNames; // Contiguous buffer holding columns names
|
||||
ImDrawListSplitter DrawSplitter; // We carry our own ImDrawList splitter to allow recursion (FIXME: could be stored outside, worst case we need 1 splitter per recursing table)
|
||||
ImDrawListSplitter* DrawSplitter; // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly
|
||||
ImGuiTableColumnSortSpecs SortSpecsSingle;
|
||||
ImVector<ImGuiTableColumnSortSpecs> SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would work be good.
|
||||
ImVector<ImGuiTableColumnSortSpecs> SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good.
|
||||
ImGuiTableSortSpecs SortSpecs; // Public facing sorts specs, this is what we return in TableGetSortSpecs()
|
||||
ImGuiTableColumnIdx SortSpecsCount;
|
||||
ImGuiTableColumnIdx ColumnsEnabledCount; // Number of enabled columns (<= ColumnsCount)
|
||||
@ -2144,6 +2256,29 @@ struct ImGuiTable
|
||||
IMGUI_API ~ImGuiTable() { IM_FREE(RawData); }
|
||||
};
|
||||
|
||||
// Transient data that are only needed between BeginTable() and EndTable(), those buffers are shared (1 per level of stacked table).
|
||||
// - Accessing those requires chasing an extra pointer so for very frequently used data we leave them in the main table structure.
|
||||
// - We also leave out of this structure data that tend to be particularly useful for debugging/metrics.
|
||||
struct ImGuiTableTempData
|
||||
{
|
||||
int TableIndex; // Index in g.Tables.Buf[] pool
|
||||
float LastTimeActive; // Last timestamp this structure was used
|
||||
|
||||
ImVec2 UserOuterSize; // outer_size.x passed to BeginTable()
|
||||
ImDrawListSplitter DrawSplitter;
|
||||
|
||||
ImRect HostBackupWorkRect; // Backup of InnerWindow->WorkRect at the end of BeginTable()
|
||||
ImRect HostBackupParentWorkRect; // Backup of InnerWindow->ParentWorkRect at the end of BeginTable()
|
||||
ImVec2 HostBackupPrevLineSize; // Backup of InnerWindow->DC.PrevLineSize at the end of BeginTable()
|
||||
ImVec2 HostBackupCurrLineSize; // Backup of InnerWindow->DC.CurrLineSize at the end of BeginTable()
|
||||
ImVec2 HostBackupCursorMaxPos; // Backup of InnerWindow->DC.CursorMaxPos at the end of BeginTable()
|
||||
ImVec1 HostBackupColumnsOffset; // Backup of OuterWindow->DC.ColumnsOffset at the end of BeginTable()
|
||||
float HostBackupItemWidth; // Backup of OuterWindow->DC.ItemWidth at the end of BeginTable()
|
||||
int HostBackupItemWidthStackSize;//Backup of OuterWindow->DC.ItemWidthStack.Size at the end of BeginTable()
|
||||
|
||||
IMGUI_API ImGuiTableTempData() { memset(this, 0, sizeof(*this)); LastTimeActive = -1.0f; }
|
||||
};
|
||||
|
||||
// sizeof() ~ 12
|
||||
struct ImGuiTableColumnSettings
|
||||
{
|
||||
@ -2182,8 +2317,6 @@ struct ImGuiTableSettings
|
||||
ImGuiTableColumnSettings* GetColumnSettings() { return (ImGuiTableColumnSettings*)(this + 1); }
|
||||
};
|
||||
|
||||
#endif // #ifdef IMGUI_HAS_TABLE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] ImGui internal API
|
||||
// No guarantee of forward compatibility here!
|
||||
@ -2205,7 +2338,6 @@ namespace ImGui
|
||||
IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent);
|
||||
IMGUI_API bool IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below);
|
||||
IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window);
|
||||
IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window);
|
||||
IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0);
|
||||
IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0);
|
||||
IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0);
|
||||
@ -2258,11 +2390,11 @@ namespace ImGui
|
||||
IMGUI_API ImVec2 ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect);
|
||||
|
||||
// Basic Accessors
|
||||
inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemId; } // Get ID of last item (~~ often same ImGui::GetID(label) beforehand)
|
||||
inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemStatusFlags; }
|
||||
inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.LastItemData.ID; } // Get ID of last item (~~ often same ImGui::GetID(label) beforehand)
|
||||
inline ImGuiItemStatusFlags GetItemStatusFlags(){ ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; }
|
||||
inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.InFlags; }
|
||||
inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; }
|
||||
inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; }
|
||||
inline ImGuiItemFlags GetItemsFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.ItemFlags; }
|
||||
IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window);
|
||||
IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window);
|
||||
IMGUI_API void ClearActiveID();
|
||||
@ -2276,21 +2408,30 @@ namespace ImGui
|
||||
// Basic Helpers for widget code
|
||||
IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f);
|
||||
IMGUI_API void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f);
|
||||
IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL);
|
||||
IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemAddFlags flags = 0);
|
||||
IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id);
|
||||
IMGUI_API void ItemFocusable(ImGuiWindow* window, ImGuiID id);
|
||||
IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged);
|
||||
IMGUI_API void SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags status_flags, const ImRect& item_rect);
|
||||
IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); // Return true if focus is requested
|
||||
IMGUI_API void FocusableItemUnregister(ImGuiWindow* window);
|
||||
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h);
|
||||
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
|
||||
IMGUI_API void PushMultiItemsWidths(int components, float width_full);
|
||||
IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled);
|
||||
IMGUI_API void PopItemFlag();
|
||||
IMGUI_API bool IsItemToggledSelection(); // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly)
|
||||
IMGUI_API ImVec2 GetContentRegionMaxAbs();
|
||||
IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess);
|
||||
|
||||
// Parameter stacks
|
||||
IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled);
|
||||
IMGUI_API void PopItemFlag();
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
// If you have old/custom copy-and-pasted widgets that used FocusableItemRegister():
|
||||
// (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool focused = FocusableItemRegister(...)'
|
||||
// (New) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0'
|
||||
// Widget code are simplified as there's no need to call FocusableItemUnregister() while managing the transition from regular widget to TempInputText()
|
||||
inline bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id) { IM_ASSERT(0); IM_UNUSED(window); IM_UNUSED(id); return false; } // -> pass ImGuiItemAddFlags_Focusable flag to ItemAdd()
|
||||
inline IM_NORETURN void FocusableItemUnregister(ImGuiWindow* window) { IM_ASSERT(0); IM_UNUSED(window); } // -> unnecessary: TempInputText() uses ImGuiInputTextFlags_MergedItem
|
||||
#endif
|
||||
|
||||
// Logging/Capture
|
||||
IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name.
|
||||
IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer
|
||||
@ -2305,9 +2446,19 @@ namespace ImGui
|
||||
IMGUI_API bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags);
|
||||
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
|
||||
IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags);
|
||||
IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow* window);
|
||||
IMGUI_API ImGuiWindow* GetTopMostPopupModal();
|
||||
IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window);
|
||||
IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy);
|
||||
IMGUI_API bool BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags);
|
||||
|
||||
// Menus
|
||||
IMGUI_API bool MenuItemEx(const char* label, const char* icon, const char* shortcut = NULL, bool selected = false, bool enabled = true);
|
||||
|
||||
// Combos
|
||||
IMGUI_API bool BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags);
|
||||
IMGUI_API bool BeginComboPreview();
|
||||
IMGUI_API void EndComboPreview();
|
||||
|
||||
// Gamepad/Keyboard Navigation
|
||||
IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit);
|
||||
@ -2319,7 +2470,7 @@ namespace ImGui
|
||||
IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f);
|
||||
IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate);
|
||||
IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again.
|
||||
IMGUI_API void SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel);
|
||||
IMGUI_API void SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel);
|
||||
|
||||
// Focus Scope (WIP)
|
||||
// This is generally used to identify a selection set (multiple of which may be in the same window), as selection
|
||||
@ -2332,6 +2483,7 @@ namespace ImGui
|
||||
// Inputs
|
||||
// FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions.
|
||||
IMGUI_API void SetItemUsingMouseWheel();
|
||||
IMGUI_API void SetActiveIdUsingNavAndKeys();
|
||||
inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; }
|
||||
inline bool IsActiveIdUsingNavInput(ImGuiNavInput input) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavInputMask & (1 << input)) != 0; }
|
||||
inline bool IsActiveIdUsingKey(ImGuiKey key) { ImGuiContext& g = *GImGui; IM_ASSERT(key < 64); return (g.ActiveIdUsingKeyInputMask & ((ImU64)1 << key)) != 0; }
|
||||
@ -2360,7 +2512,6 @@ namespace ImGui
|
||||
|
||||
// Tables: Candidates for public API
|
||||
IMGUI_API void TableOpenContextMenu(int column_n = -1);
|
||||
IMGUI_API void TableSetColumnEnabled(int column_n, bool enabled);
|
||||
IMGUI_API void TableSetColumnWidth(int column_n, float width);
|
||||
IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs);
|
||||
IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered.
|
||||
@ -2398,6 +2549,7 @@ namespace ImGui
|
||||
IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table);
|
||||
IMGUI_API void TableRemove(ImGuiTable* table);
|
||||
IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table);
|
||||
IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table);
|
||||
IMGUI_API void TableGcCompactSettings();
|
||||
|
||||
// Tables: Settings
|
||||
@ -2414,7 +2566,8 @@ namespace ImGui
|
||||
IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id);
|
||||
IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id);
|
||||
IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
|
||||
IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir);
|
||||
IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset);
|
||||
IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, ImVec2 mouse_pos);
|
||||
IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar);
|
||||
IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags);
|
||||
IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button);
|
||||
@ -2461,7 +2614,8 @@ namespace ImGui
|
||||
IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec2& padding, const ImVec4& bg_col, const ImVec4& tint_col);
|
||||
IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis);
|
||||
IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis);
|
||||
IMGUI_API ImGuiID GetWindowResizeID(ImGuiWindow* window, int n); // 0..3: corners, 4..7: borders
|
||||
IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners
|
||||
IMGUI_API ImGuiID GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir);
|
||||
IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags);
|
||||
IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value);
|
||||
IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value);
|
||||
@ -2519,12 +2673,14 @@ namespace ImGui
|
||||
|
||||
// Debug Tools
|
||||
IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL);
|
||||
inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(window->DC.LastItemRect.Min, window->DC.LastItemRect.Max, col); }
|
||||
inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, col); }
|
||||
inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; }
|
||||
|
||||
IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas);
|
||||
IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns);
|
||||
IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label);
|
||||
IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb);
|
||||
IMGUI_API void DebugNodeFont(ImFont* font);
|
||||
IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label);
|
||||
IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label);
|
||||
IMGUI_API void DebugNodeTable(ImGuiTable* table);
|
||||
@ -2572,14 +2728,10 @@ extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt,
|
||||
#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) // Register item bounding box
|
||||
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional)
|
||||
#define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log
|
||||
#define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA));
|
||||
#define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA), (const void*)(_DATA2));
|
||||
#define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) if (g.TestEngineHookIdInfo == _ID) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA));
|
||||
#define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) if (g.TestEngineHookIdInfo == _ID) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA), (const void*)(_DATA2));
|
||||
#else
|
||||
#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) do { } while (0)
|
||||
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) do { } while (0)
|
||||
#define IMGUI_TEST_ENGINE_LOG(_FMT,...) do { } while (0)
|
||||
#define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) do { } while (0)
|
||||
#define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) do { } while (0)
|
||||
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)0)
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.82
|
||||
// dear imgui, v1.84
|
||||
// (tables and columns code)
|
||||
|
||||
/*
|
||||
@ -8,6 +8,7 @@ Index of this file:
|
||||
// [SECTION] Commentary
|
||||
// [SECTION] Header mess
|
||||
// [SECTION] Tables: Main code
|
||||
// [SECTION] Tables: Simple accessors
|
||||
// [SECTION] Tables: Row changes
|
||||
// [SECTION] Tables: Columns changes
|
||||
// [SECTION] Tables: Columns width management
|
||||
@ -73,7 +74,7 @@ Index of this file:
|
||||
// (Read carefully because this is subtle but it does make sense!)
|
||||
//-----------------------------------------------------------------------------
|
||||
// About 'outer_size':
|
||||
// Its meaning needs to differ slightly depending of if we are using ScrollX/ScrollY flags.
|
||||
// Its meaning needs to differ slightly depending on if we are using ScrollX/ScrollY flags.
|
||||
// Default value is ImVec2(0.0f, 0.0f).
|
||||
// X
|
||||
// - outer_size.x <= 0.0f -> Right-align from window/work-rect right-most edge. With -FLT_MIN or 0.0f will align exactly on right-most edge.
|
||||
@ -90,7 +91,7 @@ Index of this file:
|
||||
// Outer size is also affected by the NoHostExtendX/NoHostExtendY flags.
|
||||
// Important to that note how the two flags have slightly different behaviors!
|
||||
// - ImGuiTableFlags_NoHostExtendX -> Make outer width auto-fit to columns (overriding outer_size.x value). Only available when ScrollX/ScrollY are disabled and Stretch columns are not used.
|
||||
// - ImGuiTableFlags_NoHostExtendY -> Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.
|
||||
// - ImGuiTableFlags_NoHostExtendY -> Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY is disabled. Data below the limit will be clipped and not visible.
|
||||
// In theory ImGuiTableFlags_NoHostExtendY could be the default and any non-scrolling tables with outer_size.y != 0.0f would use exact height.
|
||||
// This would be consistent but perhaps less useful and more confusing (as vertically clipped items are not easily noticeable)
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -132,7 +133,7 @@ Index of this file:
|
||||
// - the typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns.
|
||||
// - using mixed policies with ScrollX does not make much sense, as using Stretch columns with ScrollX does not make much sense in the first place!
|
||||
// that is, unless 'inner_width' is passed to BeginTable() to explicitly provide a total width to layout columns in.
|
||||
// - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the maximum contents width.
|
||||
// - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the width of the maximum contents.
|
||||
// - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weight/widths.
|
||||
//-----------------------------------------------------------------------------
|
||||
// About using column width:
|
||||
@ -140,9 +141,9 @@ Index of this file:
|
||||
// - you may use GetContentRegionAvail().x to query the width available in a given column.
|
||||
// - right-side alignment features such as SetNextItemWidth(-x) or PushItemWidth(-x) will rely on this width.
|
||||
// If the column is not resizable and has no width specified with TableSetupColumn():
|
||||
// - its width will be automatic and be the set to the max of items submitted.
|
||||
// - its width will be automatic and be set to the max of items submitted.
|
||||
// - therefore you generally cannot have ALL items of the columns use e.g. SetNextItemWidth(-FLT_MIN).
|
||||
// - but if the column has one or more item of known/fixed size, this will become the reference width used by SetNextItemWidth(-FLT_MIN).
|
||||
// - but if the column has one or more items of known/fixed size, this will become the reference width used by SetNextItemWidth(-FLT_MIN).
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
@ -161,7 +162,7 @@ Index of this file:
|
||||
// - Both TableSetColumnIndex() and TableNextColumn() return true when the column is visible or performing
|
||||
// width measurements. Otherwise, you may skip submitting the contents of a cell/column, BUT ONLY if you know
|
||||
// it is not going to contribute to row height.
|
||||
// In many situations, you may skip submitting contents for every columns but one (e.g. the first one).
|
||||
// In many situations, you may skip submitting contents for every column but one (e.g. the first one).
|
||||
// - Case A: column is not hidden by user, and at least partially in sight (most common case).
|
||||
// - Case B: column is clipped / out of sight (because of scrolling or parent ClipRect): TableNextColumn() return false as a hint but we still allow layout output.
|
||||
// - Case C: column is hidden explicitly by the user (e.g. via the context menu, or _DefaultHide column flag, etc.).
|
||||
@ -172,7 +173,7 @@ Index of this file:
|
||||
// ClipRect: normal zero-width zero-width -> [internal] when ClipRect is zero, ItemAdd() will return false and most widgets will early out mid-way.
|
||||
// ImDrawList output: normal dummy dummy -> [internal] when using the dummy channel, ImDrawList submissions (if any) will be wasted (because cliprect is zero-width anyway).
|
||||
//
|
||||
// - We need distinguish those cases because non-hidden columns that are clipped outside of scrolling bounds should still contribute their height to the row.
|
||||
// - We need to distinguish those cases because non-hidden columns that are clipped outside of scrolling bounds should still contribute their height to the row.
|
||||
// However, in the majority of cases, the contribution to row height is the same for all columns, or the tallest cells are known by the programmer.
|
||||
//-----------------------------------------------------------------------------
|
||||
// About clipping/culling of whole Tables:
|
||||
@ -209,6 +210,8 @@ Index of this file:
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later
|
||||
#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types
|
||||
#endif
|
||||
#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
|
||||
#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
|
||||
#endif
|
||||
|
||||
// Clang/GCC warnings with -Weverything
|
||||
@ -235,6 +238,19 @@ Index of this file:
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Tables: Main code
|
||||
//-----------------------------------------------------------------------------
|
||||
// - TableFixFlags() [Internal]
|
||||
// - TableFindByID() [Internal]
|
||||
// - BeginTable()
|
||||
// - BeginTableEx() [Internal]
|
||||
// - TableBeginInitMemory() [Internal]
|
||||
// - TableBeginApplyRequests() [Internal]
|
||||
// - TableSetupColumnFlags() [Internal]
|
||||
// - TableUpdateLayout() [Internal]
|
||||
// - TableUpdateBorders() [Internal]
|
||||
// - EndTable()
|
||||
// - TableSetupColumn()
|
||||
// - TableSetupScrollFreeze()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Configuration
|
||||
static const int TABLE_DRAW_CHANNEL_BG0 = 0;
|
||||
@ -272,12 +288,7 @@ inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_w
|
||||
flags |= ImGuiTableFlags_NoSavedSettings;
|
||||
|
||||
// Inherit _NoSavedSettings from top-level window (child windows always have _NoSavedSettings set)
|
||||
#ifdef IMGUI_HAS_DOCK
|
||||
ImGuiWindow* window_for_settings = outer_window->RootWindowDockStop;
|
||||
#else
|
||||
ImGuiWindow* window_for_settings = outer_window->RootWindow;
|
||||
#endif
|
||||
if (window_for_settings->Flags & ImGuiWindowFlags_NoSavedSettings)
|
||||
if (outer_window->RootWindow->Flags & ImGuiWindowFlags_NoSavedSettings)
|
||||
flags |= ImGuiTableFlags_NoSavedSettings;
|
||||
|
||||
return flags;
|
||||
@ -327,6 +338,16 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
if (instance_no > 0)
|
||||
IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID");
|
||||
|
||||
// Acquire temporary buffers
|
||||
const int table_idx = g.Tables.GetIndex(table);
|
||||
g.CurrentTableStackIdx++;
|
||||
if (g.CurrentTableStackIdx + 1 > g.TablesTempDataStack.Size)
|
||||
g.TablesTempDataStack.resize(g.CurrentTableStackIdx + 1, ImGuiTableTempData());
|
||||
ImGuiTableTempData* temp_data = table->TempData = &g.TablesTempDataStack[g.CurrentTableStackIdx];
|
||||
temp_data->TableIndex = table_idx;
|
||||
table->DrawSplitter = &table->TempData->DrawSplitter;
|
||||
table->DrawSplitter->Clear();
|
||||
|
||||
// Fix flags
|
||||
table->IsDefaultSizingPolicy = (flags & ImGuiTableFlags_SizingMask_) == 0;
|
||||
flags = TableFixFlags(flags, outer_window);
|
||||
@ -340,7 +361,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
table->ColumnsCount = columns_count;
|
||||
table->IsLayoutLocked = false;
|
||||
table->InnerWidth = inner_width;
|
||||
table->UserOuterSize = outer_size;
|
||||
temp_data->UserOuterSize = outer_size;
|
||||
|
||||
// When not using a child window, WorkRect.Max will grow as we append contents.
|
||||
if (use_child_window)
|
||||
@ -389,14 +410,14 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
table->HostIndentX = inner_window->DC.Indent.x;
|
||||
table->HostClipRect = inner_window->ClipRect;
|
||||
table->HostSkipItems = inner_window->SkipItems;
|
||||
table->HostBackupWorkRect = inner_window->WorkRect;
|
||||
table->HostBackupParentWorkRect = inner_window->ParentWorkRect;
|
||||
table->HostBackupColumnsOffset = outer_window->DC.ColumnsOffset;
|
||||
table->HostBackupPrevLineSize = inner_window->DC.PrevLineSize;
|
||||
table->HostBackupCurrLineSize = inner_window->DC.CurrLineSize;
|
||||
table->HostBackupCursorMaxPos = inner_window->DC.CursorMaxPos;
|
||||
table->HostBackupItemWidth = outer_window->DC.ItemWidth;
|
||||
table->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size;
|
||||
temp_data->HostBackupWorkRect = inner_window->WorkRect;
|
||||
temp_data->HostBackupParentWorkRect = inner_window->ParentWorkRect;
|
||||
temp_data->HostBackupColumnsOffset = outer_window->DC.ColumnsOffset;
|
||||
temp_data->HostBackupPrevLineSize = inner_window->DC.PrevLineSize;
|
||||
temp_data->HostBackupCurrLineSize = inner_window->DC.CurrLineSize;
|
||||
temp_data->HostBackupCursorMaxPos = inner_window->DC.CursorMaxPos;
|
||||
temp_data->HostBackupItemWidth = outer_window->DC.ItemWidth;
|
||||
temp_data->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size;
|
||||
inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
|
||||
|
||||
// Padding and Spacing
|
||||
@ -439,8 +460,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
table->BorderColorLight = GetColorU32(ImGuiCol_TableBorderLight);
|
||||
|
||||
// Make table current
|
||||
const int table_idx = g.Tables.GetIndex(table);
|
||||
g.CurrentTableStack.push_back(ImGuiPtrOrIndex(table_idx));
|
||||
g.CurrentTable = table;
|
||||
outer_window->DC.CurrentTableIdx = table_idx;
|
||||
if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly.
|
||||
@ -453,13 +472,18 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
if (table_idx >= g.TablesLastTimeActive.Size)
|
||||
g.TablesLastTimeActive.resize(table_idx + 1, -1.0f);
|
||||
g.TablesLastTimeActive[table_idx] = (float)g.Time;
|
||||
temp_data->LastTimeActive = (float)g.Time;
|
||||
table->MemoryCompacted = false;
|
||||
|
||||
// Setup memory buffer (clear data if columns count changed)
|
||||
const int stored_size = table->Columns.size();
|
||||
if (stored_size != 0 && stored_size != columns_count)
|
||||
ImGuiTableColumn* old_columns_to_preserve = NULL;
|
||||
void* old_columns_raw_data = NULL;
|
||||
const int old_columns_count = table->Columns.size();
|
||||
if (old_columns_count != 0 && old_columns_count != columns_count)
|
||||
{
|
||||
IM_FREE(table->RawData);
|
||||
// Attempt to preserve width on column count change (#4046)
|
||||
old_columns_to_preserve = table->Columns.Data;
|
||||
old_columns_raw_data = table->RawData;
|
||||
table->RawData = NULL;
|
||||
}
|
||||
if (table->RawData == NULL)
|
||||
@ -482,14 +506,24 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||
for (int n = 0; n < columns_count; n++)
|
||||
{
|
||||
ImGuiTableColumn* column = &table->Columns[n];
|
||||
float width_auto = column->WidthAuto;
|
||||
*column = ImGuiTableColumn();
|
||||
column->WidthAuto = width_auto;
|
||||
column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker
|
||||
if (old_columns_to_preserve && n < old_columns_count)
|
||||
{
|
||||
// FIXME: We don't attempt to preserve column order in this path.
|
||||
*column = old_columns_to_preserve[n];
|
||||
}
|
||||
else
|
||||
{
|
||||
float width_auto = column->WidthAuto;
|
||||
*column = ImGuiTableColumn();
|
||||
column->WidthAuto = width_auto;
|
||||
column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker
|
||||
column->IsEnabled = column->IsUserEnabled = column->IsUserEnabledNextFrame = true;
|
||||
}
|
||||
column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n;
|
||||
column->IsEnabled = column->IsEnabledNextFrame = true;
|
||||
}
|
||||
}
|
||||
if (old_columns_raw_data)
|
||||
IM_FREE(old_columns_raw_data);
|
||||
|
||||
// Load settings
|
||||
if (table->IsSettingsRequestLoad)
|
||||
@ -717,16 +751,18 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
column->InitStretchWeightOrWidth = -1.0f;
|
||||
}
|
||||
|
||||
// Update Enabled state, mark settings/sortspecs dirty
|
||||
// Update Enabled state, mark settings and sort specs dirty
|
||||
if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide))
|
||||
column->IsEnabledNextFrame = true;
|
||||
if (column->IsEnabled != column->IsEnabledNextFrame)
|
||||
column->IsUserEnabledNextFrame = true;
|
||||
if (column->IsUserEnabled != column->IsUserEnabledNextFrame)
|
||||
{
|
||||
column->IsEnabled = column->IsEnabledNextFrame;
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame;
|
||||
table->IsSettingsDirty = true;
|
||||
if (!column->IsEnabled && column->SortOrder != -1)
|
||||
table->IsSortSpecsDirty = true;
|
||||
}
|
||||
column->IsEnabled = column->IsUserEnabled && (column->Flags & ImGuiTableColumnFlags_Disabled) == 0;
|
||||
|
||||
if (column->SortOrder != -1 && !column->IsEnabled)
|
||||
table->IsSortSpecsDirty = true;
|
||||
if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti))
|
||||
table->IsSortSpecsDirty = true;
|
||||
|
||||
@ -1087,7 +1123,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||
// Initial state
|
||||
ImGuiWindow* inner_window = table->InnerWindow;
|
||||
if (table->Flags & ImGuiTableFlags_NoClip)
|
||||
table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);
|
||||
table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);
|
||||
else
|
||||
inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false);
|
||||
}
|
||||
@ -1125,9 +1161,8 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
|
||||
if ((table->Flags & ImGuiTableFlags_NoBordersInBody) && table->IsUsingHeaders == false)
|
||||
continue;
|
||||
|
||||
if (table->FreezeColumnsCount > 0)
|
||||
if (column->MaxX < table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsCount - 1]].MaxX)
|
||||
continue;
|
||||
if (!column->IsVisibleX && table->LastResizedColumn != column_n)
|
||||
continue;
|
||||
|
||||
ImGuiID column_id = TableGetColumnResizeID(table, column_n, table->InstanceCurrent);
|
||||
ImRect hit_rect(column->MaxX - hit_half_width, hit_y1, column->MaxX + hit_half_width, border_y2_hit);
|
||||
@ -1175,6 +1210,7 @@ void ImGui::EndTable()
|
||||
const ImGuiTableFlags flags = table->Flags;
|
||||
ImGuiWindow* inner_window = table->InnerWindow;
|
||||
ImGuiWindow* outer_window = table->OuterWindow;
|
||||
ImGuiTableTempData* temp_data = table->TempData;
|
||||
IM_ASSERT(inner_window == g.CurrentWindow);
|
||||
IM_ASSERT(outer_window == inner_window || outer_window == inner_window->ParentWindow);
|
||||
|
||||
@ -1187,9 +1223,9 @@ void ImGui::EndTable()
|
||||
TableOpenContextMenu((int)table->HoveredColumnBody);
|
||||
|
||||
// Finalize table height
|
||||
inner_window->DC.PrevLineSize = table->HostBackupPrevLineSize;
|
||||
inner_window->DC.CurrLineSize = table->HostBackupCurrLineSize;
|
||||
inner_window->DC.CursorMaxPos = table->HostBackupCursorMaxPos;
|
||||
inner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize;
|
||||
inner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize;
|
||||
inner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos;
|
||||
const float inner_content_max_y = table->RowPosY2;
|
||||
IM_ASSERT(table->RowPosY2 == inner_window->DC.CursorPos.y);
|
||||
if (inner_window != outer_window)
|
||||
@ -1236,10 +1272,11 @@ void ImGui::EndTable()
|
||||
#endif
|
||||
|
||||
// Flatten channels and merge draw calls
|
||||
table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, 0);
|
||||
ImDrawListSplitter* splitter = table->DrawSplitter;
|
||||
splitter->SetCurrentChannel(inner_window->DrawList, 0);
|
||||
if ((table->Flags & ImGuiTableFlags_NoClip) == 0)
|
||||
TableMergeDrawChannels(table);
|
||||
table->DrawSplitter.Merge(inner_window->DrawList);
|
||||
splitter->Merge(inner_window->DrawList);
|
||||
|
||||
// Update ColumnsAutoFitWidth to get us ahead for host using our size to auto-resize without waiting for next BeginTable()
|
||||
const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);
|
||||
@ -1281,18 +1318,18 @@ void ImGui::EndTable()
|
||||
|
||||
// Pop from id stack
|
||||
IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table->ID + table->InstanceCurrent, "Mismatching PushID/PopID!");
|
||||
IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= table->HostBackupItemWidthStackSize, "Too many PopItemWidth!");
|
||||
IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, "Too many PopItemWidth!");
|
||||
PopID();
|
||||
|
||||
// Restore window data that we modified
|
||||
const ImVec2 backup_outer_max_pos = outer_window->DC.CursorMaxPos;
|
||||
inner_window->WorkRect = table->HostBackupWorkRect;
|
||||
inner_window->ParentWorkRect = table->HostBackupParentWorkRect;
|
||||
inner_window->WorkRect = temp_data->HostBackupWorkRect;
|
||||
inner_window->ParentWorkRect = temp_data->HostBackupParentWorkRect;
|
||||
inner_window->SkipItems = table->HostSkipItems;
|
||||
outer_window->DC.CursorPos = table->OuterRect.Min;
|
||||
outer_window->DC.ItemWidth = table->HostBackupItemWidth;
|
||||
outer_window->DC.ItemWidthStack.Size = table->HostBackupItemWidthStackSize;
|
||||
outer_window->DC.ColumnsOffset = table->HostBackupColumnsOffset;
|
||||
outer_window->DC.ItemWidth = temp_data->HostBackupItemWidth;
|
||||
outer_window->DC.ItemWidthStack.Size = temp_data->HostBackupItemWidthStackSize;
|
||||
outer_window->DC.ColumnsOffset = temp_data->HostBackupColumnsOffset;
|
||||
|
||||
// Layout in outer window
|
||||
// (FIXME: To allow auto-fit and allow desirable effect of SameLine() we dissociate 'used' vs 'ideal' size by overriding
|
||||
@ -1315,20 +1352,20 @@ void ImGui::EndTable()
|
||||
IM_ASSERT((table->Flags & ImGuiTableFlags_ScrollX) == 0);
|
||||
outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth);
|
||||
}
|
||||
else if (table->UserOuterSize.x <= 0.0f)
|
||||
else if (temp_data->UserOuterSize.x <= 0.0f)
|
||||
{
|
||||
const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f;
|
||||
outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth + decoration_size - table->UserOuterSize.x);
|
||||
outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth + decoration_size - temp_data->UserOuterSize.x);
|
||||
outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth));
|
||||
}
|
||||
else
|
||||
{
|
||||
outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Max.x);
|
||||
}
|
||||
if (table->UserOuterSize.y <= 0.0f)
|
||||
if (temp_data->UserOuterSize.y <= 0.0f)
|
||||
{
|
||||
const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollY) ? inner_window->ScrollbarSizes.y : 0.0f;
|
||||
outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, inner_content_max_y + decoration_size - table->UserOuterSize.y);
|
||||
outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, inner_content_max_y + decoration_size - temp_data->UserOuterSize.y);
|
||||
outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, inner_content_max_y));
|
||||
}
|
||||
else
|
||||
@ -1344,8 +1381,15 @@ void ImGui::EndTable()
|
||||
|
||||
// Clear or restore current table, if any
|
||||
IM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table);
|
||||
g.CurrentTableStack.pop_back();
|
||||
g.CurrentTable = g.CurrentTableStack.Size ? g.Tables.GetByIndex(g.CurrentTableStack.back().Index) : NULL;
|
||||
IM_ASSERT(g.CurrentTableStackIdx >= 0);
|
||||
g.CurrentTableStackIdx--;
|
||||
temp_data = g.CurrentTableStackIdx >= 0 ? &g.TablesTempDataStack[g.CurrentTableStackIdx] : NULL;
|
||||
g.CurrentTable = temp_data ? g.Tables.GetByIndex(temp_data->TableIndex) : NULL;
|
||||
if (g.CurrentTable)
|
||||
{
|
||||
g.CurrentTable->TempData = temp_data;
|
||||
g.CurrentTable->DrawSplitter = &temp_data->DrawSplitter;
|
||||
}
|
||||
outer_window->DC.CurrentTableIdx = g.CurrentTable ? g.Tables.GetIndex(g.CurrentTable) : -1;
|
||||
}
|
||||
|
||||
@ -1401,7 +1445,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
|
||||
|
||||
// Init default visibility/sort state
|
||||
if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0)
|
||||
column->IsEnabled = column->IsEnabledNextFrame = false;
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = false;
|
||||
if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0)
|
||||
{
|
||||
column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
|
||||
@ -1428,13 +1472,38 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
|
||||
IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS);
|
||||
IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit
|
||||
|
||||
table->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)columns : 0;
|
||||
table->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)ImMin(columns, table->ColumnsCount) : 0;
|
||||
table->FreezeColumnsCount = (table->InnerWindow->Scroll.x != 0.0f) ? table->FreezeColumnsRequest : 0;
|
||||
table->FreezeRowsRequest = (table->Flags & ImGuiTableFlags_ScrollY) ? (ImGuiTableColumnIdx)rows : 0;
|
||||
table->FreezeRowsCount = (table->InnerWindow->Scroll.y != 0.0f) ? table->FreezeRowsRequest : 0;
|
||||
table->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b
|
||||
|
||||
// Ensure frozen columns are ordered in their section. We still allow multiple frozen columns to be reordered.
|
||||
for (int column_n = 0; column_n < table->FreezeColumnsRequest; column_n++)
|
||||
{
|
||||
int order_n = table->DisplayOrderToIndex[column_n];
|
||||
if (order_n != column_n && order_n >= table->FreezeColumnsRequest)
|
||||
{
|
||||
ImSwap(table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder, table->Columns[table->DisplayOrderToIndex[column_n]].DisplayOrder);
|
||||
ImSwap(table->DisplayOrderToIndex[order_n], table->DisplayOrderToIndex[column_n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Tables: Simple accessors
|
||||
//-----------------------------------------------------------------------------
|
||||
// - TableGetColumnCount()
|
||||
// - TableGetColumnName()
|
||||
// - TableGetColumnName() [Internal]
|
||||
// - TableSetColumnEnabled()
|
||||
// - TableGetColumnFlags()
|
||||
// - TableGetCellBgRect() [Internal]
|
||||
// - TableGetColumnResizeID() [Internal]
|
||||
// - TableGetHoveredColumn() [Internal]
|
||||
// - TableSetBgColor()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int ImGui::TableGetColumnCount()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -1463,7 +1532,12 @@ const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n)
|
||||
return &table->ColumnsNames.Buf[column->NameOffset];
|
||||
}
|
||||
|
||||
// For the getter you can use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsEnabled)
|
||||
// Change user accessible enabled/disabled state of a column (often perceived as "showing/hiding" from users point of view)
|
||||
// Note that end-user can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody)
|
||||
// - Require table to have the ImGuiTableFlags_Hideable flag because we are manipulating user accessible state.
|
||||
// - Request will be applied during next layout, which happens on the first call to TableNextRow() after BeginTable().
|
||||
// - For the getter you can test (TableGetColumnFlags() & ImGuiTableColumnFlags_IsEnabled) != 0.
|
||||
// - Alternative: the ImGuiTableColumnFlags_Disabled is an overriding/master disable flag which will also hide the column from context menu.
|
||||
void ImGui::TableSetColumnEnabled(int column_n, bool enabled)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -1471,11 +1545,12 @@ void ImGui::TableSetColumnEnabled(int column_n, bool enabled)
|
||||
IM_ASSERT(table != NULL);
|
||||
if (!table)
|
||||
return;
|
||||
IM_ASSERT(table->Flags & ImGuiTableFlags_Hideable); // See comments above
|
||||
if (column_n < 0)
|
||||
column_n = table->CurrentColumn;
|
||||
IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
column->IsEnabledNextFrame = enabled;
|
||||
column->IsUserEnabledNextFrame = enabled;
|
||||
}
|
||||
|
||||
// We allow querying for an extra column in order to poll the IsHovered state of the right-most section
|
||||
@ -1701,7 +1776,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
|
||||
// always followed by a change of clipping rectangle we perform the smallest overwrite possible here.
|
||||
if ((table->Flags & ImGuiTableFlags_NoClip) == 0)
|
||||
window->DrawList->_CmdHeader.ClipRect = table->Bg0ClipRectForDrawCmd.ToVec4();
|
||||
table->DrawSplitter.SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_BG0);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_BG0);
|
||||
}
|
||||
|
||||
// Draw row background
|
||||
@ -1773,7 +1848,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
|
||||
|
||||
// Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y
|
||||
SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect);
|
||||
table->DrawSplitter.SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent);
|
||||
}
|
||||
|
||||
if (!(table->RowFlags & ImGuiTableRowFlags_Headers))
|
||||
@ -1881,21 +1956,22 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
|
||||
window->SkipItems = column->IsSkipItems;
|
||||
if (column->IsSkipItems)
|
||||
{
|
||||
window->DC.LastItemId = 0;
|
||||
window->DC.LastItemStatusFlags = 0;
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.LastItemData.ID = 0;
|
||||
g.LastItemData.StatusFlags = 0;
|
||||
}
|
||||
|
||||
if (table->Flags & ImGuiTableFlags_NoClip)
|
||||
{
|
||||
// FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed.
|
||||
table->DrawSplitter.SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);
|
||||
//IM_ASSERT(table->DrawSplitter._Current == TABLE_DRAW_CHANNEL_NOCLIP);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME-TABLE: Could avoid this if draw channel is dummy channel?
|
||||
SetWindowClipRectBeforeSetChannel(window, column->ClipRect);
|
||||
table->DrawSplitter.SetCurrentChannel(window->DrawList, column->DrawChannelCurrent);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent);
|
||||
}
|
||||
|
||||
// Logging
|
||||
@ -1948,6 +2024,7 @@ float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n)
|
||||
if (table->Flags & ImGuiTableFlags_ScrollX)
|
||||
{
|
||||
// Frozen columns can't reach beyond visible width else scrolling will naturally break.
|
||||
// (we use DisplayOrder as within a set of multiple frozen column reordering is possible)
|
||||
if (column->DisplayOrder < table->FreezeColumnsRequest)
|
||||
{
|
||||
max_width = (table->InnerClipRect.Max.x - (table->FreezeColumnsRequest - column->DisplayOrder) * min_column_distance) - column->MinX;
|
||||
@ -2143,7 +2220,7 @@ void ImGui::TablePushBackgroundChannel()
|
||||
// Optimization: avoid SetCurrentChannel() + PushClipRect()
|
||||
table->HostBackupInnerClipRect = window->ClipRect;
|
||||
SetWindowClipRectBeforeSetChannel(window, table->Bg2ClipRectForDrawCmd);
|
||||
table->DrawSplitter.SetCurrentChannel(window->DrawList, table->Bg2DrawChannelCurrent);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Bg2DrawChannelCurrent);
|
||||
}
|
||||
|
||||
void ImGui::TablePopBackgroundChannel()
|
||||
@ -2155,7 +2232,7 @@ void ImGui::TablePopBackgroundChannel()
|
||||
|
||||
// Optimization: avoid PopClipRect() + SetCurrentChannel()
|
||||
SetWindowClipRectBeforeSetChannel(window, table->HostBackupInnerClipRect);
|
||||
table->DrawSplitter.SetCurrentChannel(window->DrawList, column->DrawChannelCurrent);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent);
|
||||
}
|
||||
|
||||
// Allocate draw channels. Called by TableUpdateLayout()
|
||||
@ -2181,7 +2258,7 @@ void ImGui::TableSetupDrawChannels(ImGuiTable* table)
|
||||
const int channels_for_bg = 1 + 1 * freeze_row_multiplier;
|
||||
const int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || table->VisibleMaskByIndex != table->EnabledMaskByIndex) ? +1 : 0;
|
||||
const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy;
|
||||
table->DrawSplitter.Split(table->InnerWindow->DrawList, channels_total);
|
||||
table->DrawSplitter->Split(table->InnerWindow->DrawList, channels_total);
|
||||
table->DummyDrawChannel = (ImGuiTableDrawChannelIdx)((channels_for_dummy > 0) ? channels_total - 1 : -1);
|
||||
table->Bg2DrawChannelCurrent = TABLE_DRAW_CHANNEL_BG2_FROZEN;
|
||||
table->Bg2DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)((table->FreezeRowsCount > 0) ? 2 + channels_for_row : TABLE_DRAW_CHANNEL_BG2_FROZEN);
|
||||
@ -2245,7 +2322,7 @@ void ImGui::TableSetupDrawChannels(ImGuiTable* table)
|
||||
void ImGui::TableMergeDrawChannels(ImGuiTable* table)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImDrawListSplitter* splitter = &table->DrawSplitter;
|
||||
ImDrawListSplitter* splitter = table->DrawSplitter;
|
||||
const bool has_freeze_v = (table->FreezeRowsCount > 0);
|
||||
const bool has_freeze_h = (table->FreezeColumnsCount > 0);
|
||||
IM_ASSERT(splitter->_Current == 0);
|
||||
@ -2256,10 +2333,11 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
|
||||
ImRect ClipRect;
|
||||
int ChannelsCount;
|
||||
ImBitArray<IMGUI_TABLE_MAX_DRAW_CHANNELS> ChannelsMask;
|
||||
|
||||
MergeGroup() { ChannelsCount = 0; }
|
||||
};
|
||||
int merge_group_mask = 0x00;
|
||||
MergeGroup merge_groups[4];
|
||||
memset(merge_groups, 0, sizeof(merge_groups));
|
||||
|
||||
// 1. Scan channels and take note of those which can be merged
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
@ -2337,7 +2415,6 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
|
||||
g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized
|
||||
ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data;
|
||||
ImBitArray<IMGUI_TABLE_MAX_DRAW_CHANNELS> remaining_mask; // We need 132-bit of storage
|
||||
remaining_mask.ClearAllBits();
|
||||
remaining_mask.SetBitRange(LEADING_DRAW_CHANNELS, splitter->_Count);
|
||||
remaining_mask.ClearBit(table->Bg2DrawChannelUnfrozen);
|
||||
IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN);
|
||||
@ -2416,7 +2493,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
|
||||
return;
|
||||
|
||||
ImDrawList* inner_drawlist = inner_window->DrawList;
|
||||
table->DrawSplitter.SetCurrentChannel(inner_drawlist, TABLE_DRAW_CHANNEL_BG0);
|
||||
table->DrawSplitter->SetCurrentChannel(inner_drawlist, TABLE_DRAW_CHANNEL_BG0);
|
||||
inner_drawlist->PushClipRect(table->Bg0ClipRectForDrawCmd.Min, table->Bg0ClipRectForDrawCmd.Max, false);
|
||||
|
||||
// Draw inner border and resizing feedback
|
||||
@ -2436,7 +2513,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
|
||||
const bool is_hovered = (table->HoveredColumnBorder == column_n);
|
||||
const bool is_resized = (table->ResizedColumn == column_n) && (table->InstanceInteracted == table->InstanceCurrent);
|
||||
const bool is_resizable = (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) == 0;
|
||||
const bool is_frozen_separator = (table->FreezeColumnsCount != -1 && table->FreezeColumnsCount == order_n + 1);
|
||||
const bool is_frozen_separator = (table->FreezeColumnsCount == order_n + 1);
|
||||
if (column->MaxX > table->InnerClipRect.Max.x && !is_resized)
|
||||
continue;
|
||||
|
||||
@ -2532,8 +2609,7 @@ ImGuiTableSortSpecs* ImGui::TableGetSortSpecs()
|
||||
if (!table->IsLayoutLocked)
|
||||
TableUpdateLayout(table);
|
||||
|
||||
if (table->IsSortSpecsDirty)
|
||||
TableSortSpecsBuild(table);
|
||||
TableSortSpecsBuild(table);
|
||||
|
||||
return &table->SortSpecs;
|
||||
}
|
||||
@ -2672,28 +2748,33 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table)
|
||||
|
||||
void ImGui::TableSortSpecsBuild(ImGuiTable* table)
|
||||
{
|
||||
IM_ASSERT(table->IsSortSpecsDirty);
|
||||
TableSortSpecsSanitize(table);
|
||||
bool dirty = table->IsSortSpecsDirty;
|
||||
if (dirty)
|
||||
{
|
||||
TableSortSpecsSanitize(table);
|
||||
table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount);
|
||||
table->SortSpecs.SpecsDirty = true; // Mark as dirty for user
|
||||
table->IsSortSpecsDirty = false; // Mark as not dirty for us
|
||||
}
|
||||
|
||||
// Write output
|
||||
table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount);
|
||||
ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data;
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
{
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
if (column->SortOrder == -1)
|
||||
continue;
|
||||
IM_ASSERT(column->SortOrder < table->SortSpecsCount);
|
||||
ImGuiTableColumnSortSpecs* sort_spec = &sort_specs[column->SortOrder];
|
||||
sort_spec->ColumnUserID = column->UserID;
|
||||
sort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n;
|
||||
sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder;
|
||||
sort_spec->SortDirection = column->SortDirection;
|
||||
}
|
||||
if (dirty && sort_specs != NULL)
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
{
|
||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
if (column->SortOrder == -1)
|
||||
continue;
|
||||
IM_ASSERT(column->SortOrder < table->SortSpecsCount);
|
||||
ImGuiTableColumnSortSpecs* sort_spec = &sort_specs[column->SortOrder];
|
||||
sort_spec->ColumnUserID = column->UserID;
|
||||
sort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n;
|
||||
sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder;
|
||||
sort_spec->SortDirection = column->SortDirection;
|
||||
}
|
||||
|
||||
table->SortSpecs.Specs = sort_specs;
|
||||
table->SortSpecs.SpecsCount = table->SortSpecsCount;
|
||||
table->SortSpecs.SpecsDirty = true; // Mark as dirty for user
|
||||
table->IsSortSpecsDirty = false; // Mark as not dirty for us
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -2713,8 +2794,11 @@ float ImGui::TableGetHeaderRowHeight()
|
||||
float row_height = GetTextLineHeight();
|
||||
int columns_count = TableGetColumnCount();
|
||||
for (int column_n = 0; column_n < columns_count; column_n++)
|
||||
if (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_IsEnabled)
|
||||
{
|
||||
ImGuiTableColumnFlags flags = TableGetColumnFlags(column_n);
|
||||
if ((flags & ImGuiTableColumnFlags_IsEnabled) && !(flags & ImGuiTableColumnFlags_NoHeaderLabel))
|
||||
row_height = ImMax(row_height, CalcTextSize(TableGetColumnName(column_n)).y);
|
||||
}
|
||||
row_height += GetStyle().CellPadding.y * 2.0f;
|
||||
return row_height;
|
||||
}
|
||||
@ -2751,7 +2835,7 @@ void ImGui::TableHeadersRow()
|
||||
// Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them)
|
||||
// - in your own code you may omit the PushID/PopID all-together, provided you know they won't collide
|
||||
// - table->InstanceCurrent is only >0 when we use multiple BeginTable/EndTable calls with same identifier.
|
||||
const char* name = TableGetColumnName(column_n);
|
||||
const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n);
|
||||
PushID(table->InstanceCurrent * table->ColumnsCount + column_n);
|
||||
TableHeader(name);
|
||||
PopID();
|
||||
@ -2833,7 +2917,6 @@ void ImGui::TableHeader(const char* label)
|
||||
const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
|
||||
//RenderFrame(bb.Min, bb.Max, col, false, 0.0f);
|
||||
TableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn);
|
||||
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2841,6 +2924,7 @@ void ImGui::TableHeader(const char* label)
|
||||
if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0)
|
||||
TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn);
|
||||
}
|
||||
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding);
|
||||
if (held)
|
||||
table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n;
|
||||
window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;
|
||||
@ -3006,16 +3090,19 @@ void ImGui::TableDrawContextMenu(ImGuiTable* table)
|
||||
for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)
|
||||
{
|
||||
ImGuiTableColumn* other_column = &table->Columns[other_column_n];
|
||||
if (other_column->Flags & ImGuiTableColumnFlags_Disabled)
|
||||
continue;
|
||||
|
||||
const char* name = TableGetColumnName(table, other_column_n);
|
||||
if (name == NULL || name[0] == 0)
|
||||
name = "<Unknown>";
|
||||
|
||||
// Make sure we can't hide the last active column
|
||||
bool menu_item_active = (other_column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true;
|
||||
if (other_column->IsEnabled && table->ColumnsEnabledCount <= 1)
|
||||
if (other_column->IsUserEnabled && table->ColumnsEnabledCount <= 1)
|
||||
menu_item_active = false;
|
||||
if (MenuItem(name, NULL, other_column->IsEnabled, menu_item_active))
|
||||
other_column->IsEnabledNextFrame = !other_column->IsEnabled;
|
||||
if (MenuItem(name, NULL, other_column->IsUserEnabled, menu_item_active))
|
||||
other_column->IsUserEnabledNextFrame = !other_column->IsUserEnabled;
|
||||
}
|
||||
PopItemFlag();
|
||||
}
|
||||
@ -3140,7 +3227,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table)
|
||||
column_settings->DisplayOrder = column->DisplayOrder;
|
||||
column_settings->SortOrder = column->SortOrder;
|
||||
column_settings->SortDirection = column->SortDirection;
|
||||
column_settings->IsEnabled = column->IsEnabled;
|
||||
column_settings->IsEnabled = column->IsUserEnabled;
|
||||
column_settings->IsStretch = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? 1 : 0;
|
||||
if ((column->Flags & ImGuiTableColumnFlags_WidthStretch) == 0)
|
||||
save_ref_scale = true;
|
||||
@ -3154,7 +3241,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table)
|
||||
settings->SaveFlags |= ImGuiTableFlags_Reorderable;
|
||||
if (column->SortOrder != -1)
|
||||
settings->SaveFlags |= ImGuiTableFlags_Sortable;
|
||||
if (column->IsEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0))
|
||||
if (column->IsUserEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0))
|
||||
settings->SaveFlags |= ImGuiTableFlags_Hideable;
|
||||
}
|
||||
settings->SaveFlags &= table->Flags;
|
||||
@ -3212,7 +3299,7 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
|
||||
else
|
||||
column->DisplayOrder = (ImGuiTableColumnIdx)column_n;
|
||||
display_order_mask |= (ImU64)1 << column->DisplayOrder;
|
||||
column->IsEnabled = column->IsEnabledNextFrame = column_settings->IsEnabled;
|
||||
column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled;
|
||||
column->SortOrder = column_settings->SortOrder;
|
||||
column->SortDirection = column_settings->SortDirection;
|
||||
}
|
||||
@ -3231,8 +3318,9 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
|
||||
static void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
|
||||
{
|
||||
ImGuiContext& g = *ctx;
|
||||
for (int i = 0; i != g.Tables.GetSize(); i++)
|
||||
g.Tables.GetByIndex(i)->SettingsOffset = -1;
|
||||
for (int i = 0; i != g.Tables.GetMapSize(); i++)
|
||||
if (ImGuiTable* table = g.Tables.TryGetMapData(i))
|
||||
table->SettingsOffset = -1;
|
||||
g.SettingsTables.clear();
|
||||
}
|
||||
|
||||
@ -3240,12 +3328,12 @@ static void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandle
|
||||
static void TableSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
|
||||
{
|
||||
ImGuiContext& g = *ctx;
|
||||
for (int i = 0; i != g.Tables.GetSize(); i++)
|
||||
{
|
||||
ImGuiTable* table = g.Tables.GetByIndex(i);
|
||||
table->IsSettingsRequestLoad = true;
|
||||
table->SettingsOffset = -1;
|
||||
}
|
||||
for (int i = 0; i != g.Tables.GetMapSize(); i++)
|
||||
if (ImGuiTable* table = g.Tables.TryGetMapData(i))
|
||||
{
|
||||
table->IsSettingsRequestLoad = true;
|
||||
table->SettingsOffset = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void* TableSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
|
||||
@ -3318,6 +3406,9 @@ static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandle
|
||||
for (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++)
|
||||
{
|
||||
// "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v"
|
||||
bool save_column = column->UserID != 0 || save_size || save_visible || save_order || (save_sort && column->SortOrder != -1);
|
||||
if (!save_column)
|
||||
continue;
|
||||
buf->appendf("Column %-2d", column_n);
|
||||
if (column->UserID != 0) buf->appendf(" UserID=%08X", column->UserID);
|
||||
if (save_size && column->IsStretch) buf->appendf(" Weight=%.4f", column->WidthOrWeight);
|
||||
@ -3371,10 +3462,9 @@ void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table)
|
||||
//IMGUI_DEBUG_LOG("TableGcCompactTransientBuffers() id=0x%08X\n", table->ID);
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(table->MemoryCompacted == false);
|
||||
table->DrawSplitter.ClearFreeMemory();
|
||||
table->SortSpecsMulti.clear();
|
||||
table->SortSpecs.Specs = NULL;
|
||||
table->IsSortSpecsDirty = true;
|
||||
table->SortSpecsMulti.clear();
|
||||
table->IsSortSpecsDirty = true; // FIXME: shouldn't have to leak into user performing a sort
|
||||
table->ColumnsNames.clear();
|
||||
table->MemoryCompacted = true;
|
||||
for (int n = 0; n < table->ColumnsCount; n++)
|
||||
@ -3382,6 +3472,12 @@ void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table)
|
||||
g.TablesLastTimeActive[g.Tables.GetIndex(table)] = -1.0f;
|
||||
}
|
||||
|
||||
void ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data)
|
||||
{
|
||||
temp_data->DrawSplitter.ClearFreeMemory();
|
||||
temp_data->LastTimeActive = -1.0f;
|
||||
}
|
||||
|
||||
// Compact and remove unused settings data (currently only used by TestEngine)
|
||||
void ImGui::TableGcCompactSettings()
|
||||
{
|
||||
|
@ -34,7 +34,7 @@
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
// Fabian Giesen
|
||||
@ -441,7 +441,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
@ -602,38 +602,38 @@ This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
// [DEAR IMGUI]
|
||||
// This is a slightly modified version of stb_textedit.h 1.13.
|
||||
// This is a slightly modified version of stb_textedit.h 1.13.
|
||||
// Those changes would need to be pushed into nothings/stb:
|
||||
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
@ -19,7 +19,7 @@
|
||||
// texts, as its performance does not scale and it has limited undo).
|
||||
//
|
||||
// Non-trivial behaviors are modelled after Windows text controls.
|
||||
//
|
||||
//
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
@ -217,20 +217,20 @@
|
||||
// call this with the mouse x,y on a mouse down; it will update the cursor
|
||||
// and reset the selection start/end to the cursor point. the x,y must
|
||||
// be relative to the text widget, with (0,0) being the top left.
|
||||
//
|
||||
//
|
||||
// drag:
|
||||
// call this with the mouse x,y on a mouse drag/up; it will update the
|
||||
// cursor and the selection end point
|
||||
//
|
||||
//
|
||||
// cut:
|
||||
// call this to delete the current selection; returns true if there was
|
||||
// one. you should FIRST copy the current selection to the system paste buffer.
|
||||
// (To copy, just copy the current selection out of the string yourself.)
|
||||
//
|
||||
//
|
||||
// paste:
|
||||
// call this to paste text at the current cursor point or over the current
|
||||
// selection if there is one.
|
||||
//
|
||||
//
|
||||
// key:
|
||||
// call this for keyboard inputs sent to the textfield. you can use it
|
||||
// for "key down" events or for "translated" key events. if you need to
|
||||
@ -241,7 +241,7 @@
|
||||
// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to
|
||||
// anything other type you wante before including.
|
||||
//
|
||||
//
|
||||
//
|
||||
// When rendering, you can read the cursor position and selection state from
|
||||
// the STB_TexteditState.
|
||||
//
|
||||
@ -716,9 +716,11 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta
|
||||
state->has_preferred_x = 0;
|
||||
return 1;
|
||||
}
|
||||
// remove the undo since we didn't actually insert the characters
|
||||
if (state->undostate.undo_point)
|
||||
--state->undostate.undo_point;
|
||||
// [DEAR IMGUI]
|
||||
//// remove the undo since we didn't actually insert the characters
|
||||
//if (state->undostate.undo_point)
|
||||
// --state->undostate.undo_point;
|
||||
// note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -764,7 +766,7 @@ retry:
|
||||
state->insert_mode = !state->insert_mode;
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
case STB_TEXTEDIT_K_UNDO:
|
||||
stb_text_undo(str, state);
|
||||
state->has_preferred_x = 0;
|
||||
@ -779,7 +781,7 @@ retry:
|
||||
// if currently there's a selection, move cursor to start of selection
|
||||
if (STB_TEXT_HAS_SELECTION(state))
|
||||
stb_textedit_move_to_first(state);
|
||||
else
|
||||
else
|
||||
if (state->cursor > 0)
|
||||
--state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
@ -828,7 +830,7 @@ retry:
|
||||
|
||||
#ifdef STB_TEXTEDIT_MOVEWORDRIGHT
|
||||
case STB_TEXTEDIT_K_WORDRIGHT:
|
||||
if (STB_TEXT_HAS_SELECTION(state))
|
||||
if (STB_TEXT_HAS_SELECTION(state))
|
||||
stb_textedit_move_to_last(str, state);
|
||||
else {
|
||||
state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
|
||||
@ -922,7 +924,7 @@ retry:
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case STB_TEXTEDIT_K_UP:
|
||||
case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT:
|
||||
case STB_TEXTEDIT_K_PGUP:
|
||||
@ -1014,7 +1016,7 @@ retry:
|
||||
}
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
|
||||
|
||||
#ifdef STB_TEXTEDIT_K_TEXTSTART2
|
||||
case STB_TEXTEDIT_K_TEXTSTART2:
|
||||
#endif
|
||||
@ -1031,7 +1033,7 @@ retry:
|
||||
state->select_start = state->select_end = 0;
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
|
||||
|
||||
#ifdef STB_TEXTEDIT_K_TEXTSTART2
|
||||
case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:
|
||||
#endif
|
||||
@ -1410,38 +1412,38 @@ This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1,7 +1,7 @@
|
||||
// dear imgui: FreeType font builder (used as a replacement for the stb_truetype builder)
|
||||
// (code)
|
||||
|
||||
// Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
|
||||
// Get the latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
|
||||
// Original code by @vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained since 2019 by @ocornut.
|
||||
|
||||
// CHANGELOG
|
||||
@ -41,7 +41,8 @@
|
||||
#include FT_SYNTHESIS_H // <freetype/ftsynth.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
||||
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
||||
#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
@ -600,13 +601,15 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
|
||||
if (src_load_color)
|
||||
{
|
||||
atlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight * 4);
|
||||
memset(atlas->TexPixelsRGBA32, 0, atlas->TexWidth * atlas->TexHeight * 4);
|
||||
size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 4;
|
||||
atlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(tex_size);
|
||||
memset(atlas->TexPixelsRGBA32, 0, tex_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight);
|
||||
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
|
||||
size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 1;
|
||||
atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(tex_size);
|
||||
memset(atlas->TexPixelsAlpha8, 0, tex_size);
|
||||
}
|
||||
|
||||
// 8. Copy rasterized font characters back into the main texture
|
||||
@ -645,6 +648,22 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
const int tx = pack_rect.x + padding;
|
||||
const int ty = pack_rect.y + padding;
|
||||
|
||||
// Register glyph
|
||||
float x0 = info.OffsetX + font_off_x;
|
||||
float y0 = info.OffsetY + font_off_y;
|
||||
float x1 = x0 + info.Width;
|
||||
float y1 = y0 + info.Height;
|
||||
float u0 = (tx) / (float)atlas->TexWidth;
|
||||
float v0 = (ty) / (float)atlas->TexHeight;
|
||||
float u1 = (tx + info.Width) / (float)atlas->TexWidth;
|
||||
float v1 = (ty + info.Height) / (float)atlas->TexHeight;
|
||||
dst_font->AddGlyph(&cfg, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX);
|
||||
|
||||
ImFontGlyph* dst_glyph = &dst_font->Glyphs.back();
|
||||
IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint);
|
||||
if (src_glyph.Info.IsColored)
|
||||
dst_glyph->Colored = tex_use_colors = true;
|
||||
|
||||
// Blit from temporary buffer to final texture
|
||||
size_t blit_src_stride = (size_t)src_glyph.Info.Width;
|
||||
size_t blit_dst_stride = (size_t)atlas->TexWidth;
|
||||
@ -663,22 +682,6 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
for (int x = 0; x < info.Width; x++)
|
||||
blit_dst[x] = blit_src[x];
|
||||
}
|
||||
|
||||
// Register glyph
|
||||
float x0 = info.OffsetX + font_off_x;
|
||||
float y0 = info.OffsetY + font_off_y;
|
||||
float x1 = x0 + info.Width;
|
||||
float y1 = y0 + info.Height;
|
||||
float u0 = (tx) / (float)atlas->TexWidth;
|
||||
float v0 = (ty) / (float)atlas->TexHeight;
|
||||
float u1 = (tx + info.Width) / (float)atlas->TexWidth;
|
||||
float v1 = (ty + info.Height) / (float)atlas->TexHeight;
|
||||
dst_font->AddGlyph(&cfg, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX);
|
||||
|
||||
ImFontGlyph* dst_glyph = &dst_font->Glyphs.back();
|
||||
IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint);
|
||||
if (src_glyph.Info.IsColored)
|
||||
dst_glyph->Colored = tex_use_colors = true;
|
||||
}
|
||||
|
||||
src_tmp.Rects = NULL;
|
||||
@ -688,8 +691,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
|
||||
// Cleanup
|
||||
for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++)
|
||||
IM_FREE(buf_bitmap_buffers[buf_i]);
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
src_tmp_array[src_i].~ImFontBuildSrcDataFT();
|
||||
src_tmp_array.clear_destruct();
|
||||
|
||||
ImFontAtlasBuildFinish(atlas);
|
||||
|
||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
BIN
romfs/audio.png
Before Width: | Height: | Size: 4.9 KiB |
@ -15,7 +15,7 @@ namespace Config {
|
||||
static int config_version_holder = 0;
|
||||
static const int buf_size = 128 + FS_MAX_PATH;
|
||||
|
||||
int Save(config_t config) {
|
||||
int Save(config_t &config) {
|
||||
Result ret = 0;
|
||||
char *buf = new char[buf_size];
|
||||
u64 len = std::snprintf(buf, buf_size, config_file, CONFIG_VERSION, config.sort, config.lang, config.dev_options, config.image_filename, config.cwd);
|
||||
@ -43,12 +43,12 @@ namespace Config {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SetDefault(config_t *config) {
|
||||
config->sort = 0;
|
||||
config->lang = 1;
|
||||
config->dev_options = false;
|
||||
config->image_filename = false;
|
||||
std::strcpy(config->cwd, "/");
|
||||
static void SetDefault(config_t &config) {
|
||||
config.sort = 0;
|
||||
config.lang = 1;
|
||||
config.dev_options = false;
|
||||
config.image_filename = false;
|
||||
std::strncpy(config.cwd, "/", 2);
|
||||
}
|
||||
|
||||
int Load(void) {
|
||||
@ -60,7 +60,7 @@ namespace Config {
|
||||
fsFsCreateDirectory(fs, "/switch/NX-Shell");
|
||||
|
||||
if (!FS::FileExists("/switch/NX-Shell/config.json")) {
|
||||
Config::SetDefault(&cfg);
|
||||
Config::SetDefault(cfg);
|
||||
return Config::Save(cfg);
|
||||
}
|
||||
|
||||
@ -117,7 +117,7 @@ namespace Config {
|
||||
// Delete config file if config file is updated. This will rarely happen.
|
||||
if (config_version_holder < CONFIG_VERSION) {
|
||||
fsFsDeleteFile(fs, "/switch/NX-Shell/config.json");
|
||||
Config::SetDefault(&cfg);
|
||||
Config::SetDefault(cfg);
|
||||
return Config::Save(cfg);
|
||||
}
|
||||
|
||||
|
352
source/fs.cpp
@ -5,26 +5,14 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "language.h"
|
||||
#include "log.h"
|
||||
#include "popups.h"
|
||||
|
||||
// Global vars
|
||||
FsFileSystem *fs;
|
||||
FsFileSystem devices[4];
|
||||
|
||||
namespace FS {
|
||||
static int PREVIOUS_BROWSE_STATE = 0;
|
||||
|
||||
typedef struct {
|
||||
char copy_path[FS_MAX_PATH];
|
||||
char copy_filename[FS_MAX_PATH];
|
||||
bool is_dir = false;
|
||||
} FS_Copy_Struct;
|
||||
|
||||
FS_Copy_Struct fs_copy_struct;
|
||||
|
||||
bool FileExists(const char path[FS_MAX_PATH]) {
|
||||
bool FileExists(const char path[FS_MAX_PATH]) {
|
||||
FsFile file;
|
||||
if (R_SUCCEEDED(fsFsOpenFile(fs, path, FsOpenMode_Read, &file))) {
|
||||
fsFileClose(&file);
|
||||
@ -44,7 +32,7 @@ namespace FS {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string GetFileExt(const std::string &filename) {
|
||||
std::string GetFileExt(const std::string &filename) {
|
||||
std::string ext = std::filesystem::path(filename).extension();
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), ::toupper);
|
||||
return ext;
|
||||
@ -55,9 +43,6 @@ namespace FS {
|
||||
|
||||
if ((!ext.compare(".ZIP")) || (!ext.compare(".RAR")) || (!ext.compare(".7Z")))
|
||||
return FileTypeArchive;
|
||||
else if ((!ext.compare(".FLAC")) || (!ext.compare(".IT")) || (!ext.compare(".MOD")) || (!ext.compare(".MP3")) || (!ext.compare(".OGG"))
|
||||
|| (!ext.compare(".OPUS")) || (!ext.compare(".S3M")) || (!ext.compare(".WAV")) || (!ext.compare(".XM")))
|
||||
return FileTypeAudio;
|
||||
else if ((!ext.compare(".BMP")) || (!ext.compare(".GIF")) || (!ext.compare(".JPG")) || (!ext.compare(".JPEG")) || (!ext.compare(".PGM"))
|
||||
|| (!ext.compare(".PPM")) || (!ext.compare(".PNG")) || (!ext.compare(".PSD")) || (!ext.compare(".TGA")) || (!ext.compare(".WEBP")))
|
||||
return FileTypeImage;
|
||||
@ -66,8 +51,8 @@ namespace FS {
|
||||
|
||||
return FileTypeNone;
|
||||
}
|
||||
|
||||
static bool Sort(const FsDirectoryEntry &entryA, const FsDirectoryEntry &entryB) {
|
||||
|
||||
static bool Sort(const FsDirectoryEntry &entryA, const FsDirectoryEntry &entryB) {
|
||||
if ((entryA.type == FsDirEntryType_Dir) && !(entryB.type == FsDirEntryType_Dir))
|
||||
return true;
|
||||
else if (!(entryA.type == FsDirEntryType_Dir) && (entryB.type == FsDirEntryType_Dir))
|
||||
@ -103,33 +88,45 @@ namespace FS {
|
||||
return false;
|
||||
}
|
||||
|
||||
Result GetDirList(char path[FS_MAX_PATH], std::vector<FsDirectoryEntry> &entries) {
|
||||
Result GetDirList(const char path[FS_MAX_PATH], std::vector<FsDirectoryEntry> &entries) {
|
||||
FsDir dir;
|
||||
Result ret = 0;
|
||||
s64 read_entries = 0;
|
||||
const std::string cwd = path;
|
||||
|
||||
if (strncmp(path, "/", std::strlen(path))) {
|
||||
FsDirectoryEntry entry;
|
||||
std::strncpy(entry.name, "..", 3);
|
||||
entry.type = FsDirEntryType_Dir;
|
||||
entry.file_size = 0;
|
||||
entries.push_back(entry);
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = fsFsOpenDirectory(fs, path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles, &dir))) {
|
||||
Log::Error("fsFsOpenDirectory(%s) failed: 0x%x\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s64 entry_count = 0;
|
||||
if (R_FAILED(ret = fsDirGetEntryCount(&dir, &entry_count))) {
|
||||
Log::Error("fsDirGetEntryCount(%s) failed: 0x%x\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
FsDirectoryEntry entry;
|
||||
if (R_FAILED(ret = fsDirRead(&dir, &read_entries, 1, &entry))) {
|
||||
fsDirClose(&dir);
|
||||
Log::Error("fsDirRead(%s) failed: 0x%x\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (read_entries != 1)
|
||||
break;
|
||||
|
||||
entries.resize(entry_count);
|
||||
if (R_FAILED(ret = fsDirRead(&dir, nullptr, static_cast<size_t>(entry_count), entries.data()))) {
|
||||
Log::Error("fsDirRead(%s) failed: 0x%x\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
entries.push_back(entry);
|
||||
}
|
||||
|
||||
std::sort(entries.begin(), entries.end(), FS::Sort);
|
||||
fsDirClose(&dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Result ChangeDir(char path[FS_MAX_PATH], std::vector<FsDirectoryEntry> &entries) {
|
||||
static Result ChangeDir(const char path[FS_MAX_PATH], std::vector<FsDirectoryEntry> &entries) {
|
||||
Result ret = 0;
|
||||
std::vector<FsDirectoryEntry> new_entries;
|
||||
|
||||
@ -185,286 +182,11 @@ namespace FS {
|
||||
|
||||
return FS::ChangeDir(new_cwd, entries);
|
||||
}
|
||||
|
||||
int ConstructPath(FsDirectoryEntry *entry, char path[FS_MAX_PATH + 1], const char filename[FS_MAX_PATH]) {
|
||||
if (entry) {
|
||||
if ((std::snprintf(path, FS_MAX_PATH, "%s%s%s", cfg.cwd, !std::strncmp(cfg.cwd, "/", 2) ? "" : "/", entry? entry->name : "")) > 0)
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
if ((std::snprintf(path, FS_MAX_PATH, "%s%s%s", cfg.cwd, !std::strncmp(cfg.cwd, "/", 2) ? "" : "/", filename[0] != '\0'? filename : "")) > 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
Result GetTimeStamp(FsDirectoryEntry *entry, FsTimeStampRaw *timestamp) {
|
||||
Result GetFreeStorageSpace(s64 &size) {
|
||||
Result ret = 0;
|
||||
|
||||
char path[FS_MAX_PATH];
|
||||
if (FS::ConstructPath(entry, path, "") < 0)
|
||||
return -1;
|
||||
|
||||
if (R_FAILED(ret = fsFsGetFileTimeStampRaw(fs, path, timestamp))) {
|
||||
Log::Error("fsFsGetFileTimeStampRaw(%s) failed: 0x%x\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result Rename(FsDirectoryEntry *entry, const char filename[FS_MAX_PATH]) {
|
||||
Result ret = 0;
|
||||
|
||||
char path[FS_MAX_PATH];
|
||||
if (FS::ConstructPath(entry, path, "") < 0)
|
||||
return -1;
|
||||
|
||||
char new_path[FS_MAX_PATH];
|
||||
if (FS::ConstructPath(nullptr, new_path, filename) < 0)
|
||||
return -1;
|
||||
|
||||
if (entry->type == FsDirEntryType_Dir) {
|
||||
if (R_FAILED(ret = fsFsRenameDirectory(fs, path, new_path))) {
|
||||
Log::Error("fsFsRenameDirectory(%s, %s) failed: 0x%x\n", path, new_path, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (R_FAILED(ret = fsFsRenameFile(fs, path, new_path))) {
|
||||
Log::Error("fsFsRenameFile(%s, %s) failed: 0x%x\n", path, new_path, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result Delete(FsDirectoryEntry *entry) {
|
||||
Result ret = 0;
|
||||
|
||||
char path[FS_MAX_PATH];
|
||||
if (FS::ConstructPath(entry, path, "") < 0)
|
||||
return -1;
|
||||
|
||||
if (entry->type == FsDirEntryType_Dir) {
|
||||
if (R_FAILED(ret = fsFsDeleteDirectoryRecursively(fs, path))) {
|
||||
Log::Error("fsFsDeleteDirectoryRecursively(%s) failed: 0x%x\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (R_FAILED(ret = fsFsDeleteFile(fs, path))) {
|
||||
Log::Error("fsFsDeleteFile(%s) failed: 0x%x\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result SetArchiveBit(FsDirectoryEntry *entry) {
|
||||
Result ret = 0;
|
||||
|
||||
char path[FS_MAX_PATH];
|
||||
if (FS::ConstructPath(entry, path, "") < 0)
|
||||
return -1;
|
||||
|
||||
if (R_FAILED(ret = fsFsSetConcatenationFileAttribute(fs, path))) {
|
||||
Log::Error("fsFsSetConcatenationFileAttribute(%s) failed: 0x%x\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Result CopyFile(const char src_path[FS_MAX_PATH], const char dest_path[FS_MAX_PATH]) {
|
||||
Result ret = 0;
|
||||
FsFile src_handle, dest_handle;
|
||||
|
||||
if (R_FAILED(ret = fsFsOpenFile(&devices[PREVIOUS_BROWSE_STATE], src_path, FsOpenMode_Read, &src_handle))) {
|
||||
Log::Error("fsFsOpenFile(%s) failed: 0x%x\n", src_path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s64 size = 0;
|
||||
if (R_FAILED(ret = fsFileGetSize(&src_handle, &size))) {
|
||||
Log::Error("fsFileGetSize(%s) failed: 0x%x\n", src_path, ret);
|
||||
fsFileClose(&src_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This may fail or not, but we don't care -> create the file if it doesn't exist, otherwise continue.
|
||||
fsFsCreateFile(fs, dest_path, size, 0);
|
||||
|
||||
if (R_FAILED(ret = fsFsOpenFile(fs, dest_path, FsOpenMode_Write, &dest_handle))) {
|
||||
Log::Error("fsFsOpenFile(%s) failed: 0x%x\n", dest_path, ret);
|
||||
fsFileClose(&src_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
u64 bytes_read = 0;
|
||||
const u64 buf_size = 0x10000;
|
||||
s64 offset = 0;
|
||||
unsigned char *buf = new unsigned char[buf_size];
|
||||
std::string filename = std::filesystem::path(src_path).filename();
|
||||
|
||||
do {
|
||||
std::memset(buf, 0, buf_size);
|
||||
|
||||
if (R_FAILED(ret = fsFileRead(&src_handle, offset, buf, buf_size, FsReadOption_None, &bytes_read))) {
|
||||
Log::Error("fsFileRead(%s) failed: 0x%x\n", src_path, ret);
|
||||
delete[] buf;
|
||||
fsFileClose(&src_handle);
|
||||
fsFileClose(&dest_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = fsFileWrite(&dest_handle, offset, buf, bytes_read, FsWriteOption_Flush))) {
|
||||
Log::Error("fsFileWrite(%s) failed: 0x%x\n", dest_path, ret);
|
||||
delete[] buf;
|
||||
fsFileClose(&src_handle);
|
||||
fsFileClose(&dest_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
offset += bytes_read;
|
||||
Popups::ProgressPopup(static_cast<float>(offset), static_cast<float>(size), strings[cfg.lang][Lang::OptionsCopying], filename.c_str());
|
||||
} while(offset < size);
|
||||
|
||||
delete[] buf;
|
||||
fsFileClose(&src_handle);
|
||||
fsFileClose(&dest_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Result CopyDir(const char src_path[FS_MAX_PATH], const char dest_path[FS_MAX_PATH]) {
|
||||
Result ret = 0;
|
||||
FsDir dir;
|
||||
|
||||
if (R_FAILED(ret = fsFsOpenDirectory(&devices[PREVIOUS_BROWSE_STATE], src_path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles, &dir))) {
|
||||
Log::Error("fsFsOpenDirectory(%s) failed: 0x%x\n", src_path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This may fail or not, but we don't care -> make the dir if it doesn't exist, otherwise continue.
|
||||
fsFsCreateDirectory(fs, dest_path);
|
||||
|
||||
s64 entry_count = 0;
|
||||
if (R_FAILED(ret = fsDirGetEntryCount(&dir, &entry_count))) {
|
||||
Log::Error("fsDirGetEntryCount(%s) failed: 0x%x\n", src_path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
FsDirectoryEntry *entries = new FsDirectoryEntry[entry_count * sizeof(*entries)];
|
||||
if (R_FAILED(ret = fsDirRead(&dir, nullptr, static_cast<size_t>(entry_count), entries))) {
|
||||
Log::Error("fsDirRead(%s) failed: 0x%x\n", src_path, ret);
|
||||
delete[] entries;
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (s64 i = 0; i < entry_count; i++) {
|
||||
std::string filename = entries[i].name;
|
||||
if (!filename.empty()) {
|
||||
if ((!filename.compare(".")) || (!filename.compare("..")))
|
||||
continue;
|
||||
|
||||
std::string src = src_path;
|
||||
src.append("/");
|
||||
src.append(filename);
|
||||
|
||||
std::string dest = dest_path;
|
||||
dest.append("/");
|
||||
dest.append(filename);
|
||||
|
||||
if (entries[i].type == FsDirEntryType_Dir)
|
||||
FS::CopyDir(src.c_str(), dest.c_str()); // Copy Folder (via recursion)
|
||||
else
|
||||
FS::CopyFile(src.c_str(), dest.c_str()); // Copy File
|
||||
}
|
||||
}
|
||||
|
||||
delete[] entries;
|
||||
fsDirClose(&dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Copy(FsDirectoryEntry *entry, const std::string &path) {
|
||||
std::string full_path = path;
|
||||
full_path.append("/");
|
||||
full_path.append(entry->name);
|
||||
std::strcpy(fs_copy_struct.copy_path, full_path.c_str());
|
||||
std::strcpy(fs_copy_struct.copy_filename, entry->name);
|
||||
if (entry->type == FsDirEntryType_Dir)
|
||||
fs_copy_struct.is_dir = true;
|
||||
}
|
||||
|
||||
Result Paste(void) {
|
||||
Result ret = 0;
|
||||
|
||||
char path[FS_MAX_PATH];
|
||||
FS::ConstructPath(nullptr, path, fs_copy_struct.copy_filename);
|
||||
|
||||
if (fs_copy_struct.is_dir) // Copy folder recursively
|
||||
ret = FS::CopyDir(fs_copy_struct.copy_path, path);
|
||||
else // Copy file
|
||||
ret = FS::CopyFile(fs_copy_struct.copy_path, path);
|
||||
|
||||
std::memset(fs_copy_struct.copy_path, 0, FS_MAX_PATH);
|
||||
std::memset(fs_copy_struct.copy_filename, 0, FS_MAX_PATH);
|
||||
fs_copy_struct.is_dir = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result Move(void) {
|
||||
Result ret = 0;
|
||||
|
||||
char path[FS_MAX_PATH];
|
||||
FS::ConstructPath(nullptr, path, fs_copy_struct.copy_filename);
|
||||
|
||||
if (fs_copy_struct.is_dir) {
|
||||
if (R_FAILED(ret = fsFsRenameDirectory(fs, fs_copy_struct.copy_path, path))) {
|
||||
Log::Error("fsFsRenameDirectory(%s, %s) failed: 0x%x\n", path, fs_copy_struct.copy_filename, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (R_FAILED(ret = fsFsRenameFile(fs, fs_copy_struct.copy_path, path))) {
|
||||
Log::Error("fsFsRenameFile(%s, %s) failed: 0x%x\n", path, fs_copy_struct.copy_filename, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
std::memset(fs_copy_struct.copy_path, 0, FS_MAX_PATH);
|
||||
std::memset(fs_copy_struct.copy_filename, 0, FS_MAX_PATH);
|
||||
fs_copy_struct.is_dir = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result GetFileSize(const char path[FS_MAX_PATH], s64 *size) {
|
||||
Result ret = 0;
|
||||
|
||||
FsFile file;
|
||||
if (R_FAILED(ret = fsFsOpenFile(fs, path, FsOpenMode_Read, &file))) {
|
||||
Log::Error("fsFsOpenFile(%s) failed: 0x%x\n", path, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = fsFileGetSize(&file, size))) {
|
||||
Log::Error("fsFileGetSize(%s) failed: 0x%x\n", path, ret);
|
||||
fsFileClose(&file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
fsFileClose(&file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result GetFreeStorageSpace(s64 *size) {
|
||||
Result ret = 0;
|
||||
|
||||
if (R_FAILED(ret = fsFsGetFreeSpace(fs, "/", size))) {
|
||||
if (R_FAILED(ret = fsFsGetFreeSpace(fs, "/", &size))) {
|
||||
Log::Error("fsFsGetFreeSpace() failed: 0x%x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
@ -472,10 +194,10 @@ namespace FS {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result GetTotalStorageSpace(s64 *size) {
|
||||
Result GetTotalStorageSpace(s64 &size) {
|
||||
Result ret = 0;
|
||||
|
||||
if (R_FAILED(ret = fsFsGetTotalSpace(fs, "/", size))) {
|
||||
if (R_FAILED(ret = fsFsGetTotalSpace(fs, "/", &size))) {
|
||||
Log::Error("fsFsGetTotalSpace() failed: 0x%x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
@ -483,17 +205,17 @@ namespace FS {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result GetUsedStorageSpace(s64 *size) {
|
||||
Result GetUsedStorageSpace(s64 &size) {
|
||||
Result ret = 0;
|
||||
s64 free_size = 0, total_size = 0;
|
||||
|
||||
if (R_FAILED(ret = FS::GetFreeStorageSpace(&free_size)))
|
||||
if (R_FAILED(ret = FS::GetFreeStorageSpace(free_size)))
|
||||
return ret;
|
||||
|
||||
if (R_FAILED(ret = FS::GetTotalStorageSpace(&total_size)))
|
||||
if (R_FAILED(ret = FS::GetTotalStorageSpace(total_size)))
|
||||
return ret;
|
||||
|
||||
*size = (total_size - free_size);
|
||||
size = (total_size - free_size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
418
source/gui.cpp
@ -1,221 +1,209 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <imgui.h>
|
||||
#include <switch.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include "popups.h"
|
||||
#include "windows.h"
|
||||
#include "imgui_deko3d.h"
|
||||
#include "imgui_nx.h"
|
||||
|
||||
// Global var used across windows/popups
|
||||
MenuItem item;
|
||||
constexpr auto MAX_SAMPLERS = 2;
|
||||
constexpr auto MAX_IMAGES = 8;
|
||||
constexpr auto FB_NUM = 2u;
|
||||
constexpr auto CMDBUF_SIZE = 1024 * 1024;
|
||||
unsigned s_width = 1920;
|
||||
unsigned s_height = 1080;
|
||||
dk::UniqueDevice s_device;
|
||||
dk::UniqueMemBlock s_depthMemBlock;
|
||||
dk::Image s_depthBuffer;
|
||||
dk::UniqueMemBlock s_fbMemBlock;
|
||||
dk::Image s_frameBuffers[FB_NUM];
|
||||
dk::UniqueMemBlock s_cmdMemBlock[FB_NUM];
|
||||
dk::UniqueCmdBuf s_cmdBuf[FB_NUM];
|
||||
dk::UniqueMemBlock s_imageMemBlock;
|
||||
dk::UniqueMemBlock s_descriptorMemBlock;
|
||||
dk::SamplerDescriptor *s_samplerDescriptors = nullptr;
|
||||
dk::ImageDescriptor *s_imageDescriptors = nullptr;
|
||||
|
||||
dk::UniqueQueue s_queue;
|
||||
dk::UniqueSwapchain s_swapchain;
|
||||
|
||||
namespace Deko3D {
|
||||
void RebuildSwapchain(unsigned const width_, unsigned const height_) {
|
||||
// destroy old swapchain
|
||||
s_swapchain = nullptr;
|
||||
|
||||
// create new depth buffer image layout
|
||||
dk::ImageLayout depthLayout;
|
||||
dk::ImageLayoutMaker{s_device}
|
||||
.setFlags(DkImageFlags_UsageRender | DkImageFlags_HwCompression)
|
||||
.setFormat(DkImageFormat_Z24S8)
|
||||
.setDimensions(width_, height_)
|
||||
.initialize(depthLayout);
|
||||
|
||||
auto const depthAlign = depthLayout.getAlignment();
|
||||
auto const depthSize = depthLayout.getSize();
|
||||
|
||||
// create depth buffer memblock
|
||||
if (!s_depthMemBlock) {
|
||||
s_depthMemBlock = dk::MemBlockMaker{s_device,
|
||||
imgui::deko3d::align(depthSize, std::max<unsigned> (depthAlign, DK_MEMBLOCK_ALIGNMENT))}
|
||||
.setFlags(DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image)
|
||||
.create();
|
||||
}
|
||||
|
||||
s_depthBuffer.initialize(depthLayout, s_depthMemBlock, 0);
|
||||
|
||||
// create framebuffer image layout
|
||||
dk::ImageLayout fbLayout;
|
||||
dk::ImageLayoutMaker{s_device}
|
||||
.setFlags(DkImageFlags_UsageRender | DkImageFlags_UsagePresent | DkImageFlags_HwCompression)
|
||||
.setFormat(DkImageFormat_RGBA8_Unorm)
|
||||
.setDimensions(width_, height_)
|
||||
.initialize(fbLayout);
|
||||
|
||||
auto const fbAlign = fbLayout.getAlignment();
|
||||
auto const fbSize = fbLayout.getSize();
|
||||
|
||||
// create framebuffer memblock
|
||||
if (!s_fbMemBlock) {
|
||||
s_fbMemBlock = dk::MemBlockMaker{s_device, imgui::deko3d::align(FB_NUM * fbSize, std::max<unsigned> (fbAlign, DK_MEMBLOCK_ALIGNMENT))}
|
||||
.setFlags(DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image)
|
||||
.create();
|
||||
}
|
||||
|
||||
// initialize swapchain images
|
||||
std::array<DkImage const *, FB_NUM> swapchainImages;
|
||||
for (unsigned i = 0; i < FB_NUM; ++i) {
|
||||
swapchainImages[i] = &s_frameBuffers[i];
|
||||
s_frameBuffers[i].initialize(fbLayout, s_fbMemBlock, i * fbSize);
|
||||
}
|
||||
|
||||
// create swapchain
|
||||
s_swapchain = dk::SwapchainMaker{s_device, nwindowGetDefault(), swapchainImages}.create();
|
||||
}
|
||||
|
||||
void Init(void) {
|
||||
// create deko3d device
|
||||
s_device = dk::DeviceMaker{}.create();
|
||||
|
||||
// initialize swapchain with maximum resolution
|
||||
Deko3D::RebuildSwapchain(1920, 1080);
|
||||
|
||||
// create memblocks for each image slot
|
||||
for (std::size_t i = 0; i < FB_NUM; ++i) {
|
||||
// create command buffer memblock
|
||||
s_cmdMemBlock[i] = dk::MemBlockMaker{s_device, imgui::deko3d::align(CMDBUF_SIZE, DK_MEMBLOCK_ALIGNMENT)}
|
||||
.setFlags(DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||
.create();
|
||||
|
||||
// create command buffer
|
||||
s_cmdBuf[i] = dk::CmdBufMaker{s_device}.create();
|
||||
s_cmdBuf[i].addMemory(s_cmdMemBlock[i], 0, s_cmdMemBlock[i].getSize());
|
||||
}
|
||||
|
||||
// create image/sampler memblock
|
||||
static_assert(sizeof(dk::ImageDescriptor) == DK_IMAGE_DESCRIPTOR_ALIGNMENT);
|
||||
static_assert(sizeof(dk::SamplerDescriptor) == DK_SAMPLER_DESCRIPTOR_ALIGNMENT);
|
||||
static_assert(DK_IMAGE_DESCRIPTOR_ALIGNMENT == DK_SAMPLER_DESCRIPTOR_ALIGNMENT);
|
||||
s_descriptorMemBlock = dk::MemBlockMaker{s_device, imgui::deko3d::align((MAX_SAMPLERS + MAX_IMAGES) * sizeof(dk::ImageDescriptor), DK_MEMBLOCK_ALIGNMENT)}
|
||||
.setFlags(DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||
.create();
|
||||
|
||||
// get cpu address for descriptors
|
||||
s_samplerDescriptors = static_cast<dk::SamplerDescriptor *> (s_descriptorMemBlock.getCpuAddr());
|
||||
s_imageDescriptors = reinterpret_cast<dk::ImageDescriptor *> (&s_samplerDescriptors[MAX_SAMPLERS]);
|
||||
|
||||
// create queue
|
||||
s_queue = dk::QueueMaker{s_device}.setFlags(DkQueueFlags_Graphics).create();
|
||||
dk::UniqueCmdBuf &cmdBuf = s_cmdBuf[0];
|
||||
|
||||
// bind image/sampler descriptors
|
||||
cmdBuf.bindSamplerDescriptorSet(s_descriptorMemBlock.getGpuAddr(), MAX_SAMPLERS);
|
||||
cmdBuf.bindImageDescriptorSet(s_descriptorMemBlock.getGpuAddr() + MAX_SAMPLERS * sizeof(dk::SamplerDescriptor), MAX_IMAGES);
|
||||
s_queue.submitCommands(cmdBuf.finishList());
|
||||
s_queue.waitIdle();
|
||||
cmdBuf.clear();
|
||||
}
|
||||
|
||||
void Exit(void) {
|
||||
// clean up all of the deko3d objects
|
||||
s_imageMemBlock = nullptr;
|
||||
s_descriptorMemBlock = nullptr;
|
||||
|
||||
for (unsigned i = 0; i < FB_NUM; ++i) {
|
||||
s_cmdBuf[i] = nullptr;
|
||||
s_cmdMemBlock[i] = nullptr;
|
||||
}
|
||||
|
||||
s_queue = nullptr;
|
||||
s_swapchain = nullptr;
|
||||
s_fbMemBlock = nullptr;
|
||||
s_depthMemBlock = nullptr;
|
||||
s_device = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace GUI {
|
||||
enum SDL_KEYS {
|
||||
SDL_KEY_A, SDL_KEY_B, SDL_KEY_X, SDL_KEY_Y,
|
||||
SDL_KEY_LSTICK, SDL_KEY_RSTICK,
|
||||
SDL_KEY_L, SDL_KEY_R,
|
||||
SDL_KEY_ZL, SDL_KEY_ZR,
|
||||
SDL_KEY_PLUS, SDL_KEY_MINUS,
|
||||
SDL_KEY_DLEFT, SDL_KEY_DUP, SDL_KEY_DRIGHT, SDL_KEY_DDOWN,
|
||||
SDL_KEY_LSTICK_LEFT, SDL_KEY_LSTICK_UP, SDL_KEY_LSTICK_RIGHT, SDL_KEY_LSTICK_DOWN,
|
||||
SDL_KEY_RSTICK_LEFT, SDL_KEY_RSTICK_UP, SDL_KEY_RSTICK_RIGHT, SDL_KEY_RSTICK_DOWN,
|
||||
SDL_KEY_SL_LEFT, SDL_KEY_SR_LEFT, SDL_KEY_SL_RIGHT, SDL_KEY_SR_RIGHT
|
||||
};
|
||||
|
||||
int RenderLoop(void) {
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
item.selected = 0;
|
||||
|
||||
Result ret = 0;
|
||||
if (R_FAILED(ret = FS::GetDirList(cfg.cwd, item.entries)))
|
||||
return ret;
|
||||
|
||||
item.checked.resize(item.entries.size());
|
||||
FS::GetUsedStorageSpace(&item.used_storage);
|
||||
FS::GetTotalStorageSpace(&item.total_storage);
|
||||
|
||||
// Main loop
|
||||
bool done = false, focus = false, first_item = true, tex_properties = false;
|
||||
|
||||
while (!done) {
|
||||
// Start the Dear ImGui frame
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame(window);
|
||||
ImGui::NewFrame();
|
||||
|
||||
Windows::FileBrowserWindow(&focus, &first_item);
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||
if (event.type == SDL_JOYBUTTONDOWN) {
|
||||
Uint8 button = event.jbutton.button;
|
||||
|
||||
if (button == SDL_KEY_A) {
|
||||
if (item.state == MENU_STATE_FILEBROWSER) {
|
||||
if (item.entries[item.selected].type == FsDirEntryType_Dir) {
|
||||
if (item.entries.size() != 0) {
|
||||
if (R_SUCCEEDED(FS::ChangeDirNext(item.entries[item.selected].name, item.entries))) {
|
||||
// Make a copy before resizing our vector.
|
||||
if ((item.checked_count > 1) && (item.checked_copy.empty()))
|
||||
item.checked_copy = item.checked;
|
||||
|
||||
item.checked.resize(item.entries.size());
|
||||
GImGui->NavId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (button == SDL_KEY_B) {
|
||||
if (item.state == MENU_STATE_FILEBROWSER) {
|
||||
if (R_SUCCEEDED(FS::ChangeDirPrev(item.entries))) {
|
||||
// Make a copy before resizing our vector.
|
||||
if (item.checked_count > 1)
|
||||
item.checked_copy = item.checked;
|
||||
|
||||
item.checked.resize(item.entries.size());
|
||||
GImGui->NavId = 0;
|
||||
}
|
||||
}
|
||||
else if ((item.state == MENU_STATE_PROPERTIES) || (item.state == MENU_STATE_DELETE))
|
||||
item.state = MENU_STATE_OPTIONS;
|
||||
else if (item.state == MENU_STATE_IMAGEVIEWER) {
|
||||
if (tex_properties)
|
||||
tex_properties = false;
|
||||
else {
|
||||
for (long unsigned int i = 0; i < item.textures.size(); i++)
|
||||
Textures::Free(&item.textures[i]);
|
||||
|
||||
item.textures.clear();
|
||||
item.frame_count = 0;
|
||||
item.zoom_factor = 1.0f;
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
}
|
||||
}
|
||||
else if (item.state == MENU_STATE_TEXTREADER) {
|
||||
text_reader.buf_size = 0;
|
||||
delete[] text_reader.buf;
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
}
|
||||
else if (item.state == MENU_STATE_SETTINGS)
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
else
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
}
|
||||
else if (button == SDL_KEY_X) {
|
||||
if (item.state == MENU_STATE_FILEBROWSER)
|
||||
item.state = MENU_STATE_OPTIONS;
|
||||
else if (item.state == MENU_STATE_IMAGEVIEWER)
|
||||
tex_properties = true;
|
||||
}
|
||||
else if (button == SDL_KEY_Y) {
|
||||
if (item.state == MENU_STATE_FILEBROWSER) {
|
||||
if (item.selected < static_cast<int>(item.checked.size())) {
|
||||
if ((!item.checked_cwd.empty()) && (item.checked_cwd.compare(cfg.cwd) != 0))
|
||||
GUI::ResetCheckbox();
|
||||
|
||||
item.checked_cwd = cfg.cwd;
|
||||
item.checked.at(item.selected) = !item.checked.at(item.selected);
|
||||
item.checked_count = std::count(item.checked.begin(), item.checked.end(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (button == SDL_KEY_DLEFT) {
|
||||
if (item.state == MENU_STATE_FILEBROWSER) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
else if (button == SDL_KEY_DRIGHT) {
|
||||
if (item.state == MENU_STATE_FILEBROWSER) {
|
||||
ImGui::SetScrollHereY(1.0f);
|
||||
}
|
||||
}
|
||||
else if (button == SDL_KEY_MINUS)
|
||||
item.state = MENU_STATE_SETTINGS;
|
||||
else if (button == SDL_KEY_PLUS)
|
||||
done = true;
|
||||
// TODO fix this so that it's continous or just scrap SDL events
|
||||
else if (button == SDL_KEY_LSTICK_DOWN) {
|
||||
if (item.state == MENU_STATE_IMAGEVIEWER) {
|
||||
item.zoom_factor -= 0.5f * ImGui::GetIO().DeltaTime;
|
||||
|
||||
if (item.zoom_factor < 0.1f)
|
||||
item.zoom_factor = 0.1f;
|
||||
}
|
||||
}
|
||||
else if (button == SDL_KEY_LSTICK_UP) {
|
||||
if (item.state == MENU_STATE_IMAGEVIEWER) {
|
||||
item.zoom_factor += 0.5f * ImGui::GetIO().DeltaTime;
|
||||
|
||||
if (item.zoom_factor > 5.0f)
|
||||
item.zoom_factor = 5.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.type == SDL_QUIT)
|
||||
done = true;
|
||||
|
||||
if ((event.type == SDL_WINDOWEVENT) && (event.window.event == SDL_WINDOWEVENT_CLOSE) && (event.window.windowID == SDL_GetWindowID(window)))
|
||||
done = true;
|
||||
}
|
||||
|
||||
switch (item.state) {
|
||||
// Popups
|
||||
case MENU_STATE_ARCHIVEEXTRACT:
|
||||
Popups::ArchivePopup();
|
||||
break;
|
||||
|
||||
case MENU_STATE_DELETE:
|
||||
Popups::DeletePopup();
|
||||
break;
|
||||
|
||||
case MENU_STATE_OPTIONS:
|
||||
Popups::OptionsPopup();
|
||||
break;
|
||||
|
||||
case MENU_STATE_PROPERTIES:
|
||||
Popups::FilePropertiesPopup();
|
||||
break;
|
||||
|
||||
// Windows
|
||||
case MENU_STATE_IMAGEVIEWER:
|
||||
Windows::ImageWindow();
|
||||
if (tex_properties)
|
||||
Popups::ImageProperties(&tex_properties);
|
||||
|
||||
break;
|
||||
|
||||
case MENU_STATE_SETTINGS:
|
||||
Windows::SettingsWindow();
|
||||
break;
|
||||
|
||||
case MENU_STATE_TEXTREADER:
|
||||
Windows::TextReaderWindow();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Rendering
|
||||
ImGui::Render();
|
||||
glViewport(0, 0, static_cast<int>(io.DisplaySize.x), static_cast<int>(io.DisplaySize.y));
|
||||
glClearColor(0.00f, 0.00f, 0.00f, 1.00f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
SDL_GL_SwapWindow(window);
|
||||
}
|
||||
|
||||
item.entries.clear();
|
||||
return 0;
|
||||
}
|
||||
bool Init(void) {
|
||||
ImGui::CreateContext();
|
||||
if (!imgui::nx::init())
|
||||
return false;
|
||||
|
||||
Deko3D::Init();
|
||||
imgui::deko3d::init(s_device, s_queue, s_cmdBuf[0], s_samplerDescriptors[0], s_imageDescriptors[0], dkMakeTextureHandle(0, 0), FB_NUM);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Loop(void) {
|
||||
if (!appletMainLoop())
|
||||
return false;
|
||||
|
||||
u64 down = imgui::nx::newFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
return !(down & HidNpadButton_Plus);
|
||||
}
|
||||
|
||||
void Render(void) {
|
||||
ImGui::Render();
|
||||
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
if (s_width != io.DisplaySize.x || s_height != io.DisplaySize.y) {
|
||||
s_width = io.DisplaySize.x;
|
||||
s_height = io.DisplaySize.y;
|
||||
Deko3D::RebuildSwapchain(s_width, s_height);
|
||||
}
|
||||
|
||||
// get image from queue
|
||||
const int slot = s_queue.acquireImage(s_swapchain);
|
||||
dk::UniqueCmdBuf &cmdBuf = s_cmdBuf[slot];
|
||||
cmdBuf.clear();
|
||||
|
||||
// bind frame/depth buffers and clear them
|
||||
dk::ImageView colorTarget{s_frameBuffers[slot]};
|
||||
dk::ImageView depthTarget{s_depthBuffer};
|
||||
cmdBuf.bindRenderTargets(&colorTarget, &depthTarget);
|
||||
cmdBuf.setScissors(0, DkScissor{0, 0, s_width, s_height});
|
||||
cmdBuf.clearColor(0, DkColorMask_RGBA, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
cmdBuf.clearDepthStencil(true, 1.0f, 0xFF, 0);
|
||||
s_queue.submitCommands(cmdBuf.finishList());
|
||||
|
||||
imgui::deko3d::render(s_device, s_queue, cmdBuf, slot);
|
||||
|
||||
// wait for fragments to be completed before discarding depth/stencil buffer
|
||||
cmdBuf.barrier(DkBarrier_Fragments, 0);
|
||||
cmdBuf.discardDepthStencil();
|
||||
|
||||
// present image
|
||||
s_queue.presentImage(s_swapchain, slot);
|
||||
}
|
||||
|
||||
void Exit(void) {
|
||||
imgui::nx::exit();
|
||||
|
||||
// wait for queue to be idle
|
||||
s_queue.waitIdle();
|
||||
|
||||
imgui::deko3d::exit();
|
||||
Deko3D::Exit();
|
||||
}
|
||||
}
|
||||
|
538
source/imgui_nx/imgui_deko3d.cpp
Normal file
@ -0,0 +1,538 @@
|
||||
// ftpd is a server implementation based on the following:
|
||||
// - RFC 959 (https://tools.ietf.org/html/rfc959)
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (C) 2020 Michael Theall
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <imgui.h>
|
||||
#include <deko3d.hpp>
|
||||
|
||||
#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES
|
||||
#define GLM_FORCE_INTRINSICS
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/mat4x4.hpp>
|
||||
|
||||
#include "imgui_deko3d.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
/// \brief Vertex buffer size
|
||||
constexpr auto VTXBUF_SIZE = 1024u * 1024u;
|
||||
/// \brief Index buffer size
|
||||
constexpr auto IDXBUF_SIZE = 1024u * 1024u;
|
||||
|
||||
/// \brief Vertex shader UBO
|
||||
struct VertUBO
|
||||
{
|
||||
/// \brief Projection matrix
|
||||
glm::mat4 projMtx;
|
||||
};
|
||||
|
||||
/// \brief Fragment shader UBO
|
||||
struct FragUBO
|
||||
{
|
||||
/// \brief Whether drawing a font or not
|
||||
std::uint32_t font;
|
||||
};
|
||||
|
||||
/// \brief Vertex attribute state
|
||||
constexpr std::array VERTEX_ATTRIB_STATE = {
|
||||
// clang-format off
|
||||
DkVtxAttribState{0, 0, offsetof (ImDrawVert, pos), DkVtxAttribSize_2x32, DkVtxAttribType_Float, 0},
|
||||
DkVtxAttribState{0, 0, offsetof (ImDrawVert, uv), DkVtxAttribSize_2x32, DkVtxAttribType_Float, 0},
|
||||
DkVtxAttribState{0, 0, offsetof (ImDrawVert, col), DkVtxAttribSize_4x8, DkVtxAttribType_Unorm, 0},
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
/// \brief Vertex buffer state
|
||||
constexpr std::array VERTEX_BUFFER_STATE = {
|
||||
DkVtxBufferState{sizeof (ImDrawVert), 0},
|
||||
};
|
||||
|
||||
/// \brief Shader code memblock
|
||||
dk::UniqueMemBlock s_codeMemBlock;
|
||||
/// \brief Shaders (vertex, fragment)
|
||||
dk::Shader s_shaders[2];
|
||||
|
||||
/// \brief UBO memblock
|
||||
dk::UniqueMemBlock s_uboMemBlock;
|
||||
|
||||
/// \brief Vertex data memblock
|
||||
std::vector<dk::UniqueMemBlock> s_vtxMemBlock;
|
||||
/// \brief Index data memblock
|
||||
std::vector<dk::UniqueMemBlock> s_idxMemBlock;
|
||||
|
||||
/// \brief Font image memblock
|
||||
dk::UniqueMemBlock s_fontImageMemBlock;
|
||||
/// \brief Font texture handle
|
||||
DkResHandle s_fontTextureHandle;
|
||||
|
||||
/// \brief Load shader code
|
||||
void loadShaders (dk::UniqueDevice &device_)
|
||||
{
|
||||
/// \brief Shader file descriptor
|
||||
struct ShaderFile
|
||||
{
|
||||
/// \brief Parameterized constructor
|
||||
/// \param shader_ Shader object
|
||||
/// \param path_ Path to source code
|
||||
ShaderFile (dk::Shader &shader_, char const *const path_)
|
||||
: shader (shader_), path (path_), size (getSize (path_))
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief Get size of a file
|
||||
/// \param path_ Path to file
|
||||
static std::size_t getSize (char const *const path_)
|
||||
{
|
||||
struct stat st;
|
||||
auto const rc = ::stat (path_, &st);
|
||||
if (rc != 0)
|
||||
{
|
||||
std::fprintf (stderr, "stat(%s): %s\n", path_, std::strerror (errno));
|
||||
std::abort ();
|
||||
}
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
/// \brief Shader object
|
||||
dk::Shader &shader;
|
||||
/// \brief Path to source code
|
||||
char const *const path;
|
||||
/// \brief Source code file size
|
||||
std::size_t const size;
|
||||
};
|
||||
|
||||
auto shaderFiles = {ShaderFile{s_shaders[0], "romfs:/shaders/imgui_vsh.dksh"},
|
||||
ShaderFile{s_shaders[1], "romfs:/shaders/imgui_fsh.dksh"}};
|
||||
|
||||
// calculate total size of shaders
|
||||
auto const codeSize = std::accumulate (std::begin (shaderFiles),
|
||||
std::end (shaderFiles),
|
||||
DK_SHADER_CODE_UNUSABLE_SIZE,
|
||||
[] (auto const sum_, auto const &file_) {
|
||||
return sum_ + imgui::deko3d::align (file_.size, DK_SHADER_CODE_ALIGNMENT);
|
||||
});
|
||||
|
||||
// create shader code memblock
|
||||
s_codeMemBlock =
|
||||
dk::MemBlockMaker{device_, imgui::deko3d::align (codeSize, DK_MEMBLOCK_ALIGNMENT)}
|
||||
.setFlags (
|
||||
DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached | DkMemBlockFlags_Code)
|
||||
.create ();
|
||||
|
||||
auto const addr = static_cast<std::uint8_t *> (s_codeMemBlock.getCpuAddr ());
|
||||
std::size_t offset = 0;
|
||||
|
||||
// read shaders into memblock
|
||||
for (auto &file : shaderFiles)
|
||||
{
|
||||
std::uint32_t const codeOffset = offset;
|
||||
|
||||
auto *fp = fopen(file.path, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
std::fprintf (stderr, "open(%s): %s\n", file.path, std::strerror (errno));
|
||||
std::abort ();
|
||||
}
|
||||
|
||||
if (fread (&addr[offset], 1, file.size, fp) != file.size)
|
||||
{
|
||||
std::fprintf (stderr, "read(%s): %s\n", file.path, std::strerror (errno));
|
||||
std::abort ();
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
dk::ShaderMaker{s_codeMemBlock, codeOffset}.initialize (file.shader);
|
||||
|
||||
offset = imgui::deko3d::align (offset + file.size, DK_SHADER_CODE_ALIGNMENT);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Setup render state
|
||||
/// \param cmdBuf_ Command buffer
|
||||
/// \param drawData_ Data to draw
|
||||
/// \param width_ Framebuffer width
|
||||
/// \param height_ Framebuffer height
|
||||
DkCmdList setupRenderState (dk::UniqueCmdBuf &cmdBuf_,
|
||||
ImDrawData *const drawData_,
|
||||
unsigned const width_,
|
||||
unsigned const height_)
|
||||
{
|
||||
// setup viewport, orthographic projection matrix
|
||||
// our visible imgui space lies from drawData_->DisplayPos (top left) to
|
||||
// drawData_->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single
|
||||
// viewport apps.
|
||||
auto const L = drawData_->DisplayPos.x;
|
||||
auto const R = drawData_->DisplayPos.x + drawData_->DisplaySize.x;
|
||||
auto const T = drawData_->DisplayPos.y;
|
||||
auto const B = drawData_->DisplayPos.y + drawData_->DisplaySize.y;
|
||||
|
||||
VertUBO vertUBO;
|
||||
vertUBO.projMtx = glm::orthoRH_ZO (L, R, B, T, -1.0f, 1.0f);
|
||||
|
||||
// create command buffer to initialize/reset render state
|
||||
cmdBuf_.setViewports (0,
|
||||
DkViewport{0.0f, 0.0f, static_cast<float>(width_), static_cast<float>(height_)});
|
||||
cmdBuf_.bindShaders (DkStageFlag_GraphicsMask, {&s_shaders[0], &s_shaders[1]});
|
||||
cmdBuf_.bindUniformBuffer (DkStage_Vertex,
|
||||
0,
|
||||
s_uboMemBlock.getGpuAddr (),
|
||||
imgui::deko3d::align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT));
|
||||
cmdBuf_.pushConstants (s_uboMemBlock.getGpuAddr (),
|
||||
imgui::deko3d::align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
||||
0,
|
||||
sizeof (VertUBO),
|
||||
&vertUBO);
|
||||
cmdBuf_.bindUniformBuffer (DkStage_Fragment,
|
||||
0,
|
||||
s_uboMemBlock.getGpuAddr () +
|
||||
imgui::deko3d::align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
||||
imgui::deko3d::align (sizeof (FragUBO), DK_UNIFORM_BUF_ALIGNMENT));
|
||||
cmdBuf_.bindRasterizerState (dk::RasterizerState{}.setCullMode (DkFace_None));
|
||||
cmdBuf_.bindColorState (dk::ColorState{}.setBlendEnable (0, true));
|
||||
cmdBuf_.bindColorWriteState (dk::ColorWriteState{});
|
||||
cmdBuf_.bindDepthStencilState (dk::DepthStencilState{}.setDepthTestEnable (false));
|
||||
cmdBuf_.bindBlendStates (0,
|
||||
dk::BlendState{}.setFactors (DkBlendFactor_SrcAlpha,
|
||||
DkBlendFactor_InvSrcAlpha,
|
||||
DkBlendFactor_InvSrcAlpha,
|
||||
DkBlendFactor_Zero));
|
||||
cmdBuf_.bindVtxAttribState (VERTEX_ATTRIB_STATE);
|
||||
cmdBuf_.bindVtxBufferState (VERTEX_BUFFER_STATE);
|
||||
|
||||
return cmdBuf_.finishList ();
|
||||
}
|
||||
}
|
||||
|
||||
void imgui::deko3d::init (dk::UniqueDevice &device_,
|
||||
dk::UniqueQueue &queue_,
|
||||
dk::UniqueCmdBuf &cmdBuf_,
|
||||
dk::SamplerDescriptor &samplerDescriptor_,
|
||||
dk::ImageDescriptor &imageDescriptor_,
|
||||
DkResHandle fontTextureHandle_,
|
||||
unsigned const imageCount_)
|
||||
{
|
||||
auto &io = ImGui::GetIO ();
|
||||
|
||||
// setup back-end capabilities flags
|
||||
io.BackendRendererName = "deko3d";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
|
||||
|
||||
// load shader code
|
||||
loadShaders (device_);
|
||||
|
||||
// create UBO memblock
|
||||
s_uboMemBlock = dk::MemBlockMaker{device_,
|
||||
align (align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT) +
|
||||
align (sizeof (FragUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
||||
DK_MEMBLOCK_ALIGNMENT)}
|
||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||
.create ();
|
||||
|
||||
// create memblocks for each image slot
|
||||
for (std::size_t i = 0; i < imageCount_; ++i)
|
||||
{
|
||||
// create vertex data memblock
|
||||
s_vtxMemBlock.emplace_back (
|
||||
dk::MemBlockMaker{device_, align (VTXBUF_SIZE, DK_MEMBLOCK_ALIGNMENT)}
|
||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||
.create ());
|
||||
|
||||
// create index data memblock
|
||||
s_idxMemBlock.emplace_back (
|
||||
dk::MemBlockMaker{device_, align (IDXBUF_SIZE, DK_MEMBLOCK_ALIGNMENT)}
|
||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||
.create ());
|
||||
}
|
||||
|
||||
// get texture atlas
|
||||
io.Fonts->SetTexID (makeTextureID (fontTextureHandle_));
|
||||
s_fontTextureHandle = fontTextureHandle_;
|
||||
unsigned char *pixels;
|
||||
int width;
|
||||
int height;
|
||||
io.Fonts->GetTexDataAsAlpha8 (&pixels, &width, &height);
|
||||
|
||||
// create memblock for transfer
|
||||
dk::UniqueMemBlock memBlock =
|
||||
dk::MemBlockMaker{device_, align (width * height, DK_MEMBLOCK_ALIGNMENT)}
|
||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||
.create ();
|
||||
std::memcpy (memBlock.getCpuAddr (), pixels, width * height);
|
||||
|
||||
// initialize sampler descriptor
|
||||
samplerDescriptor_.initialize (
|
||||
dk::Sampler{}
|
||||
.setFilter (DkFilter_Linear, DkFilter_Linear)
|
||||
.setWrapMode (DkWrapMode_ClampToEdge, DkWrapMode_ClampToEdge, DkWrapMode_ClampToEdge));
|
||||
|
||||
// initialize texture atlas image layout
|
||||
dk::ImageLayout layout;
|
||||
dk::ImageLayoutMaker{device_}
|
||||
.setFlags (0)
|
||||
.setFormat (DkImageFormat_R8_Unorm)
|
||||
.setDimensions (width, height)
|
||||
.initialize (layout);
|
||||
|
||||
auto const fontAlign = layout.getAlignment ();
|
||||
auto const fontSize = layout.getSize ();
|
||||
|
||||
// create image memblock
|
||||
s_fontImageMemBlock = dk::MemBlockMaker{device_,
|
||||
align (fontSize, std::max<unsigned> (fontAlign, DK_MEMBLOCK_ALIGNMENT))}
|
||||
.setFlags (DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image)
|
||||
.create ();
|
||||
|
||||
// initialize font texture atlas image descriptor
|
||||
dk::Image fontTexture;
|
||||
fontTexture.initialize (layout, s_fontImageMemBlock, 0);
|
||||
imageDescriptor_.initialize (fontTexture);
|
||||
|
||||
// copy font texture atlas to image view
|
||||
dk::ImageView imageView{fontTexture};
|
||||
cmdBuf_.copyBufferToImage ({memBlock.getGpuAddr ()}, imageView,
|
||||
{0, 0, 0, static_cast<std::uint32_t>(width), static_cast<std::uint32_t>(height), 1});
|
||||
|
||||
// submit commands to transfer font texture
|
||||
queue_.submitCommands (cmdBuf_.finishList ());
|
||||
|
||||
// wait for commands to complete before releasing memblock
|
||||
queue_.waitIdle ();
|
||||
}
|
||||
|
||||
void imgui::deko3d::exit ()
|
||||
{
|
||||
s_fontImageMemBlock = nullptr;
|
||||
|
||||
s_idxMemBlock.clear ();
|
||||
s_vtxMemBlock.clear ();
|
||||
|
||||
s_uboMemBlock = nullptr;
|
||||
s_codeMemBlock = nullptr;
|
||||
}
|
||||
|
||||
void imgui::deko3d::render (dk::UniqueDevice &device_,
|
||||
dk::UniqueQueue &queue_,
|
||||
dk::UniqueCmdBuf &cmdBuf_,
|
||||
unsigned const slot_)
|
||||
{
|
||||
// get ImGui draw data
|
||||
auto const drawData = ImGui::GetDrawData ();
|
||||
if (drawData->CmdListsCount <= 0)
|
||||
return;
|
||||
|
||||
// get framebuffer dimensions
|
||||
unsigned width = drawData->DisplaySize.x * drawData->FramebufferScale.x;
|
||||
unsigned height = drawData->DisplaySize.y * drawData->FramebufferScale.y;
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
// setup desired render state
|
||||
auto const setupCmd = setupRenderState (cmdBuf_, drawData, width, height);
|
||||
queue_.submitCommands (setupCmd);
|
||||
|
||||
// currently bound texture
|
||||
std::optional<DkResHandle> boundTextureHandle;
|
||||
|
||||
// will project scissor/clipping rectangles into framebuffer space
|
||||
// (0,0) unless using multi-viewports
|
||||
auto const clipOff = drawData->DisplayPos;
|
||||
// (1,1) unless using retina display which are often (2,2)
|
||||
auto const clipScale = drawData->FramebufferScale;
|
||||
|
||||
// check if we need to grow vertex data memblock
|
||||
if (s_vtxMemBlock[slot_].getSize () < drawData->TotalVtxCount * sizeof (ImDrawVert))
|
||||
{
|
||||
// add 10% to avoid growing many frames in a row
|
||||
std::size_t const count = drawData->TotalVtxCount * 1.1f;
|
||||
|
||||
s_vtxMemBlock[slot_] =
|
||||
dk::MemBlockMaker{device_, align (count * sizeof (ImDrawVert), DK_MEMBLOCK_ALIGNMENT)}
|
||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||
.create ();
|
||||
}
|
||||
|
||||
// check if we need to grow index data memblock
|
||||
if (s_idxMemBlock[slot_].getSize () < drawData->TotalIdxCount * sizeof (ImDrawIdx))
|
||||
{
|
||||
// add 10% to avoid growing many frames in a row
|
||||
std::size_t const count = drawData->TotalIdxCount * 1.1f;
|
||||
|
||||
s_idxMemBlock[slot_] =
|
||||
dk::MemBlockMaker{device_, align (count * sizeof (ImDrawIdx), DK_MEMBLOCK_ALIGNMENT)}
|
||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||
.create ();
|
||||
}
|
||||
|
||||
// get base cpu addresses
|
||||
auto const cpuVtx = static_cast<std::uint8_t *> (s_vtxMemBlock[slot_].getCpuAddr ());
|
||||
auto const cpuIdx = static_cast<std::uint8_t *> (s_idxMemBlock[slot_].getCpuAddr ());
|
||||
|
||||
// get base gpu addresses
|
||||
auto const gpuVtx = s_vtxMemBlock[slot_].getGpuAddr ();
|
||||
auto const gpuIdx = s_idxMemBlock[slot_].getGpuAddr ();
|
||||
|
||||
// get memblock sizes
|
||||
auto const sizeVtx = s_vtxMemBlock[slot_].getSize ();
|
||||
auto const sizeIdx = s_idxMemBlock[slot_].getSize ();
|
||||
|
||||
// bind vertex/index data memblocks
|
||||
static_assert (sizeof (ImDrawIdx) == sizeof (std::uint16_t));
|
||||
cmdBuf_.bindVtxBuffer (0, gpuVtx, sizeVtx);
|
||||
cmdBuf_.bindIdxBuffer (DkIdxFormat_Uint16, gpuIdx);
|
||||
|
||||
// render command lists
|
||||
std::size_t offsetVtx = 0;
|
||||
std::size_t offsetIdx = 0;
|
||||
for (int i = 0; i < drawData->CmdListsCount; ++i)
|
||||
{
|
||||
auto const &cmdList = *drawData->CmdLists[i];
|
||||
|
||||
auto const vtxSize = cmdList.VtxBuffer.Size * sizeof (ImDrawVert);
|
||||
auto const idxSize = cmdList.IdxBuffer.Size * sizeof (ImDrawIdx);
|
||||
|
||||
// double check that we don't overrun vertex data memblock
|
||||
if (sizeVtx - offsetVtx < vtxSize)
|
||||
{
|
||||
std::fprintf (stderr, "Not enough vertex buffer\n");
|
||||
std::fprintf (stderr, "\t%zu/%u used, need %zu\n", offsetVtx, sizeVtx, vtxSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
// double check that we don't overrun index data memblock
|
||||
if (sizeIdx - offsetIdx < idxSize)
|
||||
{
|
||||
std::fprintf (stderr, "Not enough index buffer\n");
|
||||
std::fprintf (stderr, "\t%zu/%u used, need %zu\n", offsetIdx, sizeIdx, idxSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
// copy vertex/index data into memblocks
|
||||
std::memcpy (cpuVtx + offsetVtx, cmdList.VtxBuffer.Data, vtxSize);
|
||||
std::memcpy (cpuIdx + offsetIdx, cmdList.IdxBuffer.Data, idxSize);
|
||||
|
||||
for (auto const &cmd : cmdList.CmdBuffer)
|
||||
{
|
||||
if (cmd.UserCallback)
|
||||
{
|
||||
// submit commands to preserve ordering
|
||||
queue_.submitCommands (cmdBuf_.finishList ());
|
||||
|
||||
// user callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to
|
||||
// request the renderer to reset render state.)
|
||||
if (cmd.UserCallback == ImDrawCallback_ResetRenderState)
|
||||
queue_.submitCommands (setupCmd);
|
||||
else
|
||||
cmd.UserCallback (&cmdList, &cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// project scissor/clipping rectangles into framebuffer space
|
||||
ImVec4 clip;
|
||||
clip.x = (cmd.ClipRect.x - clipOff.x) * clipScale.x;
|
||||
clip.y = (cmd.ClipRect.y - clipOff.y) * clipScale.y;
|
||||
clip.z = (cmd.ClipRect.z - clipOff.x) * clipScale.x;
|
||||
clip.w = (cmd.ClipRect.w - clipOff.y) * clipScale.y;
|
||||
|
||||
// check if clip coordinate are outside of the framebuffer
|
||||
if (clip.x >= width || clip.y >= height || clip.z < 0.0f || clip.w < 0.0f)
|
||||
continue;
|
||||
|
||||
// keep scissor coordinates inside viewport
|
||||
if (clip.x < 0.0f)
|
||||
clip.x = 0.0f;
|
||||
if (clip.y < 0.0f)
|
||||
clip.y = 0.0f;
|
||||
if (clip.z > width)
|
||||
clip.z = width;
|
||||
if (clip.w > height)
|
||||
clip.z = height;
|
||||
|
||||
// apply scissor boundaries
|
||||
cmdBuf_.setScissors (0,
|
||||
DkScissor{static_cast<std::uint32_t>(clip.x), static_cast<std::uint32_t>(clip.y),
|
||||
static_cast<std::uint32_t>(clip.z - clip.x), static_cast<std::uint32_t>(clip.w - clip.y)});
|
||||
|
||||
// get texture handle
|
||||
auto const textureHandle = reinterpret_cast<std::uintptr_t> (cmd.TextureId);
|
||||
|
||||
// check if we need to bind a new texture
|
||||
if (!boundTextureHandle || textureHandle != *boundTextureHandle)
|
||||
{
|
||||
// check if this is the first draw or changing to or from the font texture
|
||||
if (!boundTextureHandle || textureHandle == s_fontTextureHandle ||
|
||||
*boundTextureHandle == s_fontTextureHandle)
|
||||
{
|
||||
FragUBO fragUBO;
|
||||
fragUBO.font = (textureHandle == s_fontTextureHandle);
|
||||
|
||||
// update fragment shader UBO
|
||||
cmdBuf_.pushConstants (
|
||||
s_uboMemBlock.getGpuAddr () +
|
||||
align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
||||
align (sizeof (FragUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
||||
0,
|
||||
sizeof (FragUBO),
|
||||
&fragUBO);
|
||||
}
|
||||
|
||||
boundTextureHandle = textureHandle;
|
||||
|
||||
// bind the new texture
|
||||
cmdBuf_.bindTextures (DkStage_Fragment, 0, textureHandle);
|
||||
}
|
||||
|
||||
// draw the draw list
|
||||
cmdBuf_.drawIndexed (DkPrimitive_Triangles,
|
||||
cmd.ElemCount,
|
||||
1,
|
||||
cmd.IdxOffset + offsetIdx / sizeof (ImDrawIdx),
|
||||
cmd.VtxOffset + offsetVtx / sizeof (ImDrawVert),
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
offsetVtx += vtxSize;
|
||||
offsetIdx += idxSize;
|
||||
}
|
||||
|
||||
// submit final commands
|
||||
queue_.submitCommands (cmdBuf_.finishList ());
|
||||
}
|
48
source/imgui_nx/imgui_fsh.glsl
Normal file
@ -0,0 +1,48 @@
|
||||
// ftpd is a server implementation based on the following:
|
||||
// - RFC 959 (https://tools.ietf.org/html/rfc959)
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (C) 2020 Michael Theall
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#version 460
|
||||
|
||||
layout (location = 0) in vec2 vtxUv;
|
||||
layout (location = 1) in vec4 vtxColor;
|
||||
|
||||
layout (binding = 0) uniform sampler2D tex;
|
||||
|
||||
layout (std140, binding = 0) uniform FragUBO {
|
||||
uint font;
|
||||
} ubo;
|
||||
|
||||
layout (location = 0) out vec4 outColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
// font texture is single-channel (alpha)
|
||||
if (ubo.font != 0)
|
||||
outColor = vtxColor * vec4 (vec3 (1.0), texture (tex, vtxUv).r);
|
||||
else
|
||||
outColor = vtxColor * texture (tex, vtxUv);
|
||||
}
|
208
source/imgui_nx/imgui_nx.cpp
Normal file
@ -0,0 +1,208 @@
|
||||
// ftpd is a server implementation based on the following:
|
||||
// - RFC 959 (https://tools.ietf.org/html/rfc959)
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (C) 2020 Michael Theall
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "imgui_nx.h"
|
||||
#include <imgui.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <switch.h>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace {
|
||||
|
||||
std::chrono::steady_clock::time_point s_lastMouseUpdate;
|
||||
|
||||
float s_width = 1280.0f;
|
||||
float s_height = 720.0f;
|
||||
|
||||
ImVec2 s_mousePos = ImVec2(0.0f, 0.0f);
|
||||
|
||||
AppletHookCookie s_appletHookCookie;
|
||||
|
||||
PadState s_pad;
|
||||
|
||||
void handleAppletHook(AppletHookType type, void *param) {
|
||||
if (type != AppletHookType_OnOperationMode)
|
||||
return;
|
||||
|
||||
switch (appletGetOperationMode()) {
|
||||
default:
|
||||
case AppletOperationMode_Handheld:
|
||||
// use handheld mode resolution (720p) and scale
|
||||
s_width = 1280.0f, s_height = 720.0f;
|
||||
ImGui::GetStyle().ScaleAllSizes(1.9f / 2.6f);
|
||||
ImGui::GetIO().FontGlobalScale = 0.9f;
|
||||
break;
|
||||
|
||||
case AppletOperationMode_Console:
|
||||
// use docked mode resolution (1080p) and scale
|
||||
s_width = 1920.0f, s_height = 1080.0f;
|
||||
ImGui::GetStyle().ScaleAllSizes(2.6f / 1.9f);
|
||||
ImGui::GetIO().FontGlobalScale = 1.6f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void updateTouch(ImGuiIO &io_) {
|
||||
// read touch positions
|
||||
HidTouchScreenState state = {0};
|
||||
auto count = hidGetTouchScreenStates(&state, 1);
|
||||
if (count < 1 || state.count < 1) {
|
||||
io_.MouseDown[0] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// set mouse position to touch point
|
||||
s_mousePos = ImVec2(state.touches[0].x, state.touches[0].y);
|
||||
io_.MouseDown[0] = true;
|
||||
}
|
||||
|
||||
void updateKeys(ImGuiIO &io_) {
|
||||
constexpr std::array mapping = {
|
||||
std::pair(ImGuiNavInput_Activate, HidNpadButton_A),
|
||||
std::pair(ImGuiNavInput_Cancel, HidNpadButton_B),
|
||||
std::pair(ImGuiNavInput_Input, HidNpadButton_X),
|
||||
std::pair(ImGuiNavInput_Menu, HidNpadButton_Y),
|
||||
std::pair(ImGuiNavInput_FocusPrev, HidNpadButton_L),
|
||||
std::pair(ImGuiNavInput_TweakSlow, HidNpadButton_L),
|
||||
std::pair(ImGuiNavInput_FocusNext, HidNpadButton_R),
|
||||
std::pair(ImGuiNavInput_TweakFast, HidNpadButton_R),
|
||||
std::pair(ImGuiNavInput_DpadUp, HidNpadButton_Up),
|
||||
std::pair(ImGuiNavInput_DpadRight, HidNpadButton_Right),
|
||||
std::pair(ImGuiNavInput_DpadDown, HidNpadButton_Down),
|
||||
std::pair(ImGuiNavInput_DpadLeft, HidNpadButton_Left),
|
||||
};
|
||||
|
||||
padUpdate(&s_pad);
|
||||
auto down = padGetButtons(&s_pad);
|
||||
|
||||
for (auto [im, nx]: mapping)
|
||||
if (down & nx)
|
||||
io_.NavInputs[im] = 1.0f;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool imgui::nx::init() {
|
||||
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
|
||||
padInitializeDefault(&s_pad);
|
||||
|
||||
auto &io = ImGui::GetIO();
|
||||
|
||||
// Load nintendo font
|
||||
PlFontData standard, extended, chinese, korean;
|
||||
static ImWchar extended_range[] = {0xe000, 0xe152};
|
||||
if (R_SUCCEEDED(plGetSharedFontByType(&standard, PlSharedFontType_Standard)) &&
|
||||
R_SUCCEEDED(plGetSharedFontByType(&extended, PlSharedFontType_NintendoExt)) &&
|
||||
R_SUCCEEDED(plGetSharedFontByType(&chinese, PlSharedFontType_ChineseSimplified)) &&
|
||||
R_SUCCEEDED(plGetSharedFontByType(&korean, PlSharedFontType_KO))) {
|
||||
std::uint8_t *px;
|
||||
int w, h, bpp;
|
||||
ImFontConfig font_cfg;
|
||||
|
||||
font_cfg.FontDataOwnedByAtlas = false;
|
||||
io.Fonts->AddFontFromMemoryTTF(standard.address, standard.size, 24.0f, &font_cfg, io.Fonts->GetGlyphRangesDefault());
|
||||
font_cfg.MergeMode = true;
|
||||
io.Fonts->AddFontFromMemoryTTF(extended.address, extended.size, 24.0f, &font_cfg, extended_range);
|
||||
io.Fonts->AddFontFromMemoryTTF(chinese.address, chinese.size, 24.0f, &font_cfg, io.Fonts->GetGlyphRangesChineseFull());
|
||||
io.Fonts->AddFontFromMemoryTTF(korean.address, korean.size, 24.0f, &font_cfg, io.Fonts->GetGlyphRangesKorean());
|
||||
|
||||
// build font atlas
|
||||
io.Fonts->GetTexDataAsAlpha8(&px, &w, &h, &bpp);
|
||||
io.Fonts->Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;
|
||||
io.Fonts->Build();
|
||||
}
|
||||
|
||||
auto &style = ImGui::GetStyle();
|
||||
style.WindowRounding = 0.0f;
|
||||
|
||||
auto mode = appletGetOperationMode();
|
||||
if (mode == AppletOperationMode_Handheld) {
|
||||
s_width = 1280.0f, s_height = 720.0f;
|
||||
style.ScaleAllSizes(1.9f);
|
||||
io.FontGlobalScale = 0.9f;
|
||||
} else {
|
||||
s_width = 1920.0f, s_height = 1080.0f;
|
||||
style.ScaleAllSizes(2.6f);
|
||||
io.FontGlobalScale = 1.6f;
|
||||
}
|
||||
|
||||
// initialize applet hooks
|
||||
appletHook(&s_appletHookCookie, handleAppletHook, nullptr);
|
||||
|
||||
// disable imgui.ini file
|
||||
io.IniFilename = nullptr;
|
||||
|
||||
// setup config flags
|
||||
io.ConfigFlags |= ImGuiConfigFlags_IsTouchScreen;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
|
||||
// disable mouse cursor
|
||||
io.MouseDrawCursor = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::uint64_t imgui::nx::newFrame() {
|
||||
auto &io = ImGui::GetIO();
|
||||
|
||||
// setup display metrics
|
||||
io.DisplaySize = ImVec2(s_width, s_height);
|
||||
io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
|
||||
|
||||
// time step
|
||||
static auto const start = std::chrono::steady_clock::now();
|
||||
static auto prev = start;
|
||||
auto const now = std::chrono::steady_clock::now();
|
||||
|
||||
io.DeltaTime = std::chrono::duration<float> (now - prev).count();
|
||||
prev = now;
|
||||
|
||||
// update inputs
|
||||
updateTouch(io);
|
||||
updateKeys(io);
|
||||
|
||||
// clamp mouse to screen
|
||||
s_mousePos.x = std::clamp(s_mousePos.x, 0.0f, s_width);
|
||||
s_mousePos.y = std::clamp(s_mousePos.y, 0.0f, s_height);
|
||||
io.MousePos = s_mousePos;
|
||||
|
||||
return padGetButtonsDown(&s_pad);
|
||||
}
|
||||
|
||||
void imgui::nx::exit() {
|
||||
// deinitialize applet hooks
|
||||
appletUnhook(&s_appletHookCookie);
|
||||
}
|
47
source/imgui_nx/imgui_vsh.glsl
Normal file
@ -0,0 +1,47 @@
|
||||
// ftpd is a server implementation based on the following:
|
||||
// - RFC 959 (https://tools.ietf.org/html/rfc959)
|
||||
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (C) 2020 Michael Theall
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#version 460
|
||||
|
||||
layout (location = 0) in vec2 inPos;
|
||||
layout (location = 1) in vec2 inUv;
|
||||
layout (location = 2) in vec4 inColor;
|
||||
|
||||
layout (location = 0) out vec2 vtxUv;
|
||||
layout (location = 1) out vec4 vtxColor;
|
||||
|
||||
layout (std140, binding = 0) uniform VertUBO
|
||||
{
|
||||
mat4 projMtx;
|
||||
} ubo;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = ubo.projMtx * vec4 (inPos, 0.0, 1.0);
|
||||
vtxUv = inUv;
|
||||
vtxColor = inColor;
|
||||
}
|
232
source/main.cpp
@ -1,22 +1,21 @@
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <switch.h>
|
||||
#include <imgui.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include "log.h"
|
||||
#include "textures.h"
|
||||
#include "windows.h"
|
||||
|
||||
SDL_Window *window = nullptr;
|
||||
char __application_path[FS_MAX_PATH];
|
||||
|
||||
namespace Services {
|
||||
SDL_GLContext gl_context;
|
||||
|
||||
void SetDefaultTheme(void) {
|
||||
void SetDefaultTheme(void) {
|
||||
ImGui::GetStyle().FrameRounding = 4.0f;
|
||||
ImGui::GetStyle().GrabRounding = 4.0f;
|
||||
|
||||
@ -55,8 +54,8 @@ namespace Services {
|
||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
||||
colors[ImGuiCol_Tab] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
|
||||
colors[ImGuiCol_TabHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
|
||||
colors[ImGuiCol_TabActive] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
|
||||
colors[ImGuiCol_TabHovered] = ImVec4(0.00f, 0.50f, 0.50f, 1.0f);
|
||||
colors[ImGuiCol_TabActive] = ImVec4(0.00f, 0.50f, 0.50f, 1.0f);
|
||||
colors[ImGuiCol_TabUnfocused] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
|
||||
colors[ImGuiCol_PlotLines] = ImVec4(0.00f, 0.50f, 0.50f, 1.0f);
|
||||
@ -70,181 +69,56 @@ namespace Services {
|
||||
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
|
||||
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
|
||||
}
|
||||
|
||||
int InitImGui(void) {
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
Log::Error("Error: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (!SDL_JoystickOpen(i)) {
|
||||
Log::Error("SDL_JoystickOpen: %s\n", SDL_GetError());
|
||||
SDL_Quit();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// GL 3.0 + GLSL 130
|
||||
const char *glsl_version = "#version 130";
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
|
||||
// Create window with graphics context
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
SDL_WindowFlags window_flags = static_cast<SDL_WindowFlags>(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
window = SDL_CreateWindow("NX-Shell", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
|
||||
gl_context = SDL_GL_CreateContext(window);
|
||||
SDL_GL_MakeCurrent(window, gl_context);
|
||||
SDL_GL_SetSwapInterval(1); // Enable vsync
|
||||
|
||||
// Initialize OpenGL loader
|
||||
bool err = gladLoadGL() == 0;
|
||||
if (err) {
|
||||
Log::Error("Failed to initialize OpenGL loader!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_IsTouchScreen;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
|
||||
io.IniFilename = nullptr;
|
||||
io.MouseDrawCursor = false;
|
||||
|
||||
// Setup Dear ImGui style
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
// Setup Platform/Renderer bindings
|
||||
ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
|
||||
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||
|
||||
Result ret = 0;
|
||||
PlFontData standard, s_chinese, t_chinese, korean;
|
||||
if (R_FAILED(ret = plGetSharedFontByType(&standard, PlSharedFontType_Standard))) {
|
||||
Log::Error("plGetSharedFontByType(PlSharedFontType_Standard) failed: 0x%x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = plGetSharedFontByType(&s_chinese, PlSharedFontType_ChineseSimplified))) {
|
||||
Log::Error("plGetSharedFontByType(PlSharedFontType_ChineseSimplified) failed: 0x%x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = plGetSharedFontByType(&t_chinese, PlSharedFontType_ChineseTraditional))) {
|
||||
Log::Error("plGetSharedFontByType(PlSharedFontType_ChineseTraditional) failed: 0x%x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = plGetSharedFontByType(&korean, PlSharedFontType_KO))) {
|
||||
Log::Error("plGetSharedFontByType(PlSharedFontType_KO) failed: 0x%x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned char *pixels = nullptr;
|
||||
int width = 0, height = 0, bpp = 0;
|
||||
ImFontConfig font_cfg;
|
||||
|
||||
font_cfg.FontDataOwnedByAtlas = false;
|
||||
io.Fonts->AddFontFromMemoryTTF(standard.address, standard.size, 24.0f, &font_cfg, io.Fonts->GetGlyphRangesDefault());
|
||||
font_cfg.MergeMode = true;
|
||||
|
||||
io.Fonts->AddFontFromMemoryTTF(s_chinese.address, s_chinese.size, 24.0f, &font_cfg, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
||||
io.Fonts->AddFontFromMemoryTTF(korean.address, korean.size, 24.0f, &font_cfg, io.Fonts->GetGlyphRangesKorean());
|
||||
io.Fonts->AddFontFromMemoryTTF(t_chinese.address, t_chinese.size, 24.0f, &font_cfg, io.Fonts->GetGlyphRangesChineseFull());
|
||||
|
||||
// build font atlas
|
||||
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height, &bpp);
|
||||
io.Fonts->Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;
|
||||
io.Fonts->Build();
|
||||
|
||||
Services::SetDefaultTheme();
|
||||
Textures::Init();
|
||||
plExit();
|
||||
romfsExit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ExitImGui(void) {
|
||||
Textures::Exit();
|
||||
|
||||
// Cleanup
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
SDL_GL_DeleteContext(gl_context);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
int Init(void) {
|
||||
// FS
|
||||
devices[0] = *fsdevGetDeviceFileSystem("sdmc");
|
||||
int Init(void) {
|
||||
devices[0] = *fsdevGetDeviceFileSystem("sdmc");
|
||||
fs = &devices[0];
|
||||
|
||||
Config::Load();
|
||||
Config::Load();
|
||||
Log::Init();
|
||||
plInitialize(PlServiceType_User);
|
||||
romfsInit();
|
||||
socketInitializeDefault();
|
||||
nxlinkStdio();
|
||||
|
||||
socketInitializeDefault();
|
||||
|
||||
if (cfg.dev_options)
|
||||
nxlinkStdio();
|
||||
if (!GUI::Init())
|
||||
printf("Failed to init\n");
|
||||
|
||||
Log::Init();
|
||||
Services::SetDefaultTheme();
|
||||
Textures::Init();
|
||||
plExit();
|
||||
romfsExit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result ret = 0;
|
||||
if (R_FAILED(ret = romfsInit())) {
|
||||
Log::Error("romfsInit() failed: 0x%x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = nifmInitialize(NifmServiceType_User))) {
|
||||
Log::Error("nifmInitialize(NifmServiceType_User) failed: 0x%x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = plInitialize(PlServiceType_User))) {
|
||||
Log::Error("plInitialize(PlServiceType_User) failed: 0x%x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Exit(void) {
|
||||
nifmExit();
|
||||
Log::Exit();
|
||||
socketExit();
|
||||
}
|
||||
void Exit(void) {
|
||||
Textures::Exit();
|
||||
GUI::Exit();
|
||||
socketExit();
|
||||
Log::Exit();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char *argv[]) {
|
||||
Result ret = 0;
|
||||
|
||||
// Strip "sdmc:" from application path
|
||||
std::string __application_path_string = argv[0];
|
||||
__application_path_string.erase(0, 5);
|
||||
std::strcpy(__application_path, __application_path_string.c_str());
|
||||
|
||||
if (R_FAILED(ret = Services::Init()))
|
||||
return ret;
|
||||
|
||||
if (R_FAILED(ret = Services::InitImGui()))
|
||||
return ret;
|
||||
|
||||
if (R_FAILED(ret = GUI::RenderLoop()))
|
||||
return ret;
|
||||
|
||||
Services::ExitImGui();
|
||||
Services::Exit();
|
||||
|
||||
return 0;
|
||||
int main(int argc, char* argv[]) {
|
||||
Result ret = 0;
|
||||
WindowData data;
|
||||
|
||||
Services::Init();
|
||||
|
||||
if (R_FAILED(ret = FS::GetDirList(cfg.cwd, data.entries))) {
|
||||
Services::Exit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
data.checked.resize(data.entries.size());
|
||||
FS::GetUsedStorageSpace(data.used_storage);
|
||||
FS::GetTotalStorageSpace(data.total_storage);
|
||||
|
||||
while (GUI::Loop()) {
|
||||
Windows::MainWindow(data);
|
||||
GUI::Render();
|
||||
}
|
||||
|
||||
Services::Exit();
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ namespace Net {
|
||||
bool GetAvailableUpdate(const std::string &tag) {
|
||||
if (tag.empty())
|
||||
return false;
|
||||
|
||||
|
||||
int current_ver = ((VERSION_MAJOR * 100) + (VERSION_MINOR * 10) + VERSION_MICRO);
|
||||
|
||||
std::string tag_name = tag;
|
||||
|
@ -1,164 +0,0 @@
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <zzip/zzip.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "language.h"
|
||||
#include "log.h"
|
||||
#include "popups.h"
|
||||
|
||||
namespace ArchiveHelper {
|
||||
std::string ConstructPath(const char path[FS_MAX_PATH]) {
|
||||
std::string new_path = cfg.cwd;
|
||||
new_path.append("/");
|
||||
new_path.append(std::filesystem::path(path).stem());
|
||||
new_path.append("/");
|
||||
return new_path;
|
||||
}
|
||||
|
||||
std::string ConstructDirname(const char path[FS_MAX_PATH], char *dirname) {
|
||||
std::string new_dirname = ArchiveHelper::ConstructPath(path);
|
||||
new_dirname.append(std::filesystem::path(dirname).parent_path());
|
||||
return new_dirname;
|
||||
}
|
||||
|
||||
std::string ConstructFilename(const char path[FS_MAX_PATH], char *filename) {
|
||||
std::string new_filename = ArchiveHelper::ConstructPath(path);
|
||||
new_filename.append(filename);
|
||||
return new_filename;
|
||||
}
|
||||
|
||||
Result RecursiveMakeDir(const std::string &path) {
|
||||
Result ret = 0;
|
||||
char buf[FS_MAX_PATH + 1];
|
||||
char *p = nullptr;
|
||||
|
||||
int length = std::snprintf(buf, sizeof(buf), path.c_str());
|
||||
if (buf[length - 1] == '/')
|
||||
buf[length - 1] = 0;
|
||||
|
||||
for (p = buf + 1; *p; p++) {
|
||||
if (*p == '/') {
|
||||
*p = 0;
|
||||
ret = fsFsCreateDirectory(fs, buf);
|
||||
*p = '/';
|
||||
}
|
||||
|
||||
ret = fsFsCreateDirectory(fs, buf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result ExtractFile(ZZIP_DIR *dir, const ZZIP_DIRENT &entry, const std::string &path) {
|
||||
Result ret = 0;
|
||||
ZZIP_FILE *src_handle = zzip_file_open(dir, entry.d_name, O_RDONLY);
|
||||
if (!src_handle) {
|
||||
Log::Error("zzip_file_open(%s) failed\n", path.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
char dest_path[FS_MAX_PATH + 1];
|
||||
std::snprintf(dest_path, FS_MAX_PATH, path.c_str());
|
||||
|
||||
if (!FS::FileExists(dest_path))
|
||||
fsFsCreateFile(fs, dest_path, entry.st_size, 0);
|
||||
|
||||
FsFile dest_handle;
|
||||
if (R_FAILED(ret = fsFsOpenFile(fs, dest_path, FsOpenMode_Write, &dest_handle))) {
|
||||
Log::Error("fsFsOpenFile(%s) failed: 0x%x\n", path.c_str(), ret);
|
||||
zzip_file_close(src_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const u64 buf_size = 0x10000;
|
||||
s64 offset = 0;
|
||||
unsigned char *buf = new unsigned char[buf_size];
|
||||
|
||||
zzip_ssize_t bytes_read = 0;
|
||||
std::string filename = std::filesystem::path(entry.d_name).filename();
|
||||
while (0 < (bytes_read = zzip_read(src_handle, buf, buf_size - 1))) {
|
||||
if (R_FAILED(ret = fsFileWrite(&dest_handle, offset, buf, bytes_read, FsWriteOption_Flush))) {
|
||||
Log::Error("fsFileWrite(%s) failed: 0x%x\n", path.c_str(), ret);
|
||||
delete[] buf;
|
||||
zzip_file_close(src_handle);
|
||||
fsFileClose(&dest_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
offset += bytes_read;
|
||||
std::memset(buf, 0, buf_size);
|
||||
Popups::ProgressPopup(static_cast<float>(offset), static_cast<float>(entry.st_size), strings[cfg.lang][Lang::ArchiveExtracting], filename.c_str());
|
||||
}
|
||||
|
||||
delete[] buf;
|
||||
fsFileClose(&dest_handle);
|
||||
zzip_file_close(src_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Extract(const char path[FS_MAX_PATH]) {
|
||||
ZZIP_DIR *dir;
|
||||
ZZIP_DIRENT entry;
|
||||
zzip_error_t error;
|
||||
|
||||
dir = zzip_dir_open(path, &error);
|
||||
if (!dir) {
|
||||
Log::Error("zzip_dir_open(%s) failed: 0x%x\n", path, error);
|
||||
return;
|
||||
}
|
||||
|
||||
while (zzip_dir_read(dir, &entry)) {
|
||||
std::string pathname = ArchiveHelper::ConstructDirname(path, entry.d_name);
|
||||
ArchiveHelper::RecursiveMakeDir(pathname);
|
||||
|
||||
std::string filename = ArchiveHelper::ConstructFilename(path, entry.d_name);
|
||||
ArchiveHelper::ExtractFile(dir, entry, filename);
|
||||
}
|
||||
|
||||
zzip_dir_close(dir);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Popups {
|
||||
void ArchivePopup(void) {
|
||||
Popups::SetupPopup(strings[cfg.lang][Lang::ArchiveTitle]);
|
||||
|
||||
if (ImGui::BeginPopupModal(strings[cfg.lang][Lang::ArchiveTitle], nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text(strings[cfg.lang][Lang::ArchiveMessage]);
|
||||
std::string text = strings[cfg.lang][Lang::ArchivePrompt] + std::string(item.entries[item.selected].name) + "?";
|
||||
ImGui::Text(text.c_str());
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::ButtonOK], ImVec2(120, 0))) {
|
||||
ImGui::EndPopup();
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Render();
|
||||
|
||||
char path[FS_MAX_PATH + 1];
|
||||
if ((std::snprintf(path, FS_MAX_PATH, "%s/%s", cfg.cwd, item.entries[item.selected].name)) > 0) {
|
||||
ArchiveHelper::Extract(path);
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
GUI::ResetCheckbox();
|
||||
}
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::SameLine(0.0f, 15.0f);
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::ButtonCancel], ImVec2(120, 0))) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
}
|
||||
}
|
||||
|
||||
Popups::ExitPopup();
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "language.h"
|
||||
#include "log.h"
|
||||
#include "popups.h"
|
||||
|
||||
namespace Popups {
|
||||
void DeletePopup(void) {
|
||||
Popups::SetupPopup(strings[cfg.lang][Lang::OptionsDelete]);
|
||||
|
||||
if (ImGui::BeginPopupModal(strings[cfg.lang][Lang::OptionsDelete], nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text(strings[cfg.lang][Lang::DeleteMessage]);
|
||||
if ((item.checked_count > 1) && (!item.checked_cwd.compare(cfg.cwd))) {
|
||||
ImGui::Text(strings[cfg.lang][Lang::DeleteMultiplePrompt]);
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
ImGui::BeginChild("Scrolling", ImVec2(0, 100));
|
||||
for (long unsigned int i = 0; i < item.checked.size(); i++) {
|
||||
if (item.checked.at(i))
|
||||
ImGui::Text(item.entries[i].name);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
else {
|
||||
std::string text = strings[cfg.lang][Lang::DeletePrompt] + std::string(item.entries[item.selected].name) + "?";
|
||||
ImGui::Text(text.c_str());
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::ButtonOK], ImVec2(120, 0))) {
|
||||
Result ret = 0;
|
||||
Log::Exit();
|
||||
|
||||
if ((item.checked_count > 1) && (!item.checked_cwd.compare(cfg.cwd))) {
|
||||
for (long unsigned int i = 0; i < item.checked.size(); i++) {
|
||||
if (item.checked.at(i)) {
|
||||
if (R_FAILED(ret = FS::Delete(&item.entries[i]))) {
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
GUI::ResetCheckbox();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ret = FS::Delete(&item.entries[item.selected]);
|
||||
|
||||
if (R_SUCCEEDED(ret)) {
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
GUI::ResetCheckbox();
|
||||
}
|
||||
|
||||
Log::Exit();
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
}
|
||||
|
||||
ImGui::SameLine(0.0f, 15.0f);
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::ButtonCancel], ImVec2(120, 0))) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_OPTIONS;
|
||||
}
|
||||
}
|
||||
|
||||
Popups::ExitPopup();
|
||||
}
|
||||
}
|
@ -1,185 +0,0 @@
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "keyboard.h"
|
||||
#include "language.h"
|
||||
#include "popups.h"
|
||||
|
||||
namespace Popups {
|
||||
static bool copy = false, move = false;
|
||||
static void HandleMultipleCopy(Result (*func)()) {
|
||||
Result ret = 0;
|
||||
std::vector<FsDirectoryEntry> entries;
|
||||
|
||||
if (R_FAILED(ret = FS::GetDirList(item.checked_cwd.data(), entries)))
|
||||
return;
|
||||
|
||||
for (long unsigned int i = 0; i < item.checked_copy.size(); i++) {
|
||||
if (item.checked_copy.at(i)) {
|
||||
FS::Copy(&entries[i], item.checked_cwd);
|
||||
if (R_FAILED((*func)())) {
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
GUI::ResetCheckbox();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
GUI::ResetCheckbox();
|
||||
entries.clear();
|
||||
}
|
||||
|
||||
void OptionsPopup(void) {
|
||||
Popups::SetupPopup(strings[cfg.lang][Lang::OptionsTitle]);
|
||||
|
||||
if (ImGui::BeginPopupModal(strings[cfg.lang][Lang::OptionsTitle], nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::OptionsSelectAll], ImVec2(200, 50))) {
|
||||
if ((!item.checked_cwd.empty()) && (item.checked_cwd.compare(cfg.cwd) != 0))
|
||||
GUI::ResetCheckbox();
|
||||
|
||||
item.checked_cwd = cfg.cwd;
|
||||
std::fill(item.checked.begin(), item.checked.end(), true);
|
||||
item.checked_count = item.checked.size();
|
||||
}
|
||||
|
||||
ImGui::SameLine(0.0f, 15.0f);
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::OptionsClearAll], ImVec2(200, 50))) {
|
||||
GUI::ResetCheckbox();
|
||||
copy = false;
|
||||
move = false;
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::OptionsProperties], ImVec2(200, 50))) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_PROPERTIES;
|
||||
}
|
||||
|
||||
ImGui::SameLine(0.0f, 15.0f);
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::OptionsRename], ImVec2(200, 50))) {
|
||||
std::string path = Keyboard::GetText(strings[cfg.lang][Lang::OptionsRenamePrompt], item.entries[item.selected].name);
|
||||
if (R_SUCCEEDED(FS::Rename(&item.entries[item.selected], path.c_str())))
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::OptionsNewFolder], ImVec2(200, 50))) {
|
||||
std::string path = cfg.cwd;
|
||||
path.append("/");
|
||||
std::string name = Keyboard::GetText(strings[cfg.lang][Lang::OptionsFolderPrompt], strings[cfg.lang][Lang::OptionsNewFolder]);
|
||||
path.append(name);
|
||||
|
||||
if (R_SUCCEEDED(fsFsCreateDirectory(fs, path.c_str()))) {
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
GUI::ResetCheckbox();
|
||||
}
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
}
|
||||
|
||||
ImGui::SameLine(0.0f, 15.0f);
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::OptionsNewFile], ImVec2(200, 50))) {
|
||||
std::string path = cfg.cwd;
|
||||
path.append("/");
|
||||
std::string name = Keyboard::GetText(strings[cfg.lang][Lang::OptionsFilePrompt], strings[cfg.lang][Lang::OptionsNewFile]);
|
||||
path.append(name);
|
||||
|
||||
if (R_SUCCEEDED(fsFsCreateFile(fs, path.c_str(), 0, 0))) {
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
GUI::ResetCheckbox();
|
||||
}
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::Button(!copy? strings[cfg.lang][Lang::OptionsCopy] : strings[cfg.lang][Lang::OptionsPaste], ImVec2(200, 50))) {
|
||||
if (!copy) {
|
||||
if ((item.checked_count >= 1) && (item.checked_cwd.compare(cfg.cwd) != 0))
|
||||
GUI::ResetCheckbox();
|
||||
if (item.checked_count <= 1)
|
||||
FS::Copy(&item.entries[item.selected], cfg.cwd);
|
||||
|
||||
copy = !copy;
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
}
|
||||
else {
|
||||
ImGui::EndPopup();
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Render();
|
||||
|
||||
if ((item.checked_count > 1) && (item.checked_cwd.compare(cfg.cwd) != 0))
|
||||
Popups::HandleMultipleCopy(&FS::Paste);
|
||||
else {
|
||||
if (R_SUCCEEDED(FS::Paste())) {
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
GUI::ResetCheckbox();
|
||||
}
|
||||
}
|
||||
|
||||
copy = !copy;
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine(0.0f, 15.0f);
|
||||
|
||||
if (ImGui::Button(!move? strings[cfg.lang][Lang::OptionsMove] : strings[cfg.lang][Lang::OptionsPaste], ImVec2(200, 50))) {
|
||||
if (!move) {
|
||||
if ((item.checked_count >= 1) && (item.checked_cwd.compare(cfg.cwd) != 0))
|
||||
GUI::ResetCheckbox();
|
||||
if (item.checked_count <= 1)
|
||||
FS::Copy(&item.entries[item.selected], cfg.cwd);
|
||||
}
|
||||
else {
|
||||
if ((item.checked_count > 1) && (item.checked_cwd.compare(cfg.cwd) != 0))
|
||||
Popups::HandleMultipleCopy(&FS::Move);
|
||||
else if (R_SUCCEEDED(FS::Move())) {
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
GUI::ResetCheckbox();
|
||||
}
|
||||
}
|
||||
|
||||
move = !move;
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::OptionsDelete], ImVec2(200, 50))) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_DELETE;
|
||||
}
|
||||
|
||||
ImGui::SameLine(0.0f, 15.0f);
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::OptionsSetArchiveBit], ImVec2(200, 50))) {
|
||||
if (R_SUCCEEDED(FS::SetArchiveBit(&item.entries[item.selected]))) {
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
GUI::ResetCheckbox();
|
||||
}
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_FILEBROWSER;
|
||||
}
|
||||
}
|
||||
|
||||
Popups::ExitPopup();
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include "popups.h"
|
||||
#include "windows.h"
|
||||
|
||||
namespace Popups {
|
||||
static bool focus = false, first_item = false;
|
||||
|
||||
void ProgressPopup(float offset, float size, const std::string &title, const std::string &text) {
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame(window);
|
||||
ImGui::NewFrame();
|
||||
|
||||
Windows::FileBrowserWindow(&focus, &first_item);
|
||||
Popups::SetupPopup(title.c_str());
|
||||
|
||||
if (ImGui::BeginPopupModal(title.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text(text.c_str());
|
||||
ImGui::ProgressBar(offset/size, ImVec2(0.0f, 0.0f));
|
||||
}
|
||||
|
||||
Popups::ExitPopup();
|
||||
ImGui::Render();
|
||||
glViewport(0, 0, static_cast<int>(ImGui::GetIO().DisplaySize.x), static_cast<int>(ImGui::GetIO().DisplaySize.y));
|
||||
glClearColor(0.00f, 0.00f, 0.00f, 1.00f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
SDL_GL_SwapWindow(window);
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "language.h"
|
||||
#include "popups.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace Popups {
|
||||
static char *FormatDate(char *string, time_t timestamp) {
|
||||
strftime(string, 36, "%Y/%m/%d %H:%M:%S", localtime(×tamp));
|
||||
return string;
|
||||
}
|
||||
|
||||
void FilePropertiesPopup(void) {
|
||||
Popups::SetupPopup(strings[cfg.lang][Lang::OptionsProperties]);
|
||||
|
||||
if (ImGui::BeginPopupModal(strings[cfg.lang][Lang::OptionsProperties], nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
std::string name_text = strings[cfg.lang][Lang::PropertiesName] + std::string(item.entries[item.selected].name);
|
||||
ImGui::Text(name_text.c_str());
|
||||
|
||||
if (item.entries[item.selected].type == FsDirEntryType_File) {
|
||||
char size[16];
|
||||
Utils::GetSizeString(size, static_cast<double>(item.entries[item.selected].file_size));
|
||||
std::string size_text = strings[cfg.lang][Lang::PropertiesSize];
|
||||
size_text.append(size);
|
||||
ImGui::Text(size_text.c_str());
|
||||
}
|
||||
|
||||
FsTimeStampRaw timestamp;
|
||||
if (R_SUCCEEDED(FS::GetTimeStamp(&item.entries[item.selected], ×tamp))) {
|
||||
if (timestamp.is_valid == 1) { // Confirm valid timestamp
|
||||
char date[3][36];
|
||||
|
||||
std::string created_time = strings[cfg.lang][Lang::PropertiesCreated];
|
||||
created_time.append(Popups::FormatDate(date[0], timestamp.created));
|
||||
ImGui::Text(created_time.c_str());
|
||||
|
||||
std::string modified_time = strings[cfg.lang][Lang::PropertiesModified];
|
||||
modified_time.append(Popups::FormatDate(date[1], timestamp.modified));
|
||||
ImGui::Text(modified_time.c_str());
|
||||
|
||||
std::string accessed_time = strings[cfg.lang][Lang::PropertiesAccessed];
|
||||
accessed_time.append(Popups::FormatDate(date[2], timestamp.accessed));
|
||||
ImGui::Text(accessed_time.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::ButtonOK], ImVec2(120, 0))) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
item.state = MENU_STATE_OPTIONS;
|
||||
}
|
||||
}
|
||||
|
||||
Popups::ExitPopup();
|
||||
}
|
||||
|
||||
void ImageProperties(bool *state) {
|
||||
Popups::SetupPopup(strings[cfg.lang][Lang::OptionsProperties]);
|
||||
|
||||
if (ImGui::BeginPopupModal(strings[cfg.lang][Lang::OptionsProperties], nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
std::string name_text = strings[cfg.lang][Lang::PropertiesName] + std::string(item.entries[item.selected].name);
|
||||
ImGui::Text(name_text.c_str());
|
||||
|
||||
std::string width_text = strings[cfg.lang][Lang::PropertiesWidth];
|
||||
width_text.append(std::to_string(item.textures[0].width));
|
||||
width_text.append("px");
|
||||
ImGui::Text(width_text.c_str());
|
||||
|
||||
std::string height_text = strings[cfg.lang][Lang::PropertiesHeight];
|
||||
height_text.append(std::to_string(item.textures[0].height));
|
||||
height_text.append("px");
|
||||
ImGui::Text(height_text.c_str());
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::ButtonOK], ImVec2(120, 0))) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
*state = false;
|
||||
}
|
||||
}
|
||||
|
||||
Popups::ExitPopup();
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "language.h"
|
||||
#include "log.h"
|
||||
#include "net.h"
|
||||
#include "popups.h"
|
||||
#include "utils.h"
|
||||
#include "windows.h"
|
||||
|
||||
namespace Popups {
|
||||
static bool done = false;
|
||||
|
||||
void UpdatePopup(bool *state, bool *connection_status, bool *available, const std::string &tag) {
|
||||
Popups::SetupPopup(strings[cfg.lang][Lang::UpdateTitle]);
|
||||
|
||||
if (ImGui::BeginPopupModal(strings[cfg.lang][Lang::UpdateTitle], nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
if (!*connection_status)
|
||||
ImGui::Text(strings[cfg.lang][Lang::UpdateNetworkError]);
|
||||
else if ((*connection_status) && (*available) && (!tag.empty()) && (!done)) {
|
||||
ImGui::Text(strings[cfg.lang][Lang::UpdateAvailable]);
|
||||
std::string text = strings[cfg.lang][Lang::UpdatePrompt] + tag + "?";
|
||||
ImGui::Text(text.c_str());
|
||||
}
|
||||
else if (done) {
|
||||
ImGui::Text(strings[cfg.lang][Lang::UpdateSuccess]);
|
||||
ImGui::Text(strings[cfg.lang][Lang::UpdateRestart]);
|
||||
}
|
||||
else
|
||||
ImGui::Text(strings[cfg.lang][Lang::UpdateNotAvailable]);
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::ButtonOK], ImVec2(120, 0))) {
|
||||
if (!done) {
|
||||
Net::GetLatestReleaseNRO(tag);
|
||||
|
||||
Result ret = 0;
|
||||
if (R_FAILED(ret = fsFsDeleteFile(fs, __application_path)))
|
||||
Log::Error("fsFsDeleteFile(%s) failed: 0x%x\n", __application_path, ret);
|
||||
|
||||
if (R_FAILED(ret = fsFsRenameFile(fs, "/switch/NX-Shell/NX-Shell_UPDATE.nro", __application_path)))
|
||||
Log::Error("fsFsRenameFile(update) failed: 0x%x\n", ret);
|
||||
|
||||
done = true;
|
||||
}
|
||||
else {
|
||||
ImGui::CloseCurrentPopup();
|
||||
*state = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((*connection_status) && (*available) && (!done)) {
|
||||
ImGui::SameLine(0.0f, 15.0f);
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::ButtonCancel], ImVec2(120, 0))) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
*state = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Popups::ExitPopup();
|
||||
}
|
||||
}
|
93
source/tabs/filebrowser.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include <cstdio>
|
||||
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_deko3d.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "tabs.h"
|
||||
#include "textures.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace Tabs {
|
||||
static const ImVec2 tex_size = ImVec2(25, 25);
|
||||
|
||||
void FileBrowser(WindowData &data) {
|
||||
if (ImGui::BeginTabItem("File Browser")) {
|
||||
// Display current working directory
|
||||
ImGui::TextColored(ImVec4(1.00f, 1.00f, 1.00f, 1.00f), cfg.cwd);
|
||||
|
||||
// Draw storage bar
|
||||
ImGui::ProgressBar(static_cast<float>(data.used_storage) / static_cast<float>(data.total_storage), ImVec2(1265.0f, 6.0f), "");
|
||||
ImGui::Dummy(ImVec2(0.0f, 1.0f)); // Spacing
|
||||
|
||||
ImGuiTableFlags tableFlags = ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter |
|
||||
ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_ScrollY;
|
||||
|
||||
if (ImGui::BeginTable("Directory List", 3, tableFlags)) {
|
||||
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("Filename");
|
||||
ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (u64 i = 0; i < data.entries.size(); i++) {
|
||||
ImGui::TableNextRow();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::PushID(i);
|
||||
if (ImGui::ImageButton(imgui::deko3d::makeTextureID(
|
||||
data.checked.at(i)? dkMakeTextureHandle(check_icon.image_id, check_icon.sampler_id) : dkMakeTextureHandle(uncheck_icon.image_id, uncheck_icon.sampler_id)),
|
||||
tex_size, ImVec2(0, 0), ImVec2(1, 1), 0)) {
|
||||
data.checked.at(i) = !data.checked.at(i);
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
FileType file_type = FS::GetFileType(data.entries[i].name);
|
||||
|
||||
if (data.entries[i].type == FsDirEntryType_Dir)
|
||||
ImGui::Image(imgui::deko3d::makeTextureID(dkMakeTextureHandle(folder_icon.image_id, folder_icon.sampler_id)), tex_size);
|
||||
else
|
||||
ImGui::Image(imgui::deko3d::makeTextureID(dkMakeTextureHandle(file_icons[file_type].image_id, file_icons[file_type].sampler_id)), tex_size);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Selectable(data.entries[i].name, false)) {
|
||||
if (data.entries[i].type == FsDirEntryType_Dir) {
|
||||
if (!strncmp(data.entries[i].name, "..", sizeof(data.entries[i].name))) {
|
||||
if (R_SUCCEEDED(FS::ChangeDirPrev(data.entries))) {
|
||||
// Make a copy before resizing our vector.
|
||||
if (data.checked_count > 1)
|
||||
data.checked_copy = data.checked;
|
||||
|
||||
data.checked.resize(data.entries.size());
|
||||
}
|
||||
}
|
||||
else if (R_SUCCEEDED(FS::ChangeDirNext(data.entries[i].name, data.entries))) {
|
||||
if ((data.checked_count > 1) && (data.checked_copy.empty()))
|
||||
data.checked_copy = data.checked;
|
||||
|
||||
data.checked.resize(data.entries.size());
|
||||
}
|
||||
|
||||
// Reset navigation ID -- TODO: Scroll to top
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGui::SetNavID(ImGui::GetID(data.entries[0].name, 0), g.NavLayer, 0, ImRect());
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (data.entries[i].file_size != 0) {
|
||||
char size[16];
|
||||
Utils::GetSizeString(size, static_cast<double>(data.entries[i].file_size));
|
||||
ImGui::Text(size);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
}
|
@ -5,9 +5,9 @@
|
||||
#include "language.h"
|
||||
#include "net.h"
|
||||
#include "popups.h"
|
||||
#include "windows.h"
|
||||
#include "tabs.h"
|
||||
|
||||
namespace Windows {
|
||||
namespace Tabs {
|
||||
static bool update_popup = false, network_status = false, update_available = false;
|
||||
static std::string tag_name = std::string();
|
||||
|
||||
@ -17,10 +17,8 @@ namespace Windows {
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
}
|
||||
|
||||
void SettingsWindow(void) {
|
||||
Windows::SetupWindow();
|
||||
|
||||
if (ImGui::Begin(strings[cfg.lang][Lang::SettingsTitle], nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) {
|
||||
void Settings(WindowData &data) {
|
||||
if (ImGui::BeginTabItem("Settings")) {
|
||||
if (ImGui::TreeNode(strings[cfg.lang][Lang::SettingsSortTitle])) {
|
||||
const char *sort_options[] = {
|
||||
strings[cfg.lang][Lang::SettingsSortNameAsc],
|
||||
@ -35,7 +33,7 @@ namespace Windows {
|
||||
for (int i = 0; i < max_sort; i++) {
|
||||
if (ImGui::RadioButton(sort_options[i], &cfg.sort, i)) {
|
||||
Config::Save(cfg);
|
||||
FS::GetDirList(cfg.cwd, item.entries);
|
||||
FS::GetDirList(cfg.cwd, data.entries);
|
||||
}
|
||||
|
||||
if (i != (max_sort - 1))
|
||||
@ -45,7 +43,7 @@ namespace Windows {
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
Windows::Separator();
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::TreeNode(strings[cfg.lang][Lang::SettingsLanguageTitle])) {
|
||||
const char *languages[] = {
|
||||
@ -77,7 +75,7 @@ namespace Windows {
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
Windows::Separator();
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::TreeNode(strings[cfg.lang][Lang::SettingsImageViewTitle])) {
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
@ -88,7 +86,7 @@ namespace Windows {
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
Windows::Separator();
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::TreeNode(strings[cfg.lang][Lang::SettingsDevOptsTitle])) {
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
@ -99,7 +97,7 @@ namespace Windows {
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
Windows::Separator();
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::TreeNode(strings[cfg.lang][Lang::SettingsAboutTitle])) {
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
@ -111,19 +109,21 @@ namespace Windows {
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
ImGui::Text("%s: Preetisketch", strings[cfg.lang][Lang::SettingsAboutBanner]);
|
||||
ImGui::Dummy(ImVec2(0.0f, 5.0f)); // Spacing
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::SettingsCheckForUpdates], ImVec2(250, 50))) {
|
||||
|
||||
if (ImGui::Button(strings[cfg.lang][Lang::SettingsCheckForUpdates], ImVec2(250, 50))) {
|
||||
tag_name = Net::GetLatestReleaseJSON();
|
||||
network_status = Net::GetNetworkStatus();
|
||||
update_available = Net::GetAvailableUpdate(tag_name);
|
||||
update_popup = true;
|
||||
}
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
if (update_popup)
|
||||
Popups::UpdatePopup(&update_popup, &network_status, &update_available, tag_name);
|
||||
|
||||
Windows::ExitWindow();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
// if (update_popup)
|
||||
// Popups::UpdatePopup(&update_popup, &network_status, &update_available, tag_name);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
// BMP
|
||||
#include <libnsbmp.h>
|
||||
@ -31,14 +32,16 @@
|
||||
#include <switch.h>
|
||||
|
||||
#include "fs.h"
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_deko3d.h"
|
||||
#include "log.h"
|
||||
#include "textures.h"
|
||||
|
||||
#define BYTES_PER_PIXEL 4
|
||||
#define MAX_IMAGE_BYTES (48 * 1024 * 1024)
|
||||
|
||||
Tex folder_icon, file_icons[5], check_icon, uncheck_icon;
|
||||
Tex folder_icon, file_icons[NUM_FILE_ICONS], check_icon, uncheck_icon;
|
||||
|
||||
namespace BMP {
|
||||
static void *bitmap_create(int width, int height, [[maybe_unused]] unsigned int state) {
|
||||
@ -107,8 +110,10 @@ namespace Textures {
|
||||
ImageTypeWEBP,
|
||||
ImageTypeOther
|
||||
} ImageType;
|
||||
|
||||
static u32 counter = 1;
|
||||
|
||||
static Result ReadFile(const char path[FS_MAX_PATH], unsigned char **buffer, s64 *size) {
|
||||
static Result ReadFile(const char path[FS_MAX_PATH], unsigned char **buffer, s64 &size) {
|
||||
Result ret = 0;
|
||||
FsFile file;
|
||||
|
||||
@ -117,23 +122,23 @@ namespace Textures {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (R_FAILED(ret = fsFileGetSize(&file, size))) {
|
||||
if (R_FAILED(ret = fsFileGetSize(&file, &size))) {
|
||||
Log::Error("fsFileGetSize(%s) failed: 0x%x\n", path, ret);
|
||||
fsFileClose(&file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*buffer = new unsigned char[*size];
|
||||
*buffer = new unsigned char[size];
|
||||
|
||||
u64 bytes_read = 0;
|
||||
if (R_FAILED(ret = fsFileRead(&file, 0, *buffer, static_cast<u64>(*size), FsReadOption_None, &bytes_read))) {
|
||||
if (R_FAILED(ret = fsFileRead(&file, 0, *buffer, static_cast<u64>(size), FsReadOption_None, &bytes_read))) {
|
||||
Log::Error("fsFileRead(%s) failed: 0x%x\n", path, ret);
|
||||
fsFileClose(&file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (bytes_read != static_cast<u64>(*size)) {
|
||||
Log::Error("bytes_read(%llu) does not match file size(%llu)\n", bytes_read, *size);
|
||||
if (bytes_read != static_cast<u64>(size)) {
|
||||
Log::Error("bytes_read(%llu) does not match file size(%llu)\n", bytes_read, size);
|
||||
fsFileClose(&file);
|
||||
return -1;
|
||||
}
|
||||
@ -142,26 +147,54 @@ namespace Textures {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool LoadImage(unsigned char *data, GLint format, Tex *texture, void (*free_func)(void *)) {
|
||||
// Create a OpenGL texture identifier
|
||||
glGenTextures(1, &texture->id);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
||||
|
||||
// Setup filtering parameters for display
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// Upload pixels into texture
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format, texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
if (*free_func)
|
||||
static bool LoadImage(unsigned char *data, DkImageFormat format, Tex &texture, void (*free_func)(void *)) {
|
||||
int size = texture.width * texture.height * BYTES_PER_PIXEL;
|
||||
texture.image_id = counter;
|
||||
|
||||
s_queue.waitIdle();
|
||||
|
||||
dk::ImageLayout layout;
|
||||
dk::ImageLayoutMaker{s_device}
|
||||
.setFlags(0)
|
||||
.setFormat(format)
|
||||
.setDimensions(texture.width, texture.height)
|
||||
.initialize(layout);
|
||||
|
||||
auto memBlock = dk::MemBlockMaker{s_device, imgui::deko3d::align(size, DK_MEMBLOCK_ALIGNMENT)}
|
||||
.setFlags(DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||
.create();
|
||||
|
||||
s_imageMemBlock = dk::MemBlockMaker{s_device, imgui::deko3d::align(layout.getSize(), DK_MEMBLOCK_ALIGNMENT)}
|
||||
.setFlags(DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image)
|
||||
.create();
|
||||
|
||||
std::memcpy(memBlock.getCpuAddr(), data, size);
|
||||
|
||||
dk::Image image;
|
||||
image.initialize(layout, s_imageMemBlock, 0);
|
||||
s_imageDescriptors[texture.image_id].initialize(image);
|
||||
|
||||
dk::ImageView imageView(image);
|
||||
|
||||
s_cmdBuf[0].copyBufferToImage({memBlock.getGpuAddr()}, imageView,
|
||||
{0, 0, 0, static_cast<std::uint32_t>(texture.width), static_cast<std::uint32_t>(texture.height), 1});
|
||||
|
||||
s_queue.submitCommands(s_cmdBuf[0].finishList());
|
||||
|
||||
s_samplerDescriptors[texture.sampler_id].initialize(dk::Sampler{}
|
||||
.setFilter(DkFilter_Linear, DkFilter_Linear)
|
||||
.setWrapMode(DkWrapMode_ClampToEdge, DkWrapMode_ClampToEdge, DkWrapMode_ClampToEdge));
|
||||
|
||||
s_queue.waitIdle();
|
||||
counter++;
|
||||
|
||||
if (*free_func)
|
||||
free_func(data);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadImageRomfs(const std::string &path, Tex *texture) {
|
||||
static bool LoadImageRomfs(const std::string &path, Tex &texture) {
|
||||
bool ret = false;
|
||||
png_image image;
|
||||
std::memset(&image, 0, (sizeof image));
|
||||
@ -173,9 +206,9 @@ namespace Textures {
|
||||
buffer = new png_byte[PNG_IMAGE_SIZE(image)];
|
||||
|
||||
if (buffer != nullptr && png_image_finish_read(&image, nullptr, buffer, 0, nullptr) != 0) {
|
||||
texture->width = image.width;
|
||||
texture->height = image.height;
|
||||
ret = Textures::LoadImage(buffer, GL_RGBA, texture, nullptr);
|
||||
texture.width = image.width;
|
||||
texture.height = image.height;
|
||||
ret = Textures::LoadImage(buffer, DkImageFormat_RGBA8_Unorm, texture, nullptr);
|
||||
delete[] buffer;
|
||||
png_image_free(&image);
|
||||
}
|
||||
@ -190,7 +223,7 @@ namespace Textures {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImageBMP(unsigned char **data, s64 *size, Tex *texture) {
|
||||
static bool LoadImageBMP(unsigned char **data, s64 &size, Tex &texture) {
|
||||
bmp_bitmap_callback_vt bitmap_callbacks = {
|
||||
BMP::bitmap_create,
|
||||
BMP::bitmap_destroy,
|
||||
@ -202,7 +235,7 @@ namespace Textures {
|
||||
bmp_image bmp;
|
||||
bmp_create(&bmp, &bitmap_callbacks);
|
||||
|
||||
code = bmp_analyse(&bmp, *size, *data);
|
||||
code = bmp_analyse(&bmp, size, *data);
|
||||
if (code != BMP_OK) {
|
||||
bmp_finalise(&bmp);
|
||||
return false;
|
||||
@ -222,14 +255,14 @@ namespace Textures {
|
||||
}
|
||||
}
|
||||
|
||||
texture->width = bmp.width;
|
||||
texture->height = bmp.height;
|
||||
bool ret = LoadImage(static_cast<unsigned char *>(bmp.bitmap), GL_RGBA, texture, nullptr);
|
||||
texture.width = bmp.width;
|
||||
texture.height = bmp.height;
|
||||
bool ret = LoadImage(static_cast<unsigned char *>(bmp.bitmap), DkImageFormat_RGBA8_Unorm, texture, nullptr);
|
||||
bmp_finalise(&bmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImageGIF(unsigned char **data, s64 *size, std::vector<Tex> &textures) {
|
||||
static bool LoadImageGIF(unsigned char **data, s64 &size, std::vector<Tex> &textures) {
|
||||
gif_bitmap_callback_vt bitmap_callbacks = {
|
||||
GIF::bitmap_create,
|
||||
GIF::bitmap_destroy,
|
||||
@ -245,7 +278,7 @@ namespace Textures {
|
||||
gif_create(&gif, &bitmap_callbacks);
|
||||
|
||||
do {
|
||||
code = gif_initialise(&gif, *size, *data);
|
||||
code = gif_initialise(&gif, size, *data);
|
||||
if (code != GIF_OK && code != GIF_WORKING) {
|
||||
Log::Error("gif_initialise failed: %d\n", code);
|
||||
gif_finalise(&gif);
|
||||
@ -268,7 +301,7 @@ namespace Textures {
|
||||
textures[i].width = gif.width;
|
||||
textures[i].height = gif.height;
|
||||
textures[i].delay = gif.frames->frame_delay;
|
||||
ret = Textures::LoadImage(static_cast<unsigned char *>(gif.frame_image), GL_RGBA, &textures[i], nullptr);
|
||||
ret = Textures::LoadImage(static_cast<unsigned char *>(gif.frame_image), DkImageFormat_RGBA8_Unorm, textures[i], nullptr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -280,46 +313,46 @@ namespace Textures {
|
||||
|
||||
textures[0].width = gif.width;
|
||||
textures[0].height = gif.height;
|
||||
ret = Textures::LoadImage(static_cast<unsigned char *>(gif.frame_image), GL_RGBA, &textures[0], nullptr);
|
||||
ret = Textures::LoadImage(static_cast<unsigned char *>(gif.frame_image), DkImageFormat_RGBA8_Unorm, textures[0], nullptr);
|
||||
}
|
||||
|
||||
gif_finalise(&gif);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImageJPEG(unsigned char **data, s64 *size, Tex *texture) {
|
||||
static bool LoadImageJPEG(unsigned char **data, s64 &size, Tex &texture) {
|
||||
tjhandle jpeg = tjInitDecompress();
|
||||
int jpegsubsamp = 0;
|
||||
tjDecompressHeader2(jpeg, *data, *size, &texture->width, &texture->height, &jpegsubsamp);
|
||||
unsigned char *buffer = new unsigned char[texture->width * texture->height * 3];
|
||||
tjDecompress2(jpeg, *data, *size, buffer, texture->width, 0, texture->height, TJPF_RGB, TJFLAG_FASTDCT);
|
||||
bool ret = LoadImage(buffer, GL_RGB, texture, nullptr);
|
||||
tjDecompressHeader2(jpeg, *data, size, &texture.width, &texture.height, &jpegsubsamp);
|
||||
unsigned char *buffer = new unsigned char[texture.width * texture.height * 4];
|
||||
tjDecompress2(jpeg, *data, size, buffer, texture.width, 0, texture.height, TJPF_RGBA, TJFLAG_FASTDCT);
|
||||
bool ret = LoadImage(buffer, DkImageFormat_RGBA8_Unorm, texture, nullptr);
|
||||
tjDestroy(jpeg);
|
||||
delete[] buffer;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImageOther(unsigned char **data, s64 *size, Tex *texture) {
|
||||
unsigned char *image = stbi_load_from_memory(*data, *size, &texture->width, &texture->height, nullptr, STBI_rgb_alpha);
|
||||
bool ret = Textures::LoadImage(image, GL_RGBA, texture, nullptr);
|
||||
static bool LoadImageOther(unsigned char **data, s64 &size, Tex &texture) {
|
||||
unsigned char *image = stbi_load_from_memory(*data, size, &texture.width, &texture.height, nullptr, STBI_rgb_alpha);
|
||||
bool ret = Textures::LoadImage(image, DkImageFormat_RGBA8_Unorm, texture, nullptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImagePNG(unsigned char **data, s64 *size, Tex *texture) {
|
||||
static bool LoadImagePNG(unsigned char **data, s64 &size, Tex &texture) {
|
||||
bool ret = false;
|
||||
png_image image;
|
||||
std::memset(&image, 0, (sizeof image));
|
||||
image.version = PNG_IMAGE_VERSION;
|
||||
|
||||
if (png_image_begin_read_from_memory(&image, *data, *size) != 0) {
|
||||
if (png_image_begin_read_from_memory(&image, *data, size) != 0) {
|
||||
png_bytep buffer;
|
||||
image.format = PNG_FORMAT_RGBA;
|
||||
buffer = new png_byte[PNG_IMAGE_SIZE(image)];
|
||||
|
||||
if (buffer != nullptr && png_image_finish_read(&image, nullptr, buffer, 0, nullptr) != 0) {
|
||||
texture->width = image.width;
|
||||
texture->height = image.height;
|
||||
ret = Textures::LoadImage(buffer, GL_RGBA, texture, nullptr);
|
||||
texture.width = image.width;
|
||||
texture.height = image.height;
|
||||
ret = Textures::LoadImage(buffer, DkImageFormat_RGBA8_Unorm, texture, nullptr);
|
||||
delete[] buffer;
|
||||
png_image_free(&image);
|
||||
}
|
||||
@ -334,9 +367,9 @@ namespace Textures {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImageWEBP(unsigned char **data, s64 *size, Tex *texture) {
|
||||
*data = WebPDecodeRGBA(*data, *size, &texture->width, &texture->height);
|
||||
bool ret = Textures::LoadImage(*data, GL_RGBA, texture, nullptr);
|
||||
static bool LoadImageWEBP(unsigned char **data, s64 &size, Tex &texture) {
|
||||
*data = WebPDecodeRGBA(*data, size, &texture.width, &texture.height);
|
||||
bool ret = Textures::LoadImage(*data, DkImageFormat_RGBA8_Unorm, texture, nullptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -362,7 +395,7 @@ namespace Textures {
|
||||
unsigned char *data = nullptr;
|
||||
s64 size = 0;
|
||||
|
||||
if (R_FAILED(Textures::ReadFile(path, &data, &size))) {
|
||||
if (R_FAILED(Textures::ReadFile(path, &data, size))) {
|
||||
delete[] data;
|
||||
return ret;
|
||||
}
|
||||
@ -373,27 +406,27 @@ namespace Textures {
|
||||
ImageType type = GetImageType(path);
|
||||
switch(type) {
|
||||
case ImageTypeBMP:
|
||||
ret = Textures::LoadImageBMP(&data, &size, &textures[0]);
|
||||
ret = Textures::LoadImageBMP(&data, size, textures[0]);
|
||||
break;
|
||||
|
||||
case ImageTypeGIF:
|
||||
ret = Textures::LoadImageGIF(&data, &size, textures);
|
||||
ret = Textures::LoadImageGIF(&data, size, textures);
|
||||
break;
|
||||
|
||||
case ImageTypeJPEG:
|
||||
ret = Textures::LoadImageJPEG(&data, &size, &textures[0]);
|
||||
ret = Textures::LoadImageJPEG(&data, size, textures[0]);
|
||||
break;
|
||||
|
||||
case ImageTypePNG:
|
||||
ret = Textures::LoadImagePNG(&data, &size, &textures[0]);
|
||||
ret = Textures::LoadImagePNG(&data, size, textures[0]);
|
||||
break;
|
||||
|
||||
case ImageTypeWEBP:
|
||||
ret = Textures::LoadImageWEBP(&data, &size, &textures[0]);
|
||||
ret = Textures::LoadImageWEBP(&data, size, textures[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = Textures::LoadImageOther(&data, &size, &textures[0]);
|
||||
ret = Textures::LoadImageOther(&data, size, textures[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -402,41 +435,38 @@ namespace Textures {
|
||||
}
|
||||
|
||||
void Init(void) {
|
||||
bool image_ret = Textures::LoadImageRomfs("romfs:/folder.png", &folder_icon);
|
||||
const std::string paths[NUM_FILE_ICONS] {
|
||||
"romfs:/file.png",
|
||||
"romfs:/archive.png",
|
||||
"romfs:/image.png",
|
||||
"romfs:/text.png"
|
||||
};
|
||||
|
||||
bool image_ret = Textures::LoadImageRomfs("romfs:/folder.png", folder_icon);
|
||||
IM_ASSERT(image_ret);
|
||||
|
||||
image_ret = Textures::LoadImageRomfs("romfs:/check.png", &check_icon);
|
||||
image_ret = Textures::LoadImageRomfs("romfs:/check.png", check_icon);
|
||||
IM_ASSERT(image_ret);
|
||||
|
||||
image_ret = Textures::LoadImageRomfs("romfs:/uncheck.png", &uncheck_icon);
|
||||
IM_ASSERT(image_ret);
|
||||
|
||||
image_ret = Textures::LoadImageRomfs("romfs:/file.png", &file_icons[FileTypeNone]);
|
||||
IM_ASSERT(image_ret);
|
||||
|
||||
image_ret = Textures::LoadImageRomfs("romfs:/archive.png", &file_icons[FileTypeArchive]);
|
||||
IM_ASSERT(image_ret);
|
||||
|
||||
image_ret = Textures::LoadImageRomfs("romfs:/audio.png", &file_icons[FileTypeAudio]);
|
||||
IM_ASSERT(image_ret);
|
||||
|
||||
image_ret = Textures::LoadImageRomfs("romfs:/image.png", &file_icons[FileTypeImage]);
|
||||
IM_ASSERT(image_ret);
|
||||
|
||||
image_ret = Textures::LoadImageRomfs("romfs:/text.png", &file_icons[FileTypeText]);
|
||||
image_ret = Textures::LoadImageRomfs("romfs:/uncheck.png", uncheck_icon);
|
||||
IM_ASSERT(image_ret);
|
||||
|
||||
for (int i = 0; i < NUM_FILE_ICONS; i++) {
|
||||
bool ret = Textures::LoadImageRomfs(paths[i], file_icons[i]);
|
||||
IM_ASSERT(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void Free(Tex *texture) {
|
||||
glDeleteTextures(1, &texture->id);
|
||||
//glDeleteTextures(1, &texture->id);
|
||||
}
|
||||
|
||||
void Exit(void) {
|
||||
for (int i = 0; i < NUM_FILE_ICONS; i++)
|
||||
glDeleteTextures(1, &file_icons[i].id);
|
||||
// for (int i = 0; i < NUM_FILE_ICONS; i++)
|
||||
// glDeleteTextures(1, &file_icons[i].id);
|
||||
|
||||
glDeleteTextures(1, &uncheck_icon.id);
|
||||
glDeleteTextures(1, &check_icon.id);
|
||||
glDeleteTextures(1, &folder_icon.id);
|
||||
// glDeleteTextures(1, &uncheck_icon.id);
|
||||
// glDeleteTextures(1, &check_icon.id);
|
||||
// glDeleteTextures(1, &folder_icon.id);
|
||||
}
|
||||
}
|
||||
|
17
source/window.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include "imgui.h"
|
||||
#include "tabs.h"
|
||||
#include "windows.h"
|
||||
|
||||
namespace Windows {
|
||||
void MainWindow(WindowData &data) {
|
||||
Windows::SetupWindow();
|
||||
if (ImGui::Begin("NX-Shell", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) {
|
||||
if (ImGui::BeginTabBar("NX-Shell-tabs")) {
|
||||
Tabs::FileBrowser(data);
|
||||
Tabs::Settings(data);
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
}
|
||||
Windows::ExitWindow();
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "log.h"
|
||||
#include "windows.h"
|
||||
|
||||
namespace Windows {
|
||||
void FileBrowserWindow(bool *focus, bool *first_item) {
|
||||
Windows::SetupWindow();
|
||||
|
||||
if (ImGui::Begin("NX-Shell", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) {
|
||||
// Initially set default focus to next window (FS::DirList)
|
||||
if (!*focus) {
|
||||
ImGui::SetNextWindowFocus();
|
||||
*focus = true;
|
||||
}
|
||||
|
||||
// Display current working directory
|
||||
ImGui::TextColored(ImVec4(1.00f, 1.00f, 1.00f, 1.00f), cfg.cwd);
|
||||
|
||||
// Draw storage bar
|
||||
ImGui::Dummy(ImVec2(0.0f, 1.0f)); // Spacing
|
||||
ImGui::ProgressBar(static_cast<float>(item.used_storage) / static_cast<float>(item.total_storage), ImVec2(1265.0f, 6.0f), "");
|
||||
ImGui::Dummy(ImVec2(0.0f, 2.0f)); // Spacing
|
||||
|
||||
if (item.entries.size() != 0) {
|
||||
for (long unsigned int i = 0; i < item.entries.size(); i++) {
|
||||
std::string filename = item.entries[i].name;
|
||||
|
||||
if ((item.checked.at(i)) && (!item.checked_cwd.compare(cfg.cwd)))
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(check_icon.id), ImVec2(check_icon.width, check_icon.height));
|
||||
else
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(uncheck_icon.id), ImVec2(uncheck_icon.width, uncheck_icon.height));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
FileType file_type = FS::GetFileType(filename);
|
||||
if (item.entries[i].type == FsDirEntryType_Dir)
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(folder_icon.id), ImVec2(folder_icon.width, folder_icon.height));
|
||||
else
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(file_icons[file_type].id), ImVec2(file_icons[0].width, file_icons[0].height));
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 4);
|
||||
if (ImGui::Selectable(filename.c_str())) {
|
||||
char path[FS_MAX_PATH + 1];
|
||||
|
||||
switch(file_type) {
|
||||
case FileTypeArchive:
|
||||
item.state = MENU_STATE_ARCHIVEEXTRACT;
|
||||
break;
|
||||
|
||||
case FileTypeImage:
|
||||
if ((std::snprintf(path, FS_MAX_PATH, "%s/%s", cfg.cwd, item.entries[item.selected].name)) > 0) {
|
||||
Textures::LoadImageFile(path, item.textures);
|
||||
item.state = MENU_STATE_IMAGEVIEWER;
|
||||
}
|
||||
break;
|
||||
|
||||
case FileTypeText:
|
||||
if ((std::snprintf(path, FS_MAX_PATH, "%s/%s", cfg.cwd, item.entries[item.selected].name)) > 0) {
|
||||
Log::Exit();
|
||||
|
||||
FsFile file;
|
||||
Result ret = 0;
|
||||
if (R_FAILED(ret = fsFsOpenFile(fs, path, FsOpenMode_Read, &file)))
|
||||
Log::Error("fsFsOpenFile(%s) failed: 0x%x\n", path, ret);
|
||||
|
||||
s64 size = 0;
|
||||
if (R_FAILED(ret = fsFileGetSize(&file, &size))) {
|
||||
Log::Error("fsFileGetSize(%s) failed: 0x%x\n", path, ret);
|
||||
fsFileClose(&file);
|
||||
}
|
||||
|
||||
text_reader.buf = new char[size];
|
||||
|
||||
u64 bytes_read = 0;
|
||||
if (R_FAILED(ret = fsFileRead(&file, 0, text_reader.buf, static_cast<u64>(size), FsReadOption_None, &bytes_read))) {
|
||||
Log::Error("fsFileRead(%s) failed: 0x%x\n", path, ret);
|
||||
fsFileClose(&file);
|
||||
}
|
||||
|
||||
fsFileClose(&file);
|
||||
Log::Init();
|
||||
text_reader.buf_size = bytes_read;
|
||||
item.state = MENU_STATE_TEXTREADER;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*first_item) {
|
||||
ImGui::SetFocusID(ImGui::GetID((item.entries[0].name)), ImGui::GetCurrentWindow());
|
||||
ImGuiContext& g = *ImGui::GetCurrentContext();
|
||||
g.NavDisableHighlight = false;
|
||||
*first_item = false;
|
||||
}
|
||||
|
||||
if (!ImGui::IsAnyItemFocused() && item.state == MENU_STATE_FILEBROWSER)
|
||||
GImGui->NavId = GImGui->CurrentWindow->DC.LastItemId;
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
item.selected = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
ImGui::Text("No file entries");
|
||||
}
|
||||
|
||||
Windows::ExitWindow();
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
#include "config.h"
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "windows.h"
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include "imgui_internal.h"
|
||||
|
||||
namespace Windows {
|
||||
void ImageWindow(void) {
|
||||
Windows::SetupWindow();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
ImGuiWindowFlags_ filename_flag = !cfg.image_filename? ImGuiWindowFlags_NoTitleBar : ImGuiWindowFlags_None;
|
||||
|
||||
if (ImGui::Begin(item.entries[item.selected].name, nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | filename_flag)) {
|
||||
if (((item.textures[0].width * item.zoom_factor) <= 1280) && ((item.textures[0].height * item.zoom_factor) <= 720))
|
||||
ImGui::SetCursorPos((ImGui::GetWindowSize() - ImVec2((item.textures[0].width * item.zoom_factor), (item.textures[0].height * item.zoom_factor))) * 0.5f);
|
||||
|
||||
if (item.textures.size() > 1) {
|
||||
svcSleepThread(item.textures[item.frame_count].delay * 10000000);
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(item.textures[item.frame_count].id), (ImVec2((item.textures[item.frame_count].width * item.zoom_factor),
|
||||
(item.textures[item.frame_count].height * item.zoom_factor))));
|
||||
item.frame_count++;
|
||||
|
||||
// Reset frame counter
|
||||
if (item.frame_count == item.textures.size() - 1)
|
||||
item.frame_count = 0;
|
||||
}
|
||||
else
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(item.textures[0].id), ImVec2((item.textures[0].width * item.zoom_factor), (item.textures[0].height * item.zoom_factor)));
|
||||
}
|
||||
|
||||
Windows::ExitWindow();
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#include "gui.h"
|
||||
#include "imgui.h"
|
||||
#include "windows.h"
|
||||
|
||||
TextReader text_reader;
|
||||
|
||||
namespace Windows {
|
||||
void TextReaderWindow(void) {
|
||||
Windows::SetupWindow();
|
||||
|
||||
if (ImGui::Begin(item.entries[item.selected].name, nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) {
|
||||
ImGui::SetNextWindowFocus();
|
||||
ImGui::InputTextMultiline(item.entries[item.selected].name, text_reader.buf, text_reader.buf_size, ImVec2(1270.0f, 660.0f));
|
||||
}
|
||||
|
||||
Windows::ExitWindow();
|
||||
}
|
||||
}
|