-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Users feedback, discussion #4
Comments
Many thanks for your reply and your praise. The using of an alternative and more established place for the user feedback sounds good. I joined Stack Overflow now. You can find me here: http://stackoverflow.com/users/story/7607413 Unfortunately, I can not create the tag "final-cut" without asking a question. |
http://stackoverflow.com/questions/42408243/support-for-table-grid-widget-in-final-cut |
Can it work on MacOS? |
I don't have a macOS on my computer, but I'm using a compile-run with macOS on Travis-CI. The use of macOS should therefore be possible. Of course, I would appreciate a positive feedback. https://travis-ci.org/gansm/finalcut/builds/304405079 |
I got this error message when try to compile hello sample. |
I have checked emac in Macport. This is how they implement the mouse. https://searchcode.com/codesearch/view/27232327/ |
I have download gpm from github since it can support xterm. Then I compile with g++ -I/Library/finalcut/include -o hellofinal hellofinal.cpp and I get linker error: Then I tried to compile with g++ -I/Library/finalcut/include -o wtui hellofinal.cpp /Library/finalcut/src/fmessagebox.cpp get this error: |
It seems the examples all working when I use make. |
When I try to compile manually, error: "_tgetent", referenced from: |
I confirm that the library works on MacOS. |
Yes I know it is working on MacOS since I can make samples & run it. May I know what is c++ flag to compile it.I tried g++ -I/mylibrary/finalcut/include /mylibrary/finalcut/src/*.o -o hello hello.cpp but no success |
Thank you for your feedback. I'm a little bit confused that the configure script has found a gpm.h on your system. You should try the following commands: autoreconf -v --install --force
./configure --prefix=/usr
make If that doesn't help, you can also explicitly disable GPM support: ./configure --prefix=/usr --without-gpm
make How to use the library (a little example): #include <final/final.h>
using namespace finalcut;
int main (int argc, char* argv[])
{
FApplication app(argc, argv);
// Note: Use Shift+F10 or Ctrl+^ to close the dialog
FDialog dialog(&app);
dialog.setText ("A dialog");
dialog.setGeometry (FPoint(25, 5), FSize(30, 10));
app.setMainWidget(&dialog);
dialog.show();
return app.exec();
} Compile with: It is important that you don't forget to include the libfinal via "-lfinal". |
Yes, thank you. With "-lfinal" flag I'm able to compile my code. Thanks. |
Are there any possible this can be ported to Windows? |
I have downloaded and make & install on ubuntu 17.04 but can't compile my code with same way I compile on Mac. On Mac, I download gpm first before make & install final cut. |
A port to Microsoft Windows isn’t possible, because there are neither POSIX libraries nor a terminal emulator available. For the compiling under Ubuntu you probably need some development packages.
|
I added the [finalcut-tui] tag on SO. Your tui doesn't work too well on my arch linux though within lxterminal :) All blinking and stuff. |
Thanks for your tagging. LXTerminal is a VTE-based terminal emulator and should not cause any problems.
Post me the output of Do you also get the libtinfo.so displayed when using the ldd command?
What does the environment variable $TERM contain? If all runs correctly, the file |
xterm-256color -rw-r--r-- 1 root root 3619 Jan 29 2018 /usr/share/terminfo/g/gnome-256color |
That's interesting. I found out that the VTE project has changed the terminal ID from 1 to 65 since version 0.53.0. I have changed the terminal detection in the current commit. If it doesn't work, please don't put the whole screen output here again. I only need the part from |
It works now.
… |
Does the library support Windows, DOS, how about the android console? |
Rather than reimplementing Qt, you should strive to provide features, that Qt does not provide. Perhaps web deployment (emscripten has a curses port available) and declarative language support, that compiles into C++. Qt Quick and the associated bloat are a major issue among embedded Qt devs. |
I'm not trying to reimplement Qt Framework. The basic class design is influenced from Qt and not a one-to-one Qt clone. termcap: terminal capability database |
Hi! I'm trying to catch the terminal resize event, but don't know how. My first thought was to subclass FWidget and add a onResize(FResizeEvent *event), but it did not work. In the First Steps you explain that most events will be provided by event() of FObject, but all I see is just a call to onTimer() and onUserEvent(). Is there a simple example available about this? Thanks in advance. |
Code example: #include <final/final.h>
using namespace finalcut;
class FApp : public FApplication
{
public:
FApp (const int& _argc, char* _argv[])
: FApplication(_argc, _argv)
{ }
private:
void onResize (FResizeEvent* ev) override
{
FTerm::beep();
FWidget::onResize (ev);
}
};
int main (int argc, char* argv[])
{
FApp app(argc, argv);
FMessageBox mbox(&app);
mbox.setTitlebarText("Listen...");
mbox.setText("Beep on resize.");
mbox.exec();
} Maybe the method |
Yes, that's what I was up to. Thanks a lot. |
Hi! I've got another question. Since yesterday I'm struggling with a std::thread. Within a subclass of FDialog I want to fill a FListBox with items read by a thread. The thread is created after instantiation. Well, I started with a simple function that just prints that it's been called. But even this thread causes a segmentation fault on thread.join().
Well, Module::test() fails too. To test it, I tried the following simple code snippet:
This snippet works like charm. I'm not used to C++ so I think I'm missing something important here. Does anyone have got an idea? Thanks in advance. |
Unfortunately I don't know your program code, so I can't tell you what could be the reason for the segmentation fault. This little example might help you: #include <chrono>
#include <thread>
#include <final/final.h>
using finalcut::FPoint;
using finalcut::FSize;
class ListBoxDialog : public finalcut::FDialog
{
public:
ListBoxDialog (FWidget* parent = nullptr) : FDialog(parent)
{
setText (L"List copy per thread");
setGeometry ( FPoint(int(1 + (parent->getWidth() - 41) / 2), 5)
, FSize(41, 16) );
setShadow();
list1.setGeometry(FPoint(2, 1), FSize(18, 10));
list1.setText ("Source");
list1.insert ( {1, 2, 3, 4, 5, 6, 7, 8} );
list2.setGeometry(FPoint(21, 1), FSize(18, 10));
list2.setText ("Destination");
Quit.setGeometry(FPoint(28, 12), FSize(10, 1));
Quit.setText (L"&Quit");
Quit.addCallback
(
"clicked",
finalcut::getFApplication(),
&finalcut::FApplication::cb_exitApp,
this
);
}
~ListBoxDialog()
{ }
private:
void copy() // run as thread
{
std::this_thread::sleep_for(std::chrono::seconds(2));
for (std::size_t i = 1; i <= list1.getCount(); i++)
list2.insert(list1.getItem(i));
list2.redraw();
updateTerminal();
}
void onShow (finalcut::FShowEvent*)
{
std::thread t1(&ListBoxDialog::copy, this);
t1.detach();
}
finalcut::FListBox list1{this};
finalcut::FListBox list2{this};
finalcut::FButton Quit{this};
};
int main (int argc, char* argv[])
{
finalcut::FApplication app(argc, argv);
ListBoxDialog dlg(&app);
app.setMainWidget(&dlg);
dlg.show();
return app.exec();
} Last modified: Code changes for the upcoming release 0.7.0 If you want to learn more about C++, you should take a closer look at these pages. |
Hi Markus! Thanks for your reply. I figured out that my problem only happens when I statically link the binary. According to this: https://stackoverflow.com/questions/35116327/when-g-static-link-pthread-cause-segmentation-fault-why I needed to -Wl,--whole-archive. Now it just works. Your minimal examples was quite helpful for me. Thanks a lot. |
Thanks for the ComboBox. Today I've added this to my working tree as I didn't find anything similar. That's one thing I've missed for the ComboBox.
If anyone need that too, just add this to the implementation, and declare this method in the header file and you're done. If this is already there, then please, can someone point me to it? Kind regards. |
You are absolutely right, this important method is indeed missing. Thanks for your sample code, which I have already added to the FComboBox class. (c0b1dc5) |
|
I think you are asking me here for the communication channels you can use to ask me about FINAL CUT? Well, I prefer to use GitHub here to have all the problems and solutions for FINAL CUT on one place. You can also use the "finalcut-tui" tag on Stack Overflow to ask me a question about FINAL CUT. |
Can I create windows from a thread different from the main thread that runs the event loop? Or call methods of the widgets? For my app, that I'm about to start writing with finalcut, I will be running a scripting language in a child thread (mainly because it has its own event loop). It isn't a good idea to mix/merge them, though it is possible, but isn't a direction I'd want to go. For sending jobs to the scripting engine, I queue an event to its loop. Should I do the same going back into the finalcut API? |
Would it be possible to add a threadsafe wrapper around FApplication::queueEvent() ? https://www.xtof.info/blog/?p=593 |
I have already posted a small thread example in this issue above. I hope this helps you. The FINAL CUT main event loop is for processing widget events. I think your implementation of the separation of user interface and script engine is a good idea. It would be possible to run |
I need a mutex protected way to post user events to the main queue which can be called from any foreign thread and wake it if blocked on getch() or wherever the wait is happening. Similar to the use of Tool Command Language's: |
If I understand them correctly, you would like to have the methods
for threads in addition to
Sounds interesting! Unfortunately I don't have enough time to implement this at the moment. I'll add it to my "nice to have" list. |
Let me explain a bit more from a point-of-view I already have. In windows GUI programming, the central point of event notification for the entire application can be https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-msgwaitformultipleobjectsex. Adding alertable objects to the list is easy, and a switch/case gets you to the correct handler from the return value. I don't fully get the concept in FINAL CUT where the waitstate is taking place in |
Conceptually, I think what I want is to make my own derived class of FApplication that has my own handler for a custom event with a threadsafe ::threadQueueEvent() to be called by a foreign thread. Calling this function inserts my event to the queue and wakes the main thread to service the handlers. This wouldn't be for events to widget objects. Just a way to get into the main thread so I can do stuff like create or close windows and just generally manipulate the UI. |
FINAL CUT has no central point of event notification. The general way is to send it directly with
But if you only want to manipulate GUI elements, you should probably use Signals and Callbacks. |
There's a select() somewhere. You aren't busy looping on nothing. Callbacks are the wrong direction. I need a way to pull thread context from a foreign thread. Something like this by overriding FApplication::processNextEvent. But what do I do with the conditional to wake up the select/getch where the library idles? #include <thread>
#include <mutex>
#include <condition_variable>
class Tcl2FCEvent {
public:
virtual void work() = 0;
};
class MyApp : public FApplication
{
public:
MyApp(const int& argc, char* argv[], bool = false)
: FApplication(argc, argv) {}
void threadQueueEvent (Tcl2FCEvent *event) {
_mutex.lock();
_Q.emplace_back(event);
_mutex.unlock();
_ready.notify_one();
}
private:
bool processNextEvent() override {
if (!_Q.empty()) {
_mutex.lock();
Tcl2FCEvent *event = _Q.front();
_Q.pop_front();
_mutex.unlock();
event->work();
delete event;
}
return FApplication::processNextEvent();
}
std::deque<Tcl2FCEvent *> _Q;
std::mutex _mutex;
std::condition_variable _ready;
}; |
You are right, the method finalcut::FApplication app{argc, argv};
app.setNonBlockingRead(); I use this e.g. in examples/rotozoomer.cpp to realize fast animation in the terminal. |
Oh, that totally changes things. Thanks, I'm understanding your work better. This small change of mine is working so far, but I think I can polish it more as a better interface as I work with FINAL CUT for folks that want to drive the application in alternate ways. --- a/src/include/final/fapplication.h
+++ b/src/include/final/fapplication.h
@@ -132,6 +132,9 @@ class FApplication : public FWidget
// Callback method
void cb_exitApp (const FWidget*, const FDataPtr);
+ protected:
+ virtual bool processNextEvent();
+
private:
// Typedefs
typedef std::pair<FObject*, std::shared_ptr<FEvent> > eventPair;
@@ -177,7 +180,6 @@ class FApplication : public FWidget
void processMouseEvent();
void processResizeEvent();
void processCloseWidget();
- bool processNextEvent();
void performTimerAction (FObject*, FEvent*) override;
static bool isEventProcessable (const FObject*, const FEvent*); |
I have been thinking about your solution to provide external program code to the FINAL CUT queue. I have come to the conclusion that an event is not really a good transport vehicle for code to be executed. An event should be a reaction to a status change of the resources to be monitored. Each state transition triggers an event that calls an event handler in the (focused) widget. The widget can then react to the event. In your case I think the Here is an example: #include <chrono>
#include <thread>
#include <final/final.h>
using namespace finalcut;
// Interface class
class Tcl2FCEvent
{
public:
virtual void work() = 0;
};
// Implementation class
class myTcl2FCEvent final : public Tcl2FCEvent
{
public:
void work() override
{
// Beeps in two seconds
std::this_thread::sleep_for(std::chrono::seconds(2));
FTerm::beep();
}
};
class MyApp : public FApplication
{
public:
MyApp(const int& argc, char* argv[])
: FApplication(argc, argv)
{ }
private:
void onUserEvent (FUserEvent* ev) override
{
auto obj = ev->getData<Tcl2FCEvent*>();
obj->work();
}
};
int main (int argc, char* argv[])
{
MyApp app(argc, argv);
FDialog dialog("Dialog", &app);
dialog.setGeometry (FPoint{25, 5}, FSize{30, 10});
FWidget::setMainWidget(&dialog);
dialog.show();
// Create a user event
int id = 10;
FUserEvent user_event(Event::User, id);
myTcl2FCEvent event_code;
user_event.setData (&event_code);
FApplication::sendEvent (&app, &user_event);
return app.exec();
} Or you could use thread based notification: #include <chrono>
#include <condition_variable>
#include <future>
#include <mutex>
#include <thread>
#include <final/final.h>
using namespace finalcut;
std::condition_variable cond_var;
std::mutex mutex;
bool data_ready{false};
// Interface class
class Tcl2FCEvent
{
public:
virtual void work() = 0;
};
// Implementation class
class myTcl2FCEvent final : public Tcl2FCEvent
{
public:
void work() override
{
std::unique_lock<std::mutex> lock(mutex);
cond_var.wait (lock, []{ return data_ready; });
// Beeps in two seconds
std::this_thread::sleep_for(std::chrono::seconds(2));
FTerm::beep();
}
};
class MyApp : public FApplication
{
public:
MyApp(const int& argc, char* argv[])
: FApplication(argc, argv)
{ }
private:
void onUserEvent (FUserEvent*) override
{
{
std::lock_guard<std::mutex> lock(mutex);
data_ready = true;
}
cond_var.notify_one();
}
};
int fc_app (int argc, char* argv[])
{
MyApp app(argc, argv);
FDialog dialog("Dialog", &app);
dialog.setGeometry (FPoint{25, 5}, FSize{30, 10});
FWidget::setMainWidget(&dialog);
dialog.show();
// Create a user event
int id = 10;
FUserEvent user_event(Event::User, id);
FApplication::sendEvent (&app, &user_event);
// Start the application
return app.exec();
}
int main (int argc, char* argv[])
{
myTcl2FCEvent event_code;
std::thread t1(&Tcl2FCEvent::work, &event_code);
auto app = [&] (std::promise<int>&& p, int argc, char* argv[])
{
p.set_value(fc_app(argc,argv));
};
std::promise<int> p;
auto f = p.get_future();
std::thread t2(app, std::move(p), argc, argv);
t1.join();
t2.join();
return f.get();
} Last modified: Code changes for the new scoped enumeration data types |
Thank you for the examples. That's inverted from my usage, though. I would use events to come into FC, not leave it. In other words, while the UI might be idle from mouse moves or keyboard events, I want the scripting language to come into FC to call routines that it can't directly from the scripting thread. work() is used for calling FC routines in the FC thread (main thread), not where the threading takes place. From work(), I'll want to do something with the UI, like create a dialog |
I really must thank you for drawing my attention to the event queue. There's been a pretty nasty bug in it. I made a FEvent from every event via std::make_shared() and removed all attributes of the inherited classes. I have now fixed this in the last commit (f20e036). As for your problem, I think I now know what kind of implementation you are looking for: #include <chrono>
#include <condition_variable>
#include <future>
#include <mutex>
#include <thread>
#include <final/final.h>
using namespace finalcut;
std::condition_variable cond_var;
std::mutex mutex;
int user_event_id{-1};
// Interface class
class Tcl2FCEvent
{
public:
virtual void work(std::future<void>) = 0;
};
// Implementation class
class myTcl2FCEvent final : public Tcl2FCEvent
{
public:
void work (std::future<void> f) override
{
int color_value{0};
std::this_thread::sleep_for(std::chrono::milliseconds(250));
while ( f.wait_for(std::chrono::milliseconds(1)) == std::future_status::timeout )
{
std::this_thread::sleep_for(std::chrono::milliseconds(250));
{
std::lock_guard<std::mutex> lock(mutex);
user_event_id = color_value;
}
cond_var.notify_one();
color_value++;
color_value %= 16;
}
}
};
class MyApp : public FApplication
{
public:
MyApp(const int& argc, char* argv[])
: FApplication(argc, argv)
{
t2 = std::thread(&MyApp::wait, this, std::move(t2_future));
}
~MyApp()
{
t2_exit.set_value(); // Stop thread t2
t2.join(); // Wait until the thread has finished
}
void wait (std::future<void> f)
{
int id{};
while ( f.wait_for(std::chrono::milliseconds(1)) == std::future_status::timeout )
{
{
std::unique_lock<std::mutex> lock(mutex);
cond_var.wait (lock, []{ return ( user_event_id >= 0 ); });
id = user_event_id;
user_event_id = -1;
FUserEvent user_event(Event::User, id);
queueEvent (this, &user_event);
}
}
}
void onUserEvent (FUserEvent* ev) override
{
auto color = FColor(ev->getUserId());
getActiveWindow()->setBackgroundColor(color);
getActiveWindow()->redraw();
}
private:
std::thread t2{};
std::promise<void> t2_exit;
std::future<void> t2_future{t2_exit.get_future()};
};
int main (int argc, char* argv[])
{
MyApp app(argc, argv);
FDialog dialog("Dialog", &app);
dialog.setGeometry (FPoint{25, 5}, FSize{30, 10});
FLabel label("Colorful thread", &dialog);
label.setGeometry (FPoint{6, 3}, FSize{17, 3});
label.setAlignment(Align::Center);
FButton quit_button("&Quit", &dialog);
quit_button.setGeometry (FPoint{10, 6}, FSize{10, 1});
quit_button.addCallback
(
"clicked",
getFApplication(),
&FApplication::cb_exitApp,
&dialog
);
FWidget::setMainWidget(&dialog);
dialog.show();
myTcl2FCEvent ext_event;
std::promise<void> t1_exit;
std::future<void> t1_future{t1_exit.get_future()};
std::thread t1(&Tcl2FCEvent::work, &ext_event, std::move(t1_future));
int ret = app.exec();
t1_exit.set_value(); // Stop thread t2
t1.join(); // Wait until the thread has finished
return ret;
} Last modified: Code changes for the new scoped enumeration data types |
Thank you for the code example. I've been offline for a while. I built the sample last night, but it's apparent I need to update FC git and rebuild for it to work. Nice. queueEvent() is thread-safe? |
I forgot to tell you that the (A small application example: Using a user event) |
what is threads ? |
I was talking about POSIX threads (pthreads), the parallel processing of different code parts. |
Hi Gansm, |
Markus Gans, I am really impressed of the work you have done! In comparision with dialog/newt-snack/ncurses/npyscreen it is like a breath of fresh air. Congratulations and please continue.
I think your library will get more attention if there is a place where users (like me) can ask questions, ask for advices, etc. What shall it be? A mail list? A web forum? Probably the easiest solution (it does not require anything to setup) is to use Stackoverflow with [final-cut] tag?!
The text was updated successfully, but these errors were encountered: