| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2000-2022 Inria | ||
| 3 | * All rights reserved. | ||
| 4 | * | ||
| 5 | * Redistribution and use in source and binary forms, with or without | ||
| 6 | * modification, are permitted provided that the following conditions are met: | ||
| 7 | * | ||
| 8 | * * Redistributions of source code must retain the above copyright notice, | ||
| 9 | * this list of conditions and the following disclaimer. | ||
| 10 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
| 11 | * this list of conditions and the following disclaimer in the documentation | ||
| 12 | * and/or other materials provided with the distribution. | ||
| 13 | * * Neither the name of the ALICE Project-Team nor the names of its | ||
| 14 | * contributors may be used to endorse or promote products derived from this | ||
| 15 | * software without specific prior written permission. | ||
| 16 | * | ||
| 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
| 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
| 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
| 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
| 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
| 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
| 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 27 | * POSSIBILITY OF SUCH DAMAGE. | ||
| 28 | * | ||
| 29 | * Contact: Bruno Levy | ||
| 30 | * | ||
| 31 | * https://www.inria.fr/fr/bruno-levy | ||
| 32 | * | ||
| 33 | * Inria, | ||
| 34 | * Domaine de Voluceau, | ||
| 35 | * 78150 Le Chesnay - Rocquencourt | ||
| 36 | * FRANCE | ||
| 37 | * | ||
| 38 | */ | ||
| 39 | |||
| 40 | #include <geogram_gfx/gui/command.h> | ||
| 41 | #include <geogram_gfx/imgui_ext/imgui_ext.h> | ||
| 42 | #include <geogram_gfx/imgui_ext/icon_font.h> | ||
| 43 | |||
| 44 | namespace { | ||
| 45 | /** | ||
| 46 | * \brief Removes the underscores from a string and | ||
| 47 | * replaces them with spaces. | ||
| 48 | * \details Utility for the prototype parser used by | ||
| 49 | * Command. | ||
| 50 | * \param[in] s a const reference to the input string | ||
| 51 | * \return a copy of \p s with underscores replaced with | ||
| 52 | * spaces | ||
| 53 | */ | ||
| 54 | ✗ | std::string remove_underscores(const std::string& s) { | |
| 55 | std::string result = s; | ||
| 56 | ✗ | for(GEO::index_t i=0; i<result.size(); ++i) { | |
| 57 | ✗ | if(result[i] == '_') { | |
| 58 | ✗ | result[i] = ' '; | |
| 59 | } | ||
| 60 | } | ||
| 61 | ✗ | return result; | |
| 62 | } | ||
| 63 | |||
| 64 | |||
| 65 | |||
| 66 | /** | ||
| 67 | * \brief Removes leading and trailing spaces from | ||
| 68 | * a string. | ||
| 69 | * \details Utility for the prototype parser used by | ||
| 70 | * Command. | ||
| 71 | * \param[in,out] line the line from which spaces should | ||
| 72 | * be trimmed. | ||
| 73 | */ | ||
| 74 | ✗ | void trim_spaces(std::string& line) { | |
| 75 | size_t i=0; | ||
| 76 | ✗ | for(i=0; i<line.length(); ++i) { | |
| 77 | ✗ | if(line[i] != ' ') { | |
| 78 | break; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | size_t j=line.length(); | ||
| 82 | ✗ | for(j=line.length(); j>0; --j) { | |
| 83 | ✗ | if(line[j-1] != ' ') { | |
| 84 | break; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | ✗ | if(j>i) { | |
| 88 | ✗ | line = line.substr(i, j-i); | |
| 89 | } else { | ||
| 90 | line = ""; | ||
| 91 | } | ||
| 92 | ✗ | } | |
| 93 | } | ||
| 94 | |||
| 95 | namespace GEO { | ||
| 96 | |||
| 97 | /*****************************************************************/ | ||
| 98 | |||
| 99 | ✗ | CommandInvoker::CommandInvoker() { | |
| 100 | ✗ | } | |
| 101 | |||
| 102 | ✗ | CommandInvoker::~CommandInvoker() { | |
| 103 | ✗ | } | |
| 104 | |||
| 105 | /*****************************************************************/ | ||
| 106 | |||
| 107 | ✗ | void Command::flush_queue() { | |
| 108 | ✗ | if(queued_ != nullptr) { | |
| 109 | // Steal the queued command to avoid | ||
| 110 | // infinite recursion. | ||
| 111 | /* | ||
| 112 | SmartPointer<Command> queued = queued_; | ||
| 113 | queued_ = nullptr; | ||
| 114 | queued->apply(); | ||
| 115 | *(queued->is_visible_ptr()) = false; | ||
| 116 | */ | ||
| 117 | |||
| 118 | ✗ | latest_ = queued_; | |
| 119 | queued_ = nullptr; | ||
| 120 | ✗ | latest_->apply(); | |
| 121 | ✗ | *(latest_->is_visible_ptr()) = false; | |
| 122 | } | ||
| 123 | ✗ | } | |
| 124 | |||
| 125 | ✗ | void Command::replay_latest() { | |
| 126 | ✗ | if(!latest_.is_null()) { | |
| 127 | ✗ | latest_->apply(); | |
| 128 | } | ||
| 129 | ✗ | } | |
| 130 | |||
| 131 | ✗ | Command::~Command() { | |
| 132 | ✗ | } | |
| 133 | |||
| 134 | ✗ | Command::Command(const std::string& prototype_in) : visible_(false) { | |
| 135 | |||
| 136 | // If there is no brace, then protype only has function | ||
| 137 | // name, and then the invoker will construct the arguments | ||
| 138 | // with names arg1, arg2 ... | ||
| 139 | ✗ | auto_create_args_ = | |
| 140 | ✗ | (prototype_in.find('(') == std::string::npos); | |
| 141 | |||
| 142 | ✗ | if(auto_create_args_) { | |
| 143 | ✗ | name_ = prototype_in; | |
| 144 | ✗ | if(name_ == "") { | |
| 145 | name_ = "command"; | ||
| 146 | } | ||
| 147 | help_ = "Hay You Programmer ! No prototype was specified, \n" | ||
| 148 | "see Command::make_current() documentation\n" | ||
| 149 | "in geogram_gfx/glup_viewer/command.h\n" | ||
| 150 | ✗ | "to specify parameter names (and tooltips)"; | |
| 151 | ✗ | return; | |
| 152 | } | ||
| 153 | |||
| 154 | // Parsing the prototype... | ||
| 155 | |||
| 156 | std::string prototype = prototype_in; | ||
| 157 | |||
| 158 | // Transform carriage returns into spaces | ||
| 159 | { | ||
| 160 | ✗ | for(index_t i=0; i<prototype.size(); ++i) { | |
| 161 | ✗ | if(prototype[i] == '\n') { | |
| 162 | ✗ | prototype[i] = ' '; | |
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | // Separate function name from argument list | ||
| 168 | size_t p1 = std::string::npos; | ||
| 169 | size_t p2 = std::string::npos; | ||
| 170 | { | ||
| 171 | int level = 0; | ||
| 172 | ✗ | for(size_t i=0; i<prototype.length(); ++i) { | |
| 173 | ✗ | switch(prototype[i]) { | |
| 174 | ✗ | case '[': | |
| 175 | ✗ | ++level; | |
| 176 | ✗ | break; | |
| 177 | ✗ | case ']': | |
| 178 | ✗ | --level; | |
| 179 | ✗ | break; | |
| 180 | ✗ | case '(': | |
| 181 | ✗ | if(level == 0) { | |
| 182 | p1 = i; | ||
| 183 | } | ||
| 184 | break; | ||
| 185 | ✗ | case ')': | |
| 186 | ✗ | if(level == 0) { | |
| 187 | p2 = i; | ||
| 188 | } | ||
| 189 | break; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | |||
| 195 | ✗ | geo_assert(p1 != std::string::npos && p2 != std::string::npos); | |
| 196 | ✗ | name_ = prototype.substr(0,p1); | |
| 197 | |||
| 198 | // Trim spaces, and remove return type if it was specified. | ||
| 199 | { | ||
| 200 | std::vector<std::string> name_parts; | ||
| 201 | ✗ | String::split_string(name_, ' ', name_parts); | |
| 202 | name_ = name_parts[name_parts.size()-1]; | ||
| 203 | ✗ | } | |
| 204 | |||
| 205 | // Find help if any | ||
| 206 | { | ||
| 207 | ✗ | size_t bq1 = prototype.find('[',p2); | |
| 208 | ✗ | size_t bq2 = prototype.find(']',p2); | |
| 209 | ✗ | if(bq1 != std::string::npos && bq2 != std::string::npos) { | |
| 210 | ✗ | help_ = prototype.substr(bq1+1, bq2-bq1-1); | |
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | ✗ | std::string args_string = prototype.substr(p1+1,p2-p1-1); | |
| 215 | ✗ | std::vector<std::string> args; | |
| 216 | ✗ | String::split_string(args_string, ',', args); | |
| 217 | |||
| 218 | ✗ | for(index_t i=0; i<args.size(); ++i) { | |
| 219 | std::string arg = args[i]; | ||
| 220 | std::string default_value; | ||
| 221 | std::string help; | ||
| 222 | |||
| 223 | // Find help if any | ||
| 224 | { | ||
| 225 | ✗ | size_t bq1 = arg.find('['); | |
| 226 | ✗ | size_t bq2 = arg.find(']'); | |
| 227 | ✗ | if(bq1 != std::string::npos && bq2 != std::string::npos) { | |
| 228 | ✗ | help = arg.substr(bq1+1, bq2-bq1-1); | |
| 229 | ✗ | arg = arg.substr(0, bq1); | |
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | // Find default value if any (to the right of the '=' sign) | ||
| 234 | { | ||
| 235 | ✗ | size_t eq = arg.find('='); | |
| 236 | ✗ | if(eq != std::string::npos) { | |
| 237 | ✗ | default_value = arg.substr(eq+1, arg.length()-eq-1); | |
| 238 | ✗ | trim_spaces(default_value); | |
| 239 | ✗ | arg = arg.substr(0, eq); | |
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | // Analyze argument type and name | ||
| 244 | std::vector<std::string> arg_words; | ||
| 245 | ✗ | String::split_string(arg, ' ', arg_words); | |
| 246 | |||
| 247 | // Argument name is the last word | ||
| 248 | const std::string& arg_name = arg_words[arg_words.size()-1]; | ||
| 249 | int type = -1; | ||
| 250 | ✗ | if(arg_words.size() > 1) { | |
| 251 | bool is_unsigned = false; | ||
| 252 | ✗ | for(index_t w=0; w<arg_words.size()-1; ++w) { | |
| 253 | ✗ | if(arg_words[w] == "unsigned") { | |
| 254 | is_unsigned = true; | ||
| 255 | ✗ | } else if(arg_words[w] == "bool") { | |
| 256 | type = Arg::ARG_BOOL; | ||
| 257 | ✗ | } else if(arg_words[w] == "int") { | |
| 258 | ✗ | type = (is_unsigned) ? Arg::ARG_UINT : Arg::ARG_INT; | |
| 259 | } else if( | ||
| 260 | ✗ | arg_words[w] == "index_t" || | |
| 261 | ✗ | arg_words[w] == "GEO::index_t" | |
| 262 | ) { | ||
| 263 | type = Arg::ARG_UINT; | ||
| 264 | } else if( | ||
| 265 | ✗ | arg_words[w] == "float" || | |
| 266 | ✗ | arg_words[w] == "double" | |
| 267 | ) { | ||
| 268 | type = Arg::ARG_FLOAT; | ||
| 269 | } else if( | ||
| 270 | ✗ | arg_words[w] == "string" || | |
| 271 | ✗ | arg_words[w] == "std::string" || | |
| 272 | ✗ | arg_words[w] == "string&" || | |
| 273 | ✗ | arg_words[w] == "std::string&" | |
| 274 | ) { | ||
| 275 | type = Arg::ARG_STRING; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | ✗ | switch(type) { | |
| 281 | ✗ | case Arg::ARG_BOOL: { | |
| 282 | ✗ | bool val = false; | |
| 283 | ✗ | if(default_value != "") { | |
| 284 | String::from_string(default_value, val); | ||
| 285 | } | ||
| 286 | ✗ | add_arg(arg_name, val, help); | |
| 287 | ✗ | } break; | |
| 288 | ✗ | case Arg::ARG_INT: { | |
| 289 | ✗ | int val = 0; | |
| 290 | ✗ | if(default_value != "") { | |
| 291 | String::from_string(default_value, val); | ||
| 292 | } | ||
| 293 | ✗ | add_arg(arg_name, val, help); | |
| 294 | ✗ | } break; | |
| 295 | ✗ | case Arg::ARG_UINT: { | |
| 296 | ✗ | unsigned int val = 0; | |
| 297 | ✗ | if(default_value != "") { | |
| 298 | String::from_string(default_value, val); | ||
| 299 | } | ||
| 300 | ✗ | add_arg(arg_name, val, help); | |
| 301 | ✗ | } break; | |
| 302 | ✗ | case Arg::ARG_FLOAT: { | |
| 303 | ✗ | float val = 0.0f; | |
| 304 | ✗ | if(default_value != "") { | |
| 305 | String::from_string(default_value, val); | ||
| 306 | } | ||
| 307 | ✗ | add_arg(arg_name, val, help); | |
| 308 | ✗ | } break; | |
| 309 | case Arg::ARG_STRING: { | ||
| 310 | ✗ | if(default_value != "") { | |
| 311 | // Remove quotes | ||
| 312 | ✗ | default_value = default_value.substr( | |
| 313 | 1, default_value.length()-2 | ||
| 314 | ✗ | ); | |
| 315 | ✗ | add_arg(arg_name, default_value, help); | |
| 316 | } | ||
| 317 | } break; | ||
| 318 | default: { | ||
| 319 | ✗ | geo_assert_not_reached; | |
| 320 | } | ||
| 321 | } | ||
| 322 | ✗ | } | |
| 323 | ✗ | name_ = remove_underscores(name_); | |
| 324 | ✗ | } | |
| 325 | |||
| 326 | ✗ | void Command::apply() { | |
| 327 | ✗ | if(invoker_ != nullptr) { | |
| 328 | ✗ | invoker_->invoke(); | |
| 329 | } | ||
| 330 | ✗ | } | |
| 331 | |||
| 332 | ✗ | int Command::int_arg_by_index(index_t i) const { | |
| 333 | ✗ | const Arg& arg = find_arg_by_index(i); | |
| 334 | ✗ | geo_assert( | |
| 335 | arg.type == Arg::ARG_INT || | ||
| 336 | arg.type == Arg::ARG_UINT | ||
| 337 | ); | ||
| 338 | ✗ | int result = arg.val.int_val; | |
| 339 | ✗ | if( | |
| 340 | ✗ | arg.type == Arg::ARG_UINT && | |
| 341 | result < 0 | ||
| 342 | ) { | ||
| 343 | ✗ | Logger::warn("Cmd") | |
| 344 | << "Argument " << arg.name | ||
| 345 | << "Of type UNIT had a negative value" | ||
| 346 | << std::endl; | ||
| 347 | result = 0; | ||
| 348 | } | ||
| 349 | ✗ | return result; | |
| 350 | } | ||
| 351 | |||
| 352 | ✗ | unsigned int Command::uint_arg_by_index(index_t i) const { | |
| 353 | ✗ | const Arg& arg = find_arg_by_index(i); | |
| 354 | ✗ | geo_assert( | |
| 355 | arg.type == Arg::ARG_INT || | ||
| 356 | arg.type == Arg::ARG_UINT | ||
| 357 | ); | ||
| 358 | ✗ | int result = arg.val.int_val; | |
| 359 | ✗ | if(result < 0) { | |
| 360 | ✗ | Logger::warn("Cmd") | |
| 361 | << "Argument " << arg.name | ||
| 362 | << "queried as uint had a negative value" | ||
| 363 | << std::endl; | ||
| 364 | result = 0; | ||
| 365 | } | ||
| 366 | ✗ | return (unsigned int)(result); | |
| 367 | } | ||
| 368 | |||
| 369 | ✗ | void Command::draw() { | |
| 370 | ✗ | ImGui::Text("%s",name().c_str()); | |
| 371 | ✗ | if(ImGui::SimpleButton(icon_UTF8("window-close").c_str())) { | |
| 372 | ✗ | visible_ = false; | |
| 373 | } | ||
| 374 | ✗ | ImGui::Tooltip("close command"); | |
| 375 | ✗ | ImGui::SameLine(); | |
| 376 | ✗ | if(ImGui::SimpleButton( | |
| 377 | ✗ | icon_UTF8("cog").c_str() | |
| 378 | )) { | ||
| 379 | ✗ | reset_factory_settings(); | |
| 380 | } | ||
| 381 | ✗ | ImGui::Tooltip("reset factory settings"); | |
| 382 | ✗ | ImGui::SameLine(); | |
| 383 | ✗ | if(ImGui::Button(icon_UTF8("check").c_str(), ImVec2(-1.0, 0.0))) { | |
| 384 | ✗ | queued_ = this; | |
| 385 | } | ||
| 386 | ✗ | if(help_ == "") { | |
| 387 | ✗ | ImGui::Tooltip("apply command"); | |
| 388 | } else { | ||
| 389 | ImGui::Tooltip(help_); | ||
| 390 | } | ||
| 391 | ✗ | ImGui::Separator(); | |
| 392 | ✗ | for(index_t i=0; i<args_.size(); ++i) { | |
| 393 | ✗ | args_[i].draw(); | |
| 394 | } | ||
| 395 | ✗ | ImGui::Separator(); | |
| 396 | ✗ | } | |
| 397 | |||
| 398 | ✗ | void Command::reset_factory_settings() { | |
| 399 | ✗ | for(index_t i=0; i<args_.size(); ++i) { | |
| 400 | ✗ | args_[i].val = args_[i].default_val; | |
| 401 | } | ||
| 402 | ✗ | } | |
| 403 | |||
| 404 | ✗ | void Command::ArgVal::clear() { | |
| 405 | ✗ | bool_val = false; | |
| 406 | ✗ | int_val = 0; | |
| 407 | ✗ | float_val = 0.0f; | |
| 408 | ✗ | string_val[0] = '\0'; | |
| 409 | ✗ | } | |
| 410 | |||
| 411 | ✗ | Command::ArgVal::ArgVal(const Command::ArgVal& rhs) { | |
| 412 | ✗ | bool_val = rhs.bool_val; | |
| 413 | ✗ | int_val = rhs.int_val; | |
| 414 | ✗ | float_val = rhs.float_val; | |
| 415 | ✗ | Memory::copy(string_val, rhs.string_val, 64); | |
| 416 | ✗ | } | |
| 417 | |||
| 418 | ✗ | Command::ArgVal& Command::ArgVal::operator=(const ArgVal& rhs) { | |
| 419 | ✗ | if(&rhs != this) { | |
| 420 | ✗ | bool_val = rhs.bool_val; | |
| 421 | ✗ | int_val = rhs.int_val; | |
| 422 | ✗ | float_val = rhs.float_val; | |
| 423 | ✗ | Memory::copy(string_val, rhs.string_val, 64); | |
| 424 | } | ||
| 425 | ✗ | return *this; | |
| 426 | } | ||
| 427 | |||
| 428 | ✗ | Command::Arg::Arg() { | |
| 429 | ✗ | name = "unnamed"; | |
| 430 | ✗ | type = ARG_BOOL; | |
| 431 | ✗ | val.clear(); | |
| 432 | ✗ | default_val.clear(); | |
| 433 | ✗ | val.bool_val = false; | |
| 434 | ✗ | default_val.bool_val = false; | |
| 435 | ✗ | } | |
| 436 | |||
| 437 | ✗ | Command::Arg::Arg( | |
| 438 | const std::string& name_in, bool x, | ||
| 439 | const std::string& help_in | ||
| 440 | ✗ | ) { | |
| 441 | ✗ | name = name_in; | |
| 442 | ✗ | help = help_in; | |
| 443 | ✗ | type = ARG_BOOL; | |
| 444 | ✗ | val.clear(); | |
| 445 | ✗ | default_val.clear(); | |
| 446 | ✗ | val.bool_val = x; | |
| 447 | ✗ | default_val.bool_val = x; | |
| 448 | ✗ | } | |
| 449 | |||
| 450 | ✗ | Command::Arg::Arg( | |
| 451 | const std::string& name_in, int x, | ||
| 452 | const std::string& help_in | ||
| 453 | ✗ | ) { | |
| 454 | ✗ | name = name_in; | |
| 455 | ✗ | help = help_in; | |
| 456 | ✗ | type = ARG_INT; | |
| 457 | ✗ | val.clear(); | |
| 458 | ✗ | default_val.clear(); | |
| 459 | ✗ | val.int_val = x; | |
| 460 | ✗ | default_val.int_val = x; | |
| 461 | ✗ | } | |
| 462 | |||
| 463 | ✗ | Command::Arg::Arg( | |
| 464 | const std::string& name_in, unsigned int x, | ||
| 465 | const std::string& help_in | ||
| 466 | ✗ | ) { | |
| 467 | ✗ | name = name_in; | |
| 468 | ✗ | help = help_in; | |
| 469 | ✗ | type = ARG_UINT; | |
| 470 | ✗ | val.clear(); | |
| 471 | ✗ | default_val.clear(); | |
| 472 | ✗ | val.int_val = int(x); | |
| 473 | ✗ | default_val.int_val = int(x); | |
| 474 | ✗ | } | |
| 475 | |||
| 476 | ✗ | Command::Arg::Arg( | |
| 477 | const std::string& name_in, float x, | ||
| 478 | const std::string& help_in | ||
| 479 | ✗ | ) { | |
| 480 | ✗ | name = name_in; | |
| 481 | ✗ | help = help_in; | |
| 482 | ✗ | type = ARG_FLOAT; | |
| 483 | ✗ | val.clear(); | |
| 484 | ✗ | default_val.clear(); | |
| 485 | ✗ | val.float_val = x; | |
| 486 | ✗ | default_val.float_val = x; | |
| 487 | ✗ | } | |
| 488 | |||
| 489 | ✗ | Command::Arg::Arg( | |
| 490 | const std::string& name_in, double x, | ||
| 491 | const std::string& help_in | ||
| 492 | ✗ | ) { | |
| 493 | ✗ | name = name_in; | |
| 494 | ✗ | help = help_in; | |
| 495 | ✗ | type = ARG_FLOAT; | |
| 496 | ✗ | val.clear(); | |
| 497 | ✗ | default_val.clear(); | |
| 498 | ✗ | val.float_val = float(x); | |
| 499 | ✗ | default_val.float_val = float(x); | |
| 500 | ✗ | } | |
| 501 | |||
| 502 | ✗ | Command::Arg::Arg( | |
| 503 | const std::string& name_in, const std::string& x, | ||
| 504 | const std::string& help_in | ||
| 505 | ✗ | ) { | |
| 506 | ✗ | name = name_in; | |
| 507 | ✗ | help = help_in; | |
| 508 | ✗ | type = ARG_STRING; | |
| 509 | ✗ | val.clear(); | |
| 510 | ✗ | default_val.clear(); | |
| 511 | ✗ | geo_assert(x.length() < 63); | |
| 512 | ✗ | Memory::copy(default_val.string_val,x.c_str(), x.length()); | |
| 513 | ✗ | default_val.string_val[x.length()] = '\0'; | |
| 514 | ✗ | Memory::copy(val.string_val,x.c_str(), x.length()); | |
| 515 | ✗ | val.string_val[x.length()] = '\0'; | |
| 516 | ✗ | } | |
| 517 | |||
| 518 | ✗ | void Command::Arg::draw() { | |
| 519 | // Some widgets with labels are too wide, | ||
| 520 | // therefore their label is displayed with | ||
| 521 | // a separate ImGui::Text(). | ||
| 522 | // Each ImGUI widget requires a unique Id, | ||
| 523 | // that is normally generated from the label. | ||
| 524 | // If label starts with "##", then ImGui | ||
| 525 | // makes it invisible (and uses what's after | ||
| 526 | // "##" to generate the Id). | ||
| 527 | ✗ | switch(type) { | |
| 528 | ✗ | case ARG_BOOL: | |
| 529 | ✗ | ImGui::SetNextItemWidth(-1.0f); | |
| 530 | ✗ | ImGui::Checkbox(remove_underscores(name).c_str(), &val.bool_val); | |
| 531 | ImGui::Tooltip(help); | ||
| 532 | break; | ||
| 533 | ✗ | case ARG_INT: | |
| 534 | ✗ | ImGui::Text("%s",remove_underscores(name).c_str()); | |
| 535 | ✗ | ImGui::SetNextItemWidth(-1.0f); | |
| 536 | ImGui::Tooltip(help); | ||
| 537 | ✗ | ImGui::InputInt(("##" + name).c_str(), &val.int_val); | |
| 538 | ✗ | break; | |
| 539 | ✗ | case ARG_UINT: | |
| 540 | ✗ | ImGui::Text("%s",remove_underscores(name).c_str()); | |
| 541 | ✗ | ImGui::SetNextItemWidth(-1.0f); | |
| 542 | ImGui::Tooltip(help); | ||
| 543 | ✗ | ImGui::InputInt(("##" + name).c_str(), &val.int_val); | |
| 544 | ✗ | break; | |
| 545 | ✗ | case ARG_FLOAT: | |
| 546 | ✗ | ImGui::Text("%s",remove_underscores(name).c_str()); | |
| 547 | ✗ | ImGui::SetNextItemWidth(-1.0f); | |
| 548 | ImGui::Tooltip(help); | ||
| 549 | ✗ | ImGui::InputFloat(("##" + name).c_str(), &val.float_val); | |
| 550 | ✗ | break; | |
| 551 | ✗ | case ARG_STRING: | |
| 552 | ✗ | ImGui::Text("%s",remove_underscores(name).c_str()); | |
| 553 | ✗ | ImGui::SetNextItemWidth(-1.0f); | |
| 554 | ImGui::Tooltip(help); | ||
| 555 | ✗ | ImGui::InputText(("##" + name).c_str(), val.string_val, 64); | |
| 556 | ✗ | break; | |
| 557 | } | ||
| 558 | ✗ | } | |
| 559 | |||
| 560 | SmartPointer<Command> Command::current_; | ||
| 561 | SmartPointer<Command> Command::queued_; | ||
| 562 | SmartPointer<Command> Command::latest_; | ||
| 563 | } | ||
| 564 |