diff --git a/private/play/wizard/CMakeLists.txt b/private/play/wizard/CMakeLists.txt new file mode 100644 index 0000000..8a8fdfd --- /dev/null +++ b/private/play/wizard/CMakeLists.txt @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION 3.12) + +project( + wintc-wizard-test + VERSION 1.0 + DESCRIPTION "Windows Total Conversion 'Hello World' application." + LANGUAGES C +) + +set(PROJECT_ANYARCH false) +set(PROJECT_FREESTATUS true) +set(PROJECT_MAINTAINER "Rory Fewell ") + +set(PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR}) + +include(GNUInstallDirs) + +include(../../../packaging/cmake-inc/common/CMakeLists.txt) +include(../../../packaging/cmake-inc/linking/CMakeLists.txt) +include(../../../packaging/cmake-inc/packaging/CMakeLists.txt) +include(../../../packaging/cmake-inc/resources/CMakeLists.txt) + +wintc_resolve_library(glib-2.0 GLIB) +wintc_resolve_library(gtk+-3.0 GTK3) +wintc_resolve_library(wintc-comctl WINTC_COMCTL) +wintc_resolve_library(wintc-comgtk WINTC_COMGTK) +wintc_resolve_library(wintc-wizard97 WINTC_WIZARD97) + +wintc_compile_resources() + +add_executable( + wintc-wizard-test + src/application.c + src/application.h + src/main.c + src/resources.c + src/window.c + src/window.h +) + +target_compile_options( + wintc-wizard-test + PRIVATE ${WINTC_COMPILE_OPTIONS} +) + +target_include_directories( + wintc-wizard-test + SYSTEM + PRIVATE ${GLIB_INCLUDE_DIRS} + PRIVATE ${GTK3_INCLUDE_DIRS} + PRIVATE ${WINTC_COMCTL_INCLUDE_DIRS} + PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS} + PRIVATE ${WINTC_WIZARD97_INCLUDE_DIRS} +) + +target_link_directories( + wintc-wizard-test + PRIVATE ${GLIB_LIBRARY_DIRS} + PRIVATE ${GTK3_LIBRARY_DIRS} + PRIVATE ${WINTC_COMCTL_LIBRARY_DIRS} + PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS} + PRIVATE ${WINTC_WIZARD97_LIBRARY_DIRS} +) + +target_link_libraries( + wintc-wizard-test + PRIVATE ${GLIB_LIBRARIES} + PRIVATE ${GTK3_LIBRARIES} + PRIVATE ${WINTC_COMCTL_LIBRARIES} + PRIVATE ${WINTC_COMGTK_LIBRARIES} + PRIVATE ${WINTC_WIZARD97_LIBRARIES} +) + +# Installation +# +wintc_configure_and_install_packaging() +wintc_install_icons_into_package() + +install( + FILES wintc-wizard-test.desktop + DESTINATION share/applications +) +install( + TARGETS wintc-wizard-test + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/private/play/wizard/README.MD b/private/play/wizard/README.MD new file mode 100644 index 0000000..9b814dd --- /dev/null +++ b/private/play/wizard/README.MD @@ -0,0 +1,5 @@ +# wizard +This directory contains the source code for the sample wizard. + +Image +Image diff --git a/private/play/wizard/deps b/private/play/wizard/deps new file mode 100644 index 0000000..41159d4 --- /dev/null +++ b/private/play/wizard/deps @@ -0,0 +1,5 @@ +bt,rt:glib2 +bt,rt:gtk3 +bt,rt:wintc-comctl +bt,rt:wintc-comgtk +bt,rt:wintc-wizard97 diff --git a/private/play/wizard/icons/16x16/wintc-wizard-test.png b/private/play/wizard/icons/16x16/wintc-wizard-test.png new file mode 100644 index 0000000..3c117bc Binary files /dev/null and b/private/play/wizard/icons/16x16/wintc-wizard-test.png differ diff --git a/private/play/wizard/icons/32x32/wintc-wizard-test.png b/private/play/wizard/icons/32x32/wintc-wizard-test.png new file mode 100644 index 0000000..44289d7 Binary files /dev/null and b/private/play/wizard/icons/32x32/wintc-wizard-test.png differ diff --git a/private/play/wizard/src/application.c b/private/play/wizard/src/application.c new file mode 100644 index 0000000..662b26d --- /dev/null +++ b/private/play/wizard/src/application.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include + +#include "application.h" +#include "window.h" + +// +// GTK OOP CLASS/INSTANCE DEFINITIONS +// +struct _WinTCWizardApplicationClass +{ + GtkApplicationClass __parent__; +}; + +struct _WinTCWizardApplication +{ + GtkApplication __parent__; +}; + +// +// FORWARD DECLARATIONS +// +static void wintc_wizard_application_activate( + GApplication* application +); +static void wintc_wizard_application_startup( + GApplication* application +); + +// +// GTK TYPE DEFINITIONS & CTORS +// +G_DEFINE_TYPE( + WinTCWizardApplication, + wintc_wizard_application, + GTK_TYPE_APPLICATION +) + +static void wintc_wizard_application_class_init( + WinTCWizardApplicationClass* klass +) +{ + GApplicationClass* application_class = G_APPLICATION_CLASS(klass); + + application_class->activate = wintc_wizard_application_activate; + application_class->startup = wintc_wizard_application_startup; +} + +static void wintc_wizard_application_init( + WINTC_UNUSED(WinTCWizardApplication* self) +) { } + +// +// CLASS VIRTUAL METHODS +// +static void wintc_wizard_application_activate( + GApplication* application +) +{ + GtkWidget* new_window = + wintc_wizard_window_new(WINTC_WIZARD_APPLICATION(application)); + + gtk_widget_show_all(new_window); +} + +static void wintc_wizard_application_startup( + GApplication* application +) +{ + (G_APPLICATION_CLASS(wintc_wizard_application_parent_class)) + ->startup(application); + + wintc_ctl_install_default_styles(); +} + +// +// PUBLIC FUNCTIONS +// +WinTCWizardApplication* wintc_wizard_application_new(void) +{ + return WINTC_WIZARD_APPLICATION( + g_object_new( + wintc_wizard_application_get_type(), + "application-id", "uk.oddmatics.wintc.play.wizard", + NULL + ) + ); +} diff --git a/private/play/wizard/src/application.h b/private/play/wizard/src/application.h new file mode 100644 index 0000000..b84cc0d --- /dev/null +++ b/private/play/wizard/src/application.h @@ -0,0 +1,25 @@ +#ifndef __APPLICATION_H__ +#define __APPLICATION_H__ + +#include +#include + +// +// GTK OOP BOILERPLATE +// +#define WINTC_TYPE_WIZARD_APPLICATION (wintc_wizard_application_get_type()) + +G_DECLARE_FINAL_TYPE( + WinTCWizardApplication, + wintc_wizard_application, + WINTC, + WIZARD_APPLICATION, + GtkApplication +) + +// +// PUBLIC FUNCTIONS +// +WinTCWizardApplication* wintc_wizard_application_new(void); + +#endif diff --git a/private/play/wizard/src/main.c b/private/play/wizard/src/main.c new file mode 100644 index 0000000..56054f8 --- /dev/null +++ b/private/play/wizard/src/main.c @@ -0,0 +1,20 @@ +#include + +#include "application.h" + +int main( + int argc, + char* argv[] +) +{ + WinTCWizardApplication* app = wintc_wizard_application_new(); + int status; + + g_set_application_name("Wizard"); + + status = g_application_run(G_APPLICATION(app), argc, argv); + + g_object_unref(app); + + return status; +} diff --git a/private/play/wizard/src/res/header.png b/private/play/wizard/src/res/header.png new file mode 100644 index 0000000..32c7d6e Binary files /dev/null and b/private/play/wizard/src/res/header.png differ diff --git a/private/play/wizard/src/res/resources.xml b/private/play/wizard/src/res/resources.xml new file mode 100644 index 0000000..1d76ffb --- /dev/null +++ b/private/play/wizard/src/res/resources.xml @@ -0,0 +1,11 @@ + + + + header.png + watermk.png + wizpg1.ui + wizpg2.ui + wizpg3.ui + wizpg4.ui + + diff --git a/private/play/wizard/src/res/watermk.png b/private/play/wizard/src/res/watermk.png new file mode 100644 index 0000000..3a40ca9 Binary files /dev/null and b/private/play/wizard/src/res/watermk.png differ diff --git a/private/play/wizard/src/res/wizpg1.ui b/private/play/wizard/src/res/wizpg1.ui new file mode 100644 index 0000000..469df67 --- /dev/null +++ b/private/play/wizard/src/res/wizpg1.ui @@ -0,0 +1,47 @@ + + + + True + False + Welcome + Welcome to the test wizard. + True + vertical + + + + Welcome to the Sample Test Wizard + True + False + 25 + True + 0.0 + + + + + False + False + 0 + + + + + + This wizard guides you in the process of doing nothing, achieving nothing, and ultimately reaching enlightenment. + True + False + 25 + True + 0.0 + + + False + False + 1 + + + + diff --git a/private/play/wizard/src/res/wizpg2.ui b/private/play/wizard/src/res/wizpg2.ui new file mode 100644 index 0000000..d524510 --- /dev/null +++ b/private/play/wizard/src/res/wizpg2.ui @@ -0,0 +1,27 @@ + + + + True + False + Welcome + Welcome to the test wizard. + True + vertical + + + + This is a second exterior page, a bit like the Hardware Update Wizard uses. + True + False + 25 + True + 0.0 + + + False + False + 0 + + + + diff --git a/private/play/wizard/src/res/wizpg3.ui b/private/play/wizard/src/res/wizpg3.ui new file mode 100644 index 0000000..b02ae32 --- /dev/null +++ b/private/play/wizard/src/res/wizpg3.ui @@ -0,0 +1,64 @@ + + + + True + False + Page 2 + This is page two. + vertical + + + + Please select which one of these you think is better: + True + False + 25 + True + 0.0 + + + + + False + False + 0 + + + + + + Apples + True + True + + + + + False + False + 1 + + + + + Oranges + True + True + radio-apples + + + + + False + False + 2 + + + + diff --git a/private/play/wizard/src/res/wizpg4.ui b/private/play/wizard/src/res/wizpg4.ui new file mode 100644 index 0000000..277ad7e --- /dev/null +++ b/private/play/wizard/src/res/wizpg4.ui @@ -0,0 +1,66 @@ + + + + True + False + Finished + Completing the test wizard. + True + vertical + + + + Completing the Sample Test Wizard + True + False + 0.0 + + + + + False + False + 0 + + + + + + The Sample Test Wizard is now complete! + +You have managed to: + True + False + 25 + True + 0.0 + + + False + False + 1 + + + + + + True + False + 25 + True + 0.0 + + + + + False + False + 2 + + + + diff --git a/private/play/wizard/src/window.c b/private/play/wizard/src/window.c new file mode 100644 index 0000000..3e48024 --- /dev/null +++ b/private/play/wizard/src/window.c @@ -0,0 +1,261 @@ +#include +#include +#include +#include + +#include "application.h" +#include "window.h" + +// +// PRIVATE ENUMS +// +enum +{ + PROP_NULL, + PROP_CAN_HELP, + N_PROPERTIES +}; + +enum +{ + WIZPAGE_INTRO, + WIZPAGE_INTRO2, + WIZPAGE_DECISION, + WIZPAGE_FINISHED +}; + +enum +{ + DECISION_APPLES, + DECISION_ORANGES +}; + +// +// FORWARD DECLARATIONS +// +static void wintc_wizard_window_get_property( + GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec +); + +static void wintc_wizard_window_constructing_page( + WinTCWizard97Window* wiz_wnd, + guint page_num, + GtkBuilder* builder +); +static guint wintc_wizard_window_get_next_page( + WinTCWizard97Window* wiz_wnd, + guint current_page +); +static void wintc_wizard_window_help( + WinTCWizard97Window* wiz_wnd, + guint current_page +); + +// +// GTK OOP CLASS/INSTANCE DEFINITIONS +// +struct _WinTCWizardWindowClass +{ + WinTCWizard97WindowClass __parent__; +}; + +struct _WinTCWizardWindow +{ + WinTCWizard97Window __parent__; + + // UI stuff + // + GtkWidget* radio_apples; + GtkWidget* label_done_prefer; +}; + +// +// GTK TYPE DEFINITION & CTORS +// +G_DEFINE_TYPE( + WinTCWizardWindow, + wintc_wizard_window, + WINTC_TYPE_WIZARD97_WINDOW +) + +static void wintc_wizard_window_class_init( + WinTCWizardWindowClass* klass +) +{ + GObjectClass* object_class = G_OBJECT_CLASS(klass); + WinTCWizard97WindowClass* wizard_class = + WINTC_WIZARD97_WINDOW_CLASS(klass); + + wizard_class->constructing_page = wintc_wizard_window_constructing_page; + wizard_class->get_next_page = wintc_wizard_window_get_next_page; + wizard_class->help = wintc_wizard_window_help; + object_class->get_property = wintc_wizard_window_get_property; + + g_object_class_override_property( + object_class, + PROP_CAN_HELP, + "can-help" + ); + + wintc_wizard97_window_class_setup_from_resources( + wizard_class, + "/uk/oddmatics/wintc/play/wizard/watermk.png", + "/uk/oddmatics/wintc/play/wizard/header.png", + "/uk/oddmatics/wintc/play/wizard/wizpg1.ui", + "/uk/oddmatics/wintc/play/wizard/wizpg2.ui", + "/uk/oddmatics/wintc/play/wizard/wizpg3.ui", + "/uk/oddmatics/wintc/play/wizard/wizpg4.ui", + NULL + ); +} + +static void wintc_wizard_window_init( + WinTCWizardWindow* self +) +{ + wintc_wizard97_window_init_wizard( + WINTC_WIZARD97_WINDOW(self) + ); +} + +// +// CLASS VIRTUAL METHODS +// +static void wintc_wizard_window_get_property( + GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec +) +{ + switch (prop_id) + { + case PROP_CAN_HELP: + g_value_set_boolean(value, TRUE); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void wintc_wizard_window_constructing_page( + WinTCWizard97Window* wiz_wnd, + guint page_num, + GtkBuilder* builder +) +{ + WinTCWizardWindow* swiz_wnd = WINTC_WIZARD_WINDOW(wiz_wnd); + + switch (page_num) + { + case WIZPAGE_DECISION: + wintc_builder_get_objects( + builder, + "radio-apples", &(swiz_wnd->radio_apples), + NULL + ); + + break; + + case WIZPAGE_FINISHED: + wintc_builder_get_objects( + builder, + "label-done-prefer", &(swiz_wnd->label_done_prefer), + NULL + ); + + break; + + default: break; + } +} + +static guint wintc_wizard_window_get_next_page( + WinTCWizard97Window* wiz_wnd, + guint current_page +) +{ + WinTCWizardWindow* swiz_wnd = WINTC_WIZARD_WINDOW(wiz_wnd); + + guint next_page = current_page + 1; + + switch (next_page) + { + case WIZPAGE_FINISHED: + { + guint idx_prefer; + const gchar* text_prefer_item; + gchar* text_prefer; + + idx_prefer = + wintc_radio_group_get_selection( + gtk_radio_button_get_group( + GTK_RADIO_BUTTON(swiz_wnd->radio_apples) + ) + ); + + switch (idx_prefer) + { + case DECISION_APPLES: text_prefer_item = "apples"; break; + case DECISION_ORANGES: text_prefer_item = "oranges"; break; + } + + text_prefer = + g_strdup_printf( + "Decide that %s are better.", + text_prefer_item + ); + + gtk_label_set_text( + GTK_LABEL(swiz_wnd->label_done_prefer), + text_prefer + ); + + g_free(text_prefer); + + break; + } + + default: break; + } + + return + (WINTC_WIZARD97_WINDOW_CLASS(wintc_wizard_window_parent_class)) + ->get_next_page(wiz_wnd, current_page); +} + +static void wintc_wizard_window_help( + WinTCWizard97Window* wiz_wnd, + WINTC_UNUSED(guint current_page) +) +{ + wintc_messagebox_show( + GTK_WINDOW(wiz_wnd), + "And this is where I'd display the help dialog... IF I HAD ONE!", + "Help", + GTK_BUTTONS_OK, + GTK_MESSAGE_ERROR + ); +} + +// +// PUBLIC FUNCTIONS +// +GtkWidget* wintc_wizard_window_new( + WinTCWizardApplication* app +) +{ + return GTK_WIDGET( + g_object_new( + WINTC_TYPE_WIZARD_WINDOW, + "application", GTK_APPLICATION(app), + "title", "My Sample Wizard", + NULL + ) + ); +} diff --git a/private/play/wizard/src/window.h b/private/play/wizard/src/window.h new file mode 100644 index 0000000..e758723 --- /dev/null +++ b/private/play/wizard/src/window.h @@ -0,0 +1,30 @@ +#ifndef __WINDOW_H__ +#define __WINDOW_H__ + +#include +#include +#include + +#include "application.h" + +// +// GTK OOP BOILERPLATE +// +#define WINTC_TYPE_WIZARD_WINDOW (wintc_wizard_window_get_type()) + +G_DECLARE_FINAL_TYPE( + WinTCWizardWindow, + wintc_wizard_window, + WINTC, + WIZARD_WINDOW, + WinTCWizard97Window +) + +// +// PUBLIC FUNCTIONS +// +GtkWidget* wintc_wizard_window_new( + WinTCWizardApplication* app +); + +#endif diff --git a/private/play/wizard/wintc-wizard-test.desktop b/private/play/wizard/wintc-wizard-test.desktop new file mode 100644 index 0000000..4a04fa9 --- /dev/null +++ b/private/play/wizard/wintc-wizard-test.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=Hello (WinTC Sample) +Comment=WinTC demonstration hello program. +Exec=wintc-hello +Icon=wintc-hello +Terminal=false +StartupNotify=false +Type=Application +Categories=Utility;GTK; diff --git a/shared/comctl/src/menubind.c b/shared/comctl/src/menubind.c index d8fce1e..358a804 100644 --- a/shared/comctl/src/menubind.c +++ b/shared/comctl/src/menubind.c @@ -167,7 +167,8 @@ static void wintc_ctl_menu_binding_constructed( WinTCCtlMenuBinding* menu_binding = WINTC_CTL_MENU_BINDING(object); wintc_container_clear( - GTK_CONTAINER(menu_binding->menu_shell) + GTK_CONTAINER(menu_binding->menu_shell), + TRUE ); wintc_ctl_menu_binding_track_menu( diff --git a/shared/comctl/src/res/default.css b/shared/comctl/src/res/default.css index ab8d1ff..6d00d8e 100644 --- a/shared/comctl/src/res/default.css +++ b/shared/comctl/src/res/default.css @@ -55,3 +55,26 @@ box.vertical.wintc-button-box button:last-child { margin-bottom: 0px; } + +/** + * Edges + */ +.wintc-edge-bottom +{ + border-bottom: 1px solid @borders; +} + +.wintc-edge-left +{ + border-left: 1px solid @borders; +} + +.wintc-edge-right +{ + border-right: 1px solid @borders; +} + +.wintc-edge-top +{ + border-top: 1px solid @borders; +} diff --git a/shared/comgtk/CMakeLists.txt b/shared/comgtk/CMakeLists.txt index 6840a0b..92a3a17 100644 --- a/shared/comgtk/CMakeLists.txt +++ b/shared/comgtk/CMakeLists.txt @@ -70,6 +70,8 @@ add_library( public/msgbox.h src/profile.c public/profile.h + src/radio.c + public/radio.h src/regex.c public/regex.h public/shorthand.h diff --git a/shared/comgtk/public/container.h b/shared/comgtk/public/container.h index 31e8d99..f4fbd7c 100644 --- a/shared/comgtk/public/container.h +++ b/shared/comgtk/public/container.h @@ -13,9 +13,11 @@ * Destroys all child widgets of a container. * * @param container The container. + * @param destroy True to destroy, rather than just remove, the children. */ void wintc_container_clear( - GtkContainer* container + GtkContainer* container, + gboolean destroy ); /** diff --git a/shared/comgtk/public/libapi.h.in b/shared/comgtk/public/libapi.h.in index 653bec7..e4bea3e 100644 --- a/shared/comgtk/public/libapi.h.in +++ b/shared/comgtk/public/libapi.h.in @@ -21,6 +21,7 @@ #include "@LIB_HEADER_DIR@/menu.h" #include "@LIB_HEADER_DIR@/msgbox.h" #include "@LIB_HEADER_DIR@/profile.h" +#include "@LIB_HEADER_DIR@/radio.h" #include "@LIB_HEADER_DIR@/regex.h" #include "@LIB_HEADER_DIR@/shorthand.h" #include "@LIB_HEADER_DIR@/signals.h" diff --git a/shared/comgtk/public/radio.h b/shared/comgtk/public/radio.h new file mode 100644 index 0000000..201edb4 --- /dev/null +++ b/shared/comgtk/public/radio.h @@ -0,0 +1,19 @@ +#ifndef __COMGTK_RADIO_H__ +#define __COMGTK_RADIO_H__ + +#include + +// +// PUBLIC FUNCTIONS +// + +/** + * Retrieve the index of the active selection in a radio button group. + * + * @param group The radio button group. + */ +guint wintc_radio_group_get_selection( + GSList* group +); + +#endif diff --git a/shared/comgtk/src/container.c b/shared/comgtk/src/container.c index 4208c09..aaed670 100644 --- a/shared/comgtk/src/container.c +++ b/shared/comgtk/src/container.c @@ -7,17 +7,29 @@ // PUBLIC FUNCTIONS // void wintc_container_clear( - GtkContainer* container + GtkContainer* container, + gboolean destroy ) { GList* children = gtk_container_get_children(container); GList* iter = children; - while (iter) + if (destroy) { - gtk_widget_destroy(GTK_WIDGET(iter->data)); - - iter = iter->next; + for (; iter; iter = iter->next) + { + gtk_widget_destroy(GTK_WIDGET(iter->data)); + } + } + else + { + for (; iter; iter = iter->next) + { + gtk_container_remove( + container, + GTK_WIDGET(iter->data) + ); + } } g_list_free(children); diff --git a/shared/comgtk/src/radio.c b/shared/comgtk/src/radio.c new file mode 100644 index 0000000..281ef3a --- /dev/null +++ b/shared/comgtk/src/radio.c @@ -0,0 +1,31 @@ +#include +#include + +#include "../public/radio.h" + +// +// PUBLIC FUNCTIONS +// +guint wintc_radio_group_get_selection( + GSList* group +) +{ + GSList* iter = group; + + for (guint i = 0; iter; iter = iter->next, i++) + { + if ( + gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(iter->data) + ) + ) + { + // From GtkBuilder, it's in reverse + // + return g_slist_length(group) - i - 1; + } + } + + g_critical("%s", "comgtk: no radio in group was active"); + return 0; +} diff --git a/shared/wizard97/CMakeLists.txt b/shared/wizard97/CMakeLists.txt new file mode 100644 index 0000000..1e802c6 --- /dev/null +++ b/shared/wizard97/CMakeLists.txt @@ -0,0 +1,87 @@ +cmake_minimum_required(VERSION 3.12) + +project( + libwintc-wizard97 + VERSION 1.0 + DESCRIPTION "Windows Total Conversion wizard UI library." + LANGUAGES C +) + +set(PROJECT_ANYARCH false) +set(PROJECT_FREESTATUS true) +set(PROJECT_MAINTAINER "Rory Fewell ") + +set(PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR}) + +include(GNUInstallDirs) + +include(../../packaging/cmake-inc/common/CMakeLists.txt) +include(../../packaging/cmake-inc/libraries/CMakeLists.txt) +include(../../packaging/cmake-inc/linking/CMakeLists.txt) +include(../../packaging/cmake-inc/packaging/CMakeLists.txt) +include(../../packaging/cmake-inc/resources/CMakeLists.txt) + +wintc_resolve_library(gdk-pixbuf-2.0 GDK_PIXBUF) +wintc_resolve_library(glib-2.0 GLIB) +wintc_resolve_library(gtk+-3.0 GTK3) +wintc_resolve_library(wintc-comgtk WINTC_COMGTK) + +wintc_compile_resources() + +add_library( + libwintc-wizard97 + src/resources.c + src/wizpage.c + public/wizpage.h + src/wizwnd.c + public/wizwnd.h +) + +set_target_properties( + libwintc-wizard97 + PROPERTIES + SOVERSION 1 + VERSION ${PROJECT_VERSION} +) + +target_compile_options( + libwintc-wizard97 + PRIVATE ${WINTC_COMPILE_OPTIONS} +) + +target_include_directories( + libwintc-wizard97 + SYSTEM + BEFORE + PRIVATE ${GDK_PIXBUF_INCLUDE_DIRS} + PRIVATE ${GLIB_INCLUDE_DIRS} + PRIVATE ${GTK3_INCLUDE_DIRS} + PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS} +) + +target_link_directories( + libwintc-wizard97 + PRIVATE ${GDK_PIXBUF_LIBRARY_DIRS} + PRIVATE ${GLIB_LIBRARY_DIRS} + PRIVATE ${GTK3_LIBRARY_DIRS} + PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS} +) + +target_link_libraries( + libwintc-wizard97 + PRIVATE ${GDK_PIXBUF_LIBRARIES} + PRIVATE ${GLIB_LIBRARIES} + PRIVATE ${GTK3_LIBRARIES} + PRIVATE ${WINTC_COMGTK_LIBRARIES} +) + +# Installation +# +wintc_configure_and_install_packaging() +wintc_add_pkgconfig_install() +wintc_install_public_headers() + +install( + TARGETS libwintc-wizard97 + LIBRARY DESTINATION ${LIB_DIR} +) diff --git a/shared/wizard97/README.MD b/shared/wizard97/README.MD new file mode 100644 index 0000000..8dd6518 --- /dev/null +++ b/shared/wizard97/README.MD @@ -0,0 +1,5 @@ +# libwintc-wizard97 +This directory contains the source code for the wizard library. + +## Purpose +This library is essentially a GTK-ised version of wizard97, used for making the nice looking wizards in Windows 2000 and XP. diff --git a/shared/wizard97/deps b/shared/wizard97/deps new file mode 100644 index 0000000..7e95f86 --- /dev/null +++ b/shared/wizard97/deps @@ -0,0 +1,4 @@ +bt,rt:gdk-pixbuf2 +bt,rt:glib2 +bt,rt:gtk3 +bt,rt:wintc-comgtk diff --git a/shared/wizard97/public/libapi.h.in b/shared/wizard97/public/libapi.h.in new file mode 100644 index 0000000..2211ee6 --- /dev/null +++ b/shared/wizard97/public/libapi.h.in @@ -0,0 +1,6 @@ +#ifndef __WINTC_WIZARD97_H__ +#define __WINTC_WIZARD97_H__ + +#include "@LIB_HEADER_DIR@/wizwnd.h" + +#endif diff --git a/shared/wizard97/public/wizpage.h b/shared/wizard97/public/wizpage.h new file mode 100644 index 0000000..76d5351 --- /dev/null +++ b/shared/wizard97/public/wizpage.h @@ -0,0 +1,41 @@ +#ifndef __WIZARD97_WIZPAGE_H__ +#define __WIZARD97_WIZPAGE_H__ + +#include +#include + +// +// GTK OOP BOILERPLATE +// +#define WINTC_TYPE_WIZARD97_PAGE (wintc_wizard97_page_get_type()) + +G_DECLARE_DERIVABLE_TYPE( + WinTCWizard97Page, + wintc_wizard97_page, + WINTC, + WIZARD97_PAGE, + GtkBox +) + +struct _WinTCWizard97PageClass +{ + GtkBoxClass __parent__; +}; + +// +// PUBLIC FUNCTIONS +// +gboolean wintc_wizard97_page_get_is_exterior_page( + WinTCWizard97Page* wiz_page +); +gboolean wintc_wizard97_page_get_is_final_page( + WinTCWizard97Page* wiz_page +); +const gchar* wintc_wizard97_page_get_subtitle( + WinTCWizard97Page* wiz_page +); +const gchar* wintc_wizard97_page_get_title( + WinTCWizard97Page* wiz_page +); + +#endif diff --git a/shared/wizard97/public/wizwnd.h b/shared/wizard97/public/wizwnd.h new file mode 100644 index 0000000..3fbb22d --- /dev/null +++ b/shared/wizard97/public/wizwnd.h @@ -0,0 +1,70 @@ +#ifndef __WIZARD97_WIZWND_H__ +#define __WIZARD97_WIZWND_H__ + +#include +#include + +// +// GTK OOP BOILERPLATE +// +#define WINTC_TYPE_WIZARD97_WINDOW (wintc_wizard97_window_get_type()) + +G_DECLARE_DERIVABLE_TYPE( + WinTCWizard97Window, + wintc_wizard97_window, + WINTC, + WIZARD97_WINDOW, + GtkWindow +) + +struct _WinTCWizard97WindowClass +{ + GtkWindowClass __parent__; + + // Wizard stuff + // + gchar* resource_watermark; + gchar* resource_header; + + GList* list_resources_pages; + + // Vfuncs + // + gboolean (*cancel) ( + WinTCWizard97Window* wiz_wnd, + guint current_page + ); + void (*constructing_page) ( + WinTCWizard97Window* wiz_wnd, + guint page_num, + GtkBuilder* builder + ); + gboolean (*finish) ( + WinTCWizard97Window* wiz_wnd, + guint current_page + ); + guint (*get_next_page) ( + WinTCWizard97Window* wiz_wnd, + guint current_page + ); + void (*help) ( + WinTCWizard97Window* wiz_wnd, + guint current_page + ); +}; + +// +// PUBLIC FUNCTIONS +// +void wintc_wizard97_window_class_setup_from_resources( + WinTCWizard97WindowClass* wizard_class, + const gchar* resource_watermark, + const gchar* resource_header, + ... +); + +void wintc_wizard97_window_init_wizard( + WinTCWizard97Window* wiz_wnd +); + +#endif diff --git a/shared/wizard97/src/res/default.css b/shared/wizard97/src/res/default.css new file mode 100644 index 0000000..db65be7 --- /dev/null +++ b/shared/wizard97/src/res/default.css @@ -0,0 +1,40 @@ +/** + * Default wizard97-specific styles + */ +.wintc-w97-title +{ + font-weight: bold; +} + +.wintc-w97-header +{ + background-color: @theme_base_color; + font-family: 'Microsoft Sans Serif', sans-serif; +} + +.wintc-w97-page-area +{ + font-family: 'Microsoft Sans Serif', sans-serif; +} + +.wintc-w97-header .wintc-w97-title +{ + margin-left: 18px; + margin-top: 8px; +} + +.wintc-w97-header .wintc-w97-subtitle +{ + margin-left: 25px +} + +.wintc-w97-exterior .wintc-w97-page-area +{ + background-color: @theme_base_color; +} + +.wintc-w97-page-area .wintc-w97-title +{ + font-size: 13pt; + margin: 8px 0px; +} diff --git a/shared/wizard97/src/res/default_p.css b/shared/wizard97/src/res/default_p.css new file mode 100644 index 0000000..05275b4 --- /dev/null +++ b/shared/wizard97/src/res/default_p.css @@ -0,0 +1,19 @@ +/** + * Default wizard97 priority styles + */ + +/** Unfortunately padding is app priority, because of #249 */ +.wintc-w97-header +{ + padding: 5px; +} + +.wintc-w97-exterior .wintc-w97-page-area +{ + padding: 8px; +} + +.wintc-w97-interior .wintc-w97-page-area +{ + padding: 12px 12px 12px 42px; +} diff --git a/shared/wizard97/src/res/resources.xml b/shared/wizard97/src/res/resources.xml new file mode 100644 index 0000000..3a5a326 --- /dev/null +++ b/shared/wizard97/src/res/resources.xml @@ -0,0 +1,10 @@ + + + + default.css + default_p.css + wizext.ui + wizint.ui + wizwnd.ui + + diff --git a/shared/wizard97/src/res/wizext.ui b/shared/wizard97/src/res/wizext.ui new file mode 100644 index 0000000..2aafff8 --- /dev/null +++ b/shared/wizard97/src/res/wizext.ui @@ -0,0 +1,42 @@ + + + + True + False + horizontal + + + + False + False + + + False + False + 0 + + + + + + False + False + vertical + + + + + True + True + 1 + + + + + + diff --git a/shared/wizard97/src/res/wizint.ui b/shared/wizard97/src/res/wizint.ui new file mode 100644 index 0000000..3a8d971 --- /dev/null +++ b/shared/wizard97/src/res/wizint.ui @@ -0,0 +1,106 @@ + + + + True + False + vertical + + + + True + False + horizontal + + + + True + False + vertical + + + + This is a title + True + False + 0.0 + + + + + False + False + 0 + + + + + And this is a subtitle + True + False + 0.0 + + + + + False + False + 1 + + + + + True + True + 0 + + + + + False + False + + + False + False + 1 + + + + + + + False + False + 0 + + + + + + False + False + vertical + + + + + True + True + 1 + + + + + + diff --git a/shared/wizard97/src/res/wizwnd.ui b/shared/wizard97/src/res/wizwnd.ui new file mode 100644 index 0000000..9fcc2e2 --- /dev/null +++ b/shared/wizard97/src/res/wizwnd.ui @@ -0,0 +1,125 @@ + + + + True + False + vertical + + + + True + False + vertical + + + + + True + True + 0 + + + + + True + False + horizontal + + + + Help + + True + True + win.help + + + False + False + end + 0 + + + + + + Cancel + True + True + True + win.cancel + + + False + False + end + 1 + + + + + + Finish + + True + True + win.next + + + False + False + end + 2 + + + + + + Next > + + True + True + win.next + + + False + False + end + 3 + + + + + + < Back + True + True + True + win.back + + + False + False + end + 4 + + + + + + + False + False + 1 + + + + diff --git a/shared/wizard97/src/wizpage.c b/shared/wizard97/src/wizpage.c new file mode 100644 index 0000000..ea48b89 --- /dev/null +++ b/shared/wizard97/src/wizpage.c @@ -0,0 +1,258 @@ +#include +#include +#include + +#include "../public/wizpage.h" + +// +// PRIVATE ENUMS +// +enum +{ + PROP_NULL, + PROP_TITLE, + PROP_SUBTITLE, + PROP_IS_FINAL_PAGE, + PROP_IS_EXTERIOR_PAGE, + N_PROPERTIES +}; + +// +// FORWARD DECLARATIONS +// +static void wintc_wizard97_page_finalize( + GObject* object +); +static void wintc_wizard97_page_get_property( + GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec +); +static void wintc_wizard97_page_set_property( + GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec +); + +// +// STATIC DATA +// +static GParamSpec* wintc_wizard97_page_properties[N_PROPERTIES] = { 0 }; + +// +// GTK OOP CLASS/INSTANCE DEFINITIONS +// +typedef struct _WinTCWizard97PagePrivate +{ + gchar* title; + gchar* subtitle; + gboolean is_final_page; + gboolean is_exterior_page; +} WinTCWizard97PagePrivate; + +// +// GTK TYPE DEFINITIONS & CTORS +// +G_DEFINE_TYPE_WITH_PRIVATE( + WinTCWizard97Page, + wintc_wizard97_page, + GTK_TYPE_BOX +) + +static void wintc_wizard97_page_class_init( + WinTCWizard97PageClass* klass +) +{ + GObjectClass* object_class = G_OBJECT_CLASS(klass); + + object_class->finalize = wintc_wizard97_page_finalize; + object_class->get_property = wintc_wizard97_page_get_property; + object_class->set_property = wintc_wizard97_page_set_property; + + wintc_wizard97_page_properties[PROP_TITLE] = + g_param_spec_string( + "title", + "Title", + "The title of the page.", + NULL, + G_PARAM_READWRITE + ); + wintc_wizard97_page_properties[PROP_SUBTITLE] = + g_param_spec_string( + "subtitle", + "Subtitle", + "The subtitle of the page.", + NULL, + G_PARAM_READWRITE + ); + wintc_wizard97_page_properties[PROP_IS_FINAL_PAGE] = + g_param_spec_boolean( + "is-final-page", + "IsFinalPage", + "Determines whether this is a final page in the wizard.", + FALSE, + G_PARAM_READWRITE + ); + wintc_wizard97_page_properties[PROP_IS_EXTERIOR_PAGE] = + g_param_spec_boolean( + "is-exterior-page", + "IsExteriorPage", + "Determines whether this is an exterior page.", + FALSE, + G_PARAM_READWRITE + ); + + g_object_class_install_properties( + object_class, + N_PROPERTIES, + wintc_wizard97_page_properties + ); +} + +static void wintc_wizard97_page_init( + WINTC_UNUSED(WinTCWizard97Page* self) +) {} + +// +// CLASS VIRTUAL METHODS +// +static void wintc_wizard97_page_finalize( + GObject* object +) +{ + WinTCWizard97PagePrivate* priv = + wintc_wizard97_page_get_instance_private( + WINTC_WIZARD97_PAGE(object) + ); + + g_free(priv->title); + g_free(priv->subtitle); + + (G_OBJECT_CLASS(wintc_wizard97_page_parent_class)) + ->finalize(object); +} + +static void wintc_wizard97_page_get_property( + GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec +) +{ + WinTCWizard97PagePrivate* priv = + wintc_wizard97_page_get_instance_private( + WINTC_WIZARD97_PAGE(object) + ); + + switch (prop_id) + { + case PROP_TITLE: + g_value_set_string(value, priv->title); + break; + + case PROP_SUBTITLE: + g_value_set_string(value, priv->subtitle); + break; + + case PROP_IS_FINAL_PAGE: + g_value_set_boolean(value, priv->is_final_page); + break; + + case PROP_IS_EXTERIOR_PAGE: + g_value_set_boolean(value, priv->is_exterior_page); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void wintc_wizard97_page_set_property( + GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec +) +{ + WinTCWizard97PagePrivate* priv = + wintc_wizard97_page_get_instance_private( + WINTC_WIZARD97_PAGE(object) + ); + + switch (prop_id) + { + case PROP_TITLE: + priv->title = g_value_dup_string(value); + break; + + case PROP_SUBTITLE: + priv->subtitle = g_value_dup_string(value); + break; + + case PROP_IS_FINAL_PAGE: + priv->is_final_page = g_value_get_boolean(value); + break; + + case PROP_IS_EXTERIOR_PAGE: + priv->is_exterior_page = g_value_get_boolean(value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +// +// PUBLIC FUNCTIONS +// +gboolean wintc_wizard97_page_get_is_exterior_page( + WinTCWizard97Page* wiz_page +) +{ + WinTCWizard97PagePrivate* priv = + wintc_wizard97_page_get_instance_private( + wiz_page + ); + + return priv->is_exterior_page; +} + +gboolean wintc_wizard97_page_get_is_final_page( + WinTCWizard97Page* wiz_page +) +{ + WinTCWizard97PagePrivate* priv = + wintc_wizard97_page_get_instance_private( + wiz_page + ); + + return priv->is_final_page; +} + +const gchar* wintc_wizard97_page_get_subtitle( + WinTCWizard97Page* wiz_page +) +{ + WinTCWizard97PagePrivate* priv = + wintc_wizard97_page_get_instance_private( + wiz_page + ); + + return priv->subtitle; +} + +const gchar* wintc_wizard97_page_get_title( + WinTCWizard97Page* wiz_page +) +{ + WinTCWizard97PagePrivate* priv = + wintc_wizard97_page_get_instance_private( + wiz_page + ); + + return priv->title; +} diff --git a/shared/wizard97/src/wizwnd.c b/shared/wizard97/src/wizwnd.c new file mode 100644 index 0000000..e71f6b6 --- /dev/null +++ b/shared/wizard97/src/wizwnd.c @@ -0,0 +1,1136 @@ +#include +#include +#include +#include +#include +#include + +#include "../public/wizpage.h" +#include "../public/wizwnd.h" + +#define WIZARD97_WATERMARK_WIDTH 164 +#define WIZARD97_WATERMARK_HEIGHT 314 + +#define WIZARD97_HEADERPIC_SIZE 49 + +#define WIZARD97_PAGE_NUM_FINAL 171717 + +// +// PRIVATE ENUMS +// +enum +{ + PROP_NULL, + PROP_CAN_CANCEL, + PROP_CAN_PREV, + PROP_CAN_NEXT, + PROP_CAN_HELP, + PROP_FINAL_PAGE, + N_PROPERTIES +}; + +// +// FORWARD DECLARATIONS +// +static void wintc_wizard97_window_dispose( + GObject* object +); +static void wintc_wizard97_window_finalize( + GObject* object +); +static void wintc_wizard97_window_get_property( + GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec +); +static void wintc_wizard97_window_set_property( + GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec +); + +static gboolean wintc_wizard97_window_cancel( + WinTCWizard97Window* wiz_wnd, + guint current_page +); +static void wintc_wizard97_window_constructing_page( + WinTCWizard97Window* wiz_wnd, + guint page_num, + GtkBuilder* builder +); +static gboolean wintc_wizard97_window_finish( + WinTCWizard97Window* wiz_wnd, + guint current_page +); +static guint wintc_wizard97_window_get_next_page( + WinTCWizard97Window* wiz_wnd, + guint current_page +); +static void wintc_wizard97_window_help( + WinTCWizard97Window* wiz_wnd, + guint current_page +); + +static GtkBuilder* wintc_wizard97_window_create_builder( + WinTCWizard97Window* wiz_wnd +); +static GtkWidget* wintc_wizard97_window_create_page( + WinTCWizard97Window* wiz_wnd, + const gchar* resource_path, + guint page_num +); +static GtkWidget* wintc_wizard97_window_get_page( + WinTCWizard97Window* wiz_wnd, + guint page_num +); +static void wintc_wizard97_window_go_to_page( + WinTCWizard97Window* wiz_wnd, + guint page_num, + gboolean push_history +); +static gboolean wintc_wizard97_window_is_on_final_page( + WinTCWizard97Window* wiz_wnd +); + +static void action_back( + GSimpleAction* action, + GVariant* parameter, + gpointer user_data +); +static void action_cancel( + GSimpleAction* action, + GVariant* parameter, + gpointer user_data +); +static void action_help( + GSimpleAction* action, + GVariant* parameter, + gpointer user_data +); +static void action_next( + GSimpleAction* action, + GVariant* parameter, + gpointer user_data +); + +static gboolean on_window_map_event( + GtkWidget* widget, + GdkEvent* event, + gpointer user_data +); + +// +// STATIC DATA +// +static GParamSpec* wintc_wizard97_window_properties[N_PROPERTIES] = { 0 }; + +static const GActionEntry S_ACTIONS[] = { + { + .name = "back", + .activate = action_back, + .parameter_type = NULL, + .state = NULL, + .change_state = NULL + }, + { + .name = "cancel", + .activate = action_cancel, + .parameter_type = NULL, + .state = NULL, + .change_state = NULL + }, + { + .name = "help", + .activate = action_help, + .parameter_type = NULL, + .state = NULL, + .change_state = NULL + }, + { + .name = "next", + .activate = action_next, + .parameter_type = NULL, + .state = NULL, + .change_state = NULL + } +}; +static const gchar* S_ACTION_BINDINGS[] = { + "back", "can-prev", + "cancel", "can-cancel", + "help", "can-help", + "next", "can-next" +}; + +// +// GTK OOP CLASS/INSTANCE DEFINITIONS +// +typedef struct _WinTCWizard97WindowPrivate +{ + // State + // + guint current_page; + GSList* history; + + // UI stuff + // + GtkWidget* box_page_area; + + GtkWidget* box_tmpl_ext_page_area; + GtkWidget* box_tmpl_int_page_area; + GtkWidget* img_ext_watermark; + GtkWidget* img_int_header; + GtkWidget* label_int_subtitle; + GtkWidget* label_int_title; + + // Stuff we maintain an additional ref to + // + GdkPixbuf* pixbuf_watermark; + GdkPixbuf* pixbuf_header; + + GList* list_pages; + + GtkWidget* box_tmpl_ext_page; + GtkWidget* box_tmpl_int_page; +} WinTCWizard97WindowPrivate; + +// +// GTK TYPE DEFINITIONS & CTORS +// +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE( + WinTCWizard97Window, + wintc_wizard97_window, + GTK_TYPE_WINDOW +) + +static void wintc_wizard97_window_class_init( + WinTCWizard97WindowClass* klass +) +{ + GObjectClass* object_class = G_OBJECT_CLASS(klass); + + klass->cancel = wintc_wizard97_window_cancel; + klass->constructing_page = wintc_wizard97_window_constructing_page; + klass->finish = wintc_wizard97_window_finish; + klass->help = wintc_wizard97_window_help; + klass->get_next_page = wintc_wizard97_window_get_next_page; + object_class->dispose = wintc_wizard97_window_dispose; + object_class->finalize = wintc_wizard97_window_finalize; + object_class->get_property = wintc_wizard97_window_get_property; + object_class->set_property = wintc_wizard97_window_set_property; + + // Install properties + // + wintc_wizard97_window_properties[PROP_CAN_CANCEL] = + g_param_spec_boolean( + "can-cancel", + "CanCancel", + "Determines whether it is possible to cancel the wizard.", + TRUE, + G_PARAM_READABLE + ); + wintc_wizard97_window_properties[PROP_CAN_PREV] = + g_param_spec_boolean( + "can-prev", + "CanPrev", + "Determines whether it is possible go backward in the wizard.", + TRUE, + G_PARAM_READABLE + ); + wintc_wizard97_window_properties[PROP_CAN_NEXT] = + g_param_spec_boolean( + "can-next", + "CanNext", + "Determines whether it is possible to proceed in the wizard.", + TRUE, + G_PARAM_READABLE + ); + wintc_wizard97_window_properties[PROP_CAN_HELP] = + g_param_spec_boolean( + "can-help", + "CanHelp", + "Determines whether it is possible to get help.", + FALSE, + G_PARAM_READABLE + ); + wintc_wizard97_window_properties[PROP_FINAL_PAGE] = + g_param_spec_boolean( + "final-page", + "FinalPage", + "Determines whether the wizard is on a final page.", + FALSE, + G_PARAM_READABLE + ); + + g_object_class_install_properties( + object_class, + N_PROPERTIES, + wintc_wizard97_window_properties + ); + + // Load styles + // + GtkCssProvider* css_default = gtk_css_provider_new(); + GtkCssProvider* css_default_p = gtk_css_provider_new(); + + gtk_css_provider_load_from_resource( + css_default, + "/uk/oddmatics/wintc/wizard97/default.css" + ); + gtk_css_provider_load_from_resource( + css_default_p, + "/uk/oddmatics/wintc/wizard97/default_p.css" + ); + + gtk_style_context_add_provider_for_screen( + gdk_screen_get_default(), + GTK_STYLE_PROVIDER(css_default), + GTK_STYLE_PROVIDER_PRIORITY_FALLBACK + ); + gtk_style_context_add_provider_for_screen( + gdk_screen_get_default(), + GTK_STYLE_PROVIDER(css_default_p), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + ); +} + +static void wintc_wizard97_window_init( + WINTC_UNUSED(WinTCWizard97Window* self) +) {} + +// +// CLASS VIRTUAL METHODS +// +static void wintc_wizard97_window_dispose( + GObject* object +) +{ + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private( + WINTC_WIZARD97_WINDOW(object) + ); + + g_clear_object(&(priv->pixbuf_watermark)); + g_clear_object(&(priv->pixbuf_header)); + g_clear_list( + &(priv->list_pages), + (GDestroyNotify) g_object_unref + ); + + (G_OBJECT_CLASS(wintc_wizard97_window_parent_class)) + ->dispose(object); +} + +static void wintc_wizard97_window_finalize( + GObject* object +) +{ + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private( + WINTC_WIZARD97_WINDOW(object) + ); + + g_slist_free( + g_steal_pointer(&(priv->history)) + ); + + (G_OBJECT_CLASS(wintc_wizard97_window_parent_class)) + ->finalize(object); +} + +static void wintc_wizard97_window_get_property( + GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec +) +{ + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private( + WINTC_WIZARD97_WINDOW(object) + ); + + switch (prop_id) + { + case PROP_CAN_CANCEL: + g_value_set_boolean(value, TRUE); + break; + + case PROP_CAN_PREV: + g_value_set_boolean(value, !!(priv->history)); + break; + + case PROP_CAN_NEXT: + g_value_set_boolean(value, TRUE); + break; + + case PROP_CAN_HELP: + g_value_set_boolean(value, FALSE); + break; + + case PROP_FINAL_PAGE: + g_value_set_boolean( + value, + wintc_wizard97_window_is_on_final_page( + WINTC_WIZARD97_WINDOW(object) + ) + ); + + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void wintc_wizard97_window_set_property( + GObject* object, + guint prop_id, + WINTC_UNUSED(const GValue* value), + GParamSpec* pspec +) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static gboolean wintc_wizard97_window_cancel( + WINTC_UNUSED(WinTCWizard97Window* wiz_wnd), + WINTC_UNUSED(guint current_page) +) +{ + return TRUE; +} + +static void wintc_wizard97_window_constructing_page( + WINTC_UNUSED(WinTCWizard97Window* wiz_wnd), + WINTC_UNUSED(guint page_num), + WINTC_UNUSED(GtkBuilder* builder) +) {} + +static gboolean wintc_wizard97_window_finish( + WINTC_UNUSED(WinTCWizard97Window* wiz_wnd), + WINTC_UNUSED(guint current_page) +) +{ + return TRUE; +} + +static guint wintc_wizard97_window_get_next_page( + WinTCWizard97Window* wiz_wnd, + guint current_page +) +{ + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private(wiz_wnd); + + if (current_page + 1 >= g_list_length(priv->list_pages)) + { + return WIZARD97_PAGE_NUM_FINAL; + } + + return current_page + 1; +} + +static void wintc_wizard97_window_help( + WINTC_UNUSED(WinTCWizard97Window* wiz_wnd), + WINTC_UNUSED(guint current_page) +) {} + +// +// PUBLIC FUNCTIONS +// +void wintc_wizard97_window_class_setup_from_resources( + WinTCWizard97WindowClass* wizard_class, + const gchar* resource_watermark, + const gchar* resource_header, + ... +) +{ + va_list ap; + gchar* next_res; + + wizard_class->resource_watermark = g_strdup(resource_watermark); + wizard_class->resource_header = g_strdup(resource_header); + + va_start(ap, resource_header); + + next_res = va_arg(ap, gchar*); + + while (next_res) + { + wizard_class->list_resources_pages = + g_list_append( + wizard_class->list_resources_pages, + g_strdup(next_res) + ); + + next_res = va_arg(ap, gchar*); + } + + va_end(ap); +} + +void wintc_wizard97_window_init_wizard( + WinTCWizard97Window* wiz_wnd +) +{ + WinTCWizard97WindowClass* wizard_class = + WINTC_WIZARD97_WINDOW_GET_CLASS(wiz_wnd); + + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private( + WINTC_WIZARD97_WINDOW(wiz_wnd) + ); + + GtkBuilder* builder; + GError* error = NULL; + + g_type_ensure(WINTC_TYPE_WIZARD97_PAGE); + + // General GtkWindow setup + // + gtk_window_set_resizable(GTK_WINDOW(wiz_wnd), FALSE); + + // Add actions + // + GSimpleActionGroup* action_group = g_simple_action_group_new(); + + g_action_map_add_action_entries( + G_ACTION_MAP(action_group), + S_ACTIONS, + G_N_ELEMENTS(S_ACTIONS), + wiz_wnd + ); + + for (gsize i = 0; i < G_N_ELEMENTS(S_ACTION_BINDINGS); i += 2) + { + const gchar* action_name = S_ACTION_BINDINGS[i]; + const gchar* property_name = S_ACTION_BINDINGS[i + 1]; + + GAction* action = + g_action_map_lookup_action( + G_ACTION_MAP(action_group), + action_name + ); + + g_object_bind_property( + wiz_wnd, + property_name, + action, + "enabled", + G_BINDING_SYNC_CREATE + ); + } + + gtk_widget_insert_action_group( + GTK_WIDGET(wiz_wnd), + "win", + G_ACTION_GROUP(action_group) + ); + + g_object_unref(action_group); + + // External page template + // + builder = + gtk_builder_new_from_resource( + "/uk/oddmatics/wintc/wizard97/wizext.ui" + ); + + wintc_builder_get_objects( + builder, + "main-box", &(priv->box_tmpl_ext_page), + "box-page", &(priv->box_tmpl_ext_page_area), + "img-watermark", &(priv->img_ext_watermark), + NULL + ); + + g_object_ref(priv->box_tmpl_ext_page); + + g_clear_object(&builder); + + // Internal page template + // + builder = + gtk_builder_new_from_resource( + "/uk/oddmatics/wintc/wizard97/wizint.ui" + ); + + wintc_builder_get_objects( + builder, + "main-box", &(priv->box_tmpl_int_page), + "box-page", &(priv->box_tmpl_int_page_area), + "img-header", &(priv->img_int_header), + "label-subtitle", &(priv->label_int_subtitle), + "label-title", &(priv->label_int_title), + NULL + ); + + g_object_ref(priv->box_tmpl_int_page); + + g_clear_object(&builder); + + // Iterate over internal pages + // + GList* iter = wizard_class->list_resources_pages; + + for (guint i = 0; iter; iter = iter->next, i++) + { + GtkWidget* page = + wintc_wizard97_window_create_page( + wiz_wnd, + (gchar*) iter->data, + i + ); + + if (!page) + { + i--; + continue; + } + + if ( + wintc_wizard97_page_get_is_exterior_page( + WINTC_WIZARD97_PAGE(page) + ) + ) + { + gtk_widget_set_size_request( + page, + 317, + 193 + ); + } + else + { + gtk_widget_set_size_request( + page, + 317, + 143 + ); + } + + priv->list_pages = + g_list_append( + priv->list_pages, + page + ); + } + + // Pixbufs + // + if (wizard_class->resource_watermark) + { + GdkPixbuf* pixbuf_watermark_src = + gdk_pixbuf_new_from_resource( + wizard_class->resource_watermark, + &error + ); + + if (pixbuf_watermark_src) + { + priv->pixbuf_watermark = + gdk_pixbuf_scale_simple( + pixbuf_watermark_src, + WIZARD97_WATERMARK_WIDTH, + WIZARD97_WATERMARK_HEIGHT, + GDK_INTERP_NEAREST + ); + + g_object_unref(pixbuf_watermark_src); + + gtk_image_set_from_pixbuf( + GTK_IMAGE(priv->img_ext_watermark), + priv->pixbuf_watermark + ); + } + else + { + gtk_widget_set_size_request( + priv->img_ext_watermark, + WIZARD97_WATERMARK_WIDTH, + WIZARD97_WATERMARK_HEIGHT + ); + + wintc_log_error_and_clear(&error); + } + } + + if (wizard_class->resource_header) + { + GdkPixbuf* pixbuf_header_src = + gdk_pixbuf_new_from_resource( + wizard_class->resource_header, + &error + ); + + if (pixbuf_header_src) + { + priv->pixbuf_header = + gdk_pixbuf_scale_simple( + pixbuf_header_src, + WIZARD97_HEADERPIC_SIZE, + WIZARD97_HEADERPIC_SIZE, + GDK_INTERP_NEAREST + ); + + g_object_unref(pixbuf_header_src); + + gtk_image_set_from_pixbuf( + GTK_IMAGE(priv->img_int_header), + priv->pixbuf_header + ); + } + else + { + gtk_widget_set_size_request( + priv->img_int_header, + WIZARD97_HEADERPIC_SIZE, + WIZARD97_HEADERPIC_SIZE + ); + + wintc_log_error_and_clear(&error); + } + } + + // Set up the window + // + builder = gtk_builder_new(); + + gtk_builder_expose_object( + builder, + "wizard", + G_OBJECT(wiz_wnd) + ); + + gtk_builder_add_from_resource( + builder, + "/uk/oddmatics/wintc/wizard97/wizwnd.ui", + NULL + ); + + priv->box_page_area = + GTK_WIDGET( + gtk_builder_get_object(builder, "box-page-area") + ); + + gtk_container_add( + GTK_CONTAINER(wiz_wnd), + GTK_WIDGET( + gtk_builder_get_object(builder, "main-box") + ) + ); + + g_clear_object(&builder); + + // Unify page sizes - load each page, figure out the largest size, and make + // that our size request so the window doesn't grow/shrink between pages + // + GtkRequisition req; + GtkRequisition req_largest; + + iter = priv->list_pages; + + for (guint i = 0; iter; iter = iter->next, i++) + { + wintc_wizard97_window_go_to_page( + wiz_wnd, + i, + FALSE + ); + + gtk_widget_get_preferred_size( + priv->box_page_area, + NULL, + &req + ); + + req_largest.width = MAX(req_largest.width, req.width); + req_largest.height = MAX(req_largest.height, req.height); + } + + gtk_widget_set_size_request( + priv->box_page_area, + req_largest.width, + req_largest.height + ); + + // Connect to map event to finish start up after being shown + // + g_signal_connect( + wiz_wnd, + "map-event", + G_CALLBACK(on_window_map_event), + NULL + ); +} + +// +// PRIVATE FUNCTIONS +// +static GtkBuilder* wintc_wizard97_window_create_builder( + WinTCWizard97Window* wiz_wnd +) +{ + GtkBuilder* builder = gtk_builder_new(); + + gtk_builder_expose_object( + builder, + "wizard", + G_OBJECT(wiz_wnd) + ); + + return builder; +} + +static GtkWidget* wintc_wizard97_window_create_page( + WinTCWizard97Window* wiz_wnd, + const gchar* resource_path, + guint page_num +) +{ + WinTCWizard97WindowClass* wiz_class = + WINTC_WIZARD97_WINDOW_GET_CLASS(wiz_wnd); + + GtkBuilder* builder = wintc_wizard97_window_create_builder(wiz_wnd); + GError* error = NULL; + GtkWidget* ret = NULL; + + if ( + gtk_builder_add_from_resource( + builder, + resource_path, + &error + ) + ) + { + ret = GTK_WIDGET(gtk_builder_get_object(builder, "page")); + + if (!WINTC_IS_WIZARD97_PAGE(ret)) + { + g_critical( + "wizard97: the resource at %s doesn't have a 'page'", + resource_path + ); + } + + wiz_class->constructing_page( + wiz_wnd, + page_num, + builder + ); + + g_object_ref(ret); + } + else + { + wintc_log_error_and_clear(&error); + } + + g_object_unref(builder); + + return ret; +} + +static GtkWidget* wintc_wizard97_window_get_page( + WinTCWizard97Window* wiz_wnd, + guint page_num +) +{ + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private( + WINTC_WIZARD97_WINDOW(wiz_wnd) + ); + + return GTK_WIDGET( + g_list_nth_data( + priv->list_pages, + page_num + ) + ); +} + +static void wintc_wizard97_window_go_to_page( + WinTCWizard97Window* wiz_wnd, + guint page_num, + gboolean push_history +) +{ + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private( + WINTC_WIZARD97_WINDOW(wiz_wnd) + ); + + // Remove any existing page from view + // + GtkWidget* page_current = + wintc_wizard97_window_get_page( + wiz_wnd, + priv->current_page + ); + + if (gtk_widget_get_parent(page_current)) + { + gtk_container_remove( + GTK_CONTAINER(gtk_widget_get_parent(page_current)), + page_current + ); + } + + wintc_container_clear( + GTK_CONTAINER(priv->box_page_area), + FALSE + ); + + // Retrieve the boxes we need + // + GtkWidget* box_template; + GtkWidget* box_template_page_area; + GtkWidget* page_next; + + page_next = + wintc_wizard97_window_get_page( + wiz_wnd, + page_num + ); + + if ( + wintc_wizard97_page_get_is_exterior_page( + WINTC_WIZARD97_PAGE(page_next) + ) + ) + { + box_template = priv->box_tmpl_ext_page; + box_template_page_area = priv->box_tmpl_ext_page_area; + } + else + { + box_template = priv->box_tmpl_int_page; + box_template_page_area = priv->box_tmpl_int_page_area; + + gtk_label_set_text( + GTK_LABEL(priv->label_int_title), + wintc_wizard97_page_get_title( + WINTC_WIZARD97_PAGE(page_next) + ) + ); + gtk_label_set_text( + GTK_LABEL(priv->label_int_subtitle), + wintc_wizard97_page_get_subtitle( + WINTC_WIZARD97_PAGE(page_next) + ) + ); + } + + // Pack the page now + // + gtk_box_pack_start( + GTK_BOX(box_template_page_area), + page_next, + TRUE, + TRUE, + 0 + ); + + gtk_box_pack_start( + GTK_BOX(priv->box_page_area), + box_template, + TRUE, + TRUE, + 0 + ); + + gtk_widget_show_all(box_template); + + // Update state + // + if (push_history) + { + priv->history = + g_slist_prepend( + priv->history, + GUINT_TO_POINTER(priv->current_page) + ); + } + + priv->current_page = page_num; + + // Ping everything + // + for (gint i = PROP_CAN_PREV; i < N_PROPERTIES; i++) + { + g_object_notify_by_pspec( + G_OBJECT(wiz_wnd), + wintc_wizard97_window_properties[i] + ); + } +} + +static gboolean wintc_wizard97_window_is_on_final_page( + WinTCWizard97Window* wiz_wnd +) +{ + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private(wiz_wnd); + + WinTCWizard97WindowClass* wiz_class = + WINTC_WIZARD97_WINDOW_GET_CLASS(wiz_wnd); + + if ( + wintc_wizard97_page_get_is_final_page( + WINTC_WIZARD97_PAGE( + wintc_wizard97_window_get_page(wiz_wnd, priv->current_page) + ) + ) || + wiz_class->get_next_page( + wiz_wnd, + priv->current_page + ) == WIZARD97_PAGE_NUM_FINAL + ) + { + return TRUE; + } + + + return FALSE; +} + +// +// CALLBACKS +// +static void action_back( + WINTC_UNUSED(GSimpleAction* action), + WINTC_UNUSED(GVariant* parameter), + gpointer user_data +) +{ + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private( + WINTC_WIZARD97_WINDOW(user_data) + ); + + // Check what page we should go to + // + guint prev_page; + + if (!priv->history) + { + g_critical("%s", "wizard97: attempted to go back with no history"); + return; + } + + prev_page = GPOINTER_TO_UINT(priv->history->data); + + priv->history = + g_slist_delete_link( + priv->history, + priv->history + ); + + // Go! + // + wintc_wizard97_window_go_to_page( + WINTC_WIZARD97_WINDOW(user_data), + prev_page, + FALSE + ); +} + +static void action_cancel( + WINTC_UNUSED(GSimpleAction* action), + WINTC_UNUSED(GVariant* parameter), + gpointer user_data +) +{ + WinTCWizard97Window* wiz_wnd = WINTC_WIZARD97_WINDOW(user_data); + WinTCWizard97WindowClass* wiz_class = + WINTC_WIZARD97_WINDOW_GET_CLASS(wiz_wnd); + + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private( + wiz_wnd + ); + + if (wiz_class->cancel(wiz_wnd, priv->current_page)) + { + gtk_window_close(GTK_WINDOW(user_data)); + } +} + +static void action_help( + WINTC_UNUSED(GSimpleAction* action), + WINTC_UNUSED(GVariant* parameter), + gpointer user_data +) +{ + WinTCWizard97Window* wiz_wnd = WINTC_WIZARD97_WINDOW(user_data); + WinTCWizard97WindowClass* wiz_class = + WINTC_WIZARD97_WINDOW_GET_CLASS(wiz_wnd); + + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private( + wiz_wnd + ); + + wiz_class->help(wiz_wnd, priv->current_page); +} + +static void action_next( + WINTC_UNUSED(GSimpleAction* action), + WINTC_UNUSED(GVariant* parameter), + gpointer user_data +) +{ + WinTCWizard97Window* wiz_wnd = WINTC_WIZARD97_WINDOW(user_data); + WinTCWizard97WindowClass* wiz_class = + WINTC_WIZARD97_WINDOW_GET_CLASS(wiz_wnd); + + WinTCWizard97WindowPrivate* priv = + wintc_wizard97_window_get_instance_private( + wiz_wnd + ); + + if (wintc_wizard97_window_is_on_final_page(wiz_wnd)) + { + if (!wiz_class->finish(wiz_wnd, priv->current_page)) + { + return; + } + + gtk_window_close(GTK_WINDOW(wiz_wnd)); + } + else + { + wintc_wizard97_window_go_to_page( + WINTC_WIZARD97_WINDOW(user_data), + wiz_class->get_next_page(wiz_wnd, priv->current_page), + TRUE + ); + } +} + +static gboolean on_window_map_event( + GtkWidget* widget, + WINTC_UNUSED(GdkEvent* event), + WINTC_UNUSED(gpointer user_data) +) +{ + WinTCWizard97Window* wiz_wnd = WINTC_WIZARD97_WINDOW(widget); + + // Load the first page + // + wintc_wizard97_window_go_to_page( + wiz_wnd, + 0, + FALSE + ); + + return FALSE; +} diff --git a/shell/cpl/desk/src/pagedesk.c b/shell/cpl/desk/src/pagedesk.c index 636593b..9e0be8f 100644 --- a/shell/cpl/desk/src/pagedesk.c +++ b/shell/cpl/desk/src/pagedesk.c @@ -276,7 +276,11 @@ static void refresh_wallpaper_list( ) { g_list_free_full(wnd->list_wallpapers, g_free); - wintc_container_clear(GTK_CONTAINER(wnd->listbox_wallpapers)); + + wintc_container_clear( + GTK_CONTAINER(wnd->listbox_wallpapers), + TRUE + ); // Load up wallpapers // diff --git a/shell/explorer/src/toolbars/stdbar.c b/shell/explorer/src/toolbars/stdbar.c index 6e9ec52..e6b2677 100644 --- a/shell/explorer/src/toolbars/stdbar.c +++ b/shell/explorer/src/toolbars/stdbar.c @@ -576,7 +576,10 @@ static void populate_toolbar( { GtkWidget* toolbar = (WINTC_EXPLORER_TOOLBAR(toolbar_std))->toolbar; - wintc_container_clear(GTK_CONTAINER(toolbar)); + wintc_container_clear( + GTK_CONTAINER(toolbar), + TRUE + ); WINTC_LOG_DEBUG("explorer: populating std toolbar with %s", config_str); diff --git a/shell/taskband/src/start/personal.c b/shell/taskband/src/start/personal.c index fa414a4..cde9f10 100644 --- a/shell/taskband/src/start/personal.c +++ b/shell/taskband/src/start/personal.c @@ -778,7 +778,8 @@ static void refresh_personal_menu( // Clear existing items // wintc_container_clear( - GTK_CONTAINER(toolbar_start->personal.menubar_programs) + GTK_CONTAINER(toolbar_start->personal.menubar_programs), + TRUE ); // Set up signal tuple array diff --git a/tools/bldutils/depmap/apk-maps b/tools/bldutils/depmap/apk-maps index a7caba0..4736e42 100644 --- a/tools/bldutils/depmap/apk-maps +++ b/tools/bldutils/depmap/apk-maps @@ -44,6 +44,7 @@ wintc-shlang-->bt,rt-->libwintc-shlang wintc-sndapi-->bt,rt-->libwintc-sndapi wintc-syscfg-->bt,rt-->libwintc-syscfg wintc-winbrand-->bt,rt-->libwintc-winbrand +wintc-wizard97-->bt,rt-->libwintc-wizard97 xcursorgen-->bt,rt-->xcursorgen xdg-mime-->bt,rt-->xdg-utils xml2-->bt-->libxml2-dev diff --git a/tools/bldutils/depmap/archpkg-maps b/tools/bldutils/depmap/archpkg-maps index 01ea6c8..4e9f878 100644 --- a/tools/bldutils/depmap/archpkg-maps +++ b/tools/bldutils/depmap/archpkg-maps @@ -32,6 +32,7 @@ wintc-shlang-->bt,rt-->wintc-shlang wintc-sndapi-->bt,rt-->wintc-sndapi wintc-syscfg-->bt,rt-->wintc-syscfg wintc-winbrand-->bt,rt-->wintc-winbrand +wintc-wizard97-->bt,rt-->wintc-wizard97 xcursorgen-->bt,rt-->xorg-xcursorgen xdg-mime-->bt,rt-->xdg-utils xml2-->bt,rt-->libxml2 diff --git a/tools/bldutils/depmap/bsdpkg-maps b/tools/bldutils/depmap/bsdpkg-maps index 9a49d9f..d39ffc5 100644 --- a/tools/bldutils/depmap/bsdpkg-maps +++ b/tools/bldutils/depmap/bsdpkg-maps @@ -31,6 +31,7 @@ wintc-shlang-->bt,rt-->wintc-shlang wintc-sndapi-->bt,rt-->wintc-sndapi wintc-syscfg-->bt,rt-->wintc-syscfg wintc-winbrand-->bt,rt-->wintc-winbrand +wintc-wizard97-->bt,rt-->wintc-wizard97 xcursorgen-->bt,rt-->xcursorgen xdg-mime-->bt,rt-->xdg-utils xml2-->bt,rt-->libxml2 diff --git a/tools/bldutils/depmap/deb-maps b/tools/bldutils/depmap/deb-maps index e6576f3..a8133fa 100644 --- a/tools/bldutils/depmap/deb-maps +++ b/tools/bldutils/depmap/deb-maps @@ -45,6 +45,7 @@ wintc-shlang-->bt,rt-->libwintc-shlang wintc-sndapi-->bt,rt-->libwintc-sndapi wintc-syscfg-->bt,rt-->libwintc-syscfg wintc-winbrand-->bt,rt-->libwintc-winbrand +wintc-wizard97-->bt,rt-->libwintc-wizard97 xcursorgen-->bt,rt-->x11-apps xdg-mime-->bt,rt-->xdg-utils xml2-->bt-->libxml2-dev diff --git a/tools/bldutils/depmap/rpm-maps b/tools/bldutils/depmap/rpm-maps index 365d38d..23b34ee 100644 --- a/tools/bldutils/depmap/rpm-maps +++ b/tools/bldutils/depmap/rpm-maps @@ -44,6 +44,7 @@ wintc-shlang-->bt,rt-->wintc-shlang wintc-sndapi-->bt,rt-->wintc-sndapi wintc-syscfg-->bt,rt-->wintc-syscfg wintc-winbrand-->bt,rt-->wintc-winbrand +wintc-wizard97-->bt,rt-->wintc-wizard97 xcursorgen-->bt,rt-->xcursorgen xdg-mime-->bt,rt-->xdg-utils xml2-->bt-->libxml2-devel diff --git a/tools/bldutils/depmap/xbps-maps b/tools/bldutils/depmap/xbps-maps index 68bbc1e..188ad96 100644 --- a/tools/bldutils/depmap/xbps-maps +++ b/tools/bldutils/depmap/xbps-maps @@ -44,6 +44,7 @@ wintc-shlang-->bt,rt-->wintc-shlang wintc-sndapi-->bt,rt-->wintc-sndapi wintc-syscfg-->bt,rt-->wintc-syscfg wintc-winbrand-->bt,rt-->wintc-winbrand +wintc-wizard97-->bt,rt-->wintc-wizard97 xcursorgen-->bt,rt-->xcursorgen xdg-mime-->bt,rt-->xdg-utils xml2-->bt-->libxml2-devel