blob: c1dbc15dfadae14346ae756cef436665ed3d16bd [file] [log] [blame]
Austin Schuh1e69f942020-11-14 15:06:14 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#pragma once
9
10#include <functional>
11
12#include <imgui.h>
13
14extern "C" struct GLFWwindow;
15
16namespace wpi::gui {
17
18/**
19 * Creates GUI context. Must be called prior to calling any other functions.
20 */
21void CreateContext();
22
23/**
24 * Destroys GUI context.
25 */
26void DestroyContext();
27
28/**
29 * Initializes the GUI.
30 *
31 * @param title main application window title
32 * @param width main application window width
33 * @param height main application window height
34 */
35bool Initialize(const char* title, int width, int height);
36
37/**
38 * Runs main GUI loop. On some OS'es this must be called from the main thread.
39 * Does not return until Exit() is called.
40 */
41void Main();
42
43/**
44 * Exits main GUI loop when current loop iteration finishes.
45 * Safe to call from any thread, including from within main GUI loop.
46 */
47void Exit();
48
49/**
50 * Adds initializer to GUI. The passed function is called once, immediately
51 * after the GUI (both GLFW and Dear ImGui) are initialized in Initialize().
52 * To have any effect, must be called prior to Initialize().
53 *
54 * @param initialize initialization function
55 */
56void AddInit(std::function<void()> initialize);
57
58/**
59 * Adds window scaler function. The passed function is called once during
60 * Initialize() if the window scale is not 1.0. To have any effect, must
61 * be called prior to Initialize().
62 *
63 * @param windowScaler window scaler function
64 */
65void AddWindowScaler(std::function<void(float scale)> windowScaler);
66
67/**
68 * Adds per-frame executor to GUI. The passed function is called on each
69 * Dear ImGui frame prior to any of the late execute functions.
70 *
71 * @param execute frame execution function
72 */
73void AddEarlyExecute(std::function<void()> execute);
74
75/**
76 * Adds per-frame executor to GUI. The passed function is called on each
77 * Dear ImGui frame after all of the early execute functions.
78 *
79 * @param execute frame execution function
80 */
81void AddLateExecute(std::function<void()> execute);
82
83/**
84 * Gets GLFW window handle.
85 */
86GLFWwindow* GetSystemWindow();
87
88/**
89 * Adds a font to the GUI. The passed function is called during
90 * initialization as many times as necessary to create a range of sizes.
91 *
92 * @param name font name
93 * @param makeFont font creation / loader function
94 * @return Font index for later use with GetFont()
95 */
96int AddFont(
97 const char* name,
98 std::function<ImFont*(ImGuiIO& io, float size, const ImFontConfig* cfg)>
99 makeFont);
100
101/**
102 * Gets a font added with AddFont() with the appropriate font size for
103 * the current scaling of the GUI.
104 *
105 * @param font font index returned by AddFont()
106 * @return Font pointer
107 */
108ImFont* GetFont(int font);
109
110enum Style { kStyleClassic = 0, kStyleDark, kStyleLight };
111
112/**
113 * Sets the ImGui style. Using this function makes this setting persistent.
114 *
115 * @param style Style
116 */
117void SetStyle(Style style);
118
119/**
120 * Sets the clear (background) color.
121 *
122 * @param color Color
123 */
124void SetClearColor(ImVec4 color);
125
126/**
127 * Emits a View menu (e.g. for a main menu bar) that allows setting of
128 * style and zoom. Internally starts with ImGui::BeginMenu("View").
129 */
130void EmitViewMenu();
131
132/**
133 * Pixel formats for texture pixel data.
134 */
135enum PixelFormat { kPixelRGBA, kPixelBGRA };
136
137/**
138 * Creates a texture from pixel data.
139 *
140 * @param format pixel format
141 * @param width image width
142 * @param height image height
143 * @param data pixel data
144 * @return Texture
145 */
146ImTextureID CreateTexture(PixelFormat format, int width, int height,
147 const unsigned char* data);
148
149/**
150 * Updates a texture from pixel data.
151 * The passed-in width and height must match the width and height of the
152 * texture.
153 *
154 * @param texture texture
155 * @param format pixel format
156 * @param width texture width
157 * @param height texture height
158 * @param data pixel data
159 */
160void UpdateTexture(ImTextureID texture, PixelFormat format, int width,
161 int height, const unsigned char* data);
162
163/**
164 * Updates a texture from image data.
165 * The pixel format of the texture must be RGBA. The passed-in width and
166 * height must match the width and height of the texture. If the width and
167 * height of the image differ from the passed-in width and height, a new
168 * texture is created (note this may be inefficient).
169 *
170 * @param texture texture (pointer, may be updated)
171 * @param width texture width
172 * @param height texture height
173 * @param data image data
174 * @param len image data length
175 *
176 * @return True on success, false on failure.
177 */
178bool UpdateTextureFromImage(ImTextureID* texture, int width, int height,
179 const unsigned char* data, int len);
180
181/**
182 * Creates a texture from an image file.
183 *
184 * @param filename filename
185 * @param out_texture texture (output)
186 * @param out_width image width (output)
187 * @param out_height image height (output)
188 * @return True on success, false on failure.
189 */
190bool CreateTextureFromFile(const char* filename, ImTextureID* out_texture,
191 int* out_width, int* out_height);
192
193/**
194 * Creates a texture from image data.
195 *
196 * @param data image data
197 * @param len image data length
198 * @param out_texture texture (output)
199 * @param out_width image width (output)
200 * @param out_height image height (output)
201 * @return True on success, false on failure.
202 */
203bool CreateTextureFromImage(const unsigned char* data, int len,
204 ImTextureID* out_texture, int* out_width,
205 int* out_height);
206
207/**
208 * Deletes a texture.
209 *
210 * @param texture texture
211 */
212void DeleteTexture(ImTextureID texture);
213
214/**
215 * RAII wrapper around ImTextureID. Also keeps track of width, height, and
216 * pixel format.
217 */
218class Texture {
219 public:
220 Texture() = default;
221
222 /**
223 * Constructs a texture from pixel data.
224 *
225 * @param format pixel format
226 * @param width image width
227 * @param height image height
228 * @param data pixel data
229 */
230 Texture(PixelFormat format, int width, int height, const unsigned char* data)
231 : m_format{format}, m_width{width}, m_height{height} {
232 m_texture = CreateTexture(format, width, height, data);
233 }
234
235 Texture(const Texture&) = delete;
236 Texture(Texture&& oth)
237 : m_texture{oth.m_texture},
238 m_format{oth.m_format},
239 m_width{oth.m_width},
240 m_height{oth.m_height} {
241 oth.m_texture = 0;
242 }
243
244 Texture& operator=(const Texture&) = delete;
245 Texture& operator=(Texture&& oth) {
246 if (m_texture) DeleteTexture(m_texture);
247 m_texture = oth.m_texture;
248 oth.m_texture = 0;
249 m_format = oth.m_format;
250 m_width = oth.m_width;
251 m_height = oth.m_height;
252 return *this;
253 }
254
255 ~Texture() {
256 if (m_texture) DeleteTexture(m_texture);
257 }
258
259 /**
260 * Evaluates to true if the texture is valid.
261 */
262 explicit operator bool() const { return m_texture; }
263
264 /**
265 * Implicit conversion to ImTextureID.
266 */
267 operator ImTextureID() const { return m_texture; }
268
269 /**
270 * Gets the texture pixel format.
271 *
272 * @return pixel format
273 */
274 PixelFormat GetFormat() const { return m_format; }
275
276 /**
277 * Gets the texture width.
278 *
279 * @return width
280 */
281 int GetWidth() const { return m_width; }
282
283 /**
284 * Gets the texture height.
285 *
286 * @return height
287 */
288 int GetHeight() const { return m_height; }
289
290 /**
291 * Updates the texture from pixel data.
292 * The image data size and format is assumed to match that of the texture.
293 *
294 * @param format pixel format
295 * @param data pixel data
296 */
297 void Update(const unsigned char* data) {
298 UpdateTexture(m_texture, m_format, m_width, m_height, data);
299 }
300
301 /**
302 * Updates the texture from image data.
303 * The pixel format of the texture must be RGBA. If the width and height of
304 * the image differ from the texture width and height, a new texture is
305 * created (note this may be inefficient).
306 *
307 * @param data image data
308 * @param len image data length
309 *
310 * @return True on success, false on failure.
311 */
312 bool UpdateFromImage(const unsigned char* data, int len) {
313 return UpdateTextureFromImage(&m_texture, m_width, m_height, data, len);
314 }
315
316 /**
317 * Creates a texture by loading an image file.
318 *
319 * @param filename filename
320 *
321 * @return Texture, or invalid (empty) texture on failure.
322 */
323 static Texture CreateFromFile(const char* filename) {
324 Texture texture;
325 if (!CreateTextureFromFile(filename, &texture.m_texture, &texture.m_width,
326 &texture.m_height))
327 return {};
328 return texture;
329 }
330
331 /**
332 * Creates a texture from image data.
333 *
334 * @param data image data
335 * @param len image data length
336 *
337 * @return Texture, or invalid (empty) texture on failure.
338 */
339 static Texture CreateFromImage(const unsigned char* data, int len) {
340 Texture texture;
341 if (!CreateTextureFromImage(data, len, &texture.m_texture, &texture.m_width,
342 &texture.m_height))
343 return {};
344 return texture;
345 }
346
347 private:
348 ImTextureID m_texture = nullptr;
349 PixelFormat m_format = kPixelRGBA;
350 int m_width = 0;
351 int m_height = 0;
352};
353
354/**
355 * Get square of distance between two ImVec2's.
356 *
357 * @param a first ImVec
358 * @param b second ImVec
359 *
360 * @return Distance^2 between a and b.
361 */
362inline float GetDistSquared(const ImVec2& a, const ImVec2& b) {
363 float deltaX = b.x - a.x;
364 float deltaY = b.y - a.y;
365 return deltaX * deltaX + deltaY * deltaY;
366}
367
368/**
369 * Maximize fit in "window" while preserving aspect ratio. Min and max
370 * passed-in values are modified such that the object maximally fits.
371 *
372 * @param min upper left corner of window (modified to fit)
373 * @param max lower right corner of window (modified to fit)
374 * @param width width of object to fit
375 * @param height height of object to fit
376 */
377void MaxFit(ImVec2* min, ImVec2* max, float width, float height);
378
379} // namespace wpi::gui