/* AbiSource Application Framework * Copyright (C) 1998 AbiSource, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include <stdlib.h> #include <string.h> #include "ut_string.h" #include "ut_assert.h" #include "ut_debugmsg.h" #include "ut_vector.h" #include "ut_hash.h" // This header defines some functions for Cocoa dialogs, // like centering them, measuring them, etc. #include "xap_CocoaDialogHelper.h" #include "gr_CocoaGraphics.h" #include "xap_App.h" #include "xap_CocoaApp.h" #include "xap_CocoaFrame.h" #include "xap_CocoaFont.h" #include "xap_CocoaFontManager.h" #include "xap_Dialog_Id.h" #include "xap_Dlg_Insert_Symbol.h" #include "xap_CocoaDlg_Insert_Symbol.h" /*****************************************************************/ #define WIDGET_ID_TAG_KEY "id" /*****************************************************************/ static UT_uint32 xap_CocoaDlg_Insert_Symbol_first = 0; static UT_UCSChar m_CurrentSymbol; static UT_UCSChar m_PreviousSymbol; XAP_Dialog * XAP_CocoaDialog_Insert_Symbol::static_constructor(XAP_DialogFactory * pFactory, XAP_Dialog_Id id) { XAP_CocoaDialog_Insert_Symbol * p = new XAP_CocoaDialog_Insert_Symbol(pFactory,id); return p; } XAP_CocoaDialog_Insert_Symbol::XAP_CocoaDialog_Insert_Symbol(XAP_DialogFactory * pDlgFactory, XAP_Dialog_Id id) : XAP_Dialog_Insert_Symbol(pDlgFactory,id) { m_windowMain = NULL; m_unixGraphics = NULL; m_unixarea = NULL; m_buttonOK = NULL; m_buttonCancel = NULL; m_SymbolMap = NULL; m_areaCurrentSym = NULL; m_InsertS_Font_list = NULL; } XAP_CocoaDialog_Insert_Symbol::~XAP_CocoaDialog_Insert_Symbol(void) { DELETEP(m_unixGraphics); DELETEP(m_unixarea); } /*****************************************************************/ static gboolean s_ok_clicked(GtkWidget * widget, XAP_CocoaDialog_Insert_Symbol * dlg) { UT_ASSERT(widget && dlg); dlg->event_OK(); return FALSE; } static gboolean s_cancel_clicked(GtkWidget * widget, XAP_CocoaDialog_Insert_Symbol * dlg) { UT_ASSERT(widget && dlg); dlg->event_Cancel(); return FALSE; } static void s_sym_SymbolMap_exposed(GtkWidget * widget, GdkEvent * e, XAP_CocoaDialog_Insert_Symbol * dlg) { UT_ASSERT( dlg); dlg->SymbolMap_exposed(); } static void s_Symbolarea_exposed(GtkWidget * widget, GdkEvent * e, XAP_CocoaDialog_Insert_Symbol * dlg) { UT_ASSERT( dlg); dlg->Symbolarea_exposed(); } static gboolean s_SymbolMap_clicked(GtkWidget * widget, GdkEvent * e, XAP_CocoaDialog_Insert_Symbol * dlg) { UT_ASSERT(widget && dlg); dlg->SymbolMap_clicked( e ); return FALSE; } static gboolean s_CurrentSymbol_clicked(GtkWidget * widget, GdkEvent * e, XAP_CocoaDialog_Insert_Symbol * dlg) { UT_ASSERT(widget && dlg); dlg->CurrentSymbol_clicked( e ); return FALSE; } static void s_new_font(GtkWidget * widget, XAP_CocoaDialog_Insert_Symbol * dlg) { UT_ASSERT(widget && dlg); dlg->New_Font(); } static gboolean s_keypressed(GtkWidget * widget, GdkEventKey * e, XAP_CocoaDialog_Insert_Symbol * dlg) { dlg->Key_Pressed( e ); return TRUE; } static void s_delete_clicked(GtkWidget * /* widget */, gpointer /* data */, XAP_CocoaDialog_Insert_Symbol * dlg) { UT_ASSERT(dlg); dlg->event_WindowDelete(); } #if 0 // TODO: there must be a better way of doing this // TODO: it just seems so wasteful to have a callback // TODO: registered for every time the mouse moves over a widget static void s_motion_event(GtkWidget * /* widget */, GdkEventMotion *evt, XAP_CocoaDialog_Insert_Symbol *dlg) { UT_DEBUGMSG(("DOM: motion event\n")); dlg->Motion_event(evt); } void XAP_CocoaDialog_Insert_Symbol::Motion_event(GdkEventMotion *e) { UT_uint32 x, y; XAP_Draw_Symbol * iDrawSymbol = _getCurrentSymbolMap(); UT_ASSERT(iDrawSymbol); x = (UT_uint32) e->x; y = (UT_uint32) e->y; UT_UCSChar cSymbol = iDrawSymbol->calcSymbol(x, y); // only draw if different if(m_CurrentSymbol != cSymbol) { m_PreviousSymbol = m_CurrentSymbol; m_CurrentSymbol = cSymbol; iDrawSymbol->drawarea(m_CurrentSymbol, m_PreviousSymbol); } } #endif /*****************************************************************/ void XAP_CocoaDialog_Insert_Symbol::runModal(XAP_Frame * pFrame) { } void XAP_CocoaDialog_Insert_Symbol::activate(void) { UT_ASSERT(m_windowMain); ConstructWindowName(); gtk_window_set_title (GTK_WINDOW (m_windowMain), m_WindowName); gdk_window_raise(m_windowMain->window); } void XAP_CocoaDialog_Insert_Symbol::notifyActiveFrame(XAP_Frame *pFrame) { UT_ASSERT(m_windowMain); ConstructWindowName(); gtk_window_set_title (GTK_WINDOW (m_windowMain), m_WindowName); } void XAP_CocoaDialog_Insert_Symbol::runModeless(XAP_Frame * pFrame) { // First see if the dialog is already running UT_sint32 sid =(UT_sint32) getDialogId(); // Build the window's widgets and arrange them GtkWidget * mainWindow = _constructWindow(); UT_ASSERT(mainWindow); // Save dialog the ID number and pointer to the Dialog m_pApp->rememberModelessId( sid, (XAP_Dialog_Modeless *) m_pDialog); // This magic command displays the frame that characters will be // inserted into. connectFocusModeless(GTK_WIDGET(mainWindow),m_pApp); // To center the dialog, we need the frame of its parent. XAP_CocoaFrame * pCocoaFrame = static_cast<XAP_CocoaFrame *>(pFrame); UT_ASSERT(pCocoaFrame); // Get the GtkWindow of the parent frame GtkWidget * parentWindow = pCocoaFrame->getTopLevelWindow(); UT_ASSERT(parentWindow); // Center our new dialog in its parent. // centerDialog(parentWindow, mainWindow); gtk_widget_show (mainWindow); // *** this is how we add the gc for symbol table *** // attach a new graphics context to the drawing area XAP_CocoaApp * unixapp = static_cast<XAP_CocoaApp *> (m_pApp); UT_ASSERT(unixapp); UT_ASSERT(m_SymbolMap && m_SymbolMap->window); // make a new Cocoa GC DELETEP (m_unixGraphics); m_unixGraphics = new GR_CocoaGraphics(m_SymbolMap->window, unixapp->getFontManager(), m_pApp); // let the widget materialize _createSymbolFromGC(m_unixGraphics, (UT_uint32) m_SymbolMap->allocation.width, (UT_uint32) m_SymbolMap->allocation.height); // *** Re use the code to draw into the selected symbol area. UT_ASSERT(m_areaCurrentSym && m_areaCurrentSym->window); // make a new Cocoa GC DELETEP (m_unixarea); m_unixarea = new GR_CocoaGraphics(m_areaCurrentSym->window, unixapp->getFontManager(), m_pApp); // let the widget materialize _createSymbolareaFromGC(m_unixarea, (UT_uint32) m_areaCurrentSym->allocation.width, (UT_uint32) m_areaCurrentSym->allocation.height); XAP_Draw_Symbol * iDrawSymbol = _getCurrentSymbolMap(); UT_ASSERT(iDrawSymbol); // We use this code to insert the default font name into to static // variable "m_Insert_Symbol_font" the first time this dialog is // called. Afterwards it is just whatever was left from the last // call. if ( xap_CocoaDlg_Insert_Symbol_first == 0) { iDrawSymbol->setSelectedFont( (char *) DEFAULT_UNIX_SYMBOL_FONT); m_CurrentSymbol = ' '; m_PreviousSymbol = ' '; xap_CocoaDlg_Insert_Symbol_first = 1; } // Show the top level dialog gtk_widget_show(mainWindow); // Put the current font in the entry box char* iSelectedFont = iDrawSymbol->getSelectedFont(); gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(m_fontcombo)->entry), (gchar *) iSelectedFont); // Show the Previously selected symbol m_PreviousSymbol = m_CurrentSymbol; iDrawSymbol->drawarea(m_CurrentSymbol, m_PreviousSymbol); // return to ap_Editmethods and wait for something interesting // to happen. } void XAP_CocoaDialog_Insert_Symbol::event_OK(void) { m_Inserted_Symbol = m_CurrentSymbol; _onInsertButton(); } void XAP_CocoaDialog_Insert_Symbol::event_Cancel(void) { if(m_Insert_Symbol_no_fonts > 0 ) { m_answer = XAP_Dialog_Insert_Symbol::a_CANCEL; g_list_free( m_InsertS_Font_list); for(UT_uint32 i = 0; i < m_Insert_Symbol_no_fonts; i++) { if(m_fontlist[i] != NULL) g_free (m_fontlist[i]); } m_Insert_Symbol_no_fonts = 0; modeless_cleanup(); if(m_windowMain && GTK_IS_WIDGET(m_windowMain)) gtk_widget_destroy(m_windowMain); m_windowMain= NULL; } } void XAP_CocoaDialog_Insert_Symbol::SymbolMap_exposed(void ) { XAP_Draw_Symbol * iDrawSymbol = _getCurrentSymbolMap(); UT_ASSERT(iDrawSymbol); iDrawSymbol->draw(); /* Need this to see the blue square after an expose event */ iDrawSymbol->drawarea(m_CurrentSymbol, m_PreviousSymbol); } void XAP_CocoaDialog_Insert_Symbol::Symbolarea_exposed(void ) { XAP_Draw_Symbol * iDrawSymbol = _getCurrentSymbolMap(); UT_ASSERT(iDrawSymbol); iDrawSymbol->drawarea(m_CurrentSymbol, m_PreviousSymbol); } // // This function allows the symbol to be selected via the keyboard // void XAP_CocoaDialog_Insert_Symbol::Key_Pressed(GdkEventKey * e) { int move = 0; switch (e->keyval) { case GDK_Up: move = -32; break; case GDK_Down: move = 32; break; case GDK_Left: move = -1; break; case GDK_Right: move = 1; break; case GDK_Return: gtk_signal_emit_stop_by_name((GTK_OBJECT(m_windowMain)), "key_press_event"); event_OK(); break; } if (move != 0) { if ((m_CurrentSymbol + move) >= 32 && (m_CurrentSymbol + move) <= 255) { XAP_Draw_Symbol * iDrawSymbol = _getCurrentSymbolMap(); UT_ASSERT(iDrawSymbol); m_PreviousSymbol = m_CurrentSymbol; m_CurrentSymbol = m_CurrentSymbol + move; iDrawSymbol->drawarea(m_CurrentSymbol, m_PreviousSymbol); } gtk_signal_emit_stop_by_name((GTK_OBJECT(m_windowMain)), "key_press_event"); } } void XAP_CocoaDialog_Insert_Symbol::SymbolMap_clicked( GdkEvent * event) { UT_uint32 x, y; x = (UT_uint32) event->button.x; y = (UT_uint32) event->button.y; XAP_Draw_Symbol * iDrawSymbol = _getCurrentSymbolMap(); UT_ASSERT(iDrawSymbol); m_PreviousSymbol = m_CurrentSymbol; m_CurrentSymbol = iDrawSymbol->calcSymbol(x, y); iDrawSymbol->drawarea(m_CurrentSymbol, m_PreviousSymbol); // double click should also insert the symbol if(event->type == GDK_2BUTTON_PRESS) event_OK(); } void XAP_CocoaDialog_Insert_Symbol::New_Font(void ) { XAP_Draw_Symbol * iDrawSymbol = _getCurrentSymbolMap(); UT_ASSERT(iDrawSymbol); /* Extract the new font string from the combo box, update the current symbol font and display the new set of symbols to choose from. The text extraction code was stolen from ev_GnomeCocoaToolbar. */ gchar * buffer = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(m_fontcombo)->entry)); iDrawSymbol->setSelectedFont( (char *) buffer); iDrawSymbol->draw(); iDrawSymbol->drawarea(m_CurrentSymbol, m_PreviousSymbol); } void XAP_CocoaDialog_Insert_Symbol::destroy(void) { g_list_free( m_InsertS_Font_list); for(UT_uint32 i = 0; i < m_Insert_Symbol_no_fonts; i++) g_free(m_fontlist[i]); modeless_cleanup(); // Just nuke this dialog gtk_widget_destroy(m_windowMain); m_windowMain = NULL; } void XAP_CocoaDialog_Insert_Symbol::event_WindowDelete(void) { m_answer = XAP_Dialog_Insert_Symbol::a_CANCEL; g_list_free( m_InsertS_Font_list); for(UT_uint32 i = 0; i < m_Insert_Symbol_no_fonts; i++) g_free(m_fontlist[i]); modeless_cleanup(); gtk_widget_destroy(m_windowMain); m_windowMain = NULL; } /*****************************************************************/ GtkWidget * XAP_CocoaDialog_Insert_Symbol::_constructWindow(void) { GtkWidget * vboxInsertS; GtkWidget * vhbox; GtkWidget * hboxInsertS; const XAP_StringSet * pSS = m_pApp->getStringSet(); XML_Char * tmp = NULL; m_windowMain = gtk_window_new (GTK_WINDOW_DIALOG); ConstructWindowName(); gtk_window_set_title (GTK_WINDOW (m_windowMain), m_WindowName); // gtk_widget_set_usize(m_windowMain, 610, 245); gtk_window_set_policy (GTK_WINDOW (m_windowMain), FALSE, FALSE, FALSE); gtk_container_set_border_width (GTK_CONTAINER (m_windowMain), 4); // Now put in a Vbox to hold our 3 widgets (Font Selector, Symbol Table // and OK -Selected Symbol- Cancel vboxInsertS = gtk_vbox_new (FALSE, 4); // gtk_box_set_spacing (GTK_BOX (vboxInsertS), 4); gtk_widget_show(vboxInsertS); // Insert the vbox into the dialog window gtk_container_add(GTK_CONTAINER(m_windowMain), vboxInsertS); vhbox = gtk_hbox_new(FALSE, 1); // Insert the vhbox into the vbox to hold the combo box gtk_widget_show(vhbox); gtk_box_pack_start(GTK_BOX(vboxInsertS), vhbox, TRUE, TRUE, 0); // Finally construct the combo box m_fontcombo = _createComboboxWithFonts (); gtk_object_set_data (GTK_OBJECT(m_windowMain), "fontcombo", m_fontcombo); // Now put the font combo box at the top of the dialog gtk_box_pack_start(GTK_BOX(vhbox), m_fontcombo, TRUE, FALSE, 0); // Now the Symbol Map. // TODO: 32 * x (19) = 608, 7 * y (21) = 147 FIXME! m_SymbolMap = _previewNew (608, 147); gtk_object_set_data (GTK_OBJECT (m_windowMain), "SymbolMap", m_SymbolMap); gtk_box_pack_start(GTK_BOX(vboxInsertS), m_SymbolMap, FALSE, FALSE, 0); // Now make a Hbox to hold OK, Current Selection and Cancel hboxInsertS = gtk_hbox_new (FALSE, 1); // Insert the hbox into the dialog window gtk_object_set_data (GTK_OBJECT (m_windowMain), "hboxInsertS", hboxInsertS); gtk_widget_show (hboxInsertS); gtk_box_pack_start (GTK_BOX (vboxInsertS), hboxInsertS, TRUE, TRUE, 0); UT_XML_cloneNoAmpersands(tmp, pSS->getValue(XAP_STRING_ID_DLG_Insert)); m_buttonOK = gtk_button_new_with_label (tmp); FREEP(tmp); gtk_object_set_data (GTK_OBJECT (m_windowMain), "buttonOK", m_buttonOK); gtk_widget_show (m_buttonOK); gtk_box_pack_start(GTK_BOX(hboxInsertS), m_buttonOK, TRUE, FALSE, 4); GTK_WIDGET_SET_FLAGS (m_buttonOK, GTK_CAN_DEFAULT); m_areaCurrentSym = _previewNew (60, 45); gtk_object_set_data (GTK_OBJECT (m_windowMain), "areaCurrentSym", m_areaCurrentSym); gtk_box_pack_start(GTK_BOX(hboxInsertS), m_areaCurrentSym, TRUE, FALSE, 0); UT_XML_cloneNoAmpersands(tmp, pSS->getValue(XAP_STRING_ID_DLG_Close)); m_buttonCancel = gtk_button_new_with_label (tmp); FREEP(tmp); gtk_object_set_data (GTK_OBJECT (m_windowMain), "buttonCancel", m_buttonCancel); gtk_widget_show (m_buttonCancel); gtk_box_pack_start(GTK_BOX(hboxInsertS), m_buttonCancel, TRUE, FALSE, 4); GTK_WIDGET_SET_FLAGS (m_buttonCancel, GTK_CAN_DEFAULT); gtk_widget_show (hboxInsertS); _connectSignals (); gtk_widget_grab_focus (m_buttonOK); gtk_widget_grab_default (m_buttonOK); return m_windowMain; } GtkWidget *XAP_CocoaDialog_Insert_Symbol::_previewNew (int w, int h) { GtkWidget *pre = createDrawingArea (); gtk_widget_show (pre); gtk_widget_set_usize (pre, w, h); // Enable button press events gtk_widget_add_events(pre, GDK_BUTTON_PRESS_MASK); return pre; } /* This code is to suck all the available fonts and put them in a GList. This can then be displayed on a combo box at the top of the dialog. Code stolen from ap_CocoaToolbar_FontCombo */ /* Now we remove all the duplicate name entries and create the Glist glFonts. This will be used in the font selection combo box */ GList *XAP_CocoaDialog_Insert_Symbol::_getGlistFonts (void) { XAP_CocoaApp * unixapp = static_cast<XAP_CocoaApp *> (m_pApp); UT_Vector * list = unixapp->getFontManager()->getAllFonts(); UT_uint32 count = list->size(); GList *glFonts = NULL; gchar currentfont[50] = "\0"; UT_uint32 j = 0; for (UT_uint32 i = 0; i < count; i++) { XAP_CocoaFont * pFont = (XAP_CocoaFont *)list->getNthItem(i); gchar * lgn = (gchar *) pFont->getName(); if((strstr(currentfont,lgn)==NULL) || (strlen(currentfont)!=strlen(lgn)) ) { strncpy(currentfont, lgn, 50); m_fontlist[j] = g_strdup(currentfont); glFonts = g_list_prepend(glFonts, m_fontlist[j++]); } } m_Insert_Symbol_no_fonts = j; DELETEP(list); return g_list_reverse(glFonts); } void XAP_CocoaDialog_Insert_Symbol::CurrentSymbol_clicked(GdkEvent *event) { // have single-click insert the symbol if(event->type == GDK_BUTTON_PRESS) event_OK(); } GtkWidget *XAP_CocoaDialog_Insert_Symbol::_createComboboxWithFonts (void) { GtkWidget *fontcombo = gtk_combo_new(); m_InsertS_Font_list = _getGlistFonts (); gtk_widget_set_usize(fontcombo, 200, 25); gtk_widget_show(fontcombo); gtk_combo_set_value_in_list(GTK_COMBO(fontcombo), TRUE, TRUE); gtk_combo_set_use_arrows(GTK_COMBO(fontcombo), FALSE); gtk_combo_set_popdown_strings(GTK_COMBO(fontcombo), m_InsertS_Font_list); // Put the current font in the entry box. gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(fontcombo)->entry), (gchar *) DEFAULT_UNIX_SYMBOL_FONT); // Turn off keyboard entry in the font selection box gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(fontcombo)->entry),FALSE); return fontcombo; } void XAP_CocoaDialog_Insert_Symbol::_connectSignals (void) { // Now connect the signals gtk_signal_connect(GTK_OBJECT(m_buttonOK), "clicked", GTK_SIGNAL_FUNC(s_ok_clicked), (gpointer) this); gtk_signal_connect(GTK_OBJECT(m_buttonCancel), "clicked", GTK_SIGNAL_FUNC(s_cancel_clicked), (gpointer) this); // The event to choose the Symbol! gtk_signal_connect(GTK_OBJECT(m_SymbolMap), "button_press_event", GTK_SIGNAL_FUNC(s_SymbolMap_clicked), (gpointer) this); #if 0 // Motion over the dialog gtk_signal_connect(GTK_OBJECT(m_SymbolMap), "motion_notify_event", GTK_SIGNAL_FUNC(s_motion_event), (gpointer) this); #endif // The event to choose the Symbol! gtk_signal_connect(GTK_OBJECT(m_areaCurrentSym), "button_press_event", GTK_SIGNAL_FUNC(s_CurrentSymbol_clicked), (gpointer) this); // Look for keys pressed gtk_signal_connect(GTK_OBJECT(m_windowMain), "key_press_event", GTK_SIGNAL_FUNC(s_keypressed), (gpointer) this); // Look for "changed" signal on the entry part of the combo box. // Code stolen from ev_CocoaGnomeToolbar.cpp GtkEntry * blah = GTK_ENTRY(GTK_COMBO(m_fontcombo)->entry); GtkEditable * yuck = GTK_EDITABLE(blah); gtk_signal_connect(GTK_OBJECT(&yuck->widget), "changed", GTK_SIGNAL_FUNC(s_new_font), (gpointer) this); // the catch-alls // Dont use gtk_signal_connect_after for modeless dialogs gtk_signal_connect(GTK_OBJECT(m_windowMain), "delete_event", GTK_SIGNAL_FUNC(s_delete_clicked), (gpointer) this); gtk_signal_connect_after(GTK_OBJECT(m_windowMain), "destroy",NULL, NULL); // the expose event of the m_SymbolMap gtk_signal_connect(GTK_OBJECT(m_SymbolMap), "expose_event", GTK_SIGNAL_FUNC(s_sym_SymbolMap_exposed), (gpointer) this); gtk_signal_connect(GTK_OBJECT(m_areaCurrentSym), "expose_event", GTK_SIGNAL_FUNC(s_Symbolarea_exposed), (gpointer) this); }