diff --git a/.gitignore b/.gitignore index ae7c1ae6..fbb1211b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea *.a *.o *.os diff --git a/CMakeLists.txt b/CMakeLists.txt index c0af7209..84716551 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,12 +20,16 @@ option( SFGUI_BUILD_EXAMPLES "Build examples." option( SFGUI_BUILD_DOC "Generate API documentation." OFF) option( SFGUI_INCLUDE_FONT "Include default font in library (DejaVuSans)." ON) option( SFML_STATIC_LIBRARIES "Do you want to link SFML statically?" OFF) +option( SFGUI_BOOST_FILESYSTEM_SUPPORT "Do you want SFGUI to support Boost.FileSystem? (enable FilePickerDialog widget)" OFF) # Find packages. find_package( OpenGL REQUIRED ) find_package( SFML 2.5 REQUIRED COMPONENTS graphics window system ) +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/include/SFGUI/Config.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/include/SFGUI/Config.hpp) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) + set( INCLUDE_PATH "${PROJECT_SOURCE_DIR}/include/" ) set( SOURCE_PATH "${PROJECT_SOURCE_DIR}/src/" ) @@ -59,6 +63,11 @@ endif() target_link_libraries( ${TARGET} PUBLIC sfml-graphics sfml-window sfml-system ${OPENGL_gl_LIBRARY} ) +# Link to Boost.FileSystem if enabled +if( SFGUI_BOOST_FILESYSTEM_SUPPORT ) + target_link_libraries( sfgui ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ) +endif() + # Tell the compiler to export when necessary. set_target_properties( ${TARGET} PROPERTIES DEFINE_SYMBOL SFGUI_EXPORTS ) @@ -115,7 +124,7 @@ elseif( APPLE ) IMPORTED_LOCATION "${COREFOUNDATION_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "/System/Library/Frameworks/CoreFoundation.framework/Headers" ) - + target_link_libraries( ${TARGET} PUBLIC CoreFoundation ) set( SHARE_PATH "${CMAKE_INSTALL_PREFIX}/share/SFGUI" ) set( LIB_PATH "lib" ) @@ -165,6 +174,11 @@ install( DESTINATION include ) +install( + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include + DESTINATION . +) + install( FILES README.md AUTHORS.md LICENSE.md FONT.LICENSE.md CHANGELOG.md DESTINATION "${SHARE_PATH}" diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b966d5c2..d7edba36 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -38,8 +38,15 @@ build_example( "ProgressBar" "ProgressBar.cpp" ) build_example( "SpinButton" "SpinButton.cpp" ) build_example( "Canvas" "Canvas.cpp" ) build_example( "CustomWidget" "CustomWidget.cpp" ) +build_example( "ListBox" "ListBox.cpp" ) build_example( "SFGUI-Test" "Test.cpp" ) +if( SFGUI_BOOST_FILESYSTEM_SUPPORT ) + build_example( "FilePickerDialog" "FilePickerDialog.cpp" ) + include_directories( SYSTEM ${Boost_INCLUDE_DIR} ) + target_link_libraries( FilePickerDialog ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ) +endif() + # Copy data directory to build cache directory to be able to run examples from # there. Useful for testing stuff. # Don't try to copy if the directories are the same. @@ -49,13 +56,13 @@ if( NOT ( "${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}" ) ) COMMAND "${CMAKE_COMMAND}" ARGS -E copy_directory "${PROJECT_SOURCE_DIR}/examples/data" "${PROJECT_BINARY_DIR}/examples/data" ) - + add_custom_command( TARGET "Image" COMMAND "${CMAKE_COMMAND}" ARGS -E copy_directory "${PROJECT_SOURCE_DIR}/examples/data" "${PROJECT_BINARY_DIR}/examples/data" ) - + add_custom_command( TARGET "Canvas" COMMAND "${CMAKE_COMMAND}" diff --git a/examples/CustomWidget.cpp b/examples/CustomWidget.cpp index 49b6b980..9ab1beaa 100644 --- a/examples/CustomWidget.cpp +++ b/examples/CustomWidget.cpp @@ -96,7 +96,7 @@ class MyCustomWidget : public sfg::Widget { 5.f, inverted_color, background_color, - 20.f + 20 ) ); @@ -120,7 +120,7 @@ class MyCustomWidget : public sfg::Widget { 255 ), inner_border_color, - 20.f + 20 ) ); diff --git a/examples/FilePickerDialog.cpp b/examples/FilePickerDialog.cpp new file mode 100644 index 00000000..115196dd --- /dev/null +++ b/examples/FilePickerDialog.cpp @@ -0,0 +1,88 @@ +// Always include the necessary header files. +// Including SFGUI/Widgets.hpp includes everything +// you can possibly need automatically. +#include +#include + +#include + +int main() { + // Create the main SFML window + sf::RenderWindow app_window( sf::VideoMode( 800, 600 ), "SFGUI Window Example", sf::Style::Titlebar | sf::Style::Close ); + + // We have to do this because we don't use SFML to draw. + app_window.resetGLStates(); + + // Create an SFGUI. This is required before doing anything with SFGUI. + sfg::SFGUI sfgui; + + // Create our main SFGUI window + + // Almost everything in SFGUI is handled through smart pointers + // for automatic resource management purposes. You create them + // and they will automatically be destroyed when the time comes. + + // Creation of widgets is always done with it's Create() method + // which will return a smart pointer owning the new widget. + auto window = sfg::FilePickerDialog::Create( "/home/victor" ); + + // Here we can set the window's title bar text. + window->SetTitle( "A really really really really long title" ); + + window->GetSignal( sfg::FilePickerDialog::OnCancel ).Connect( + []() + { + std::cout << "Path selection cancelled !" << std::endl; + } + ); + window->GetSignal( sfg::FilePickerDialog::OnOk ).Connect( + [window]() + { + std::cout << "Selected path : \"" << window->GetSelectedPath().toAnsiString() << "\"" << std::endl; + } + ); + + // For more things to set around the window refer to the + // API documentation. + + // Start the game loop + while ( app_window.isOpen() ) { + // Process events + sf::Event event; + + while ( app_window.pollEvent( event ) ) { + // Every frame we have to send SFML events to the window + // to enable user interactivity. Without doing this your + // GUI is nothing but a big colorful picture ;) + window->HandleEvent( event ); + + // Close window : exit + if ( event.type == sf::Event::Closed ) { + app_window.close(); + } + } + + // Update the GUI, note that you shouldn't normally + // pass 0 seconds to the update method. + window->Update( 0.f ); + + // Clear screen + app_window.clear(); + + // After drawing the rest of your game, you have to let the GUI + // render itself. If you don't do this you will never be able + // to see it ;) + sfgui.Display( app_window ); + + // NOTICE + // Because the window doesn't have any children it will shrink to + // it's minimum size of (0,0) resulting in you not seeing anything + // except the title bar text ;) Don't worry, in the Label example + // you'll get to see more. + + // Update the window + app_window.display(); + } + + return EXIT_SUCCESS; +} diff --git a/examples/ListBox.cpp b/examples/ListBox.cpp new file mode 100644 index 00000000..38574fd9 --- /dev/null +++ b/examples/ListBox.cpp @@ -0,0 +1,138 @@ +// Always include the necessary header files. +// Including SFGUI/Widgets.hpp includes everything +// you can possibly need automatically. +#include +#include + +#include + +int main() { + sfg::SFGUI sfgui; + sf::RenderWindow window(sf::VideoMode(800, 600), "ListBox Example"); + window.setVerticalSyncEnabled(true); + window.setFramerateLimit(30); + + sf::Image firstImage; + firstImage.loadFromFile("data/add.png"); + + sf::Image secondImage; + secondImage.loadFromFile("data/delete.png"); + + sfg::Desktop desktop; + + auto window1 = sfg::Window::Create(); + window1->SetTitle( "ListBox with ItemTextPolicy::RESIZE_LISTBOX" ); + + auto box1 = sfg::Box::Create( sfg::Box::Orientation::VERTICAL ); + box1->SetSpacing( 5.f ); + box1->PackEnd( sfg::Label::Create( "The minimum width\nof this ListBox\ncorresponds to the largest\nitem's text width." ), false, true ); + + auto listbox1 = sfg::ListBox::Create(); + listbox1->AppendItem( "This is the first item" ); + listbox1->AppendItem( "Second item" ); + listbox1->AppendItem( "Third item which is a bit large" ); + listbox1->AppendItem( "Fourth item" ); + listbox1->AppendItem( "Fifth item" ); + listbox1->AppendItem( "Sixth item" ); + listbox1->AppendItem( "Last one !" ); + box1->PackEnd( listbox1 ); + listbox1->SetImagesSize(sf::Vector2f(32.f, 32.f)); + + window1->Add( box1 ); + + auto window2 = sfg::Window::Create(); + window2->SetTitle( "ListBox with ItemTextPolicy::SHRINK" ); + + auto box2 = sfg::Box::Create( sfg::Box::Orientation::VERTICAL ); + box2->SetSpacing( 5.f ); + auto label2 = sfg::Label::Create( "The items' texts\nare shrinked if the\nListBox is not big\nenough." ); + box2->PackEnd( label2, false, true ); + + auto listbox2 = sfg::ListBox::Create(); + listbox2->AppendItem( "This is the first item (long text)" ); + listbox2->AppendItem( "Second item", firstImage ); + listbox2->AppendItem( "Third item which is very long !", secondImage ); + listbox2->AppendItem( "Fourth item" ); + listbox2->AppendItem( "Fifth item" ); + listbox2->AppendItem( "Sixth item, again it's too large !" ); + listbox2->AppendItem( "Last one !" ); + listbox2->SetItemTextPolicy( sfg::ListBox::ItemTextPolicy::SHRINK ); + box2->PackEnd( listbox2 ); + listbox2->SetImagesSize(sf::Vector2f(32.f, 32.f)); + + window2->Add( box2 ); + + auto window3 = sfg::Window::Create(); + window3->SetTitle( "ListBox with ItemTextPolicy::SHRINK" ); + + auto box3 = sfg::Box::Create( sfg::Box::Orientation::VERTICAL ); + box3->SetSpacing( 5.f ); + auto label3 = sfg::Label::Create( "You can select multiple\nitems in this ListBox." ); + box3->PackEnd( label3, false, true ); + + auto listbox3 = sfg::ListBox::Create(); + listbox3->AppendItem( "First item" ); + listbox3->AppendItem( "Second item" ); + listbox3->AppendItem( "Third item" ); + listbox3->AppendItem( "Fourth item" ); + listbox3->AppendItem( "Fifth item" ); + listbox3->AppendItem( "Sixth item" ); + listbox3->AppendItem( "Last one !" ); + listbox3->SetSelectionMode( sfg::ListBox::SelectionMode::MULTI_SELECTION ); + listbox3->SetSelection( {1, 3, 4, 5} ); + box3->PackEnd( listbox3 ); + + window3->Add( box3 ); + + desktop.Add( window1 ); + desktop.Add( window2 ); + desktop.Add( window3 ); + + sf::Vector2f windowSize( static_cast( window.getSize().x ), static_cast( window.getSize().y ) ); + + window2->SetPosition(sf::Vector2f(windowSize.x/2.f - window2->GetRequisition().x/2.f, windowSize.y/2.f - window2->GetRequisition().y/2.f)); + window3->SetPosition(sf::Vector2f(windowSize.x - window3->GetRequisition().x - 100.f, windowSize.y - window3->GetRequisition().y - 100.f)); + + sf::Event event; + sf::Clock clock; + + window.resetGLStates(); + + int i = 0; + + while (window.isOpen()) + { + while (window.pollEvent(event)) + { + desktop.HandleEvent( event ); + switch(event.type) + { + case sf::Event::Closed: + window.close(); + break; + case sf::Event::KeyPressed: + if( event.key.code == sf::Keyboard::R ) { + listbox3->RemoveItem(2); + } else if( event.key.code == sf::Keyboard::I ) { + listbox3->InsertItem(3, "Inserted item #" + std::to_string(i)); + ++i; + } else if( event.key.code == sf::Keyboard::A) { + listbox3->AppendItem("Appended item #" + std::to_string(i)); + ++i; + } else if( event.key.code == sf::Keyboard::P) { + listbox3->PrependItem("Prepended item #" + std::to_string(i)); + ++i; + } + break; + default: + break; + } + } + desktop.Update( clock.restart().asSeconds() ); + window.clear(); + sfgui.Display( window ); + window.display(); + } + + return 0; +} diff --git a/include/SFGUI/Button.hpp b/include/SFGUI/Button.hpp index f2ed9c8a..048563d5 100644 --- a/include/SFGUI/Button.hpp +++ b/include/SFGUI/Button.hpp @@ -13,6 +13,16 @@ class Image; */ class SFGUI_API Button : public Bin { public: + enum Alignment { + CENTER, + LEFT = 0x1, + RIGHT = 0x2, + TOP = 0x4, + BOTTOM = 0x8, + HORIZONTAL = LEFT + RIGHT, + VERTICAL = TOP + BOTTOM, + }; + typedef std::shared_ptr