From a MessageDialog how to read variables when i use pango markup? - c++

how to use pango markup in messagedialog text using variable
For example this code
void usb_boot::creation(){
//Gtk::MessageDialog dialogue(*this, listeDeroulante.get_active_text());
std::string message("Type de formatage : " + type), type1, chemin1;
Gtk::MessageDialog *dialogue = new Gtk::MessageDialog("Résumé", true, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
dialogue->set_title("Résumé");
dialogue->set_message("<span weight='bold'>message</span>",true);
dialogue->set_secondary_text("<b>listeDeroulante.get_active_text()</b>", true);
dialogue->set_default_response(Gtk::RESPONSE_YES);
int result = dialogue->run();
set_message and set_secondary_text have to print variables but just "see" word.
Is there a way to read like variables ?

While the std::stringstream solution works, I would suggest using simple string concatenation, through std::string's operator+:
#include <gtkmm.h>
int main(int argc, char **argv)
{
auto app = Gtk::Application::create(argc, argv, "so.question.q63886899");
Gtk::Window w;
w.show_all();
{
// Unformatted messages:
std::string primaryMessage = "Some message...";
std::string secondaryMessage = "Some more message details...";
Gtk::MessageDialog dialog(w, "Message dialog", true, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
dialog.set_title("Title");
// Add pango markup tags through string concatenation:
dialog.set_message("<span weight='bold'>" + primaryMessage + "</span>", true);
dialog.set_secondary_text("<b>" + secondaryMessage + "</b>", true);
dialog.run();
}
return app->run(w);
}
With this solution, no need to introduce an extra type.

Related

ROS2 reading bag files

I have got a bag file in db3 format and I was trying to read its messages, deserialise them and access their fields. I couldn't find any appropriate document or working example anywhere. I only managed to load the file and display all its message types using the rosbag2_cpp API as follows:
#include <rclcpp/rclcpp.hpp>
#include <tf2_msgs/msg/tf_message.hpp>
#include <ament_index_cpp/get_package_share_directory.hpp>
#include <rosbag2_cpp/readers/sequential_reader.hpp>
#include <rosbag2_cpp/converter_interfaces/serialization_format_converter.hpp>
#include <rosbag2_storage/storage_options.hpp>
int main(int argc, char** argv)
{
(void) argc;
(void) argv;
rclcpp::init(argc, argv);
rclcpp::Node node("test");
rosbag2_storage::StorageOptions storage_options{};
auto file_path = ament_index_cpp::get_package_share_directory("test")
+ "/data/rosbag_autoware_receiver_0.db3";
storage_options.uri = file_path;
storage_options.storage_id = "sqlite3";
rosbag2_cpp::ConverterOptions converter_options{};
converter_options.input_serialization_format = "cdr";
converter_options.output_serialization_format = "cdr";
rosbag2_cpp::readers::SequentialReader reader;
reader.open(storage_options, converter_options);
const auto topics = reader.get_all_topics_and_types();
for (const auto topic : topics)
RCLCPP_INFO(node.get_logger(), topic.name.c_str());
return 0;
}
Any hint, help or guide on reading the actual messages and deserialising them is much appreciated.
Regards
What you're looking for is the has_next() property.
Declare a msg variable of the type(s) you're looking for (such as sensor_msgs::msg::Image msg), and deserialize as following:
while (reader.has_next())
{
// serialized data
auto serialized_message = reader.read_next();
rclcpp::SerializedMessage extracted_serialized_msg(*serialized_message->serialized_data);
auto topic = serialized_message->topic_name;
if (topic.find("whatever...") != std::string::npos)
{
serialization_info.deserialize_message(&extracted_serialized_msg, &msg);
}
}

Specific filepath to store Screen Record using CGDisplayStream in OSX

I have been working on a c++ command line tool to record screen. After some searching I have come up with this following code. Looks like screen is being recorded when I compile and run the code. I am looking for functions where I can provide the specific filepath where the screen record is to be stored. Also I would like to append the timestamp along with filename. If anybody has better approach or method to this problem please suggest here. Any leads are appreciated. Thanks
#include <ApplicationServices/ApplicationServices.h>
int main(int argc, const char * argv[]) {
// insert code here...
CGRect mainMonitor = CGDisplayBounds(CGMainDisplayID());
CGFloat monitorHeight = CGRectGetHeight(mainMonitor);
CGFloat monitorWidth = CGRectGetWidth(mainMonitor);
const void *keys[1] = { kCGDisplayStreamSourceRect };
const void *values[1] = { CGRectCreateDictionaryRepresentation(CGRectMake(0, 0, 100, 100)) };
CFDictionaryRef properties = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CGDisplayStreamRef stream = CGDisplayStreamCreate(CGMainDisplayID(), monitorWidth, monitorHeight, '420f' , properties, ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef){});
CGDirectDisplayID displayID = CGMainDisplayID();
CGImageRef image_create = CGDisplayCreateImage(displayID);
CFRunLoopSourceRef runLoop = CGDisplayStreamGetRunLoopSource(stream);
// CFRunLoopAddSource(<#CFRunLoopRef rl#>, runLoop, <#CFRunLoopMode mode#>);
CGError err = CGDisplayStreamStart(stream);
if (err == CGDisplayNoErr) {
std::cout<<"WORKING"<<std::endl;
sleep(5);
} else {
std::cout<<"Error: "<<err<<std::endl;
}
//std::cout << "Hello, World!\n";
return 0;
}
You should do that in the callback which you provide in CGDisplayStreamCreate. You can access the pixels via IOSurfaceGetBaseAddress (see other IOSurface functions). If you don't want to do the pixel twiddling yourself, you could create a CVPixelBuffer with CVPixelBufferCreateWithBytes from the IOSurface and then create a CIImage with [CIImage imageWithCVImageBuffer] and save that to file as seen here.

Calling a boost unit_test test within code

I'm trying to call a boost::unit_test from code.
In a number of files I've got
BOOST_AUTO_TEST_SUITE(DataAccessSuite)
BOOST_AUTO_TEST_CASE(DateAppender)
{
...
}
BOOST_AUTO_TEST_SUITE_END()
For my dialog box I have a visitor to gather the IDs and names of all the test cases/suites
namespace {
unit_test::test_suite* init_unit_test_suite(int argc, char** argv) {
return 0;
}
using namespace std::string_literals;
struct test_visitor : unit_test::test_tree_visitor {
test_visitor(std::vector<std::tuple<std::string, unit_test::test_unit_id>>& tests) : m_tests(tests) {}
void visit(unit_test::test_case const& test) {
m_tests.emplace_back(std::make_tuple(suite + "/"s + static_cast<std::string>(test.p_name),test.p_id));
}
virtual bool test_suite_start(unit_test::test_suite const& ts) {
suite = ts.p_name;
return true;
}
virtual void test_suite_finish(unit_test::test_suite const&) {
suite = std::string();
}
std::string suite;
std::vector<std::tuple<std::string, unit_test::test_unit_id>>& m_tests;
};
}
TestDialogImpl::TestDialogImpl(wxWindow* parent) : TestDialog(parent)
{
// Make a list of test cases to show in my dialog box
unit_test::traverse_test_tree(unit_test::framework::master_test_suite(), test_visitor(m_tests), true);
for (auto& test : m_tests) {
m_listBox2->Append(wxString(std::get<0>(test)));
}
}
And here's my call to the test case
void TestDialogImpl::OnClick_RunButton(wxCommandEvent & event)
{
auto selection = m_listBox2->GetStringSelection();
char* argv[] = { "OptionModeller.exe","--run_test=DataAccessSuite/DateAppender" };
unit_test::framework::init(init_unit_test_suite, 2, argv);
auto finder = std::find_if(std::begin(m_tests), std::end(m_tests), [&selection](auto& v) { return std::get<0>(v) == selection; });
// This fails with setup_error(), but I don't know why?
unit_test::framework::run(std::get<1>(*finder), true);
}
Is there a way I could call the test and utilize the framework. I know I could alternatively call the free functions but that defeats the point of using BOOST_TEST
UPDATE
From #A Fagrell's idea
I changed the call of the test executor to
void TestDialogImpl::OnClick_RunButton(wxCommandEvent & event)
{
wxString selection = "--run_test=" + m_listBox2->GetStringSelection();
const char* option = static_cast<const char*>(selection);
char* argv[] = { "OptionModeller.exe" , (char*)(option)};
unit_test::unit_test_main(&init_unit_test_suite, 2, argv);
}
Seems to work ok, but does seem the wrong way of doing things. I would have expected to be able to call a test explicitly by id, rather than by fudging the command line args.
Is there a better way?

Passing a value to std::ifstream through constructor

I'm trying to pass a file name with a string through a constructor, my code is this. I've removed some of the unnecessary stuff for simplicity.
// header file
Interpreter(const std::string location);
std::ifstream *file;
// end header file
// class file
Interpreter::Interpreter(const std::string location) {
file = new std::ifstream(location.c_str());
}
// end class file
However, the result is a "Debug Assertion Failed!".
image
Edit:
As a fairly newbie C++ programmer (came from Java), I've taken the advice of an initializer list and this is my code now (in the header):
std::ifstream file;
Interpreter(const std::string location) {
file.open(location.c_str());
}
Yet I'm still getting the same error, any help? Thanks!
Edit 2:
int main(int argc, char** argv) {
Interpreter *interpreter = nullptr;
// check if arguments are provided
if (argc > 0) {
interpreter = new Interpreter(argv[1]);
} else {
// for now just use the debug script
error("No input files, using default script (debug)");
interpreter = new Interpreter("test.m");
}
interpreter->read();
delete interpreter;
return 0;
}
Edit 3
Did you mean this initializer list?
Interpreter::Interpreter(const std::string location): file(location) {
}
Edit 4
Final edit, thanks guys :)
Turns out the problem was with the arguments
And argc>0 does not mean argv[1] is safe to access.
That's in the CPP file, and still gives the same result. D:
if (argc > 0) {
interpreter = new Interpreter(argv[1]);
This is not correct, if argc == 1 then argv[1] is out of bounds, it should be
if (argc > 1) {
interpreter = new Interpreter(argv[1]);
As for the rest of the question, I would write the constructor like this:
Interpreter(const std::string location) : file(location) { }
(In C++11 you can construct an fstream from a std::string, if that doesn't work with your compiler then use location.c_str() as you had previously:
Interpreter(const std::string location) : file(location.c_str()) { }
I would write your main function like this:
int main(int argc, char** argv)
{
std::string file;
// check if arguments are provided
if (argc > 1) {
file = argv[1];
} else {
// for now just use the debug script
error("No input files, using default script (debug)");
file = "test.m";
}
Interpreter interpreter(file);
interpreter.read();
}
This has no new and delete and is simpler and clearer.

How to get the stem of a filename from a path?

I want to extract a const char* filename from a const char* filepath. I tried with regex but failed:
const char* currentLoadedFile = "D:\files\file.lua";
char fileName[256];
if (sscanf(currentLoadedFile, "%*[^\\]\\%[^.].lua", fileName)) {
return (const char*)fileName; // WILL RETURN "D:\files\file!!
}
The issue is that "D:\files\file" will be returned and not the wanted "file"(note: without ".lua")
What about using std::string?
e.g.
std::string path("d:\\dir\\subdir\\file.ext");
std::string filename;
size_t pos = path.find_last_of("\\");
if(pos != std::string::npos)
filename.assign(path.begin() + pos + 1, path.end());
else
filename = path;
Just use boost::filesystem.
#include <boost/filesystem.hpp>
std::string filename_noext;
filename_noext = boost::filesystem::path("D:\\files\\file.lua").stem().string().
const char* result_as_const_char = filename_noext.c_str();
or alternatively, if you want to introduce bugs yourself :
// have fun defining that to the separator of the target OS.
#define PLATFORM_DIRECTORY_SEPARATOR '\\'
// the following code is guaranteed to have bugs.
std::string input = "D:\\files\\file.lua";
std::string::size_type filename_begin = input.find_last_of(PLATFORM_DIRECTORY_SEPERATOR);
if (filename_begin == std::string::npos)
filename_begin = 0;
else
filename_begin++;
std::string::size_type filename_length = input.find_last_of('.');
if (filename_length != std::string::npos)
filename_length = filename_length - filename_begin;
std::string result = input.substr(filename_begin, filename_length);
const char* bugy_result_as_const_char = result.c_str();
You can do this portably and easily using the new filesystem library in C++17.
#include <cstdint>
#include <cstdio>
#include <filesystem>
int main()
{
std::filesystem::path my_path("D:/files/file.lua");
std::printf("filename: %s\n", my_path.filename().u8string().c_str());
std::printf("stem: %s\n", my_path.stem().u8string().c_str());
std::printf("extension: %s\n", my_path.extension().u8string().c_str());
}
Output:
filename: file.lua
stem: file
extension: .lua
Do note that for the time being you may need to use #include <experimental/fileystem> along with std::experimental::filesystem instead until standard libraries are fully conforming.
For more documentation on std::filesystem check out the filesystem library reference.
You can easily extract the file:
int main()
{
char pscL_Dir[]="/home/srfuser/kush/folder/kushvendra.txt";
char pscL_FileName[50];
char pscL_FilePath[100];
char *pscL;
pscL=strrchr(pscL_Dir,'/');
if(pscL==NULL)
printf("\n ERROR :INvalid DIr");
else
{
strncpy(pscL_FilePath,pscL_Dir,(pscL-pscL_Dir));
strcpy(pscL_FileName,pscL+1);
printf("LENTH [%d}\n pscL_FilePath[%s]\n pscL_FileName[%s]",(pscL-pscL_Dir),pscL_FilePath,pscL_FileName);
}
return 0;
}
output:
LENTH [25}
pscL_FilePath[/home/srfuser/kush/folder]
pscL_FileName[kushvendra.txt
Here you can find an example. I'm not saying it's the best and I'm sure you could improve on that but it uses only standard C++ (anyway at least what's now considered standard).
Of course you won't have the features of the boost::filesystem (those functions in the example play along with plain strings and do not guarantee/check you'll actually working with a real filesystem path).
// Set short name:
char *Filename;
Filename = strrchr(svFilename, '\\');
if ( Filename == NULL )
Filename = svFilename;
if ( Filename[0] == '\\')
++Filename;
if ( !lstrlen(Filename) )
{
Filename = svFilename;
}
fprintf( m_FileOutput, ";\n; %s\n;\n", Filename );
You could use the _splitpath_s function to break a path name into its components. I don't know if this is standard C or is Windows specific. Anyway this is the function:
#include <stdlib.h>
#include <string>
using std::string;
bool splitPath(string const &path, string &drive, string &directory, string &filename, string &extension) {
// validate path
drive.resize(_MAX_DRIVE);
directory.resize(_MAX_DIR);
filename.resize(_MAX_FNAME);
extension.resize(_MAX_EXT);
errno_t result;
result = _splitpath_s(path.c_str(), &drive[0], drive.size(), &directory[0], directory.size(), &filename[0], filename.size(), &extension[0], extension.size());
//_splitpath(path.c_str(), &drive[0], &directory[0], &filename[0], &extension[0]); //WindowsXp compatibility
_get_errno(&result);
if (result != 0) {
return false;
} else {
//delete the blank spaces at the end
drive = drive.c_str();
directory = directory.c_str();
filename = filename.c_str();
extension = extension.c_str();
return true;
}
}
It is a lot easier and safe to use std::string but you could modify this to use TCHAR* (wchar, char)...
For your specific case:
int main(int argc, char *argv[]) {
string path = argv[0];
string drive, directory, filename, extension;
splitPath(path, drive, directory, filename, extension);
printf("FILE = %s%s", filename.c_str(), extension.c_str());
return 0;
}
If you are going to display a filename to the user on Windows you should respect their shell settings (show/hide extension etc).
You can get a filename in the correct format by calling SHGetFileInfo with the SHGFI_DISPLAYNAME flag.