diff options
Diffstat (limited to 'tui/newt')
44 files changed, 9326 insertions, 0 deletions
diff --git a/tui/newt/Makefile.am b/tui/newt/Makefile.am new file mode 100644 index 000000000..0db5525d0 --- /dev/null +++ b/tui/newt/Makefile.am @@ -0,0 +1,54 @@ +AM_CPPFLAGS= \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/include \ + -DG_LOG_DOMAIN=\""nmtui"\" \ + $(GLIB_CFLAGS) \ + $(NEWT_CFLAGS) \ + $(NULL) + +noinst_LIBRARIES = libnmt-newt.a + +libnmt_newt_a_SOURCES = \ + nmt-newt.h \ + nmt-newt-types.h \ + nmt-newt-button.c \ + nmt-newt-button.h \ + nmt-newt-button-box.c \ + nmt-newt-button-box.h \ + nmt-newt-checkbox.c \ + nmt-newt-checkbox.h \ + nmt-newt-component.c \ + nmt-newt-component.h \ + nmt-newt-container.c \ + nmt-newt-container.h \ + nmt-newt-entry.c \ + nmt-newt-entry.h \ + nmt-newt-entry-numeric.c \ + nmt-newt-entry-numeric.h \ + nmt-newt-form.c \ + nmt-newt-form.h \ + nmt-newt-grid.c \ + nmt-newt-grid.h \ + nmt-newt-hacks.c \ + nmt-newt-hacks.h \ + nmt-newt-label.c \ + nmt-newt-label.h \ + nmt-newt-listbox.c \ + nmt-newt-listbox.h \ + nmt-newt-popup.c \ + nmt-newt-popup.h \ + nmt-newt-section.c \ + nmt-newt-section.h \ + nmt-newt-separator.c \ + nmt-newt-separator.h \ + nmt-newt-stack.c \ + nmt-newt-stack.h \ + nmt-newt-textbox.c \ + nmt-newt-textbox.h \ + nmt-newt-toggle-button.c \ + nmt-newt-toggle-button.h \ + nmt-newt-utils.c \ + nmt-newt-utils.h \ + nmt-newt-widget.c \ + nmt-newt-widget.h \ + $(NULL) diff --git a/tui/newt/Makefile.in b/tui/newt/Makefile.in new file mode 100644 index 000000000..043382bea --- /dev/null +++ b/tui/newt/Makefile.in @@ -0,0 +1,802 @@ +# Makefile.in generated by automake 1.13.4 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tui/newt +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/build-aux/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ + $(top_srcdir)/m4/compiler_warnings.m4 \ + $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/gnome-code-coverage.m4 \ + $(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intltool.m4 \ + $(top_srcdir)/m4/introspection.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libnmt_newt_a_AR = $(AR) $(ARFLAGS) +libnmt_newt_a_LIBADD = +am_libnmt_newt_a_OBJECTS = nmt-newt-button.$(OBJEXT) \ + nmt-newt-button-box.$(OBJEXT) nmt-newt-checkbox.$(OBJEXT) \ + nmt-newt-component.$(OBJEXT) nmt-newt-container.$(OBJEXT) \ + nmt-newt-entry.$(OBJEXT) nmt-newt-entry-numeric.$(OBJEXT) \ + nmt-newt-form.$(OBJEXT) nmt-newt-grid.$(OBJEXT) \ + nmt-newt-hacks.$(OBJEXT) nmt-newt-label.$(OBJEXT) \ + nmt-newt-listbox.$(OBJEXT) nmt-newt-popup.$(OBJEXT) \ + nmt-newt-section.$(OBJEXT) nmt-newt-separator.$(OBJEXT) \ + nmt-newt-stack.$(OBJEXT) nmt-newt-textbox.$(OBJEXT) \ + nmt-newt-toggle-button.$(OBJEXT) nmt-newt-utils.$(OBJEXT) \ + nmt-newt-widget.$(OBJEXT) +libnmt_newt_a_OBJECTS = $(am_libnmt_newt_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libnmt_newt_a_SOURCES) +DIST_SOURCES = $(libnmt_newt_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALL_LINGUAS = @ALL_LINGUAS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CKDB_PATH = @CKDB_PATH@ +CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@ +CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@ +CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DBUS_CFLAGS = @DBUS_CFLAGS@ +DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ +DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ +DBUS_LIBS = @DBUS_LIBS@ +DBUS_SYS_DIR = @DBUS_SYS_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DHCLIENT_PATH = @DHCLIENT_PATH@ +DHCPCD_PATH = @DHCPCD_PATH@ +DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ +DLLTOOL = @DLLTOOL@ +DNSMASQ_PATH = @DNSMASQ_PATH@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GENHTML = @GENHTML@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MAKEFILE = @GLIB_MAKEFILE@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ +GNUTLS_LIBS = @GNUTLS_LIBS@ +GREP = @GREP@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +GUDEV_CFLAGS = @GUDEV_CFLAGS@ +GUDEV_LIBS = @GUDEV_LIBS@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@ +INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@ +INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@ +INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ +INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ +INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@ +INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@ +INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ +INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ +INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ +INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +IPTABLES_PATH = @IPTABLES_PATH@ +IWMX_SDK_CFLAGS = @IWMX_SDK_CFLAGS@ +IWMX_SDK_LIBS = @IWMX_SDK_LIBS@ +KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBDL = @LIBDL@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBM = @LIBM@ +LIBNDP_CFLAGS = @LIBNDP_CFLAGS@ +LIBNDP_LIBS = @LIBNDP_LIBS@ +LIBNL_CFLAGS = @LIBNL_CFLAGS@ +LIBNL_LIBS = @LIBNL_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@ +LIBSOUP_LIBS = @LIBSOUP_LIBS@ +LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@ +LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MM_GLIB_CFLAGS = @MM_GLIB_CFLAGS@ +MM_GLIB_LIBS = @MM_GLIB_LIBS@ +MOC = @MOC@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NEWT_CFLAGS = @NEWT_CFLAGS@ +NEWT_LIBS = @NEWT_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ +NM_MICRO_VERSION = @NM_MICRO_VERSION@ +NM_MINOR_VERSION = @NM_MINOR_VERSION@ +NM_MODIFY_SYSTEM_POLICY = @NM_MODIFY_SYSTEM_POLICY@ +NM_VERSION = @NM_VERSION@ +NSS_CFLAGS = @NSS_CFLAGS@ +NSS_LIBS = @NSS_LIBS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POLKIT_CFLAGS = @POLKIT_CFLAGS@ +POLKIT_LIBS = @POLKIT_LIBS@ +POSUB = @POSUB@ +PPPD_PATH = @PPPD_PATH@ +PPPD_PLUGIN_DIR = @PPPD_PLUGIN_DIR@ +PPPOE_PATH = @PPPOE_PATH@ +QT_CFLAGS = @QT_CFLAGS@ +QT_LIBS = @QT_LIBS@ +RANLIB = @RANLIB@ +READLINE_LIBS = @READLINE_LIBS@ +SED = @SED@ +SELINUX_CFLAGS = @SELINUX_CFLAGS@ +SELINUX_LIBS = @SELINUX_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSTEMD_200_CFLAGS = @SYSTEMD_200_CFLAGS@ +SYSTEMD_200_LIBS = @SYSTEMD_200_LIBS@ +SYSTEMD_INHIBIT_CFLAGS = @SYSTEMD_INHIBIT_CFLAGS@ +SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@ +SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ +SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ +SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ +UDEV_BASE_DIR = @UDEV_BASE_DIR@ +USE_NLS = @USE_NLS@ +UUID_CFLAGS = @UUID_CFLAGS@ +UUID_LIBS = @UUID_LIBS@ +VALGRIND_RULES = @VALGRIND_RULES@ +VAPIGEN = @VAPIGEN@ +VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@ +VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +intltool__v_merge_options_ = @intltool__v_merge_options_@ +intltool__v_merge_options_0 = @intltool__v_merge_options_0@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +nmbinary = @nmbinary@ +nmconfdir = @nmconfdir@ +nmdatadir = @nmdatadir@ +nmrundir = @nmrundir@ +nmstatedir = @nmstatedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +with_dhclient = @with_dhclient@ +with_dhcpcd = @with_dhcpcd@ +with_netconfig = @with_netconfig@ +with_resolvconf = @with_resolvconf@ +with_valgrind = @with_valgrind@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/include \ + -DG_LOG_DOMAIN=\""nmtui"\" \ + $(GLIB_CFLAGS) \ + $(NEWT_CFLAGS) \ + $(NULL) + +noinst_LIBRARIES = libnmt-newt.a +libnmt_newt_a_SOURCES = \ + nmt-newt.h \ + nmt-newt-types.h \ + nmt-newt-button.c \ + nmt-newt-button.h \ + nmt-newt-button-box.c \ + nmt-newt-button-box.h \ + nmt-newt-checkbox.c \ + nmt-newt-checkbox.h \ + nmt-newt-component.c \ + nmt-newt-component.h \ + nmt-newt-container.c \ + nmt-newt-container.h \ + nmt-newt-entry.c \ + nmt-newt-entry.h \ + nmt-newt-entry-numeric.c \ + nmt-newt-entry-numeric.h \ + nmt-newt-form.c \ + nmt-newt-form.h \ + nmt-newt-grid.c \ + nmt-newt-grid.h \ + nmt-newt-hacks.c \ + nmt-newt-hacks.h \ + nmt-newt-label.c \ + nmt-newt-label.h \ + nmt-newt-listbox.c \ + nmt-newt-listbox.h \ + nmt-newt-popup.c \ + nmt-newt-popup.h \ + nmt-newt-section.c \ + nmt-newt-section.h \ + nmt-newt-separator.c \ + nmt-newt-separator.h \ + nmt-newt-stack.c \ + nmt-newt-stack.h \ + nmt-newt-textbox.c \ + nmt-newt-textbox.h \ + nmt-newt-toggle-button.c \ + nmt-newt-toggle-button.h \ + nmt-newt-utils.c \ + nmt-newt-utils.h \ + nmt-newt-widget.c \ + nmt-newt-widget.h \ + $(NULL) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tui/newt/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tui/newt/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libnmt-newt.a: $(libnmt_newt_a_OBJECTS) $(libnmt_newt_a_DEPENDENCIES) $(EXTRA_libnmt_newt_a_DEPENDENCIES) + $(AM_V_at)-rm -f libnmt-newt.a + $(AM_V_AR)$(libnmt_newt_a_AR) libnmt-newt.a $(libnmt_newt_a_OBJECTS) $(libnmt_newt_a_LIBADD) + $(AM_V_at)$(RANLIB) libnmt-newt.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-button-box.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-button.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-checkbox.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-component.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-container.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-entry-numeric.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-entry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-form.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-grid.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-hacks.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-label.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-listbox.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-popup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-section.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-separator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-stack.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-textbox.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-toggle-button.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmt-newt-widget.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tui/newt/nmt-newt-button-box.c b/tui/newt/nmt-newt-button-box.c new file mode 100644 index 000000000..0199ebe93 --- /dev/null +++ b/tui/newt/nmt-newt-button-box.c @@ -0,0 +1,385 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-button-box + * @short_description: A container for #NmtNewtButtons + * + * #NmtNewtButtonBox is a container for creating and holding + * #NmtNewtButtons. + * + * A button box can be either horizontally or vertically laid out, and + * has two sections within it: the "start" (left or top) and "end" + * (right or bottom). Buttons are added from left to right or top to bottom + * within each of the two sections. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-button-box.h" +#include "nmt-newt-button.h" + +G_DEFINE_TYPE (NmtNewtButtonBox, nmt_newt_button_box, NMT_TYPE_NEWT_CONTAINER) + +#define NMT_NEWT_BUTTON_BOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBoxPrivate)) + +typedef struct { + NmtNewtButtonBoxOrientation orientation; + GPtrArray *start_buttons, *end_buttons; +} NmtNewtButtonBoxPrivate; + +enum { + PROP_0, + + PROP_ORIENTATION, + + LAST_PROP +}; + +/** + * NmtNewtButtonBoxOrientation: + * @NMT_NEWT_BUTTON_BOX_HORIZONTAL: horizontal + * @NMT_NEWT_BUTTON_BOX_VERTICAL: vertical + * + * The orientation of an #NmtNewtButtonBox + */ + +/** + * nmt_newt_button_box_new: + * @orientation: the orientation + * + * Creates a new #NmtNewtButtonBox + * + * Returns: a new #NmtNewtButtonBox + */ +NmtNewtWidget * +nmt_newt_button_box_new (NmtNewtButtonBoxOrientation orientation) +{ + return g_object_new (NMT_TYPE_NEWT_BUTTON_BOX, + "orientation", orientation, + NULL); +} + +static void +nmt_newt_button_box_init (NmtNewtButtonBox *bbox) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox); + + priv->start_buttons = g_ptr_array_new (); + priv->end_buttons = g_ptr_array_new (); +} + +/** + * nmt_newt_button_box_add_start: + * @bbox: an #NmtNewtButtonBox + * @label: the label for the newt button + * + * Creates a new #NmtNewtButton with the given @label, adds it + * to the "start" section of @bbox, and returns the newly-created + * button. + * + * Returns: the newly-created button, already added to @bbox + */ +NmtNewtWidget * +nmt_newt_button_box_add_start (NmtNewtButtonBox *bbox, + const char *label) +{ + NmtNewtWidget *button; + + button = nmt_newt_button_new (label); + nmt_newt_button_box_add_widget_start (bbox, button); + return button; +} + +/** + * nmt_newt_button_box_add_widget_start: + * @bbox: an #NmtNewtButtonBox + * @widget: the #NmtNewtWidget to add + * + * Adds the given widget to the "start" section of @bbox. + */ +void +nmt_newt_button_box_add_widget_start (NmtNewtButtonBox *bbox, + NmtNewtWidget *widget) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox); + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_button_box_parent_class)-> + add (NMT_NEWT_CONTAINER (bbox), widget); + g_ptr_array_add (priv->start_buttons, widget); +} + +/** + * nmt_newt_button_box_add_end: + * @bbox: an #NmtNewtButtonBox + * @label: the label for the newt button + * + * Creates a new #NmtNewtButton with the given @label, adds it + * to the "end" section of @bbox, and returns the newly-created + * button. + * + * Returns: the newly-created button, already added to @bbox + */ +NmtNewtWidget * +nmt_newt_button_box_add_end (NmtNewtButtonBox *bbox, + const char *label) +{ + NmtNewtWidget *button; + + button = nmt_newt_button_new (label); + nmt_newt_button_box_add_widget_end (bbox, button); + return button; +} + +/** + * nmt_newt_button_box_add_widget_end: + * @bbox: an #NmtNewtButtonBox + * @widget: the #NmtNewtWidget to add + * + * Adds the given widget to the "end" section of @bbox. + */ +void +nmt_newt_button_box_add_widget_end (NmtNewtButtonBox *bbox, + NmtNewtWidget *widget) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox); + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_button_box_parent_class)-> + add (NMT_NEWT_CONTAINER (bbox), widget); + g_ptr_array_add (priv->end_buttons, widget); +} + +static void +nmt_newt_button_box_remove (NmtNewtContainer *container, + NmtNewtWidget *child) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (container); + int i; + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_button_box_parent_class)-> + remove (container, child); + + for (i = 0; i < priv->start_buttons->len; i++) { + if (priv->start_buttons->pdata[i] == (gpointer) child) { + g_ptr_array_remove_index (priv->start_buttons, i); + return; + } + } + for (i = 0; i < priv->end_buttons->len; i++) { + if (priv->end_buttons->pdata[i] == (gpointer) child) { + g_ptr_array_remove_index (priv->end_buttons, i); + return; + } + } +} + +static void +add_buttons (GPtrArray *buttons, GPtrArray *cos) +{ + NmtNewtWidget *child; + newtComponent *child_cos; + int i, c; + + for (i = 0; i < buttons->len; i++) { + child = buttons->pdata[i]; + + if (!nmt_newt_widget_get_visible (child)) + continue; + + child_cos = nmt_newt_widget_get_components (child); + for (c = 0; child_cos[c]; c++) + g_ptr_array_add (cos, child_cos[c]); + g_free (child_cos); + } +} + +static newtComponent * +nmt_newt_button_box_get_components (NmtNewtWidget *widget) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (widget); + GPtrArray *cos; + + cos = g_ptr_array_new (); + add_buttons (priv->start_buttons, cos); + add_buttons (priv->end_buttons, cos); + g_ptr_array_add (cos, NULL); + + return (newtComponent *) g_ptr_array_free (cos, FALSE); +} + +static void +size_request_buttons (NmtNewtButtonBox *bbox, + GPtrArray *buttons, + int *width, + int *height) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (bbox); + int child_width, child_height; + int i; + + for (i = 0; i < buttons->len; i++) { + NmtNewtWidget *child = buttons->pdata[i]; + + nmt_newt_widget_size_request (child, &child_width, &child_height); + if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) { + *width += child_width; + if (i > 0) + *width += 1; + *height = MAX (*height, child_height); + } else { + *height += child_height; + if (i > 0) + *height += 1; + *width = MAX (*width, child_width); + } + } +} + +static void +nmt_newt_button_box_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtNewtButtonBox *bbox = NMT_NEWT_BUTTON_BOX (widget); + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (widget); + + *width = *height = 0; + size_request_buttons (bbox, priv->start_buttons, width, height); + size_request_buttons (bbox, priv->end_buttons, width, height); + + if (priv->start_buttons && priv->end_buttons) { + if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) + *width += 1; + else + *height += 1; + } +} + +static void +nmt_newt_button_box_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (widget); + NmtNewtWidget *child; + int child_x, child_y, child_width, child_height; + int i; + + child_x = x; + child_y = y; + for (i = 0; i < priv->start_buttons->len; i++) { + child = priv->start_buttons->pdata[i]; + nmt_newt_widget_size_request (child, &child_width, &child_height); + + if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) { + nmt_newt_widget_size_allocate (child, child_x, child_y, child_width, child_height); + child_x += child_width + 1; + } else { + nmt_newt_widget_size_allocate (child, child_x, child_y, child_width, child_height); + child_y += child_height + 1; + } + } + + if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) + child_x = x + width; + else + child_y = y + height; + + for (i = priv->end_buttons->len - 1; i >= 0; i--) { + child = priv->end_buttons->pdata[i]; + nmt_newt_widget_size_request (child, &child_width, &child_height); + + if (priv->orientation == NMT_NEWT_BUTTON_BOX_HORIZONTAL) { + nmt_newt_widget_size_allocate (child, + child_x - child_width, child_y, + child_width, child_height); + child_x -= child_width + 1; + } else { + nmt_newt_widget_size_allocate (child, + child_x, child_y - child_height, + child_width, child_height); + child_y -= child_height + 1; + } + } +} + +static void +nmt_newt_button_box_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_ORIENTATION: + priv->orientation = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_button_box_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtButtonBoxPrivate *priv = NMT_NEWT_BUTTON_BOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_ORIENTATION: + g_value_set_int (value, priv->orientation); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_button_box_class_init (NmtNewtButtonBoxClass *bbox_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (bbox_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (bbox_class); + NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (bbox_class); + + g_type_class_add_private (bbox_class, sizeof (NmtNewtButtonBoxPrivate)); + + object_class->get_property = nmt_newt_button_box_get_property; + object_class->set_property = nmt_newt_button_box_set_property; + + widget_class->get_components = nmt_newt_button_box_get_components; + widget_class->size_request = nmt_newt_button_box_size_request; + widget_class->size_allocate = nmt_newt_button_box_size_allocate; + + container_class->remove = nmt_newt_button_box_remove; + + g_object_class_install_property (object_class, PROP_ORIENTATION, + g_param_spec_int ("orientation", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-button-box.h b/tui/newt/nmt-newt-button-box.h new file mode 100644 index 000000000..970588a4d --- /dev/null +++ b/tui/newt/nmt-newt-button-box.h @@ -0,0 +1,65 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_BUTTON_BOX_H +#define NMT_NEWT_BUTTON_BOX_H + +#include "nmt-newt-grid.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_BUTTON_BOX (nmt_newt_button_box_get_type ()) +#define NMT_NEWT_BUTTON_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBox)) +#define NMT_NEWT_BUTTON_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBoxClass)) +#define NMT_IS_NEWT_BUTTON_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_BUTTON_BOX)) +#define NMT_IS_NEWT_BUTTON_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_BUTTON_BOX)) +#define NMT_NEWT_BUTTON_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_BUTTON_BOX, NmtNewtButtonBoxClass)) + +struct _NmtNewtButtonBox { + NmtNewtContainer parent; + +}; + +typedef struct { + NmtNewtContainerClass parent; + +} NmtNewtButtonBoxClass; + +GType nmt_newt_button_box_get_type (void); + +typedef enum { + NMT_NEWT_BUTTON_BOX_HORIZONTAL, + NMT_NEWT_BUTTON_BOX_VERTICAL +} NmtNewtButtonBoxOrientation; + +NmtNewtWidget *nmt_newt_button_box_new (NmtNewtButtonBoxOrientation orientation); + +NmtNewtWidget *nmt_newt_button_box_add_start (NmtNewtButtonBox *bbox, + const char *label); +NmtNewtWidget *nmt_newt_button_box_add_end (NmtNewtButtonBox *bbox, + const char *label); + +void nmt_newt_button_box_add_widget_start (NmtNewtButtonBox *bbox, + NmtNewtWidget *widget); +void nmt_newt_button_box_add_widget_end (NmtNewtButtonBox *bbox, + NmtNewtWidget *widget); + + +G_END_DECLS + +#endif /* NMT_NEWT_BUTTON_BOX_H */ diff --git a/tui/newt/nmt-newt-button.c b/tui/newt/nmt-newt-button.c new file mode 100644 index 000000000..97ad50ca6 --- /dev/null +++ b/tui/newt/nmt-newt-button.c @@ -0,0 +1,260 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-button + * @short_description: Push buttons + * + * #NmtNewtButton implements a button widget. + */ + +#include "config.h" + +#include "nmt-newt-button.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtButton, nmt_newt_button, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_BUTTON, NmtNewtButtonPrivate)) + +typedef struct { + char *label; +} NmtNewtButtonPrivate; + +enum { + PROP_0, + PROP_LABEL, + + LAST_PROP +}; + +enum { + CLICKED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +/** + * nmt_newt_button_new: + * @label: the (initial) button label + * + * Creates a new button. + * + * Returns: a new #NmtNewtButton + */ +NmtNewtWidget * +nmt_newt_button_new (const char *label) +{ + return g_object_new (NMT_TYPE_NEWT_BUTTON, + "label", label, + NULL); +} + +/** + * nmt_newt_button_set_label: + * @button: an #NmtNewtButton + * @label: the new label + * + * Updates @button's label. + */ +void +nmt_newt_button_set_label (NmtNewtButton *button, + const char *label) +{ + NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (button); + + if (!g_strcmp0 (priv->label, label)) + return; + + g_free (priv->label); + priv->label = g_strdup (label); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (button)); +} + +/** + * nmt_newt_button_get_label: + * @button: an #NmtNewtButton + * + * Gets @button's label. + * + * Returns: @button's label. + */ +const char * +nmt_newt_button_get_label (NmtNewtButton *button) +{ + NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (button); + + return priv->label; +} + +static void +nmt_newt_button_init (NmtNewtButton *button) +{ +} + +static void +nmt_newt_button_finalize (GObject *object) +{ + NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (object); + + g_free (priv->label); + + G_OBJECT_CLASS (nmt_newt_button_parent_class)->finalize (object); +} + +static newtComponent +nmt_newt_button_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (component); + newtComponent co; + char *label = NULL, *label_lc; + + if (sensitive) { + label_lc = nmt_newt_locale_from_utf8 (priv->label); + co = newtCompactButton (-1, -1, label_lc); + g_free (label_lc); + } else { + label = g_strdup_printf (" <%s>", priv->label); + label_lc = nmt_newt_locale_from_utf8 (label); + co = newtLabel (-1, -1, label_lc); + g_free (label_lc); + newtLabelSetColors (co, NMT_NEWT_COLORSET_DISABLED_BUTTON); + } + + return co; +} + +static void +nmt_newt_button_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NMT_NEWT_WIDGET_CLASS (nmt_newt_button_parent_class)->size_request (widget, width, height); + + /* remove the automatically-added left padding */ + (*width)--; +} + +static void +nmt_newt_button_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + /* account for the automatically-added left padding */ + x--; + width++; + + NMT_NEWT_WIDGET_CLASS (nmt_newt_button_parent_class)->size_allocate (widget, x, y, width, height); +} + +static void +nmt_newt_button_activated (NmtNewtWidget *widget) +{ + g_signal_emit (widget, signals[CLICKED], 0); + + NMT_NEWT_WIDGET_CLASS (nmt_newt_button_parent_class)->activated (widget); +} + +static void +nmt_newt_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_LABEL: + nmt_newt_button_set_label (NMT_NEWT_BUTTON (object), + g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_LABEL: + g_value_set_string (value, priv->label); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_button_class_init (NmtNewtButtonClass *button_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (button_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (button_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (button_class); + + g_type_class_add_private (button_class, sizeof (NmtNewtButtonPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_button_set_property; + object_class->get_property = nmt_newt_button_get_property; + object_class->finalize = nmt_newt_button_finalize; + + widget_class->size_request = nmt_newt_button_size_request; + widget_class->size_allocate = nmt_newt_button_size_allocate; + widget_class->activated = nmt_newt_button_activated; + + component_class->build_component = nmt_newt_button_build_component; + + /* signals */ + + /** + * NmtNewtButton::clicked: + * @button: the #NmtNewtButton + * + * Emitted when the button is clicked. + */ + signals[CLICKED] = + g_signal_new ("clicked", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + + /* properties */ + + /** + * NmtNewtButton:label: + * + * The button's label + */ + g_object_class_install_property (object_class, PROP_LABEL, + g_param_spec_string ("label", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-button.h b/tui/newt/nmt-newt-button.h new file mode 100644 index 000000000..52e95c5d1 --- /dev/null +++ b/tui/newt/nmt-newt-button.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_BUTTON_H +#define NMT_NEWT_BUTTON_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_BUTTON (nmt_newt_button_get_type ()) +#define NMT_NEWT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_BUTTON, NmtNewtButton)) +#define NMT_NEWT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_BUTTON, NmtNewtButtonClass)) +#define NMT_IS_NEWT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_BUTTON)) +#define NMT_IS_NEWT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_BUTTON)) +#define NMT_NEWT_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_BUTTON, NmtNewtButtonClass)) + +struct _NmtNewtButton { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtButtonClass; + +GType nmt_newt_button_get_type (void); + +NmtNewtWidget *nmt_newt_button_new (const char *label); + +void nmt_newt_button_set_label (NmtNewtButton *button, + const char *label); +const char *nmt_newt_button_get_label (NmtNewtButton *button); + +G_END_DECLS + +#endif /* NMT_NEWT_BUTTON_H */ diff --git a/tui/newt/nmt-newt-checkbox.c b/tui/newt/nmt-newt-checkbox.c new file mode 100644 index 000000000..168fada20 --- /dev/null +++ b/tui/newt/nmt-newt-checkbox.c @@ -0,0 +1,235 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-checkbox + * @short_description: Checkboxes + * + * #NmtNewtCheckbox implements a checkbox widget. + */ + +#include "config.h" + +#include "nmt-newt-checkbox.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtCheckbox, nmt_newt_checkbox, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_CHECKBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckboxPrivate)) + +typedef struct { + char *label_lc; + gboolean active; +} NmtNewtCheckboxPrivate; + +enum { + PROP_0, + PROP_LABEL, + PROP_ACTIVE, + + LAST_PROP +}; + +#define CHECKBOX_INACTIVE ' ' +#define CHECKBOX_ACTIVE 'X' +#define CHECKBOX_STATES " X" + +/** + * nmt_newt_checkbox_new: + * @label: the (initial) checkbox label + * + * Creates a new checkbox. + * + * Returns: a new #NmtNewtCheckbox + */ +NmtNewtWidget * +nmt_newt_checkbox_new (const char *label) +{ + return g_object_new (NMT_TYPE_NEWT_CHECKBOX, + "label", label, + NULL); +} + +/** + * nmt_newt_checkbox_set_active: + * @checkbox: an #NmtNewtCheckbox + * @active: whether @checkbox should be checked + * + * Updates @checkbox's checked state + */ +void +nmt_newt_checkbox_set_active (NmtNewtCheckbox *checkbox, + gboolean active) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (checkbox); + newtComponent co; + + active = !!active; + if (active == priv->active) + return; + + priv->active = active; + + co = nmt_newt_component_get_component (NMT_NEWT_COMPONENT (checkbox)); + if (co) + newtCheckboxSetValue (co, priv->active ? CHECKBOX_ACTIVE : CHECKBOX_INACTIVE); + + g_object_notify (G_OBJECT (checkbox), "active"); +} + +/** + * nmt_newt_checkbox_get_active: + * @checkbox: an #NmtNewtCheckbox + * + * Gets @checkbox's checked state + * + * Returns: @checkbox's checked state + */ +gboolean +nmt_newt_checkbox_get_active (NmtNewtCheckbox *checkbox) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (checkbox); + + return priv->active; +} + +static void +nmt_newt_checkbox_init (NmtNewtCheckbox *checkbox) +{ +} + +static void +nmt_newt_checkbox_finalize (GObject *object) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (object); + + g_free (priv->label_lc); + + G_OBJECT_CLASS (nmt_newt_checkbox_parent_class)->finalize (object); +} + +static void +checkbox_toggled_callback (newtComponent co, + void *checkbox) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (checkbox); + gboolean active; + + active = (newtCheckboxGetValue (co) == CHECKBOX_ACTIVE); + if (active != priv->active) { + priv->active = active; + g_object_notify (checkbox, "active"); + } +} + +static newtComponent +nmt_newt_checkbox_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (component); + newtComponent co; + + co = newtCheckbox (-1, -1, priv->label_lc, + priv->active ? CHECKBOX_ACTIVE : CHECKBOX_INACTIVE, + CHECKBOX_STATES, NULL); + if (!sensitive) + newtCheckboxSetFlags (co, NEWT_FLAG_DISABLED, NEWT_FLAGS_SET); + newtComponentAddCallback (co, checkbox_toggled_callback, component); + return co; +} + +static void +nmt_newt_checkbox_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtCheckbox *checkbox = NMT_NEWT_CHECKBOX (object); + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_LABEL: + g_free (priv->label_lc); + priv->label_lc = nmt_newt_locale_from_utf8 (g_value_get_string (value)); + break; + case PROP_ACTIVE: + nmt_newt_checkbox_set_active (checkbox, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_checkbox_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtCheckboxPrivate *priv = NMT_NEWT_CHECKBOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_LABEL: + g_value_take_string (value, nmt_newt_locale_to_utf8 (priv->label_lc)); + break; + case PROP_ACTIVE: + g_value_set_boolean (value, priv->active); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_checkbox_class_init (NmtNewtCheckboxClass *checkbox_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (checkbox_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (checkbox_class); + + g_type_class_add_private (checkbox_class, sizeof (NmtNewtCheckboxPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_checkbox_set_property; + object_class->get_property = nmt_newt_checkbox_get_property; + object_class->finalize = nmt_newt_checkbox_finalize; + + component_class->build_component = nmt_newt_checkbox_build_component; + + /** + * NmtNewtCheckbox:label: + * + * The checkbox's label + */ + g_object_class_install_property (object_class, PROP_LABEL, + g_param_spec_string ("label", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtCheckbox:active: + * + * The checkbox's checked state + */ + g_object_class_install_property (object_class, PROP_ACTIVE, + g_param_spec_boolean ("active", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-checkbox.h b/tui/newt/nmt-newt-checkbox.h new file mode 100644 index 000000000..c277386b1 --- /dev/null +++ b/tui/newt/nmt-newt-checkbox.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_CHECKBOX_H +#define NMT_NEWT_CHECKBOX_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_CHECKBOX (nmt_newt_checkbox_get_type ()) +#define NMT_NEWT_CHECKBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckbox)) +#define NMT_NEWT_CHECKBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckboxClass)) +#define NMT_IS_NEWT_CHECKBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_CHECKBOX)) +#define NMT_IS_NEWT_CHECKBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_CHECKBOX)) +#define NMT_NEWT_CHECKBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_CHECKBOX, NmtNewtCheckboxClass)) + +struct _NmtNewtCheckbox { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtCheckboxClass; + +GType nmt_newt_checkbox_get_type (void); + +NmtNewtWidget *nmt_newt_checkbox_new (const char *label); + +void nmt_newt_checkbox_set_active (NmtNewtCheckbox *checkbox, + gboolean active); +gboolean nmt_newt_checkbox_get_active (NmtNewtCheckbox *checkbox); + +G_END_DECLS + +#endif /* NMT_NEWT_CHECKBOX_H */ diff --git a/tui/newt/nmt-newt-component.c b/tui/newt/nmt-newt-component.c new file mode 100644 index 000000000..877b53dbf --- /dev/null +++ b/tui/newt/nmt-newt-component.c @@ -0,0 +1,307 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-component + * @short_description: Base class for widgets that wrap #newtComponents + * + * #NmtNewtComponent is the abstract class for #NmtNewtWidgets that + * wrap a (single) #newtComponent. + */ + +#include "config.h" + +#include "nmt-newt-component.h" +#include "nmt-newt-form.h" +#include "nmt-newt-hacks.h" + +G_DEFINE_ABSTRACT_TYPE (NmtNewtComponent, nmt_newt_component, NMT_TYPE_NEWT_WIDGET) + +#define NMT_NEWT_COMPONENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponentPrivate)) + +typedef struct { + newtComponent co; + gboolean own_component; + gboolean sensitive; +} NmtNewtComponentPrivate; + +enum { + PROP_0, + + PROP_COMPONENT, + PROP_SENSITIVE, + + LAST_PROP +}; + +static void +nmt_newt_component_init (NmtNewtComponent *component) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component); + + priv->sensitive = TRUE; +} + +static void +nmt_newt_component_unrealize (NmtNewtWidget *widget) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + + if (!priv->co) + return; + + newtComponentAddCallback (priv->co, NULL, NULL); + newtComponentAddDestroyCallback (priv->co, NULL, NULL); + + if (priv->own_component) + newtComponentDestroy (priv->co); + priv->co = NULL; +} + +static void +component_destroy_callback (newtComponent co, + void *component) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component); + + priv->own_component = FALSE; + nmt_newt_widget_unrealize (component); + nmt_newt_widget_needs_rebuild (component); +} + +static void +nmt_newt_component_realize (NmtNewtWidget *widget) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + + nmt_newt_component_unrealize (widget); + priv->co = NMT_NEWT_COMPONENT_GET_CLASS (widget)-> + build_component (NMT_NEWT_COMPONENT (widget), priv->sensitive); + priv->own_component = TRUE; + if (!priv->sensitive) + newtComponentTakesFocus (priv->co, FALSE); + newtComponentAddDestroyCallback (priv->co, component_destroy_callback, widget); +} + +static newtComponent * +nmt_newt_component_get_components (NmtNewtWidget *widget) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + newtComponent *cos; + + priv->own_component = FALSE; + cos = g_new0 (newtComponent, 2); + cos[0] = priv->co; + return cos; +} + +static NmtNewtWidget * +nmt_newt_component_find_component (NmtNewtWidget *widget, + newtComponent co) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + + if (co == priv->co) + return widget; + else + return NULL; +} + +static void +nmt_newt_component_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + + newtComponentGetSize (priv->co, width, height); +} + +static void +nmt_newt_component_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + newtGrid grid; + + /* You can't directly place a newtComponent, so we create a newtGrid, + * position the component within that, and then place the grid. + */ + grid = newtCreateGrid (1, 1); + newtGridSetField (grid, 0, 0, + NEWT_GRID_COMPONENT, priv->co, + x, y, 0, 0, + NEWT_ANCHOR_LEFT | NEWT_ANCHOR_TOP, 0); + newtGridPlace (grid, 0, 0); + newtGridFree (grid, FALSE); +} + +static newtComponent +nmt_newt_component_get_focus_component (NmtNewtWidget *widget) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (widget); + + return priv->co; +} + +/** + * nmt_newt_component_get_component: + * @component: an #NmtNewtComponent + * + * A simpler version of nmt_newt_widget_get_components() for the + * single-component case. Also, unlike + * nmt_newt_widget_get_component(), this does not realize the widget + * if it isn't already realized. FIXME: why? + * + * Returns: @component's #newtComponent + */ +newtComponent +nmt_newt_component_get_component (NmtNewtComponent *component) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component); + + return priv->co; +} + +/** + * nmt_newt_component_get_sensitive: + * @component: an #NmtNewtComponent + * + * Gets @component's #NmtNewtComponent:sensitive property, indicating + * whether the widget is available for manipulation. Insensitive + * components will be skipped over in the keyboard tab chain, and may + * be displayed differently. + * + * Returns: @component's #NmtNewtComponent:sensitive property + */ +gboolean +nmt_newt_component_get_sensitive (NmtNewtComponent *component) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component); + + return priv->sensitive; +} + +/** + * nmt_newt_component_set_sensitive: + * @component: an #NmtNewtComponent + * @sensitive: whether @component should be sensitive + * + * Sets @component's #NmtNewtComponent:sensitive property. + */ +void +nmt_newt_component_set_sensitive (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtComponentPrivate *priv = NMT_NEWT_COMPONENT_GET_PRIVATE (component); + + sensitive = !!sensitive; + if (priv->sensitive == sensitive) + return; + + priv->sensitive = sensitive; + g_object_notify (G_OBJECT (component), "sensitive"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (component)); +} + +static void +nmt_newt_component_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtComponent *component = NMT_NEWT_COMPONENT (object); + + switch (prop_id) { + case PROP_SENSITIVE: + nmt_newt_component_set_sensitive (component, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_component_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtComponent *component = NMT_NEWT_COMPONENT (object); + + switch (prop_id) { + case PROP_COMPONENT: + g_value_set_pointer (value, nmt_newt_component_get_component (component)); + break; + case PROP_SENSITIVE: + g_value_set_boolean (value, nmt_newt_component_get_sensitive (component)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_component_class_init (NmtNewtComponentClass *component_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (component_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (component_class); + + g_type_class_add_private (component_class, sizeof (NmtNewtComponentPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_component_set_property; + object_class->get_property = nmt_newt_component_get_property; + + widget_class->realize = nmt_newt_component_realize; + widget_class->unrealize = nmt_newt_component_unrealize; + widget_class->get_components = nmt_newt_component_get_components; + widget_class->find_component = nmt_newt_component_find_component; + widget_class->size_request = nmt_newt_component_size_request; + widget_class->size_allocate = nmt_newt_component_size_allocate; + widget_class->get_focus_component = nmt_newt_component_get_focus_component; + + /* properties */ + + /** + * NmtNewtComponent:component: + * + * The component's #newtComponent + */ + g_object_class_install_property (object_class, PROP_COMPONENT, + g_param_spec_pointer ("component", "", "", + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtComponent:sensitive: + * + * Whether the component is sensitive. Insensitive components will + * be skipped over in the keyboard tab chain, and may be displayed + * differently. + */ + g_object_class_install_property (object_class, PROP_SENSITIVE, + g_param_spec_boolean ("sensitive", "", "", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-component.h b/tui/newt/nmt-newt-component.h new file mode 100644 index 000000000..2ffa018e1 --- /dev/null +++ b/tui/newt/nmt-newt-component.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_COMPONENT_H +#define NMT_NEWT_COMPONENT_H + +#include "nmt-newt-widget.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_COMPONENT (nmt_newt_component_get_type ()) +#define NMT_NEWT_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponent)) +#define NMT_NEWT_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponentClass)) +#define NMT_IS_NEWT_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_COMPONENT)) +#define NMT_IS_NEWT_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_COMPONENT)) +#define NMT_NEWT_COMPONENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_COMPONENT, NmtNewtComponentClass)) + +struct _NmtNewtComponent { + NmtNewtWidget parent; + +}; + +typedef struct { + NmtNewtWidgetClass parent; + + /* methods */ + newtComponent (*build_component) (NmtNewtComponent *component, + gboolean sensitive); + +} NmtNewtComponentClass; + +GType nmt_newt_component_get_type (void); + +newtComponent nmt_newt_component_get_component (NmtNewtComponent *component); + +gboolean nmt_newt_component_get_sensitive (NmtNewtComponent *component); +void nmt_newt_component_set_sensitive (NmtNewtComponent *component, + gboolean sensitive); + +G_END_DECLS + +#endif /* NMT_NEWT_COMPONENT_H */ diff --git a/tui/newt/nmt-newt-container.c b/tui/newt/nmt-newt-container.c new file mode 100644 index 000000000..03f677fbd --- /dev/null +++ b/tui/newt/nmt-newt-container.c @@ -0,0 +1,252 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-container + * @short_description: Base class for containers + * + * #NmtNewtContainer is the base class for #NmtNewtWidgets that + * contain other widgets. + * + * #NmtNewtGrid is the most generic container type. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-container.h" +#include "nmt-newt-component.h" + +G_DEFINE_ABSTRACT_TYPE (NmtNewtContainer, nmt_newt_container, NMT_TYPE_NEWT_WIDGET) + +#define NMT_NEWT_CONTAINER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainerPrivate)) + +typedef struct { + GPtrArray *children; + +} NmtNewtContainerPrivate; + +static void child_needs_rebuild (NmtNewtWidget *widget, gpointer user_data); + +static void +nmt_newt_container_init (NmtNewtContainer *container) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container); + + priv->children = g_ptr_array_new (); +} + +static void +nmt_newt_container_finalize (GObject *object) +{ + NmtNewtContainer *container = NMT_NEWT_CONTAINER (object); + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (object); + + while (priv->children->len) + nmt_newt_container_remove (container, priv->children->pdata[0]); + + G_OBJECT_CLASS (nmt_newt_container_parent_class)->finalize (object); +} + +static void +nmt_newt_container_realize (NmtNewtWidget *widget) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (widget); + int i; + + for (i = 0; i < priv->children->len; i++) + nmt_newt_widget_realize (priv->children->pdata[i]); +} + +static void +nmt_newt_container_unrealize (NmtNewtWidget *widget) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (widget); + int i; + + for (i = 0; i < priv->children->len; i++) + nmt_newt_widget_unrealize (priv->children->pdata[i]); +} + +static void +child_needs_rebuild (NmtNewtWidget *widget, + gpointer user_data) +{ + NmtNewtWidget *container = user_data; + + nmt_newt_widget_needs_rebuild (container); +} + +static void +nmt_newt_container_real_child_validity_changed (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtContainerPrivate *priv; + int i; + + if (widget) { + if (!nmt_newt_widget_get_visible (widget)) + return; + if (!nmt_newt_widget_get_valid (widget)) { + nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (container), FALSE); + return; + } + } + + priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container); + for (i = 0; i < priv->children->len; i++) { + widget = priv->children->pdata[i]; + if ( nmt_newt_widget_get_visible (widget) + && !nmt_newt_widget_get_valid (widget)) { + nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (container), FALSE); + return; + } + } + + nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (container), TRUE); +} + +static void +nmt_newt_container_child_validity_changed (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NMT_NEWT_CONTAINER_GET_CLASS (container)->child_validity_changed (container, widget); +} + +static void +child_validity_notify (GObject *object, + GParamSpec *pspec, + gpointer container) +{ + nmt_newt_container_child_validity_changed (container, NMT_NEWT_WIDGET (object)); +} + +static void +nmt_newt_container_real_add (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container); + + g_signal_connect (widget, "needs-rebuild", G_CALLBACK (child_needs_rebuild), container); + g_signal_connect (widget, "notify::valid", G_CALLBACK (child_validity_notify), container); + g_ptr_array_add (priv->children, g_object_ref_sink (widget)); + nmt_newt_widget_set_parent (widget, NMT_NEWT_WIDGET (container)); + + nmt_newt_container_child_validity_changed (container, widget); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (container)); +} + +static void +nmt_newt_container_real_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container); + int i; + + for (i = 0; i < priv->children->len; i++) { + if (widget == priv->children->pdata[i]) { + g_ptr_array_remove_index (priv->children, i); + g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (child_needs_rebuild), container); + g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (child_validity_notify), container); + nmt_newt_widget_set_parent (widget, NULL); + g_object_unref (widget); + + nmt_newt_container_child_validity_changed (container, NULL); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (container)); + return; + } + } +} + +/** + * nmt_newt_container_remove: + * @container: the #NmtNewtContainer + * @widget: the child to remove + * + * Removes @widget from @container. + * + * Note that there is not a corresponding + * <literal>nmt_newt_container_add ()</literal>; you must use + * container-type-specific methods to add widgets to containers. + */ +void +nmt_newt_container_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NMT_NEWT_CONTAINER_GET_CLASS (container)->remove (container, widget); +} + +static NmtNewtWidget * +nmt_newt_container_find_component (NmtNewtWidget *widget, + newtComponent co) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (widget); + NmtNewtWidget *found, *child; + int i; + + for (i = 0; i < priv->children->len; i++) { + child = priv->children->pdata[i]; + + found = nmt_newt_widget_find_component (child, co); + if (found) + return found; + } + + return NULL; +} + +/** + * nmt_newt_container_get_children: + * @container: an #NmtNewtContainer + * + * Gets a list of @container's children. + * + * Returns: (transfer full): a list of @container's children. + */ +GSList * +nmt_newt_container_get_children (NmtNewtContainer *container) +{ + NmtNewtContainerPrivate *priv = NMT_NEWT_CONTAINER_GET_PRIVATE (container); + GSList *ret; + int i; + + for (i = 0, ret = NULL; i < priv->children->len; i++) + ret = g_slist_prepend (ret, g_object_ref (priv->children->pdata[i])); + return g_slist_reverse (ret); +} + +static void +nmt_newt_container_class_init (NmtNewtContainerClass *container_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (container_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (container_class); + + g_type_class_add_private (container_class, sizeof (NmtNewtContainerPrivate)); + + /* virtual methods */ + object_class->finalize = nmt_newt_container_finalize; + + widget_class->realize = nmt_newt_container_realize; + widget_class->unrealize = nmt_newt_container_unrealize; + widget_class->find_component = nmt_newt_container_find_component; + + container_class->add = nmt_newt_container_real_add; + container_class->remove = nmt_newt_container_real_remove; + container_class->child_validity_changed = nmt_newt_container_real_child_validity_changed; +} diff --git a/tui/newt/nmt-newt-container.h b/tui/newt/nmt-newt-container.h new file mode 100644 index 000000000..6f182925d --- /dev/null +++ b/tui/newt/nmt-newt-container.h @@ -0,0 +1,61 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_CONTAINER_H +#define NMT_NEWT_CONTAINER_H + +#include "nmt-newt-widget.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_CONTAINER (nmt_newt_container_get_type ()) +#define NMT_NEWT_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainer)) +#define NMT_NEWT_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainerClass)) +#define NMT_IS_NEWT_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_CONTAINER)) +#define NMT_IS_NEWT_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_CONTAINER)) +#define NMT_NEWT_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_CONTAINER, NmtNewtContainerClass)) + +struct _NmtNewtContainer { + NmtNewtWidget parent; + +}; + +typedef struct { + NmtNewtWidgetClass parent; + + /* methods */ + void (*add) (NmtNewtContainer *container, + NmtNewtWidget *child); + void (*remove) (NmtNewtContainer *container, + NmtNewtWidget *child); + + void (*child_validity_changed) (NmtNewtContainer *container, + NmtNewtWidget *child); + +} NmtNewtContainerClass; + +GType nmt_newt_container_get_type (void); + +void nmt_newt_container_remove (NmtNewtContainer *container, + NmtNewtWidget *widget); + +GSList *nmt_newt_container_get_children (NmtNewtContainer *container); + +G_END_DECLS + +#endif /* NMT_NEWT_CONTAINER_H */ diff --git a/tui/newt/nmt-newt-entry-numeric.c b/tui/newt/nmt-newt-entry-numeric.c new file mode 100644 index 000000000..753c209a3 --- /dev/null +++ b/tui/newt/nmt-newt-entry-numeric.c @@ -0,0 +1,213 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-entry-numeric + * @short_description: Numeric text entry + * + * #NmtNewtEntryNumeric implements a numeric-only #NmtNewtEntry. + * + * #NmtNewtEntryNumeric provides its own #NmtNewtEntryFilter and + * #NmtNewtEntryValidator functions, so you should not set your own. + */ + +#include "config.h" + +#include <stdlib.h> + +#include "nmt-newt-entry-numeric.h" + +G_DEFINE_TYPE (NmtNewtEntryNumeric, nmt_newt_entry_numeric, NMT_TYPE_NEWT_ENTRY) + +#define NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumericPrivate)) + +typedef struct { + int min, max; +} NmtNewtEntryNumericPrivate; + +enum { + PROP_0, + PROP_MINIMUM, + PROP_MAXIMUM, + + LAST_PROP +}; + +/** + * nmt_newt_entry_numeric_new: + * @width: the entry's width in characters + * @min: the minimum valid value + * @max: the maximum valid value + * + * Creates a new #NmtNewtEntryNumeric, accepting values in the + * indicated range. + * + * Returns: a new #NmtNewtEntryNumeric + */ +NmtNewtWidget * +nmt_newt_entry_numeric_new (int width, + int min, + int max) +{ + return g_object_new (NMT_TYPE_NEWT_ENTRY_NUMERIC, + "width", width, + "minimum", min, + "maximum", max, + NULL); +} + +static gboolean +newt_entry_numeric_filter (NmtNewtEntry *entry, + const char *text, + int ch, + int position, + gpointer user_data) +{ + NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (entry); + + if (g_ascii_isdigit (ch)) + return TRUE; + + if (ch == '-' && position == 0 && priv->min < 0) + return TRUE; + + return FALSE; +} + +static gboolean +newt_entry_numeric_validate (NmtNewtEntry *entry, + const char *text, + gpointer user_data) +{ + NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (entry); + int val; + char *end; + + if (!*text) + return FALSE; + + val = strtoul (text, &end, 10); + if (*end) + return FALSE; + if (val < priv->min || val > priv->max) + return FALSE; + + return TRUE; +} + +static void +nmt_newt_entry_numeric_init (NmtNewtEntryNumeric *entry) +{ + nmt_newt_entry_set_filter (NMT_NEWT_ENTRY (entry), newt_entry_numeric_filter, NULL); + nmt_newt_entry_set_validator (NMT_NEWT_ENTRY (entry), newt_entry_numeric_validate, NULL); +} + +static void +nmt_newt_entry_numeric_constructed (GObject *object) +{ + NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (object); + + if (!*nmt_newt_entry_get_text (NMT_NEWT_ENTRY (object))) { + char buf[32]; + + g_snprintf (buf, sizeof (buf), "%d", priv->min); + nmt_newt_entry_set_text (NMT_NEWT_ENTRY (object), buf); + } + + G_OBJECT_CLASS (nmt_newt_entry_numeric_parent_class)->constructed (object); +} + +static void +nmt_newt_entry_numeric_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MINIMUM: + priv->min = g_value_get_int (value); + break; + case PROP_MAXIMUM: + priv->max = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_entry_numeric_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtEntryNumericPrivate *priv = NMT_NEWT_ENTRY_NUMERIC_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MINIMUM: + g_value_set_int (value, priv->min); + break; + case PROP_MAXIMUM: + g_value_set_int (value, priv->max); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_entry_numeric_class_init (NmtNewtEntryNumericClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtNewtEntryNumericPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_newt_entry_numeric_constructed; + object_class->set_property = nmt_newt_entry_numeric_set_property; + object_class->get_property = nmt_newt_entry_numeric_get_property; + + /** + * NmtNewtEntryNumeric:minimum: + * + * The minimum #NmtNewtWidget:valid value for the entry. If this + * is non-negative, then the entry will not allow negative numbers + * to be entered. + */ + g_object_class_install_property (object_class, PROP_MINIMUM, + g_param_spec_int ("minimum", "", "", + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtEntryNumeric:maximum: + * + * The maximum #NmtNewtWidget:valid value for the entry. + */ + g_object_class_install_property (object_class, PROP_MAXIMUM, + g_param_spec_int ("maximum", "", "", + G_MININT, G_MAXINT, G_MAXINT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-entry-numeric.h b/tui/newt/nmt-newt-entry-numeric.h new file mode 100644 index 000000000..43ac34490 --- /dev/null +++ b/tui/newt/nmt-newt-entry-numeric.h @@ -0,0 +1,51 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_ENTRY_NUMERIC_H +#define NMT_NEWT_ENTRY_NUMERIC_H + +#include "nmt-newt-entry.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_ENTRY_NUMERIC (nmt_newt_entry_numeric_get_type ()) +#define NMT_NEWT_ENTRY_NUMERIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumeric)) +#define NMT_NEWT_ENTRY_NUMERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumericClass)) +#define NMT_IS_NEWT_ENTRY_NUMERIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_ENTRY_NUMERIC)) +#define NMT_IS_NEWT_ENTRY_NUMERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_ENTRY_NUMERIC)) +#define NMT_NEWT_ENTRY_NUMERIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_ENTRY_NUMERIC, NmtNewtEntryNumericClass)) + +struct _NmtNewtEntryNumeric { + NmtNewtEntry parent; + +}; + +typedef struct { + NmtNewtEntryClass parent; + +} NmtNewtEntryNumericClass; + +GType nmt_newt_entry_numeric_get_type (void); + +NmtNewtWidget *nmt_newt_entry_numeric_new (int width, + int min, + int max); + +G_END_DECLS + +#endif /* NMT_NEWT_ENTRY_NUMERIC_H */ diff --git a/tui/newt/nmt-newt-entry.c b/tui/newt/nmt-newt-entry.c new file mode 100644 index 000000000..c98fcee8a --- /dev/null +++ b/tui/newt/nmt-newt-entry.c @@ -0,0 +1,536 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-entry + * @short_description: Text entries + * + * #NmtNewtEntry implements entry widgets, with optional filtering and + * validation. + * + * See also #NmtNewtEntryNumeric, for numeric-only entries. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-entry.h" +#include "nmt-newt-form.h" +#include "nmt-newt-hacks.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtEntry, nmt_newt_entry, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_ENTRY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_ENTRY, NmtNewtEntryPrivate)) + +typedef struct { + int width; + NmtNewtEntryFlags flags; + char *text; + int last_cursor_pos; + guint idle_update; + + NmtNewtEntryFilter filter; + gpointer filter_data; + + NmtNewtEntryValidator validator; + gpointer validator_data; +} NmtNewtEntryPrivate; + +enum { + PROP_0, + PROP_TEXT, + PROP_WIDTH, + PROP_FLAGS, + PROP_PASSWORD, + + LAST_PROP +}; + +/** + * NmtNewtEntryFlags: + * @NMT_NEWT_ENTRY_NOSCROLL: the entry content should not scroll left + * and right + * @NMT_NEWT_ENTRY_PASSWORD: the entry should show '*'s instead of its + * actual contents + * @NMT_NEWT_ENTRY_NONEMPTY: the entry should be considered not + * #NmtNewtWidget:valid if it is empty. + * + * Flags describing an #NmtNewtEntry + */ + +/** + * nmt_newt_entry_new: + * @width: the width in characters for the entry + * @flags: flags describing the entry + * + * Creates a new #NmtNewtEntry. + * + * Returns: a new #NmtNewtEntry + */ +NmtNewtWidget * +nmt_newt_entry_new (int width, + NmtNewtEntryFlags flags) +{ + return g_object_new (NMT_TYPE_NEWT_ENTRY, + "width", width, + "flags", flags, + NULL); +} + +/** + * NmtNewtEntryFilter: + * @entry: the #NmtNewtEntry + * @text: the current contents of @entry + * @ch: the character just typed + * @position: the position of the cursor in @entry + * @user_data: the data passed to nmt_newt_entry_set_filter() + * + * Callback function used to filter the contents of an entry. + * + * Returns: %TRUE if @ch should be accepted, %FALSE if not + */ + +/** + * nmt_newt_entry_set_filter: + * @entry: an #NmtNewtEntry + * @filter: the function to use to filter the entry + * @user_data: data for @filter + * + * Sets a #NmtNewtEntryFilter on @entry, to allow filtering out + * certain characters from the entry. + * + * Note that @filter will only be called for printable characters (eg, + * not for cursor-control characters or the like), and that it will + * only be called for user input, not, eg, for + * nmt_newt_entry_set_text(). + */ +void +nmt_newt_entry_set_filter (NmtNewtEntry *entry, + NmtNewtEntryFilter filter, + gpointer user_data) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + priv->filter = filter; + priv->filter_data = user_data; +} + +static void +nmt_newt_entry_check_valid (NmtNewtEntry *entry) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + gboolean valid; + + if ( (priv->flags & NMT_NEWT_ENTRY_NONEMPTY) + && *priv->text == '\0') + valid = FALSE; + else if (priv->validator) + valid = !!priv->validator (entry, priv->text, priv->validator_data); + else + valid = TRUE; + + nmt_newt_widget_set_valid (NMT_NEWT_WIDGET (entry), valid); +} + +/** + * NmtNewtEntryValidator: + * @entry: the #NmtNewtEntry + * @text: the current contents of @entry + * @user_data: the data passed to nmt_newt_entry_set_validator() + * + * Callback function used to validate the contents of an entry. + * + * Returns: whether the entry is #NmtNewtWidget:valid + */ + +/** + * nmt_newt_entry_set_validator: + * @entry: an #NmtNewtEntry + * @validator: the function to use to validate the entry + * @user_data: data for @validator + * + * Sets a #NmtNewtEntryValidator on @entry, to allow validation of + * the entry contents. If @validator returns %FALSE, then the entry + * will not be considered #NmtNewtWidget:valid. + */ +void +nmt_newt_entry_set_validator (NmtNewtEntry *entry, + NmtNewtEntryValidator validator, + gpointer user_data) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + priv->validator = validator; + priv->validator_data = user_data; + + nmt_newt_entry_check_valid (entry); +} + +static void +nmt_newt_entry_set_text_internal (NmtNewtEntry *entry, + const char *text, + newtComponent co) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + if (!text) + text = ""; + + if (!strcmp (priv->text, text)) + return; + + g_free (priv->text); + priv->text = g_strdup (text); + + if (co) { + char *text_lc; + + text_lc = priv->text ? nmt_newt_locale_from_utf8 (priv->text) : NULL; + newtEntrySet (co, text_lc, TRUE); + g_free (text_lc); + priv->last_cursor_pos = -1; + } + + g_object_freeze_notify (G_OBJECT (entry)); + nmt_newt_entry_check_valid (entry); + g_object_notify (G_OBJECT (entry), "text"); + g_object_thaw_notify (G_OBJECT (entry)); +} + +/** + * nmt_newt_entry_set_text: + * @entry: an #NmtNewtEntry + * @text: the new text + * + * Updates @entry's text. Note that this skips the entry's + * #NmtNewtEntryFilter, but will cause its #NmtNewtEntryValidator to + * be re-run. + */ +void +nmt_newt_entry_set_text (NmtNewtEntry *entry, + const char *text) +{ + newtComponent co; + + co = nmt_newt_component_get_component (NMT_NEWT_COMPONENT (entry)); + nmt_newt_entry_set_text_internal (entry, text, co); +} + +/** + * nmt_newt_entry_get_text: + * @entry: an #NmtNewtEntry + * + * Gets @entry's text + * + * Returns: @entry's text + */ +const char * +nmt_newt_entry_get_text (NmtNewtEntry *entry) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + return priv->text; +} + +/** + * nmt_newt_entry_set_width: + * @entry: an #NmtNewtEntpry + * @widget: the new width + * + * Updates @entry's width + */ +void +nmt_newt_entry_set_width (NmtNewtEntry *entry, + int width) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + if (priv->width == width) + return; + + priv->width = width; + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (entry)); + + g_object_notify (G_OBJECT (entry), "width"); +} + +/** + * nmt_newt_entry_get_width: + * @entry: an #NmtNewtEntry + * + * Gets @entry's width + * + * Returns: @entry's width + */ +int +nmt_newt_entry_get_width (NmtNewtEntry *entry) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + return priv->width; +} + +static void +nmt_newt_entry_init (NmtNewtEntry *entry) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + priv->text = g_strdup (""); + priv->last_cursor_pos = -1; +} + +static void +nmt_newt_entry_constructed (GObject *object) +{ + nmt_newt_entry_check_valid (NMT_NEWT_ENTRY (object)); + + G_OBJECT_CLASS (nmt_newt_entry_parent_class)->constructed (object); +} + +static void +nmt_newt_entry_finalize (GObject *object) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (object); + + g_free (priv->text); + if (priv->idle_update) + g_source_remove (priv->idle_update); + + G_OBJECT_CLASS (nmt_newt_entry_parent_class)->finalize (object); +} + +static gboolean +idle_update_entry (gpointer entry) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + newtComponent co = nmt_newt_component_get_component (entry); + char *text; + + priv->idle_update = 0; + if (!co) + return FALSE; + + priv->last_cursor_pos = newtEntryGetCursorPosition (co); + + text = nmt_newt_locale_to_utf8 (newtEntryGetValue (co)); + nmt_newt_entry_set_text_internal (entry, text, NULL); + g_free (text); + + return FALSE; +} + +static int +entry_filter (newtComponent entry, + void *self, + int ch, + int cursor) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (self); + + if (g_ascii_isprint (ch)) { + if (priv->filter) { + char *text = nmt_newt_locale_to_utf8 (newtEntryGetValue (entry)); + + if (!priv->filter (self, text, ch, cursor, priv->filter_data)) { + g_free (text); + return 0; + } + g_free (text); + } + } + + if (!priv->idle_update) + priv->idle_update = g_idle_add (idle_update_entry, self); + return ch; +} + +static guint +convert_flags (NmtNewtEntryFlags flags) +{ + guint newt_flags = NEWT_FLAG_RETURNEXIT; + + if (!(flags & NMT_NEWT_ENTRY_NOSCROLL)) + newt_flags |= NEWT_FLAG_SCROLL; + if (flags & NMT_NEWT_ENTRY_PASSWORD) + newt_flags |= NEWT_FLAG_PASSWORD; + + return newt_flags; +} + +static newtComponent +nmt_newt_entry_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (component); + newtComponent co; + char *text_lc; + int flags; + + flags = convert_flags (priv->flags); + if (!sensitive) + flags |= NEWT_FLAG_DISABLED; + + text_lc = priv->text ? nmt_newt_locale_from_utf8 (priv->text) : NULL; + co = newtEntry (-1, -1, text_lc, priv->width, NULL, flags); + g_free (text_lc); + + if (priv->last_cursor_pos != -1) + newtEntrySetCursorPosition (co, priv->last_cursor_pos); + + newtEntrySetFilter (co, entry_filter, component); + return co; +} + +static void +nmt_newt_entry_activated (NmtNewtWidget *widget) +{ + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (widget); + + if (priv->idle_update) { + g_source_remove (priv->idle_update); + idle_update_entry (widget); + } + + NMT_NEWT_WIDGET_CLASS (nmt_newt_entry_parent_class)->activated (widget); +} + +static void +nmt_newt_entry_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtEntry *entry = NMT_NEWT_ENTRY (object); + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + switch (prop_id) { + case PROP_TEXT: + nmt_newt_entry_set_text (entry, g_value_get_string (value)); + break; + case PROP_WIDTH: + nmt_newt_entry_set_width (entry, g_value_get_int (value)); + break; + case PROP_FLAGS: + priv->flags = g_value_get_uint (value); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (entry)); + break; + case PROP_PASSWORD: + if (g_value_get_boolean (value)) + priv->flags |= NMT_NEWT_ENTRY_PASSWORD; + else + priv->flags &= ~NMT_NEWT_ENTRY_PASSWORD; + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (entry)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_entry_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtEntry *entry = NMT_NEWT_ENTRY (object); + NmtNewtEntryPrivate *priv = NMT_NEWT_ENTRY_GET_PRIVATE (entry); + + switch (prop_id) { + case PROP_TEXT: + g_value_set_string (value, nmt_newt_entry_get_text (entry)); + break; + case PROP_WIDTH: + g_value_set_int (value, priv->width); + break; + case PROP_FLAGS: + g_value_set_uint (value, priv->flags); + break; + case PROP_PASSWORD: + g_value_set_boolean (value, (priv->flags & NMT_NEWT_ENTRY_PASSWORD) != 0); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_entry_class_init (NmtNewtEntryClass *entry_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (entry_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (entry_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (entry_class); + + g_type_class_add_private (entry_class, sizeof (NmtNewtEntryPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_newt_entry_constructed; + object_class->set_property = nmt_newt_entry_set_property; + object_class->get_property = nmt_newt_entry_get_property; + object_class->finalize = nmt_newt_entry_finalize; + + widget_class->activated = nmt_newt_entry_activated; + + component_class->build_component = nmt_newt_entry_build_component; + + /** + * NmtNewtEntry:text + * + * The entry's text + */ + g_object_class_install_property (object_class, PROP_TEXT, + g_param_spec_string ("text", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtEntry:width + * + * The entry's width in characters + */ + g_object_class_install_property (object_class, PROP_WIDTH, + g_param_spec_int ("width", "", "", + -1, 80, -1, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtEntry:flags + * + * The entry's #NmtNewtEntryFlags + */ + g_object_class_install_property (object_class, PROP_FLAGS, + g_param_spec_uint ("flags", "", "", + 0, 0xFFFF, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtEntry:password + * + * %TRUE if #NmtNewtEntry:flags contains %NMT_NEWT_ENTRY_PASSWORD, + * %FALSE if not. + */ + g_object_class_install_property (object_class, PROP_PASSWORD, + g_param_spec_boolean ("password", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-entry.h b/tui/newt/nmt-newt-entry.h new file mode 100644 index 000000000..8df0b1370 --- /dev/null +++ b/tui/newt/nmt-newt-entry.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_ENTRY_H +#define NMT_NEWT_ENTRY_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_ENTRY (nmt_newt_entry_get_type ()) +#define NMT_NEWT_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_ENTRY, NmtNewtEntry)) +#define NMT_NEWT_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_ENTRY, NmtNewtEntryClass)) +#define NMT_IS_NEWT_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_ENTRY)) +#define NMT_IS_NEWT_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_ENTRY)) +#define NMT_NEWT_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_ENTRY, NmtNewtEntryClass)) + +struct _NmtNewtEntry { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtEntryClass; + +GType nmt_newt_entry_get_type (void); + +typedef gboolean (*NmtNewtEntryFilter) (NmtNewtEntry *, const char *text, int ch, int position, gpointer); +typedef gboolean (*NmtNewtEntryValidator) (NmtNewtEntry *, const char *text, gpointer); + +typedef enum { + NMT_NEWT_ENTRY_NOSCROLL = (1 << 0), + NMT_NEWT_ENTRY_PASSWORD = (1 << 1), + NMT_NEWT_ENTRY_NONEMPTY = (1 << 2) +} NmtNewtEntryFlags; + +NmtNewtWidget *nmt_newt_entry_new (int width, + NmtNewtEntryFlags flags); + +void nmt_newt_entry_set_filter (NmtNewtEntry *entry, + NmtNewtEntryFilter filter, + gpointer user_data); +void nmt_newt_entry_set_validator (NmtNewtEntry *entry, + NmtNewtEntryValidator validator, + gpointer user_data); + +void nmt_newt_entry_set_text (NmtNewtEntry *entry, + const char *text); +const char *nmt_newt_entry_get_text (NmtNewtEntry *entry); + +void nmt_newt_entry_set_width (NmtNewtEntry *entry, + int width); +int nmt_newt_entry_get_width (NmtNewtEntry *entry); + +G_END_DECLS + +#endif /* NMT_NEWT_ENTRY_H */ diff --git a/tui/newt/nmt-newt-form.c b/tui/newt/nmt-newt-form.c new file mode 100644 index 000000000..0c2063be7 --- /dev/null +++ b/tui/newt/nmt-newt-form.c @@ -0,0 +1,743 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-form + * @short_description: The top-level NmtNewt widget + * + * #NmtNewtForm is the top-level widget that contains and presents a + * "form" (aka dialog) to the user. + */ + +#include "config.h" + +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +#include <glib/gi18n-lib.h> + +#include "nmt-newt-form.h" +#include "nmt-newt-button.h" +#include "nmt-newt-grid.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtForm, nmt_newt_form, NMT_TYPE_NEWT_CONTAINER) + +#define NMT_NEWT_FORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_FORM, NmtNewtFormPrivate)) + +typedef struct { + newtComponent form; + NmtNewtWidget *content; + + guint x, y, width, height; + guint padding; + gboolean fixed_x, fixed_y; + gboolean fixed_width, fixed_height; + char *title_lc; + + gboolean dirty, escape_exits; + NmtNewtWidget *focus; +#ifdef HAVE_NEWTFORMGETSCROLLPOSITION + int scroll_position = 0; +#endif +} NmtNewtFormPrivate; + +enum { + PROP_0, + PROP_TITLE, + PROP_FULLSCREEN, + PROP_FULLSCREEN_VERTICAL, + PROP_FULLSCREEN_HORIZONTAL, + PROP_X, + PROP_Y, + PROP_WIDTH, + PROP_HEIGHT, + PROP_PADDING, + PROP_ESCAPE_EXITS, + + LAST_PROP +}; + +enum { + QUIT, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void nmt_newt_form_redraw (NmtNewtForm *form); + +/** + * nmt_newt_form_new: + * @title: (allow-none): the form title + * + * Creates a new form, which will be shown centered on the screen. + * Compare nmt_newt_form_new_fullscreen(). You can also position a + * form manually by setting its #NmtNewtForm:x and #NmtNewtForm:y + * properties at construct time, and/or by setting + * #NmtNewtForm:fullscreen, #NmtNewtform:fullscreen-horizontal, or + * #NmtNewtForm:fullscreen-vertical. + * + * If @title is NULL, the form will have no title. + * + * Returns: a new #NmtNewtForm + */ +NmtNewtForm * +nmt_newt_form_new (const char *title) +{ + return g_object_new (NMT_TYPE_NEWT_FORM, + "title", title, + NULL); +} + +/** + * nmt_newt_form_new_fullscreen: + * @title: (allow-none): the form title + * + * Creates a new fullscreen form. Compare nmt_newt_form_new(). + * + * If @title is NULL, the form will have no title. + * + * Returns: a new #NmtNewtForm + */ +NmtNewtForm * +nmt_newt_form_new_fullscreen (const char *title) +{ + return g_object_new (NMT_TYPE_NEWT_FORM, + "title", title, + "fullscreen", TRUE, + NULL); +} + +static void +nmt_newt_form_init (NmtNewtForm *form) +{ + g_object_ref_sink (form); +} + +static void +nmt_newt_form_finalize (GObject *object) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (object); + + g_free (priv->title_lc); + g_clear_object (&priv->focus); + + G_OBJECT_CLASS (nmt_newt_form_parent_class)->finalize (object); +} + +static void +nmt_newt_form_needs_rebuild (NmtNewtWidget *widget) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (widget); + + if (!priv->dirty) { + priv->dirty = TRUE; + nmt_newt_form_redraw (NMT_NEWT_FORM (widget)); + } +} + +static void +nmt_newt_form_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (container); + NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_form_parent_class); + + g_return_if_fail (widget == priv->content); + + parent_class->remove (container, widget); + priv->content = NULL; +} + +/** + * nmt_newt_form_set_content: + * @form: the #NmtNewtForm + * @content: the form's content + * + * Sets @form's content to be @content. + */ +void +nmt_newt_form_set_content (NmtNewtForm *form, + NmtNewtWidget *content) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_form_parent_class); + + if (priv->content) + nmt_newt_form_remove (NMT_NEWT_CONTAINER (form), priv->content); + + priv->content = content; + + if (priv->content) + parent_class->add (NMT_NEWT_CONTAINER (form), content); +} + +static void +nmt_newt_form_build (NmtNewtForm *form) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + int screen_height, screen_width, form_height, form_width; + newtComponent *cos; + int i; + + priv->dirty = FALSE; + nmt_newt_widget_realize (NMT_NEWT_WIDGET (form)); + + nmt_newt_widget_size_request (priv->content, &form_width, &form_height); + newtGetScreenSize (&screen_width, &screen_height); + + if (!priv->fixed_width) + priv->width = MIN (form_width + 2 * priv->padding, screen_width - 2); + if (!priv->fixed_height) + priv->height = MIN (form_height + 2 * priv->padding, screen_height - 2); + + if (!priv->fixed_x) + priv->x = (screen_width - form_width) / 2; + if (!priv->fixed_y) + priv->y = (screen_height - form_height) / 2; + + nmt_newt_widget_size_allocate (priv->content, + priv->padding, + priv->padding, + priv->width - 2 * priv->padding, + priv->height - 2 * priv->padding); + + if (priv->height - 2 * priv->padding < form_height) { + newtComponent scroll_bar = + newtVerticalScrollbar (priv->width - 1, 0, priv->height, + NEWT_COLORSET_WINDOW, + NEWT_COLORSET_ACTCHECKBOX); + + priv->form = newtForm (scroll_bar, NULL, NEWT_FLAG_NOF12); + newtFormAddComponent (priv->form, scroll_bar); + newtFormSetHeight (priv->form, priv->height - 2); + } else + priv->form = newtForm (NULL, NULL, NEWT_FLAG_NOF12); + + if (priv->escape_exits) + newtFormAddHotKey (priv->form, NEWT_KEY_ESCAPE); + + cos = nmt_newt_widget_get_components (priv->content); + for (i = 0; cos[i]; i++) + newtFormAddComponent (priv->form, cos[i]); + g_free (cos); + + if (priv->focus) { + newtComponent fco; + + fco = nmt_newt_widget_get_focus_component (priv->focus); + if (fco) + newtFormSetCurrent (priv->form, fco); + } +#ifdef HAVE_NEWTFORMGETSCROLLPOSITION + if (priv->scroll_position) + newtFormSetScrollPosition (priv->form, priv->scroll_position); +#endif + + newtOpenWindow (priv->x, priv->y, priv->width, priv->height, priv->title_lc); +} + +static void +nmt_newt_form_destroy (NmtNewtForm *form) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + +#ifdef HAVE_NEWTFORMGETSCROLLPOSITION + priv->scroll_position = newtFormGetScrollPosition (priv->form); +#endif + + newtFormDestroy (priv->form); + priv->form = NULL; + newtPopWindowNoRefresh (); + + nmt_newt_widget_unrealize (NMT_NEWT_WIDGET (form)); +} + +/* A "normal" newt program would call newtFormRun() to run newt's main loop + * and process events. But we want to let GLib's main loop control the program + * (eg, so libnm-glib can process D-Bus notifications). So we call this function + * to run a single iteration of newt's main loop (or rather, to run newt's + * main loop for 1ms) whenever there are events for newt to process (redrawing + * or keypresses). + */ +static void +nmt_newt_form_iterate (NmtNewtForm *form) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + NmtNewtWidget *focus; + struct newtExitStruct es; + + if (priv->dirty) { + nmt_newt_form_destroy (form); + nmt_newt_form_build (form); + } + + newtFormSetTimer (priv->form, 1); + newtFormRun (priv->form, &es); + + if ( es.reason == NEWT_EXIT_HOTKEY + || es.reason == NEWT_EXIT_ERROR) { + /* The user hit Esc or there was an error. */ + g_clear_object (&priv->focus); + nmt_newt_form_quit (form); + return; + } + + if (es.reason == NEWT_EXIT_COMPONENT) { + /* The user hit Return/Space on a component; update the form focus + * to point that that component, and activate it. + */ + focus = nmt_newt_widget_find_component (priv->content, es.u.co); + if (focus) { + nmt_newt_form_set_focus (form, focus); + nmt_newt_widget_activated (focus); + } + } else { + /* The 1ms timer ran out. Update focus but don't do anything else. */ + focus = nmt_newt_widget_find_component (priv->content, + newtFormGetCurrent (priv->form)); + if (focus) + nmt_newt_form_set_focus (form, focus); + } +} + +/* @form_stack keeps track of all currently-displayed forms, from top to bottom. + * @keypress_source is the global stdin-monitoring GSource. When it triggers, + * nmt_newt_form_keypress_callback() iterates the top-most form, so it can + * process the keypress. + */ +static GSList *form_stack; +static GSource *keypress_source; + +static gboolean +nmt_newt_form_keypress_callback (int fd, + GIOCondition condition, + gpointer user_data) +{ + g_return_val_if_fail (form_stack != NULL, FALSE); + + nmt_newt_form_iterate (form_stack->data); + return TRUE; +} + +static gboolean +nmt_newt_form_timeout_callback (gpointer user_data) +{ + if (form_stack) + nmt_newt_form_iterate (form_stack->data); + return FALSE; +} + +static void +nmt_newt_form_redraw (NmtNewtForm *form) +{ + g_timeout_add (0, nmt_newt_form_timeout_callback, NULL); +} + +static void +nmt_newt_form_real_show (NmtNewtForm *form) +{ + if (!keypress_source) { + GIOChannel *io; + + io = g_io_channel_unix_new (STDIN_FILENO); + keypress_source = g_io_create_watch (io, G_IO_IN); + g_source_set_can_recurse (keypress_source, TRUE); + g_source_set_callback (keypress_source, + (GSourceFunc) nmt_newt_form_keypress_callback, + NULL, NULL); + g_source_attach (keypress_source, NULL); + g_io_channel_unref (io); + } + + nmt_newt_form_build (form); + form_stack = g_slist_prepend (form_stack, g_object_ref (form)); + nmt_newt_form_redraw (form); +} + +/** + * nmt_newt_form_show: + * @form: an #NmtNewtForm + * + * Displays @form and begins running it asynchronously in the default + * #GMainContext. If another form is currently running, it will remain + * visible in the background, but will not be able to receive keyboard + * input until @form exits. + * + * Call nmt_newt_form_quit() to quit the form. + */ +void +nmt_newt_form_show (NmtNewtForm *form) +{ + NMT_NEWT_FORM_GET_CLASS (form)->show (form); +} + +/** + * nmt_newt_form_run_sync: + * @form: an #NmtNewtForm + * + * Displays @form as with nmt_newt_form_show(), but then iterates the + * #GMainContext internally until @form exits. + * + * Returns: the widget whose activation caused @form to exit, or + * %NULL if it was not caused by a widget. FIXME: this exit value is + * sort of weird and may not be 100% accurate anyway. + */ +NmtNewtWidget * +nmt_newt_form_run_sync (NmtNewtForm *form) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + + nmt_newt_form_show (form); + while (priv->form) + g_main_context_iteration (NULL, TRUE); + + return priv->focus; +} + +/** + * nmt_newt_form_quit: + * @form: an #NmtNewtForm + * + * Causes @form to exit. + */ +void +nmt_newt_form_quit (NmtNewtForm *form) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + + g_return_if_fail (priv->form != NULL); + + nmt_newt_form_destroy (form); + + form_stack = g_slist_remove (form_stack, form); + + if (form_stack) + nmt_newt_form_iterate (form_stack->data); + else if (keypress_source) { + g_source_destroy (keypress_source); + g_clear_pointer (&keypress_source, g_source_unref); + } + + g_signal_emit (form, signals[QUIT], 0); + g_object_unref (form); +} + +/** + * nmt_newt_form_set_focus: + * @form: an #NmtNewtForm + * @widget: the widget to focus + * + * Focuses @widget in @form. + */ +void +nmt_newt_form_set_focus (NmtNewtForm *form, + NmtNewtWidget *widget) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (form); + + g_return_if_fail (priv->form != NULL); + + if (priv->focus == widget) + return; + + if (priv->focus) + g_object_unref (priv->focus); + priv->focus = widget; + if (priv->focus) + g_object_ref (priv->focus); +} + +static void +nmt_newt_form_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (object); + int screen_width, screen_height; + + switch (prop_id) { + case PROP_TITLE: + if (g_value_get_string (value)) { + priv->title_lc = nmt_newt_locale_from_utf8 (g_value_get_string (value)); + } else + priv->title_lc = NULL; + break; + case PROP_FULLSCREEN: + if (g_value_get_boolean (value)) { + newtGetScreenSize (&screen_width, &screen_height); + priv->x = priv->y = 2; + priv->fixed_x = priv->fixed_y = TRUE; + priv->width = screen_width - 4; + priv->height = screen_height - 4; + priv->fixed_width = priv->fixed_height = TRUE; + } + break; + case PROP_FULLSCREEN_VERTICAL: + if (g_value_get_boolean (value)) { + newtGetScreenSize (&screen_width, &screen_height); + priv->y = 2; + priv->fixed_y = TRUE; + priv->height = screen_height - 4; + priv->fixed_height = TRUE; + } + break; + case PROP_FULLSCREEN_HORIZONTAL: + if (g_value_get_boolean (value)) { + newtGetScreenSize (&screen_width, &screen_height); + priv->x = 2; + priv->fixed_x = TRUE; + priv->width = screen_width - 4; + priv->fixed_width = TRUE; + } + break; + case PROP_X: + if (g_value_get_uint (value)) { + priv->x = g_value_get_uint (value); + priv->fixed_x = TRUE; + } + break; + case PROP_Y: + if (g_value_get_uint (value)) { + priv->y = g_value_get_uint (value); + priv->fixed_y = TRUE; + } + break; + case PROP_WIDTH: + if (g_value_get_uint (value)) { + priv->width = g_value_get_uint (value); + priv->fixed_width = TRUE; + } + break; + case PROP_HEIGHT: + if (g_value_get_uint (value)) { + priv->height = g_value_get_uint (value); + priv->fixed_height = TRUE; + } + break; + case PROP_PADDING: + priv->padding = g_value_get_uint (value); + break; + case PROP_ESCAPE_EXITS: + priv->escape_exits = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_form_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtFormPrivate *priv = NMT_NEWT_FORM_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_TITLE: + if (priv->title_lc) { + g_value_take_string (value, nmt_newt_locale_to_utf8 (priv->title_lc)); + } else + g_value_set_string (value, NULL); + break; + case PROP_X: + g_value_set_uint (value, priv->x); + break; + case PROP_Y: + g_value_set_uint (value, priv->y); + break; + case PROP_WIDTH: + g_value_set_uint (value, priv->width); + break; + case PROP_HEIGHT: + g_value_set_uint (value, priv->height); + break; + case PROP_PADDING: + g_value_set_uint (value, priv->padding); + break; + case PROP_ESCAPE_EXITS: + g_value_set_boolean (value, priv->escape_exits); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_form_class_init (NmtNewtFormClass *form_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (form_class); + NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (form_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (form_class); + + g_type_class_add_private (form_class, sizeof (NmtNewtFormPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_form_set_property; + object_class->get_property = nmt_newt_form_get_property; + object_class->finalize = nmt_newt_form_finalize; + + widget_class->needs_rebuild = nmt_newt_form_needs_rebuild; + + container_class->remove = nmt_newt_form_remove; + + form_class->show = nmt_newt_form_real_show; + + /* signals */ + + /** + * NmtNewtForm::quit: + * @form: the #NmtNewtForm + * + * Emitted when the form quits. + */ + signals[QUIT] = + g_signal_new ("quit", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NmtNewtFormClass, quit), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + /** + * NmtNewtForm:title: + * + * The form's title. If non-%NULL, this will be displayed above + * the form in its border. + */ + g_object_class_install_property (object_class, PROP_TITLE, + g_param_spec_string ("title", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:fullscreen: + * + * If %TRUE, the form will fill the entire "screen" (ie, terminal + * window). + */ + g_object_class_install_property (object_class, PROP_FULLSCREEN, + g_param_spec_boolean ("fullscreen", "", "", + FALSE, + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:fullscreen-vertical: + * + * If %TRUE, the form will fill the entire "screen" (ie, terminal + * window) vertically, but not necessarily horizontally. + */ + g_object_class_install_property (object_class, PROP_FULLSCREEN_VERTICAL, + g_param_spec_boolean ("fullscreen-vertical", "", "", + FALSE, + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:fullscreen-horizontal: + * + * If %TRUE, the form will fill the entire "screen" (ie, terminal + * window) horizontally, but not necessarily vertically. + */ + g_object_class_install_property (object_class, PROP_FULLSCREEN_HORIZONTAL, + g_param_spec_boolean ("fullscreen-horizontal", "", "", + FALSE, + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:x: + * + * The form's x coordinate. By default, the form will be centered + * on the screen. + */ + g_object_class_install_property (object_class, PROP_X, + g_param_spec_uint ("x", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:y: + * + * The form's y coordinate. By default, the form will be centered + * on the screen. + */ + g_object_class_install_property (object_class, PROP_Y, + g_param_spec_uint ("y", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:width: + * + * The form's width. By default, this will be determined by the + * width of the form's content. + */ + g_object_class_install_property (object_class, PROP_WIDTH, + g_param_spec_uint ("width", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:height: + * + * The form's height. By default, this will be determined by the + * height of the form's content. + */ + g_object_class_install_property (object_class, PROP_HEIGHT, + g_param_spec_uint ("height", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:padding: + * + * The padding between the form's content and its border. + */ + g_object_class_install_property (object_class, PROP_PADDING, + g_param_spec_uint ("padding", "", "", + 0, G_MAXUINT, 1, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); + /** + * NmtNewtForm:escape-exits: + * + * If %TRUE, then hitting the Escape key will cause the form to + * exit. + */ + g_object_class_install_property (object_class, PROP_ESCAPE_EXITS, + g_param_spec_boolean ("escape-exits", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY)); +} diff --git a/tui/newt/nmt-newt-form.h b/tui/newt/nmt-newt-form.h new file mode 100644 index 000000000..be95eb68a --- /dev/null +++ b/tui/newt/nmt-newt-form.h @@ -0,0 +1,66 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_FORM_H +#define NMT_NEWT_FORM_H + +#include "nmt-newt-container.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_FORM (nmt_newt_form_get_type ()) +#define NMT_NEWT_FORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_FORM, NmtNewtForm)) +#define NMT_NEWT_FORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_FORM, NmtNewtFormClass)) +#define NMT_IS_NEWT_FORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_FORM)) +#define NMT_IS_NEWT_FORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_FORM)) +#define NMT_NEWT_FORM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_FORM, NmtNewtFormClass)) + +struct _NmtNewtForm { + NmtNewtContainer parent; + +}; + +typedef struct { + NmtNewtContainerClass parent; + + /* signals */ + void (*quit) (NmtNewtForm *form); + + /* methods */ + void (*show) (NmtNewtForm *form); + +} NmtNewtFormClass; + +GType nmt_newt_form_get_type (void); + +NmtNewtForm *nmt_newt_form_new (const char *title); +NmtNewtForm *nmt_newt_form_new_fullscreen (const char *title); + +void nmt_newt_form_set_content (NmtNewtForm *form, + NmtNewtWidget *content); + +void nmt_newt_form_show (NmtNewtForm *form); +NmtNewtWidget *nmt_newt_form_run_sync (NmtNewtForm *form); +void nmt_newt_form_quit (NmtNewtForm *form); + +void nmt_newt_form_set_focus (NmtNewtForm *form, + NmtNewtWidget *widget); + +G_END_DECLS + +#endif /* NMT_NEWT_FORM_H */ diff --git a/tui/newt/nmt-newt-grid.c b/tui/newt/nmt-newt-grid.c new file mode 100644 index 000000000..ac9673345 --- /dev/null +++ b/tui/newt/nmt-newt-grid.c @@ -0,0 +1,472 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-grid + * @short_description: Grid container + * + * #NmtNewtGrid is the most general-purpose container widget in NmtNewt. + * + * An #NmtNewtGrid consists of a number of rows and columns. There is + * no pre-established maximum row or columns. Rather, rows and columns + * exist if and only if there are widgets in them. + * + * The width of each column is the width of the widest widget in that + * column, and the height of each row is the height of the tallest + * widget in that row. Empty rows and empty columns take up no space, + * so a grid with a single widget at 0,0 would look exactly the same + * if the widget was at 5,10 instead. + * + * If a widget's cell ends up being larger than the widget's requested + * size, then by default the widget will be centered in its cell. + * However, this can be modified by changing its #NmtNewtGridFlags. + * FIXME: the FILL/ANCHOR flags can be implemented in #NmtNewtWidget + * and so should move there. Less clear about the EXPAND flags, which + * must be implemented by the container... + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-grid.h" + +G_DEFINE_TYPE (NmtNewtGrid, nmt_newt_grid, NMT_TYPE_NEWT_CONTAINER) + +#define NMT_NEWT_GRID_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_GRID, NmtNewtGridPrivate)) + +typedef struct { + NmtNewtWidget *widget; + int x, y; + NmtNewtGridFlags flags; + int req_height, req_width; +} NmtNewtGridChild; + +typedef struct { + GArray *children; + int max_x, max_y; + int *row_heights, *col_widths; + gboolean *expand_rows, *expand_cols; + int n_expand_rows, n_expand_cols; + int req_height, req_width; +} NmtNewtGridPrivate; + +/** + * nmt_newt_grid_new: + * + * Creates a new #NmtNewtGrid + * + * Returns: a new #NmtNewtGrid + */ +NmtNewtWidget * +nmt_newt_grid_new (void) +{ + return g_object_new (NMT_TYPE_NEWT_GRID, NULL); +} + +static void +nmt_newt_grid_init (NmtNewtGrid *grid) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + + priv->children = g_array_new (FALSE, FALSE, sizeof (NmtNewtGridChild)); +} + +static void +nmt_newt_grid_finalize (GObject *object) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (object); + + g_array_unref (priv->children); + g_clear_pointer (&priv->row_heights, g_free); + g_clear_pointer (&priv->col_widths, g_free); + g_clear_pointer (&priv->expand_rows, g_free); + g_clear_pointer (&priv->expand_cols, g_free); + + G_OBJECT_CLASS (nmt_newt_grid_parent_class)->finalize (object); +} + +static int +child_sort_func (gconstpointer a, + gconstpointer b) +{ + NmtNewtGridChild *child_a = (NmtNewtGridChild *)a; + NmtNewtGridChild *child_b = (NmtNewtGridChild *)b; + + if (child_a->y != child_b->y) + return child_a->y - child_b->y; + else + return child_a->x - child_b->x; +} + +static newtComponent * +nmt_newt_grid_get_components (NmtNewtWidget *widget) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (widget); + NmtNewtGridChild *children; + GPtrArray *cos; + newtComponent *child_cos; + int i, c; + + g_array_sort (priv->children, child_sort_func); + children = (NmtNewtGridChild *)priv->children->data; + + cos = g_ptr_array_new (); + + for (i = 0; i < priv->children->len; i++) { + if (!nmt_newt_widget_get_visible (children[i].widget)) + continue; + + child_cos = nmt_newt_widget_get_components (children[i].widget); + for (c = 0; child_cos[c]; c++) + g_ptr_array_add (cos, child_cos[c]); + g_free (child_cos); + } + g_ptr_array_add (cos, NULL); + + return (newtComponent *) g_ptr_array_free (cos, FALSE); +} + +static void +nmt_newt_grid_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtNewtGrid *grid = NMT_NEWT_GRID (widget); + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data; + int row, col, i; + + g_free (priv->row_heights); + g_free (priv->col_widths); + g_free (priv->expand_rows); + g_free (priv->expand_cols); + + priv->row_heights = g_new0 (int, priv->max_y + 1); + priv->col_widths = g_new0 (int, priv->max_x + 1); + priv->expand_rows = g_new0 (gboolean, priv->max_y + 1); + priv->expand_cols = g_new0 (gboolean, priv->max_x + 1); + priv->n_expand_rows = priv->n_expand_cols = 0; + + for (row = 0; row < priv->max_y + 1; row++) { + for (col = 0; col < priv->max_x + 1; col++) { + for (i = 0; i < priv->children->len; i++) { + if (children[i].x != col || children[i].y != row) + continue; + if (!nmt_newt_widget_get_visible (children[i].widget)) + continue; + + nmt_newt_widget_size_request (children[i].widget, + &children[i].req_width, + &children[i].req_height); + if (children[i].req_height > priv->row_heights[row]) + priv->row_heights[row] = children[i].req_height; + if (children[i].req_width > priv->col_widths[col]) + priv->col_widths[col] = children[i].req_width; + + if ( (children[i].flags & NMT_NEWT_GRID_EXPAND_X) + && !priv->expand_cols[children[i].x]) { + priv->expand_cols[children[i].x] = TRUE; + priv->n_expand_cols++; + } + if ( (children[i].flags & NMT_NEWT_GRID_EXPAND_Y) + && !priv->expand_rows[children[i].y]) { + priv->expand_rows[children[i].y] = TRUE; + priv->n_expand_rows++; + } + } + } + } + + priv->req_height = priv->req_width = 0; + for (row = 0; row < priv->max_y + 1; row++) + priv->req_height += priv->row_heights[row]; + for (col = 0; col < priv->max_x + 1; col++) + priv->req_width += priv->col_widths[col]; + + *height = priv->req_height; + *width = priv->req_width; +} + +static void +nmt_newt_grid_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (widget); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data, *child; + int i, row, col; + int child_x, child_y, child_width, child_height; + int extra, extra_all, extra_some; + + extra = width - priv->req_width; + if (extra > 0 && priv->n_expand_cols) { + extra_all = extra / priv->n_expand_cols; + extra_some = extra % priv->n_expand_cols; + + for (col = 0; col < priv->max_x + 1; col++) { + if (!priv->expand_cols[col]) + continue; + priv->col_widths[col] += extra_all; + if (extra_some) { + priv->col_widths[col]++; + extra_some--; + } + } + } + + extra = height - priv->req_height; + if (extra > 0 && priv->n_expand_rows) { + extra_all = extra / priv->n_expand_rows; + extra_some = extra % priv->n_expand_rows; + + for (row = 0; row < priv->max_y + 1; row++) { + if (!priv->expand_rows[row]) + continue; + priv->row_heights[row] += extra_all; + if (extra_some) { + priv->row_heights[row]++; + extra_some--; + } + } + } + + for (i = 0; i < priv->children->len; i++) { + child = &children[i]; + if (!nmt_newt_widget_get_visible (child->widget)) + continue; + + child_x = x; + for (col = 0; col < child->x; col++) + child_x += priv->col_widths[col]; + + if ((child->flags & NMT_NEWT_GRID_FILL_X) == NMT_NEWT_GRID_FILL_X) { + child_width = priv->col_widths[child->x]; + } else { + child_width = child->req_width; + if (child->flags & NMT_NEWT_GRID_ANCHOR_RIGHT) + child_x += priv->col_widths[child->x] - child->req_width; + else if (!(child->flags & NMT_NEWT_GRID_ANCHOR_LEFT)) + child_x += (priv->col_widths[child->x] - child->req_width) / 2; + } + + child_y = y; + for (row = 0; row < child->y; row++) + child_y += priv->row_heights[row]; + + if ((child->flags & NMT_NEWT_GRID_FILL_Y) == NMT_NEWT_GRID_FILL_Y) { + child_height = priv->row_heights[child->y]; + } else { + child_height = child->req_height; + if (child->flags & NMT_NEWT_GRID_ANCHOR_BOTTOM) + child_y += priv->row_heights[child->y] - child->req_height; + else if (!(child->flags & NMT_NEWT_GRID_ANCHOR_TOP)) + child_y += (priv->row_heights[child->y] - child->req_height) / 2; + } + + nmt_newt_widget_size_allocate (child->widget, + child_x, child_y, + child_width, child_height); + } +} + +static void +nmt_newt_grid_find_size (NmtNewtGrid *grid) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data; + int i; + + priv->max_x = priv->max_y = 0; + for (i = 0; i < priv->children->len; i++) { + if (children[i].x > priv->max_x) + priv->max_x = children[i].x; + if (children[i].y > priv->max_y) + priv->max_y = children[i].y; + } +} + +/** + * nmt_newt_grid_add: + * @grid: an #NmtNewtGrid + * @widget: the widget to add + * @x: x coordinate + * @y: y coordinate + * + * Adds @widget to @grid at @x, @y. See the discussion above for more + * details of exactly how this works. + */ +void +nmt_newt_grid_add (NmtNewtGrid *grid, + NmtNewtWidget *widget, + int x, + int y) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild child; + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_grid_parent_class)->add (NMT_NEWT_CONTAINER (grid), widget); + + memset (&child, 0, sizeof (child)); + child.widget = widget; + child.x = x; + child.y = y; + child.flags = NMT_NEWT_GRID_FILL_X | NMT_NEWT_GRID_FILL_Y; + g_array_append_val (priv->children, child); + + if (x > priv->max_x) + priv->max_x = x; + if (y > priv->max_y) + priv->max_y = y; +} + +static int +find_child (NmtNewtGrid *grid, + NmtNewtWidget *widget) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data; + int i; + + for (i = 0; i < priv->children->len; i++) { + if (children[i].widget == widget) + return i; + } + + return -1; +} + +static void +nmt_newt_grid_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtGrid *grid = NMT_NEWT_GRID (container); + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + int i; + + i = find_child (grid, widget); + if (i != -1) { + g_array_remove_index (priv->children, i); + nmt_newt_grid_find_size (grid); + } + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_grid_parent_class)->remove (container, widget); +} + +/** + * nmt_newt_grid_move: + * @grid: an #NmtNewtGrid + * @widget: a child of @grid + * @x: x coordinate + * @y: y coordinate + * + * Moves @widget to the given new coordinates. + */ +void +nmt_newt_grid_move (NmtNewtGrid *grid, + NmtNewtWidget *widget, + int x, + int y) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data; + int i; + + i = find_child (grid, widget); + if (i != -1 && (children[i].x != x || children[i].y != y)) { + children[i].x = x; + children[i].y = y; + nmt_newt_grid_find_size (grid); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (grid)); + } +} + +/** + * NmtNewtGridFlags: + * @NMT_NEWT_GRID_EXPAND_X: The widget's cell should expand + * horizontally if the grid as a whole is given more width than + * it requested. + * @NMT_NEWT_GRID_EXPAND_Y: The widget's cell should expand + * vertically if the grid as a whole is given more height than + * it requested. + * @NMT_NEWT_GRID_ANCHOR_LEFT: If the widget's cell is wider than + * the widget requested, the widget should be anchored to the + * left of its cell rather than being centered. + * @NMT_NEWT_GRID_ANCHOR_RIGHT: If the widget's cell is wider than + * the widget requested, the widget should be anchored to the + * right of its cell rather than being centered. + * @NMT_NEWT_GRID_FILL_X: If the widget's cell is wider than + * the widget requested, the widget should be allocated the + * full width of the cell; this is equivalent to specifying + * both %NMT_NEWT_GRID_ANCHOR_LEFT and %NMT_NEWT_GRID_ANCHOR_RIGHT. + * @NMT_NEWT_GRID_ANCHOR_TOP: If the widget's cell is taller than + * the widget requested, the widget should be anchored to the + * top of its cell rather than being centered. + * @NMT_NEWT_GRID_ANCHOR_BOTTOM: If the widget's cell is taller than + * the widget requested, the widget should be anchored to the + * bottom of its cell rather than being centered. + * @NMT_NEWT_GRID_FILL_Y: If the widget's cell is taller than + * the widget requested, the widget should be allocated the + * full height of the cell; this is equivalent to specifying + * both %NMT_NEWT_GRID_ANCHOR_TOP and %NMT_NEWT_GRID_ANCHOR_BOTTOM. + * + * Flags describing how a widget is placed within its grid cell. + */ + +/** + * nmt_newt_grid_set_flags: + * @grid: an #NmtNewtGrid + * @widget: a child of @grid + * @flags: #NmtNewtGridFlags for @widget + * + * Sets the #NmtNewtGridFlags on @widget + */ +void +nmt_newt_grid_set_flags (NmtNewtGrid *grid, + NmtNewtWidget *widget, + NmtNewtGridFlags flags) +{ + NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (grid); + NmtNewtGridChild *children = (NmtNewtGridChild *)priv->children->data; + int i; + + i = find_child (grid, widget); + if (i != -1) + children[i].flags = flags; +} + +static void +nmt_newt_grid_class_init (NmtNewtGridClass *grid_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (grid_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (grid_class); + NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (grid_class); + + g_type_class_add_private (grid_class, sizeof (NmtNewtGridPrivate)); + + /* virtual methods */ + object_class->finalize = nmt_newt_grid_finalize; + + widget_class->get_components = nmt_newt_grid_get_components; + widget_class->size_request = nmt_newt_grid_size_request; + widget_class->size_allocate = nmt_newt_grid_size_allocate; + + container_class->remove = nmt_newt_grid_remove; +} diff --git a/tui/newt/nmt-newt-grid.h b/tui/newt/nmt-newt-grid.h new file mode 100644 index 000000000..f36a38ee8 --- /dev/null +++ b/tui/newt/nmt-newt-grid.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_GRID_H +#define NMT_NEWT_GRID_H + +#include "nmt-newt-container.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_GRID (nmt_newt_grid_get_type ()) +#define NMT_NEWT_GRID(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_GRID, NmtNewtGrid)) +#define NMT_NEWT_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_GRID, NmtNewtGridClass)) +#define NMT_IS_NEWT_GRID(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_GRID)) +#define NMT_IS_NEWT_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_GRID)) +#define NMT_NEWT_GRID_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_GRID, NmtNewtGridClass)) + +struct _NmtNewtGrid { + NmtNewtContainer parent; + +}; + +typedef struct { + NmtNewtContainerClass parent; + +} NmtNewtGridClass; + +GType nmt_newt_grid_get_type (void); + +typedef enum { + NMT_NEWT_GRID_EXPAND_X = (1 << 0), + NMT_NEWT_GRID_EXPAND_Y = (1 << 1), + NMT_NEWT_GRID_ANCHOR_LEFT = (1 << 2), + NMT_NEWT_GRID_ANCHOR_RIGHT = (1 << 3), + NMT_NEWT_GRID_FILL_X = NMT_NEWT_GRID_ANCHOR_LEFT | NMT_NEWT_GRID_ANCHOR_RIGHT, + NMT_NEWT_GRID_ANCHOR_TOP = (1 << 4), + NMT_NEWT_GRID_ANCHOR_BOTTOM = (1 << 5), + NMT_NEWT_GRID_FILL_Y = NMT_NEWT_GRID_ANCHOR_TOP | NMT_NEWT_GRID_ANCHOR_BOTTOM, +} NmtNewtGridFlags; + +NmtNewtWidget *nmt_newt_grid_new (void); + +void nmt_newt_grid_add (NmtNewtGrid *grid, + NmtNewtWidget *widget, + int x, + int y); +void nmt_newt_grid_move (NmtNewtGrid *grid, + NmtNewtWidget *widget, + int x, + int y); +void nmt_newt_grid_set_flags (NmtNewtGrid *grid, + NmtNewtWidget *widget, + NmtNewtGridFlags flags); + +G_END_DECLS + +#endif /* NMT_NEWT_GRID_H */ diff --git a/tui/newt/nmt-newt-hacks.c b/tui/newt/nmt-newt-hacks.c new file mode 100644 index 000000000..2d9b1725a --- /dev/null +++ b/tui/newt/nmt-newt-hacks.c @@ -0,0 +1,103 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-hacks + * @short_description: Hacks! + * + * This contains hacky cheating implementations of certain newt + * functions that were added after 0.52.15. + */ + +#include "config.h" + +#include "nmt-newt-hacks.h" + +#if !defined (HAVE_NEWTCOMPONENTGETSIZE) || !defined (HAVE_NEWTENTRYGETCURSORPOSITION) +struct newtComponent_0_52_15_struct_hack { + int height, width; + int top, left; + int takesFocus; + int isMapped; + + struct componentOps *ops; + + newtCallback callback; + void *callbackData; + + newtCallback destroyCallback; + void *destroyCallbackData; + + void *data; +}; +#endif + +#ifndef HAVE_NEWTCOMPONENTGETSIZE +void +newtComponentGetSize (newtComponent component, + int *width, + int *height) +{ + struct newtComponent_0_52_15_struct_hack *hack = (void *) component; + + *width = hack->width; + *height = hack->height; +} + +void +newtComponentGetPosition (newtComponent component, + int *left, + int *top) +{ + struct newtComponent_0_52_15_struct_hack *hack = (void *) component; + + *left = hack->left; + *top = hack->top; +} +#endif + +#ifndef HAVE_NEWTENTRYGETCURSORPOSITION +struct newtEntry_0_52_15_struct_hack { + int flags; + char *buf; + const char **resultPtr; + int bufAlloced; + int bufUsed; + int cursorPosition; + /* ... */ +}; + +int +newtEntryGetCursorPosition (newtComponent component) +{ + struct newtComponent_0_52_15_struct_hack *co_hack = (void *) component; + struct newtEntry_0_52_15_struct_hack *entry_hack = co_hack->data; + + return entry_hack->cursorPosition; +} + +void +newtEntrySetCursorPosition (newtComponent component, + int position) +{ + struct newtComponent_0_52_15_struct_hack *co_hack = (void *) component; + struct newtEntry_0_52_15_struct_hack *entry_hack = co_hack->data; + + entry_hack->cursorPosition = position; +} +#endif diff --git a/tui/newt/nmt-newt-hacks.h b/tui/newt/nmt-newt-hacks.h new file mode 100644 index 000000000..ba8464af0 --- /dev/null +++ b/tui/newt/nmt-newt-hacks.h @@ -0,0 +1,42 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_HACKS_H +#define NMT_NEWT_HACKS_H + +#include "config.h" + +#include <newt.h> + +#ifndef HAVE_NEWTCOMPONENTGETSIZE +void newtComponentGetSize (newtComponent component, + int *width, + int *height); + +void newtComponentGetPosition (newtComponent component, + int *left, + int *top); +#endif + +#ifndef HAVE_NEWTENTRYGETCURSORPOSITION +int newtEntryGetCursorPosition (newtComponent component); +void newtEntrySetCursorPosition (newtComponent component, + int position); +#endif + +#endif /* NMT_NEWT_HACKS_H */ diff --git a/tui/newt/nmt-newt-label.c b/tui/newt/nmt-newt-label.c new file mode 100644 index 000000000..a9d44b04f --- /dev/null +++ b/tui/newt/nmt-newt-label.c @@ -0,0 +1,323 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-label + * @short_description: Labels + * + * #NmtNewtLabel implements a single-line label. + * + * See also #NmtNewtTextbox, for multiline. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-label.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtLabel, nmt_newt_label, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_LABEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_LABEL, NmtNewtLabelPrivate)) + +typedef struct { + char *text; + NmtNewtLabelStyle style; + gboolean highlight; +} NmtNewtLabelPrivate; + +enum { + PROP_0, + PROP_TEXT, + PROP_STYLE, + PROP_HIGHLIGHT, + + LAST_PROP +}; + +/** + * nmt_newt_label_new: + * @text: the initial label text + * + * Creates a new #NmtNewtLabel + * + * Returns: a new #NmtNewtLabel + */ +NmtNewtWidget * +nmt_newt_label_new (const char *text) +{ + return g_object_new (NMT_TYPE_NEWT_LABEL, + "text", text, + NULL); +} + +/** + * nmt_newt_label_set_text: + * @label: an #NmtNewtLabel + * @text: the new text + * + * Updates @label's text. + */ +void +nmt_newt_label_set_text (NmtNewtLabel *label, + const char *text) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + if (!g_strcmp0 (priv->text, text)) + return; + + g_free (priv->text); + priv->text = g_strdup (text); + + g_object_notify (G_OBJECT (label), "text"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (label)); +} + +/** + * nmt_newt_label_get_text: + * @label: an #NmtNewtLabel + * + * Gets @label's text + * + * Returns: @label's text + */ +const char * +nmt_newt_label_get_text (NmtNewtLabel *label) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + return priv->text; +} + +/** + * NmtNewtLabelStyle: + * @NMT_NEWT_LABEL_NORMAL: a normal label + * @NMT_NEWT_LABEL_PLAIN: a "plain-looking" label + * + * The label style. Normal labels are blue. Plain labels are black, + * making them look more like they are text in their own right rather + * than just being a label for something else. + */ + +/** + * nmt_newt_label_set_style: + * @label: an #NmtNewtLabel + * @style: the #NmtNewtLabelStyle + * + * Sets the style of @label + */ +void +nmt_newt_label_set_style (NmtNewtLabel *label, + NmtNewtLabelStyle style) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + if (priv->style == style) + return; + + priv->style = style; + g_object_notify (G_OBJECT (label), "style"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (label)); +} + +/** + * nmt_newt_label_get_style: + * @label: an #NmtNewtLabel + * + * Gets the style of @label + * + * Returns: the style of @label + */ +NmtNewtLabelStyle +nmt_newt_label_get_style (NmtNewtLabel *label) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + return priv->style; +} + +/** + * nmt_newt_label_set_highlight: + * @label: an #NmtNewtLabel + * @highlight: %TRUE if @label should be highlighted + * + * Sets whether @label is highlighted. Highlighted labels are red; + * this is generally used to highlight invalid widgets. + */ +void +nmt_newt_label_set_highlight (NmtNewtLabel *label, + gboolean highlight) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + highlight = !!highlight; + if (priv->highlight == highlight) + return; + + priv->highlight = highlight; + g_object_notify (G_OBJECT (label), "highlight"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (label)); +} + +/** + * nmt_newt_label_get_highlight: + * @label: an #NmtNewtLabel + * + * Gets whether @label is highlighted. + * + * Returns: whether @label is highlighted. + */ +gboolean +nmt_newt_label_get_highlight (NmtNewtLabel *label) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (label); + + return priv->highlight; +} + +static void +nmt_newt_label_init (NmtNewtLabel *label) +{ +} + +static void +nmt_newt_label_finalize (GObject *object) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (object); + + g_free (priv->text); + + G_OBJECT_CLASS (nmt_newt_label_parent_class)->finalize (object); +} + +static newtComponent +nmt_newt_label_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (component); + newtComponent co; + char *text_lc; + + text_lc = nmt_newt_locale_from_utf8 (priv->text); + co = newtLabel (-1, -1, text_lc); + g_free (text_lc); + + if (priv->highlight) + newtLabelSetColors (co, NMT_NEWT_COLORSET_BAD_LABEL); + else if (priv->style == NMT_NEWT_LABEL_PLAIN) + newtLabelSetColors (co, NMT_NEWT_COLORSET_PLAIN_LABEL); + + return co; +} + +static void +nmt_newt_label_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtLabel *label = NMT_NEWT_LABEL (object); + + switch (prop_id) { + case PROP_TEXT: + nmt_newt_label_set_text (label, g_value_get_string (value)); + break; + case PROP_STYLE: + nmt_newt_label_set_style (label, g_value_get_int (value)); + break; + case PROP_HIGHLIGHT: + nmt_newt_label_set_highlight (label, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_label_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtLabelPrivate *priv = NMT_NEWT_LABEL_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_TEXT: + g_value_set_string (value, priv->text); + break; + case PROP_STYLE: + g_value_set_int (value, priv->style); + break; + case PROP_HIGHLIGHT: + g_value_set_boolean (value, priv->highlight); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_label_class_init (NmtNewtLabelClass *label_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (label_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (label_class); + + g_type_class_add_private (label_class, sizeof (NmtNewtLabelPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_label_set_property; + object_class->get_property = nmt_newt_label_get_property; + object_class->finalize = nmt_newt_label_finalize; + + component_class->build_component = nmt_newt_label_build_component; + + /** + * NmtNewtLabel:text: + * + * The label's text + */ + g_object_class_install_property (object_class, PROP_TEXT, + g_param_spec_string ("text", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtLabel:style: + * + * The label's #NmtNewtLabelStyle + */ + g_object_class_install_property (object_class, PROP_STYLE, + g_param_spec_int ("style", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtLabel:highlight: + * + * Whether the label is highlighted. + */ + g_object_class_install_property (object_class, PROP_HIGHLIGHT, + g_param_spec_boolean ("highlight", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-label.h b/tui/newt/nmt-newt-label.h new file mode 100644 index 000000000..a4e0dcca5 --- /dev/null +++ b/tui/newt/nmt-newt-label.h @@ -0,0 +1,66 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_LABEL_H +#define NMT_NEWT_LABEL_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_LABEL (nmt_newt_label_get_type ()) +#define NMT_NEWT_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_LABEL, NmtNewtLabel)) +#define NMT_NEWT_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_LABEL, NmtNewtLabelClass)) +#define NMT_IS_NEWT_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_LABEL)) +#define NMT_IS_NEWT_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_LABEL)) +#define NMT_NEWT_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_LABEL, NmtNewtLabelClass)) + +struct _NmtNewtLabel { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtLabelClass; + +GType nmt_newt_label_get_type (void); + +typedef enum { + NMT_NEWT_LABEL_NORMAL, + NMT_NEWT_LABEL_PLAIN +} NmtNewtLabelStyle; + +NmtNewtWidget *nmt_newt_label_new (const char *text); + +void nmt_newt_label_set_text (NmtNewtLabel *label, + const char *text); +const char *nmt_newt_label_get_text (NmtNewtLabel *label); + +void nmt_newt_label_set_style (NmtNewtLabel *label, + NmtNewtLabelStyle style); +NmtNewtLabelStyle nmt_newt_label_get_style (NmtNewtLabel *label); + +void nmt_newt_label_set_highlight (NmtNewtLabel *label, + gboolean highlight); +gboolean nmt_newt_label_get_highlight (NmtNewtLabel *label); + +G_END_DECLS + +#endif /* NMT_NEWT_LABEL_H */ diff --git a/tui/newt/nmt-newt-listbox.c b/tui/newt/nmt-newt-listbox.c new file mode 100644 index 000000000..78c55dbe3 --- /dev/null +++ b/tui/newt/nmt-newt-listbox.c @@ -0,0 +1,543 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-listbox + * @short_description: Single-choice listboxes + * + * #NmtNewtListbox implements a single-choice listbox. + * + * A listbox has some number of rows, each associated with an + * arbitrary pointer value. The pointer values do not need to be + * unique, but some APIs will not be usable if they aren't. You + * can also cause rows with %NULL keys to be treated specially. + * + * The listbox will emit #NmtNewtWidget::activate when the user + * presses Return on a selection. + */ + +#include "config.h" + +#include "nmt-newt-listbox.h" +#include "nmt-newt-form.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtListbox, nmt_newt_listbox, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_LISTBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_LISTBOX, NmtNewtListboxPrivate)) + +typedef struct { + int height, alloc_height, width; + gboolean fixed_height; + NmtNewtListboxFlags flags; + + GPtrArray *entries; + GPtrArray *keys; + + int active; + gpointer active_key; + gboolean skip_null_keys; + +} NmtNewtListboxPrivate; + +enum { + PROP_0, + PROP_HEIGHT, + PROP_FLAGS, + PROP_ACTIVE, + PROP_ACTIVE_KEY, + PROP_SKIP_NULL_KEYS, + + LAST_PROP +}; + +/** + * NmtNewtListboxFlags: + * @NMT_NEWT_LISTBOX_SCROLL: the listbox should have a scroll bar. + * @NMT_NEWT_LISTBOX_BORDER: the listbox should have a border around it. + * + * Flags describing an #NmtNewtListbox + */ + +/** + * nmt_newt_listbox_new: + * @height: the height of the listbox, or -1 for no fixed height + * @flags: the listbox flags + * + * Creates a new #NmtNewtListbox + * + * Returns: a new #NmtNewtListbox + */ +NmtNewtWidget * +nmt_newt_listbox_new (int height, + NmtNewtListboxFlags flags) +{ + return g_object_new (NMT_TYPE_NEWT_LISTBOX, + "height", height, + "flags", flags, + NULL); +} + +/** + * nmt_newt_listbox_append: + * @listbox: an #NmtNewtListbox + * @entry: the text for the new row + * @key: (allow-none): the key associated with @entry + * + * Adds a row to @listbox. + */ +void +nmt_newt_listbox_append (NmtNewtListbox *listbox, + const char *entry, + gpointer key) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + g_ptr_array_add (priv->entries, nmt_newt_locale_from_utf8 (entry)); + g_ptr_array_add (priv->keys, key); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (listbox)); +} + +/** + * nmt_newt_listbox_clear: + * @listbox: an #NmtNewtListbox + * + * Clears the contents of @listbox. + */ +void +nmt_newt_listbox_clear (NmtNewtListbox *listbox) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + g_ptr_array_set_size (priv->entries, 0); + g_ptr_array_set_size (priv->keys, 0); + + priv->active = -1; + priv->active_key = NULL; + + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (listbox)); +} + +/** + * nmt_newt_listbox_set_active: + * @listbox: an #NmtNewtListbox + * @active: the row to make active + * + * Sets @active to be the currently-selected row in @listbox, + * scrolling it into view if needed. + */ +void +nmt_newt_listbox_set_active (NmtNewtListbox *listbox, + int active) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + if (active == priv->active) + return; + + g_return_if_fail (active >= 0 && active < priv->entries->len); + g_return_if_fail (!priv->skip_null_keys || priv->keys->pdata[active]); + + priv->active = active; + priv->active_key = priv->keys->pdata[active]; + + g_object_notify (G_OBJECT (listbox), "active"); + g_object_notify (G_OBJECT (listbox), "active-key"); +} + +/** + * nmt_newt_listbox_set_active_key: + * @listbox: an #NmtNewtListbox + * @active_key: the key for the row to make active + * + * Selects the (first) row in @listbox with @active_key as its key, + * scrolling it into view if needed. + */ +void +nmt_newt_listbox_set_active_key (NmtNewtListbox *listbox, + gpointer active_key) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + int i; + + if (active_key == priv->active_key) + return; + + g_return_if_fail (!priv->skip_null_keys || active_key); + + for (i = 0; i < priv->keys->len; i++) { + if (priv->keys->pdata[i] == active_key) { + priv->active = i; + priv->active_key = active_key; + + g_object_notify (G_OBJECT (listbox), "active"); + g_object_notify (G_OBJECT (listbox), "active-key"); + return; + } + } +} + +/** + * nmt_newt_listbox_get_active: + * @listbox: an #NmtNewtListbox + * + * Gets the currently-selected row in @listbox. + * + * Returns: the currently-selected row in @listbox. + */ +int +nmt_newt_listbox_get_active (NmtNewtListbox *listbox) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + return priv->active; +} + +/** + * nmt_newt_listbox_get_active_key: + * @listbox: an #NmtNewtListbox + * + * Gets the key of the currently-selected row in @listbox. + * + * Returns: the key of the currently-selected row in @listbox. + */ +gpointer +nmt_newt_listbox_get_active_key (NmtNewtListbox *listbox) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + return priv->active_key; +} + +/** + * nmt_newt_listbox_set_height: + * @listbox: an #NmtNewtListbox + * @height: the new height, or -1 for no fixed heigh + * + * Updates @listbox's height. + */ +void +nmt_newt_listbox_set_height (NmtNewtListbox *listbox, + int height) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + priv->height = height; + priv->fixed_height = priv->height != 0; + g_object_notify (G_OBJECT (listbox), "height"); +} + +static void +nmt_newt_listbox_init (NmtNewtListbox *listbox) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + priv->entries = g_ptr_array_new_with_free_func (g_free); + priv->keys = g_ptr_array_new (); + + priv->active = -1; +} + +static void +nmt_newt_listbox_finalize (GObject *object) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (object); + + g_ptr_array_unref (priv->entries); + g_ptr_array_unref (priv->keys); + + G_OBJECT_CLASS (nmt_newt_listbox_parent_class)->finalize (object); +} + +static void +nmt_newt_listbox_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (widget); + + NMT_NEWT_WIDGET_CLASS (nmt_newt_listbox_parent_class)-> + size_request (widget, width, height); + + priv->alloc_height = -1; + if (!priv->fixed_height) + *height = 1; + priv->width = *width; +} + +static void +nmt_newt_listbox_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (widget); + + if (width > priv->width) { + newtListboxSetWidth (nmt_newt_component_get_component (NMT_NEWT_COMPONENT (widget)), + width); + } + + NMT_NEWT_WIDGET_CLASS (nmt_newt_listbox_parent_class)-> + size_allocate (widget, x, y, width, height); + + priv->alloc_height = height; + + if (!priv->fixed_height && height != priv->height) { + priv->height = height; + nmt_newt_widget_needs_rebuild (widget); + } +} + +static void +update_active_internal (NmtNewtListbox *listbox, + int new_active) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + + if (priv->active == new_active) + return; + if (new_active >= priv->keys->len) + return; + + if (priv->skip_null_keys && !priv->keys->pdata[new_active]) { + if (new_active > priv->active) { + while ( new_active < priv->entries->len + && !priv->keys->pdata[new_active]) + new_active++; + } else { + while ( new_active >= 0 + && !priv->keys->pdata[new_active]) + new_active--; + } + + if ( new_active < 0 + || new_active >= priv->entries->len + || !priv->keys->pdata[new_active]) { + g_assert (priv->active >= 0 && priv->active < priv->entries->len); + return; + } + } + + nmt_newt_listbox_set_active (listbox, new_active); +} + +static void +selection_changed_callback (newtComponent co, + void *user_data) +{ + NmtNewtListbox *listbox = user_data; + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (listbox); + int new_active; + + new_active = GPOINTER_TO_UINT (newtListboxGetCurrent (co)); + update_active_internal (listbox, new_active); + + if (priv->active != new_active) + newtListboxSetCurrent (co, priv->active); +} + +static guint +convert_flags (NmtNewtListboxFlags flags) +{ + guint newt_flags = NEWT_FLAG_RETURNEXIT; + + if (flags & NMT_NEWT_LISTBOX_SCROLL) + newt_flags |= NEWT_FLAG_SCROLL; + if (flags & NMT_NEWT_LISTBOX_BORDER) + newt_flags |= NEWT_FLAG_BORDER; + + return newt_flags; +} + +static newtComponent +nmt_newt_listbox_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (component); + newtComponent co; + int i, active; + + if (priv->active == -1) + update_active_internal (NMT_NEWT_LISTBOX (component), 0); + active = priv->active; + + co = newtListbox (-1, -1, priv->height, convert_flags (priv->flags)); + newtComponentAddCallback (co, selection_changed_callback, component); + + for (i = 0; i < priv->entries->len; i++) { + newtListboxAppendEntry (co, priv->entries->pdata[i], GUINT_TO_POINTER (i)); + if (active == -1 && priv->keys->pdata[i] == priv->active_key) + active = i; + } + + if (active != -1) + newtListboxSetCurrent (co, active); + + return co; +} + +static void +nmt_newt_listbox_activated (NmtNewtWidget *widget) +{ + NmtNewtListbox *listbox = NMT_NEWT_LISTBOX (widget); + newtComponent co = nmt_newt_component_get_component (NMT_NEWT_COMPONENT (widget)); + + nmt_newt_listbox_set_active (listbox, GPOINTER_TO_UINT (newtListboxGetCurrent (co))); + + NMT_NEWT_WIDGET_CLASS (nmt_newt_listbox_parent_class)->activated (widget); +} + +static void +nmt_newt_listbox_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtListbox *listbox = NMT_NEWT_LISTBOX (object); + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_HEIGHT: + priv->height = g_value_get_int (value); + priv->fixed_height = (priv->height != 0); + break; + case PROP_FLAGS: + priv->flags = g_value_get_uint (value); + break; + case PROP_ACTIVE: + nmt_newt_listbox_set_active (listbox, g_value_get_int (value)); + break; + case PROP_ACTIVE_KEY: + nmt_newt_listbox_set_active_key (listbox, g_value_get_pointer (value)); + break; + case PROP_SKIP_NULL_KEYS: + priv->skip_null_keys = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_listbox_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtListboxPrivate *priv = NMT_NEWT_LISTBOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_HEIGHT: + g_value_set_int (value, priv->height); + break; + case PROP_FLAGS: + g_value_set_uint (value, priv->flags); + break; + case PROP_ACTIVE: + g_value_set_int (value, priv->active); + break; + case PROP_ACTIVE_KEY: + g_value_set_pointer (value, priv->active_key); + break; + case PROP_SKIP_NULL_KEYS: + g_value_set_boolean (value, priv->skip_null_keys); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_listbox_class_init (NmtNewtListboxClass *listbox_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (listbox_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (listbox_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (listbox_class); + + g_type_class_add_private (listbox_class, sizeof (NmtNewtListboxPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_listbox_set_property; + object_class->get_property = nmt_newt_listbox_get_property; + object_class->finalize = nmt_newt_listbox_finalize; + + widget_class->size_request = nmt_newt_listbox_size_request; + widget_class->size_allocate = nmt_newt_listbox_size_allocate; + widget_class->activated = nmt_newt_listbox_activated; + + component_class->build_component = nmt_newt_listbox_build_component; + + /* properties */ + + /** + * NmtNewtListbox:height: + * + * The listbox's height, or -1 if it has no fixed height. + */ + g_object_class_install_property (object_class, PROP_HEIGHT, + g_param_spec_int ("height", "", "", + -1, 255, -1, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtListbox:flags: + * + * The listbox's #NmtNewtListboxFlags. + */ + g_object_class_install_property (object_class, PROP_FLAGS, + g_param_spec_uint ("flags", "", "", + 0, 0xFFFF, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtListbox:active: + * + * The currently-selected row. + */ + g_object_class_install_property (object_class, PROP_ACTIVE, + g_param_spec_int ("active", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtListbox:active-key: + * + * The key of the currently-selected row. + */ + g_object_class_install_property (object_class, PROP_ACTIVE_KEY, + g_param_spec_pointer ("active-key", "", "", + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtListbox:skip-null-keys: + * + * If %TRUE, rows with %NULL key values will be skipped over when + * navigating the list with the arrow keys. + */ + g_object_class_install_property (object_class, PROP_SKIP_NULL_KEYS, + g_param_spec_boolean ("skip-null-keys", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-listbox.h b/tui/newt/nmt-newt-listbox.h new file mode 100644 index 000000000..c18c9f8e6 --- /dev/null +++ b/tui/newt/nmt-newt-listbox.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_LISTBOX_H +#define NMT_NEWT_LISTBOX_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_LISTBOX (nmt_newt_listbox_get_type ()) +#define NMT_NEWT_LISTBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_LISTBOX, NmtNewtListbox)) +#define NMT_NEWT_LISTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_LISTBOX, NmtNewtListboxClass)) +#define NMT_IS_NEWT_LISTBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_LISTBOX)) +#define NMT_IS_NEWT_LISTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_LISTBOX)) +#define NMT_NEWT_LISTBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_LISTBOX, NmtNewtListboxClass)) + +struct _NmtNewtListbox { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtListboxClass; + +GType nmt_newt_listbox_get_type (void); + +typedef enum { + NMT_NEWT_LISTBOX_SCROLL = (1 << 0), + NMT_NEWT_LISTBOX_BORDER = (1 << 1) +} NmtNewtListboxFlags; + +NmtNewtWidget *nmt_newt_listbox_new (int height, + NmtNewtListboxFlags flags); + +void nmt_newt_listbox_set_height (NmtNewtListbox *listbox, + int height); + +void nmt_newt_listbox_append (NmtNewtListbox *listbox, + const char *entry, + gpointer key); +void nmt_newt_listbox_clear (NmtNewtListbox *listbox); + +void nmt_newt_listbox_set_active (NmtNewtListbox *listbox, + int active); +void nmt_newt_listbox_set_active_key (NmtNewtListbox *listbox, + gpointer active_key); + +int nmt_newt_listbox_get_active (NmtNewtListbox *listbox); +gpointer nmt_newt_listbox_get_active_key (NmtNewtListbox *listbox); + +G_END_DECLS + +#endif /* NMT_NEWT_LISTBOX_H */ diff --git a/tui/newt/nmt-newt-popup.c b/tui/newt/nmt-newt-popup.c new file mode 100644 index 000000000..e9757eac2 --- /dev/null +++ b/tui/newt/nmt-newt-popup.c @@ -0,0 +1,343 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-popup + * @short_description: Pop-up menus + * + * #NmtNewtPopup implements a pop-up menu. When inactive, they appear + * the same as #NmtNewtButtons, displaying the label from the + * #NmtNewtPopup:active entry. When activated, they pop up a temporary + * #NmtNewtForm containing an #NmtNewtListbox to select from. + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> + +#include "nmt-newt-popup.h" +#include "nmt-newt-form.h" +#include "nmt-newt-hacks.h" +#include "nmt-newt-listbox.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtPopup, nmt_newt_popup, NMT_TYPE_NEWT_BUTTON) + +#define NMT_NEWT_POPUP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_POPUP, NmtNewtPopupPrivate)) + +typedef struct { + GArray *entries; + int active; +} NmtNewtPopupPrivate; + +enum { + PROP_0, + PROP_ACTIVE, + PROP_ACTIVE_ID, + + LAST_PROP +}; + +/** + * NmtNewtPopupEntry: + * @label: the user-visible label for the entry + * @id: the internal ID of the entry + * + * A single entry in a pop-up menu. + */ + +/** + * nmt_newt_popup_new: + * @entries: an array of #NmtNewtPopupEntry, terminated by an + * entry with a %NULL label + * + * Creates a new #NmtNewtPopup with the given entries. + * + * Returns: a new #NmtNewtPopup + */ +NmtNewtWidget * +nmt_newt_popup_new (NmtNewtPopupEntry *entries) +{ + NmtNewtWidget *widget; + NmtNewtPopupPrivate *priv; + int i; + + widget = g_object_new (NMT_TYPE_NEWT_POPUP, NULL); + priv = NMT_NEWT_POPUP_GET_PRIVATE (widget); + + for (i = 0; entries[i].label; i++) { + NmtNewtPopupEntry entry; + + entry.label = nmt_newt_locale_from_utf8 (_(entries[i].label)); + entry.id = g_strdup (entries[i].id); + g_array_append_val (priv->entries, entry); + } + + return widget; +} + +static void +popup_entry_clear_func (NmtNewtPopupEntry *entry) +{ + g_free (entry->label); + g_free (entry->id); +} + +static void +nmt_newt_popup_init (NmtNewtPopup *popup) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup); + + priv->entries = g_array_sized_new (FALSE, FALSE, sizeof (NmtNewtPopupEntry), 10); + g_array_set_clear_func (priv->entries, (GDestroyNotify) popup_entry_clear_func); +} + +static void +nmt_newt_popup_finalize (GObject *object) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (object); + + g_array_unref (priv->entries); + + G_OBJECT_CLASS (nmt_newt_popup_parent_class)->finalize (object); +} + +static newtComponent +nmt_newt_popup_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (component); + NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data; + + nmt_newt_button_set_label (NMT_NEWT_BUTTON (component), + entries[priv->active].label); + return NMT_NEWT_COMPONENT_CLASS (nmt_newt_popup_parent_class)-> + build_component (component, sensitive); +} + +static void +nmt_newt_popup_activated (NmtNewtWidget *widget) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (widget); + NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data; + NmtNewtForm *form; + NmtNewtWidget *listbox, *ret; + int button_x, button_y; + int window_x, window_y; + int list_w, list_h; + int i, active; + + listbox = nmt_newt_listbox_new (priv->entries->len, 0); + nmt_newt_widget_set_exit_on_activate (listbox, TRUE); + for (i = 0; i < priv->entries->len; i++) + nmt_newt_listbox_append (NMT_NEWT_LISTBOX (listbox), entries[i].label, NULL); + nmt_newt_listbox_set_active (NMT_NEWT_LISTBOX (listbox), priv->active); + + nmt_newt_widget_size_request (listbox, &list_w, &list_h); + newtComponentGetPosition (nmt_newt_component_get_component (NMT_NEWT_COMPONENT (widget)), + &button_x, &button_y); + window_x = button_x + 4; + window_y = button_y + 2 - priv->active; + + form = g_object_new (NMT_TYPE_NEWT_FORM, + "x", window_x, + "y", window_y, + "width", list_w, + "height", list_h, + "padding", 0, + "escape-exits", TRUE, + NULL); + nmt_newt_form_set_content (form, listbox); + + ret = nmt_newt_form_run_sync (form); + if (ret == listbox) + active = nmt_newt_listbox_get_active (NMT_NEWT_LISTBOX (listbox)); + else + active = priv->active; + + g_object_unref (form); + + if (active != priv->active) { + priv->active = active; + g_object_notify (G_OBJECT (widget), "active"); + g_object_notify (G_OBJECT (widget), "active-id"); + nmt_newt_widget_needs_rebuild (widget); + } + + NMT_NEWT_WIDGET_CLASS (nmt_newt_popup_parent_class)->activated (widget); +} + +/** + * nmt_newt_popup_get_active: + * @popup: a #NmtNewtPopup + * + * Gets the index of the active entry in @popup. + * + * Returns: the index of the active entry in @popup. + */ +int +nmt_newt_popup_get_active (NmtNewtPopup *popup) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup); + + return priv->active; +} + +/** + * nmt_newt_popup_set_active: + * @popup: a #NmtNewtPopup + * @active: the index of the new active entry + * + * Sets the active entry in @popup. + */ +void +nmt_newt_popup_set_active (NmtNewtPopup *popup, + int active) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup); + + active = CLAMP (active, 0, priv->entries->len - 1); + + if (active != priv->active) { + priv->active = active; + g_object_notify (G_OBJECT (popup), "active"); + g_object_notify (G_OBJECT (popup), "active-id"); + } +} + +/** + * nmt_newt_popup_get_active_id: + * @popup: a #NmtNewtPopup + * + * Gets the textual ID of the active entry in @popup. + * + * Returns: the ID of the active entry in @popup. + */ +const char * +nmt_newt_popup_get_active_id (NmtNewtPopup *popup) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup); + NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data; + + return entries[priv->active].id; +} + +/** + * nmt_newt_popup_set_active_id: + * @popup: a #NmtNewtPopup + * @active_id: the ID of the new active entry + * + * Sets the active entry in @popup. + */ +void +nmt_newt_popup_set_active_id (NmtNewtPopup *popup, + const char *active_id) +{ + NmtNewtPopupPrivate *priv = NMT_NEWT_POPUP_GET_PRIVATE (popup); + NmtNewtPopupEntry *entries = (NmtNewtPopupEntry *)priv->entries->data; + int i; + + for (i = 0; i < priv->entries->len; i++) { + if (!g_strcmp0 (active_id, entries[i].id)) { + nmt_newt_popup_set_active (popup, i); + return; + } + } +} + +static void +nmt_newt_popup_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtPopup *popup = NMT_NEWT_POPUP (object); + + switch (prop_id) { + case PROP_ACTIVE: + nmt_newt_popup_set_active (popup, g_value_get_uint (value)); + break; + case PROP_ACTIVE_ID: + nmt_newt_popup_set_active_id (popup, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_popup_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtPopup *popup = NMT_NEWT_POPUP (object); + + switch (prop_id) { + case PROP_ACTIVE: + g_value_set_uint (value, nmt_newt_popup_get_active (popup)); + break; + case PROP_ACTIVE_ID: + g_value_set_string (value, nmt_newt_popup_get_active_id (popup)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_popup_class_init (NmtNewtPopupClass *popup_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (popup_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (popup_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (popup_class); + + g_type_class_add_private (popup_class, sizeof (NmtNewtPopupPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_popup_set_property; + object_class->get_property = nmt_newt_popup_get_property; + object_class->finalize = nmt_newt_popup_finalize; + + widget_class->activated = nmt_newt_popup_activated; + + component_class->build_component = nmt_newt_popup_build_component; + + /** + * NmtNewtPopup:active: + * + * The index of the currently-active entry. + */ + g_object_class_install_property (object_class, PROP_ACTIVE, + g_param_spec_uint ("active", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtPopup:active-id: + * + * The textual ID of the currently-active entry. + */ + g_object_class_install_property (object_class, PROP_ACTIVE_ID, + g_param_spec_string ("active-id", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-popup.h b/tui/newt/nmt-newt-popup.h new file mode 100644 index 000000000..643ea2d8c --- /dev/null +++ b/tui/newt/nmt-newt-popup.h @@ -0,0 +1,62 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_POPUP_H +#define NMT_NEWT_POPUP_H + +#include "nmt-newt-button.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_POPUP (nmt_newt_popup_get_type ()) +#define NMT_NEWT_POPUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_POPUP, NmtNewtPopup)) +#define NMT_NEWT_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_POPUP, NmtNewtPopupClass)) +#define NMT_IS_NEWT_POPUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_POPUP)) +#define NMT_IS_NEWT_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_POPUP)) +#define NMT_NEWT_POPUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_POPUP, NmtNewtPopupClass)) + +struct _NmtNewtPopup { + NmtNewtButton parent; + +}; + +typedef struct { + NmtNewtButtonClass parent; + +} NmtNewtPopupClass; + +GType nmt_newt_popup_get_type (void); + +typedef struct { + char *label; + char *id; +} NmtNewtPopupEntry; + +NmtNewtWidget *nmt_newt_popup_new (NmtNewtPopupEntry *entries); + +int nmt_newt_popup_get_active (NmtNewtPopup *popup); +void nmt_newt_popup_set_active (NmtNewtPopup *popup, + int active); + +const char *nmt_newt_popup_get_active_id (NmtNewtPopup *popup); +void nmt_newt_popup_set_active_id (NmtNewtPopup *popup, + const char *active_id); + +G_END_DECLS + +#endif /* NMT_NEWT_POPUP_H */ diff --git a/tui/newt/nmt-newt-section.c b/tui/newt/nmt-newt-section.c new file mode 100644 index 000000000..094b41b73 --- /dev/null +++ b/tui/newt/nmt-newt-section.c @@ -0,0 +1,408 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-section + * @short_description: A collapsible section + * + * #NmtNewtSection is a container with two children; the header and + * the body. The header is always visible, but the body is only + * visible when the container is #NmtNewtSection:open. + * + * Note that there is no default way to open and close an + * #NmtNewtSection. You need to implement this yourself. (Eg, by + * binding the #NmtToggleButton:active property of an #NmtToggleButton + * in the section's header to the section's #NmtNewtSection:open + * property.) + * + * In addition to the header and body, the #NmtNewtSection also draws + * a border along the left side, indicating the extent of the section. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-section.h" +#include "nmt-newt-grid.h" +#include "nmt-newt-label.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtSection, nmt_newt_section, NMT_TYPE_NEWT_CONTAINER) + +#define NMT_NEWT_SECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_SECTION, NmtNewtSectionPrivate)) + +typedef struct { + NmtNewtWidget *header; + int hheight_req, hwidth_req; + + NmtNewtWidget *body; + int bheight_req, bwidth_req; + + NmtNewtWidget *border_grid; + NmtNewtWidget *border_open_label; + NmtNewtWidget *border_closed_label; + NmtNewtWidget *border_end_label; + GPtrArray *border_line_labels; + + gboolean open; +} NmtNewtSectionPrivate; + +static char *closed_glyph, *open_glyph, *line_glyph, *end_glyph; + +enum { + PROP_0, + + PROP_OPEN, + + LAST_PROP +}; + +/** + * nmt_newt_section_new: + * + * Creates a new #NmtNewtSection + * + * Returns: a new #NmtNewtSection + */ +NmtNewtWidget * +nmt_newt_section_new (void) +{ + return g_object_new (NMT_TYPE_NEWT_SECTION, + NULL); +} + +static void +nmt_newt_section_init (NmtNewtSection *section) +{ + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section); + NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class); + + priv->border_grid = nmt_newt_grid_new (); + parent_class->add (NMT_NEWT_CONTAINER (section), priv->border_grid); + + priv->border_open_label = nmt_newt_label_new (open_glyph); + nmt_newt_widget_set_visible (priv->border_open_label, FALSE); + nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), priv->border_open_label, 0, 0); + + priv->border_closed_label = nmt_newt_label_new (closed_glyph); + nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), priv->border_closed_label, 0, 0); + + priv->border_end_label = nmt_newt_label_new (end_glyph); + nmt_newt_widget_set_visible (priv->border_open_label, FALSE); + nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), priv->border_end_label, 0, 1); + + priv->border_line_labels = g_ptr_array_new (); +} + +static void +nmt_newt_section_finalize (GObject *object) +{ + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (object); + + g_ptr_array_unref (priv->border_line_labels); + + G_OBJECT_CLASS (nmt_newt_section_parent_class)->finalize (object); +} + +/** + * nmt_newt_section_set_header: + * @section: an #NmtNewtSection + * @header: the header widget + * + * Sets @section's header widget. + */ +void +nmt_newt_section_set_header (NmtNewtSection *section, + NmtNewtWidget *header) +{ + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section); + NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class); + NmtNewtContainer *container = NMT_NEWT_CONTAINER (section); + + if (priv->header) + parent_class->remove (container, priv->header); + priv->header = header; + parent_class->add (container, header); +} + +/** + * nmt_newt_section_get_header: + * @section: an #NmtNewtSection + * + * Gets @section's header widget. + * + * Returns: @section's header widget. + */ +NmtNewtWidget * +nmt_newt_section_get_header (NmtNewtSection *section) +{ + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section); + + return priv->header; +} + +/** + * nmt_newt_section_set_body: + * @section: an #NmtNewtSection + * @body: the body widget + * + * Sets @section's body widget. + */ +void +nmt_newt_section_set_body (NmtNewtSection *section, + NmtNewtWidget *body) +{ + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section); + NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class); + NmtNewtContainer *container = NMT_NEWT_CONTAINER (section); + + if (priv->body) + parent_class->remove (container, priv->body); + priv->body = body; + parent_class->add (container, body); +} + +/** + * nmt_newt_section_get_body: + * @section: an #NmtNewtSection + * + * Gets @section's body widget. + * + * Returns: @section's body widget. + */ +NmtNewtWidget * +nmt_newt_section_get_body (NmtNewtSection *section) +{ + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section); + + return priv->body; +} + +static void +nmt_newt_section_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtSection *section = NMT_NEWT_SECTION (container); + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (section); + NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_newt_section_parent_class); + + if (widget == priv->header) + priv->header = NULL; + else if (widget == priv->body) + priv->body = NULL; + else if (widget == priv->border_grid) + priv->border_grid = NULL; + + parent_class->remove (container, widget); +} + +static newtComponent * +nmt_newt_section_get_components (NmtNewtWidget *widget) +{ + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (widget); + newtComponent *child_cos; + GPtrArray *cos; + int i; + + g_return_val_if_fail (priv->header != NULL && priv->body != NULL, NULL); + + cos = g_ptr_array_new (); + + child_cos = nmt_newt_widget_get_components (priv->border_grid); + for (i = 0; child_cos[i]; i++) + g_ptr_array_add (cos, child_cos[i]); + g_free (child_cos); + + child_cos = nmt_newt_widget_get_components (priv->header); + for (i = 0; child_cos[i]; i++) + g_ptr_array_add (cos, child_cos[i]); + g_free (child_cos); + + if (priv->open) { + child_cos = nmt_newt_widget_get_components (priv->body); + for (i = 0; child_cos[i]; i++) + g_ptr_array_add (cos, child_cos[i]); + g_free (child_cos); + } + + g_ptr_array_add (cos, NULL); + return (newtComponent *) g_ptr_array_free (cos, FALSE); +} + +static void +nmt_newt_section_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (widget); + int border_width, border_height; + + g_return_if_fail (priv->header != NULL && priv->body != NULL); + + nmt_newt_widget_size_request (priv->border_grid, &border_width, &border_height); + nmt_newt_widget_size_request (priv->header, &priv->hwidth_req, &priv->hheight_req); + nmt_newt_widget_size_request (priv->body, &priv->bwidth_req, &priv->bheight_req); + + *width = MAX (priv->hwidth_req, priv->bwidth_req) + 2; + *height = priv->open ? priv->hheight_req + priv->bheight_req + 1 : priv->hheight_req; +} + +static void +adjust_border_for_allocation (NmtNewtSectionPrivate *priv, + int height) +{ + int i; + + /* We have to use a series of one-line labels rather than a multi-line + * textbox, because newt will hide any component that's partially offscreen, + * but we want the on-screen portion of the border to show even if part of + * it is offscreen. + */ + + if (height == 1) { + nmt_newt_widget_set_visible (priv->border_closed_label, TRUE); + nmt_newt_widget_set_visible (priv->border_open_label, FALSE); + for (i = 0; i < priv->border_line_labels->len; i++) + nmt_newt_widget_set_visible (priv->border_line_labels->pdata[i], FALSE); + nmt_newt_widget_set_visible (priv->border_end_label, FALSE); + } else { + nmt_newt_widget_set_visible (priv->border_closed_label, FALSE); + nmt_newt_widget_set_visible (priv->border_open_label, TRUE); + for (i = 0; i < height - 2; i++) { + if (i >= priv->border_line_labels->len) { + NmtNewtWidget *label; + + label = nmt_newt_label_new (line_glyph); + g_ptr_array_add (priv->border_line_labels, label); + nmt_newt_grid_add (NMT_NEWT_GRID (priv->border_grid), label, 0, i + 1); + } else + nmt_newt_widget_set_visible (priv->border_line_labels->pdata[i], TRUE); + } + nmt_newt_widget_set_visible (priv->border_end_label, TRUE); + nmt_newt_grid_move (NMT_NEWT_GRID (priv->border_grid), priv->border_end_label, 0, height - 1); + } +} + +static void +nmt_newt_section_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (widget); + + adjust_border_for_allocation (priv, height); + + nmt_newt_widget_size_allocate (priv->border_grid, x, y, 1, height); + nmt_newt_widget_size_allocate (priv->header, x + 2, y, width, priv->hheight_req); + if (priv->open) { + nmt_newt_widget_size_allocate (priv->body, x + 2, y + priv->hheight_req, + width, height - priv->hheight_req); + } +} + +static void +nmt_newt_section_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_OPEN: + priv->open = g_value_get_boolean (value); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (object)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_section_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtSectionPrivate *priv = NMT_NEWT_SECTION_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_OPEN: + g_value_set_boolean (value, priv->open); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_section_class_init (NmtNewtSectionClass *section_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (section_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (section_class); + NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (section_class); + + g_type_class_add_private (section_class, sizeof (NmtNewtSectionPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_section_set_property; + object_class->get_property = nmt_newt_section_get_property; + object_class->finalize = nmt_newt_section_finalize; + + widget_class->get_components = nmt_newt_section_get_components; + widget_class->size_request = nmt_newt_section_size_request; + widget_class->size_allocate = nmt_newt_section_size_allocate; + + container_class->remove = nmt_newt_section_remove; + + /* properties */ + + /** + * NmtNewtSection:open: + * + * %TRUE if the section is open (ie, its body is visible), %FALSE + * if not. + */ + g_object_class_install_property (object_class, PROP_OPEN, + g_param_spec_boolean ("open", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /* globals */ + closed_glyph = nmt_newt_locale_from_utf8 ("\342\225\220"); /* ═ */ + open_glyph = nmt_newt_locale_from_utf8 ("\342\225\244"); /* ╤ */ + line_glyph = nmt_newt_locale_from_utf8 ("\342\224\202"); /* │ */ + end_glyph = nmt_newt_locale_from_utf8 ("\342\224\224"); /* └ */ + if (!closed_glyph || !open_glyph || !line_glyph || !end_glyph) { + g_clear_pointer (&closed_glyph, g_free); + g_clear_pointer (&open_glyph, g_free); + g_clear_pointer (&line_glyph, g_free); + g_clear_pointer (&end_glyph, g_free); + + closed_glyph = g_strdup ("-"); + open_glyph = g_strdup ("+"); + line_glyph = g_strdup ("|"); + end_glyph = g_strdup ("\\"); + } +} diff --git a/tui/newt/nmt-newt-section.h b/tui/newt/nmt-newt-section.h new file mode 100644 index 000000000..a943ba200 --- /dev/null +++ b/tui/newt/nmt-newt-section.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_SECTION_H +#define NMT_NEWT_SECTION_H + +#include "nmt-newt-container.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_SECTION (nmt_newt_section_get_type ()) +#define NMT_NEWT_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_SECTION, NmtNewtSection)) +#define NMT_NEWT_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_SECTION, NmtNewtSectionClass)) +#define NMT_IS_NEWT_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_SECTION)) +#define NMT_IS_NEWT_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_SECTION)) +#define NMT_NEWT_SECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_SECTION, NmtNewtSectionClass)) + +struct _NmtNewtSection { + NmtNewtContainer parent; + +}; + +typedef struct { + NmtNewtContainerClass parent; + +} NmtNewtSectionClass; + +GType nmt_newt_section_get_type (void); + +NmtNewtWidget *nmt_newt_section_new (void); + +void nmt_newt_section_set_header (NmtNewtSection *section, + NmtNewtWidget *header); +NmtNewtWidget *nmt_newt_section_get_header (NmtNewtSection *section); + +void nmt_newt_section_set_body (NmtNewtSection *section, + NmtNewtWidget *body); +NmtNewtWidget *nmt_newt_section_get_body (NmtNewtSection *section); + +G_END_DECLS + +#endif /* NMT_NEWT_SECTION_H */ diff --git a/tui/newt/nmt-newt-separator.c b/tui/newt/nmt-newt-separator.c new file mode 100644 index 000000000..07deb1af9 --- /dev/null +++ b/tui/newt/nmt-newt-separator.c @@ -0,0 +1,66 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-separator + * @short_description: Separator + * + * #NmtNewtSeparator is just a blank label, which is used in a few places + * where a widget is needed but none is desired, or to add blank space + * between widgets in containers that don't implement padding. + */ + +#include "config.h" + +#include "nmt-newt-separator.h" + +G_DEFINE_TYPE (NmtNewtSeparator, nmt_newt_separator, NMT_TYPE_NEWT_COMPONENT) + +/** + * nmt_newt_separator_new: + * + * Creates a new #NmtNewtSeparator. + * + * Returns: a new #NmtNewtSeparator + */ +NmtNewtWidget * +nmt_newt_separator_new (void) +{ + return g_object_new (NMT_TYPE_NEWT_SEPARATOR, NULL); +} + +static void +nmt_newt_separator_init (NmtNewtSeparator *separator) +{ +} + +static newtComponent +nmt_newt_separator_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + return newtLabel (-1, -1, " "); +} + +static void +nmt_newt_separator_class_init (NmtNewtSeparatorClass *separator_class) +{ + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (separator_class); + + /* virtual methods */ + component_class->build_component = nmt_newt_separator_build_component; +} diff --git a/tui/newt/nmt-newt-separator.h b/tui/newt/nmt-newt-separator.h new file mode 100644 index 000000000..3f4183d58 --- /dev/null +++ b/tui/newt/nmt-newt-separator.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_SEPARATOR_H +#define NMT_NEWT_SEPARATOR_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_SEPARATOR (nmt_newt_separator_get_type ()) +#define NMT_NEWT_SEPARATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_SEPARATOR, NmtNewtSeparator)) +#define NMT_NEWT_SEPARATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_SEPARATOR, NmtNewtSeparatorClass)) +#define NMT_IS_NEWT_SEPARATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_SEPARATOR)) +#define NMT_IS_NEWT_SEPARATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_SEPARATOR)) +#define NMT_NEWT_SEPARATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_SEPARATOR, NmtNewtSeparatorClass)) + +struct _NmtNewtSeparator { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtSeparatorClass; + +GType nmt_newt_separator_get_type (void); + +NmtNewtWidget *nmt_newt_separator_new (void); + +G_END_DECLS + +#endif /* NMT_NEWT_SEPARATOR_H */ diff --git a/tui/newt/nmt-newt-stack.c b/tui/newt/nmt-newt-stack.c new file mode 100644 index 000000000..1b31d58fe --- /dev/null +++ b/tui/newt/nmt-newt-stack.c @@ -0,0 +1,366 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-stack + * @short_description: A stack of alternative widgets + * + * #NmtNewtStack implements a stack of widgets, only one of which is + * visible at any time. + * + * The height and width of the widget is determined only by its + * visible child. Likewise, the widget's #NmtNewtWidget:valid is + * determined only by the validity of its visible child, not its other + * children. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-stack.h" + +G_DEFINE_TYPE (NmtNewtStack, nmt_newt_stack, NMT_TYPE_NEWT_CONTAINER) + +#define NMT_NEWT_STACK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_STACK, NmtNewtStackPrivate)) + +typedef struct { + GPtrArray *children; + GPtrArray *ids; + + guint active; +} NmtNewtStackPrivate; + +enum { + PROP_0, + PROP_ACTIVE, + PROP_ACTIVE_ID, + + LAST_PROP +}; + +/** + * nmt_newt_stack_new: + * + * Creates a new #NmtNewtStack + * + * Returns: a new #NmtNewtStack + */ +NmtNewtWidget * +nmt_newt_stack_new (void) +{ + return g_object_new (NMT_TYPE_NEWT_STACK, NULL); +} + +static void +nmt_newt_stack_init (NmtNewtStack *stack) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + + priv->children = g_ptr_array_new (); + priv->ids = g_ptr_array_new_with_free_func (g_free); +} + +static void +nmt_newt_stack_finalize (GObject *object) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (object); + + g_ptr_array_unref (priv->children); + g_ptr_array_unref (priv->ids); + + G_OBJECT_CLASS (nmt_newt_stack_parent_class)->finalize (object); +} + +static newtComponent * +nmt_newt_stack_get_components (NmtNewtWidget *widget) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (widget); + + if (priv->active > priv->children->len) + return NULL; + + return nmt_newt_widget_get_components (priv->children->pdata[priv->active]); +} + +static void +nmt_newt_stack_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + NmtNewtStack *stack = NMT_NEWT_STACK (widget); + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + int i, child_width, child_height; + + if (priv->active > priv->children->len) { + *width = *height = 0; + return; + } + + /* We size-request all pages so that embedded NmtPageGrids will + * participate in their size-grouping (so that switching pages + * won't result in the column widths changing). + */ + for (i = 0; i < priv->children->len; i++) { + nmt_newt_widget_size_request (priv->children->pdata[i], &child_width, &child_height); + if (i == priv->active) { + *width = child_width; + *height = child_height; + } + } +} + +static void +nmt_newt_stack_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (widget); + + if (priv->active > priv->children->len) + return; + + nmt_newt_widget_size_allocate (priv->children->pdata[priv->active], x, y, width, height); +} + +/** + * nmt_newt_stack_add: + * @stack: an #NmtNewtStack + * @id: the ID for the new page + * @widget: the widget to add + * + * Adds @widget to @stack with the given @id. + */ +void +nmt_newt_stack_add (NmtNewtStack *stack, + const char *id, + NmtNewtWidget *widget) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + + g_ptr_array_add (priv->children, widget); + g_ptr_array_add (priv->ids, g_strdup (id)); + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)->add (NMT_NEWT_CONTAINER (stack), widget); +} + +static void +nmt_newt_stack_remove (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtStack *stack = NMT_NEWT_STACK (container); + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + int i; + + NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)->remove (container, widget); + + for (i = 0; i < priv->children->len; i++) { + if (priv->children->pdata[i] == widget) { + g_ptr_array_remove_index (priv->children, i); + g_ptr_array_remove_index (priv->ids, i); + return; + } + } +} + +static void +nmt_newt_stack_child_validity_changed (NmtNewtContainer *container, + NmtNewtWidget *widget) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (container); + + if (priv->active > priv->children->len) + return; + + if (priv->children->pdata[priv->active] == (gpointer) widget) { + NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)-> + child_validity_changed (container, widget); + } +} + +/** + * nmt_newt_stack_set_active: + * @stack: an #NmtNewtStack + * @active: the index of the new active page + * + * Sets the active page on @stack to @active. + */ +void +nmt_newt_stack_set_active (NmtNewtStack *stack, + guint active) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + + if (priv->active == active) + return; + + priv->active = active; + g_object_notify (G_OBJECT (stack), "active"); + g_object_notify (G_OBJECT (stack), "active-id"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (stack)); +} + +/** + * nmt_newt_stack_get_active: + * @stack: an #NmtNewtStack + * + * Gets the index of the active page on @stack + * + * Returns: the index of the active page on @stack + */ +guint +nmt_newt_stack_get_active (NmtNewtStack *stack) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + + return priv->active; +} + +/** + * nmt_newt_stack_set_active_id: + * @stack: an #NmtNewtStack + * @active_id: the ID of the new active page + * + * Sets the active page on @stack to @active_id. + */ +void +nmt_newt_stack_set_active_id (NmtNewtStack *stack, + const char *id) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + int i; + + if (!g_strcmp0 (priv->ids->pdata[priv->active], id)) + return; + + for (i = 0; i < priv->ids->len; i++) { + if (!g_strcmp0 (priv->ids->pdata[i], id)) { + priv->active = i; + g_object_notify (G_OBJECT (stack), "active"); + g_object_notify (G_OBJECT (stack), "active-id"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (stack)); + return; + } + } +} + +/** + * nmt_newt_stack_get_active_id: + * @stack: an #NmtNewtStack + * + * Gets the ID of the active page on @stack + * + * Returns: the ID of the active page on @stack + */ +const char * +nmt_newt_stack_get_active_id (NmtNewtStack *stack) +{ + NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack); + + if (priv->active > priv->children->len) + return NULL; + + return priv->ids->pdata[priv->active]; +} + +static void +nmt_newt_stack_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtStack *stack = NMT_NEWT_STACK (object); + + switch (prop_id) { + case PROP_ACTIVE: + nmt_newt_stack_set_active (stack, g_value_get_uint (value)); + break; + case PROP_ACTIVE_ID: + nmt_newt_stack_set_active_id (stack, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_stack_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtStack *stack = NMT_NEWT_STACK (object); + + switch (prop_id) { + case PROP_ACTIVE: + g_value_set_uint (value, nmt_newt_stack_get_active (stack)); + break; + case PROP_ACTIVE_ID: + g_value_set_string (value, nmt_newt_stack_get_active_id (stack)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_stack_class_init (NmtNewtStackClass *stack_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (stack_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (stack_class); + NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (stack_class); + + g_type_class_add_private (stack_class, sizeof (NmtNewtStackPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_stack_set_property; + object_class->get_property = nmt_newt_stack_get_property; + object_class->finalize = nmt_newt_stack_finalize; + + widget_class->get_components = nmt_newt_stack_get_components; + widget_class->size_request = nmt_newt_stack_size_request; + widget_class->size_allocate = nmt_newt_stack_size_allocate; + + container_class->remove = nmt_newt_stack_remove; + container_class->child_validity_changed = nmt_newt_stack_child_validity_changed; + + /** + * NmtNewtStack:active: + * + * The index of the active page + */ + g_object_class_install_property (object_class, PROP_ACTIVE, + g_param_spec_uint ("active", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtStack:active-id: + * + * The ID of the active page + */ + g_object_class_install_property (object_class, PROP_ACTIVE_ID, + g_param_spec_string ("active-id", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-stack.h b/tui/newt/nmt-newt-stack.h new file mode 100644 index 000000000..09afe4baf --- /dev/null +++ b/tui/newt/nmt-newt-stack.h @@ -0,0 +1,61 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_STACK_H +#define NMT_NEWT_STACK_H + +#include "nmt-newt-container.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_STACK (nmt_newt_stack_get_type ()) +#define NMT_NEWT_STACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_STACK, NmtNewtStack)) +#define NMT_NEWT_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_STACK, NmtNewtStackClass)) +#define NMT_IS_NEWT_STACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_STACK)) +#define NMT_IS_NEWT_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_STACK)) +#define NMT_NEWT_STACK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_STACK, NmtNewtStackClass)) + +struct _NmtNewtStack { + NmtNewtContainer parent; + +}; + +typedef struct { + NmtNewtContainerClass parent; + +} NmtNewtStackClass; + +GType nmt_newt_stack_get_type (void); + +NmtNewtWidget *nmt_newt_stack_new (void); + +void nmt_newt_stack_add (NmtNewtStack *stack, + const char *id, + NmtNewtWidget *widget); + +void nmt_newt_stack_set_active (NmtNewtStack *stack, + guint active); +guint nmt_newt_stack_get_active (NmtNewtStack *stack); + +void nmt_newt_stack_set_active_id (NmtNewtStack *stack, + const char *id); +const char * nmt_newt_stack_get_active_id (NmtNewtStack *stack); + +G_END_DECLS + +#endif /* NMT_NEWT_STACK_H */ diff --git a/tui/newt/nmt-newt-textbox.c b/tui/newt/nmt-newt-textbox.c new file mode 100644 index 000000000..67b8b247d --- /dev/null +++ b/tui/newt/nmt-newt-textbox.c @@ -0,0 +1,292 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-textbox + * @short_description: Multi-line text box + * + * #NmtNewtTextbox implements a multi-line text, optionally with + * word-wrapping. + */ + +#include "config.h" + +#include <string.h> + +#include "nmt-newt-textbox.h" +#include "nmt-newt-utils.h" + +G_DEFINE_TYPE (NmtNewtTextbox, nmt_newt_textbox, NMT_TYPE_NEWT_COMPONENT) + +#define NMT_NEWT_TEXTBOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextboxPrivate)) + +typedef struct { + int wrap_width; + NmtNewtTextboxFlags flags; + + char *text; + int width, height; +} NmtNewtTextboxPrivate; + +enum { + PROP_0, + PROP_TEXT, + PROP_FLAGS, + PROP_WRAP_WIDTH, + + LAST_PROP +}; + +/** + * NmtNewtTextboxFlags: + * @NMT_NEWT_TEXTBOX_SCROLLABLE: the textbox should be scollable. + * @NMT_NEWT_TEXTBOX_SET_BACKGROUND: the textbox should have a + * white background + * + * Flags for an #NmtNewtTextbox + */ + +/** + * nmt_newt_textbox_new: + * @flags: the textbox's flags + * @wrap_width: width in characters at which to word-wrap, or + * 0 to not wrap. + * + * Creates a new #NmtNewtTextbox. + * + * Returns: a new #NmtNewtTextbox + */ +NmtNewtWidget * +nmt_newt_textbox_new (NmtNewtTextboxFlags flags, + int wrap_width) +{ + return g_object_new (NMT_TYPE_NEWT_TEXTBOX, + "flags", flags, + "wrap-width", wrap_width, + NULL); +} + +/** + * nmt_newt_textbox_get_text: + * @textbox: an #NmtNewtTextbox + * + * Gets @textbox's text + * + * Returns: @textbox's text + */ +void +nmt_newt_textbox_set_text (NmtNewtTextbox *textbox, + const char *text) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox); + char **lines; + int i, width; + + if (!text) + text = ""; + if (!strcmp (priv->text, text)) + return; + + g_free (priv->text); + priv->text = g_strdup (text); + + priv->width = priv->height = 0; + lines = g_strsplit (priv->text, "\n", -1); + for (i = 0; lines[i]; i++) { + width = nmt_newt_text_width (lines[i]); + if (width > priv->width) + priv->width = width; + } + g_free (lines); + priv->height = MIN (i, 1); + + g_object_notify (G_OBJECT (textbox), "text"); + nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (textbox)); +} + +/** + * nmt_newt_textbox_get_text: + * @textbox: an #NmtNewtTextbox + * + * Gets @textbox's text + * + * Returns: @textbox's text + */ +const char * +nmt_newt_textbox_get_text (NmtNewtTextbox *textbox) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox); + + return priv->text; +} + +static void +nmt_newt_textbox_init (NmtNewtTextbox *textbox) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox); + + priv->text = g_strdup (""); +} + +static void +nmt_newt_textbox_finalize (GObject *object) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (object); + + g_free (priv->text); + + G_OBJECT_CLASS (nmt_newt_textbox_parent_class)->finalize (object); +} + +static guint +convert_flags (NmtNewtTextboxFlags flags) +{ + guint newt_flags = 0; + + if (flags & NMT_NEWT_TEXTBOX_SCROLLABLE) + newt_flags |= NEWT_FLAG_SCROLL; + + return newt_flags; +} + +static newtComponent +nmt_newt_textbox_build_component (NmtNewtComponent *component, + gboolean sensitive) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (component); + newtComponent co; + const char *text; + char *text_lc; + + text = priv->text; + if (!*text) + text = "\n"; + + text_lc = nmt_newt_locale_from_utf8 (text); + if (priv->wrap_width > 0) { + co = newtTextboxReflowed (-1, -1, text_lc, priv->wrap_width, 0, 0, 0); + } else { + co = newtTextbox (-1, -1, priv->width, priv->height, convert_flags (priv->flags)); + newtTextboxSetText (co, text_lc); + } + g_free (text_lc); + + if (priv->flags & NMT_NEWT_TEXTBOX_SET_BACKGROUND) + newtTextboxSetColors (co, NMT_NEWT_COLORSET_TEXTBOX_WITH_BACKGROUND, NEWT_COLORSET_ACTTEXTBOX); + + return co; +} + +static void +nmt_newt_textbox_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtTextbox *textbox = NMT_NEWT_TEXTBOX (object); + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (textbox); + + switch (prop_id) { + case PROP_TEXT: + nmt_newt_textbox_set_text (textbox, g_value_get_string (value)); + break; + case PROP_FLAGS: + priv->flags = g_value_get_uint (value); + break; + case PROP_WRAP_WIDTH: + priv->wrap_width = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_textbox_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_TEXT: + g_value_set_string (value, priv->text); + break; + case PROP_FLAGS: + g_value_set_uint (value, priv->flags); + break; + case PROP_WRAP_WIDTH: + g_value_set_int (value, priv->wrap_width); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_textbox_class_init (NmtNewtTextboxClass *textbox_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (textbox_class); + NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS (textbox_class); + + g_type_class_add_private (textbox_class, sizeof (NmtNewtTextboxPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_textbox_set_property; + object_class->get_property = nmt_newt_textbox_get_property; + object_class->finalize = nmt_newt_textbox_finalize; + + component_class->build_component = nmt_newt_textbox_build_component; + + /** + * NmtNewtTextbox:text: + * + * The textbox's text + */ + g_object_class_install_property (object_class, PROP_TEXT, + g_param_spec_string ("text", "", "", + "", + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtTextbox:flags: + * + * The textbox's flags + */ + g_object_class_install_property (object_class, PROP_FLAGS, + g_param_spec_uint ("flags", "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtTextbox:wrap-width: + * + * The width in characters at which the textbox's text + * will wrap, or 0 if it does not wrap. + */ + g_object_class_install_property (object_class, PROP_WRAP_WIDTH, + g_param_spec_int ("wrap-width", "", "", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-textbox.h b/tui/newt/nmt-newt-textbox.h new file mode 100644 index 000000000..b3743aea0 --- /dev/null +++ b/tui/newt/nmt-newt-textbox.h @@ -0,0 +1,59 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_TEXTBOX_H +#define NMT_NEWT_TEXTBOX_H + +#include "nmt-newt-component.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_TEXTBOX (nmt_newt_textbox_get_type ()) +#define NMT_NEWT_TEXTBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextbox)) +#define NMT_NEWT_TEXTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextboxClass)) +#define NMT_IS_NEWT_TEXTBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_TEXTBOX)) +#define NMT_IS_NEWT_TEXTBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_TEXTBOX)) +#define NMT_NEWT_TEXTBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextboxClass)) + +struct _NmtNewtTextbox { + NmtNewtComponent parent; + +}; + +typedef struct { + NmtNewtComponentClass parent; + +} NmtNewtTextboxClass; + +GType nmt_newt_textbox_get_type (void); + +typedef enum { + NMT_NEWT_TEXTBOX_SCROLLABLE = (1 << 0), + NMT_NEWT_TEXTBOX_SET_BACKGROUND = (1 << 1) +} NmtNewtTextboxFlags; + +NmtNewtWidget *nmt_newt_textbox_new (NmtNewtTextboxFlags flags, + int wrap_width); + +void nmt_newt_textbox_set_text (NmtNewtTextbox *textbox, + const char *text); +const char *nmt_newt_textbox_get_text (NmtNewtTextbox *textbox); + +G_END_DECLS + +#endif /* NMT_NEWT_TEXTBOX_H */ diff --git a/tui/newt/nmt-newt-toggle-button.c b/tui/newt/nmt-newt-toggle-button.c new file mode 100644 index 000000000..d435e459e --- /dev/null +++ b/tui/newt/nmt-newt-toggle-button.c @@ -0,0 +1,234 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-toggle-button + * @short_description: Toggle buttons + * + * #NmtNewtToggleButton implements a two-state toggle button. + */ + +#include "config.h" + +#include "nmt-newt-toggle-button.h" + +G_DEFINE_TYPE (NmtNewtToggleButton, nmt_newt_toggle_button, NMT_TYPE_NEWT_BUTTON) + +#define NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButtonPrivate)) + +typedef struct { + char *on_label, *off_label; + gboolean active; +} NmtNewtToggleButtonPrivate; + +enum { + PROP_0, + PROP_ON_LABEL, + PROP_OFF_LABEL, + PROP_ACTIVE, + + LAST_PROP +}; + +/** + * nmt_newt_toggle_button_new: + * @on_label: the button's label when it is in the "on" state + * @off_label: the button's label when it is in the "off" state + * + * Creates a new #NmtNewtToggleButton + * + * Returns: a new #NmtNewtToggleButton + */ +NmtNewtWidget * +nmt_newt_toggle_button_new (const char *on_label, + const char *off_label) +{ + return g_object_new (NMT_TYPE_NEWT_TOGGLE_BUTTON, + "on-label", on_label, + "off-label", off_label, + NULL); +} + +/** + * nmt_newt_toggle_button_get_active: + * @button: an #NmtNewtToggleButton + * + * Gets whether @button is currently "on" or "off" + * + * Returns: whether @button is currently "on" (%TRUE) or "off" (%FALSE) + */ +gboolean +nmt_newt_toggle_button_get_active (NmtNewtToggleButton *button) +{ + NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (button); + + return priv->active; +} + +/** + * nmt_newt_toggle_button_set_active: + * @button: an #NmtNewtToggleButton + * @active: whether @button should be "on" or "off" + * + * Sets whether @button is currently "on" or "off" + */ +void +nmt_newt_toggle_button_set_active (NmtNewtToggleButton *button, + gboolean active) +{ + NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (button); + + if (priv->active == active) + return; + + priv->active = active; + g_object_set (G_OBJECT (button), + "label", active ? priv->on_label : priv->off_label, + NULL); + g_object_notify (G_OBJECT (button), "active"); +} + +static void +nmt_newt_toggle_button_init (NmtNewtToggleButton *button) +{ +} + +static void +nmt_newt_toggle_button_finalize (GObject *object) +{ + NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (object); + + g_free (priv->on_label); + g_free (priv->off_label); + + G_OBJECT_CLASS (nmt_newt_toggle_button_parent_class)->finalize (object); +} + +static void +nmt_newt_toggle_button_activated (NmtNewtWidget *widget) +{ + NmtNewtToggleButton *button = NMT_NEWT_TOGGLE_BUTTON (widget); + + nmt_newt_toggle_button_set_active (button, !nmt_newt_toggle_button_get_active (button)); + + NMT_NEWT_WIDGET_CLASS (nmt_newt_toggle_button_parent_class)->activated (widget); +} + +static void +nmt_newt_toggle_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_ON_LABEL: + g_free (priv->on_label); + priv->on_label = g_value_dup_string (value); + if (priv->active) + g_object_set (object, "label", priv->on_label, NULL); + break; + case PROP_OFF_LABEL: + g_free (priv->off_label); + priv->off_label = g_value_dup_string (value); + if (!priv->active) + g_object_set (object, "label", priv->off_label, NULL); + break; + case PROP_ACTIVE: + priv->active = g_value_get_boolean (value); + g_object_set (object, + "label", priv->active ? priv->on_label : priv->off_label, + NULL); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_toggle_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtToggleButtonPrivate *priv = NMT_NEWT_TOGGLE_BUTTON_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_ON_LABEL: + g_value_set_string (value, priv->on_label); + break; + case PROP_OFF_LABEL: + g_value_set_string (value, priv->off_label); + break; + case PROP_ACTIVE: + g_value_set_boolean (value, priv->active); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_toggle_button_class_init (NmtNewtToggleButtonClass *button_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (button_class); + NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (button_class); + + g_type_class_add_private (button_class, sizeof (NmtNewtToggleButtonPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_toggle_button_set_property; + object_class->get_property = nmt_newt_toggle_button_get_property; + object_class->finalize = nmt_newt_toggle_button_finalize; + + widget_class->activated = nmt_newt_toggle_button_activated; + + /** + * NmtNewtToggleButton:on-label: + * + * The label the button displays when it is "on". + */ + g_object_class_install_property (object_class, PROP_ON_LABEL, + g_param_spec_string ("on-label", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtToggleButton:off-label: + * + * The label the button displays when it is "off". + */ + g_object_class_install_property (object_class, PROP_OFF_LABEL, + g_param_spec_string ("off-label", "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtToggleButton:active: + * + * Whether the button is currently "on" (%TRUE) or "off" (%FALSE) + */ + g_object_class_install_property (object_class, PROP_ACTIVE, + g_param_spec_boolean ("active", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-toggle-button.h b/tui/newt/nmt-newt-toggle-button.h new file mode 100644 index 000000000..e54c6d3fa --- /dev/null +++ b/tui/newt/nmt-newt-toggle-button.h @@ -0,0 +1,54 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_TOGGLE_BUTTON_H +#define NMT_NEWT_TOGGLE_BUTTON_H + +#include "nmt-newt-button.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_TOGGLE_BUTTON (nmt_newt_toggle_button_get_type ()) +#define NMT_NEWT_TOGGLE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButton)) +#define NMT_NEWT_TOGGLE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButtonClass)) +#define NMT_IS_NEWT_TOGGLE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_TOGGLE_BUTTON)) +#define NMT_IS_NEWT_TOGGLE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_TOGGLE_BUTTON)) +#define NMT_NEWT_TOGGLE_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_TOGGLE_BUTTON, NmtNewtToggleButtonClass)) + +struct _NmtNewtToggleButton { + NmtNewtButton parent; + +}; + +typedef struct { + NmtNewtButtonClass parent; + +} NmtNewtToggleButtonClass; + +GType nmt_newt_toggle_button_get_type (void); + +NmtNewtWidget *nmt_newt_toggle_button_new (const char *on_label, + const char *off_label); + +gboolean nmt_newt_toggle_button_get_active (NmtNewtToggleButton *button); +void nmt_newt_toggle_button_set_active (NmtNewtToggleButton *button, + gboolean active); + +G_END_DECLS + +#endif /* NMT_NEWT_TOGGLE_BUTTON_H */ diff --git a/tui/newt/nmt-newt-types.h b/tui/newt/nmt-newt-types.h new file mode 100644 index 000000000..608f7ff6f --- /dev/null +++ b/tui/newt/nmt-newt-types.h @@ -0,0 +1,50 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_TYPES_H +#define NMT_NEWT_TYPES_H + +#include <glib-object.h> +#include <newt.h> +#include "nm-glib-compat.h" + +G_BEGIN_DECLS + +typedef struct _NmtNewtButton NmtNewtButton; +typedef struct _NmtNewtButtonBox NmtNewtButtonBox; +typedef struct _NmtNewtCheckbox NmtNewtCheckbox; +typedef struct _NmtNewtComponent NmtNewtComponent; +typedef struct _NmtNewtContainer NmtNewtContainer; +typedef struct _NmtNewtEntry NmtNewtEntry; +typedef struct _NmtNewtEntryNumeric NmtNewtEntryNumeric; +typedef struct _NmtNewtForm NmtNewtForm; +typedef struct _NmtNewtGrid NmtNewtGrid; +typedef struct _NmtNewtLabel NmtNewtLabel; +typedef struct _NmtNewtListbox NmtNewtListbox; +typedef struct _NmtNewtPopup NmtNewtPopup; +typedef struct _NmtNewtSection NmtNewtSection; +typedef struct _NmtNewtSectionBorder NmtNewtSectionBorder; +typedef struct _NmtNewtSeparator NmtNewtSeparator; +typedef struct _NmtNewtStack NmtNewtStack; +typedef struct _NmtNewtTextbox NmtNewtTextbox; +typedef struct _NmtNewtToggleButton NmtNewtToggleButton; +typedef struct _NmtNewtWidget NmtNewtWidget; + +G_END_DECLS + +#endif /* NMT_NEWT_COMPONENT_H */ diff --git a/tui/newt/nmt-newt-utils.c b/tui/newt/nmt-newt-utils.c new file mode 100644 index 000000000..68d8c449e --- /dev/null +++ b/tui/newt/nmt-newt-utils.c @@ -0,0 +1,392 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-utils + * @short_description: Utility functions + */ + +#include "config.h" + +#include <errno.h> +#include <stdarg.h> +#include <unistd.h> +#include <sys/wait.h> + +#include <glib/gi18n-lib.h> + +#include "nmt-newt-utils.h" + +static void +nmt_newt_dialog_g_log_handler (const char *log_domain, + GLogLevelFlags log_level, + const char *message, + gpointer user_data) +{ + const char *level_name; + char *full_message; + int screen_width, screen_height; + newtComponent text, ok, form; + newtGrid grid; + + g_assert (!(log_level & G_LOG_FLAG_RECURSION)); + + if (log_level & G_LOG_LEVEL_DEBUG) + return; + + switch (log_level & G_LOG_LEVEL_MASK) { + case G_LOG_LEVEL_ERROR: + level_name = "ERROR"; + break; + case G_LOG_LEVEL_CRITICAL: + level_name = "CRITICAL"; + break; + case G_LOG_LEVEL_WARNING: + level_name = "WARNING"; + break; + case G_LOG_LEVEL_MESSAGE: + level_name = "Message"; + break; + default: + level_name = NULL; + } + + full_message = g_strdup_printf ("%s%s%s%s%s", + log_domain ? log_domain : "", + log_domain && level_name ? " " : "", + level_name ? level_name : "", + log_domain || level_name ? ": " : "", + message); + + /* newtWinMessage() wraps the window too narrowly by default, so + * we don't want to use that. But we intentionally avoid using any + * NmtNewt classes, to avoid possible error recursion. + */ + + newtGetScreenSize (&screen_width, &screen_height); + text = newtTextboxReflowed (-1, -1, full_message, MAX (70, screen_width - 10), 0, 0, 0); + g_free (full_message); + + ok = newtButton (-1, -1, "OK"); + + grid = newtCreateGrid (1, 2); + newtGridSetField (grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 0, 0, 0); + newtGridSetField (grid, 0, 1, NEWT_GRID_COMPONENT, ok, 0, 1, 0, 0, + NEWT_ANCHOR_RIGHT, 0); + + newtGridWrappedWindow (grid, (char *) (level_name ? level_name : "")); + newtGridFree (grid, TRUE); + + form = newtForm (NULL, NULL, 0); + newtFormAddComponents (form, text, ok, NULL); + newtRunForm (form); + newtFormDestroy (form); + newtPopWindow (); +} + +static void +nmt_newt_basic_g_log_handler (const char *log_domain, + GLogLevelFlags log_level, + const char *message, + gpointer user_data) +{ + newtSuspend (); + g_log_default_handler (log_domain, log_level, message, NULL); + newtResume (); +} + +static void +nmt_newt_suspend_callback (gpointer user_data) +{ + newtSuspend (); + kill (getpid (), SIGTSTP); + newtResume (); +} + +/** + * nmt_newt_init: + * + * Wrapper for newtInit() that also does some nmt-newt-internal setup. + * This should be called once, before any other nmt-newt functions. + */ +void +nmt_newt_init (void) +{ + newtInit (); + newtCls (); + + newtSetColor (NEWT_COLORSET_CHECKBOX, "black", "lightgray"); + newtSetColor (NMT_NEWT_COLORSET_BAD_LABEL, "red", "lightgray"); + newtSetColor (NMT_NEWT_COLORSET_PLAIN_LABEL, "black", "lightgray"); + newtSetColor (NMT_NEWT_COLORSET_DISABLED_BUTTON, "blue", "lightgray"); + newtSetColor (NMT_NEWT_COLORSET_TEXTBOX_WITH_BACKGROUND, "black", "white"); + + if (g_getenv ("NMTUI_DEBUG")) + g_log_set_default_handler (nmt_newt_dialog_g_log_handler, NULL); + else + g_log_set_default_handler (nmt_newt_basic_g_log_handler, NULL); + + newtSetSuspendCallback (nmt_newt_suspend_callback, NULL); +} + +/** + * nmt_newt_finished: + * + * Wrapper for newtFinished(). Should be called at the end of the program. + */ +void +nmt_newt_finished (void) +{ + newtFinished (); + g_log_set_default_handler (g_log_default_handler, NULL); +} + +/** + * nmt_newt_message_dialog: + * @message: a printf()-style message format + * @...: arguments + * + * Displays the given message in a dialog box with a single "OK" + * button, and returns after the user clicks "OK". + */ +void +nmt_newt_message_dialog (const char *message, + ...) +{ + va_list ap; + char *msg, *msg_lc, *ok_lc; + + va_start (ap, message); + msg = g_strdup_vprintf (message, ap); + va_end (ap); + + msg_lc = nmt_newt_locale_from_utf8 (msg); + ok_lc = nmt_newt_locale_from_utf8 (_("OK")); + newtWinMessage (NULL, ok_lc, "%s", msg_lc); + + g_free (ok_lc); + g_free (msg_lc); + g_free (msg); +} + +/** + * nmt_newt_choice_dialog: + * @button1: the label for the first button + * @button2: the label for the second button + * @message: a printf()-style message format + * @...: arguments + * + * Displays the given message in a dialog box with two buttons with + * the indicated labels, and waits for the user to click one. + * + * Returns: which button was clicked: 0 for @button1 or 1 for @button2 + */ +int +nmt_newt_choice_dialog (const char *button1, + const char *button2, + const char *message, + ...) +{ + va_list ap; + char *msg, *msg_lc, *button1_lc, *button2_lc; + int choice; + + va_start (ap, message); + msg = g_strdup_vprintf (message, ap); + va_end (ap); + + msg_lc = nmt_newt_locale_from_utf8 (msg); + button1_lc = nmt_newt_locale_from_utf8 (button1); + button2_lc = nmt_newt_locale_from_utf8 (button2); + choice = newtWinChoice (NULL, button1_lc, button2_lc, "%s", msg_lc); + + g_free (button1_lc); + g_free (button2_lc); + g_free (msg_lc); + g_free (msg); + + return choice; +} + +/** + * nmt_newt_locale_to_utf8: + * @str_lc: a string in the user's locale encoding + * + * Convenience wrapper around g_locale_to_utf8(). + * + * Note that libnewt works in terms of the user's locale character + * set, NOT UTF-8, so all strings received from libnewt must be + * converted back to UTF-8 before being returned to the caller or used + * in other APIs. + * + * Returns: @str_lc, converted to UTF-8. + */ +char * +nmt_newt_locale_to_utf8 (const char *str_lc) +{ + char *str_utf8; + + str_utf8 = g_locale_to_utf8 (str_lc, -1, NULL, NULL, NULL); + if (!str_utf8) + str_utf8 = g_strdup (""); + return str_utf8; +} + +/** + * nmt_newt_locale_from_utf8: + * @str_utf8: a UTF-8 string + * + * Convenience wrapper around g_locale_from_utf8(). + * + * Note that libnewt works in terms of the user's locale character + * set, NOT UTF-8, so all strings from nmt-newt must be converted to + * locale encoding before being passed to libnewt. + * + * Returns: @str_utf8, converted to the user's locale encoding. + */ +char * +nmt_newt_locale_from_utf8 (const char *str_utf8) +{ + char *str_lc; + + str_lc = g_locale_from_utf8 (str_utf8, -1, NULL, NULL, NULL); + if (!str_lc) + str_lc = g_strdup (""); + return str_lc; +} + +/** + * nmt_newt_text_width + * @str: a UTF-8 string + * + * Computes the width (in terminal columns) of @str. + * + * Returns: the width of @str + */ +int +nmt_newt_text_width (const char *str) +{ + int width; + gunichar ch; + + for (width = 0; *str; str = g_utf8_next_char (str)) { + ch = g_utf8_get_char (str); + + /* Based on _vte_iso2022_unichar_width */ + if (G_LIKELY (ch < 0x80)) + width += 1; + else if (G_UNLIKELY (g_unichar_iszerowidth (ch))) + width += 0; + else if (G_UNLIKELY (g_unichar_iswide (ch))) + width += 2; + else + width += 1; + } + + return width; +} + +/** + * nmt_newt_edit_string: + * @data: data to edit + * + * libnewt does not have a multi-line editable text component, so + * nmt-newt provides this function instead, which will open the user's + * editor to edit a file containing the given @data (ensuring that the + * current screen state is saved before starting the editor and + * restored after it returns). + * + * Returns: the edited data, or %NULL if an error occurred. + */ +char * +nmt_newt_edit_string (const char *data) +{ + gssize len, nwrote; + char *filename, *argv[3]; + GError *error = NULL; + int fd, status; + char *new_data = NULL; + + fd = g_file_open_tmp ("XXXXXX.json", &filename, &error); + if (fd == -1) { + nmt_newt_message_dialog (_("Could not create temporary file: %s"), error->message); + g_error_free (error); + return NULL; + } + + len = data ? strlen (data) : 0; + while (len) { + do + nwrote = write (fd, data, len); + while (nwrote == -1 && errno == EINTR); + + len -= nwrote; + data += nwrote; + } + close (fd); + + argv[0] = (char *) g_getenv ("VISUAL"); + if (!argv[0]) + argv[0] = (char *) g_getenv ("EDITOR"); + if (!argv[0]) + argv[0] = (char *) "vi"; + argv[1] = filename; + argv[2] = NULL; + + newtSuspend (); + g_spawn_sync (NULL, argv, NULL, + G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN, + NULL, NULL, NULL, NULL, + &status, &error); + newtResume (); + + if (error) { + nmt_newt_message_dialog (_("Could not create temporary file: %s"), error->message); + g_error_free (error); + goto done; + } + +#if GLIB_CHECK_VERSION (2, 34, 0) + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + if (!g_spawn_check_exit_status (status, &error)) { + nmt_newt_message_dialog (_("Editor failed: %s"), error->message); + g_error_free (error); + goto done; + } + G_GNUC_END_IGNORE_DEPRECATIONS +#else + if (WIFEXITED (status)) { + if (WEXITSTATUS (status) != 0) + nmt_newt_message_dialog (_("Editor failed with status %d"), WEXITSTATUS (status)); + } else if (WIFSIGNALED (status)) + nmt_newt_message_dialog (_("Editor failed with signal %d"), WTERMSIG (status)); +#endif + + if (!g_file_get_contents (filename, &new_data, NULL, &error)) { + nmt_newt_message_dialog (_("Could not re-read file: %s"), error->message); + g_error_free (error); + goto done; + } + + done: + unlink (filename); + g_free (filename); + + return new_data; +} + diff --git a/tui/newt/nmt-newt-utils.h b/tui/newt/nmt-newt-utils.h new file mode 100644 index 000000000..3b37868a0 --- /dev/null +++ b/tui/newt/nmt-newt-utils.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_UTILS_H +#define NMT_NEWT_UTILS_H + +#include <newt.h> +#include <glib.h> + +G_BEGIN_DECLS + +void nmt_newt_init (void); +void nmt_newt_finished (void); + +typedef enum { + NMT_NEWT_COLORSET_BAD_LABEL = NEWT_COLORSET_CUSTOM (0), + NMT_NEWT_COLORSET_PLAIN_LABEL, + NMT_NEWT_COLORSET_DISABLED_BUTTON, + NMT_NEWT_COLORSET_TEXTBOX_WITH_BACKGROUND +} NmtNewtColorsets; + +char *nmt_newt_locale_to_utf8 (const char *str_lc); +char *nmt_newt_locale_from_utf8 (const char *str_utf8); + +int nmt_newt_text_width (const char *str); + +void nmt_newt_message_dialog (const char *message, + ...); +int nmt_newt_choice_dialog (const char *button1, + const char *button2, + const char *message, + ...); + +char *nmt_newt_edit_string (const char *data); + +G_END_DECLS + +#endif /* NMT_NEWT_UTILS_H */ diff --git a/tui/newt/nmt-newt-widget.c b/tui/newt/nmt-newt-widget.c new file mode 100644 index 000000000..24ee8b0a6 --- /dev/null +++ b/tui/newt/nmt-newt-widget.c @@ -0,0 +1,664 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +/** + * SECTION:nmt-newt-widget + * @short_description: Base TUI Widget class + * + * #NmtNewtWidget is the abstract base class for nmt-newt. All widgets + * inherit from one of its two subclasses: #NmtNewtComponent, for + * widgets that wrap a (single) #newtComponent, and #NmtNewtContainer, + * for widgets consisting of multiple components. See those classes + * for more details. + * + * With the exception of #NmtNewtForm, all widgets start out with a + * floating reference, which will be sunk by the container they are + * added to. #NmtNewtForm is the "top-level" widget type, and so does + * not have a floating reference. + * + * FIXME: need RTL support + */ + +#include "config.h" + +#include "nmt-newt-widget.h" +#include "nmt-newt-form.h" + +G_DEFINE_ABSTRACT_TYPE (NmtNewtWidget, nmt_newt_widget, G_TYPE_INITIALLY_UNOWNED) + +#define NMT_NEWT_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_WIDGET, NmtNewtWidgetPrivate)) + +typedef struct { + NmtNewtWidget *parent; + gboolean visible, realized, valid; + gboolean exit_on_activate; + + int pad_left, pad_top, pad_right, pad_bottom; +} NmtNewtWidgetPrivate; + +enum { + PROP_0, + + PROP_PARENT, + PROP_VISIBLE, + PROP_VALID, + PROP_EXIT_ON_ACTIVATE, + + LAST_PROP +}; + +enum { + NEEDS_REBUILD, + ACTIVATED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +nmt_newt_widget_init (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + priv->visible = TRUE; + priv->valid = TRUE; +} + +static void +nmt_newt_widget_finalize (GObject *object) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (object); + + nmt_newt_widget_unrealize (NMT_NEWT_WIDGET (object)); + g_clear_object (&priv->parent); + + G_OBJECT_CLASS (nmt_newt_widget_parent_class)->finalize (object); +} + +/** + * nmt_newt_widget_realize: + * @widget: an #NmtNewtWidget + * + * "Realizes" @widget. That is, creates #newtComponents corresponding + * to @widget and its children. + * + * You should not need to call this yourself; an #NmtNewtForm will + * cause its children to be realized and unrealized as needed. + */ +void +nmt_newt_widget_realize (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + if (!priv->realized) { + NMT_NEWT_WIDGET_GET_CLASS (widget)->realize (widget); + priv->realized = TRUE; + } +} + +/** + * nmt_newt_widget_unrealize: + * @widget: an #NmtNewtWidget + * + * "Unrealizes" @widget, destroying its #newtComponents. + * + * You should not need to call this yourself; an #NmtNewtForm will + * cause its children to be realized and unrealized as needed. + */ +void +nmt_newt_widget_unrealize (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + if (priv->realized) { + NMT_NEWT_WIDGET_GET_CLASS (widget)->unrealize (widget); + priv->realized = FALSE; + } +} + +/** + * nmt_newt_widget_get_realized: + * @widget: an #NmtNewtWidget + * + * Checks if @widget is realized or not. + * + * Returns: whether @widget is realized. + */ +gboolean +nmt_newt_widget_get_realized (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + return priv->realized; +} + +/** + * nmt_newt_widget_get_components: + * @widget: an #NmtNewtWidget + * + * Gets the #newtComponents that make up @widget, if @widget is + * visible. If @widget has not yet been realized, it will be realized + * first. + * + * If this function is called on a widget, then the widget will assume + * that someone else is now responsible for destroying the components, + * and so it will not destroy them itself when the widget is + * destroyed. Normally, components will end up being destroyed by the + * #NmtNewtForm they are added to. + * + * Returns: a %NULL-terminated array of components, in focus-chain + * order. You must free the array with g_free() when you are done + * with it. + */ +newtComponent * +nmt_newt_widget_get_components (NmtNewtWidget *widget) +{ + if (nmt_newt_widget_get_visible (widget)) { + nmt_newt_widget_realize (widget); + return NMT_NEWT_WIDGET_GET_CLASS (widget)->get_components (widget); + } else + return NULL; +} + +/** + * nmt_newt_widget_find_component: + * @widget: an #NmtNewtWidget + * @co: a #newtComponent + * + * Finds the widget inside @widget that owns @co. + * + * Return value: @co's owner, or %NULL if it was not found. + */ +NmtNewtWidget * +nmt_newt_widget_find_component (NmtNewtWidget *widget, + newtComponent co) +{ + return NMT_NEWT_WIDGET_GET_CLASS (widget)->find_component (widget, co); +} + +/** + * nmt_newt_widget_set_padding: + * @widget: an #NmtNewtWidget + * @pad_left: padding on the left of @widget + * @pad_top: padding on the top of @widget + * @pad_right: padding on the right of @widget + * @pad_bottom: padding on the bottom of @widget + * + * Sets the padding on @widget. + */ +void +nmt_newt_widget_set_padding (NmtNewtWidget *widget, + int pad_left, + int pad_top, + int pad_right, + int pad_bottom) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + priv->pad_left = pad_left; + priv->pad_top = pad_top; + priv->pad_right = pad_right; + priv->pad_bottom = pad_bottom; +} + +/** + * nmt_newt_widget_size_request: + * @widget: an #NmtNewtWidget + * @width: (out): on output, the widget's requested width + * @height: (out): on output, the widget's requested height + * + * Asks @widget for its requested size. If @widget is not visible, + * this will return 0, 0. If @widget has not yet been realized, it + * will be realized first. + */ +void +nmt_newt_widget_size_request (NmtNewtWidget *widget, + int *width, + int *height) +{ + if (nmt_newt_widget_get_visible (widget)) { + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + nmt_newt_widget_realize (widget); + NMT_NEWT_WIDGET_GET_CLASS (widget)->size_request (widget, width, height); + + *width += priv->pad_left + priv->pad_right; + *height += priv->pad_top + priv->pad_bottom; + } else + *width = *height = 0; +} + +/** + * nmt_newt_widget_size_allocate: + * @widget: an #NmtNewtWidget + * @x: the widget's (absolute) X coordinate + * @y: the widget's (absolute) Y coordinate + * @width: the widget's allocated width + * @height: the widget's allocated height + * + * Positions @widget at the given coordinates, with the given size. If + * @widget is not visible, this has no effect. If @widget has not yet + * been realized, it will be realized first. + * + * @x and @y are absolute coordinates (ie, relative to the screen / + * terminal window, not relative to @widget's parent). + * + * In general, the results are undefined if @width or @height is less + * than the widget's requested size. If @width or @height is larger + * than the requested size, most #NmtNewtComponents will ignore the + * extra space, but some components and most containers will expand to + * fit. + */ +void +nmt_newt_widget_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height) +{ + if (nmt_newt_widget_get_visible (widget)) { + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + nmt_newt_widget_realize (widget); + x += priv->pad_left; + y += priv->pad_top; + width -= priv->pad_left + priv->pad_right; + height -= priv->pad_top + priv->pad_bottom; + + NMT_NEWT_WIDGET_GET_CLASS (widget)->size_allocate (widget, x, y, width, height); + } +} + +/** + * nmt_newt_widget_get_focus_component: + * @widget: an #NmtNewtWidget + * + * Gets the #newtComponent that should be given the keyboard focus when + * @widget is focused. + * + * Returns: the #newtComponent to focus, or %NULL if @widget can't + * take the focus. + */ +newtComponent +nmt_newt_widget_get_focus_component (NmtNewtWidget *widget) +{ + if (!NMT_NEWT_WIDGET_GET_CLASS (widget)->get_focus_component) + return NULL; + + return NMT_NEWT_WIDGET_GET_CLASS (widget)->get_focus_component (widget); +} + +static void +nmt_newt_widget_real_activated (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + if (priv->exit_on_activate) + nmt_newt_form_quit (nmt_newt_widget_get_form (widget)); +} + +/** + * nmt_newt_widget_activated: + * @widget: an #NmtNewtWidget + * + * Tells @widget that its #newtComponent has been activated (ie, the + * user hit "Return" on it) and emits #NmtNewtWidget::activated. + * + * If #NmtNewtWidget:exit-on-activate is set on @widget, then this + * will call nmt_newt_form_quit() on the widget's form. + */ +void +nmt_newt_widget_activated (NmtNewtWidget *widget) +{ + g_signal_emit (widget, signals[ACTIVATED], 0); +} + +/** + * nmt_newt_widget_get_exit_on_activate: + * @widget: an #NmtNewtWidget + * + * Gets @widget's #NmtNewtWidget:exit-on-activate flag, qv. + * + * Returns: @widget's #NmtNewtWidget:exit-on-activate flag + */ +gboolean +nmt_newt_widget_get_exit_on_activate (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + return priv->exit_on_activate; +} + +/** + * nmt_newt_widget_set_exit_on_activate: + * @widget: an #NmtNewtWidget + * @exit_on_activate: whether @widget should exit on activate. + * + * Sets @widget's #NmtNewtWidget:exit-on-activate flag, qv. + */ +void +nmt_newt_widget_set_exit_on_activate (NmtNewtWidget *widget, + gboolean exit_on_activate) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + exit_on_activate = !!exit_on_activate; + if (priv->exit_on_activate != exit_on_activate) { + priv->exit_on_activate = exit_on_activate; + g_object_notify (G_OBJECT (widget), "exit-on-activate"); + } +} + +/** + * nmt_newt_widget_get_visible: + * @widget: an #NmtNewtWidget + * + * Gets @widget's #NmtNewtWidget:visible flag, qv. + * + * Returns: @widget's #NmtNewtWidget:visible flag + */ +gboolean +nmt_newt_widget_get_visible (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + return priv->visible; +} + +/** + * nmt_newt_widget_set_visible: + * @widget: an #NmtNewtWidget + * @visible: whether @widget should be visible + * + * Sets @widget's #NmtNewtWidget:visible flag, qv. + */ +void +nmt_newt_widget_set_visible (NmtNewtWidget *widget, + gboolean visible) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + visible = !!visible; + if (priv->visible != visible) { + priv->visible = visible; + g_object_notify (G_OBJECT (widget), "visible"); + nmt_newt_widget_needs_rebuild (widget); + } +} + +/** + * nmt_newt_widget_set_parent: + * @widget: an #NmtNewtWidget + * @parent: @widget's parent + * + * Sets @widget's parent to @parent. This is used internally by + * #NmtNewtContainer implementations; you must use an appropriate + * container-specific method to actually add a widget to a container. + */ +void +nmt_newt_widget_set_parent (NmtNewtWidget *widget, + NmtNewtWidget *parent) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + g_clear_object (&priv->parent); + priv->parent = parent ? g_object_ref (parent) : NULL; + g_object_notify (G_OBJECT (widget), "parent"); +} + +/** + * nmt_newt_widget_get_parent: + * @widget: an #NmtNewtWidget + * + * Gets @widget's parent + * + * Returns: @widget's parent + */ +NmtNewtWidget * +nmt_newt_widget_get_parent (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + return priv->parent; +} + +/** + * nmt_newt_widget_get_form: + * @widget: an #NmtNewtWidget + * + * Gets @widget's top-level form. + * + * Returns: @widget's #NmtNewtForm + */ +NmtNewtForm * +nmt_newt_widget_get_form (NmtNewtWidget *widget) +{ + while (widget) { + if (NMT_IS_NEWT_FORM (widget)) + return NMT_NEWT_FORM (widget); + widget = nmt_newt_widget_get_parent (widget); + } + + return NULL; +} + +/** + * nmt_newt_widget_get_valid: + * @widget: an #NmtNewtWidget + * + * Gets @widget's #NmtNewtWidget:valid flag, indicating whether its + * content is valid. + * + * Returns: @widget's #NmtNewtWidget:valid flag + */ +gboolean +nmt_newt_widget_get_valid (NmtNewtWidget *widget) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + return priv->valid; +} + +/** + * nmt_newt_widget_set_valid: + * @widget: an #NmtNewtWidget + * @valid: whether @widget is valid + * + * Sets @widget's #NmtNewtWidget:valid flag, indicating whether its + * content is valid. + * + * This method should be considered "protected"; if you change it, the + * widget implementation will likely just change it back at some + * point. + */ +void +nmt_newt_widget_set_valid (NmtNewtWidget *widget, + gboolean valid) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (widget); + + valid = !!valid; + if (priv->valid == valid) + return; + + priv->valid = valid; + g_object_notify (G_OBJECT (widget), "valid"); +} + +/** + * nmt_newt_widget_needs_rebuilds: + * @widget: an #NmtNewtWidget + * + * Marks @widget as needing to be "rebuilt" (ie, re-realized). This is + * called automatically in some cases (such as when adding a widget to + * or removing it from a container). #NmtNewtComponent implementations + * should also call this if they need to make some change that can + * only be done by destroying their current #newtComponent and + * creating a new one. + */ +void +nmt_newt_widget_needs_rebuild (NmtNewtWidget *widget) +{ + g_signal_emit (widget, signals[NEEDS_REBUILD], 0); +} + +static void +nmt_newt_widget_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NmtNewtWidget *widget = NMT_NEWT_WIDGET (object); + + switch (prop_id) { + case PROP_PARENT: + nmt_newt_widget_set_parent (widget, g_value_get_object (value)); + break; + case PROP_VISIBLE: + nmt_newt_widget_set_visible (widget, g_value_get_boolean (value)); + break; + case PROP_EXIT_ON_ACTIVATE: + nmt_newt_widget_set_exit_on_activate (widget, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_widget_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NmtNewtWidgetPrivate *priv = NMT_NEWT_WIDGET_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_PARENT: + g_value_set_object (value, priv->parent); + break; + case PROP_VISIBLE: + g_value_set_boolean (value, priv->visible); + break; + case PROP_VALID: + g_value_set_boolean (value, priv->valid); + break; + case PROP_EXIT_ON_ACTIVATE: + g_value_set_boolean (value, priv->exit_on_activate); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nmt_newt_widget_class_init (NmtNewtWidgetClass *widget_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (widget_class); + + g_type_class_add_private (widget_class, sizeof (NmtNewtWidgetPrivate)); + + /* virtual methods */ + object_class->set_property = nmt_newt_widget_set_property; + object_class->get_property = nmt_newt_widget_get_property; + object_class->finalize = nmt_newt_widget_finalize; + + widget_class->activated = nmt_newt_widget_real_activated; + + /* signals */ + + /** + * NmtNewtWidget::needs-rebuild: + * @widget: the #NmtNewtWidget + * + * Emitted when nmt_newt_widget_need_rebuild() is called on @widget + * or any of its children. This signal propagates up the container + * hierarchy, eventually reaching the top-level #NmtNewtForm. + */ + signals[NEEDS_REBUILD] = + g_signal_new ("needs-rebuild", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NmtNewtWidgetClass, needs_rebuild), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + /** + * NmtNewtWidget::activated: + * @widget: the #NmtNewtWidget + * + * Emitted when the widget's #newtComponent is activated. + */ + signals[ACTIVATED] = + g_signal_new ("activated", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NmtNewtWidgetClass, activated), + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + /* properties */ + + /** + * NmtNewtWidget:parent: + * + * The widget's parent widget, or %NULL if it has no parent. + */ + g_object_class_install_property (object_class, PROP_PARENT, + g_param_spec_object ("parent", "", "", + NMT_TYPE_NEWT_WIDGET, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtWidget:visible: + * + * Whether the widget is visible. Invisible widgets do not get + * realized or sized. + */ + g_object_class_install_property (object_class, PROP_VISIBLE, + g_param_spec_boolean ("visible", "", "", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtWidget:valid: + * + * Whether the widget's content is considered valid. Components + * determine their own validity. A container, by default, is + * considered valid if all of its children are valid. + */ + g_object_class_install_property (object_class, PROP_VALID, + g_param_spec_boolean ("valid", "", "", + TRUE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /** + * NmtNewtWidget:exit-on-activate: + * + * If %TRUE, the widget will call nmt_newt_form_quit() on its form + * when it is activated. + */ + g_object_class_install_property (object_class, PROP_EXIT_ON_ACTIVATE, + g_param_spec_boolean ("exit-on-activate", "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/tui/newt/nmt-newt-widget.h b/tui/newt/nmt-newt-widget.h new file mode 100644 index 000000000..a526a674c --- /dev/null +++ b/tui/newt/nmt-newt-widget.h @@ -0,0 +1,118 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_WIDGET_H +#define NMT_NEWT_WIDGET_H + +#include "nmt-newt-types.h" + +G_BEGIN_DECLS + +#define NMT_TYPE_NEWT_WIDGET (nmt_newt_widget_get_type ()) +#define NMT_NEWT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_NEWT_WIDGET, NmtNewtWidget)) +#define NMT_NEWT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_NEWT_WIDGET, NmtNewtWidgetClass)) +#define NMT_IS_NEWT_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMT_TYPE_NEWT_WIDGET)) +#define NMT_IS_NEWT_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMT_TYPE_NEWT_WIDGET)) +#define NMT_NEWT_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMT_TYPE_NEWT_WIDGET, NmtNewtWidgetClass)) + +struct _NmtNewtWidget { + GInitiallyUnowned parent; + +}; + +typedef struct { + GInitiallyUnownedClass parent; + + /* signals */ + void (*needs_rebuild) (NmtNewtWidget *widget); + void (*activated) (NmtNewtWidget *widget); + + /* methods */ + void (*realize) (NmtNewtWidget *widget); + void (*unrealize) (NmtNewtWidget *widget); + + newtComponent * (*get_components) (NmtNewtWidget *widget); + NmtNewtWidget * (*find_component) (NmtNewtWidget *widget, + newtComponent co); + + void (*size_request) (NmtNewtWidget *widget, + int *width, + int *height); + void (*size_allocate) (NmtNewtWidget *widget, + int x, + int y, + int width, + int height); + + newtComponent (*get_focus_component) (NmtNewtWidget *widget); + +} NmtNewtWidgetClass; + +GType nmt_newt_widget_get_type (void); + +void nmt_newt_widget_realize (NmtNewtWidget *widget); +void nmt_newt_widget_unrealize (NmtNewtWidget *widget); +gboolean nmt_newt_widget_get_realized (NmtNewtWidget *widget); + +newtComponent *nmt_newt_widget_get_components (NmtNewtWidget *widget); + +void nmt_newt_widget_set_padding (NmtNewtWidget *widget, + int pad_left, + int pad_top, + int pad_right, + int pad_bottom); + +void nmt_newt_widget_size_request (NmtNewtWidget *widget, + int *width, + int *height); +void nmt_newt_widget_size_allocate (NmtNewtWidget *widget, + int x, + int y, + int width, + int height); + +void nmt_newt_widget_set_parent (NmtNewtWidget *widget, + NmtNewtWidget *parent); +NmtNewtWidget *nmt_newt_widget_get_parent (NmtNewtWidget *widget); + +NmtNewtForm *nmt_newt_widget_get_form (NmtNewtWidget *widget); + +gboolean nmt_newt_widget_get_visible (NmtNewtWidget *widget); +void nmt_newt_widget_set_visible (NmtNewtWidget *widget, + gboolean visible); + +newtComponent nmt_newt_widget_get_focus_component (NmtNewtWidget *widget); + +void nmt_newt_widget_activated (NmtNewtWidget *widget); +gboolean nmt_newt_widget_get_exit_on_activate (NmtNewtWidget *widget); +void nmt_newt_widget_set_exit_on_activate (NmtNewtWidget *widget, + gboolean exit_on_activate); + +gboolean nmt_newt_widget_get_valid (NmtNewtWidget *widget); + +NmtNewtWidget *nmt_newt_widget_find_component (NmtNewtWidget *widget, + newtComponent co); + +/* protected */ +void nmt_newt_widget_needs_rebuild (NmtNewtWidget *widget); +void nmt_newt_widget_set_valid (NmtNewtWidget *widget, + gboolean valid); + +G_END_DECLS + +#endif /* NMT_NEWT_WIDGET_H */ diff --git a/tui/newt/nmt-newt.h b/tui/newt/nmt-newt.h new file mode 100644 index 000000000..6a9c8d9fb --- /dev/null +++ b/tui/newt/nmt-newt.h @@ -0,0 +1,39 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef NMT_NEWT_H +#define NMT_NEWT_H + +#include "nmt-newt-button.h" +#include "nmt-newt-button-box.h" +#include "nmt-newt-checkbox.h" +#include "nmt-newt-entry.h" +#include "nmt-newt-entry-numeric.h" +#include "nmt-newt-form.h" +#include "nmt-newt-grid.h" +#include "nmt-newt-label.h" +#include "nmt-newt-listbox.h" +#include "nmt-newt-popup.h" +#include "nmt-newt-section.h" +#include "nmt-newt-separator.h" +#include "nmt-newt-stack.h" +#include "nmt-newt-textbox.h" +#include "nmt-newt-toggle-button.h" +#include "nmt-newt-utils.h" + +#endif /* NMT_NEWT_H */ |