diff --git a/configure.ac b/configure.ac index 04385e51b5..9ae83b7af5 100644 --- a/configure.ac +++ b/configure.ac @@ -188,6 +188,19 @@ for frontend in $FRONTENDS ; do dnl FRONTEND_INCLUDES="${GNOME_FRONTEND_CFLAGS}" dnl FRONTEND_LIBS="@XPM_LIB@ @XFORMS_LIB@ ${GNOME_FRONTEND_LIBS}" dnl ;; + gtk) + XFORMS_DO_IT_ALL + PKG_CHECK_MODULES(GTK_FRONTEND, gtkmm-2.0 libglademm-2.0) + FRONTENDS_PROGS="$FRONTENDS_PROGS lyx-gtk\$(EXEEXT)" + FRONTENDS_SUBDIRS="$FRONTENDS_SUBDIRS xforms gtk" + RPM_FRONTEND="gtk" + RPM_FRONTEND_DEPS='gtkmm >= 2.2.0' + GTKMM_VERSION=`pkg-config --modversion gtkmm-2.0` + LIBGLADEMM_VERSION=`pkg-config --modversion libglademm-2.0` + FRONTEND_INFO=" libgtkmm version: ${GTKMM_VERSION}\n\ + libglademm version: ${LIBGLADEMM_VERSION}\n" + ;; + qt) QT_DO_IT_ALL FRONTENDS_PROGS="$FRONTENDS_PROGS lyx-qt\$(EXEEXT)" @@ -395,6 +408,8 @@ AC_CONFIG_FILES([Makefile \ src/frontends/xforms/lyx_forms.h-tmp:src/frontends/xforms/lyx_forms.h.in \ src/frontends/xforms/lyx_xpm.h-tmp:src/frontends/xforms/lyx_xpm.h.in \ src/frontends/xforms/forms/Makefile \ + src/frontends/gtk/Makefile \ + src/frontends/gtk/glade/Makefile \ src/frontends/qt2/Makefile \ src/frontends/qt2/moc/Makefile \ src/frontends/qt2/ui/Makefile \ diff --git a/po/POTFILES.in b/po/POTFILES.in index 4942f1d64f..db0888f6ce 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -35,6 +35,8 @@ src/frontends/controllers/character.C src/frontends/controllers/frnt_lang.C src/frontends/controllers/helper_funcs.C src/frontends/gnome/GLog.C +src/frontends/gtk/Dialogs.C +src/frontends/gtk/GBC.h src/frontends/qt2/Alert_pimpl.C src/frontends/qt2/BulletsModule.C src/frontends/qt2/Dialogs.C diff --git a/src/Makefile.am b/src/Makefile.am index 311fe12251..649144df95 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,7 +31,7 @@ OTHERLIBS = $(BOOST_LIBS) $(INTLLIBS) $(AIKSAURUS_LIBS) @LIBS@ bin_PROGRAMS = lyx noinst_PROGRAMS = $(FRONTENDS_PROGS) -EXTRA_PROGRAMS = lyx-xforms lyx-qt +EXTRA_PROGRAMS = lyx-xforms lyx-qt lyx-gtk lyx_xforms_LDADD = $(lyx_OBJECTS) $(LYX_PRE_LIBS) \ frontends/xforms/libxforms.la $(LYX_POST_LIBS) $(OTHERLIBS) @@ -42,6 +42,10 @@ lyx_qt_LDADD = $(lyx_OBJECTS) $(LYX_PRE_LIBS) \ frontends/qt2/libqt2.la $(LYX_POST_LIBS) $(OTHERLIBS) lyx_qt_SOURCES = main.C +lyx_gtk_LDADD = $(lyx_OBJECTS) $(LYX_PRE_LIBS) \ + frontends/gtk/libgtk.la $(LYX_POST_LIBS) $(OTHERLIBS) +lyx_gtk_SOURCES = main.C + lyx$(EXEEXT): $(FRONTENDS_PROGS) rm -f $@ $(LN_S) $< $@ diff --git a/src/frontends/Makefile.am b/src/frontends/Makefile.am index 213ed48c09..6b37652747 100644 --- a/src/frontends/Makefile.am +++ b/src/frontends/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/config/common.am SUBDIRS = controllers $(FRONTENDS_SUBDIRS) -DIST_SUBDIRS = controllers xforms qt2 gnome +DIST_SUBDIRS = controllers xforms qt2 gnome gtk noinst_LTLIBRARIES = libfrontends.la diff --git a/src/frontends/gtk/Alert_pimpl.C b/src/frontends/gtk/Alert_pimpl.C new file mode 100644 index 0000000000..d39033978f --- /dev/null +++ b/src/frontends/gtk/Alert_pimpl.C @@ -0,0 +1,103 @@ +/** + * \file Alert_pimpl.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "frontends/Alert.h" +#include "frontends/Alert_pimpl.h" + + +namespace { + + +string translateShortcut(string const & str) +{ + string::size_type i = str.find_first_of("&"); + if (i == string::npos || i == str.length() - 1) + return str; + string tstr = str; + tstr[i] = '_'; + return tstr; +} + + +} + + +void warning_pimpl(string const &, string const & message) +{ + Gtk::MessageDialog dlg(Glib::locale_to_utf8(message), + Gtk::MESSAGE_WARNING, + Gtk::BUTTONS_CLOSE, true, true); + dlg.run(); +} + + +void error_pimpl(string const &, string const & message) +{ + Gtk::MessageDialog dlg(Glib::locale_to_utf8(message), + Gtk::MESSAGE_ERROR, + Gtk::BUTTONS_CLOSE, true, true); + dlg.run(); +} + + +void information_pimpl(string const &, string const & message) +{ + Gtk::MessageDialog dlg(Glib::locale_to_utf8(message), + Gtk::MESSAGE_INFO, + Gtk::BUTTONS_CLOSE, true, true); + dlg.run(); +} + + +int prompt_pimpl(string const &, string const & question, + int defaultButton, int /*escapeButton*/, + string const & b1, string const & b2, string const & b3) +{ + Glib::ustring gb1 = Glib::locale_to_utf8(translateShortcut(b1)); + Glib::ustring gb2 = Glib::locale_to_utf8(translateShortcut(b2)); + Glib::ustring gb3; + if (!b3.empty()) + gb3 = Glib::locale_to_utf8(translateShortcut(b3)); + Gtk::MessageDialog dlg(Glib::locale_to_utf8(question), + Gtk::MESSAGE_QUESTION, + Gtk::BUTTONS_NONE, true, true); + dlg.add_button(gb1, 0); + dlg.add_button(gb2, 1); + if (!b3.empty()) + dlg.add_button(gb3, 2); + dlg.set_default_response(defaultButton); + return dlg.run(); +} + + +std::pair const askForText_pimpl(string const & msg, + string const & dflt) +{ + Gtk::MessageDialog dlg(Glib::locale_to_utf8(msg), + Gtk::MESSAGE_QUESTION, + Gtk::BUTTONS_OK_CANCEL, + true, true); + Gtk::Entry entry; + entry.set_text(Glib::locale_to_utf8(dflt)); + entry.set_position(-1); + entry.show(); + dlg.get_vbox()->children().push_back( + Gtk::Box_Helpers::Element(entry)); + int response = dlg.run(); + if (response == Gtk::RESPONSE_OK) { + string str = Glib::locale_from_utf8(entry.get_text()); + return std::make_pair(true, str); + } + else + return std::make_pair(false, string()); +} diff --git a/src/frontends/gtk/ChangeLog b/src/frontends/gtk/ChangeLog new file mode 100644 index 0000000000..7b6f21411b --- /dev/null +++ b/src/frontends/gtk/ChangeLog @@ -0,0 +1,3 @@ +2003-9-2 hying_caritas@163.com + + * initial release diff --git a/src/frontends/gtk/Dialogs.C b/src/frontends/gtk/Dialogs.C new file mode 100644 index 0000000000..5a22d89294 --- /dev/null +++ b/src/frontends/gtk/Dialogs.C @@ -0,0 +1,481 @@ +/** + * \file xforms/Dialogs.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS + */ + +#include + +#include "Dialogs.h" +#include "Dialog.h" + +#include "Tooltips.h" + +#include "ControlAboutlyx.h" +#include "ControlBibtex.h" +#include "ControlBranch.h" +#include "ControlChanges.h" +#include "ControlCharacter.h" +#include "ControlCitation.h" +#include "ControlCommand.h" +#include "ControlErrorList.h" +#include "ControlERT.h" +#include "ControlExternal.h" +#include "ControlFloat.h" +#include "ControlGraphics.h" +#include "ControlInclude.h" +#include "ControlLog.h" +#include "ControlMath.h" +#include "ControlMinipage.h" +#include "ControlNote.h" +#include "ControlParagraph.h" +#include "ControlRef.h" +#include "ControlShowFile.h" +#include "ControlTabular.h" +#include "ControlTabularCreate.h" +#include "ControlTexinfo.h" +#include "ControlToc.h" +#include "ControlVCLog.h" +#include "ControlWrap.h" + +#include "GAboutlyx.h" +#include "GText.h" +#include "FormBibitem.h" +#include "FormBibtex.h" +#include "FormBranch.h" +#include "FormChanges.h" +#include "FormCharacter.h" +#include "FormCitation.h" +#include "FormErrorList.h" +#include "FormERT.h" +#include "FormExternal.h" +#include "FormFloat.h" +#include "FormGraphics.h" +#include "FormInclude.h" +#include "FormLog.h" +#include "FormMathsPanel.h" +#include "FormMathsBitmap.h" +#include "FormMathsDelim.h" +#include "FormMathsMatrix.h" +#include "FormMathsSpace.h" +#include "FormMathsStyle.h" +#include "FormMinipage.h" +#include "FormNote.h" +#include "FormParagraph.h" +#include "FormRef.h" +#include "FormTabular.h" +#include "FormTexinfo.h" +#include "FormShowFile.h" +#include "FormTabularCreate.h" +#include "FormToc.h" +#include "FormUrl.h" +#include "FormVCLog.h" +#include "FormWrap.h" + +#ifdef HAVE_LIBAIKSAURUS +#include "ControlThesaurus.h" +#include "FormThesaurus.h" +#endif + +#include "xformsBC.h" +#include "ButtonController.h" + +#include "arrows.xbm" +#include "bop.xbm" +#include "brel.xbm" +#include "deco.xbm" +#include "dots.xbm" +#include "greek.xbm" +#include "misc.xbm" +#include "varsz.xbm" + +#include "ams_misc.xbm" +#include "ams_arrows.xbm" +#include "ams_rel.xbm" +#include "ams_nrel.xbm" +#include "ams_ops.xbm" + +#include + + +namespace { + +FormMathsBitmap * createFormBitmap(Dialog & parent, string const & title, + char const * const * data, int size) +{ + char const * const * const end = data + size; + return new FormMathsBitmap(parent, title, std::vector(data, end)); +} + + +char const * const dialognames[] = { "aboutlyx", "bibitem", "bibtex", "branch", "changes", +"character", "citation", "error", "errorlist" , "ert", "external", "file", +"float", "graphics", "include", "index", "label", "latexlog", "mathpanel", +"mathaccents", "matharrows", "mathoperators", "mathrelations", "mathgreek", +"mathmisc", "mathdots", "mathbigoperators", "mathamsmisc", +"mathamsarrows", "mathamsrelations", "mathamsnegatedrelations", "mathamsoperators", +"mathdelimiter", "mathmatrix", "mathspace", "mathstyle", +"minipage", "note", "paragraph", "ref", "tabular", "tabularcreate", "texinfo", + +#ifdef HAVE_LIBAIKSAURUS +"thesaurus", +#endif + +"toc", "url", "vclog", "wrap" }; + +char const * const * const end_dialognames = + dialognames + (sizeof(dialognames) / sizeof(char *)); + +struct cmpCStr { + cmpCStr(char const * name) : name_(name) {} + bool operator()(char const * other) { + return strcmp(other, name_) == 0; + } +private: + char const * name_; +}; + +} // namespace anon + + +bool Dialogs::isValidName(string const & name) const +{ + return std::find_if(dialognames, end_dialognames, + cmpCStr(name.c_str())) != end_dialognames; +} + + +Dialog * Dialogs::build(string const & name) +{ + if (!isValidName(name)) + return 0; + + Dialog * dialog = new Dialog(lyxview_, name); + dialog->bc().view(new xformsBC(dialog->bc())); + + if (name == "aboutlyx") { + dialog->bc().view(new GBC(dialog->bc())); + dialog->setController(new ControlAboutlyx(*dialog)); + dialog->setView(new GAboutlyx(*dialog)); + dialog->bc().bp(new OkCancelPolicy); + } else if (name == "bibitem") { + dialog->setController(new ControlCommand(*dialog, name)); + dialog->setView(new FormBibitem(*dialog)); + dialog->bc().bp(new OkCancelReadOnlyPolicy); + } else if (name == "bibtex") { + dialog->setController(new ControlBibtex(*dialog)); + dialog->setView(new FormBibtex(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "character") { + dialog->setController(new ControlCharacter(*dialog)); + dialog->setView(new FormCharacter(*dialog)); + dialog->bc().bp(new OkApplyCancelReadOnlyPolicy); + } else if (name == "changes") { + dialog->setController(new ControlChanges(*dialog)); + dialog->setView(new FormChanges(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "citation") { + dialog->setController(new ControlCitation(*dialog)); + dialog->setView(new FormCitation(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "errorlist") { + dialog->setController(new ControlErrorList(*dialog)); + dialog->setView(new FormErrorList(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "ert") { + dialog->setController(new ControlERT(*dialog)); + dialog->setView(new FormERT(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "external") { + dialog->setController(new ControlExternal(*dialog)); + dialog->setView(new FormExternal(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "file") { + dialog->setController(new ControlShowFile(*dialog)); + dialog->setView(new FormShowFile(*dialog)); + dialog->bc().bp(new OkCancelPolicy); + } else if (name == "float") { + dialog->setController(new ControlFloat(*dialog)); + dialog->setView(new FormFloat(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "graphics") { + dialog->setController(new ControlGraphics(*dialog)); + dialog->setView(new FormGraphics(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "include") { + dialog->setController(new ControlInclude(*dialog)); + dialog->setView(new FormInclude(*dialog)); + dialog->bc().bp(new OkApplyCancelReadOnlyPolicy); + } else if (name == "index") { + dialog->bc().view(new GBC(dialog->bc())); + dialog->setController(new ControlCommand(*dialog, name)); + dialog->setView(new GText(*dialog, + _("Index"), _("Keyword:|#K"))); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "label") { + dialog->bc().view(new GBC(dialog->bc())); + dialog->setController(new ControlCommand(*dialog, name)); + dialog->setView(new GText(*dialog, + _("Label"), _("Label:|#L"))); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "latexlog") { + dialog->setController(new ControlLog(*dialog)); + dialog->setView(new FormLog(*dialog)); + dialog->bc().bp(new OkCancelPolicy); + + } else if (name == "mathpanel") { + dialog->setController(new ControlMath(*dialog)); + dialog->setView(new FormMathsPanel(*dialog)); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathaccents") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("Maths Decorations & Accents"), + latex_deco, nr_latex_deco); + bitmap->addBitmap( + BitmapStore(12, 3, 4, deco1_width, deco1_height, deco1_bits, true)); + bitmap->addBitmap( + BitmapStore(10, 4, 3, deco2_width, deco2_height, deco2_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "matharrows") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("Arrows"), latex_arrow, nr_latex_arrow); + bitmap->addBitmap( + BitmapStore(20, 5, 4, arrow_width, arrow_height, arrow_bits, true)); + bitmap->addBitmap( + BitmapStore(7, 2, 4, larrow_width, larrow_height, larrow_bits, false)); + bitmap->addBitmap( + BitmapStore(4, 2, 2, darrow_width, darrow_height, darrow_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathoperators") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("Binary Ops"), + latex_bop, nr_latex_bop); + bitmap->addBitmap( + BitmapStore(31, 4, 8, bop_width, bop_height, bop_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathrelations") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("Binary Relations"), + latex_brel, nr_latex_brel); + bitmap->addBitmap( + BitmapStore(35, 4, 9, brel_width, brel_height, brel_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathgreek") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("Greek"), + latex_greek, nr_latex_greek); + bitmap->addBitmap( + BitmapStore(11, 6, 2, Greek_width, Greek_height, Greek_bits, true)); + bitmap->addBitmap( + BitmapStore(28, 7, 4, greek_width, greek_height, greek_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathmisc") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("Misc"), + latex_misc, nr_latex_misc); + bitmap->addBitmap( + BitmapStore(29, 5, 6, misc_width, misc_height, misc_bits, true)); + bitmap->addBitmap( + BitmapStore(5, 5, 1, misc4_width, misc4_height, misc4_bits, true)); + bitmap->addBitmap( + BitmapStore(6, 3, 2, misc2_width, misc2_height, misc2_bits, false)); + bitmap->addBitmap( + BitmapStore(4, 2, 2, misc3_width, misc3_height, misc3_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathdots") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("Dots"), + latex_dots, nr_latex_dots); + bitmap->addBitmap( + BitmapStore(4, 4, 1, dots_width, dots_height, dots_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathbigoperators") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("Big Operators"), + latex_varsz, nr_latex_varsz); + bitmap->addBitmap( + BitmapStore(14, 3, 5, varsz_width, varsz_height, varsz_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathamsmisc") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("AMS Misc"), + latex_ams_misc, nr_latex_ams_misc); + bitmap->addBitmap( + BitmapStore(9, 5, 2, ams1_width, ams1_height, ams1_bits, true)); + bitmap->addBitmap( + BitmapStore(26, 3, 9, ams7_width, ams7_height, ams7_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathamsarrows") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("AMS Arrows"), + latex_ams_arrows, nr_latex_ams_arrows); + bitmap->addBitmap( + BitmapStore(32, 3, 11, ams2_width, ams2_height, ams2_bits, true)); + bitmap->addBitmap( + BitmapStore(6, 3, 2, ams3_width, ams3_height, ams3_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathamsrelations") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("AMS Relations"), + latex_ams_rel, nr_latex_ams_rel); + bitmap->addBitmap( + BitmapStore(66, 6, 11, ams_rel_width, ams_rel_height, ams_rel_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathamsnegatedrelations") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("AMS Negated Rel"), + latex_ams_nrel, nr_latex_ams_nrel); + bitmap->addBitmap( + BitmapStore(51, 6, 9, ams_nrel_width, ams_nrel_height, ams_nrel_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathamsoperators") { + FormMathsBitmap * bitmap = + createFormBitmap(*dialog, _("AMS Operators"), + latex_ams_ops, nr_latex_ams_ops); + bitmap->addBitmap( + BitmapStore(23, 3, 8, ams_ops_width, ams_ops_height, ams_ops_bits, true)); + + dialog->setController(new ControlMath(*dialog)); + dialog->setView(bitmap); + dialog->bc().bp(new IgnorantPolicy); + + } else if (name == "mathdelimiter") { + dialog->setController(new ControlMath(*dialog)); + dialog->setView(new FormMathsDelim(*dialog)); + dialog->bc().bp(new OkApplyCancelReadOnlyPolicy); + } else if (name == "mathmatrix") { + dialog->setController(new ControlMath(*dialog)); + dialog->setView(new FormMathsMatrix(*dialog)); + dialog->bc().bp(new OkApplyCancelReadOnlyPolicy); + } else if (name == "mathspace") { + dialog->setController(new ControlMath(*dialog)); + dialog->setView(new FormMathsSpace(*dialog)); + dialog->bc().bp(new IgnorantPolicy); + } else if (name == "mathstyle") { + dialog->setController(new ControlMath(*dialog)); + dialog->setView(new FormMathsStyle(*dialog)); + dialog->bc().bp(new IgnorantPolicy); + } else if (name == "minipage") { + dialog->setController(new ControlMinipage(*dialog)); + dialog->setView(new FormMinipage(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "note") { + dialog->setController(new ControlNote(*dialog)); + dialog->setView(new FormNote(*dialog)); + dialog->bc().bp(new OkApplyCancelReadOnlyPolicy); + } else if (name == "branch") { + dialog->setController(new ControlBranch(*dialog)); + dialog->setView(new FormBranch(*dialog)); + dialog->bc().bp(new OkApplyCancelReadOnlyPolicy); + } else if (name == "paragraph") { + dialog->setController(new ControlParagraph(*dialog)); + dialog->setView(new FormParagraph(*dialog)); + dialog->bc().bp(new OkApplyCancelReadOnlyPolicy); + } else if (name == "ref") { + dialog->setController(new ControlRef(*dialog)); + dialog->setView(new FormRef(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "tabular") { + dialog->setController(new ControlTabular(*dialog)); + dialog->setView(new FormTabular(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "tabularcreate") { + dialog->setController(new ControlTabularCreate(*dialog)); + dialog->setView(new FormTabularCreate(*dialog)); + dialog->bc().bp(new IgnorantPolicy); + } else if (name == "texinfo") { + dialog->setController(new ControlTexinfo(*dialog)); + dialog->setView(new FormTexinfo(*dialog)); + dialog->bc().bp(new OkCancelPolicy); +#ifdef HAVE_LIBAIKSAURUS + } else if (name == "thesaurus") { + dialog->setController(new ControlThesaurus(*dialog)); + dialog->setView(new FormThesaurus(*dialog)); + dialog->bc().bp(new OkApplyCancelReadOnlyPolicy); +#endif + } else if (name == "toc") { + dialog->setController(new ControlToc(*dialog)); + dialog->setView(new FormToc(*dialog)); + dialog->bc().bp(new OkCancelPolicy); + } else if (name == "url") { + dialog->setController(new ControlCommand(*dialog, name)); + dialog->setView(new FormUrl(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "vclog") { + dialog->setController(new ControlVCLog(*dialog)); + dialog->setView(new FormVCLog(*dialog)); + dialog->bc().bp(new OkCancelPolicy); + } else if (name == "wrap") { + dialog->setController(new ControlWrap(*dialog)); + dialog->setView(new FormWrap(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } + + return dialog; +} + + +void Dialogs::toggleTooltips() +{ + Tooltips::toggleEnabled(); +} + + +/// Are the tooltips on or off? +bool Dialogs::tooltipsEnabled() +{ + return Tooltips::enabled(); +} diff --git a/src/frontends/gtk/FileDialog.C b/src/frontends/gtk/FileDialog.C new file mode 100644 index 0000000000..99a5f08fb3 --- /dev/null +++ b/src/frontends/gtk/FileDialog.C @@ -0,0 +1,52 @@ +/** + * \file FileDialog.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "FileDialogPrivate.h" + + +FileDialog::FileDialog(string const & title, + kb_action action, + Button b1, + Button b2) +{ + private_ = new FileDialog::Private(title, action, b1, b2); +} + + +FileDialog::~FileDialog() +{ + delete private_; +} + + +FileDialog::Result const FileDialog::open(string const & path, + string const & mask, + string const & suggested) +{ + return private_->open(path, mask, suggested); +} + + +FileDialog::Result const FileDialog::opendir(string const & path, + string const & suggested) +{ + return private_->opendir(path, suggested); +} + + +FileDialog::Result const FileDialog::save(string const & path, + string const & mask, + string const & suggested) +{ + return private_->save(path, mask, suggested); +} diff --git a/src/frontends/gtk/FileDialogPrivate.C b/src/frontends/gtk/FileDialogPrivate.C new file mode 100644 index 0000000000..096f018f65 --- /dev/null +++ b/src/frontends/gtk/FileDialogPrivate.C @@ -0,0 +1,99 @@ +/** + * \file FileDialogPrivate.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "LString.h" + +#include "FileDialogPrivate.h" + + +FileDialog::Private::Private(string const & title, + kb_action action, + FileDialog::Button b1, + FileDialog::Button b2) : + action_(action) +{ + fileSelection_.set_title(title); + fileSelection_.get_button_area()->children().push_back( + Gtk::Box_Helpers::Element(button1_)); + fileSelection_.get_button_area()->children().push_back( + Gtk::Box_Helpers::Element(button2_)); + button1_.signal_clicked().connect( + SigC::slot(*this, &FileDialog::Private::onButton1Clicked)); + button2_.signal_clicked().connect( + SigC::slot(*this, &FileDialog::Private::onButton2Clicked)); + if (!b1.first.empty() && !b1.second.empty()) { + string::size_type pos = b1.first.find('|'); + button1_.set_label( + Glib::locale_to_utf8(b1.first.substr(0, pos))); + dir1_ = b1.second; + button1_.show(); + } + if (!b2.first.empty() && !b2.second.empty()) { + string::size_type pos = b2.first.find('|'); + button2_.set_label( + Glib::locale_to_utf8(b2.first.substr(0, pos))); + dir2_ = b2.second; + button2_.show(); + } +} + + +void FileDialog::Private::onButton1Clicked() +{ + fileSelection_.set_filename(dir1_); +} + + +void FileDialog::Private::onButton2Clicked() +{ + fileSelection_.set_filename(dir2_); +} + + +FileDialog::Result const FileDialog::Private::open(string const & path, + string const & /*mask*/, + string const & /*suggested*/) +{ + fileSelection_.set_filename(path); + fileSelection_.get_file_list()->get_parent()->show(); + Result result; + result.first = FileDialog::Chosen; + if (fileSelection_.run() == Gtk::RESPONSE_OK) + result.second = fileSelection_.get_filename(); + else + result.second = string(); + return result; +} + + +FileDialog::Result const FileDialog::Private::opendir(string const & path, + string const & /*suggested*/) +{ + fileSelection_.set_filename(path); + fileSelection_.get_file_list()->get_parent()->hide(); + Result result; + result.first = FileDialog::Chosen; + if (fileSelection_.run() == Gtk::RESPONSE_OK) + result.second = fileSelection_.get_filename(); + else + result.second = string(); + return result; +} + + +FileDialog::Result const FileDialog::Private::save(string const & path, + string const & mask, + string const & suggested) +{ + return open(path, mask, suggested); +} diff --git a/src/frontends/gtk/FileDialogPrivate.h b/src/frontends/gtk/FileDialogPrivate.h new file mode 100644 index 0000000000..51d4777b3c --- /dev/null +++ b/src/frontends/gtk/FileDialogPrivate.h @@ -0,0 +1,45 @@ +// -*- C++ -*- +/** + * \file FileDialogPrivate.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef FILE_DIALOG_PRIVATE_H +#define FILE_DIALOG_PRIVATE_H + +#include +#include "frontends/FileDialog.h" + +class FileDialog::Private : public SigC::Object +{ +public: + Private(string const & title, + kb_action action, + FileDialog::Button b1, FileDialog::Button b2); + FileDialog::Result const open(string const & path, + string const & mask, + string const & suggested); + FileDialog::Result const opendir(string const & path, + string const & suggested); + + FileDialog::Result const save(string const & path, + string const & mask, + string const & suggested); + +private: + void onButton1Clicked(); + void onButton2Clicked(); + Gtk::FileSelection fileSelection_; + Gtk::Button button1_; + Gtk::Button button2_; + string dir1_; + string dir2_; + kb_action action_; +}; + +#endif diff --git a/src/frontends/gtk/GAboutlyx.C b/src/frontends/gtk/GAboutlyx.C new file mode 100644 index 0000000000..9967cc2435 --- /dev/null +++ b/src/frontends/gtk/GAboutlyx.C @@ -0,0 +1,168 @@ +/** + * \file GAboutlyx.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include +#include + +#include "ControlAboutlyx.h" +#include "GAboutlyx.h" +#include "support/filetools.h" +#include "version.h" + +namespace { + +enum TranslateState {NORMAL, BEGIN, IN_AT, IN_BOLD, IN_ITALIC}; + + +Glib::ustring translateMarkup(Glib::ustring const & lyxMarkup) +{ + Glib::ustring::const_iterator it = lyxMarkup.begin(); + Glib::ustring pangoMarkup; + TranslateState state = BEGIN; + for (; it != lyxMarkup.end(); it++) { + switch (state) { + case BEGIN: + switch (*it) { + case '@': + state = IN_AT; + break; + case '\n': + state = BEGIN; + pangoMarkup.push_back('\n'); + break; + default: + state = NORMAL; + pangoMarkup.push_back(*it); + break; + } + break; + case IN_AT: + switch (*it) { + case 'b': + state = IN_BOLD; + pangoMarkup += ""; + break; + case 'i': + state = IN_ITALIC; + pangoMarkup += ""; + break; + case '\n': + state = BEGIN; + pangoMarkup.push_back('@'); + pangoMarkup.push_back('\n'); + break; + default: + state = NORMAL; + pangoMarkup.push_back('@'); + pangoMarkup.push_back(*it); + } + break; + case IN_BOLD: + switch (*it) { + case '\n': + state = BEGIN; + pangoMarkup += "\n"; + break; + default: + pangoMarkup.push_back(*it); + } + break; + case IN_ITALIC: + switch (*it) { + case '\n': + state = BEGIN; + pangoMarkup += "\n"; + break; + default: + pangoMarkup.push_back(*it); + } + break; + case NORMAL: + switch (*it) { + case '\n': + state = BEGIN; + pangoMarkup.push_back('\n'); + break; + default: + pangoMarkup.push_back(*it); + } + } + switch (*it) { + case '&': + pangoMarkup += "amp;"; + break; + case '<': + pangoMarkup.erase(--(pangoMarkup.end())); + pangoMarkup += "<"; + break; + case '>': + pangoMarkup.erase(--(pangoMarkup.end())); + pangoMarkup += ">"; + break; + default: + break; + } + } + switch (state) { + case IN_AT: + pangoMarkup.push_back('@'); + break; + case IN_ITALIC: + pangoMarkup += ""; + break; + case IN_BOLD: + pangoMarkup += ""; + break; + default: + break; + } + return pangoMarkup; +} + + +} + + +GAboutlyx::GAboutlyx(Dialog & parent) + : GViewCB(parent, "About LyX") +{ +} + + +void GAboutlyx::doBuild() +{ + string const gladeName = + lyx::support::LibFileSearch("glade", "aboutlyx", "glade"); + xml_ = Gnome::Glade::Xml::create(gladeName); + Gtk::Label * version; + Gtk::Label * credits; + Gtk::Label * license; + xml_->get_widget("version", version); + xml_->get_widget("credits", credits); + xml_->get_widget("license", license); + std::ostringstream vs; + vs << controller().getVersion() + << std::endl << lyx_version_info; + version->set_text(Glib::locale_to_utf8(vs.str())); + std::ostringstream crs; + controller().getCredits(crs); + credits->set_markup(translateMarkup(Glib::locale_to_utf8(crs.str()))); + std::ostringstream ls; + ls << controller().getCopyright() << "\n\n" + << controller().getLicense() << "\n\n" + << controller().getDisclaimer(); + license->set_text(Glib::locale_to_utf8(ls.str())); + Gtk::Button * btn; + xml_->get_widget("close_button", btn); + btn->signal_clicked().connect(SigC::slot(*this, &GViewBase::onCancel)); +} diff --git a/src/frontends/gtk/GAboutlyx.h b/src/frontends/gtk/GAboutlyx.h new file mode 100644 index 0000000000..f0a85d4c85 --- /dev/null +++ b/src/frontends/gtk/GAboutlyx.h @@ -0,0 +1,29 @@ +// -*- C++ -*- +/** + * \file GAboutlyx.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef GABOUTLYX_H +#define GABOUTLYX_H + +#include "GViewBase.h" + +class ControlAboutlyx; + +class GAboutlyx : public GViewCB +{ +public: + GAboutlyx(Dialog &); +private: + virtual void apply() {} + virtual void update() {} + virtual void doBuild(); +}; + +#endif diff --git a/src/frontends/gtk/GBC.C b/src/frontends/gtk/GBC.C new file mode 100644 index 0000000000..9a9992e5f7 --- /dev/null +++ b/src/frontends/gtk/GBC.C @@ -0,0 +1,39 @@ +/** + * \file GBC.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "GBC.h" + + +GBC::GBC(ButtonController const & parent, + string const & cancel, string const & close) + : GuiBC(parent, cancel, close) +{ +} + + +void GBC::setButtonEnabled(Gtk::Button * btn, bool enabled) const +{ + btn->set_sensitive(enabled); +} + + +void GBC::setWidgetEnabled(Gtk::Widget * widget, bool enabled) const +{ + widget->set_sensitive(enabled); +} + + +void GBC::setButtonLabel(Gtk::Button * btn, string const & label) const +{ + btn->set_label(Glib::locale_to_utf8(label)); +} diff --git a/src/frontends/gtk/GBC.h b/src/frontends/gtk/GBC.h new file mode 100644 index 0000000000..a85d079998 --- /dev/null +++ b/src/frontends/gtk/GBC.h @@ -0,0 +1,39 @@ +// -*- C++ -*- +/** + * \file GBC.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef GBUTTONCONTROLLER_H +#define GBUTTONCONTROLLER_H + +#include + +#include "ButtonController.h" +#include "BCView.h" +#include "LString.h" +#include "gettext.h" + +class GBC : public GuiBC +{ +public: + GBC(ButtonController const & parent, + string const & cancel = _("Cancel"), + string const & close = _("Close")); +private: + /// Updates the button sensitivity (enabled/disabled) + void setButtonEnabled(Gtk::Button *, bool enabled) const; + + /// Updates the widget sensitivity (enabled/disabled) + void setWidgetEnabled(Gtk::Widget *, bool enabled) const; + + /// Set the label on the button + void setButtonLabel(Gtk::Button *, string const & label) const; +}; + +#endif diff --git a/src/frontends/gtk/GLyXKeySym.C b/src/frontends/gtk/GLyXKeySym.C new file mode 100644 index 0000000000..17f80bd870 --- /dev/null +++ b/src/frontends/gtk/GLyXKeySym.C @@ -0,0 +1,97 @@ +/** + * \file GLyXKeySym.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include +#include "GLyXKeySym.h" + + +GLyXKeySym::GLyXKeySym() : keyval_(GDK_VoidSymbol) +{ +} + + +GLyXKeySym::GLyXKeySym(unsigned int keyval) : keyval_(keyval) +{ +} + + +void GLyXKeySym::setKeyval(unsigned int keyval) +{ + keyval_ = keyval; +} + + +void GLyXKeySym::init(string const & symbolname) +{ + keyval_ = gdk_keyval_from_name(symbolname.c_str()); +} + + +bool GLyXKeySym::isOK() const +{ + return keyval_ != GDK_VoidSymbol; +} + + +bool GLyXKeySym::isModifier() const +{ + return ((keyval_ >= GDK_Shift_L && keyval_ <= GDK_Hyper_R) + || keyval_ == GDK_Mode_switch || keyval_ == 0); +} + + +string GLyXKeySym::getSymbolName() const +{ + const char * name = gdk_keyval_name(keyval_); + return name ? name : string(); +} + + +char GLyXKeySym::getISOEncoded(string const & /*encoding*/) const +{ + if (keyval_ == GDK_VoidSymbol) + return 0; + + unsigned int c = keyval_; + + switch (c & 0x0000FF00) { + // latin 1 byte 3 = 0 + case 0x00000000: break; + // latin 2 byte 3 = 1 + case 0x00000100: + // latin 3 byte 3 = 2 + case 0x00000200: + // latin 4 byte 3 = 3 + case 0x00000300: + // cyrillic KOI8 & Co + case 0x00000600: + // greek + case 0x00000700: + // latin 8 byte 3 = 18 (0x12) + case 0x00001200: + // latin 9 byte 3 = 19 (0x13) + case 0x00001300: + c &= 0x000000FF; + break; + default: + c = 0; + } + return c; +} + + +bool operator==(LyXKeySym const & k1, LyXKeySym const & k2) +{ + return static_cast(k1).getKeyval() + == static_cast(k2).getKeyval(); +} diff --git a/src/frontends/gtk/GLyXKeySym.h b/src/frontends/gtk/GLyXKeySym.h new file mode 100644 index 0000000000..db650c49fb --- /dev/null +++ b/src/frontends/gtk/GLyXKeySym.h @@ -0,0 +1,35 @@ +// -*- C++ -*- +/** + * \file GLyXKeySym.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef GLYX_KEYSYM_H +#define GLYX_KEYSYM_H + +#include "LString.h" +#include "frontends/LyXKeySym.h" + +class GLyXKeySym : public LyXKeySym +{ +public: + GLyXKeySym(); + GLyXKeySym(unsigned int keyval); + void setKeyval(unsigned int keyval); + unsigned int getKeyval() const { return keyval_; } + virtual void init(string const & symbolname); + virtual ~GLyXKeySym() {} + virtual bool isOK() const; + virtual bool isModifier() const; + virtual string getSymbolName() const; + virtual char getISOEncoded(string const & encoding) const; +private: + unsigned int keyval_; +}; + +#endif diff --git a/src/frontends/gtk/GMenubar.C b/src/frontends/gtk/GMenubar.C new file mode 100644 index 0000000000..a5baacaa3d --- /dev/null +++ b/src/frontends/gtk/GMenubar.C @@ -0,0 +1,228 @@ +/** + * \file GMenubar.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "GMenubar.h" +#include "GView.h" +#include "debug.h" +#include "lyxfunc.h" + +namespace +{ + +class LyxMenu : public Gtk::Menu +{ +public: + LyxMenu() { menu_.reset(new ::Menu); } + + ::Menu& getBackMenu() { return *menu_.get(); } + + void clearBackMenu() { menu_.reset(new ::Menu); } +private: + std::auto_ptr< ::Menu > menu_; +}; + + +Glib::ustring labelTrans(string const & label, string const & shortcut) +{ + string labelN = label; + string::size_type i = label.find(shortcut); + if (i == string::npos) + return Glib::locale_to_utf8(label); + labelN.insert(i, "_"); + return Glib::locale_to_utf8(labelN); +} + + +void ClearMenu(Gtk::MenuShell * menu) +{ + Gtk::Menu_Helpers::MenuList::iterator m, end; + m = menu->items().begin(); + end = menu->items().end(); + Gtk::Menu * subMenu; + for (; m != end; ++m) { + if ((subMenu = m->get_submenu()) != 0) { + ClearMenu(subMenu); + delete subMenu; + } + } + menu->items().clear(); +} + + +} + + +GMenubar::GMenubar(LyXView *lyxView, MenuBackend const & /*menuBackend*/) : + view_(lyxView) +{ + GView * gview = static_cast(lyxView); + Gtk::VBox& vbox = gview->getVBox(); + Menu const & menu = menubackend.getMenubar(); + Menu::const_iterator i = menu.begin(); + Menu::const_iterator end = menu.end(); + for (; i != end; ++i) { + if (i->kind() != MenuItem::Submenu) { + lyxerr << "ERROR: GMenubar::createMenubar:" + " only submenus can appear in a menubar" + << std::endl; + continue; + } + Gtk::Menu * gmenu = new LyxMenu; + menubar_.items().push_back( + Gtk::Menu_Helpers::MenuElem( + labelTrans(i->label(), i->shortcut()), + *gmenu)); + menubar_.items().back().signal_activate().connect( + SigC::bind(SigC::slot(*this, &GMenubar::onSubMenuActivate), &(*i), + &menubar_.items().back())); + mainMenuNames_.push_back(i->submenuname()); + } + menubar_.show(); + vbox.children().push_back(Gtk::Box_Helpers::Element(menubar_, + Gtk::PACK_SHRINK)); +} + + +GMenubar::~GMenubar() +{ + ClearMenu(&menubar_); +} + + +void GMenubar::update() +{ +} + + +void GMenubar::openByName(string const & name) +{ + Glib::ustring uname = Glib::locale_to_utf8(name); + std::vector::iterator it = + std::find(mainMenuNames_.begin(), mainMenuNames_.end(), + uname); + if (it != mainMenuNames_.end()) { + Gtk::MenuItem& mitem = menubar_.items()[it - mainMenuNames_.begin()]; + mitem.select(); + mitem.activate(); + return; + } + lyxerr << "GMenubar::openByName: menu " + << name << " not found" << std::endl; +} + + +bool GMenubar::submenuDisabled(MenuItem const * item) +{ + Menu & from = menubackend.getMenu(item->submenuname()); + Menu to; + menubackend.expand(from, to, view_); + Menu::const_iterator i = to.begin(); + Menu::const_iterator end = to.end(); + for (; i != end; ++i) { + switch (i->kind()) { + case MenuItem::Submenu: + if (!submenuDisabled(&(*i))) + return false; + break; + case MenuItem::Command: + { + FuncStatus const flag = + view_->getLyXFunc().getStatus(i->action()); + if (!flag.disabled()) + return false; + break; + } + default: + break; + } + } + return true; +} + + +void GMenubar::onSubMenuActivate(MenuItem const * item, + Gtk::MenuItem * gitem) +{ + Gtk::Menu * gmenu = gitem->get_submenu(); + ClearMenu(gmenu); + LyxMenu * lyxmenu = static_cast(gmenu); + lyxmenu->clearBackMenu(); + Menu * fmenu = &menubackend.getMenu(item->submenuname()); + menubackend.expand(*fmenu, lyxmenu->getBackMenu(), view_); + Menu::const_iterator i = lyxmenu->getBackMenu().begin(); + Menu::const_iterator end = lyxmenu->getBackMenu().end(); + Gtk::Menu * gmenu_new; + for (; i != end; ++i) { + switch (i->kind()) { + case MenuItem::Submenu: + gmenu_new = new LyxMenu; + gmenu->items().push_back( + Gtk::Menu_Helpers::MenuElem( + labelTrans(i->label(), i->shortcut()), + *gmenu_new)); + gmenu->items().back().signal_activate().connect( + SigC::bind(SigC::slot(*this, &GMenubar::onSubMenuActivate), + &(*i), + &gmenu->items().back())); + if (submenuDisabled(&(*i))) + gmenu->items().back().set_sensitive(false); + break; + case MenuItem::Command: + { + FuncStatus const flag = + view_->getLyXFunc().getStatus(i->action()); + bool on, off; + on = flag.onoff(true); + off = flag.onoff(false); + + if (on || off) { + gmenu->items().push_back( + Gtk::Menu_Helpers::CheckMenuElem( + labelTrans(i->label(), + i->shortcut()))); + Gtk::CheckMenuItem& citem = + static_cast( + gmenu->items().back()); + citem.set_active(on); + } else { + gmenu->items().push_back( + Gtk::Menu_Helpers::MenuElem( + labelTrans(i->label(), + i->shortcut()))); + } + Gtk::MenuItem & item = gmenu->items().back(); + item.signal_activate().connect( + SigC::bind(SigC::slot(*this, &GMenubar::onCommandActivate), + &(*i), &item)); + if (flag.disabled()) + item.set_sensitive(false); + break; + } + case MenuItem::Separator: + gmenu->items().push_back( + Gtk::Menu_Helpers::SeparatorElem()); + break; + default: + lyxerr << "GMenubar::create_submenu: " + "this should not happen" << std::endl; + break; + } + } +} + + +void GMenubar::onCommandActivate(MenuItem const * item, + Gtk::MenuItem * /*gitem*/) +{ + view_->getLyXFunc().dispatch(item->action(), true); +} diff --git a/src/frontends/gtk/GMenubar.h b/src/frontends/gtk/GMenubar.h new file mode 100644 index 0000000000..8a5f8b7ab3 --- /dev/null +++ b/src/frontends/gtk/GMenubar.h @@ -0,0 +1,36 @@ +// -*- C++ -*- +/** + * \file gtk/GMenubar.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef MENUBAR_PIMPL_H +#define MENUBAR_PIMPL_H + +#include "frontends/Menubar.h" +#include "MenuBackend.h" +#include + +class LyXView; + +class GMenubar : public Menubar, public SigC::Object { +public: + GMenubar(LyXView *, MenuBackend const &); + ~GMenubar(); + void update(); + void openByName(string const &); +private: + void onCommandActivate(MenuItem const * item, Gtk::MenuItem * gitem); + void onSubMenuActivate(MenuItem const * item, Gtk::MenuItem * gitem); + bool submenuDisabled(MenuItem const * item); + Gtk::MenuBar menubar_; + LyXView * view_; + std::vector mainMenuNames_; +}; + +#endif diff --git a/src/frontends/gtk/GMiniBuffer.C b/src/frontends/gtk/GMiniBuffer.C new file mode 100644 index 0000000000..892c1f7181 --- /dev/null +++ b/src/frontends/gtk/GMiniBuffer.C @@ -0,0 +1,281 @@ +/** + * \file GMiniBuffer.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "GView.h" +#include "GMiniBuffer.h" +#include "debug.h" +#include "bufferview_funcs.h" +#include +#include +#include "frontends/controllers/ControlCommandBuffer.h" + + +GMiniBuffer::GMiniBuffer(GView * view, ControlCommandBuffer & control) : + controller_(control), view_(view) +{ + listCols_.add(listCol_); + listStore_ = Gtk::ListStore::create(listCols_); + listView_.set_model(listStore_); + listView_.append_column("Completions", listCol_); + listView_.signal_key_press_event().connect( + SigC::slot(*this, &GMiniBuffer::onListKeyPress)); + listView_.signal_focus_in_event().connect( + SigC::slot(*this, &GMiniBuffer::onListFocusIn)); + listView_.signal_focus_out_event().connect( + SigC::slot(*this, &GMiniBuffer::onFocusOut)); + listSel_ = listView_.get_selection(); + listSel_->signal_changed().connect( + SigC::slot(*this, &GMiniBuffer::onSelected)); + listView_.show(); + scrolledWindow_.set_policy(Gtk::POLICY_AUTOMATIC, + Gtk::POLICY_AUTOMATIC); + scrolledWindow_.set_size_request(300, 150); + scrolledWindow_.add(listView_); + view_->getVBox().children().push_back( + Gtk::Box_Helpers::Element(scrolledWindow_, + Gtk::PACK_SHRINK)); + entry_.signal_key_press_event().connect( + SigC::slot(*this, &GMiniBuffer::onKeyPress)); + entry_.signal_focus_in_event().connect( + SigC::slot(*this, &GMiniBuffer::onFocusIn)); + entry_.signal_focus_out_event().connect( + SigC::slot(*this, &GMiniBuffer::onFocusOut)); + entry_.signal_activate().connect( + SigC::slot(*this, &GMiniBuffer::onCommit)); + entry_.show(); + view_->getVBox().children().push_back( + Gtk::Box_Helpers::Element(entry_, + Gtk::PACK_SHRINK)); + infoTimer_.reset(new Timeout(1500)); + idleTimer_.reset(new Timeout(6000)); + focusTimer_.reset(new Timeout(50)); + infoCon_ = infoTimer_->timeout.connect( + boost::bind(&GMiniBuffer::infoTimeout, this)); + idleCon_ = idleTimer_->timeout.connect( + boost::bind(&GMiniBuffer::idleTimeout, this)); + focusTimer_->timeout.connect( + boost::bind(&GMiniBuffer::focusTimeout, this)); + idleTimer_->start(); + messageMode(); +} + + +GMiniBuffer::~GMiniBuffer() +{ +} + + +void GMiniBuffer::message(string const & str) +{ + if (!isEditMode()) + setInput(Glib::locale_to_utf8(str)); +} + + +void GMiniBuffer::showInfo(Glib::ustring const & info, bool append) +{ + storedInput_ = entry_.get_text(); + entry_.set_editable(false); + infoShown_ = true; + if (append) + setInput(storedInput_ + ' ' + info); + else + setInput(info); + infoTimer_->start(); +} + + +void GMiniBuffer::onSelected() +{ + if (!listSel_->count_selected_rows()) + return; + Gtk::TreeModel::iterator it = listSel_->get_selected(); + Glib::ustring sel = (*it)[listCol_]; + setInput(sel + ' '); +} + + +void GMiniBuffer::onCommit() +{ + controller_.dispatch(Glib::locale_from_utf8(entry_.get_text())); + messageMode(); +} + + +bool GMiniBuffer::onListFocusIn(GdkEventFocus * /*event*/) +{ + if (focusTimer_->running()) + focusTimer_->stop(); + if (infoShown_) { + infoTimer_->stop(); + infoTimeout(); + } + return false; +} + + +bool GMiniBuffer::onFocusIn(GdkEventFocus * /*event*/) +{ + if (infoShown_) { + infoTimer_->stop(); + infoTimeout(); + } + if (focusTimer_->running()) { + focusTimer_->stop(); + return false; + } + setInput(""); + idleTimer_->stop(); + return false; +} + + +bool GMiniBuffer::onFocusOut(GdkEventFocus * /*event*/) +{ + focusTimer_->start(); + return false; +} + + +void GMiniBuffer::focusTimeout() +{ + if (infoShown_) { + infoTimer_->stop(); + infoTimeout(); + } + focusTimer_->stop(); + setInput(""); + idleTimer_->start(); + scrolledWindow_.hide(); +} + + +bool GMiniBuffer::onListKeyPress(GdkEventKey * event) +{ + if (infoShown_) { + infoTimer_->stop(); + infoTimeout(); + } + switch (event->keyval) { + case GDK_Escape: + messageMode(); + break; + case GDK_Tab: + entry_.grab_focus(); + setInput(entry_.get_text() + ' '); + break; + } + return true; +} + + +bool GMiniBuffer::onKeyPress(GdkEventKey * event) +{ + if (infoShown_) { + infoTimer_->stop(); + infoTimeout(); + } + switch (event->keyval) { + case GDK_Down: + { + Glib::ustring const h = + Glib::locale_to_utf8(controller_.historyDown()); + if (h.empty()) + showInfo("[End of history]", false); + else + setInput(h); + break; + } + case GDK_Up: + { + Glib::ustring const h = + Glib::locale_to_utf8(controller_.historyUp()); + if (h.empty()) + showInfo("[Beginning of history]", false); + else + setInput(h); + break; + } + case GDK_Escape: + messageMode(); + break; + case GDK_Tab: + { + Glib::ustring new_input, input; + string new_input_locale; + input = entry_.get_text(); + std::vector comp = + controller_.completions(Glib::locale_from_utf8(input), + new_input_locale); + new_input = Glib::locale_to_utf8(new_input_locale); + if (comp.empty() && new_input == input) { + showInfo("[no match]"); + break; + } + + if (comp.empty()) { + setInput(new_input + ' '); + showInfo("[only completion]"); + break; + } + setInput(new_input); + listStore_->clear(); + std::vector::iterator it; + for (it = comp.begin(); it != comp.end(); ++it) + (*listStore_->append())[listCol_] = + Glib::locale_to_utf8(*it); + scrolledWindow_.show(); + break; + } + } + return true; +} + + +bool GMiniBuffer::isEditMode() const +{ + return entry_.has_focus() || listView_.has_focus(); +} + + +void GMiniBuffer::infoTimeout() +{ + infoShown_ = false; + setInput(storedInput_); + entry_.set_editable(true); +} + + +void GMiniBuffer::idleTimeout() +{ + setInput(Glib::locale_to_utf8(controller_.getCurrentState())); +} + + +void GMiniBuffer::editMode() +{ + entry_.grab_focus(); +} + + +void GMiniBuffer::messageMode() +{ + view_->focusWorkArea(); +} + + +void GMiniBuffer::setInput(Glib::ustring const & input) +{ + entry_.set_text(input); + entry_.set_position(-1); +} diff --git a/src/frontends/gtk/GMiniBuffer.h b/src/frontends/gtk/GMiniBuffer.h new file mode 100644 index 0000000000..07f68af243 --- /dev/null +++ b/src/frontends/gtk/GMiniBuffer.h @@ -0,0 +1,70 @@ +// -*- C++ -*- +/** + * \file GMiniBuffer.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + + +#ifndef GMINI_BUFFER_H +#define GMINI_BUFFER_H + +#include "frontends/Timeout.h" +#include "LString.h" +class ControlCommandBuffer; + +class GMiniBuffer : public SigC::Object +{ +public: + GMiniBuffer(GView * view, ControlCommandBuffer & control); + ~GMiniBuffer(); + void message(string const & str); + /// go into edit mode + void editMode(); +private: + bool onKeyPress(GdkEventKey * event); + bool onListKeyPress(GdkEventKey * event); + void onCommit(); + bool onListFocusIn(GdkEventFocus * event); + bool onFocusIn(GdkEventFocus * event); + bool onFocusOut(GdkEventFocus * event); + void focusTimeout(); + void onSelected(); + /// Are we in edit mode? + bool isEditMode() const; + /// reset buffer to stored input text + void infoTimeout(); + /// go back to "at rest" message + void idleTimeout(); + /// go into message mode + void messageMode(); + /// show a temporary message whilst in edit mode + void showInfo(Glib::ustring const & info, bool append = true); + void setInput(Glib::ustring const & input); + ControlCommandBuffer & controller_; + GView * view_; + Gtk::Entry entry_; + /// info timer + boost::scoped_ptr infoTimer_; + boost::signals::connection infoCon_; + /// idle timer + boost::scoped_ptr idleTimer_; + boost::signals::connection idleCon_; + Glib::ustring storedInput_; + /// are we showing an informational temporary message ? + bool infoShown_; + boost::scoped_ptr focusTimer_; + + Gtk::ScrolledWindow scrolledWindow_; + Gtk::TreeModelColumn listCol_; + Gtk::TreeModel::ColumnRecord listCols_; + Glib::RefPtr listStore_; + Gtk::TreeView listView_; + Glib::RefPtr listSel_; +}; + +#endif diff --git a/src/frontends/gtk/GPainter.C b/src/frontends/gtk/GPainter.C new file mode 100644 index 0000000000..c17115ea69 --- /dev/null +++ b/src/frontends/gtk/GPainter.C @@ -0,0 +1,272 @@ +/** + * \file GPainter.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "GPainter.h" +#include "LString.h" +#include "debug.h" +#include "GWorkArea.h" +#include "lyxrc.h" +#include "encoding.h" +#include "language.h" +#include "xftFontLoader.h" +#include "xformsImage.h" +#include "frontends/font_metrics.h" +#include "codeConvert.h" + +#include "support/LAssert.h" +#include "support/lstrings.h" + +#include +#include +#include + + +GPainter::GPainter(GWorkArea & xwa) + : Painter(), owner_(xwa) +{ +} + + +int GPainter::paperWidth() const +{ + return owner_.workWidth(); +} + + +int GPainter::paperHeight() const +{ + return owner_.workHeight(); +} + + +void GPainter::setForeground(Glib::RefPtr gc, LColor::color clr) +{ + Gdk::Color * gclr = owner_.getColorHandler().getGdkColor(clr); + gc->set_foreground(*gclr); +} + + +void GPainter::setLineParam(Glib::RefPtr gc, + line_style ls, line_width lw) +{ + int width; + Gdk::LineStyle style; + switch (lw) { + case Painter::line_thin: + width = 0; + break; + case Painter::line_thick: + width = 2; + break; + } + + switch (ls) { + case Painter::line_solid: + style = Gdk::LINE_SOLID; + break; + case Painter::line_onoffdash: + style = Gdk::LINE_ON_OFF_DASH; + break; + } + gc->set_line_attributes(width, style, + Gdk::CAP_NOT_LAST, Gdk::JOIN_MITER); +} + + +Painter & GPainter::point(int x, int y, LColor::color c) +{ + setForeground(owner_.getGC(), c); + owner_.getPixmap()->draw_point(owner_.getGC(), x, y); + return *this; +} + + +Painter & GPainter::line(int x1, int y1, + int x2, int y2, + LColor::color col, + line_style ls, + line_width lw) +{ + setForeground(owner_.getGC(), col); + setLineParam(owner_.getGC(), ls, lw); + owner_.getPixmap()->draw_line(owner_.getGC(), x1, y1, x2, y2); + return *this; +} + + +Painter & GPainter::lines(int const * xp, int const * yp, + int np, + LColor::color col, + line_style ls, + line_width lw) +{ + setForeground(owner_.getGC(), col); + setLineParam(owner_.getGC(), ls, lw); + std::vector points(np); + + for (int i = 0; i < np; ++i) { + points[i].set_x(xp[i]); + points[i].set_y(yp[i]); + } + owner_.getPixmap()->draw_lines(owner_.getGC(), points); + return *this; +} + + +Painter & GPainter::rectangle(int x, int y, + int w, int h, + LColor::color col, + line_style ls, + line_width lw) +{ + setForeground(owner_.getGC(), col); + setLineParam(owner_.getGC(), ls, lw); + owner_.getPixmap()->draw_rectangle(owner_.getGC(), false, x, y, w, h); + return *this; +} + + +Painter & GPainter::fillRectangle(int x, int y, + int w, int h, + LColor::color col) +{ + setForeground(owner_.getGC(), col); + owner_.getPixmap()->draw_rectangle(owner_.getGC(), true, x, y, w, h); + return *this; +} + + +Painter & GPainter::fillPolygon(int const * xp, int const * yp, + int np, LColor::color col) +{ + setForeground(owner_.getGC(), col); + std::vector points(np); + + for (int i = 0; i < np; ++i) { + points[i].set_x(xp[i]); + points[i].set_y(yp[i]); + } + owner_.getPixmap()->draw_polygon(owner_.getGC(), true, points); + return *this; +} + + +Painter & GPainter::arc(int x, int y, + unsigned int w, unsigned int h, + int a1, int a2, LColor::color col) +{ + setForeground(owner_.getGC(), col); + owner_.getPixmap()->draw_arc(owner_.getGC(), + false, x, y, w, h, a1, a2); + return *this; +} + + +Painter & GPainter::image(int x, int y, + int w, int h, + lyx::graphics::Image const & i) +{ + lyx::graphics::xformsImage const & image = + static_cast(i); + Pixmap pixmap = GDK_PIXMAP_XID(owner_.getPixmap()->gobj()); + GC gc = GDK_GC_XGC(owner_.getGC()->gobj()); + XCopyArea(owner_.getDisplay(), image.getPixmap(), pixmap, + gc, 0, 0, w, h, x, y); + return *this; +} + + +Painter & GPainter::text(int x, int y, + string const & s, LyXFont const & f) +{ + size_t size = s.length() + 1; + wchar_t * wcs = (wchar_t *) alloca(size * sizeof(wchar_t)); + size = mbstowcs(wcs, s.c_str(), size); + return text(x, y, wcs, size, f); +} + + +Painter & GPainter::text(int x, int y, + char c, LyXFont const & f) +{ + char s[2] = { c, '\0' }; + return text(x, y, s, 1, f); +} + + +inline XftFont * getXftFont(LyXFont const & f) +{ + return fontLoader.load(f.family(), f.series(), + f.realShape(), f.size()); +} + + +namespace font_metrics +{ + +int width(wchar_t const *s, size_t n, LyXFont const & f); + +} + + +Painter & GPainter::text(int x, int y, wchar_t const * s, int ls, + LyXFont const & f) +{ + XftFont * font = getXftFont(f); + XftColor * xftClr = owner_.getColorHandler(). + getXftColor(f.realColor()); +// getXftColor(f.realColor()); + XftDraw * draw = owner_.getXftDraw(); + if (f.realShape() != LyXFont::SMALLCAPS_SHAPE) { + XftDrawString32(draw, xftClr, font, x, y, + wcsToFcChar32StrFast(s), ls); + } else { + LyXFont smallfont(f); + smallfont.decSize().decSize().setShape(LyXFont::UP_SHAPE); + XftFont * fontS = getXftFont(smallfont); + wchar_t c; + int tmpx = x; + for(int i = 0; i < ls; ++i) { + c = lyx::support::uppercase(s[i]); + if(c != s[i]) { + XftDrawString32(draw, xftClr, fontS, tmpx, y, + wcsToFcChar32StrFast(&c), 1); + tmpx += font_metrics::width(c, smallfont); + } else { + XftDrawString32(draw, xftClr, font, tmpx, y, + wcsToFcChar32StrFast(&c), 1); + tmpx += font_metrics::width(c, f); + } + } + } + if (f.underbar() == LyXFont::ON) + underline(f, x, y, font_metrics::width(s, ls, f)); + return *this; +} + + +Painter & GPainter::text(int x, int y, + char const * s, size_t ls, + LyXFont const & f) +{ + boost::scoped_array wcs(new wchar_t[ls + 1]); + size_t len; + if (fontLoader.isSpecial(f)) { + unsigned char const * us = + reinterpret_cast(s); + len = ls; + std::copy(us, us + ls, wcs.get()); + } else + len = mbstowcs(wcs.get(), s, ls + 1); + return text(x, y, wcs.get(), len, f); +} diff --git a/src/frontends/gtk/GPainter.h b/src/frontends/gtk/GPainter.h new file mode 100644 index 0000000000..7f06c28b6f --- /dev/null +++ b/src/frontends/gtk/GPainter.h @@ -0,0 +1,129 @@ +// -*- C++ -*- +/** + * \file GPainter.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef GPAINTER_H +#define GPAINTER_H + +#include +#include + +#include +#include "frontends/Painter.h" +#include "LString.h" + +class LyXFont; +class GWorkArea; + +/** + * GPainter - a painter implementation for Gtkmm + */ +class GPainter : public Painter { +public: + GPainter(GWorkArea &); + + /// return the width of the work area in pixels + virtual int paperWidth() const; + /// return the height of the work area in pixels + virtual int paperHeight() const; + + void setForeground(Glib::RefPtr gc, LColor::color clr); + void setLineParam(Glib::RefPtr gc, + line_style ls, line_width lw); + XftColor * getXftColor(LColor::color clr); + /// draw a line from point to point + virtual Painter & line( + int x1, int y1, + int x2, int y2, + LColor::color = LColor::foreground, + line_style = line_solid, + line_width = line_thin); + + /** + * lines - draw a set of lines + * @param xp array of points' x co-ords + * @param yp array of points' y co-ords + * @param np size of the points array + */ + virtual Painter & lines( + int const * xp, + int const * yp, + int np, + LColor::color = LColor::foreground, + line_style = line_solid, + line_width = line_thin); + + /// draw a rectangle + virtual Painter & rectangle( + int x, int y, + int w, int h, + LColor::color = LColor::foreground, + line_style = line_solid, + line_width = line_thin); + + /// draw a filled rectangle + virtual Painter & fillRectangle( + int x, int y, + int w, int h, + LColor::color); + + /// draw a filled (irregular) polygon + virtual Painter & fillPolygon( + int const * xp, + int const * yp, + int np, + LColor::color = LColor::foreground); + + /// draw an arc + virtual Painter & arc( + int x, int y, + unsigned int w, unsigned int h, + int a1, int a2, + LColor::color = LColor::foreground); + + /// draw a pixel + virtual Painter & point( + int x, int y, + LColor::color = LColor::foreground); + + /// draw an image from the image cache + virtual Painter & image(int x, int y, + int w, int h, + lyx::graphics::Image const & image); + + /// draw a string at position x, y (y is the baseline) + virtual Painter & text(int x, int y, + string const & str, LyXFont const & f); + + /** Draw a string at position x, y (y is the baseline) + * This is just for fast drawing + */ + virtual Painter & text(int x, int y, + char const * str, size_t l, + LyXFont const & f); + + virtual Painter & text(int x, int y, wchar_t const * str, int l, + LyXFont const & f); + + /// draw a char at position x, y (y is the baseline) + virtual Painter & text(int x, int y, + char c, LyXFont const & f); + + /// draw a wide string at position x, y + Painter & text(int x, int y, + XChar2b const * str, size_t l, + LyXFont const & f); + +private: + /// our owner who we paint upon + GWorkArea & owner_; +}; + +#endif // XPAINTER_H diff --git a/src/frontends/gtk/GPrint.C b/src/frontends/gtk/GPrint.C new file mode 100644 index 0000000000..ba5e3bb830 --- /dev/null +++ b/src/frontends/gtk/GPrint.C @@ -0,0 +1,156 @@ +// GPrint.C + +#include +#include +#include + +#include "GPrint.h" +#include "ControlPrint.h" +#include "support/filetools.h" +#include "PrinterParams.h" +#include "support/lstrings.h" + + +GPrint::GPrint(Dialog & parent, string title) + : GViewCB(parent, title, false) +{ +} + + +void GPrint::apply() +{ + PrinterParams pp; + pp.target = printer_->get_active() ? PrinterParams::PRINTER : PrinterParams::FILE; + pp.printer_name = printerEntry_->get_text(); + pp.file_name = printerEntry_->get_text(); + pp.all_pages = all_->get_active(); + pp.from_page = pp.to_page = 0; + if (!fromEntry_->get_text().empty()) { + pp.from_page = strToInt(fromEntry_->get_text()); + if (!toEntry_->get_text().empty()) + pp.to_page = strToInt(toEntry_->get_text()); + } + pp.odd_pages = odd_->get_active(); + pp.even_pages = even_->get_active(); + pp.count_copies = number_->get_value_as_int(); + pp.sorted_copies = sorted_->get_active(); + pp.reverse_order = reverse_->get_active(); + controller().params() = pp; +} + + +void GPrint::update() +{ + PrinterParams & pp = controller().params(); + printer_->set_active(pp.target == PrinterParams::PRINTER); + printerEntry_->set_text(pp.printer_name); + fileEntry_->set_text(pp.file_name); + all_->set_active(pp.all_pages); + + string const from = ( pp.from_page ? tostr(pp.from_page) : string() ); + string const to = ( pp.to_page ? tostr(pp.to_page) : string() ); + fromEntry_->set_text(from); + toEntry_->set_text(to); + odd_->set_active(pp.odd_pages); + even_->set_active(pp.even_pages); + reverse_->set_active(pp.reverse_order); + sorted_->set_active(pp.sorted_copies); + number_->set_value(pp.count_copies); + bool const enable_counter = pp.target == PrinterParams::PRINTER; + number_->set_sensitive(enable_counter); + sorted_->set_sensitive(enable_counter && pp.count_copies > 1); +} + + +void GPrint::updateUI() +{ + ButtonPolicy::SMInput activate = ButtonPolicy::SMI_VALID; + // disable OK/Apply buttons when file output is selected, but no file name entered + if (file_->get_active() && fileEntry_->get_text().empty()) + activate = ButtonPolicy::SMI_INVALID; + // check 'from' and 'to' fields only when 'from/to' radio button is selected + if (fromTo_->get_active()) { + string from = fromEntry_->get_text(); + string to = toEntry_->get_text(); + if (from.empty() || (!to.empty() && strToInt(from) > strToInt(to))) + activate = ButtonPolicy::SMI_INVALID; + } + bool const enableCounter = printer_->get_active(); + number_->set_sensitive(enableCounter); + bool const enableSorted = enableCounter && number_->get_value_as_int() > 1; + sorted_->set_sensitive(enableSorted); + bc().input(activate); +} + + +void GPrint::onBrowse() +{ + string const inName = fileEntry_->get_text(); + string const outName = Glib::locale_to_utf8(controller().Browse(Glib::locale_from_utf8(inName))); + if (outName != inName && !outName.empty()) + fileEntry_->set_text(outName); + if (!outName.empty()) + file_->set_active(true); + updateUI(); +} + + +void GPrint::onTargetEdit(Gtk::Entry const * who) +{ + if (who == fileEntry_) + file_->set_active(true); + else if (who == printerEntry_) + printer_->set_active(true); + updateUI(); +} + + +void GPrint::onFromToEdit() +{ + fromTo_->set_active(true); + updateUI(); +} + + +void GPrint::doBuild() +{ + string const gladeName = LibFileSearch("glade", "print", "glade"); + xml_ = Gnome::Glade::Xml::create(gladeName); + xml_->get_widget("Printer", printer_); + xml_->get_widget("File", file_); + xml_->get_widget("All", all_); + xml_->get_widget("FromTo", fromTo_); + xml_->get_widget("Odd", odd_); + xml_->get_widget("Even", even_); + xml_->get_widget("Reverse", reverse_); + xml_->get_widget("Number", number_); + xml_->get_widget("Sorted", sorted_); + xml_->get_widget("FromEntry", fromEntry_); + xml_->get_widget("ToEntry", toEntry_); + xml_->get_widget("PrinterEntry", printerEntry_); + xml_->get_widget("FileEntry", fileEntry_); + Gtk::Button * ok; + Gtk::Button * cancel; + Gtk::Button * apply; + xml_->get_widget("OkButton", ok); + xml_->get_widget("CancelButton", cancel); + xml_->get_widget("ApplyButton", apply); + bc().setOK(ok); + bc().setApply(apply); + bc().setCancel(cancel); + ok->signal_clicked().connect(SigC::slot(*this, &GViewBase::onOK)); + apply->signal_clicked().connect(SigC::slot(*this, &GViewBase::onApply)); + cancel->signal_clicked().connect(SigC::slot(*this, &GViewBase::onCancel)); + Gtk::Button * browse; + xml_->get_widget("Browse", browse); + browse->signal_clicked().connect(SigC::slot(*this, &GPrint::onBrowse)); + fileEntry_->signal_changed().connect(SigC::bind(SigC::slot(*this, &GPrint::onTargetEdit), fileEntry_)); + printerEntry_->signal_changed().connect(SigC::bind(SigC::slot(*this, &GPrint::onTargetEdit), printerEntry_)); + fromEntry_->signal_changed().connect(SigC::slot(*this, &GPrint::onFromToEdit)); + toEntry_->signal_changed().connect(SigC::slot(*this, &GPrint::onFromToEdit)); + printer_->signal_toggled().connect(SigC::slot(*this, &GPrint::updateUI)); + file_->signal_toggled().connect(SigC::slot(*this, &GPrint::updateUI)); + all_->signal_toggled().connect(SigC::slot(*this, &GPrint::updateUI)); + fromTo_->signal_toggled().connect(SigC::slot(*this, &GPrint::updateUI)); + number_->signal_changed().connect(SigC::slot(*this, &GPrint::updateUI)); +} diff --git a/src/frontends/gtk/GPrint.h b/src/frontends/gtk/GPrint.h new file mode 100644 index 0000000000..a296335986 --- /dev/null +++ b/src/frontends/gtk/GPrint.h @@ -0,0 +1,43 @@ +// -*- C++ -*- +/* + * /file GPrint.h + */ + +#ifndef GPRINT_H +#define GPRINT_H + +#include "LString.h" +#include "GViewBase.h" + +class ControlPrint; + +class GPrint : public GViewCB +{ +public: + GPrint(Dialog & parent, string title = "Print Document"); +private: + virtual void apply(); + virtual void update(); + virtual void doBuild(); + void updateUI(); + void onBrowse(); + void onTargetEdit(Gtk::Entry const * who); + void onFromToEdit(); + + Gtk::RadioButton * printer_; + Gtk::RadioButton * file_; + Gtk::RadioButton * all_; + Gtk::RadioButton * fromTo_; + Gtk::CheckButton * odd_; + Gtk::CheckButton * even_; + Gtk::CheckButton * reverse_; + Gtk::SpinButton * number_; + Gtk::CheckButton * sorted_; + Gtk::Entry * printerEntry_; + Gtk::Entry * fileEntry_; + Gtk::Entry * fromEntry_; + Gtk::Entry * toEntry_; +}; + +#endif + diff --git a/src/frontends/gtk/GScreen.C b/src/frontends/gtk/GScreen.C new file mode 100644 index 0000000000..3d4c6fecfc --- /dev/null +++ b/src/frontends/gtk/GScreen.C @@ -0,0 +1,134 @@ +/** + * \file GScreen.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include + +#include "frontends/screen.h" +#include "frontends/font_metrics.h" +#include "GWorkArea.h" +#include "GScreen.h" +#include "lyxtext.h" +#include "lyxrow.h" +#include "Painter.h" +#include "WorkArea.h" +#include "buffer.h" +#include "BufferView.h" +#include "insets/insettext.h" +#include "language.h" +#include "debug.h" + + +GScreen::GScreen(GWorkArea & o) + : LyXScreen(), owner_(o) +{ + // the cursor isnt yet visible + cursorX_ = 0; + cursorY_ = 0; + cursorW_ = 0; + cursorH_ = 0; +} + + +GScreen::~GScreen() +{ +} + + +void GScreen::setCursorColor(Glib::RefPtr gc) +{ + Gdk::Color * clr = owner_.getColorHandler(). + getGdkColor(LColor::cursor); + gc->set_foreground(*clr); +} + + +void GScreen::showCursor(int x, int y, + int h, Cursor_Shape shape) +{ + // Update the cursor color. + setCursorColor(owner_.getGC()); + + cursorX_ = x; + cursorY_ = y; + cursorH_ = h; + + switch (shape) { + case BAR_SHAPE: + cursorW_ = 1; + break; + case L_SHAPE: + cursorW_ = cursorH_ / 3; + break; + case REVERSED_L_SHAPE: + cursorW_ = cursorH_ / 3; + cursorX_ = x - cursorW_ + 1; + break; + } + + int fx, fy, fwidth, fheight, fdepth; + owner_.getWindow()->get_geometry(fx, fy, fwidth, fheight, fdepth); + cursorPixmap_ = Gdk::Pixmap::create(owner_.getWindow(), + cursorW_, + cursorH_, + fdepth); + cursorPixmap_->draw_drawable(owner_.getGC(), + owner_.getWindow(), + owner_.xpos() + cursorX_, + owner_.ypos() + cursorY_, + 0, 0, + cursorW_, + cursorH_); + owner_.getWindow()->draw_line(owner_.getGC(), + x + owner_.xpos(), + y + owner_.ypos(), + x + owner_.xpos(), + y + h - 1 + owner_.ypos()); + switch (shape) { + case BAR_SHAPE: + break; + case L_SHAPE: + case REVERSED_L_SHAPE: + owner_.getWindow()->draw_line(owner_.getGC(), + owner_.xpos() + cursorX_, + owner_.ypos() + y + h - 1, + owner_.xpos() + cursorX_ + cursorW_ - 1, + owner_.xpos() + y + h - 1); + break; + } +} + + +void GScreen::removeCursor() +{ + if (cursorPixmap_) { + owner_.getWindow()->draw_drawable(owner_.getGC(), + cursorPixmap_, + 0, 0, + cursorX_ + owner_.xpos(), + cursorY_ + owner_.ypos(), + cursorW_, cursorH_); + } +} + + +void GScreen::expose(int x, int y, int w, int h) +{ + lyxerr[Debug::GUI] << "expose " << w << 'x' << h + << '+' << x << '+' << y << std::endl; + owner_.getWindow()->draw_drawable(owner_.getGC(), + owner_.getPixmap(), + x, y, + x + owner_.xpos(), + y + owner_.ypos(), + w, h); +} diff --git a/src/frontends/gtk/GScreen.h b/src/frontends/gtk/GScreen.h new file mode 100644 index 0000000000..50587c67d4 --- /dev/null +++ b/src/frontends/gtk/GScreen.h @@ -0,0 +1,63 @@ +// -*- C++ -*- +/** + * \file GScreen.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef GSCREEN_H +#define GSCREEN_H + +#include "screen.h" + +class GWorkArea; + +/** The class GScreen is used for the main Textbody. + Concretely, the screen is held in a pixmap. This pixmap is kept up to + date and used to optimize drawing on the screen. + This class also handles the drawing of the cursor and partly the selection. + */ +class GScreen : public LyXScreen { +public: + /// + GScreen(GWorkArea &); + + /// + virtual ~GScreen(); + + /// Sets the cursor color to LColor::cursor. + virtual void setCursorColor(Glib::RefPtr gc); + /// + virtual void removeCursor(); + /// + virtual void showCursor(int x, int y, int h, + Cursor_Shape shape); + +protected: + /// get the work area + virtual WorkArea & workarea() const { return owner_; } + + /// Copies specified area of pixmap to screen + virtual void expose(int x, int y, int w, int h); + +private: + /// our owning widget + GWorkArea & owner_; + + /// + Glib::RefPtr cursorPixmap_; + /// + int cursorX_; + /// + int cursorY_; + /// + int cursorW_; + /// + int cursorH_; +}; + +#endif diff --git a/src/frontends/gtk/GText.C b/src/frontends/gtk/GText.C new file mode 100644 index 0000000000..71c0141cba --- /dev/null +++ b/src/frontends/gtk/GText.C @@ -0,0 +1,77 @@ +/** + * \file GText.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include +#include + +#include "support/lstrings.h" +#include "support/filetools.h" +#include "ControlCommand.h" +#include "GText.h" +#include "IdSc.h" + +GText::GText(Dialog & parent, string const & title, string const & label) + : GViewCB(parent, title), + label_(label), entry_(0) +{ +} + +void GText::apply() +{ + string const contents = Glib::locale_from_utf8(entry_->get_text()); + controller().params().setContents(contents); +} + +void GText::update() +{ + string const contents = lyx::support::trim( + controller().params().getContents()); + entry_->set_text(Glib::locale_to_utf8(contents)); +} + +void GText::doBuild() +{ + string const gladeName = + lyx::support::LibFileSearch("glade", "text", "glade"); + xml_ = Gnome::Glade::Xml::create(gladeName); + Gtk::Label * label; + Gtk::Button * restore; + Gtk::Button * cancel; + Gtk::Button * apply; + Gtk::Button * ok; + xml_->get_widget("Label", label); + xml_->get_widget("Text", entry_); + xml_->get_widget("Restore", restore); + xml_->get_widget("Cancel", cancel); + xml_->get_widget("Apply", apply); + xml_->get_widget("OK", ok); + label->set_text(Glib::locale_to_utf8(id_sc::id(label_))); + bcview().setOK(ok); + bcview().setApply(apply); + bcview().setCancel(cancel); + bcview().setRestore(restore); + bcview().addReadOnly(entry_); + ok->signal_clicked().connect( + SigC::slot(*this, &GViewBase::onOK)); + apply->signal_clicked().connect( + SigC::slot(*this, &GViewBase::onApply)); + cancel->signal_clicked().connect( + SigC::slot(*this, &GViewBase::onCancel)); + restore->signal_clicked().connect( + SigC::slot(*this, &GViewBase::onRestore)); + entry_->signal_changed().connect( + SigC::slot(*this, >ext::onEntryChanged)); +} + +void GText::onEntryChanged() +{ + bc().valid(!entry_->get_text().empty()); +} diff --git a/src/frontends/gtk/GText.h b/src/frontends/gtk/GText.h new file mode 100644 index 0000000000..cb480342c0 --- /dev/null +++ b/src/frontends/gtk/GText.h @@ -0,0 +1,33 @@ +// -*- C++ -*- +/** + * \file GText.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef GTEXT_H +#define GTEXT_H + +#include "GViewBase.h" +#include "LString.h" + +class ControlCommand; + +class GText : public GViewCB +{ +public: + GText(Dialog & parent, string const & title, string const & label); +private: + virtual void apply(); + virtual void update(); + virtual void doBuild(); + void onEntryChanged(); + string const label_; + Gtk::Entry * entry_; +}; + +#endif diff --git a/src/frontends/gtk/GTimeout.C b/src/frontends/gtk/GTimeout.C new file mode 100644 index 0000000000..c4512f1a71 --- /dev/null +++ b/src/frontends/gtk/GTimeout.C @@ -0,0 +1,69 @@ +/** + * \file gtk/GTimeout.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Baruch Even + * \author Michael Koziarski + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "GTimeout.h" +#include "debug.h" + + +Timeout::Timeout(unsigned int msec, Type t) + : pimpl_(new GTimeout(*this)), type(t), timeout_ms(msec) +{} + + +GTimeout::GTimeout(Timeout & owner) + : Timeout::Impl(owner) +{ +} + + +void GTimeout::reset() +{ + stop(); +} + + +bool GTimeout::running() const +{ + return running_; +} + + +void GTimeout::start() +{ + if (conn_.connected()) { + lyxerr << "Timeout::start: already running!" << std::endl; + stop(); + } + + conn_ = Glib::signal_timeout().connect( + SigC::slot(*this, >imeout::timeoutEvent), + timeout_ms() + ); + running_ = true; +} + + +void GTimeout::stop() +{ + conn_.disconnect(); + running_ = false; +} + + +bool GTimeout::timeoutEvent() +{ + emit(); + return false; // discontinue emitting timeouts. +} diff --git a/src/frontends/gtk/GTimeout.h b/src/frontends/gtk/GTimeout.h new file mode 100644 index 0000000000..c2726a1eaf --- /dev/null +++ b/src/frontends/gtk/GTimeout.h @@ -0,0 +1,47 @@ +// -*- C++ -*- +/** + * \file gtk/GTimeout.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Baruch Even + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef GTIMEOUT_H +#define GTIMEOUT_H + +#include "frontends/Timeout.h" + +#include + +/** + * This class executes the callback when the timeout expires + * using Gtk mechanisms + */ +class GTimeout : public Timeout::Impl, public SigC::Object { +public: + /// + GTimeout(Timeout & owner_); + /// start the timer + void start(); + /// stop the timer + void stop(); + /// reset + void reset(); + /// Is the timer running? + bool running() const; + +public: + /// The timeout signal, this gets called when the timeout passed. + bool timeoutEvent(); +private: + /// Timer connection + SigC::Connection conn_; + /// Used for running as SigC::Connection::connected() isn't const + bool running_; +}; + +#endif diff --git a/src/frontends/gtk/GToolbar.C b/src/frontends/gtk/GToolbar.C new file mode 100644 index 0000000000..80ea2f2de6 --- /dev/null +++ b/src/frontends/gtk/GToolbar.C @@ -0,0 +1,261 @@ +/** + * \file GToolbar.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "GToolbar.h" +#include "GView.h" +#include "LyXAction.h" +#include "lyxfunc.h" +#include "FuncStatus.h" +#include "buffer.h" +#include "funcrequest.h" +#include "gettext.h" +#include "Tooltips.h" +#include "support/filetools.h" +#include "support/lstrings.h" +#include "debug.h" + + +namespace +{ + + +char const * gToolData = "tool_data"; + + +inline void comboClear(Gtk::Combo & combo) +{ + std::vector strings; + strings.push_back(""); + combo.set_popdown_strings(strings); +} + + +inline bool comboIsEmpty(Gtk::Combo & combo) +{ + std::vector strings = combo.get_popdown_strings(); + return (strings.empty() || (strings.size() == 1 && strings[0] == "")); +} + + +} + + +GToolbar::GToolbar(LyXView * lyxView, int /*x*/, int /*y*/) + : view_(lyxView), internal_(false) +{ + combo_.set_value_in_list(); + combo_.get_entry()->set_editable(false); + combo_.unset_flags(Gtk::CAN_FOCUS | Gtk::CAN_DEFAULT); + combo_.get_entry()->unset_flags(Gtk::CAN_FOCUS | Gtk::CAN_DEFAULT); + comboClear(combo_); + combo_.get_entry()->signal_changed().connect( + SigC::slot(*this, + >oolbar::onLayoutSelected)); + GView * gview = static_cast(lyxView); + vbox_.show(); + Gtk::VBox & vbox = gview->getVBox(); + vbox.children().push_back(Gtk::Box_Helpers::Element(vbox_, + Gtk::PACK_SHRINK)); +} + + +GToolbar::~GToolbar() +{ +} + + +void GToolbar::add(ToolbarBackend::Toolbar const & tb) +{ + Gtk::Toolbar * toolbar = manage(new Gtk::Toolbar()); + ToolbarBackend::item_iterator it = tb.items.begin(); + ToolbarBackend::item_iterator end = tb.items.end(); + for (; it != end; ++it) + add(toolbar, it->first, it->second); + toolbar->set_toolbar_style(Gtk::TOOLBAR_ICONS); + toolbar->show(); + vbox_.children().push_back( + Gtk::Box_Helpers::Element(*toolbar, + Gtk::PACK_SHRINK)); + toolbars_.push_back(toolbar); +} + + +void GToolbar::add(Gtk::Toolbar * toolbar, + int action, + string const & tooltip) +{ + switch (action) { + case ToolbarBackend::SEPARATOR: + toolbar->tools().push_back(Gtk::Toolbar_Helpers::Space()); + break; + case ToolbarBackend::MINIBUFFER: + // Not supported yet. + break; + case ToolbarBackend::LAYOUTS: + { + combo_.show(); + toolbar->tools().push_back( + Gtk::Toolbar_Helpers::Element(combo_)); + toolbar->tools().back().get_widget()->set_data( + gToolData, + reinterpret_cast(LFUN_LAYOUT)); + break; + } + default: + { + Glib::ustring xpmName = + Glib::locale_to_utf8(toolbarbackend.getIcon(action)); + Glib::ustring tip = Glib::locale_to_utf8(tooltip); + if (xpmName.size() == 0) { + toolbar->tools().push_back( + Gtk::Toolbar_Helpers::ButtonElem( + "", + SigC::bind(SigC::slot(*this, >oolbar::onButtonClicked), + action), + tip)); + } else { + Gtk::Image * image = + Gtk::manage(new Gtk::Image(xpmName)); + image->show(); + toolbar->tools().push_back( + Gtk::Toolbar_Helpers::ButtonElem( + "", + *image, + SigC::bind(SigC::slot(*this, >oolbar::onButtonClicked), + action), + tip)); + } + toolbar->tools().back().get_content()->set_data( + gToolData, + reinterpret_cast(action)); + break; + } + } +} + + +void GToolbar::onButtonClicked(int action) +{ + view_->getLyXFunc().dispatch(action, true); +} + + +void GToolbar::onLayoutSelected() +{ + if (internal_) + return; + string layoutGuiName = combo_.get_entry()->get_text(); + // we get two signal, one of it is empty and useless + if (layoutGuiName.empty()) + return; + LyXTextClass const & tc = + view_->buffer()->params.getLyXTextClass(); + + LyXTextClass::const_iterator end = tc.end(); + for (LyXTextClass::const_iterator cit = tc.begin(); + cit != end; ++cit) { + if ((*cit)->name() == layoutGuiName) { + view_->getLyXFunc().dispatch( + FuncRequest(LFUN_LAYOUT, (*cit)->name()), + true); + return; + } + } + lyxerr << "ERROR (GToolbar::layoutSelected): layout not found! name : " + << layoutGuiName + << std::endl; +} + + +void GToolbar::displayToolbar(ToolbarBackend::Toolbar const & /*tb*/, bool /*show*/) +{ +} + + +void GToolbar::update() +{ + std::vector::iterator itToolbar; + for (itToolbar = toolbars_.begin(); + itToolbar != toolbars_.end(); ++itToolbar) { + Gtk::Toolbar * toolbar = *itToolbar; + Gtk::Toolbar_Helpers::ToolList::iterator it; + for (it = toolbar->tools().begin(); + it != toolbar->tools().end(); ++it) { + Gtk::Widget * widget; + switch (it->get_type()) { + case Gtk::TOOLBAR_CHILD_WIDGET: + widget = it->get_widget(); + break; + case Gtk::TOOLBAR_CHILD_SPACE: + continue; + default: + widget = it->get_content(); + } + int action = reinterpret_cast( + widget->get_data(gToolData)); + FuncStatus const status = view_-> + getLyXFunc().getStatus(action); + bool sensitive = !status.disabled(); + widget->set_sensitive(sensitive); + if (it->get_type() != Gtk::TOOLBAR_CHILD_BUTTON) + return; + if (status.onoff(true)) + static_cast(widget)-> + set_relief(Gtk::RELIEF_NORMAL); + if (status.onoff(false)) + static_cast(widget)-> + set_relief(Gtk::RELIEF_NONE); + } + } +} + + +void GToolbar::setLayout(string const & layout) +{ + LyXTextClass const & tc = + view_->buffer()->params.getLyXTextClass(); + internal_ = true; + combo_.get_entry()->set_text(tc[layout]->name()); + internal_ = false; +} + + +void GToolbar::updateLayoutList() +{ + LyXTextClass const & tc = + view_->buffer()->params.getLyXTextClass(); + LyXTextClass::const_iterator end = tc.end(); + std::vector strings; + for (LyXTextClass::const_iterator cit = tc.begin(); + cit != end; ++cit) + if ((*cit)->obsoleted_by().empty()) + strings.push_back( + Glib::locale_to_utf8((*cit)->name())); + internal_ = true; + combo_.set_popdown_strings(strings); + internal_ = false; +} + + +void GToolbar::openLayoutList() +{ + combo_.get_list()->activate(); +} + + +void GToolbar::clearLayoutList() +{ + internal_ = true; + comboClear(combo_); + internal_ = false; +} diff --git a/src/frontends/gtk/GToolbar.h b/src/frontends/gtk/GToolbar.h new file mode 100644 index 0000000000..6779fd3cb0 --- /dev/null +++ b/src/frontends/gtk/GToolbar.h @@ -0,0 +1,62 @@ +// -*- C++ -*- +/** + * \file GToolbar.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef TOOLBAR_PIMPL_H +#define TOOLBAR_PIMPL_H + +#include +#include "frontends/Toolbar.h" +#include "ToolbarBackend.h" +#include "LString.h" + +class GToolbar : public Toolbar, public SigC::Object +{ +public: + GToolbar(LyXView * o, int x, int y); + + ~GToolbar(); + + // add a new toolbar + void add(ToolbarBackend::Toolbar const & tb); + + /// add a new button to the toolbar. + void add(Gtk::Toolbar * toolbar, + int action, + string const & tooltip); + + /// display toolbar, not implemented + void displayToolbar(ToolbarBackend::Toolbar const & tb, bool show); + + /// update the state of the icons + void update(); + + /// select the right layout in the combox + void setLayout(string const & layout); + + /// Populate the layout combox; re-do everything if force is true. + void updateLayoutList(); + + /// Drop down the layout list + void openLayoutList(); + + /// Erase the layout list + void clearLayoutList(); +private: + void onButtonClicked(int action); + void onLayoutSelected(); + Gtk::VBox vbox_; + std::vector toolbars_; + Gtk::Combo combo_; + LyXView * view_; + bool internal_; +}; + +#endif diff --git a/src/frontends/gtk/GView.C b/src/frontends/gtk/GView.C new file mode 100644 index 0000000000..75181b4db1 --- /dev/null +++ b/src/frontends/gtk/GView.C @@ -0,0 +1,124 @@ +/** + * \file GView.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "GView.h" +#include "MenuBackend.h" +#include "support/filetools.h" +#include "GMenubar.h" +#include "GToolbar.h" +#include "BufferView.h" +#include "XWorkArea.h" +#include "lyx_cb.h" +#include "GMiniBuffer.h" +#include "lyxfunc.h" +#include + +BufferView * current_view; + +GView * GView::view_ = 0; + + +GView::GView() +{ + view_ = this; + vbox_.reset(new Gtk::VBox()); + add(*vbox_.get()); + menubar_.reset(new GMenubar(this, menubackend)); + toolbar_.reset(new GToolbar(this, 0, 0)); + toolbar_->init(); + bufferview_.reset(new BufferView(this, 0, 0, 300, 300)); + ::current_view = bufferview_.get(); + minibuffer_.reset(new GMiniBuffer(this, *controlcommand_)); + vbox_->show(); + focus_command_buffer.connect( + boost::bind(&GMiniBuffer::editMode, minibuffer_.get())); + view_state_changed.connect(boost::bind(&GView::showViewState, this)); + signal_focus_in_event().connect(SigC::slot(*this, &GView::onFocusIn)); + set_default_size(500, 550); + // Make sure the buttons are disabled if needed. + updateToolbar(); + string const iconName = + lyx::support::LibFileSearch("images", "lyx", "xpm"); + if (!iconName.empty()) + set_icon_from_file(iconName); +} + + +GView::~GView() +{ +} + + +bool GView::on_delete_event(GdkEventAny * /*event*/) +{ + QuitLyX(); + return true; +} + + +bool GView::onFocusIn(GdkEventFocus * /*event*/) +{ + workArea_->grab_focus(); + return true; +} + + +void GView::prohibitInput() const +{ + view()->hideCursor(); + const_cast(this)->set_sensitive(false); +} + + +void GView::allowInput() const +{ + const_cast(this)->set_sensitive(true); +} + + +void GView::message(string const & msg) +{ + minibuffer_->message(msg); +} + + +void GView::showViewState() +{ + message(getLyXFunc().view_status_message()); +} + + +void GView::setWindowTitle(string const & t, string const & /*it*/) +{ + set_title(Glib::locale_to_utf8(t)); +} + + +void GView::busy(bool yes) const +{ + if (yes ) { + view()->hideCursor(); + Gdk::Cursor cursor(Gdk::WATCH); + const_cast(this)->get_window()->set_cursor(cursor); + const_cast(this)->set_sensitive(false); + } else { + const_cast(this)->get_window()->set_cursor(); + const_cast(this)->set_sensitive(true); + } +} + + +void GView::clearMessage() +{ + message(getLyXFunc().view_status_message()); +} diff --git a/src/frontends/gtk/GView.h b/src/frontends/gtk/GView.h new file mode 100644 index 0000000000..cf1d312d03 --- /dev/null +++ b/src/frontends/gtk/GView.h @@ -0,0 +1,48 @@ +// -*- C++ -*- +/** + * \file GView.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef GVIEW_H +#define GVIEW_H + +#include "frontends/LyXView.h" +#include "bufferview_funcs.h" +#include +class GMiniBuffer; + +class GView : public LyXView, public Gtk::Window +{ +public: + virtual ~GView(); + + virtual void prohibitInput() const; + virtual void allowInput() const; + virtual void message(string const &); + Gtk::VBox & getVBox() { return *vbox_.get(); } + GView(); + bool on_delete_event(GdkEventAny * event); + void focusWorkArea() { workArea_->grab_focus(); } + void setGWorkArea(Gtk::Widget * w) { workArea_ = w; } + static GView * instance() { return view_; } + /// show busy cursor + virtual void busy(bool) const; + /// clear any temporary message and replace with current status + virtual void clearMessage(); +private: + void showViewState(); + bool onFocusIn(GdkEventFocus * event); + virtual void setWindowTitle(string const & t, string const & it); + static GView * view_; + std::auto_ptr vbox_; + boost::scoped_ptr minibuffer_; + Gtk::Widget * workArea_; +}; + +#endif diff --git a/src/frontends/gtk/GViewBase.C b/src/frontends/gtk/GViewBase.C new file mode 100644 index 0000000000..07d8d6c76d --- /dev/null +++ b/src/frontends/gtk/GViewBase.C @@ -0,0 +1,124 @@ +/** + * \file GViewBase.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "GViewBase.h" +#include "ControlButtons.h" +#include "support/filetools.h" + + +GViewBase::GViewBase(Dialog & parent, string const & t, bool allowResize) : + Dialog::View(parent, t), allowResize_(allowResize) +{ +} + + +GViewBase::~GViewBase() +{ +} + + +void GViewBase::hide() +{ + window()->hide(); +} + + +void GViewBase::build() +{ + doBuild(); + string const iconName = + lyx::support::LibFileSearch("images", "lyx", "xpm"); + if (!iconName.empty()) + window()->set_icon_from_file(iconName); + window()->signal_delete_event().connect( + SigC::slot(*this, &GViewBase::onDeleteEvent)); + window()->set_title(Glib::locale_to_utf8(getTitle())); +} + + +void GViewBase::show() +{ + if (!window()) { + build(); + } + window()->show(); +} + + +bool GViewBase::isVisible() const +{ + return window() && window()->is_visible(); +} + + +GBC & GViewBase::bcview() +{ + return static_cast(dialog().bc().view()); +} + + +void GViewBase::onApply() +{ + dialog().ApplyButton(); +} + + +void GViewBase::onOK() +{ + dialog().OKButton(); +} + + +void GViewBase::onCancel() +{ + dialog().CancelButton(); +} + + +void GViewBase::onRestore() +{ + dialog().RestoreButton(); +} + + +bool GViewBase::onDeleteEvent(GdkEventAny *) +{ + dialog().CancelButton(); + return false; +} + + +GViewGladeB::GViewGladeB(Dialog & parent, string const & t, bool allowResize) : + GViewBase(parent, t, allowResize) +{ +} + + +Gtk::Window * GViewGladeB::window() +{ + Gtk::Window * win; + if (!xml_) + return 0; + xml_->get_widget("dialog", win); + return win; +} + + +const Gtk::Window * GViewGladeB::window() const +{ + Gtk::Window * win; + if (!xml_) + return 0; + xml_->get_widget("dialog", win); + return win; +} diff --git a/src/frontends/gtk/GViewBase.h b/src/frontends/gtk/GViewBase.h new file mode 100644 index 0000000000..0b9d88ac5c --- /dev/null +++ b/src/frontends/gtk/GViewBase.h @@ -0,0 +1,123 @@ +// -*- C++ -*- +/** + * \file GViewBase.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef GVIEWBASE_H +#define GVIEWBASE_H + +#include +#include +#include +#include "Dialog.h" +#include "ButtonPolicies.h" +#include "GBC.h" + +class GViewBase : public Dialog::View, public SigC::Object +{ +public: + GViewBase(Dialog &, string const &, bool allowResize); + virtual ~GViewBase(); +protected: + // Build the dialog + virtual void build(); + virtual void doBuild() = 0; + // Hide the dialog + virtual void hide(); + // Create the dialog if necessary, update it and display it. + virtual void show(); + // + virtual bool isVisible() const; + GBC & bcview(); + void onApply(); + void onOK(); + void onCancel(); + void onRestore(); + bool onDeleteEvent(GdkEventAny *); +private: + virtual Gtk::Window * window() = 0; + virtual Gtk::Window const * window() const = 0; + bool allowResize_; +}; + +template +class GViewDB : public GViewBase +{ +protected: + GViewDB(Dialog &, string const &, bool allowResize); + virtual const Gtk::Window * window() const; + virtual Gtk::Window * window(); + boost::scoped_ptr dialog_; +}; + + +template +GViewDB::GViewDB(Dialog & parent, string const & t, bool allowResize) : + GViewBase(parent, t, allowResize) +{ +} + + +template +Gtk::Window * GViewDB::window() +{ + return dialog_.get(); +} + + +template +const Gtk::Window * GViewDB::window() const +{ + return dialog_.get(); +} + + +class GViewGladeB : public GViewBase +{ +protected: + GViewGladeB(Dialog & parent, string const & t, bool allowResize); + virtual const Gtk::Window * window() const; + virtual Gtk::Window * window(); + Glib::RefPtr xml_; +}; + + +template +class GViewCB : public Base +{ +public: + Controller & controller(); + Controller const & controller() const; +protected: + GViewCB(Dialog & parent, string const & t, bool allowResize = false); +}; + + +template +GViewCB::GViewCB(Dialog & parent, string const & t, + bool allowResize) : + Base(parent, t, allowResize) +{ +} + + +template +Controller & GViewCB::controller() +{ + return static_cast(getController()); +} + + +template +Controller const & GViewCB::controller() const +{ + return static_cast(getController()); +} + +#endif diff --git a/src/frontends/gtk/GWorkArea.C b/src/frontends/gtk/GWorkArea.C new file mode 100644 index 0000000000..2ab906b1c8 --- /dev/null +++ b/src/frontends/gtk/GWorkArea.C @@ -0,0 +1,355 @@ +/** + * \file GWorkArea.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include +#include + +#include "GWorkArea.h" +#include "debug.h" +#include "funcrequest.h" +#include "GView.h" +#include "GtkmmX.h" +#include "GLyXKeySym.h" + +ColorCache colorCache; + + +void ColorCache::clear() +{ + MapIt it = cache_.begin(); + for (; it != cache_.end(); ++it) + delete it->second; + cache_.clear(); + MapIt2 it2 = cache2_.begin(); + for (; it2 != cache2_.end(); ++it2) + delete it2->second; + cache2_.clear(); +} + + +XftColor * ColorHandler::getXftColor(LColor::color clr) +{ + XftColor * xclr = colorCache.getXftColor(clr); + if (!xclr) { + xclr = new XftColor; + Colormap colormap = GDK_COLORMAP_XCOLORMAP( + owner_.getColormap()->gobj()); + Visual * visual = GDK_VISUAL_XVISUAL( + owner_.getColormap()->get_visual()->gobj()); + XftColorAllocName(owner_.getDisplay(), visual, colormap, + lcolor.getX11Name(clr).c_str(), xclr); + colorCache.cacheXftColor(clr, xclr); + } + return xclr; +} + + +Gdk::Color * ColorHandler::getGdkColor(LColor::color clr) +{ + Gdk::Color * gclr = colorCache.getColor(clr); + if (!gclr) { + gclr = new Gdk::Color; + gclr->parse(lcolor.getX11Name(clr)); + owner_.getColormap()->alloc_color(*gclr); + colorCache.cacheColor(clr, gclr); + } + return gclr; +} + + +namespace +{ + + +mouse_button::state gtkButtonState(unsigned int state) +{ + mouse_button::state b = mouse_button::none; + if (state & GDK_BUTTON1_MASK) + b = mouse_button::button1; + else if (state & GDK_BUTTON2_MASK) + b = mouse_button::button2; + else if (state & GDK_BUTTON3_MASK) + b = mouse_button::button3; + else if (state & GDK_BUTTON3_MASK) + b = mouse_button::button3; + else if (state & GDK_BUTTON4_MASK) + b = mouse_button::button4; + else if (state & GDK_BUTTON5_MASK) + b = mouse_button::button5; + return b; +} + + +key_modifier::state gtkKeyState(guint state) +{ + key_modifier::state k = key_modifier::none; + if (state & GDK_CONTROL_MASK) + k |= key_modifier::ctrl; + if (state & GDK_SHIFT_MASK) + k |= key_modifier::shift; + if (state & GDK_MOD1_MASK) + k |= key_modifier::alt; + return k; +} + + +void inputCommitRelay(GtkIMContext */*imcontext*/, gchar * str, GWorkArea * area) +{ + area->inputCommit(str); +} + + +} + + +GWorkArea::GWorkArea(int width, int height) + : workAreaPixmap_(0), painter_(*this), draw_(0), colorHandler_(*this) +{ + workArea_.set_size_request(width, height); + workArea_.set_double_buffered(false); + workArea_.add_events(Gdk::STRUCTURE_MASK | Gdk::EXPOSURE_MASK | + Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | + Gdk::KEY_PRESS_MASK | Gdk::BUTTON1_MOTION_MASK); + workArea_.signal_expose_event().connect( + SigC::slot(*this, &GWorkArea::onExpose)); + workArea_.signal_configure_event().connect( + SigC::slot(*this, &GWorkArea::onConfigure)); + workArea_.signal_button_press_event().connect( + SigC::slot(*this, &GWorkArea::onButtonPress)); + workArea_.signal_button_release_event().connect( + SigC::slot(*this, &GWorkArea::onButtonRelease)); + workArea_.signal_key_press_event().connect( + SigC::slot(*this, &GWorkArea::onKeyPress)); + workArea_.signal_motion_notify_event().connect( + SigC::slot(*this, &GWorkArea::onMotionNotify)); + workArea_.show(); + vscrollbar_.get_adjustment()->signal_value_changed().connect( + SigC::slot(*this, &GWorkArea::onScroll)); + vscrollbar_.show(); + hbox_.children().push_back(Gtk::Box_Helpers::Element(workArea_)); + hbox_.children().push_back( + Gtk::Box_Helpers::Element(vscrollbar_,Gtk::PACK_SHRINK)); + hbox_.show(); + GView::instance()->getVBox().children().push_back( + Gtk::Box_Helpers::Element(hbox_)); + workArea_.set_flags(workArea_.get_flags() | Gtk::CAN_DEFAULT | + Gtk::CAN_FOCUS); + workArea_.grab_default(); + GView::instance()->setGWorkArea(&workArea_); + imContext_ = GTK_IM_CONTEXT(gtk_im_multicontext_new()); + g_signal_connect(G_OBJECT(imContext_), "commit", + G_CALLBACK(&inputCommitRelay), + this); +} + + +GWorkArea::~GWorkArea() +{ + g_object_unref(imContext_); +} + + +bool GWorkArea::onExpose(GdkEventExpose * event) +{ + workArea_.get_window()->draw_drawable( + workArea_.get_style()->get_black_gc(), + workAreaPixmap_, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + return true; +} + + +bool GWorkArea::onConfigure(GdkEventConfigure * /*event*/) +{ + int x, y, width, height, depth; + workArea_.get_window()->get_geometry(x, y, width, height, depth); + if (draw_) + XftDrawDestroy(draw_); + workAreaPixmap_ = Gdk::Pixmap::create(workArea_.get_window(), + width, height, depth); + Pixmap pixmap = GDK_PIXMAP_XID(workAreaPixmap_->gobj()); + Colormap colormap = GDK_COLORMAP_XCOLORMAP( + workArea_.get_colormap()->gobj()); + Visual * visual = GDK_VISUAL_XVISUAL( + workArea_.get_colormap()->get_visual()->gobj()); + draw_ = XftDrawCreate(getDisplay(), pixmap, + visual, colormap); + if (!workAreaGC_) { + workAreaGC_ = Gdk::GC::create(workArea_.get_window()); + Gdk::Cursor cursor(Gdk::XTERM); + workArea_.get_window()->set_cursor(cursor); + gtk_im_context_set_client_window( + imContext_, workArea_.get_window()->gobj()); + } + workAreaResize(); + return true; +} + + +void GWorkArea::setScrollbarParams(int height, int pos, int line_height) +{ + Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment(); + adjustment->set_lower(0); + int workAreaHeight = workHeight(); + if (!height || height < workAreaHeight) { + adjustment->set_upper(workAreaHeight); + adjustment->set_page_size(workAreaHeight); + adjustment->set_value(0); + adjustment->changed(); + return; + } + adjustment->set_step_increment(line_height); + adjustment->set_page_increment(workAreaHeight - line_height); + adjustment->set_upper(height); + adjustment->set_page_size(workAreaHeight); + adjustment->set_value(pos); + adjustment->changed(); +} + + +void GWorkArea::onScroll() +{ + double val = vscrollbar_.get_adjustment()->get_value(); + scrollDocView(static_cast(val)); +} + + +bool GWorkArea::onButtonPress(GdkEventButton * event) +{ + kb_action ka = LFUN_MOUSE_PRESS; + switch (event->type) { + case GDK_BUTTON_PRESS: + ka = LFUN_MOUSE_PRESS; + break; + case GDK_2BUTTON_PRESS: + ka = LFUN_MOUSE_DOUBLE; + break; + case GDK_3BUTTON_PRESS: + ka = LFUN_MOUSE_TRIPLE; + break; + default: + break; + } + dispatch(FuncRequest(ka, + static_cast(event->x), + static_cast(event->y), + static_cast(event->button))); + workArea_.grab_focus(); + return true; +} + + +bool GWorkArea::onButtonRelease(GdkEventButton * event) +{ + dispatch(FuncRequest(LFUN_MOUSE_RELEASE, + static_cast(event->x), + static_cast(event->y), + static_cast(event->button))); + return true; +} + + +bool GWorkArea::onMotionNotify(GdkEventMotion * event) +{ + static guint32 timeBefore; + Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment(); + double step = adjustment->get_step_increment(); + double value = adjustment->get_value(); + if (event->x < 0) + value -= step; + else if (event->x > workArea_.get_height()) + value += step; + if (value != adjustment->get_value()) { + if (event->time - timeBefore > 200) { + adjustment->set_value(value); + adjustment->value_changed(); + } + timeBefore = event->time; + } + dispatch(FuncRequest(LFUN_MOUSE_MOTION, + static_cast(event->x), + static_cast(event->y), + gtkButtonState(event->state))); + return true; +} + + +void GWorkArea::inputCommit(gchar * str) +{ + inputCache_ = Glib::locale_from_utf8(str); +} + + +bool GWorkArea::onKeyPress(GdkEventKey * event) +{ +#ifdef I18N + inputCache_ = ""; + bool inputGet = gtk_im_context_filter_keypress(imContext_, event); + // cope with ascii + if ((inputGet && inputCache_.size() == 1 && inputCache_[0] < 128) || + !inputGet) { +#endif + GLyXKeySym *glk = new GLyXKeySym(event->keyval); + workAreaKeyPress(LyXKeySymPtr(glk), + gtkKeyState(event->state)); +#ifdef I18N + } else if (!inputCache_.empty()) + workAreaCJK_IMprocess(inputCache_.size(), inputCache_.data()); +#endif + return true; +} + + +void GWorkArea::onClipboardGet(Gtk::SelectionData & /*selection_data*/, + guint /*info*/) +{ + selectionRequested(); +} + + +void GWorkArea::onClipboardClear() +{ +// selectionLost(); +} + + +void GWorkArea::haveSelection(bool toHave) const +{ + if (toHave) { + Glib::RefPtr clipboard = + Gtk::Clipboard::get(GDK_SELECTION_PRIMARY); + std::vector listTargets; + listTargets.push_back(Gtk::TargetEntry("UTF8_STRING")); + clipboard->set(listTargets, + SigC::slot(const_cast(*this), + &GWorkArea::onClipboardGet), + SigC::slot(const_cast(*this), + &GWorkArea::onClipboardClear)); + } +} + + +string const GWorkArea::getClipboard() const +{ + Glib::RefPtr clipboard = + Gtk::Clipboard::get(GDK_SELECTION_PRIMARY); + return Glib::locale_from_utf8(clipboard->wait_for_text()); +} + + +void GWorkArea::putClipboard(string const & str) const +{ + Glib::RefPtr clipboard = + Gtk::Clipboard::get(GDK_SELECTION_PRIMARY); + clipboard->set_text(Glib::locale_to_utf8(str)); +} diff --git a/src/frontends/gtk/GWorkArea.h b/src/frontends/gtk/GWorkArea.h new file mode 100644 index 0000000000..ae7940fc65 --- /dev/null +++ b/src/frontends/gtk/GWorkArea.h @@ -0,0 +1,125 @@ +// -*- C++ -*- +/** + * \file GWorkArea.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef GWORKAREA_H +#define GWORKAREA_H + +#include +#include "frontends/WorkArea.h" +#include "GPainter.h" +#include "LColor.h" +#include +#include + +class ColorCache +{ + typedef std::map Map; + typedef Map::iterator MapIt; + typedef std::map Map2; + typedef Map2::iterator MapIt2; +public: + ~ColorCache() { clear(); } + Gdk::Color * getColor(LColor::color clr) + { + MapIt it = cache_.find(clr); + return it == cache_.end() ? 0 : it->second; + } + XftColor * getXftColor(LColor::color clr) + { + MapIt2 it = cache2_.find(clr); + return it == cache2_.end() ? 0 : it->second; + } + void cacheColor(LColor::color clr, Gdk::Color * gclr) + { + cache_[clr] = gclr; + } + void cacheXftColor(LColor::color clr, XftColor * xclr) + { + cache2_[clr] = xclr; + } + void clear(); +private: + Map cache_; + Map2 cache2_; +}; + +extern ColorCache colorCache; + +class ColorHandler +{ +public: + ColorHandler(GWorkArea& owner) : owner_(owner) {} + XftColor * getXftColor(LColor::color clr); + Gdk::Color * getGdkColor(LColor::color clr); +private: + GWorkArea & owner_; +}; + +class GWorkArea : public WorkArea, public SigC::Object +{ +public: + GWorkArea(int width, int height); + ~GWorkArea(); + + virtual Painter & getPainter() { return painter_; } + /// + virtual int workWidth() const { return workArea_.get_width(); } + /// + virtual int workHeight() const { return workArea_.get_height(); } + /// return x position of window + int xpos() const { return 0; } + /// return y position of window + int ypos() const { return 0; } + /// + Glib::RefPtr getWindow() { return workArea_.get_window(); } + Display * getDisplay() const + { return GDK_WINDOW_XDISPLAY( + const_cast(workArea_.get_window()->gobj())); } + Glib::RefPtr getPixmap() { return workAreaPixmap_; } + Glib::RefPtr getGC() { return workAreaGC_; } + Glib::RefPtr getColormap() + { return workArea_.get_colormap(); } + XftDraw * getXftDraw() { return draw_; } + ColorHandler & getColorHandler() { return colorHandler_; } + + virtual void setScrollbarParams(int height, int pos, int line_height); + /// a selection exists + virtual void haveSelection(bool) const; + /// + virtual string const getClipboard() const; + /// + virtual void putClipboard(string const &) const; + void inputCommit(gchar * str); +private: + bool onExpose(GdkEventExpose * event); + bool onConfigure(GdkEventConfigure * event); + void onScroll(); + bool onButtonPress(GdkEventButton * event); + bool onButtonRelease(GdkEventButton * event); + bool onMotionNotify(GdkEventMotion * event); + bool onKeyPress(GdkEventKey * event); + void onClipboardGet(Gtk::SelectionData& selection_data, guint info); + void onClipboardClear(); + Gtk::HBox hbox_; + Gtk::DrawingArea workArea_; + Gtk::VScrollbar vscrollbar_; + /// The pixmap overlay on the workarea + Glib::RefPtr workAreaPixmap_; + Glib::RefPtr workAreaGC_; + /// the xforms-specific painter + GPainter painter_; + XftDraw * draw_; + ColorHandler colorHandler_; + GtkIMContext * imContext_; + string inputCache_; +}; + +#endif diff --git a/src/frontends/gtk/GtkmmX.h b/src/frontends/gtk/GtkmmX.h new file mode 100644 index 0000000000..b236d7b2ec --- /dev/null +++ b/src/frontends/gtk/GtkmmX.h @@ -0,0 +1,64 @@ +// -*- C++ -*- +/** + * \file GtkmmX.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef GTKMMX_H +#define GTKMMX_H + +#include +#include +#include + + +inline Display * getDisplay() +{ + return gdk_x11_get_default_xdisplay(); +} + + +inline int getScreen() +{ + return gdk_x11_get_default_screen(); +} + + +inline Window getRootWindow() +{ + static Window rootWin = + GDK_WINDOW_XID(Gdk::Display::get_default()-> + get_default_screen()-> + get_root_window()->gobj()); + return rootWin; +} + + +inline int getDepth() +{ + static int depth; + if (!depth) { + int width, height, x, y; + Gdk::Display::get_default()->get_default_screen()-> + get_root_window()-> + get_geometry(x, y, width, height, depth); + } + return depth; +} + + +inline Colormap getColormap() +{ + static Colormap colormap = GDK_COLORMAP_XCOLORMAP( + Gdk::Display::get_default()->get_default_screen()-> + get_default_colormap()->gobj()); + return colormap; +} + + +#endif diff --git a/src/frontends/gtk/IdSc.C b/src/frontends/gtk/IdSc.C new file mode 100644 index 0000000000..9de4ce0144 --- /dev/null +++ b/src/frontends/gtk/IdSc.C @@ -0,0 +1,35 @@ +/** + * \file IdSc.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include + +#include "IdSc.h" +#include "support/lstrings.h" + +using lyx::support::split; + + +/// Extract shortcut from "|#" string +string const id_sc::shortcut(string const & idsc) +{ + string sc = split(idsc, '|'); + if (!sc.empty() && sc[0] == '#') + sc.erase(sc.begin()); + return sc; +} + + +/// Extract identifier from "|#" string +string const id_sc::id(string const & idsc) +{ + string id; + split(idsc, id, '|'); + return id; +} diff --git a/src/frontends/gtk/IdSc.h b/src/frontends/gtk/IdSc.h new file mode 100644 index 0000000000..c203c87771 --- /dev/null +++ b/src/frontends/gtk/IdSc.h @@ -0,0 +1,28 @@ +// -*- C++ -*- +/** + * \file IdSc.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef ID_SC_H +#define ID_SC_H + +#include "LString.h" + +namespace id_sc +{ + +/// Extract shortcut from "|" string +string const shortcut(string const &); + +/// Extract identifier from "|" string +string const id(string const &); + +} + +#endif diff --git a/src/frontends/gtk/LyXKeySymFactory.C b/src/frontends/gtk/LyXKeySymFactory.C new file mode 100644 index 0000000000..424ccbec5f --- /dev/null +++ b/src/frontends/gtk/LyXKeySymFactory.C @@ -0,0 +1,27 @@ +/** + * \file gtk/LyXKeySymFactory.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include + +#include "frontends/LyXKeySymFactory.h" + +#include "GLyXKeySym.h" + + +namespace LyXKeySymFactory { + + +LyXKeySym * create() +{ + return new GLyXKeySym(); +} + + +} diff --git a/src/frontends/gtk/LyXScreenFactory.C b/src/frontends/gtk/LyXScreenFactory.C new file mode 100644 index 0000000000..c4890f0535 --- /dev/null +++ b/src/frontends/gtk/LyXScreenFactory.C @@ -0,0 +1,29 @@ +/** + * \file gtk/LyXScreenFactory.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include + +#include +#include "frontends/LyXScreenFactory.h" + +#include "GWorkArea.h" +#include "GScreen.h" + + +namespace LyXScreenFactory { + + +LyXScreen * create(WorkArea & owner) +{ + return new GScreen(static_cast(owner)); +} + + +} diff --git a/src/frontends/gtk/Makefile.am b/src/frontends/gtk/Makefile.am new file mode 100644 index 0000000000..69dbc16797 --- /dev/null +++ b/src/frontends/gtk/Makefile.am @@ -0,0 +1,132 @@ +include $(top_srcdir)/config/common.am + +SUBDIRS = glade + +noinst_LTLIBRARIES = libgtk.la + +INCLUDES = -I$(top_srcdir)/images -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/frontends \ + -I$(top_srcdir)/src/frontends/controllers \ + -I$(top_srcdir)/src/frontends/xforms \ + $(BOOST_INCLUDES) @GTK_FRONTEND_CFLAGS@ + +libgtk_la_LIBADD = xforms.lo @GTK_FRONTEND_LIBS@ @XFORMS_LIBS@ + +# Alphabetical order please. It makes it easier to figure out what's missing. +libgtk_la_SOURCES = \ + lyx_gui.C \ + GtkmmX.h \ + xftFontLoader.C \ + xftFontLoader.h \ + codeConvert.h \ + xftFontMetrics.C \ + GScreen.C \ + GScreen.h \ + LyXScreenFactory.C \ + GMenubar.C \ + GMenubar.h \ + GTimeout.C \ + GTimeout.h \ + GToolbar.C \ + GToolbar.h \ + WorkAreaFactory.C \ + GMiniBuffer.C \ + GMiniBuffer.h \ + GPainter.C \ + GPainter.h \ + GWorkArea.h \ + GWorkArea.C \ + GLyXKeySym.h \ + GLyXKeySym.C \ + LyXKeySymFactory.C \ + Alert_pimpl.C \ + GView.h \ + GView.C \ + Dialogs.C \ + GAboutlyx.h \ + GAboutlyx.C \ + GViewBase.h \ + GViewBase.C \ + GBC.h \ + GBC.C \ + FileDialogPrivate.h \ + FileDialogPrivate.C \ + FileDialog.C \ + GText.h \ + GText.C \ + IdSc.h \ + IdSc.C + +# GPrint.h +# GPrint.C + +xforms_objects = \ + ../xforms/bmtable.lo \ + ../xforms/checkedwidgets.lo \ + ../xforms/ColorHandler.lo \ + ../xforms/Color.lo \ + ../xforms/combox.lo \ + ../xforms/Dialogs2.lo \ + ../xforms/fdesign_base.lo \ + ../xforms/FormBase.lo \ + ../xforms/FormBibitem.lo \ + ../xforms/FormBibtex.lo \ + ../xforms/FormBranch.lo \ + ../xforms/FormBrowser.lo \ + ../xforms/FormChanges.lo \ + ../xforms/FormCharacter.lo \ + ../xforms/FormCitation.lo \ + ../xforms/FormColorpicker.lo \ + ../xforms/FormDialogView.lo \ + ../xforms/FormDocument.lo \ + ../xforms/FormErrorList.lo \ + ../xforms/FormERT.lo \ + ../xforms/FormExternal.lo \ + ../xforms/FormFloat.lo \ + ../xforms/FormForks.lo \ + ../xforms/FormGraphics.lo \ + ../xforms/FormInclude.lo \ + ../xforms/FormLog.lo \ + ../xforms/FormMathsBitmap.lo \ + ../xforms/FormMathsDelim.lo \ + ../xforms/FormMathsMatrix.lo \ + ../xforms/FormMathsPanel.lo \ + ../xforms/FormMathsSpace.lo \ + ../xforms/FormMathsStyle.lo \ + ../xforms/FormMinipage.lo \ + ../xforms/FormNote.lo \ + ../xforms/FormParagraph.lo \ + ../xforms/FormPreamble.lo \ + ../xforms/FormPreferences.lo \ + ../xforms/FormPrint.lo \ + ../xforms/FormRef.lo \ + ../xforms/FormSearch.lo \ + ../xforms/FormSendto.lo \ + ../xforms/forms_gettext.lo \ + ../xforms/FormShowFile.lo \ + ../xforms/FormSpellchecker.lo \ + ../xforms/FormTabularCreate.lo \ + ../xforms/FormTabular.lo \ + ../xforms/FormTexinfo.lo \ + ../xforms/FormText.lo \ + ../xforms/FormThesaurus.lo \ + ../xforms/FormToc.lo \ + ../xforms/FormUrl.lo \ + ../xforms/FormVCLog.lo \ + ../xforms/FormWrap.lo \ + ../xforms/freebrowser.lo \ + ../xforms/input_validators.lo \ + ../xforms/RadioButtonGroup.lo \ + ../xforms/Tooltips.lo \ + ../xforms/xformsBC.lo \ + ../xforms/xforms_helpers.lo \ + ../xforms/xformsImage.lo \ + ../xforms/xforms_resize.lo + +# ../xforms/Dialogs.lo +# ../xforms/FormFiledialog.lo +# ../xforms/FileDialog.lo +# ../xforms/FormAboutlyx.lo + +xforms.lo: $(xforms_objects) ../xforms/forms/*.lo + $(CXXLINK) $(xforms_objects) ../xforms/forms/*.lo diff --git a/src/frontends/gtk/WorkAreaFactory.C b/src/frontends/gtk/WorkAreaFactory.C new file mode 100644 index 0000000000..bf6c1b2259 --- /dev/null +++ b/src/frontends/gtk/WorkAreaFactory.C @@ -0,0 +1,28 @@ +/** + * \file gtk/WorkAreaFactory.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "frontends/WorkAreaFactory.h" + +#include "GWorkArea.h" + + +namespace WorkAreaFactory { + + +WorkArea * create(int /*x*/, int /*y*/, int w, int h) +{ + return new GWorkArea(w, h); +} + + +} diff --git a/src/frontends/gtk/codeConvert.h b/src/frontends/gtk/codeConvert.h new file mode 100644 index 0000000000..e9cb573f74 --- /dev/null +++ b/src/frontends/gtk/codeConvert.h @@ -0,0 +1,36 @@ +// -*- C++ -*- +/** + * \file codeConvert.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef CODE_CONVERT_H +#define CODE_CONVERT_H + +#include + + +inline FcChar32 * wcsToFcChar32StrFast(wchar_t * wcs) +{ + return reinterpret_cast(wcs); +} + + +inline FcChar32 const * wcsToFcChar32StrFast(wchar_t const * wcs) +{ + return reinterpret_cast(wcs); +} + + +inline FcChar32 wcToFcChar32(wchar_t wc) +{ + return static_cast(wc); +} + + +#endif diff --git a/src/frontends/gtk/glade/Makefile.am b/src/frontends/gtk/glade/Makefile.am new file mode 100644 index 0000000000..74195b50a1 --- /dev/null +++ b/src/frontends/gtk/glade/Makefile.am @@ -0,0 +1,20 @@ +DISTCLEANFILES = *.orig *.rej *~ *.bak *.gladep +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +GLADE_DIR = glade + +GLADE_FILES = *.glade + +EXTRA_DIST = ${GLADE_FILES} + +gladeinstalldirs: + $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/${GLADE_DIR} ; + +install-data-local: gladeinstalldirs + files=`cd $(srcdir) ; echo $(GLADE_FILES)` ; \ + for i in $${files} ; do \ + $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(pkgdatadir)/${GLADE_DIR}/$$i ; \ + done + +dist-hook: + cd $(distdir) ; rm -rf `find . -name \*CVS\*` ; diff --git a/src/frontends/gtk/glade/aboutlyx.glade b/src/frontends/gtk/glade/aboutlyx.glade new file mode 100644 index 0000000000..c966986efa --- /dev/null +++ b/src/frontends/gtk/glade/aboutlyx.glade @@ -0,0 +1,245 @@ + + + + + + + About LyX + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 300 + 200 + True + False + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + -7 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + True + True + True + GTK_POS_TOP + False + False + + + + 400 + 250 + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + GTK_SHADOW_IN + + + + True + version + False + False + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 0 + + + + + + + False + True + + + + + + True + Version + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + tab + + + + + + 400 + 250 + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + GTK_SHADOW_IN + + + + True + credits + False + False + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 0 + + + + + + + False + True + + + + + + True + Credits + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + tab + + + + + + 400 + 250 + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + GTK_SHADOW_IN + + + + True + license + False + False + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 0 + + + + + + + False + True + + + + + + True + License + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + tab + + + + + 0 + True + True + + + + + + + diff --git a/src/frontends/gtk/glade/print.glade b/src/frontends/gtk/glade/print.glade new file mode 100644 index 0000000000..f8e8efb99c --- /dev/null +++ b/src/frontends/gtk/glade/print.glade @@ -0,0 +1,568 @@ + + + + + + + True + LyX:Print + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + False + False + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + True + True + True + gtk-apply + True + GTK_RELIEF_NORMAL + -10 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + False + 0 + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + 5 + True + 3 + 2 + False + 0 + 0 + + + + True + False + 0 + + + + True + True + _Browse... + True + GTK_RELIEF_NORMAL + + + 5 + False + True + + + + + + + + + 1 + 2 + 2 + 3 + 5 + shrink|fill + fill + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 0 + 1 + 5 + 2 + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 1 + 2 + 5 + 2 + + + + + + + True + True + _File: + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + 1 + 1 + 2 + 2 + 2 + fill + + + + + + + True + True + _Printer: + True + GTK_RELIEF_NORMAL + False + False + True + File + + + 0 + 1 + 0 + 1 + 2 + 2 + fill + + + + + + + + + True + Destination + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + label_item + + + + + 0 + True + True + + + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + 5 + True + False + 10 + + + + True + True + A_ll + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + False + 0 + + + + True + True + Fro_m: + True + GTK_RELIEF_NORMAL + False + False + True + All + + + 0 + False + False + + + + + + True + True + True + True + 5 + + True + * + False + 5 + + + 10 + False + False + + + + + + True + To: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + True + True + 5 + + True + * + False + 5 + + + 10 + False + False + + + + + 0 + True + True + + + + + + True + True + _Odd numbered pages + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + _Even numbered pages + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + True + True + _Reverse order + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + + + True + Pages + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + label_item + + + + + 0 + True + True + + + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + 10 + True + True + 5 + + + + True + Number + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + 1 + 0 + True + GTK_UPDATE_ALWAYS + False + False + 1 0 100 1 10 10 + + + 0 + True + True + + + + + + True + True + _Sorted + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + False + False + + + + + + + + True + Copies + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + label_item + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + diff --git a/src/frontends/gtk/glade/text.glade b/src/frontends/gtk/glade/text.glade new file mode 100644 index 0000000000..ecc1661ad8 --- /dev/null +++ b/src/frontends/gtk/glade/text.glade @@ -0,0 +1,194 @@ + + + + + + + True + dialog1 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + GTK_RELIEF_NORMAL + 0 + + + + True + 0.5 + 0.5 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-undo + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + _Restore + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + True + True + True + gtk-apply + True + GTK_RELIEF_NORMAL + -10 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + False + 5 + + + + True + label + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + 0 + True + True + + + + + 0 + True + True + + + + + + + diff --git a/src/frontends/gtk/lyx_gui.C b/src/frontends/gtk/lyx_gui.C new file mode 100644 index 0000000000..680f93d277 --- /dev/null +++ b/src/frontends/gtk/lyx_gui.C @@ -0,0 +1,454 @@ +/** + * \file gtk/lyx_gui.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Lars Gullik Bjnes + * \author John Levon + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include "lyx_gui.h" + +#include "support/lyxlib.h" +#include "support/os.h" +#include "support/filetools.h" +#include "support/path_defines.h" + +#include "debug.h" +#include "gettext.h" + +#include "lyx_main.h" +#include "lyxrc.h" +#include "lyxfont.h" +#include "graphics/LoaderQueue.h" + +// FIXME: move this stuff out again +#include "bufferlist.h" +#include "buffer_funcs.h" +#include "lyxfunc.h" +#include "lyxserver.h" +#include "BufferView.h" + +#include "GView.h" +#include "GtkmmX.h" + +#include "xftFontLoader.h" +#include "GWorkArea.h" + +#include "Lsstream.h" +#include +#include +#include + +//just for xforms +#include "lyx_forms.h" +#include "xformsImage.h" +#include "xforms_helpers.h" + +extern BufferList bufferlist; + +// FIXME: wrong place ! +LyXServer * lyxserver; + +bool lyx_gui::use_gui = true; + +namespace { + +/// quit lyx +bool finished = false; + + +/// estimate DPI from X server +float getDPI() +{ + Screen * scr = ScreenOfDisplay(getDisplay(), getScreen()); + return ((HeightOfScreen(scr) * 25.4 / HeightMMOfScreen(scr)) + + (WidthOfScreen(scr) * 25.4 / WidthMMOfScreen(scr))) / 2; +} + + +/// set default GUI configuration +void setDefaults() +{ + FL_IOPT cntl; + cntl.buttonFontSize = FL_NORMAL_SIZE; + cntl.browserFontSize = FL_NORMAL_SIZE; + cntl.labelFontSize = FL_NORMAL_SIZE; + cntl.choiceFontSize = FL_NORMAL_SIZE; + cntl.inputFontSize = FL_NORMAL_SIZE; + cntl.menuFontSize = FL_NORMAL_SIZE; + cntl.borderWidth = -1; + cntl.vclass = FL_DefaultVisual; + fl_set_defaults(FL_PDVisual + | FL_PDButtonFontSize + | FL_PDBrowserFontSize + | FL_PDLabelFontSize + | FL_PDChoiceFontSize + | FL_PDInputFontSize + | FL_PDMenuFontSize + | FL_PDBorderWidth, &cntl); +} + + +extern "C" { + + +int LyX_XErrHandler(Display * display, XErrorEvent * xeev) { + // We don't abort on BadWindow + if (xeev->error_code == BadWindow) { + lyxerr << "BadWindow received !" << std::endl; + lyxerr << "If you're using xforms 1.0 or greater, " + << " please report this to lyx-devel@lists.lyx.org" + << std::endl; + return 0; + } + + // emergency cleanup + LyX::emergencyCleanup(); + + // Get the reason for the crash. + char etxt[513]; + XGetErrorText(display, xeev->error_code, etxt, 512); + lyxerr << etxt << " id: " << xeev->resourceid << std::endl; + // By doing an abort we get a nice backtrace. (hopefully) + lyx::support::abort(); + return 0; +} + +} + +/// read in geometry specification +char geometry[40]; + +} // namespace anon + + +void parse_init_xforms(int & argc, char * argv[]) +{ + setDefaults(); + + FL_CMD_OPT cmdopt[] = { + {"-geometry", "*.geometry", XrmoptionSepArg, "690x510"} + }; + + FL_resource res[] = { + {"geometry", "geometryClass", FL_STRING, geometry, "", 40} + }; + + const int num_res = sizeof(res)/sizeof(FL_resource); + fl_initialize(&argc, argv, "LyX", cmdopt, num_res); + + // It appears that, in xforms >=0.89.5, fl_initialize() + // calls setlocale() and ruins our LC_NUMERIC setting. + + fl_get_app_resources(res, num_res); + + Display * display = fl_get_display(); + + if (!display) { + lyxerr << "LyX: unable to access X display, exiting" + << std::endl; + lyx::support::os::warn("Unable to access X display, exiting"); + ::exit(1); + } + + fcntl(ConnectionNumber(display), F_SETFD, FD_CLOEXEC); + + XSetErrorHandler(LyX_XErrHandler); + + using namespace lyx::graphics; + + // connect the image loader based on the xforms library + Image::newImage = boost::bind(&xformsImage::newImage); + Image::loadableFormats = boost::bind(&xformsImage::loadableFormats); +} + + +void lyx_gui::parse_init(int & argc, char * argv[]) +{ + new Gtk::Main(argc, argv); + + parse_init_xforms(argc, argv); + + locale_init(); + + // must do this /before/ lyxrc gets read + lyxrc.dpi = getDPI(); +} + + +void parse_lyxrc_xforms() +{ + XformsColor::read(lyx::support::AddName( + lyx::support::user_lyxdir(), "preferences.xform")); + + if (lyxrc.popup_font_encoding.empty()) + lyxrc.popup_font_encoding = lyxrc.font_norm; + // Set the font name for popups and menus + string boldfontname = lyxrc.popup_bold_font + + "-*-*-*-?-*-*-*-*-" + + lyxrc.popup_font_encoding; + // "?" means "scale that font" + string fontname = lyxrc.popup_normal_font + + "-*-*-*-?-*-*-*-*-" + + lyxrc.popup_font_encoding; + + int bold = fl_set_font_name(FL_BOLD_STYLE, boldfontname.c_str()); + int normal = fl_set_font_name(FL_NORMAL_STYLE, fontname.c_str()); + if (bold < 0) + lyxerr << "Could not set menu font to " + << boldfontname << std::endl; + + if (normal < 0) + lyxerr << "Could not set popup font to " + << fontname << std::endl; + + if (bold < 0 && normal < 0) { + lyxerr << "Using 'helvetica' font for menus" << std::endl; + boldfontname = "-*-helvetica-bold-r-*-*-*-?-*-*-*-*-iso8859-1"; + fontname = "-*-helvetica-medium-r-*-*-*-?-*-*-*-*-iso8859-1"; + bold = fl_set_font_name(FL_BOLD_STYLE, boldfontname.c_str()); + normal = fl_set_font_name(FL_NORMAL_STYLE, fontname.c_str()); + + if (bold < 0 && normal < 0) { + lyxerr << "Could not find helvetica font. Using 'fixed'." + << std::endl; + fl_set_font_name(FL_NORMAL_STYLE, "fixed"); + normal = bold = 0; + } + } + if (bold < 0) + fl_set_font_name(FL_BOLD_STYLE, fontname.c_str()); + else if (normal < 0) + fl_set_font_name(FL_NORMAL_STYLE, boldfontname.c_str()); + + fl_setpup_fontstyle(FL_NORMAL_STYLE); + fl_setpup_fontsize(FL_NORMAL_SIZE); + fl_setpup_color(FL_MCOL, FL_BLACK); + fl_set_goodies_font(FL_NORMAL_STYLE, FL_NORMAL_SIZE); + fl_set_tooltip_font(FL_NORMAL_STYLE, FL_NORMAL_SIZE); +} + + +void lyx_gui::parse_lyxrc() +{ + parse_lyxrc_xforms(); +} + + +void start_xforms() +{ + // initial geometry + int xpos = -1; + int ypos = -1; + unsigned int width = 690; + unsigned int height = 510; + + int const geometryBitmask = + XParseGeometry(geometry, + &xpos, &ypos, &width, &height); + + // if width is not set by geometry, check it against monitor width + if (!(geometryBitmask & WidthValue)) { + Screen * scr = ScreenOfDisplay(fl_get_display(), fl_screen); + if (WidthOfScreen(scr) - 8 < int(width)) + width = WidthOfScreen(scr) - 8; + } + + // if height is not set by geometry, check it against monitor height + if (!(geometryBitmask & HeightValue)) { + Screen * scr = ScreenOfDisplay(fl_get_display(), fl_screen); + if (HeightOfScreen(scr) - 24 < int(height)) + height = HeightOfScreen(scr) - 24; + } + + Screen * s = ScreenOfDisplay(fl_get_display(), fl_screen); + + // recalculate xpos if it's not set + if (xpos == -1) + xpos = (WidthOfScreen(s) - width) / 2; + + // recalculate ypos if it's not set + if (ypos == -1) + ypos = (HeightOfScreen(s) - height) / 2; + + lyxerr[Debug::GUI] << "Creating view: " << width << 'x' << height + << '+' << xpos << '+' << ypos << std::endl; + +// XFormsView view(width, height); +// view.show(xpos, ypos, "LyX"); +// view.init(); +} + + +static void events_xforms() +{ + if (fl_check_forms() == FL_EVENT) { + XEvent ev; + fl_XNextEvent(&ev); + lyxerr[Debug::GUI] + << "Received unhandled X11 event" << std::endl + << "Type: " << ev.xany.type + << " Target: 0x" << std::hex << ev.xany.window + << std::dec << std::endl; + } +} + + +void lyx_gui::start(string const & batch, std::vector const & files) +{ + start_xforms(); + // just for debug + XSynchronize(getDisplay(), true); + GView view; + view.show(); + view.init(); + + Buffer * last = 0; + + // FIXME: some code below needs moving + + lyxserver = new LyXServer(&view.getLyXFunc(), lyxrc.lyxpipes); + + std::vector::const_iterator cit = files.begin(); + std::vector::const_iterator end = files.end(); + for (; cit != end; ++cit) { + Buffer * b = bufferlist.newBuffer(*cit); + if (loadLyXFile(b, *cit)) + last = b; + } + + // switch to the last buffer successfully loaded + if (last) { + view.view()->buffer(last); + } + + // handle the batch commands the user asked for + if (!batch.empty()) { + view.getLyXFunc().dispatch(batch); + } + + // enter the event loop + while (!finished) { + while (Gtk::Main::events_pending()) + Gtk::Main::iteration(false); + events_xforms(); + } + + // FIXME: breaks emergencyCleanup + delete lyxserver; +} + + +void lyx_gui::exit() +{ + finished = true; +} + + +FuncStatus lyx_gui::getStatus(FuncRequest const & /*ev*/) +{ + // Nothing interesting to do here + return FuncStatus(); +} + + +string const lyx_gui::hexname(LColor::color col) +{ + Gdk::Color gdkColor; + Gdk::Color * gclr = colorCache.getColor(col); + if (!gclr) { + gclr = &gdkColor; + gclr->parse(lcolor.getX11Name(col)); + } + + std::ostringstream os; + + // Note that X stores the RGB values in the range 0 - 65535 + // whilst we require them in the range 0 - 255. + os << std::setbase(16) << std::setfill('0') + << std::setw(2) << (gclr->get_red() / 256) + << std::setw(2) << (gclr->get_green() / 256) + << std::setw(2) << (gclr->get_blue() / 256); + + return os.str(); +} + + +void lyx_gui::update_color(LColor::color /*col*/) +{ + colorCache.clear(); +} + + +void lyx_gui::update_fonts() +{ + fontLoader.update(); +} + + +bool lyx_gui::font_available(LyXFont const & font) +{ + return fontLoader.available(font); +} + + +namespace { + + +bool readCallback(Glib::IOCondition /*condition*/, LyXComm * comm) +{ + comm->read_ready(); + return true; +} + + +std::map gReadCallbackMap; + +} + + +void lyx_gui::set_read_callback(int fd, LyXComm * comm) +{ + gReadCallbackMap[fd] = Glib::signal_io().connect( + SigC::bind(SigC::slot(readCallback), comm), + fd, + Glib::IO_IN); +} + + +void lyx_gui::remove_read_callback(int fd) +{ + gReadCallbackMap[fd].disconnect(); + gReadCallbackMap.erase(fd); +} + + +string const lyx_gui::roman_font_name() +{ + return "times"; +} + + +string const lyx_gui::sans_font_name() +{ + return "helvetica"; +} + + +string const lyx_gui::typewriter_font_name() +{ + return "courier"; +} + + +void lyx_gui::sync_events() +{ + // FIXME +} diff --git a/src/frontends/gtk/xftFontLoader.C b/src/frontends/gtk/xftFontLoader.C new file mode 100644 index 0000000000..12ddbbd30f --- /dev/null +++ b/src/frontends/gtk/xftFontLoader.C @@ -0,0 +1,213 @@ +/** + * \file xftFontLoader.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include +#include // fabs() + +#include +#include "xftFontLoader.h" +#include "FontInfo.h" +#include "gettext.h" +#include "debug.h" +#include "lyxrc.h" // lyxrc.font_* +#include "BufferView.h" +#include "frontends/LyXView.h" +#include "support/systemcall.h" +#include "support/filetools.h" +#include "GtkmmX.h" +#include +#include "frontends/lyx_gui.h" + +using std::endl; + +// The global fontLoader +xftFontLoader fontLoader; + + +// Initialize font loader +xftFontLoader::xftFontLoader() +{ +} + + +// Destroy font loader +xftFontLoader::~xftFontLoader() +{ + unload(); +} + + +// Update fonts after zoom, dpi, font names, or norm change +// For now, we just ditch all fonts we have. Later, we should +// reuse the ones that are already loaded. +void xftFontLoader::update() +{ + unload(); +} + + +// Unload all fonts +void xftFontLoader::unload() +{ + // Unload all fonts + for (int i1 = 0; i1 < LyXFont::NUM_FAMILIES; ++i1) + for (int i2 = 0; i2 < 2; ++i2) + for (int i3 = 0; i3 < 4; ++i3) + for (int i4 = 0; i4 < 10; ++i4) { + if (fonts_[i1][i2][i3][i4]){ + XftFontClose(getDisplay(), fonts_[i1][i2][i3][i4]); + fonts_[i1][i2][i3][i4] = 0; + } + } +} + + +string xftFontLoader::familyString(LyXFont::FONT_FAMILY family) +{ + string ffamily; + switch (family) { + case LyXFont::ROMAN_FAMILY: + ffamily = lyxrc.roman_font_name; + break; + case LyXFont::SANS_FAMILY: + ffamily = lyxrc.sans_font_name; + break; + case LyXFont::TYPEWRITER_FAMILY: + ffamily = lyxrc.typewriter_font_name; + break; + case LyXFont::CMR_FAMILY: + ffamily = "cmr10"; + break; + case LyXFont::CMSY_FAMILY: + ffamily = "cmsy10"; + break; + case LyXFont::CMM_FAMILY: + ffamily = "cmmi10"; + break; + case LyXFont::CMEX_FAMILY: + ffamily = "cmex10"; + break; + case LyXFont::MSA_FAMILY: + ffamily = "msam10"; + break; + case LyXFont::MSB_FAMILY: + ffamily = "msbm10"; + break; + default: + ffamily = "Sans"; + break; + } + return ffamily; +} + + +// Get font pattern +/* Takes care of finding which font that can match the given request. Tries +different alternatives. */ +XftPattern * xftFontLoader::getFontPattern(LyXFont::FONT_FAMILY family, + LyXFont::FONT_SERIES series, + LyXFont::FONT_SHAPE shape, + LyXFont::FONT_SIZE size) +{ + // Normal font. Let's search for an existing name that matches. + string ffamily; + int fweight; + int fslant; + double fsize = lyxrc.font_sizes[size] * lyxrc.zoom / 100.0; + XftPattern *fpat = XftPatternCreate(); + + ffamily = familyString(family); + switch (series) { + case LyXFont::MEDIUM_SERIES: + fweight = XFT_WEIGHT_MEDIUM; + break; + case LyXFont::BOLD_SERIES: + fweight = XFT_WEIGHT_BOLD; + break; + default: + fweight = XFT_WEIGHT_MEDIUM; + break; + } + + switch (shape) { + case LyXFont::UP_SHAPE: + case LyXFont::SMALLCAPS_SHAPE: + fslant = XFT_SLANT_ROMAN; + break; + case LyXFont::ITALIC_SHAPE: + fslant = XFT_SLANT_ITALIC; + break; + case LyXFont::SLANTED_SHAPE: + fslant = XFT_SLANT_OBLIQUE; + break; + default: + fslant = XFT_SLANT_ROMAN; + break; + } + XftPatternAddString(fpat, XFT_FAMILY, ffamily.c_str()); + XftPatternAddInteger(fpat, XFT_WEIGHT, fweight); + XftPatternAddInteger(fpat, XFT_SLANT, fslant); + XftPatternAddDouble(fpat, XFT_SIZE, fsize); + return fpat; +} + + +/// Do load font +XftFont * xftFontLoader::doLoad(LyXFont::FONT_FAMILY family, + LyXFont::FONT_SERIES series, + LyXFont::FONT_SHAPE shape, + LyXFont::FONT_SIZE size) +{ + XftPattern *fpat = getFontPattern(family, series, shape, size); + XftResult result; + XftPattern *fpat2 = XftFontMatch(getDisplay(), getScreen(), + fpat, &result); + XftFont * font = XftFontOpenPattern(getDisplay(), fpat2); + fonts_[family][series][shape][size] = font; + return font; +} + + +bool xftFontLoader::available(LyXFont const & f) +{ + if (!lyx_gui::use_gui) + return false; + + static std::vector cache_set(LyXFont::NUM_FAMILIES, false); + static std::vector cache(LyXFont::NUM_FAMILIES, false); + + LyXFont::FONT_FAMILY family = f.family(); + if (cache_set[family]) + return cache[family]; + cache_set[family] = true; + + string const ffamily = familyString(family); + if (isSpecial(f)) { + cache_set[family] = true; + XftPattern *fpat = XftPatternCreate(); + XftPatternAddString(fpat, XFT_FAMILY, ffamily.c_str()); + XftResult result; + XftPattern *fpat2 = XftFontMatch(getDisplay(), getScreen(), + fpat, &result); + XftPatternDestroy(fpat); + char * familyM; + XftPatternGetString(fpat2, XFT_FAMILY, 0, &familyM); + if (ffamily == familyM) { + cache[family] = true; + return true; + } + // We don't need to set cache[family] to false, as it + // is initialized to false; + return false; + } + // We don't care about non-symbol fonts + return false; +} diff --git a/src/frontends/gtk/xftFontLoader.h b/src/frontends/gtk/xftFontLoader.h new file mode 100644 index 0000000000..9194ae605a --- /dev/null +++ b/src/frontends/gtk/xftFontLoader.h @@ -0,0 +1,81 @@ +// -*- C++ -*- +/** + * \file xftFontLoader.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#ifndef XFT_FONT_LOADER_H +#define XFT_FONT_LOADER_H + +#include "lyxfont.h" +#include "LString.h" +#include + +class GWorkArea; + + +class xftFontLoader { +public: + /// + xftFontLoader(); + + /// + ~xftFontLoader(); + + /// Update fonts after zoom, dpi, font names, or norm change + void update(); + + bool available(LyXFont const & f); + + /// Load font + XftFont * load(LyXFont::FONT_FAMILY family, + LyXFont::FONT_SERIES series, + LyXFont::FONT_SHAPE shape, + LyXFont::FONT_SIZE size) + { + if (fonts_[family][series][shape][size]) + return fonts_[family][series][shape][size]; + else + return doLoad(family, series, shape, size); + } + bool isSpecial(LyXFont const & f) + { + switch (f.family()) { + case LyXFont::CMR_FAMILY: + case LyXFont::EUFRAK_FAMILY: + return true; + default: + break; + } + return f.isSymbolFont(); + } +private: + /// Array of fonts + XftFont * fonts_[LyXFont::NUM_FAMILIES][2][4][10]; + XftPattern * getFontPattern(LyXFont::FONT_FAMILY family, + LyXFont::FONT_SERIES series, + LyXFont::FONT_SHAPE shape, + LyXFont::FONT_SIZE size); + string familyString(LyXFont::FONT_FAMILY family); + /// Reset font handler + void reset(); + + /// Unload all fonts + void unload(); + + /** Does the actual loading of a font. Updates fontstruct. */ + XftFont * doLoad(LyXFont::FONT_FAMILY family, + LyXFont::FONT_SERIES series, + LyXFont::FONT_SHAPE shape, + LyXFont::FONT_SIZE size); +}; + +/// +extern xftFontLoader fontLoader; + +#endif diff --git a/src/frontends/gtk/xftFontMetrics.C b/src/frontends/gtk/xftFontMetrics.C new file mode 100644 index 0000000000..dd10bd5374 --- /dev/null +++ b/src/frontends/gtk/xftFontMetrics.C @@ -0,0 +1,265 @@ +/** + * \file xfont_metrics.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Huang Ying + * + * Full author contact details are available in file CREDITS + */ + +#include +#include + +#include +#include "GtkmmX.h" +#include "support/lstrings.h" +#include "xftFontLoader.h" +#include "font_metrics.h" +#include "lyxrc.h" +#include "encoding.h" +#include "language.h" +#include "codeConvert.h" + +#include + + +namespace { + + +inline XftFont * getXftFont(LyXFont const & f) +{ + return fontLoader.load(f.family(), f.series(), + f.realShape(), f.size()); +} + + +inline int XGlyphAscent(XGlyphInfo const & info) +{ + return info.y; +} + + +inline int XGlyphDescent(XGlyphInfo const & info) +{ + return info.height - info.y; +} + + +inline int XGlyphLbearing(XGlyphInfo const & info) +{ + return -info.x; +} + + +inline int XGlyphRbearing(XGlyphInfo const & info) +{ + return -info.x + info.width; +} + + +inline int XGlyphLogWidth(XGlyphInfo const & info) +{ + return info.xOff; +} + + +wchar_t C2WC(char ch) +{ + wchar_t wcs[2] = {0, 0}; + char mbs[2] = {0, 0}; + mbs[0] = ch; + mbstowcs(wcs, mbs, 2); + return wcs[0]; +} + + +} // namespace anon + + +namespace font_metrics { + + +int maxAscent(LyXFont const & f) +{ + XftFont * font = getXftFont(f); + return font->ascent; +} + + +int maxDescent(LyXFont const & f) +{ + XftFont * font = getXftFont(f); + return font->descent; +} + + +int ascent(wchar_t c,LyXFont const & f) +{ + XftFont * font = getXftFont(f); + XGlyphInfo glyph; + XftTextExtents32(getDisplay(), font, + wcsToFcChar32StrFast(&c), + 1, + &glyph); + return XGlyphAscent(glyph); +} + + +int ascent(char c, LyXFont const & f) +{ + return ascent(C2WC(c), f); +} + + +int descent(wchar_t c,LyXFont const & f) +{ + XftFont * font = getXftFont(f); + XGlyphInfo glyph; + XftTextExtents32(getDisplay(), font, + wcsToFcChar32StrFast(&c), + 1, + &glyph); + return XGlyphDescent(glyph); +} + + +int descent(char c, LyXFont const & f) +{ + return descent(C2WC(c), f); +} + + +int lbearing(wchar_t c,LyXFont const & f) + { + XftFont * font = getXftFont(f); + XGlyphInfo glyph; + XftTextExtents32(getDisplay(), font, + wcsToFcChar32StrFast(&c), + 1, + &glyph); + return XGlyphLbearing(glyph); + } + + +int rbearing(wchar_t c,LyXFont const & f) +{ + XftFont * font = getXftFont(f); + XGlyphInfo glyph; + XftTextExtents32(getDisplay(), font, + wcsToFcChar32StrFast(&c), + 1, + &glyph); + return XGlyphRbearing(glyph); +} + + +int lbearing(char c, LyXFont const & f) +{ + return lbearing(C2WC(c), f); +} + + +int rbearing(char c, LyXFont const & f) +{ + return rbearing(C2WC(c), f); +} + + +int width(wchar_t const * s, size_t n, LyXFont const & f) +{ + XftFont * font = getXftFont(f); + XGlyphInfo glyph; + if (f.realShape() != LyXFont::SMALLCAPS_SHAPE){ + XftTextExtents32(getDisplay(), font, + wcsToFcChar32StrFast(s), + n, + &glyph); + return XGlyphLogWidth(glyph); + } else { + int result = 0; + LyXFont smallfont(f); + smallfont.decSize().decSize().setShape(LyXFont::UP_SHAPE); + XftFont * fontS = getXftFont(smallfont); + for (size_t i = 0; i < n; ++i) { + wchar_t wc = lyx::support::uppercase(s[i]); + if (wc != s[i]) { + XftTextExtents32(getDisplay(), fontS, + wcsToFcChar32StrFast(&wc), + 1, + &glyph); + result += XGlyphLogWidth(glyph); + } else { + XftTextExtents32(getDisplay(), font, + wcsToFcChar32StrFast(&wc), + 1, + &glyph); + result += XGlyphLogWidth(glyph); + } + } + return result; + } +} + + +int width(wchar_t c,LyXFont const & f) +{ + return width(&c, 1, f); +} + + +int width(char const * s, size_t n,LyXFont const & f) +{ + boost::scoped_array wcs(new wchar_t[n]); + size_t len; + if (fontLoader.isSpecial(f)) { + unsigned char const * us = + reinterpret_cast(s); + len = n; + std::copy(us, us + n, wcs.get()); + } else + len = mbstowcs(wcs.get(), s, n); + return width(wcs.get(), len, f); +} + + +int signedWidth(string const & s, LyXFont const & f) +{ + if (s.empty()) + return 0; + boost::scoped_array wcs(new wchar_t[s.length() + 1]); + int len = mbstowcs(wcs.get(), s.c_str(), s.length()); + if (wcs[0] == '-') + return width(wcs.get() + 1, len - 1, f); + else + return width(wcs.get(), len, f); +} + + +void rectText(string const & str, LyXFont const & font, + int & width, + int & ascent, + int & descent) +{ + static int const d = 2; + width = font_metrics::width(str, font) + d * 2 + 2; + ascent = font_metrics::maxAscent(font) + d; + descent = font_metrics::maxDescent(font) + d; +} + + +void buttonText(string const & str, LyXFont const & font, + int & width, + int & ascent, + int & descent) +{ + static int const d = 3; + + width = font_metrics::width(str, font) + d * 2 + 2; + ascent = font_metrics::maxAscent(font) + d; + descent = font_metrics::maxDescent(font) + d; +} + + +} // namespace font_metrics +