diff options
author | Arturo Espinosa <unammx@src.gnome.org> | 2000-01-06 13:48:27 +0800 |
---|---|---|
committer | Arturo Espinosa <unammx@src.gnome.org> | 2000-01-06 13:48:27 +0800 |
commit | ed4e8afecd5a7f9fab04715ca26a67b2917d78f3 (patch) | |
tree | fb33e24ef2eb7c01b225e094d69228c395b1afb4 /widgets | |
parent | 36e5e42d31a56499b1b2534fdf9f6a720b3813e0 (diff) | |
download | gsoc2013-evolution-ed4e8afecd5a7f9fab04715ca26a67b2917d78f3.tar.gz gsoc2013-evolution-ed4e8afecd5a7f9fab04715ca26a67b2917d78f3.tar.zst gsoc2013-evolution-ed4e8afecd5a7f9fab04715ca26a67b2917d78f3.zip |
Lots of reorganization to get the Evolution shell to begin its life. It
Lots of reorganization to get the Evolution shell to begin its life.
It also includes a new evolution widget from Damon.
Miguel.
svn path=/trunk/; revision=1536
Diffstat (limited to 'widgets')
91 files changed, 8007 insertions, 7866 deletions
diff --git a/widgets/ChangeLog b/widgets/ChangeLog deleted file mode 100644 index 47e410e613..0000000000 --- a/widgets/ChangeLog +++ /dev/null @@ -1,579 +0,0 @@ -1999-12-30 Miguel de Icaza <miguel@gnu.org> - - * e-table-item.c (eti_attach_cell_views): New routine, creates the - cell views. - (eti_detach_cell_views): Detaches the cell_views from the - ETableItem. - (eti_realize_cell_views, eti_unrealize_cell_views): Simplified to - just do realize/unrealize notification. - (eti_add_table_model): Only attach the cells when we have both the - table model and the header model. - - * e-cell.h (ECellClass): Added two new methods: new_view and - kill_view which drive the view process (instead of putting that on - realize/unrealize). - - * e-cell.c: Adapt the code to use the new scheme for view - instantiation. - - * e-cell-text.c, e-cell-toggle.c: Adapted to the new class - changes. - -1999-12-22 Miguel de Icaza <miguel@helixcode.com> - - * e-table-item.c (e_table_item_focus): grab focus here with the - canvas method. - -1999-12-20 Miguel de Icaza <miguel@helixcode.com> - - * e-table-group.c (etg_update): Change the dimensions only if the - child changes its own. - - * e-table-item.c (eti_table_model_changed): Emit new signal on - table height change. - (eti_class_init): Register new "height_change" signal. - -1999-12-19 Damon Chaplin <damon@karuna.freeserve.co.uk> - - * Makefile.am (SUBDIRS): created SUBDIRS with meeting-time-sel. - - * meeting-time-sel/Makefile.am: - * meeting-time-sel/.cvsignore: - * meeting-time-sel/e-meeting-time-sel.h: - * meeting-time-sel/e-meeting-time-sel.c: - * meeting-time-sel/e-meeting-time-sel-item.h: - * meeting-time-sel/e-meeting-time-sel-item.c: - * meeting-time-sel/e-meeting-time-sel-list-item.h: - * meeting-time-sel/e-meeting-time-sel-list-item.c: - * meeting-time-sel/e-meeting-time-sel-mail.xpm: - * meeting-time-sel/e-meeting-time-sel-no-mail.xpm: - * meeting-time-sel/test-meeting-time-sel.c: new files implementing - the meeting time selector. - -1999-12-12 Miguel de Icaza <miguel@helixcode.com> - - * e-table-item.c (eti_class_init): X and Y arguments are now - doubles (to make it consistent with the rest of the canvas x, y - arguments). - - * e-table.c (e_table_create_leaf): Use new argument values here - - * test-*.c: Update to new argument types for x and y - - * e-table-group.c: New implementation as a canvas item used to - group childs. - - * e-table-item.c (eti_update): Make this play nicely with groups. - (eti_draw): ditto. - (eti_request_region_redraw): ditto. - (eti_item_region_redraw): New function. - - * e-table-subset.c (etss_proxy_model_row_changed): Added model - proxying. - - * e-cell.h: Drop ETableModel from the ECell; - (realize): Now takes an ETableModel - - * e-cell-checkbox.c: Adapted to new class - changes; - * e-cell-toggle.c: ditto - - * e-table-subset.c (etss_row_count): Fix this guy. - -1999-12-11 Miguel de Icaza <miguel@helixcode.com> - - * e-table-item.c (eti_unrealize_cell_views): Null the cell views. - (eti_header_structure_changed): Only unrealize/realize if we were - realized before. - - * e-table-header.c (e_table_header_add_column): Allow -1 as an - insert position - -1999-12-11 Miguel de Icaza <miguel@helixcode.com> - - * e-table.c: Massive fixage. - - * test-table.c: Updates to test the mega widget. - -1999-12-10 Miguel de Icaza <miguel@helixcode.com> - - * e-table.c: New file, implements the mega widget. - -1999-12-09 Miguel de Icaza <miguel@gnu.org> - - * e-table-header.c (e_table_header_col_diff): fix this routine. - -1999-12-04 Miguel de Icaza <miguel@gnu.org> - - * e-table-header-item.c (ethi_event): Started drag and drop - support. - - * e-table-item.c (eti_table_model_changed): The columns are - controled by the Header, not by the TableModel. - - * e-table-header-item.c (ethi_draw): Fixed redraw logic to support - arbitrary header positioning. - - * e-cell.h: Revamped e-cell interface. We now provide the model - column and the view column to all methods (so that the methods can - talk to the view and to the model at the same time). - - * e-table-item.c: Update to new API - * e-cell-test.c: Update to new API - -1999-12-03 Miguel de Icaza <miguel@gnu.org> - - * e-cell.c (e_cell_class_init): Provide emtpy methods for - enter_edit, and leave_edit. - - * e-table-item.c: Killed draw cell. - (eti_draw): Perform column mapping here. - (e_table_item_leave_edit): ditto. - (e_table_item_enter_edit): ditto. - (eti_event): ditto. - -1999-12-02 Miguel de Icaza <miguel@gnu.org> - - * e-table-header.c (e_table_header_index): fixed api. - -1999-12-01 Miguel de Icaza <miguel@gnu.org> - - * test-cols.c (multi_cols_test): Update to simplified API. - * test-check.c (check_test): ditto - * test-table.c (table_browser_test): ditto - - * e-table-simple.c (e_table_simple_class_init): Kill column_name method. - - * e-table-model.h: Kill column_name method. - - * e-table-col.c (e_table_col_new): Instead of using a column name, - use a column index. - - * e-cell-text.c (ect_draw): Keep track of the originally allocated - piece of code. - - * e-table-header-item.c (ethi_unrealize): Removed change cursor - from here. - - * e-cell-text.c (ect_draw): Memory leak fix. - - * table-test.c (main): Enhance the demo to load sample.table - automatically, to get memprof working. - - * e-table-header.c (eth_do_remove): Take an argument: do -remove. - - * e-table-header.c (e_table_header_add_column): Sink ETableCol to - own the object. - - * e-table-col.h: Made ETableCol a GtkObject to make reference - counting the lifecycle method for these objects. - - * e-table-col.c (e_table_col_destroy): New API call. - - * e-table-subset.c (e_table_subset_get_toplevel): New API call. - -1999-11-30 Miguel de Icaza <miguel@gnu.org> - - * e-cell-checkbox.c (e_cell_checkbox_new): This one derives from - e-cell-toggle. - - * check-emtpy.xpm, check-filled.xpm: new files. - - * e-cell-toggle.c (etog_draw): Paint in white. - If we have transparency enabled, do the nice alpha computation. - - * test-table.c, test-cols.c: new files; They implement the split - tests. - -1999-11-29 Miguel de Icaza <miguel@gnu.org> - - * e-table-col.c (e_table_col_new): Set etc->resizeable. - - * e-table-header-item.c (ethi_event): Handle non-resizeables - columns; Add support for minimum width. - - * e-cell-toggle.c, e-cell-toggle.h: New file. Implement a - multi-state image toggle cell object. - - * e-cell-text.c (ect_leave_edit): Handle the case of us calling - leave edit manually. - (ect_stop_editing): Leave manually editing here. - (ect_draw): Add one pixel to the border for left and right; - Handle off-screen cursor (must be improved). - (ect_edit_select_all): New function. - (ect_event): Select all text on editing start - - * e-table-item.c (eti_event): Map mouse events and dispatch them. - (eti_event): Add spreadsheet mode for editing; Enter editing only - with visual characters; - Leave editing mode when a different row has been selected. - (eti_get_height): Fix the computation for this; Fix logic for the - length_threshold. - - (eti_draw): Add borders on all sides of the box; - Only draw focus if the cell is not being edited. - -1999-11-28 Miguel de Icaza <miguel@gnu.org> - - * e-table-item.c (eti_draw): Focus inside, not outside. - (eti_realize): Enhance our focus gc. - - * e-cell-text.c (ect_enter_edit, ect_leave_edit): New methods; - They implement editing. - - * e-cell.h: new methods: enter_edit, leave_edit - - * e-table-model.h (set_value_at): make val argument const. - - * e-table-simple.c (simple_set_value_at): Make value argument const; - - * e-table-item.c (eti_set_arg): Add new mode: draw_focus; - -1999-11-27 Miguel de Icaza <miguel@gnu.org> - - * e-table-item.c (eti_event): beginning of the keyboard navigation. - - * e-table-model.c (e_table_model_row_changed): new function. - (e_table_model_cell_changed): new function. - (e_table_model_class_init): New signals. - - * e-table-item.c (eti_request_region_redraw): x2, y2 offsets were - wrong. - (eti_select): Repaint selected region. - (eti_request_region_redraw): Fix range. - (eti_draw): Correct offset computation here. - (e_table_item_class_init): New method: row_selection, handles the - selection. - - Now it implement GTK_SELECTION_SINGLE and GTK_SELECTION_MULTIPLE. - - Focusing and selection should be correct now. - -1999-11-26 Miguel de Icaza <miguel@gnu.org> - - * e-table-item.c (eti_realize): Compute height using the ecell - methods here. - (eti_get_height): new method to compute dimensions. - - * e-cursors.c: use a different cursor. - - * e-table-model.h: kill height and row_height methods. - - * e-cell.c (ec_height): New method. - - * e-cell-text.c (ect_realize): Load the font from the canvas. - (ect_draw): New color setup. - Center in the row. - (ect_height): Implement new method. - -1999-11-26 Michael Meeks <mmeeks@gnu.org> - - * ROADMAP.e-table: small spelling/typo fixes. - -1999-11-25 Miguel de Icaza <miguel@gnu.org> - - * e-table-item.c (eti_event): Work on mouse-button event - propagation to cells. - - * e-cell-text.c (ect_draw): Use CellViews now. - - * e-table-item.c (eti_realize_cell_views): New routine: Realizes - the cell views - (eti_unrealize_cell_views): New routine: unrealizes the cell views. - - * e-table-item.h: Move cell_views array here. - - * table-test.c (value_at): Fix return value. - (main): use new invocation method. - - * e-table-header-item.c (ethi_realize): Realize cells. - - * e-table-item.c (eti_header_dim_changed): redraw before and after. - - * e-table-header-item.c (ethi_event): Add continuous resizing. - -1999-11-24 Miguel de Icaza <miguel@gnu.org> - - * e-table-subset.h, e-table-subset.c: New files, used to implement - subset tables. - - * e-table-sorted.h, e-table-sorted.c: Now they derive from - e-table-subset. - - * e-cell.c, e-cell.h: realize method now return per view instance - data. - -1999-11-20 Miguel de Icaza <miguel@gnu.org> - - * e-table-item.c (eti_draw): WOOOOHOOOOOoO! It took me quite a - while to figure this one out. Fixed. - - * e-table-header-item.c (ethi_set_arg): Compute width, keep track - of it. - (ethi_add_table_header): Monitor changes to the Header model; - Queue updates. - (ethi_draw): Fix the redraw logic here. - - * table-test.c (main): Change the sample code, so we can better - debug this. - - * e-table-item.c (eti_header_structure_changed): Keep track of - width; - (eti_header_dim_changed): ditto. - (eti_draw): Many redraw fixes. - -1999-11-19 Miguel de Icaza <miguel@gnu.org> - - * e-table-item.c (eti_realize): Hook up; Load gcs. - (eti_unrealize): Hook up. - - * e-table-sorted.c: Finished implementing. - -1999-11-18 Miguel de Icaza <miguel@gnu.org> - - * e-table-model.c (e_table_model_class_init): Add model_changed - signal here. - - * e-table-item.c, e-table-item.h: New files. They implement the - view of the ETableModel as Canvas Items. - - * e-table-header-item.c (ethi_set_arg): Ref header here. - (ethi_destroy): Unref it here. - -1999-11-17 Ettore Perazzoli <ettore@gnu.org> - - * e-msg-composer-address-dialog.c: Moved to `$(srcdir)/composer'. - * e-msg-composer-address-dialog.h: Likewise. - * e-msg-composer-address-entry.c: Likewise. - * e-msg-composer-address-entry.h: Likewise. - * e-msg-composer-attachment-bar.c: Likewise. - * e-msg-composer-attachment-bar.h: Likewise. - * e-msg-composer-attachment.c: Likewise. - * e-msg-composer-attachment.h: Likewise. - * e-msg-composer-hdrs.c: Likewise. - * e-msg-composer-hdrs.h: Likewise. - * e-msg-composer.c: Likewise. - * e-msg-composer.h: Likewise. - * e-msg-composer-address-dialog.glade: Likewise. - * e-msg-composer-attachment.glade: Likewise. - * e-msg-composer.glade: Likewise. - * Makefile.am: Updated accordingly. - -Nov 14 1999 Elliot Lee - * Makefile.am: It's libevolutionwidgets.la, not .a - -1999-11-14 Miguel de Icaza <miguel@gnu.org> - - * e-table-header-item.c (is_pointer_on_division): Add resizing - capabilities. - - * e-table-sorted.c: Finish implementation. - -1999-11-13 Miguel de Icaza <miguel@gnu.org> - - * e-table-sorted.c: Implement e-table-sorted object. - -1999-11-12 Miguel de Icaza <miguel@gnu.org> - - * e-table-header-item.c: Make the thing configurable. - - * e-table-header-item.h: Add font field, location, height. - -1999-11-12 Ettore Perazzoli <ettore@gnu.org> - - * e-msg-composer-hdrs.c: New member `tooltips' in `struct - _EMsgComposerHdrsPrivate'. - (init): Initialize it. - (destroy): New function. - (class_init): Install it as the `destroy' GtkObject method. - (add_header): New parameters `tip', `tip_private'. Setup a - tooltip for the entry with them. - (setup_headers): Updated accordingly. - -1999-11-11 Miguel de Icaza <miguel@gnu.org> - - * e-table-header.c (e_table_header_add_column): Update offsets. - (eth_update_offsets): New routine. - - * e-table-col.h, e-table-col.c: New files. - - * e-table-header.h (e_table_header_get_selected_indexes): - Pretify. - - * table-test.c (main): New file; used for testing ETable package. - - * e-table-simple.h: Fix type. - -1999-11-12 Ettore Perazzoli <ettore@gnu.org> - - * e-msg-composer-address-dialog.glade: Cosmetical changes. - - * e-msg-composer-attachment-bar.c (size_to_string): New helper - function. - (update): Put the size in the icon's label using this function. - (ICON_SEPARATORS): Remove '.' to avoid wrapping of the size string - on the decimal dot. But gnome-libs is broken and this has no real - effect! :-( - (e_msg_composer_attachment_bar_new): No longer make text editable. - Use the `GTK_SELECTION_MULTIPLE' selection mode. - (remove_selected): No longer assume only one attachment is - selected. - - * e-msg-composer-attachment.c: #include <sys/stat.h> - (init): Initialize all the members. - (e_msg_composer_attachment_new): Set size using `stat()'. - - * e-msg-composer-attachment.h: New member `size' in `struct - _EMsgComposerAttachment'. - - * e-msg-composer.c (setup_signals): Connect `address_dialog_cb' to - the "show_address_dialog" signal of the header widget. - - * e-msg-composer-hdrs.c (add_address_header): Renamed to - `add_header'. New parameter `addrbook_button': if true, use a - button instead of a label and make it trigger an - "show_address_dialog" signal. - (address_button_clicked_cb): Signal handler to handle this on a - "clicked" signal from the button. - (setup_headers): Updated accordingly. Also, make "Subject" the - last item. (This makes it look more like Outlook and friends.) - - * e-msg-composer-hdrs.c: New signal "show_address_dialog". - * e-msg-composer-hdrs.h: Updated accordingly. - - * e-msg-composer-hdrs.c (add_address_header): Reduce padding - considerably. - - * e-msg-composer.c (e_msg_composer_construct): Do not use any - padding in the main vbox. - - * Makefile.am: Moved the `e-table*' sources to `EXTRA_DIST'. - Compile as a shared library. - -1999-11-08 Ettore Perazzoli <ettore@gnu.org> - - * e-msg-composer-address-dialog.c: Implemented cut & paste for the - recipient lists. - (init): Initialize `cut_buffer'. - (destroy): Free it. - (recipient_clist_selection_get_cb): New function. - (recipient_clist_selection_received_cb): New function. - (recipient_clist_selection_clear_event_cb): New function. - (setup_recipient_list_signals): Install them as signal handlers - for "selection_get", "selection_received" and - "selection_clear_event" respectively. - (copy_recipient_cb): New function implementing the "copy" - operation. - (cut_recipient_cb): New function implementing the "cut" operation. - (paste_recipient_cb): New function implementing the "paste" - operation. - - * e-msg-composer-address-dialog.h: New member `cut_buffer' in - `struct _EMsgComposerAddressDialog'. - -1999-11-07 Ettore Perazzoli <ettore@gnu.org> - - * e-msg-composer-address-dialog.c: New context menu - `recipient_list_popup_info' for the recipient CLists. - (recipient_clist_button_press_cb): New function. - (setup_signals): Install it as the "button_press_event" signal - handler for popping up the CList context menu. - - * e-msg-composer.c (free_string_list): New helper function. - (setup_address_dialog): Setup the initial values in the address - dialog according to the ones in the header widget. - - * e-msg-composer-hdrs.c (e_msg_composer_hdrs_get_to): New function. - (e_msg_composer_hdrs_get_cc): New function. - (e_msg_composer_hdrs_get_bcc): New function. - - * e-msg-composer.c (setup_address_dialog): New helper function. - (address_dialog_cb): Use it. - - * e-msg-composer-address-dialog.c (add_address): Do not set the - row data anymore. Instead, put the full address description - (i.e. complete with the email address, not just the full name) in - the CList. - (add_address): Do nothing if no item is selected in the address - CList. - (get_list): Get the address list from the CList without passing - through the address CList. - (set_list): New helper function. - (e_msg_composer_address_dialog_set_to_list): New function. - (e_msg_composer_address_dialog_set_cc_list): New function. - (e_msg_composer_address_dialog_set_bcc_list): New function. - - * e-msg-composer.c (address_dialog_apply_cb): Apply values from - the address dialog into the composer. - - * e-msg-composer-hdrs.c (e_msg_composer_hdrs_set_to): New function. - (e_msg_composer_hdrs_set_cc): New function. - (e_msg_composer_hdrs_set_bcc): New function. - - * e-msg-composer-address-entry.c - (e_msg_composer_address_entry_set_list): New function. - - * e-msg-composer-address-dialog.c (apply): New helper function. - (clicked): New function, `clicked' method for the `GnomeDialog' - class. - (class_init): Install it. - -1999-11-06 Ettore Perazzoli <ettore@gnu.org> - - * e-msg-composer-attachment-bar.c (destroy): Call the destroy - method of the parent class. - - * e-msg-composer.c: #include "e-msg-composer-address-dialog.h". - (address_dialog_cb): New callback to start the address dialog. - (setup_signals): Connect it to the appropriate button/menu item. - (init): Initialize the new `address_dialog' member to NULL. - (destroy): Destroy the `address_dialog' if not NULL. - - * e-msg-composer.h: New member `address_dialog' in `struct - _EMsgComposer'. - - * e-msg-composer.glade: Added button to activate the address - composition dialog. - - * e-msg-composer-address-dialog.h, e-msg-composer-address-dialog.c: - New files implementing the address composition dialog for Evolution. - - * e-msg-composer-address-dialog.glade: New file. - - * e-msg-composer-attachment.c: `signals' made static. - -1999-11-05 Ettore Perazzoli <ettore@gnu.org> - - * Makefile.am: Compile the new files in a `libevolutionwidgets' - library. - (CPPFLAGS): #define `E_GUIDIR'. - - * e-msg-composer.c, e-msg-composer.h: New files implementing an - initial version of the Evolution message composer widget. - - * e-msg-composer-address-entry.c, e-msg-composer-address-entry.h: - New files implementing a GtkEntry customized for entering email - address lists. - - * e-msg-composer-attachment-bar.c, e-msg-composer-attachment-bar.h: - New files implementing a widget for editing mail attachments. - - * e-msg-composer-attachment.c, e-msg-composer-attachment.h: New - files implementing file attachment objects for the message - composer. - - * e-msg-composer-hdrs.c, e-msg-composer-hdrs.h: New files - implementing a widget for editing of email message headers. - - * e-msg-composer-attachment.glade: New file. - * e-msg-composer.glade: New file. - -1999-10-31 Miguel de Icaza <miguel@gnu.org> - - * widgets/e-table-column.c, e-table-column.h: New file, implements the - e-table-column object. - - * widget/e-table-model.h, e-table-model.c, e-table-simple.c, - e-table-simple.h: New files. Implements the column model and - a simple table wrapper. - diff --git a/widgets/Makefile.am b/widgets/Makefile.am index 73bd54ee2c..f8fd9b1c08 100644 --- a/widgets/Makefile.am +++ b/widgets/Makefile.am @@ -1,65 +1,3 @@ -SUBDIRS = - meeting-time-sel - -INCLUDES = \ - -I$(top_srcdir)/camel \ - -I$(top_builddir)/camel \ - $(GNOME_INCLUDEDIR) - -noinst_LIBRARIES = \ - libevolutionwidgets.a - -libevolutionwidgets_a_SOURCES = \ - e-cell.c \ - e-cell.h \ - e-cell-checkbox.c \ - e-cell-checkbox.h \ - e-cell-text.c \ - e-cell-text.h \ - e-cell-toggle.c \ - e-cell-toggle.h \ - e-cursors.c \ - e-cursors.h \ - e-table.c \ - e-table.h \ - e-table-col.c \ - e-table-col.h \ - e-table-group.c \ - e-table-group.h \ - e-table-header.c \ - e-table-header.h \ - e-table-header-item.c \ - e-table-header-item.h \ - e-table-item.c \ - e-table-item.h \ - e-table-model.c \ - e-table-model.h \ - e-table-simple.c \ - e-table-simple.h \ - e-table-sorted.c \ - e-table-sorted.h \ - e-table-subset.c \ - e-table-subset.h - -noinst_PROGRAMS = \ - table-test - -table_test_SOURCES = \ - test-table.c \ - test-check.c \ - test-cols.c \ - table-test.c - -table_test_LDADD = \ - $(EXTRA_GNOME_LIBS) \ - libevolutionwidgets.a - -table_test_LDFLAGS = `gnome-config --libs gdk_pixbuf` - -EXTRA_DIST = \ - sample.table \ - add-col.xpm \ - check-empty.xpm \ - check-filled.xpm \ - remove-col.xpm +SUBDIRS = \ + util meeting-time-sel shortcut-bar e-table diff --git a/widgets/ROADMAP.e-table b/widgets/ROADMAP.e-table deleted file mode 100644 index 4edacced86..0000000000 --- a/widgets/ROADMAP.e-table +++ /dev/null @@ -1,113 +0,0 @@ - -The E-Table package implements an editable table that provides -user-defined rendering, user-defined editing, sorting and grouping of -the objects displayed. - -It is inspired by Java's Swing JTable object. There are models for -the actual table contents and for the table headers; they are the -actual repository of information. - -The objects are rendered by various view objects. In the current code -base, we use we use GnomeCanvasItems to do the rendering. One for -each table and one for the headers. - -* The main widget - -e-table.c, e-table.h: - - Implements a full widget. Uses various components described - below. Handles column display as well as grouping/nesting - -* The Models - -All of them are GtkObjects. - -e-table-model.h, e-table-model.c: - - These implement the abstract E-Table-Model class. You - can derive this object to create your own data repository. - - These emits signals to notify the views about selection, and - changes in the model. - -e-table-simple.h, e-table-simple.c: - - A simple implementation of e-table-model that uses callback - routines (you provide the callbacks). For lazy people, like - me. - -e-cell.c, e-cell.h: - - These are actually mis-named. Objects of type e-cell know - about rendering a single cell, and these are attached to the - e-table-cols (described next). - - The user provides the various rendering modes as e-cells (they - are actually column-rendering repositories). - - This is just an abstract class. I will provide various - e-cells: a text cell, a checkbox cell, an image cell, and - perhaps an n-state image cell (one that switches the image when - the cell is clicked). - -e-table-col.h, e-table-col.c: - - Describes a single column (the size, the string displayed, the - rendering function for each row and comparison function for - this field). - - -* The Views - -e-table-header.h, e-table-header.c: - - These implement the ETableHeaderItem canvas item. This item is - used both to control the columns displayed as well as displaying them. - - They describe what columns are shown in the screen and in - which order. - - These emit signals: column-size-changed and structure-changed - (if a column is added/removed) - -e-table-item.c, e-table-item.h - - This is a canvas item that renders the contents of a - ETableModel into the screen. - -e-table-header-item.c, e-table-header-item.h - - This canvas item renders the ETableHeader headings. - -e-cell-text.c, e-cell-text.h - - Not really a view, but actually a derivative of e-cell that - implements text display: supports justification and font - setting. Will add color in the future most likely - -e-cell-toggle.c, e-cell-toggle.h - - A derivative of e-cell as well that support N-toggle values - using images. - -e-cell-check.c, e-cell-check.h - - An e-cell-toggle with two states only (for checkboxes). - -* The Filters - -e-table-sorted.c, e-table-sorted.h - - This is an ETableModel that can sort an existing ETableModel. - -e-table-subset.c, e-table-subset.h - - Not finished, but it is just an ETableModel that happens to be - a subset of another ETableModel. - -* Everything - -e-table.c, e-table.h - - In the future these guys will implement the whole widget for - doing table editing. Nothing done about these yet. diff --git a/widgets/TODO b/widgets/TODO deleted file mode 100644 index 29dbd454e5..0000000000 --- a/widgets/TODO +++ /dev/null @@ -1,24 +0,0 @@ -Implement e-cell-height -Implement computation of heights from the e-cell-heights -Make sure we compute the height from that -Include spacing in columns and rows for the decoration lines -Add threshold to compute a "global" size -Implement the two methods for row finding: by full thing, or by a factor. - - -Add editing -mouse grabbing for scrolling - - -1. Make sure that all values are updated on header changes and table - model changes (they are slightly out of sync now) - -* Correctness - - * Make sure we can boot and shutdown with no memory leaks. - - * Run Insure on the thing. - -* Propagation - - * Row changes should be reflected in the subsets. diff --git a/widgets/add-col.xpm b/widgets/add-col.xpm deleted file mode 100644 index 9c5f314c8e..0000000000 --- a/widgets/add-col.xpm +++ /dev/null @@ -1,22 +0,0 @@ -/* XPM */ -static char * add_col_xpm[] = { -"16 16 3 1", -" c None", -". c #000000", -"+ c #FFFFFF", -" ", -" ", -" ", -" ", -" .............. ", -" .++++++++++++. ", -" .++++++++++++. ", -" ....+++....... ", -" .+. ", -" . ", -" ", -" ", -" ", -" ", -" ", -" "}; diff --git a/widgets/check-empty.xpm b/widgets/check-empty.xpm deleted file mode 100644 index 2dd873e137..0000000000 --- a/widgets/check-empty.xpm +++ /dev/null @@ -1,21 +0,0 @@ -/* XPM */ -static char * check_empty_xpm[] = { -"16 16 2 1", -" c None", -". c #000000", -" ", -" ", -" ............ ", -" . . ", -" . . ", -" . . ", -" . . ", -" . . ", -" . . ", -" . . ", -" . . ", -" . . ", -" . . ", -" ............ ", -" ", -" "}; diff --git a/widgets/check-filled.xpm b/widgets/check-filled.xpm deleted file mode 100644 index 689d7a7967..0000000000 --- a/widgets/check-filled.xpm +++ /dev/null @@ -1,21 +0,0 @@ -/* XPM */ -static char * check_filled_xpm[] = { -"16 16 2 1", -" c None", -". c #000000", -" ", -" ", -" ............ ", -" . . ", -" . . . ", -" . .. . ", -" . ... . ", -" . . ... . ", -" . .. ... . ", -" . ..... . ", -" . ... . ", -" . . . ", -" . . ", -" ............ ", -" ", -" "}; diff --git a/widgets/e-cell-checkbox.c b/widgets/e-cell-checkbox.c deleted file mode 100644 index 6e4b597abf..0000000000 --- a/widgets/e-cell-checkbox.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * e-cell-checkbox.c: Checkbox cell renderer - * - * Author: - * Miguel de Icaza (miguel@kernel.org) - * - * (C) 1999 Helix Code, Inc - */ -#include <config.h> -#include <gtk/gtkenums.h> -#include <gtk/gtkentry.h> -#include <gtk/gtkwindow.h> -#include <gtk/gtksignal.h> -#include <gdk/gdkkeysyms.h> -#include <libgnomeui/gnome-canvas.h> -#include "e-cell-checkbox.h" -#include "e-util.h" -#include "e-table-item.h" - -#include "check-empty.xpm" -#include "check-filled.xpm" - -#define PARENT_TYPE e_cell_toggle_get_type() - -static GdkPixbuf *checks [2]; - -static void -e_cell_checkbox_class_init (GtkObjectClass *object_class) -{ - checks [0] = gdk_pixbuf_new_from_xpm_data (check_empty_xpm); - checks [1] = gdk_pixbuf_new_from_xpm_data (check_filled_xpm); -} - -E_MAKE_TYPE(e_cell_checkbox, "ECellCheckbox", ECellCheckbox, e_cell_checkbox_class_init, NULL, PARENT_TYPE); - -ECell * -e_cell_checkbox_new (void) -{ - ECellCheckbox *eccb = gtk_type_new (e_cell_checkbox_get_type ()); - - e_cell_toggle_construct (E_CELL_TOGGLE (eccb), 2, 2, checks); - - return (ECell *) eccb; -} diff --git a/widgets/e-cell-checkbox.h b/widgets/e-cell-checkbox.h deleted file mode 100644 index 969e4a5edc..0000000000 --- a/widgets/e-cell-checkbox.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _E_CELL_CHECKBOX_H_ -#define _E_CELL_CHECKBOX_H_ - -#include "e-cell-toggle.h" - -#define E_CELL_CHECKBOX_TYPE (e_cell_checkbox_get_type ()) -#define E_CELL_CHECKBOX(o) (GTK_CHECK_CAST ((o), E_CELL_CHECKBOX_TYPE, ECellCheckbox)) -#define E_CELL_CHECKBOX_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CELL_CHECKBOX_TYPE, ECellCheckboxClass)) -#define E_IS_CELL_CHECKBOX(o) (GTK_CHECK_TYPE ((o), E_CELL_CHECKBOX_TYPE)) -#define E_IS_CELL_CHECKBOX_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CELL_CHECKBOX_TYPE)) - -typedef struct { - ECellToggle parent; -} ECellCheckbox; - -typedef struct { - ECellToggleClass parent_class; -} ECellCheckboxClass; - -GtkType e_cell_checkbox_get_type (void); -ECell *e_cell_checkbox_new (void); - -#endif /* _E_CELL_CHECKBOX_H_ */ - diff --git a/widgets/e-cell-string.c b/widgets/e-cell-string.c deleted file mode 100644 index 992b1bd10e..0000000000 --- a/widgets/e-cell-string.c +++ /dev/null @@ -1,9 +0,0 @@ -ECell * -e_cell_string_new (void) -{ - ECell *ecell; - - ecell = gtk_type_new (ecell); - - return ecell; -} diff --git a/widgets/e-cell-text.c b/widgets/e-cell-text.c deleted file mode 100644 index 1b2205ba51..0000000000 --- a/widgets/e-cell-text.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * e-cell-text.c: Text cell renderer - * - * Author: - * Miguel de Icaza (miguel@kernel.org) - * - * (C) 1999 Helix Code, Inc - */ -#include <config.h> -#include <gtk/gtkenums.h> -#include <gtk/gtkentry.h> -#include <gtk/gtkwindow.h> -#include <gtk/gtksignal.h> -#include <gdk/gdkkeysyms.h> -#include <libgnomeui/gnome-canvas.h> -#include <stdio.h> -#include "e-cell-text.h" -#include "e-util.h" -#include "e-table-item.h" - -#define PARENT_TYPE e_cell_get_type() - -#define TEXT_PAD 2 - -typedef struct { - char *old_text; - GtkWidget *entry_top; - GtkEntry *entry; - - /* - * Where the editing is taking place - */ - int model_col, view_col, row; -} CellEdit; - -typedef struct { - ECellView cell_view; - GdkGC *gc; - GdkFont *font; - GnomeCanvas *canvas; - - /* - * During edition. - */ - CellEdit *edit; -} ECellTextView; - -static ECellClass *parent_class; - -static void -ect_queue_redraw (ECellTextView *text_view, int view_col, int view_row) -{ - e_table_item_redraw_range ( - text_view->cell_view.e_table_item_view, - view_col, view_row, view_col, view_row); -} - -/* - * Accept the currently edited text - */ -static void -ect_accept_edits (ECellTextView *text_view) -{ - const char *text = gtk_entry_get_text (text_view->edit->entry); - CellEdit *edit = text_view->edit; - - e_table_model_set_value_at (text_view->cell_view.e_table_model, edit->model_col, edit->row, text); -} - -/* - * Shuts down the editing process - */ -static void -ect_stop_editing (ECellTextView *text_view) -{ - CellEdit *edit = text_view->edit; - - g_free (edit->old_text); - edit->old_text = NULL; - gtk_widget_destroy (edit->entry_top); - edit->entry_top = NULL; - edit->entry = NULL; - - g_free (edit); - - text_view->edit = NULL; - - e_table_item_leave_edit (text_view->cell_view.e_table_item_view); -} - -/* - * Cancels the edits - */ -static void -ect_cancel_edit (ECellTextView *text_view) -{ - ect_queue_redraw (text_view, text_view->edit->view_col, text_view->edit->row); - ect_stop_editing (text_view); -} - -/* - * ECell::new_view method - */ -static ECellView * -ect_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view) -{ - ECellText *ect = E_CELL_TEXT (ecell); - ECellTextView *text_view = g_new0 (ECellTextView, 1); - GnomeCanvas *canvas = GNOME_CANVAS_ITEM (e_table_item_view)->canvas; - - text_view->cell_view.ecell = ecell; - text_view->cell_view.e_table_model = table_model; - text_view->cell_view.e_table_item_view = e_table_item_view; - - if (ect->font_name){ - GdkFont *f; - - f = gdk_fontset_load (ect->font_name); - text_view->font = f; - } - if (!text_view->font){ - text_view->font = GTK_WIDGET (canvas)->style->font; - - gdk_font_ref (text_view->font); - } - - text_view->canvas = canvas; - - return (ECellView *)text_view; -} - -/* - * ECell::kill_view method - */ -static void -ect_kill_view (ECellView *ecv) -{ - ECellTextView *text_view = (ECellTextView *) ecv; - - gdk_font_unref (text_view->font); - text_view->font = NULL; - - g_free (text_view); -} - -/* - * ECell::realize method - */ -static void -ect_realize (ECellView *ecell_view) -{ - ECellTextView *text_view = (ECellTextView *) ecell_view; - - text_view->gc = gdk_gc_new (GTK_WIDGET (text_view->canvas)->window); -} - -/* - * ECell::unrealize method - */ -static void -ect_unrealize (ECellView *ecv) -{ - ECellTextView *text_view = (ECellTextView *) ecv; - - gdk_gc_unref (text_view->gc); - text_view->gc = NULL; -} - -/* - * ECell::draw method - */ -static void -ect_draw (ECellView *ecell_view, GdkDrawable *drawable, - int model_col, int view_col, int row, gboolean selected, - int x1, int y1, int x2, int y2) -{ - ECellText *ect = E_CELL_TEXT (ecell_view->ecell); - ECellTextView *text_view = (ECellTextView *) ecell_view; - GtkWidget *w = GTK_WIDGET (text_view->canvas); - GdkRectangle rect; - const char *str = e_table_model_value_at (ecell_view->e_table_model, model_col, row); - GdkFont *font = text_view->font; - const int height = font->ascent + font->descent; - int xoff; - gboolean edit_display = FALSE; - - /* - * Figure if this cell is being edited - */ - if (text_view->edit){ - CellEdit *edit = text_view->edit; - - if ((edit->view_col == view_col) && (edit->row == row)) - edit_display = TRUE; - } - - /* - * Be a nice citizen: clip to the region we are supposed to draw on - */ - rect.x = x1; - rect.y = y1; - rect.width = x2 - x1; - rect.height = y2 - y1; - gdk_gc_set_clip_rectangle (text_view->gc, &rect); - - if (edit_display){ - CellEdit *edit = text_view->edit; - const char *text = gtk_entry_get_text (edit->entry); - GdkWChar *p, *text_wc = g_new (GdkWChar, strlen (text) + 1); - int text_wc_len = gdk_mbstowcs (text_wc, text, strlen (text)); - const int cursor_pos = GTK_EDITABLE (edit->entry)->current_pos; - const int left_len = gdk_text_width_wc (text_view->font, text_wc, cursor_pos); - - text_wc [text_wc_len] = 0; - /* - * Paint - */ - gdk_gc_set_foreground (text_view->gc, &w->style->base [GTK_STATE_NORMAL]); - gdk_draw_rectangle (drawable, text_view->gc, TRUE, - rect.x, rect.y, rect.width, rect.height); - gdk_gc_set_foreground (text_view->gc, &w->style->text [GTK_STATE_NORMAL]); - - { - GdkGC *gc = text_view->gc; - const int y = y2 - font->descent - ((y2-y1-height)/2); - int px, i; - - /* - * Border - */ - x1 += 2; - x2--; - - px = x1; - - /* - * If the cursor is outside the visible range - * - * FIXME: we really want a better behaviour. - */ - if ((px + left_len) > x2) - px -= left_len - (x2-x1); - - /* - * Draw - */ - for (i = 0, p = text_wc; *p; p++, i++){ - gdk_draw_text_wc ( - drawable, font, gc, px, y, p, 1); - - if (i == cursor_pos){ - gdk_draw_line ( - drawable, gc, - px, y - font->ascent, - px, y + font->descent - 1); - } - - px += gdk_text_width_wc (font, p, 1); - } - - if (i == cursor_pos){ - gdk_draw_line ( - drawable, gc, - px, y - font->ascent, - px, y + font->descent - 1); - } - } - g_free (text_wc); - } else { - /* - * Regular cell - */ - GdkColor *background, *foreground; - int width; - - /* - * Border - */ - x1++; - x2--; - - /* - * Compute draw mode - */ - switch (ect->justify){ - case GTK_JUSTIFY_LEFT: - xoff = 1; - break; - - case GTK_JUSTIFY_RIGHT: - width = 1 + gdk_text_width (font, str, strlen (str)); - xoff = (x2 - x1) - width; - break; - - case GTK_JUSTIFY_CENTER: - xoff = ((x2 - x1) - gdk_text_width (font, str, strlen (str))) / 2; - break; - default: - xoff = 0; - g_warning ("Can not handle GTK_JUSTIFY_FILL"); - break; - } - - - if (selected){ - background = &w->style->bg [GTK_STATE_SELECTED]; - foreground = &w->style->text [GTK_STATE_SELECTED]; - } else { - background = &w->style->base [GTK_STATE_NORMAL]; - foreground = &w->style->text [GTK_STATE_NORMAL]; - } - - gdk_gc_set_foreground (text_view->gc, background); - gdk_draw_rectangle (drawable, text_view->gc, TRUE, - rect.x, rect.y, rect.width, rect.height); - gdk_gc_set_foreground (text_view->gc, foreground); - - gdk_draw_string ( - drawable, font, text_view->gc, - x1 + xoff, - y2 - font->descent - ((y2-y1-height)/2), str); - } -} - -/* - * Selects the entire string - */ -static void -ect_edit_select_all (ECellTextView *text_view) -{ - g_assert (text_view->edit); - - gtk_editable_select_region (GTK_EDITABLE (text_view->edit->entry), 0, -1); -} - -/* - * ECell::event method - */ -static gint -ect_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row) -{ - ECellTextView *text_view = (ECellTextView *) ecell_view; - - switch (event->type){ - case GDK_BUTTON_PRESS: - /* - * Adjust for the border we use - */ - event->button.x++; - - printf ("Button pressed at %g %g\n", event->button.x, event->button.y); - if (text_view->edit){ - printf ("FIXME: Should handle click here\n"); - } else - e_table_item_enter_edit (text_view->cell_view.e_table_item_view, view_col, row); - break; - - case GDK_BUTTON_RELEASE: - /* - * Adjust for the border we use - */ - event->button.x++; - printf ("Button released at %g %g\n", event->button.x, event->button.y); - return TRUE; - - case GDK_KEY_PRESS: - if (event->key.keyval == GDK_Escape){ - ect_cancel_edit (text_view); - return TRUE; - } - - if (!text_view->edit){ - e_table_item_enter_edit (text_view->cell_view.e_table_item_view, view_col, row); - ect_edit_select_all (text_view); - } - - gtk_widget_event (GTK_WIDGET (text_view->edit->entry), event); - ect_queue_redraw (text_view, view_col, row); - break; - - case GDK_KEY_RELEASE: - break; - - default: - return FALSE; - } - return TRUE; -} - -/* - * ECell::height method - */ -static int -ect_height (ECellView *ecell_view, int model_col, int view_col, int row) -{ - ECellTextView *text_view = (ECellTextView *) ecell_view; - - return (text_view->font->ascent + text_view->font->descent) + TEXT_PAD; -} - -/* - * Callback: invoked when the user pressed "enter" on the GtkEntry - */ -static void -ect_entry_activate (GtkEntry *entry, ECellTextView *text_view) -{ - e_table_item_leave_edit (text_view->cell_view.e_table_item_view); -} - -/* - * ECellView::enter_edit method - */ -static void * -ect_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row) -{ - ECellTextView *text_view = (ECellTextView *) ecell_view; - const char *str = e_table_model_value_at (ecell_view->e_table_model, model_col, row); - CellEdit *edit; - - edit = g_new (CellEdit, 1); - text_view->edit = edit; - - edit->model_col = model_col; - edit->view_col = view_col; - edit->row = row; - - edit->entry = (GtkEntry *) gtk_entry_new (); - gtk_entry_set_text (edit->entry, str); - edit->old_text = g_strdup (str); - gtk_signal_connect (GTK_OBJECT (edit->entry), "activate", - GTK_SIGNAL_FUNC (ect_entry_activate), text_view); - - /* - * The hack: create this window off-screen - */ - edit->entry_top = gtk_window_new (GTK_WINDOW_POPUP); - gtk_container_add (GTK_CONTAINER (edit->entry_top), GTK_WIDGET (edit->entry)); - gtk_widget_set_uposition (edit->entry_top, 20000, 20000); - gtk_widget_show_all (edit->entry_top); - - ect_queue_redraw (text_view, view_col, row); - - return NULL; -} - -/* - * ECellView::leave_edit method - */ -static void -ect_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context) -{ - ECellTextView *text_view = (ECellTextView *) ecell_view; - - if (text_view->edit){ - ect_accept_edits (text_view); - ect_stop_editing (text_view); - } else { - /* - * We did invoke this leave edit internally - */ - } -} - -/* - * GtkObject::destroy method - */ -static void -ect_destroy (GtkObject *object) -{ - ECellText *ect = E_CELL_TEXT (object); - - g_free (ect->font_name); - - GTK_OBJECT_CLASS (parent_class)->destroy (object); -} - -static void -e_cell_text_class_init (GtkObjectClass *object_class) -{ - ECellClass *ecc = (ECellClass *) object_class; - - object_class->destroy = ect_destroy; - - ecc->new_view = ect_new_view; - ecc->kill_view = ect_kill_view; - ecc->realize = ect_realize; - ecc->unrealize = ect_unrealize; - ecc->draw = ect_draw; - ecc->event = ect_event; - ecc->height = ect_height; - ecc->enter_edit = ect_enter_edit; - ecc->leave_edit = ect_leave_edit; - - parent_class = gtk_type_class (PARENT_TYPE); -} - -E_MAKE_TYPE(e_cell_text, "ECellText", ECellText, e_cell_text_class_init, NULL, PARENT_TYPE); - -ECell * -e_cell_text_new (ETableModel *etm, const char *fontname, GtkJustification justify) -{ - ECellText *ect = gtk_type_new (e_cell_text_get_type ()); - - ect->font_name = g_strdup (fontname); - ect->justify = justify; - - return (ECell *) ect; -} diff --git a/widgets/e-cell-text.h b/widgets/e-cell-text.h deleted file mode 100644 index de9629b97b..0000000000 --- a/widgets/e-cell-text.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _E_CELL_TEXT_H_ -#define _E_CELL_TEXT_H_ - -#include <libgnomeui/gnome-canvas.h> -#include "e-cell.h" - -#define E_CELL_TEXT_TYPE (e_cell_text_get_type ()) -#define E_CELL_TEXT(o) (GTK_CHECK_CAST ((o), E_CELL_TEXT_TYPE, ECellText)) -#define E_CELL_TEXT_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CELL_TEXT_TYPE, ECellTextClass)) -#define E_IS_CELL_TEXT(o) (GTK_CHECK_TYPE ((o), E_CELL_TEXT_TYPE)) -#define E_IS_CELL_TEXT_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CELL_TEXT_TYPE)) - -typedef struct { - ECell parent; - - GtkJustification justify; - char *font_name; -} ECellText; - -typedef struct { - ECellClass parent_class; -} ECellTextClass; - -GtkType e_cell_text_get_type (void); -ECell *e_cell_text_new (ETableModel *model, const char *fontname, GtkJustification justify); - -#endif /* _E_CELL_TEXT_H_ */ - diff --git a/widgets/e-cell-toggle.c b/widgets/e-cell-toggle.c deleted file mode 100644 index 6ea181ea40..0000000000 --- a/widgets/e-cell-toggle.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * e-cell-toggle.c: Multi-state image toggle cell object. - * - * Author: - * Miguel de Icaza (miguel@kernel.org) - * - * (C) 1999 Helix Code, Inc - */ -#include <config.h> -#include <gtk/gtkenums.h> -#include <gtk/gtkentry.h> -#include <gtk/gtkwindow.h> -#include <gtk/gtksignal.h> -#include <gdk/gdkkeysyms.h> -#include <libgnomeui/gnome-canvas.h> -#include "e-cell-toggle.h" -#include "e-util.h" -#include "e-table-item.h" - -#define PARENT_TYPE e_cell_get_type() - -typedef struct { - ECellView cell_view; - GdkGC *gc; - GnomeCanvas *canvas; -} ECellToggleView; - -static ECellClass *parent_class; - -static void -etog_queue_redraw (ECellToggleView *text_view, int view_col, int view_row) -{ - e_table_item_redraw_range ( - text_view->cell_view.e_table_item_view, - view_col, view_row, view_col, view_row); -} - -/* - * ECell::realize method - */ -static ECellView * -etog_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view) -{ - ECellToggleView *toggle_view = g_new0 (ECellToggleView, 1); - ETableItem *eti = E_TABLE_ITEM (e_table_item_view); - GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; - - toggle_view->cell_view.ecell = ecell; - toggle_view->cell_view.e_table_model = table_model; - toggle_view->cell_view.e_table_item_view = e_table_item_view; - toggle_view->canvas = canvas; - - return (ECellView *) toggle_view; -} - -static void -etog_kill_view (ECellView *ecell_view) -{ - g_free (ecell_view); -} - -static void -etog_realize (ECellView *ecell_view) -{ - ECellToggleView *toggle_view = (ECellToggleView *) ecell_view; - - toggle_view->gc = gdk_gc_new (GTK_WIDGET (toggle_view->canvas)->window); -} - -/* - * ECell::unrealize method - */ -static void -etog_unrealize (ECellView *ecv) -{ - ECellToggleView *toggle_view = (ECellToggleView *) ecv; - - gdk_gc_unref (toggle_view->gc); - toggle_view->gc = NULL; -} - -/* - * ECell::draw method - */ -static void -etog_draw (ECellView *ecell_view, GdkDrawable *drawable, - int model_col, int view_col, int row, gboolean selected, - int x1, int y1, int x2, int y2) -{ - ECellToggle *toggle = E_CELL_TOGGLE (ecell_view->ecell); - ECellToggleView *toggle_view = (ECellToggleView *) ecell_view; - GdkPixbuf *image; - ArtPixBuf *art; - int x, y, width, height; - const int value = GPOINTER_TO_INT ( - e_table_model_value_at (ecell_view->e_table_model, model_col, row)); - - if (value >= toggle->n_states){ - g_warning ("Value from the table model is %d, the states we support are [0..%d)\n", - value, toggle->n_states); - return; - } - - /* - * Paint the background - */ - gdk_draw_rectangle (drawable, GTK_WIDGET (toggle_view->canvas)->style->white_gc, TRUE, x1, y1, x2 - x1, y2 - y1); - - image = toggle->images [value]; - art = image->art_pixbuf; - - if ((x2 - x1) < art->width){ - x = x1; - width = x2 - x1; - } else { - x = x1 + ((x2 - x1) - art->width) / 2; - width = art->width; - } - - if ((y2 - y1) < art->height){ - y = y1; - height = y2 - y1; - } else { - y = y1 + ((y2 - y1) - art->height) / 2; - height = art->height; - } - - width = y2 - y1; - - if (image->art_pixbuf->has_alpha){ - GdkColor background; - guchar *buffer; - int alpha, ix, iy; - - buffer = g_malloc (art->rowstride * art->height * 3); - - background.red = 255; - background.green = 255; - background.blue = 255; - - for (iy = 0; iy < art->height; iy++){ - unsigned char *dest; - unsigned char *src; - - dest = buffer + (iy * art->rowstride); - src = art->pixels + (iy * art->rowstride); - - for (ix = 0; ix < art->width; ix++){ - alpha = src [3]; - if (alpha == 0){ - *dest++ = background.red; - *dest++ = background.green; - *dest++ = background.blue; - src += 3; - } else if (alpha == 255){ - *dest++ = *src++; - *dest++ = *src++; - *dest++ = *src++; - } else { - *dest++ = (background.red + ((*src++ - background.red) * alpha + 0x80)) >> 8; - *dest++ = (background.green + ((*src++ - background.green) * alpha + 0x80)) >> 8; - *dest++ = (background.blue + ((*src++ - background.blue) * alpha + 0x80)) >> 8; - } - src++; - } - } - - gdk_draw_rgb_image_dithalign ( - drawable, toggle_view->gc, x, y, width, height, - GDK_RGB_DITHER_NORMAL, buffer, art->rowstride, 0, 0); - - g_free (buffer); - } else - gdk_draw_rgb_image_dithalign ( - drawable, toggle_view->gc, x, y, width, height, - GDK_RGB_DITHER_NORMAL, art->pixels, art->rowstride, 0, 0); -} - -static void -etog_set_value (ECellToggleView *toggle_view, int model_col, int view_col, int row, int value) -{ - ECell *ecell = toggle_view->cell_view.ecell; - ECellToggle *toggle = E_CELL_TOGGLE (ecell); - - if (value >= toggle->n_states) - value = 0; - - e_table_model_set_value_at (toggle_view->cell_view.e_table_model, - model_col, row, GINT_TO_POINTER (value)); - etog_queue_redraw (toggle_view, view_col, row); -} - -/* - * ECell::event method - */ -static gint -etog_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row) -{ - ECellToggleView *toggle_view = (ECellToggleView *) ecell_view; - void *_value = e_table_model_value_at (ecell_view->e_table_model, model_col, row); - const int value = GPOINTER_TO_INT (_value); - - switch (event->type){ - case GDK_BUTTON_RELEASE: - etog_set_value (toggle_view, model_col, view_col, row, value + 1); - return TRUE; - - case GDK_KEY_PRESS: - if (event->key.keyval == GDK_space){ - etog_set_value (toggle_view, model_col, view_col, row, value + 1); - return TRUE; - } - return FALSE; - - default: - return FALSE; - } - return TRUE; -} - -/* - * ECell::height method - */ -static int -etog_height (ECellView *ecell_view, int model_col, int view_col, int row) -{ - ECellToggle *toggle = E_CELL_TOGGLE (ecell_view->ecell); - - return toggle->height; -} - -static void -etog_destroy (GtkObject *object) -{ - ECellToggle *etog = E_CELL_TOGGLE (object); - int i; - - for (i = 0; i < etog->n_states; i++) - gdk_pixbuf_unref (etog->images [i]); - - g_free (etog->images); - - GTK_OBJECT_CLASS (parent_class)->destroy (object); -} - -static void -e_cell_toggle_class_init (GtkObjectClass *object_class) -{ - ECellClass *ecc = (ECellClass *) object_class; - - object_class->destroy = etog_destroy; - - ecc->new_view = etog_new_view; - ecc->kill_view = etog_kill_view; - ecc->realize = etog_realize; - ecc->unrealize = etog_unrealize; - ecc->draw = etog_draw; - ecc->event = etog_event; - ecc->height = etog_height; - - parent_class = gtk_type_class (PARENT_TYPE); -} - -E_MAKE_TYPE(e_cell_toggle, "ECellToggle", ECellToggle, e_cell_toggle_class_init, NULL, PARENT_TYPE); - -void -e_cell_toggle_construct (ECellToggle *etog, int border, int n_states, GdkPixbuf **images) -{ - int max_height = 0; - int i; - - etog->border = border; - etog->n_states = n_states; - - etog->images = g_new (GdkPixbuf *, n_states); - - for (i = 0; i < n_states; i++){ - etog->images [i] = images [i]; - gdk_pixbuf_ref (images [i]); - - if (images [i]->art_pixbuf->height > max_height) - max_height = images [i]->art_pixbuf->height; - } - - etog->height = max_height; -} - -ECell * -e_cell_toggle_new (int border, int n_states, GdkPixbuf **images) -{ - ECellToggle *etog = gtk_type_new (e_cell_toggle_get_type ()); - - e_cell_toggle_construct (etog, border, n_states, images); - - return (ECell *) etog; -} - - diff --git a/widgets/e-cell-toggle.h b/widgets/e-cell-toggle.h deleted file mode 100644 index d5773b454a..0000000000 --- a/widgets/e-cell-toggle.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _E_CELL_TOGGLE_H_ -#define _E_CELL_TOGGLE_H_ - -#include <libgnomeui/gnome-canvas.h> -#include <gdk-pixbuf/gdk-pixbuf.h> -#include "e-cell.h" - -#define E_CELL_TOGGLE_TYPE (e_cell_toggle_get_type ()) -#define E_CELL_TOGGLE(o) (GTK_CHECK_CAST ((o), E_CELL_TOGGLE_TYPE, ECellToggle)) -#define E_CELL_TOGGLE_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CELL_TOGGLE_TYPE, ECellToggleClass)) -#define E_IS_CELL_TOGGLE(o) (GTK_CHECK_TYPE ((o), E_CELL_TOGGLE_TYPE)) -#define E_IS_CELL_TOGGLE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CELL_TOGGLE_TYPE)) - -typedef struct { - ECell parent; - - int border; - int n_states; - GdkPixbuf **images; - - int height; -} ECellToggle; - -typedef struct { - ECellClass parent_class; -} ECellToggleClass; - -GtkType e_cell_toggle_get_type (void); -ECell *e_cell_toggle_new (int border, int n_states, GdkPixbuf **images); -void e_cell_toggle_construct (ECellToggle *etog, int border, - int n_states, GdkPixbuf **images); - -#endif /* _E_CELL_TOGGLE_H_ */ - - diff --git a/widgets/e-cell.c b/widgets/e-cell.c deleted file mode 100644 index 0f9297ecba..0000000000 --- a/widgets/e-cell.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * e-cell.c: base class for cell renderers in e-table - * - * Author: - * Miguel de Icaza (miguel@kernel.org) - * - * (C) 1999 Helix Code, Inc - */ -#include <config.h> -#include "e-cell.h" -#include "e-util.h" - -#define PARENT_TYPE gtk_object_get_type() - -static ECellView * -ec_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view) -{ - return NULL; -} - -static void -ec_realize (ECellView *e_cell) -{ -} - -static void -ec_kill_view (ECellView *ecell_view) -{ -} - -static void -ec_unrealize (ECellView *e_cell) -{ -} - -static void -ec_draw (ECellView *ecell_view, GdkDrawable *drawable, - int model_col, int view_col, int row, gboolean selected, - int x1, int y1, int x2, int y2) -{ - g_error ("e-cell-draw invoked\n"); -} - -static gint -ec_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row) -{ - g_error ("e-cell-event invoked\n"); - return 0; -} - -static gint -ec_height (ECellView *ecell_view, int model_col, int view_col, int row) -{ - g_error ("e-cell-event invoked\n"); - return 0; -} - -static void -ec_focus (ECellView *ecell_view, int model_col, int view_col, int row, int x1, int y1, int x2, int y2) -{ - ecell_view->focus_col = view_col; - ecell_view->focus_row = row; - ecell_view->focus_x1 = x1; - ecell_view->focus_y1 = y1; - ecell_view->focus_x2 = x2; - ecell_view->focus_y2 = y2; -} - -static void -ec_unfocus (ECellView *ecell_view) -{ - ecell_view->focus_col = -1; - ecell_view->focus_row = -1; - ecell_view->focus_x1 = -1; - ecell_view->focus_y1 = -1; - ecell_view->focus_x2 = -1; - ecell_view->focus_y2 = -1; -} - -static void * -ec_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row) -{ - return NULL; -} - -static void -ec_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *context) -{ -} - -static void -e_cell_class_init (GtkObjectClass *object_class) -{ - ECellClass *ecc = (ECellClass *) object_class; - - ecc->realize = ec_realize; - ecc->unrealize = ec_unrealize; - ecc->new_view = ec_new_view; - ecc->kill_view = ec_kill_view; - ecc->draw = ec_draw; - ecc->event = ec_event; - ecc->focus = ec_focus; - ecc->unfocus = ec_unfocus; - ecc->height = ec_height; - ecc->enter_edit = ec_enter_edit; - ecc->leave_edit = ec_leave_edit; -} - -static void -e_cell_init (GtkObject *object) -{ -} - -E_MAKE_TYPE(e_cell, "ECell", ECell, e_cell_class_init, e_cell_init, PARENT_TYPE); - - -void -e_cell_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row) -{ - E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->event ( - ecell_view, event, model_col, view_col, row); -} - -ECellView * -e_cell_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view) -{ - return E_CELL_CLASS (GTK_OBJECT (ecell)->klass)->new_view ( - ecell, table_model, e_table_item_view); -} - -void -e_cell_view_realize (ECellView *ecell_view) -{ - return E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->realize (ecell_view); -} - -void -e_cell_kill_view (ECellView *ecell_view) -{ - E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->kill_view (ecell_view); -} - -void -e_cell_unrealize (ECellView *ecell_view) -{ - E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->unrealize (ecell_view); -} - -void -e_cell_draw (ECellView *ecell_view, GdkDrawable *drawable, - int model_col, int view_col, int row, gboolean selected, int x1, int y1, int x2, int y2) -{ - E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->draw ( - ecell_view, drawable, model_col, view_col, row, selected, x1, y1, x2, y2); -} - -int -e_cell_height (ECellView *ecell_view, int model_col, int view_col, int row) -{ - return E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->height ( - ecell_view, model_col, view_col, row); -} - -void * -e_cell_enter_edit (ECellView *ecell_view, int model_col, int view_col, int row) -{ - return E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->enter_edit ( - ecell_view, model_col, view_col, row); -} - -void -e_cell_leave_edit (ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context) -{ - E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->leave_edit ( - ecell_view, model_col, view_col, row, edit_context); -} diff --git a/widgets/e-cell.h b/widgets/e-cell.h deleted file mode 100644 index 3c258689e4..0000000000 --- a/widgets/e-cell.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _E_CELL_H_ -#define _E_CELL_H_ - -#include <gdk/gdktypes.h> -#include "e-table-model.h" - -#define E_CELL_TYPE (e_cell_get_type ()) -#define E_CELL(o) (GTK_CHECK_CAST ((o), E_CELL_TYPE, ECell)) -#define E_CELL_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CELL_TYPE, ECellClass)) -#define E_IS_CELL(o) (GTK_CHECK_TYPE ((o), E_CELL_TYPE)) -#define E_IS_CELL_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CELL_TYPE)) - -typedef struct _ECell ECell; -typedef struct _ECellView ECellView; - -struct _ECell { - GtkObject object; -}; - -struct _ECellView { - ECell *ecell; - ETableModel *e_table_model; - void *e_table_item_view; - - gint focus_x1, focus_y1, focus_x2, focus_y2; - gint focus_col, focus_row; -}; - -#define E_CELL_IS_FOCUSED(ecell_view) (ecell_view->focus_x1 != -1) - -typedef struct { - GtkObjectClass parent_class; - - ECellView *(*new_view) (ECell *ecell, ETableModel *table_model, void *e_table_item_view); - void (*kill_view) (ECellView *ecell_view); - - void (*realize) (ECellView *ecell_view); - void (*unrealize) (ECellView *ecell_view); - - void (*draw) (ECellView *ecell_view, GdkDrawable *drawable, - int model_col, int view_col, int row, - gboolean selected, int x1, int y1, int x2, int y2); - gint (*event) (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row); - void (*focus) (ECellView *ecell_view, int model_col, int view_col, - int row, int x1, int y1, int x2, int y2); - void (*unfocus) (ECellView *ecell_view); - int (*height) (ECellView *ecell_view, int model_col, int view_col, int row); - - void *(*enter_edit)(ECellView *ecell_view, int model_col, int view_col, int row); - void (*leave_edit)(ECellView *ecell_view, int model_col, int view_col, int row, void *context); -} ECellClass; - -GtkType e_cell_get_type (void); -ECellView *e_cell_new_view (ECell *ecell, ETableModel *table_model, void *e_table_item_view); -void e_cell_kill_view (ECellView *ecell_view); - -void e_cell_event (ECellView *ecell_view, GdkEvent *event, int model_col, int view_col, int row); - -void e_cell_realize (ECellView *ecell_view); -void e_cell_unrealize (ECellView *ecell_view); - -void e_cell_draw (ECellView *ecell_view, GdkDrawable *dr, - int model_col, int view_col, int row, gboolean selected, - int x1, int y1, int x2, int y2); -void e_cell_focus (ECellView *ecell_view, int model_col, int view_col, int row, - int x1, int y1, int x2, int y2); -void e_cell_unfocus (ECellView *ecell_view); -int e_cell_height (ECellView *ecell_view, int model_col, int view_col, int row); - -void *e_cell_enter_edit(ECellView *ecell_view, int model_col, int view_col, int row); -void e_cell_leave_edit(ECellView *ecell_view, int model_col, int view_col, int row, void *edit_context); - -#endif /* _E_CELL_H_ */ diff --git a/widgets/e-table-col-dnd.h b/widgets/e-table-col-dnd.h deleted file mode 100644 index c1c26175c7..0000000000 --- a/widgets/e-table-col-dnd.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _E_TABLE_COL_DND_H_ -#define _E_TABLE_COL_DND_H_ - -#define TARGET_ETABLE_COL_TYPE "application/x-etable-column-header" - -enum { - TARGET_ETABLE_COL_HEADER -}; - -#endif /* _E_TABLE_COL_DND_H_ */ diff --git a/widgets/e-table-col.c b/widgets/e-table-col.c deleted file mode 100644 index 86392a9419..0000000000 --- a/widgets/e-table-col.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * E-table-col.c: ETableCol implementation - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * (C) 1999 Helix Code, Inc - */ -#include <config.h> -#include <gtk/gtkobject.h> -#include <gtk/gtksignal.h> -#include "e-table-col.h" -#include "e-util.h" - -#define PARENT_TYPE (gtk_object_get_type ()) - -static GtkObjectClass *parent_class; - -static void -etc_destroy (GtkObject *object) -{ - ETableCol *etc = E_TABLE_COL (object); - - g_free (etc->text); - - (*parent_class->destroy)(object); -} - -static void -e_table_col_class_init (GtkObjectClass *object_class) -{ - parent_class = gtk_type_class (PARENT_TYPE); - object_class->destroy = etc_destroy; -} - -E_MAKE_TYPE(e_table_col, "ETableCol", ETableCol, e_table_col_class_init, NULL, PARENT_TYPE); - -ETableCol * -e_table_col_new (int col_idx, const char *text, int width, int min_width, - ECell *ecell, GCompareFunc compare, gboolean resizable) -{ - ETableCol *etc; - - g_return_val_if_fail (width >= 0, NULL); - g_return_val_if_fail (min_width >= 0, NULL); - g_return_val_if_fail (width >= min_width, NULL); - g_return_val_if_fail (compare != NULL, NULL); - - etc = gtk_type_new (E_TABLE_COL_TYPE); - - etc->col_idx = col_idx; - etc->text = g_strdup (text); - etc->width = width; - etc->min_width = min_width; - etc->ecell = ecell; - etc->compare = compare; - - etc->selected = 0; - etc->resizeable = resizable; - - return etc; -} - - diff --git a/widgets/e-table-col.h b/widgets/e-table-col.h deleted file mode 100644 index 54f03ae237..0000000000 --- a/widgets/e-table-col.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _E_TABLE_COL_H_ -#define _E_TABLE_COL_H_ - -#include "e-cell.h" - -#define E_TABLE_COL_TYPE (e_table_col_get_type ()) -#define E_TABLE_COL(o) (GTK_CHECK_CAST ((o), E_TABLE_COL_TYPE, ETableCol)) -#define E_TABLE_COL_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TABLE_COL_TYPE, ETableColClass)) -#define E_IS_TABLE_COL(o) (GTK_CHECK_TYPE ((o), E_TABLE_COL_TYPE)) -#define E_IS_TABLE_COL_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_COL_TYPE)) - -typedef struct _ETableCol ETableCol; - -/* - * Information about a single column - */ -struct _ETableCol { - GtkObject base; - char *text; - short width; - short min_width; - short x; - GCompareFunc compare; - unsigned int selected:1; - unsigned int resizeable:1; - int col_idx; - - ECell *ecell; -}; - -typedef struct { - GtkObjectClass parent_class; -} ETableColClass; - -GtkType e_table_col_get_type (void); -ETableCol *e_table_col_new (int col_idx, const char *text, - int width, int min_width, - ECell *ecell, GCompareFunc compare, - gboolean resizable); -void e_table_col_destroy (ETableCol *etc); - - -#endif /* _E_TABLE_COL_H_ */ - diff --git a/widgets/e-table-column-item.c b/widgets/e-table-column-item.c deleted file mode 100644 index 0616327a93..0000000000 --- a/widgets/e-table-column-item.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * E-table-column-view.c: A canvas view of the TableColumn. - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * Copyright 1999, Helix Code, Inc. - */ -#include <config.h> -#include "e-table-column.h" -#include "e-table-column-view.h" - -#define PARENT_OBJECT_TYPE gnome_canvas_item_get_type () - -static GnomeCanvasItemClass *etci_parent_class; - -enum { - ARG_0, - ARG_TABLE_COLUMN -}; - -static void -etci_destroy (GtkObject *object) -{ - ETableColumnItem *etcv = E_TABLE_COLUMN_VIEW (object); - - gtk_object_unref (GTK_OBJECT (etcv)); - - if (GTK_OBJECT_CLASS (etcv_parent_class)->destroy) - (*GTK_OBJECT_CLASS (etcv_parent_class)->destroy) (object); -} - -static void -etci_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) -{ - if (GNOME_CANVAS_ITEM_CLASS(item_bar_parent_class)->update) - (*GNOME_CANVAS_ITEM_CLASS(item_bar_parent_class)->update)(item, affine, clip_path, flags); - - item->x1 = 0; - item->y1 = 0; - item->x2 = INT_MAX; - item->y2 = INT_MAX; - gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item); -} - -static void -etci_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) -{ - GnomeCanvasItem *item; - ETableColumnItem *etci; - int v; - - item = GNOME_CANVAS_ITEM (o); - etci = E_TABLE_COLUMN_ITEM (o); - - switch (arg_id){ - case ARG_TABLE_COLUMN: - etci->etci = GTK_VALUE_POINTER (*arg); - break; - } - etci_update (item, NULL, NULL, 0); -} - -static void -etci_realize (GnomeCanvasItem *item) -{ - ETableColumnItem *etci = E_TABLE_COLUMN_ITEM (item); - GdkWindow *window; - GdkColor c; - - if (GNOME_CANVAS_ITEM_CLASS (etci_parent_class)-> realize) - (*GNOME_CANVAS_ITEM_CLASS (etci_parent_class)->realize)(item); - - window = GTK_WIDGET (item->canvas)->window; - - etci->gc = gdk_gc_new (window); - gnome_canvas_get_color (item->canvas, "black", &c); - gdk_gc_set_foreground (etci->gc, &c); - - etci->normal_cursor = gdk_cursor_new (GDK_ARROW); -} - -static void -etci_unrealize (GnomeCanvasItem *item) -{ - ETableColumnItem *etci = E_TABLE_COLUMN_ITEM (item); - - gdk_gc_unref (etci->gc); - etci->gc = NULL; - - gdk_cursor_destroy (etci->change_cursor); - etci->change_cursor = NULL; - - gdk_cursor_destroy (etci->normal_cursor); - etci->normal_cursor = NULL; - - if (GNOME_CANVAS_ITEM_CLASS (etci_parent_class)->unrealize) - (*GNOME_CANVAS_ITEM_CLASS (etci_parent_class)->unrealize)(item); -} - -static void -etci_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x1, int y1, int width, int height) -{ - ETableColumnItem *etci = E_TABLE_COLUMN_ITEM (item); - GnomeCanvas *canvas = item->canvas; - GdkGC *gc; - const int cols = e_table_column_count (etci->etc); - int x2 = x1 + width; - int col, total; - - total = 0; - for (col = 0; col < cols; col++){ - ETableCol *col = e_table_column_get_column (etci->etc, col); - const int col_width = col->width; - - if (x1 > total + col_width) - continue; - - if (x2 < total) - return; - - gc = canvas->style->bg_gc [GTK_STATE_ACTIVE]; - gdk_draw_rectangle (drawble, gc, TRUE, - gtk_draw_shadow (canvas->style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, - x, y, width, height - } -} - -static double -etci_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, - GnomeCanvasItem **actual_item) -{ - *actual_item = *item; - return 0.0; -} - -static void -etci_event (GnomeCanvasItem *item, GdkEvent *e) -{ - switch (e->type){ - default: - return FALSE; - } - return TRUE; -} - -static void -etci_class_init (GtkObjectClass *object_class) -{ - GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class; - - object_class->destroy = etci_destroy; - object_class->set_arg = etci_set_arg; - - item_class->update = etci_update; - item_class->realize = etci_realize; - item_class->unrealize = etci_unrealize; - item_class->draw = etci_draw; - item_class->point = etci_point; - item_class->event = etci_event; - - gtk_object_add_arg_type ("ETableColumnItem::ETableColumn", GTK_TYPE_POINTER, - GTK_ARG_WRITABLE, ARG_TABLE_COLUMN); -} - -static void -etci_init (GnomeCanvasItem *item) -{ - item->x1 = 0; - item->y1 = 0; - item->x2 = 0; - item->y2 = 0; -} - -GtkType -e_table_column_view_get_type (void) -{ - static GtkType type = 0; - - if (!type){ - GtkTypeInfo info = { - "ETableColumnItem", - sizeof (ETableColumnItem), - sizeof (ETableColumnItemClass), - (GtkClassInitFunc) etci_class_init, - (GtkObjectInitFunc) etci_init, - NULL, /* reserved 1 */ - NULL, /* reserved 2 */ - (GtkClassInitFunc) NULL - }; - - type = gtk_type_unique (PARENT_OBJECT_TYPE, &info); - } - - return type; -} - - - diff --git a/widgets/e-table-column-item.h b/widgets/e-table-column-item.h deleted file mode 100644 index fd38681a73..0000000000 --- a/widgets/e-table-column-item.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _E_TABLE_COLUMN_VIEW_H -#defein _E_TABLE_COLUMN_VIEW_H - -#include "e-table-column.h" - -typedef struct { - GnomeCanvasItem parent; - ETableColumn *etc; - - GdkGC *gc; - GdkCursor *change_cursor, *normal_cursor; -} ETableColumnView; - -typedef struct { - GnomeCanvasItemClass parent_class; -} ETableColumnViewClass; - -GtkType e_table_column_item_get_type (void); - -#endif /* _E_TABLE_COLUMN_VIEW_H */ diff --git a/widgets/e-table-column-model.h b/widgets/e-table-column-model.h deleted file mode 100644 index 043dd783ca..0000000000 --- a/widgets/e-table-column-model.h +++ /dev/null @@ -1,5 +0,0 @@ - -class ETableColumnModel { - virtual void add_column (ETableCol *et) = 0; - virtual ETableCol *get_column (int column); - virtual diff --git a/widgets/e-table-column.c b/widgets/e-table-column.c deleted file mode 100644 index d17a285321..0000000000 --- a/widgets/e-table-column.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * e-table-column.c: TableColumn implementation - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * (C) 1999 Helix Code, Inc - */ -#include <config.h> -#include "e-table-column.h" - -enum { - STRUCTURE_CHANGE, - DIMENSION_CHANGE, - LAST_SIGNAL -}; - -static guint etc_signals [LAST_SIGNAL] = { 0, }; - -static GtkObjectClass *e_table_column_parent_class; - -static void -e_table_column_destroy (GtkObject *object) -{ - ETableColumn *etc = E_TABLE_COLUMN (object); - const int cols = etc->col_count; - - /* - * Destroy listeners - */ - for (l = etc->listeners; l; l = l->next) - g_free (l->data); - g_slist_free (etc->listeners); - etc->listeners = NULL; - - /* - * Destroy columns - */ - for (i = 0; i < cols; i++) - e_table_column_remove (etc, i); - - if (e_table_column_parent_class->destroy) - e_table_column_parent_class->destroy (object); -} - -static void -e_table_column_class_init (GtkObjectClass *object_class) -{ - object_class->destroy = e_table_column_destroy; - - e_table_column_parent_class = (gtk_type_class (gtk_object_get_type ())); - - etc_signals [STRUCTURE_CHANGE] = - gtk_signal_new ("structure_change", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableColumn, structure_change), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - etc_signals [DIMENSION_CHANGE] = - gtk_signal_new ("dimension_change", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableColumn, dimension_change), - gtk_marshal_NONE__INT, - GTK_TYPE_NONE, 1, GTK_TYPE_INT); - - gtk_object_class_add_signals (object_class, etc_signals, LAST_SIGNAL); -} - -GtkType -e_table_column_get_type (void) -{ - static GtkType type = 0; - - if (!type){ - GtkTypeInfo info = { - "ETableColumn", - sizeof (ETableColumn), - sizeof (ETableColumnClass), - (GtkClassInitFunc) e_table_column_class_init, - (GtkObjectInitFunc) NULL, - NULL, /* reserved 1 */ - NULL, /* reserved 2 */ - (GtkClassInitFunc) NULL - }; - - type = gtk_type_unique (gtk_object_get_type (), &info); - } - - return type; -} - -static void -etc_do_insert (ETableColumn *etc, int pos, ETableCol *val) -{ - memcpy (&etc->columns [pos+1], &etc->columns [pos], - sizeof (ETableCol *) * (etc->col_count - pos)); - etc->columns [pos] = val; -} - -void -e_table_column_add_column (ETableColumn *etc, ETableCol *tc, int pos) -{ - ETableCol **new_ptr; - - g_return_if_fail (etc != NULL); - g_return_if_fail (E_IS_TABLE_COLUMN (etc)); - g_return_if_fail (tc != NULL); - g_return_if_fail (pos >= 0 && pos < etc->col_count); - - if (pos == -1) - pos = etc->col_count; - etc->columns = g_realloc (etc->columns, sizeof (ETableCol *) * (etc->col_count + 1)); - etc_do_insert (etc, pos, tc); - etc->col_count++; - - gtk_signal_emit (GTK_OBJECT (etc), etc_signals [STRUCTURE_CHANGE]); -} - -ETableCol * -e_table_column_get_column (ETableColumn *etc, int column) -{ - g_return_val_if_fail (etc != NULL, NULL); - g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), NULL); - - if (column < 0) - return NULL; - - if (column >= etc->col_count) - return NULL; - - return etc->columns [column]; -} - -int -e_table_column_count (ETableColumn *etc) -{ - g_return_val_if_fail (etc != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0); - - return etc->col_count; -} - -int -e_table_column_index (ETableColumn *etc, const char *identifier) -{ - int i; - - g_return_val_if_fail (etc != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0); - g_return_val_if_fail (identifier != NULL, 0); - - for (i = 0; i < etc->col_count; i++){ - ETableCol *tc = etc->columns [i]; - - if (strcmp (i->id, identifier) == 0) - return i; - } - - return -1; -} - -int -e_table_column_get_index_at (ETableColumn *etc, int x_offset) -{ - int i, total; - - g_return_val_if_fail (etc != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0); - g_return_val_if_fail (identifier != NULL, 0); - - total = 0; - for (i = 0; i < etc->col_count; i++){ - total += etc->columns [i]->width; - - if (x_offset < total) - return i; - } - - return -1; -} - -ETableCol ** -e_table_column_get_columns (ETableColumn *etc) -{ - ETableCol **ret; - int i; - - g_return_val_if_fail (etc != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0); - - ret = g_new (ETableCol *, etc->col_count + 1); - memcpy (ret, etc->columns, sizeof (ETableCol *) * etc->col_count); - ret [etc->col_count] = NULL; - - return ret; -} - -gboolean -e_table_column_selection_ok (ETableColumn *etc) -{ - g_return_val_if_fail (etc != NULL, FALSE); - g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), FALSE); - - return etc->selectable; -} - -int -ve_table_column_get_selected (ETableColumn *etc) -{ - int i; - int selected = 0; - - g_return_val_if_fail (etc != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0); - - for (i = 0; i < etc->col_count; i++){ - if (etc->columns [i]->selected) - selected++; - } - - return selected; -} - -int -e_table_column_total_width (ETableColumn *etc) -{ - int total; - - g_return_val_if_fail (etc != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_COLUMN (etc), 0); - - total = 0; - for (i = 0; i < etc->col_count; i++) - total += etc->columns [i].width; - - return total; -} - -static void -etc_do_remove (ETableColumn *etc, int idx) -{ - memcpy (&etc->columns [idx], &etc->columns [idx+1], - sizeof (ETableCol *) * etc->col_count - idx); - etc->col_count--; -} - -void -e_table_column_move (ETableColumn *etc, int source_index, int target_index) -{ - g_return_if_fail (etc != NULL); - g_return_if_fail (E_IS_TABLE_COLUMN (etc)); - g_return_if_fail (source_index >= 0); - g_return_if_fail (target_index >= 0); - g_return_if_fail (source_index < etc->col_count); - g_return_if_fail (target_index < etc->col_count); - - old = etc->columns [source_index]; - etc_do_remove (etc, source_index); - etc_do_insert (etc, target_index, old); - gtk_signal_emit (GTK_OBJECT (etc), etc_signals [STRUCTURE_CHANGE]); -} - -void -e_table_column_remove (ETableColumn *etc, int idx) -{ - g_return_if_fail (etc != NULL); - g_return_if_fail (E_IS_TABLE_COLUMN (etc)); - g_return_if_fail (idx >= 0); - g_return_if_fail (idx < etc->col_count); - - etc_do_remove (etc, idx); - gtk_signal_emit (GTK_OBJECT (etc), etc_signals [STRUCTURE_CHANGE]); -} - -void -e_table_column_set_selection (ETableColumn *etc, gboolean allow_selection); -{ -} - -void -e_table_column_set_size (ETableColumn *etc, int idx, int size) -{ - g_return_if_fail (etc != NULL); - g_return_if_fail (E_IS_TABLE_COLUMN (etc)); - g_return_if_fail (idx >= 0); - g_return_if_fail (idx < etc->col_count); - g_return_if_fail (size > 0); - - etc->columns [idx]->width = size; - gtk_signal_emit (GTK_OBJECT (etc), etc_signals [SIZE_CHANGE], idx); -} diff --git a/widgets/e-table-group.c b/widgets/e-table-group.c deleted file mode 100644 index 8765c3b83c..0000000000 --- a/widgets/e-table-group.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * E-Table-Group.c: Implements the grouping objects for elements on a table - * - * Author: - * Miguel de Icaza (miguel@gnu.org() - * - * Copyright 1999, Helix Code, Inc. - */ - -#include <config.h> -#include <gtk/gtksignal.h> -#include "e-table-group.h" -#include "e-table-item.h" -#include <libgnomeui/gnome-canvas-rect-ellipse.h> -#include "e-util.h" - -#define TITLE_HEIGHT 16 -#define GROUP_INDENT 10 - -#define PARENT_TYPE gnome_canvas_group_get_type () - -static GnomeCanvasGroupClass *etg_parent_class; - -enum { - HEIGHT_CHANGED, - LAST_SIGNAL -}; - -static gint etg_signals [LAST_SIGNAL] = { 0, }; - -static void -etg_destroy (GtkObject *object) -{ - ETableGroup *etg = E_TABLE_GROUP (object); - - GTK_OBJECT_CLASS (etg_parent_class)->destroy (object); -} - -static void -etg_dim (ETableGroup *etg, int *width, int *height) -{ - GSList *l; - - *width = *height = 0; - - for (l = etg->children; l; l = l->next){ - GnomeCanvasItem *child = l->data; - - *height += child->y2 - child->y1; - *width += child->x2 - child->x1; - } - - if (!etg->transparent){ - *height += TITLE_HEIGHT; - *width += GROUP_INDENT; - } -} - -void -e_table_group_construct (GnomeCanvasGroup *parent, ETableGroup *etg, - ETableCol *ecol, gboolean open, - gboolean transparent) -{ - gnome_canvas_item_constructv (GNOME_CANVAS_ITEM (etg), parent, 0, NULL); - - etg->ecol = ecol; - etg->open = open; - etg->transparent = transparent; - - etg_dim (etg, &etg->width, &etg->height); - - if (!etg->transparent) - etg->rect = gnome_canvas_item_new ( - GNOME_CANVAS_GROUP (etg), - gnome_canvas_rect_get_type (), - "fill_color", "gray", - "outline_color", "gray20", - "x1", 0.0, - "y1", 0.0, - "x2", (double) etg->width, - "y2", (double) etg->height, - NULL); - -#if 0 - /* - * Reparent the child into our space. - */ - gnome_canvas_item_reparent (child, GNOME_CANVAS_GROUP (etg)); - - gnome_canvas_item_set ( - child, - "x", (double) GROUP_INDENT, - "y", (double) TITLE_HEIGHT, - NULL); - - /* - * Force dimension computation - */ - GNOME_CANVAS_ITEM_CLASS (etg_parent_class)->update ( - GNOME_CANVAS_ITEM (etg), NULL, NULL, GNOME_CANVAS_UPDATE_REQUESTED); -#endif -} - -GnomeCanvasItem * -e_table_group_new (GnomeCanvasGroup *parent, ETableCol *ecol, - gboolean open, gboolean transparent) -{ - ETableGroup *etg; - - g_return_val_if_fail (parent != NULL, NULL); - g_return_val_if_fail (ecol != NULL, NULL); - - etg = gtk_type_new (e_table_group_get_type ()); - - e_table_group_construct (parent, etg, ecol, open, transparent); - - return GNOME_CANVAS_ITEM (etg); -} - -static void -etg_relayout (GnomeCanvasItem *eti, ETableGroup *etg) -{ - GSList *l; - int height = etg->transparent ? 0 : GROUP_INDENT; - gboolean move = FALSE; - - printf ("Relaying out\n"); - - for (l = etg->children; l->next; l = l->next){ - GnomeCanvasItem *child = l->data; - - height += child->y2 - child->y1; - - if (child == eti) - move = TRUE; - - if (move){ - printf ("Moving item %p\n", child); - gnome_canvas_item_set ( - child, - "y", (double) height, - NULL); - } - } - if (height != etg->height){ - etg->height = height; - gtk_signal_emit (GTK_OBJECT (etg), etg_signals [HEIGHT_CHANGED]); - } -} - -void -e_table_group_add (ETableGroup *etg, GnomeCanvasItem *item) -{ - double x1, y1, x2, y2; - - g_return_if_fail (etg != NULL); - g_return_if_fail (item != NULL); - g_return_if_fail (E_IS_TABLE_GROUP (etg)); - g_return_if_fail (GNOME_IS_CANVAS_ITEM (item)); - - etg->children = g_slist_append (etg->children, item); - - GNOME_CANVAS_ITEM_CLASS (GTK_OBJECT (etg)->klass)->bounds (etg, &x1, &y1, &x2, &y2); - - if (GTK_OBJECT (etg)->flags & GNOME_CANVAS_ITEM_REALIZED){ - GSList *l; - int height = etg->transparent ? 0 : TITLE_HEIGHT; - int x = etg->transparent ? 0 : GROUP_INDENT; - - for (l = etg->children; l->next; l = l->next){ - GnomeCanvasItem *child = l->data; - - height += child->y2 - child->y1; - } - - printf ("Positioning item %p at %d\n", item, height); - gnome_canvas_item_set ( - item, - "y", (double) height, - "x", (double) x, - NULL); - - - if (E_IS_TABLE_ITEM (item)){ - - printf ("Table item! ---------\n"); - gtk_signal_connect (GTK_OBJECT (item), "height_changed", - GTK_SIGNAL_FUNC (etg_relayout), etg); - } - } -} - -static void -etg_realize (GnomeCanvasItem *item) -{ - ETableGroup *etg = E_TABLE_GROUP (item); - GSList *l; - int height = 0; - - GNOME_CANVAS_ITEM_CLASS (etg_parent_class)->realize (item); - - for (l = etg->children; l; l = l->next){ - GnomeCanvasItem *child = l->data; - - printf ("During realization for child %p -> %d\n", child, height); - gnome_canvas_item_set ( - child, - "y", (double) height, - NULL); - - height += child->y2 - child->y1; - } -} - -static void -etg_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) -{ - ETableGroup *etg = E_TABLE_GROUP (item); - - GNOME_CANVAS_ITEM_CLASS (etg_parent_class)->update (item, affine, clip_path, flags); - - if (!etg->transparent){ - int current_width, current_height; - - etg_dim (etg, ¤t_width, ¤t_height); - - if ((current_height != etg->height) || (current_width != etg->width)){ - etg->width = current_width; - etg->height = current_height; - - gnome_canvas_item_set ( - etg->rect, - "x1", 0.0, - "y1", 0.0, - "x2", (double) etg->width, - "y2", (double) etg->height, - NULL); - } - } -} - -static void -etg_class_init (GtkObjectClass *object_class) -{ - GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class; - - object_class->destroy = etg_destroy; - - item_class->realize = etg_realize; - item_class->update = etg_update; - - etg_parent_class = gtk_type_class (PARENT_TYPE); - - etg_signals [HEIGHT_CHANGED] = - gtk_signal_new ("height_changed", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableGroupClass, height_changed), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - - gtk_object_class_add_signals (object_class, etg_signals, LAST_SIGNAL); - -} - -E_MAKE_TYPE (e_table_group, "ETableGroup", ETableGroup, etg_class_init, NULL, PARENT_TYPE); - - - diff --git a/widgets/e-table-group.h b/widgets/e-table-group.h deleted file mode 100644 index 468d5dd794..0000000000 --- a/widgets/e-table-group.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _E_TABLE_TREE_H_ -#define _E_TABLE_TREE_H_ - -#include <libgnomeui/gnome-canvas.h> -#include "e-table-model.h" -#include "e-table-header.h" - -#define E_TABLE_GROUP_TYPE (e_table_group_get_type ()) -#define E_TABLE_GROUP(o) (GTK_CHECK_CAST ((o), E_TABLE_GROUP_TYPE, ETableGroup)) -#define E_TABLE_GROUP_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TABLE_GROUP_TYPE, ETableGroupClass)) -#define E_IS_TABLE_GROUP(o) (GTK_CHECK_TYPE ((o), E_TABLE_GROUP_TYPE)) -#define E_IS_TABLE_GROUP_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_GROUP_TYPE)) - -typedef struct { - GnomeCanvasGroup group; - - /* - * The ETableCol used to group this set - */ - ETableCol *ecol; - - /* - * The canvas rectangle that contains the children - */ - GnomeCanvasItem *rect; - - /* - * Dimensions of the ETableGroup - */ - int width, height; - - /* - * State: the ETableGroup is open or closed - */ - guint open:1; - - /* - * Whether we should add indentation and open/close markers, - * or if we just act as containers of subtables. - */ - guint transparent:1; - - /* - * List of GnomeCanvasItems we stack - */ - GSList *children; -} ETableGroup; - -typedef struct { - GnomeCanvasGroupClass parent_class; - void (*height_changed) (ETableGroup *etg); -} ETableGroupClass; - -GnomeCanvasItem *e_table_group_new (GnomeCanvasGroup *parent, ETableCol *ecol, - gboolean open, gboolean transparent); -void e_table_group_construct (GnomeCanvasGroup *parent, ETableGroup *etg, - ETableCol *ecol, gboolean open, gboolean transparent); - -void e_table_group_add (ETableGroup *etg, GnomeCanvasItem *child); - -GtkType e_table_group_get_type (void); - -#endif /* _E_TABLE_TREE_H_ */ diff --git a/widgets/e-table-header-item.c b/widgets/e-table-header-item.c deleted file mode 100644 index 7cea9ae7a0..0000000000 --- a/widgets/e-table-header-item.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * E-table-column-view.c: A canvas item based view of the ETableColumn. - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * Copyright 1999, Helix Code, Inc. - */ -#include <config.h> -#include <gtk/gtksignal.h> -#include <gtk/gtkdnd.h> -#include <libgnomeui/gnome-canvas.h> -#include <libgnomeui/gnome-canvas-util.h> -#include <libgnomeui/gnome-canvas-polygon.h> -#include <libgnomeui/gnome-canvas-rect-ellipse.h> -#include "e-table-header.h" -#include "e-table-header-item.h" -#include "e-table-col-dnd.h" -#include "e-cursors.h" - -#include "add-col.xpm" -#include "remove-col.xpm" - -/* Padding above and below of the string in the header display */ -#define PADDING 4 - -/* Defines the tolerance for proximity of the column division to the cursor position */ -#define TOLERANCE 2 - -#define ETHI_RESIZING(x) ((x)->resize_col != -1) - -#define PARENT_OBJECT_TYPE gnome_canvas_item_get_type () - -#define ELEMENTS(x) (sizeof (x) / sizeof (x[0])) - -static GnomeCanvasItemClass *ethi_parent_class; - -/* - * DnD icons - */ -static GdkColormap *dnd_colormap; -static GdkPixmap *remove_col_pixmap, *remove_col_mask; -static GdkPixmap *add_col_pixmap, *add_col_mask; - -enum { - ARG_0, - ARG_TABLE_HEADER, - ARG_TABLE_X, - ARG_TABLE_Y, - ARG_TABLE_FONTSET -}; - -static GtkTargetEntry ethi_drag_types [] = { - { TARGET_ETABLE_COL_TYPE, 0, TARGET_ETABLE_COL_HEADER }, -}; - -static GtkTargetEntry ethi_drop_types [] = { - { TARGET_ETABLE_COL_TYPE, 0, TARGET_ETABLE_COL_HEADER }, -}; - -static void -ethi_destroy (GtkObject *object) -{ - ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (object); - - gtk_object_unref (GTK_OBJECT (ethi->eth)); - - if (GTK_OBJECT_CLASS (ethi_parent_class)->destroy) - (*GTK_OBJECT_CLASS (ethi_parent_class)->destroy) (object); -} - -static void -ethi_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) -{ - ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item); - - if (GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->update) - (*GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->update)(item, affine, clip_path, flags); - - item->x1 = ethi->x1; - item->y1 = ethi->y1; - item->x2 = ethi->x1 + ethi->width; - item->y2 = ethi->y1 + ethi->height; - - gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item); -} - -static void -ethi_font_load (ETableHeaderItem *ethi, char *font) -{ - if (ethi->font) - gdk_font_unref (ethi->font); - - ethi->font = gdk_fontset_load (font); - if (ethi->font == NULL) - ethi->font = gdk_font_load ("fixed"); - - ethi->height = ethi->font->ascent + ethi->font->descent + PADDING; -} - -static void -ethi_drop_table_header (ETableHeaderItem *ethi) -{ - GtkObject *header; - - if (!ethi->eth) - return; - - header = GTK_OBJECT (ethi->eth); - gtk_signal_disconnect (header, ethi->structure_change_id); - gtk_signal_disconnect (header, ethi->dimension_change_id); - - gtk_object_unref (header); - ethi->eth = NULL; - ethi->width = 0; -} - -static void -structure_changed (ETableHeader *header, ETableHeaderItem *ethi) -{ - ethi->width = e_table_header_total_width (header); - - ethi_update (GNOME_CANVAS_ITEM (ethi), NULL, NULL, 0); -} - -static void -dimension_changed (ETableHeader *header, int col, ETableHeaderItem *ethi) -{ - ethi->width = e_table_header_total_width (header); - - ethi_update (GNOME_CANVAS_ITEM (ethi), NULL, NULL, 0); -} - -static void -ethi_add_table_header (ETableHeaderItem *ethi, ETableHeader *header) -{ - ethi->eth = header; - gtk_object_ref (GTK_OBJECT (ethi->eth)); - ethi->width = e_table_header_total_width (header); - - ethi->structure_change_id = gtk_signal_connect ( - GTK_OBJECT (header), "structure_change", - GTK_SIGNAL_FUNC(structure_changed), ethi); - ethi->dimension_change_id = gtk_signal_connect ( - GTK_OBJECT (header), "dimension_change", - GTK_SIGNAL_FUNC(dimension_changed), ethi); -} - -static void -ethi_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) -{ - GnomeCanvasItem *item; - ETableHeaderItem *ethi; - - item = GNOME_CANVAS_ITEM (o); - ethi = E_TABLE_HEADER_ITEM (o); - - switch (arg_id){ - case ARG_TABLE_HEADER: - ethi_drop_table_header (ethi); - ethi_add_table_header (ethi, GTK_VALUE_POINTER (*arg)); - break; - - case ARG_TABLE_X: - ethi->x1 = GTK_VALUE_INT (*arg); - break; - - case ARG_TABLE_Y: - ethi->y1 = GTK_VALUE_INT (*arg); - break; - - case ARG_TABLE_FONTSET: - ethi_font_load (ethi, GTK_VALUE_STRING (*arg)); - break; - - } - ethi_update (item, NULL, NULL, 0); -} - -static int -ethi_find_col_by_x (ETableHeaderItem *ethi, int x) -{ - const int cols = e_table_header_count (ethi->eth); - int x1 = ethi->x1; - int col; - - if (x < x1) - return -1; - - for (col = 0; col < cols; col++){ - ETableCol *ecol = e_table_header_get_column (ethi->eth, col); - - if ((x >= x1) && (x <= x1 + ecol->width)) - return col; - - x1 += ecol->width; - } - return -1; -} - -static void -ethi_remove_drop_marker (ETableHeaderItem *ethi) -{ - if (ethi->drag_mark == -1) - return; - - ethi->drag_mark = -1; - gtk_object_destroy (GTK_OBJECT (ethi->drag_mark_item)); - ethi->drag_mark_item = NULL; -} - -static void -ethi_add_drop_marker (ETableHeaderItem *ethi, int col) -{ - GnomeCanvasPoints *points; - int x; - - if (ethi->drag_mark == col) - return; - - if (ethi->drag_mark_item) - gtk_object_destroy (GTK_OBJECT (ethi->drag_mark_item)); - - ethi->drag_mark = col; - - ethi->drag_mark_item = gnome_canvas_item_new ( - GNOME_CANVAS_GROUP (GNOME_CANVAS_ITEM (ethi)->canvas->root), - gnome_canvas_group_get_type (), - "x", 0, - "y", 0, - NULL); - - points = gnome_canvas_points_new (3); - - x = e_table_header_col_diff (ethi->eth, 0, col); - - points->coords [0] = ethi->x1 + x - 5; - points->coords [1] = ethi->y1; - points->coords [2] = points->coords [0] + 10; - points->coords [3] = points->coords [1]; - points->coords [4] = ethi->x1 + x; - points->coords [5] = ethi->y1 + 5; - - gnome_canvas_item_new ( - GNOME_CANVAS_GROUP (ethi->drag_mark_item), - gnome_canvas_polygon_get_type (), - "points", points, - "fill_color", "red", - NULL); - - points->coords [0] --; - points->coords [1] += ethi->height - 1; - points->coords [3] = points->coords [1]; - points->coords [5] = points->coords [1] - 6; - - gnome_canvas_item_new ( - GNOME_CANVAS_GROUP (ethi->drag_mark_item), - gnome_canvas_polygon_get_type (), - "points", points, - "fill_color", "red", - NULL); - - gnome_canvas_points_unref (points); -} - -#define gray50_width 2 -#define gray50_height 2 -static char gray50_bits [] = { - 0x02, 0x01, }; - -static void -ethi_add_destroy_marker (ETableHeaderItem *ethi) -{ - double x1; - - if (ethi->remove_item) - gtk_object_destroy (GTK_OBJECT (ethi->remove_item)); - - if (!ethi->stipple) - ethi->stipple = gdk_bitmap_create_from_data (NULL, gray50_bits, gray50_width, gray50_height); - - x1 = ethi->x1 + (double) e_table_header_col_diff (ethi->eth, 0, ethi->drag_col); - ethi->remove_item = gnome_canvas_item_new ( - GNOME_CANVAS_GROUP (GNOME_CANVAS_ITEM (ethi)->canvas->root), - gnome_canvas_rect_get_type (), - "x1", x1 + 1, - "y1", (double) ethi->y1 + 1, - "x2", (double) x1 + e_table_header_col_diff (ethi->eth, ethi->drag_col, ethi->drag_col+1) - 2, - "y2", (double) ethi->y1 + ethi->height - 2, - "fill_color", "red", - "fill_stipple", ethi->stipple, - NULL); -} - -static void -ethi_remove_destroy_marker (ETableHeaderItem *ethi) -{ - if (!ethi->remove_item) - return; - - gtk_object_destroy (GTK_OBJECT (ethi->remove_item)); - ethi->remove_item = NULL; -} - -static gboolean -ethi_drag_motion (GtkObject *canvas, GdkDragContext *context, - gint x, gint y, guint time, - ETableHeaderItem *ethi) -{ - - if ((x >= ethi->x1) && (x <= (ethi->x1 + ethi->width)) && - (y >= ethi->y1) && (y <= (ethi->y1 + ethi->height))){ - int col; - - col = ethi_find_col_by_x (ethi, x); - - if (col != -1){ - ethi_remove_destroy_marker (ethi); - ethi_add_drop_marker (ethi, col); - } else { - ethi_remove_drop_marker (ethi); - ethi_add_destroy_marker (ethi); - } - } else { - ethi_remove_drop_marker (ethi); - ethi_add_destroy_marker (ethi); - } - - gdk_drag_status (context, context->suggested_action, time); - - return TRUE; -} - -static void -ethi_drag_end (GtkWidget *canvas, GdkDragContext *context, ETableHeaderItem *ethi) -{ - ethi_remove_drop_marker (ethi); - ethi_remove_destroy_marker (ethi); - ethi->drag_col = -1; -} - -static void -ethi_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time, ETableHeaderItem *ethi) -{ - ethi_remove_drop_marker (ethi); - ethi_add_destroy_marker (ethi); -} - -static void -ethi_realize (GnomeCanvasItem *item) -{ - ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item); - GdkWindow *window; - GdkColor c; - - if (GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)-> realize) - (*GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->realize)(item); - - window = GTK_WIDGET (item->canvas)->window; - - ethi->gc = gdk_gc_new (window); - gnome_canvas_get_color (item->canvas, "black", &c); - gdk_gc_set_foreground (ethi->gc, &c); - - ethi->normal_cursor = gdk_cursor_new (GDK_ARROW); - - if (!ethi->font) - ethi_font_load (ethi, "fixed"); - - /* - * Now, configure DnD - */ - gtk_drag_dest_set (GTK_WIDGET (item->canvas), GTK_DEST_DEFAULT_ALL, - ethi_drop_types, ELEMENTS (ethi_drop_types), - GDK_ACTION_MOVE); - - ethi->drag_motion_id = gtk_signal_connect ( - GTK_OBJECT (item->canvas), "drag_motion", - GTK_SIGNAL_FUNC (ethi_drag_motion), ethi); - - ethi->drag_leave_id = gtk_signal_connect ( - GTK_OBJECT (item->canvas), "drag_leave", - GTK_SIGNAL_FUNC (ethi_drag_leave), ethi); - - ethi->drag_end_id = gtk_signal_connect ( - GTK_OBJECT (item->canvas), "drag_end", - GTK_SIGNAL_FUNC (ethi_drag_end), ethi); -} - -static void -ethi_unrealize (GnomeCanvasItem *item) -{ - ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item); - - gdk_gc_unref (ethi->gc); - ethi->gc = NULL; - - gdk_cursor_destroy (ethi->normal_cursor); - ethi->normal_cursor = NULL; - - gtk_signal_disconnect (GTK_OBJECT (item->canvas), ethi->drag_motion_id); - gtk_signal_disconnect (GTK_OBJECT (item->canvas), ethi->drag_end_id); - gtk_signal_disconnect (GTK_OBJECT (item->canvas), ethi->drag_leave_id); - - if (ethi->stipple){ - gdk_bitmap_unref (ethi->stipple); - ethi->stipple = NULL; - } - - if (GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->unrealize) - (*GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->unrealize)(item); -} - -static void -draw_button (ETableHeaderItem *ethi, ETableCol *col, - GdkDrawable *drawable, GdkGC *gc, GtkStyle *style, - int x, int y, int width, int height) -{ - GdkRectangle clip; - int xtra; - - gdk_draw_rectangle ( - drawable, gc, TRUE, - x + 1, y + 1, width - 2, height -2); - - gtk_draw_shadow ( - style, drawable, - GTK_STATE_NORMAL, GTK_SHADOW_OUT, - x , y, width, height); - - clip.x = x + 2; - clip.y = y + 2; - clip.width = width - 4; - clip.height = ethi->height; - - gdk_gc_set_clip_rectangle (ethi->gc, &clip); - - /* Center the thing */ - xtra = (clip.width - gdk_string_measure (ethi->font, col->text))/2; - - if (xtra < 0) - xtra = 0; - - /* Skip over border */ - x += xtra + 2; - - gdk_draw_text ( - drawable, ethi->font, - ethi->gc, x, y + ethi->height - PADDING, - col->text, strlen (col->text)); -} - -static void -ethi_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) -{ - ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item); - GnomeCanvas *canvas = item->canvas; - GdkGC *gc; - const int cols = e_table_header_count (ethi->eth); - int x1, x2; - int col; - -#if 0 - printf ("My coords are: %g %g %g %g\n", - item->x1, item->y1, item->x2, item->y2); -#endif - x1 = x2 = ethi->x1; - for (col = 0; col < cols; col++, x1 = x2){ - ETableCol *ecol = e_table_header_get_column (ethi->eth, col); - int col_width; - - if (col == ethi->resize_col) - col_width = ethi->resize_width; - else - col_width = ecol->width; - - x2 += col_width; - - if (x1 > (x + width)) - break; - - if (x2 < x) - continue; - - gc = GTK_WIDGET (canvas)->style->bg_gc [GTK_STATE_ACTIVE]; - - draw_button (ethi, ecol, drawable, gc, - GTK_WIDGET (canvas)->style, - x1 - x, ethi->y1 - y, col_width, ethi->height); - } -} - -static double -ethi_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, - GnomeCanvasItem **actual_item) -{ - *actual_item = item; - return 0.0; -} - -/* - * is_pointer_on_division: - * - * Returns whether @pos is a column header division; If @the_total is not NULL, - * then the actual position is returned here. If @return_ecol is not NULL, - * then the ETableCol that actually contains this point is returned here - */ -static gboolean -is_pointer_on_division (ETableHeaderItem *ethi, int pos, int *the_total, int *return_col) -{ - const int cols = e_table_header_count (ethi->eth); - int col, total; - - total = 0; - for (col = 0; col < cols; col++){ - ETableCol *ecol = e_table_header_get_column (ethi->eth, col); - - total += ecol->width; - - if ((total - TOLERANCE < pos ) && (pos < total + TOLERANCE)){ - if (return_col) - *return_col = col; - if (the_total) - *the_total = total; - - return TRUE; - } - - if (total > pos + TOLERANCE) - return FALSE; - } - - return FALSE; -} - -#define convert(c,sx,sy,x,y) gnome_canvas_w2c (c,sx,sy,x,y) - -static void -set_cursor (ETableHeaderItem *ethi, int pos) -{ - GtkWidget *canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas); - - /* We might be invoked before we are realized */ - if (!canvas->window) - return; - - if (is_pointer_on_division (ethi, pos, NULL, NULL)) - e_cursor_set (canvas->window, E_CURSOR_SIZE_X); - else - e_cursor_set (canvas->window, E_CURSOR_ARROW); -} - -static void -ethi_request_redraw (ETableHeaderItem *ethi) -{ - GnomeCanvas *canvas = GNOME_CANVAS_ITEM (ethi)->canvas; - - /* - * request a redraw - */ - gnome_canvas_request_redraw ( - canvas, ethi->x1, ethi->y1, ethi->x1 + ethi->width, ethi->x1 + ethi->height); -} - -static void -ethi_end_resize (ETableHeaderItem *ethi, int new_size) -{ - e_table_header_set_size (ethi->eth, ethi->resize_col, new_size); - - ethi->resize_col = -1; - ethi_request_redraw (ethi); -} - -static gboolean -ethi_maybe_start_drag (ETableHeaderItem *ethi, GdkEventMotion *event) -{ - if (!ethi->maybe_drag) - return FALSE; - - if (MAX (abs (ethi->click_x - event->x), - abs (ethi->click_y - event->y)) <= 3) - return FALSE; - - return TRUE; -} - -static void -ethi_start_drag (ETableHeaderItem *ethi, GdkEvent *event) -{ - GtkWidget *widget = GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas); - GtkTargetList *list; - GdkDragContext *context; - - ethi->drag_col = ethi_find_col_by_x (ethi, event->motion.x); - if (ethi->drag_col == -1) - return; - - list = gtk_target_list_new (ethi_drag_types, ELEMENTS (ethi_drag_types)); - context = gtk_drag_begin (widget, list, GDK_ACTION_MOVE, 1, event); - ethi->maybe_drag = FALSE; -} - -/* - * Handles the events on the ETableHeaderItem, particularly it handles resizing - */ -static int -ethi_event (GnomeCanvasItem *item, GdkEvent *e) -{ - ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item); - GnomeCanvas *canvas = item->canvas; - const gboolean resizing = ETHI_RESIZING (ethi); - int x, y, start, col; - - switch (e->type){ - case GDK_ENTER_NOTIFY: - convert (canvas, e->crossing.x, e->crossing.y, &x, &y); - set_cursor (ethi, x); - break; - - case GDK_LEAVE_NOTIFY: - e_cursor_set (GTK_WIDGET (canvas)->window, E_CURSOR_ARROW); - break; - - case GDK_MOTION_NOTIFY: - convert (canvas, e->motion.x, e->motion.y, &x, &y); - if (resizing){ - int new_width; - - if (ethi->resize_guide == NULL){ - /* Quick hack until I actually bind the views */ - ethi->resize_guide = GINT_TO_POINTER (1); - gnome_canvas_item_grab (item, - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_RELEASE_MASK, - e_cursor_get (E_CURSOR_SIZE_X), - e->button.time); - } - - new_width = x - ethi->resize_start_pos; - if (new_width <= 0) - break; - - if (new_width < ethi->resize_min_width) - break; - - ethi_request_redraw (ethi); - - ethi->resize_width = new_width; - e_table_header_set_size (ethi->eth, ethi->resize_col, ethi->resize_width); - - ethi_request_redraw (ethi); - } else if (ethi_maybe_start_drag (ethi, &e->motion)){ - ethi_start_drag (ethi, e); - } else - set_cursor (ethi, x); - break; - - case GDK_BUTTON_PRESS: - convert (canvas, e->button.x, e->button.y, &x, &y); - - if (is_pointer_on_division (ethi, x, &start, &col)){ - ETableCol *ecol; - - /* - * Record the important bits. - * - * By setting resize_pos to a non -1 value, - * we know that we are being resized (used in the - * other event handlers). - */ - ecol = e_table_header_get_column (ethi->eth, col); - - if (!ecol->resizeable) - break; - ethi->resize_col = col; - ethi->resize_width = ecol->width; - ethi->resize_start_pos = start - ecol->width; - ethi->resize_min_width = ecol->min_width; - } else { - if (e->button.button == 1){ - ethi->click_x = e->button.x; - ethi->click_y = e->button.y; - ethi->maybe_drag = TRUE; - } - } - break; - - case GDK_2BUTTON_PRESS: - if (!resizing) - break; - - if (e->button.button != 1) - break; - break; - - case GDK_BUTTON_RELEASE: { - gboolean needs_ungrab = FALSE; - - if (ethi->resize_col != -1){ - needs_ungrab = (ethi->resize_guide != NULL); - ethi_end_resize (ethi, ethi->resize_width); - } - if (needs_ungrab) - gnome_canvas_item_ungrab (item, e->button.time); - - ethi->maybe_drag = FALSE; - break; - } - - default: - return FALSE; - } - return TRUE; -} - -static void -ethi_class_init (GtkObjectClass *object_class) -{ - GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class; - - ethi_parent_class = gtk_type_class (PARENT_OBJECT_TYPE); - - object_class->destroy = ethi_destroy; - object_class->set_arg = ethi_set_arg; - - item_class->update = ethi_update; - item_class->realize = ethi_realize; - item_class->unrealize = ethi_unrealize; - item_class->draw = ethi_draw; - item_class->point = ethi_point; - item_class->event = ethi_event; - - gtk_object_add_arg_type ("ETableHeaderItem::ETableHeader", GTK_TYPE_POINTER, - GTK_ARG_WRITABLE, ARG_TABLE_HEADER); - gtk_object_add_arg_type ("ETableHeaderItem::x", GTK_TYPE_INT, - GTK_ARG_WRITABLE, ARG_TABLE_X); - gtk_object_add_arg_type ("ETableHeaderItem::y", GTK_TYPE_INT, - GTK_ARG_WRITABLE, ARG_TABLE_Y); - gtk_object_add_arg_type ("ETableHeaderItem::fontset", GTK_TYPE_STRING, - GTK_ARG_WRITABLE, ARG_TABLE_FONTSET); - - /* - * Create our pixmaps for DnD - */ - dnd_colormap = gtk_widget_get_default_colormap (); - remove_col_pixmap = gdk_pixmap_colormap_create_from_xpm_d ( - NULL, dnd_colormap, - &remove_col_mask, NULL, remove_col_xpm); - - add_col_pixmap = gdk_pixmap_colormap_create_from_xpm_d ( - NULL, dnd_colormap, - &add_col_mask, NULL, add_col_xpm); -} - -static void -ethi_init (GnomeCanvasItem *item) -{ - ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item); - - ethi->resize_col = -1; - - item->x1 = 0; - item->y1 = 0; - item->x2 = 0; - item->y2 = 0; - - ethi->drag_col = -1; - ethi->drag_mark = -1; -} - -GtkType -e_table_header_item_get_type (void) -{ - static GtkType type = 0; - - if (!type){ - GtkTypeInfo info = { - "ETableHeaderItem", - sizeof (ETableHeaderItem), - sizeof (ETableHeaderItemClass), - (GtkClassInitFunc) ethi_class_init, - (GtkObjectInitFunc) ethi_init, - NULL, /* reserved 1 */ - NULL, /* reserved 2 */ - (GtkClassInitFunc) NULL - }; - - type = gtk_type_unique (PARENT_OBJECT_TYPE, &info); - } - - return type; -} - diff --git a/widgets/e-table-header-item.h b/widgets/e-table-header-item.h deleted file mode 100644 index 5522d24fae..0000000000 --- a/widgets/e-table-header-item.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _E_TABLE_HEADER_ITEM_H_ -#define _E_TABLE_HEADER_ITEM_H_ - -#include <libgnomeui/gnome-canvas.h> -#include "e-table-header.h" - -#define E_TABLE_HEADER_ITEM_TYPE (e_table_header_item_get_type ()) -#define E_TABLE_HEADER_ITEM(o) (GTK_CHECK_CAST ((o), E_TABLE_HEADER_ITEM_TYPE, ETableHeaderItem)) -#define E_TABLE_HEADER_ITEM_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TABLE_HEADER_ITEM_TYPE, ETableHeaderItemClass)) -#define E_IS_TABLE_HEADER_ITEM(o) (GTK_CHECK_TYPE ((o), E_TABLE_HEADER_ITEM_TYPE)) -#define E_IS_TABLE_HEADER_ITEM_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_HEADER_ITEM_TYPE)) - -typedef struct { - GnomeCanvasItem parent; - ETableHeader *eth; - - GdkGC *gc; - GdkCursor *change_cursor, *normal_cursor; - - short x1, y1, height, width; - GdkFont *font; - - /* - * Used during resizing; Could be shorts - */ - int resize_col; - int resize_width; - int resize_start_pos; - int resize_min_width; - - GtkObject *resize_guide; - - /* - * Ids - */ - int structure_change_id, dimension_change_id; - - /* - * For dragging columns - */ - guint maybe_drag:1; - guint dnd_ready:1; - int click_x, click_y; - int drag_col, drag_mark; - guint drag_motion_id, drag_end_id, drag_leave_id; - GnomeCanvasItem *drag_mark_item, *remove_item; - GdkBitmap *stipple; -} ETableHeaderItem; - -typedef struct { - GnomeCanvasItemClass parent_class; -} ETableHeaderItemClass; - -GtkType e_table_header_item_get_type (void); - -#endif /* _E_TABLE_HEADER_ITEM_H_ */ diff --git a/widgets/e-table-header.c b/widgets/e-table-header.c deleted file mode 100644 index 7c54bd936e..0000000000 --- a/widgets/e-table-header.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * E-table-col-head.c: TableColHead implementation - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * (C) 1999 Helix Code, Inc - */ -#include <config.h> -#include <gtk/gtkobject.h> -#include <gtk/gtksignal.h> -#include "e-table-header.h" - -enum { - STRUCTURE_CHANGE, - DIMENSION_CHANGE, - LAST_SIGNAL -}; - -static guint eth_signals [LAST_SIGNAL] = { 0, }; - -static GtkObjectClass *e_table_header_parent_class; - -static void -e_table_header_destroy (GtkObject *object) -{ - ETableHeader *eth = E_TABLE_HEADER (object); - const int cols = eth->col_count; - int i; - - /* - * Destroy columns - */ - for (i = 0; i < cols; i++){ - e_table_header_remove (eth, i); - } - - if (e_table_header_parent_class->destroy) - e_table_header_parent_class->destroy (object); -} - -static void -e_table_header_class_init (GtkObjectClass *object_class) -{ - object_class->destroy = e_table_header_destroy; - - e_table_header_parent_class = (gtk_type_class (gtk_object_get_type ())); - - eth_signals [STRUCTURE_CHANGE] = - gtk_signal_new ("structure_change", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableHeaderClass, structure_change), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - eth_signals [DIMENSION_CHANGE] = - gtk_signal_new ("dimension_change", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableHeaderClass, dimension_change), - gtk_marshal_NONE__INT, - GTK_TYPE_NONE, 1, GTK_TYPE_INT); - - gtk_object_class_add_signals (object_class, eth_signals, LAST_SIGNAL); -} - -GtkType -e_table_header_get_type (void) -{ - static GtkType type = 0; - - if (!type){ - GtkTypeInfo info = { - "ETableHeader", - sizeof (ETableHeader), - sizeof (ETableHeaderClass), - (GtkClassInitFunc) e_table_header_class_init, - (GtkObjectInitFunc) NULL, - NULL, /* reserved 1 */ - NULL, /* reserved 2 */ - (GtkClassInitFunc) NULL - }; - - type = gtk_type_unique (gtk_object_get_type (), &info); - } - - return type; -} - -ETableHeader * -e_table_header_new (void) -{ - ETableHeader *eth; - - eth = gtk_type_new (e_table_header_get_type ()); - - return eth; -} - -static void -eth_do_insert (ETableHeader *eth, int pos, ETableCol *val) -{ - memcpy (ð->columns [pos+1], ð->columns [pos], - sizeof (ETableCol *) * (eth->col_count - pos)); - eth->columns [pos] = val; -} - -static void -eth_update_offsets (ETableHeader *eth) -{ - int i; - int x = 0; - - for (i = 0; i < eth->col_count; i++){ - ETableCol *etc = eth->columns [i]; - - etc->x = x; - x += etc->width; - } -} - -void -e_table_header_add_column (ETableHeader *eth, ETableCol *tc, int pos) -{ - g_return_if_fail (eth != NULL); - g_return_if_fail (E_IS_TABLE_HEADER (eth)); - g_return_if_fail (tc != NULL); - g_return_if_fail (E_IS_TABLE_COL (tc)); - g_return_if_fail (pos >= -1 && pos <= eth->col_count); - - if (pos == -1) - pos = eth->col_count; - eth->columns = g_realloc (eth->columns, sizeof (ETableCol *) * (eth->col_count + 1)); - - /* - * We are the primary owners of the column - */ - gtk_object_ref (GTK_OBJECT (tc)); - gtk_object_sink (GTK_OBJECT (tc)); - - eth_do_insert (eth, pos, tc); - eth->col_count++; - eth_update_offsets (eth); - - gtk_signal_emit (GTK_OBJECT (eth), eth_signals [STRUCTURE_CHANGE]); - gtk_signal_emit (GTK_OBJECT (eth), eth_signals [DIMENSION_CHANGE]); -} - -ETableCol * -e_table_header_get_column (ETableHeader *eth, int column) -{ - g_return_val_if_fail (eth != NULL, NULL); - g_return_val_if_fail (E_IS_TABLE_HEADER (eth), NULL); - - if (column < 0) - return NULL; - - if (column >= eth->col_count) - return NULL; - - return eth->columns [column]; -} - -int -e_table_header_count (ETableHeader *eth) -{ - g_return_val_if_fail (eth != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0); - - return eth->col_count; -} - -int -e_table_header_index (ETableHeader *eth, int col) -{ - g_return_val_if_fail (eth != NULL, -1); - g_return_val_if_fail (E_IS_TABLE_HEADER (eth), -1); - g_return_val_if_fail (col < eth->col_count, -1); - - return eth->columns [col]->col_idx; -} - -int -e_table_header_get_index_at (ETableHeader *eth, int x_offset) -{ - int i, total; - - g_return_val_if_fail (eth != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0); - - total = 0; - for (i = 0; i < eth->col_count; i++){ - total += eth->columns [i]->width; - - if (x_offset < total) - return i; - } - - return -1; -} - -ETableCol ** -e_table_header_get_columns (ETableHeader *eth) -{ - ETableCol **ret; - - g_return_val_if_fail (eth != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0); - - ret = g_new (ETableCol *, eth->col_count + 1); - memcpy (ret, eth->columns, sizeof (ETableCol *) * eth->col_count); - ret [eth->col_count] = NULL; - - return ret; -} - -gboolean -e_table_header_selection_ok (ETableHeader *eth) -{ - g_return_val_if_fail (eth != NULL, FALSE); - g_return_val_if_fail (E_IS_TABLE_HEADER (eth), FALSE); - - return eth->selectable; -} - -int -e_table_header_get_selected (ETableHeader *eth) -{ - int i; - int selected = 0; - - g_return_val_if_fail (eth != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0); - - for (i = 0; i < eth->col_count; i++){ - if (eth->columns [i]->selected) - selected++; - } - - return selected; -} - -int -e_table_header_total_width (ETableHeader *eth) -{ - int total, i; - - g_return_val_if_fail (eth != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0); - - total = 0; - for (i = 0; i < eth->col_count; i++) - total += eth->columns [i]->width; - - return total; -} - -static void -eth_do_remove (ETableHeader *eth, int idx, gboolean do_unref) -{ - if (do_unref) - gtk_object_unref (GTK_OBJECT (eth->columns [idx])); - - memcpy (ð->columns [idx], ð->columns [idx+1], - sizeof (ETableCol *) * eth->col_count - idx); - eth->col_count--; -} - -void -e_table_header_move (ETableHeader *eth, int source_index, int target_index) -{ - ETableCol *old; - - g_return_if_fail (eth != NULL); - g_return_if_fail (E_IS_TABLE_HEADER (eth)); - g_return_if_fail (source_index >= 0); - g_return_if_fail (target_index >= 0); - g_return_if_fail (source_index < eth->col_count); - g_return_if_fail (target_index < eth->col_count); - - old = eth->columns [source_index]; - eth_do_remove (eth, source_index, FALSE); - eth_do_insert (eth, target_index, old); - eth_update_offsets (eth); - - gtk_signal_emit (GTK_OBJECT (eth), eth_signals [STRUCTURE_CHANGE]); - gtk_signal_emit (GTK_OBJECT (eth), eth_signals [DIMENSION_CHANGE]); -} - -void -e_table_header_remove (ETableHeader *eth, int idx) -{ - g_return_if_fail (eth != NULL); - g_return_if_fail (E_IS_TABLE_HEADER (eth)); - g_return_if_fail (idx >= 0); - g_return_if_fail (idx < eth->col_count); - - eth_do_remove (eth, idx, TRUE); - gtk_signal_emit (GTK_OBJECT (eth), eth_signals [STRUCTURE_CHANGE]); - gtk_signal_emit (GTK_OBJECT (eth), eth_signals [DIMENSION_CHANGE]); -} - -void -e_table_header_set_selection (ETableHeader *eth, gboolean allow_selection) -{ -} - -void -e_table_header_set_size (ETableHeader *eth, int idx, int size) -{ - g_return_if_fail (eth != NULL); - g_return_if_fail (E_IS_TABLE_HEADER (eth)); - g_return_if_fail (idx >= 0); - g_return_if_fail (idx < eth->col_count); - g_return_if_fail (size > 0); - - eth->columns [idx]->width = size; - gtk_signal_emit (GTK_OBJECT (eth), eth_signals [DIMENSION_CHANGE], idx); -} - -int -e_table_header_col_diff (ETableHeader *eth, int start_col, int end_col) -{ - int total, col; - - g_return_val_if_fail (eth != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0); - - { - const int max_col = eth->col_count; - - total = 0; - for (col = start_col; col < end_col; col++){ - - if (col == max_col) - break; - total += eth->columns [col]->width; - } - } - - return total; -} diff --git a/widgets/e-table-header.h b/widgets/e-table-header.h deleted file mode 100644 index 96e65fdc2f..0000000000 --- a/widgets/e-table-header.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef _E_TABLE_COLUMN_H_ -#define _E_TABLE_COLUMN_H_ - -#include <gtk/gtkobject.h> -#include <gdk/gdk.h> -#include "e-table-col.h" - -typedef struct _ETableHeader ETableHeader; - -#define E_TABLE_HEADER_TYPE (e_table_header_get_type ()) -#define E_TABLE_HEADER(o) (GTK_CHECK_CAST ((o), E_TABLE_HEADER_TYPE, ETableHeader)) -#define E_TABLE_HEADER_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TABLE_HEADER_TYPE, ETableHeaderClass)) -#define E_IS_TABLE_HEADER(o) (GTK_CHECK_TYPE ((o), E_TABLE_HEADER_TYPE)) -#define E_IS_TABLE_HEADER_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_HEADER_TYPE)) - -/* - * A Columnar header. - */ -struct _ETableHeader { - GtkObject base; - - int col_count; - ETableCol **columns; - gboolean selectable; -}; - -typedef struct { - GtkObjectClass parent_class; - - void (*structure_change) (ETableHeader *eth); - void (*dimension_change) (ETableHeader *eth, int col); -} ETableHeaderClass; - -GtkType e_table_header_get_type (void); -ETableHeader *e_table_header_new (void); - -void e_table_header_add_column (ETableHeader *eth, - ETableCol *tc, int pos); -ETableCol * e_table_header_get_column (ETableHeader *eth, - int column); -int e_table_header_count (ETableHeader *eth); -int e_table_header_index (ETableHeader *eth, - int col); -int e_table_header_get_index_at (ETableHeader *eth, - int x_offset); -ETableCol **e_table_header_get_columns (ETableHeader *eth); -gboolean e_table_header_selection_ok (ETableHeader *eth); -int e_table_header_get_selected (ETableHeader *eth); -int e_table_header_total_width (ETableHeader *eth); -void e_table_header_move (ETableHeader *eth, - int source_index, - int target_index); -void e_table_header_remove (ETableHeader *eth, int idx); -void e_table_header_set_size (ETableHeader *eth, int idx, int size); -void e_table_header_set_selection (ETableHeader *eth, - gboolean allow_selection); - -int e_table_header_col_diff (ETableHeader *eth, - int start_col, int end_col); - -GList *e_table_header_get_selected_indexes(ETableHeader *eth); - - -#endif /* _E_TABLE_HEADER_H_ */ - diff --git a/widgets/e-table-item.c b/widgets/e-table-item.c deleted file mode 100644 index 33f0c18616..0000000000 --- a/widgets/e-table-item.c +++ /dev/null @@ -1,1316 +0,0 @@ -/* - * E-table-item.c: A GnomeCanvasItem that is a view of an ETableModel. - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * Copyright 1999, Helix Code, Inc. - * - * TODO: - * Add a border to the thing, so that focusing works properly. - * - */ -#include <config.h> -#include <stdio.h> -#include <gtk/gtksignal.h> -#include <gdk/gdkkeysyms.h> -#include <math.h> -#include "e-table-item.h" -#include "e-cell.h" - -#define PARENT_OBJECT_TYPE gnome_canvas_item_get_type () - -#define FOCUSED_BORDER 2 - -static GnomeCanvasItemClass *eti_parent_class; - -enum { - ROW_SELECTION, - HEIGHT_CHANGED, - LAST_SIGNAL -}; - -static gint eti_signals [LAST_SIGNAL] = { 0, }; - -enum { - ARG_0, - ARG_TABLE_HEADER, - ARG_TABLE_MODEL, - ARG_TABLE_X, - ARG_TABLE_Y, - ARG_TABLE_DRAW_GRID, - ARG_TABLE_DRAW_FOCUS, - ARG_MODE_SPREADSHEET, - ARG_LENGHT_THRESHOLD -}; - -static gboolean -eti_editing (ETableItem *eti) -{ - if (eti->editing_col == -1) - return FALSE; - else - return TRUE; -} - -/* - * During realization, we have to invoke the per-ecell realize routine - * (On our current setup, we have one e-cell per column. - * - * We might want to optimize this to only realize the unique e-cells: - * ie, a strings-only table, uses the same e-cell for every column, and - * we might want to avoid realizing each e-cell. - */ -static void -eti_realize_cell_views (ETableItem *eti) -{ - int i; - - for (i = 0; i < eti->n_cells; i++) - e_cell_view_realize (eti->cell_views [i], eti); - eti->cell_views_realized = 1; -} - -static void eti_compute_height (ETableItem *eti); - -static void -eti_attach_cell_views (ETableItem *eti) -{ - int i; - - g_assert (eti->header); - g_assert (eti->table_model); - - /* - * Now realize the various ECells - */ - eti->n_cells = eti->cols; - eti->cell_views = g_new (ECellView *, eti->n_cells); - - for (i = 0; i < eti->n_cells; i++){ - ETableCol *col = e_table_header_get_column (eti->header, i); - - eti->cell_views [i] = e_cell_new_view (col->ecell, eti->table_model, eti); - } - - eti_compute_height (eti); -} - -/* - * During unrealization: we invoke every e-cell (one per column in the current - * setup) to dispose all X resources allocated - */ -static void -eti_unrealize_cell_views (ETableItem *eti) -{ - int i; - - if (eti->cell_views_realized == 0) - return; - - for (i = 0; i < eti->n_cells; i++) - e_cell_unrealize (eti->cell_views [i]); - eti->cell_views_realized = 0; -} - -static void -eti_detach_cell_views (ETableItem *eti) -{ - int i; - - for (i = 0; i < eti->n_cells; i++){ - e_cell_kill_view (eti->cell_views [i]); - eti->cell_views [i] = NULL; - } - - g_free (eti->cell_views); - eti->cell_views = NULL; - eti->n_cells = 0; -} - -static void -eti_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) -{ - double i2c [6]; - ArtPoint c1, c2, i1, i2; - ETableItem *eti = E_TABLE_ITEM (item); - - gnome_canvas_item_i2c_affine (item, i2c); - i1.x = eti->x1; - i1.y = eti->y1; - i2.x = eti->x1 + eti->width; - i2.y = eti->y1 + eti->height; - art_affine_point (&c1, &i1, i2c); - art_affine_point (&c2, &i2, i2c); - - item->x1 = c1.x; - item->y1 = c1.y; - item->x2 = c2.x; - item->y2 = c2.y; -} - - -/* - * GnomeCanvasItem::update method - */ -static void -eti_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) -{ - if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->update) - (*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->update)(item, affine, clip_path, flags); - - eti_bounds (item, &item->x1, &item->y1, &item->x2, &item->y2); - gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item); -} - -/* - * eti_remove_table_model: - * - * Invoked to release the table model associated with this ETableItem - */ -static void -eti_remove_table_model (ETableItem *eti) -{ - if (!eti->table_model) - return; - - gtk_signal_disconnect (GTK_OBJECT (eti->table_model), - eti->table_model_change_id); - gtk_signal_disconnect (GTK_OBJECT (eti->table_model), - eti->table_model_row_change_id); - gtk_object_unref (GTK_OBJECT (eti->table_model)); - - eti->table_model_change_id = 0; - eti->table_model_row_change_id = 0; - eti->table_model = NULL; -} - -/* - * eti_remove_header_model: - * - * Invoked to release the header model associated with this ETableItem - */ -static void -eti_remove_header_model (ETableItem *eti) -{ - if (!eti->header) - return; - - gtk_signal_disconnect (GTK_OBJECT (eti->header), - eti->header_structure_change_id); - gtk_signal_disconnect (GTK_OBJECT (eti->header), - eti->header_dim_change_id); - - if (eti->cell_views){ - eti_unrealize_cell_views (eti); - eti_detach_cell_views (eti); - } - gtk_object_unref (GTK_OBJECT (eti->header)); - - - eti->header_structure_change_id = 0; - eti->header_dim_change_id = 0; - eti->header = NULL; -} - -/* - * eti_row_height: - * - * Returns the height used by row @row. This does not include the one-pixel - * used as a separator between rows - */ -static int -eti_row_height (ETableItem *eti, int row) -{ - const int cols = e_table_header_count (eti->header); - int col; - int h, max_h; - - g_assert (eti->cell_views); - - max_h = 0; - - for (col = 0; col < cols; col++){ - ETableCol *ecol = e_table_header_get_column (eti->header, col); - - h = e_cell_height (eti->cell_views [col], ecol->col_idx, col, row); - - if (h > max_h) - max_h = h; - } - return max_h; -} - -/* - * eti_get_height: - * - * Returns the height of the ETableItem. - * - * The ETableItem might compute the whole height by asking every row its - * size. There is a special mode (designed to work when there are too - * many rows in the table that performing the previous step could take - * too long) set by the ETableItem->length_threshold that would determine - * when the height is computed by using the first row as the size for - * every other row in the ETableItem. - */ -static int -eti_get_height (ETableItem *eti) -{ - const int rows = eti->rows; - int row; - int height; - - if (rows == 0) - return 0; - - if (eti->length_threshold != -1){ - if (rows > eti->length_threshold){ - height = (eti_row_height (eti, 0) + 1) * rows; - - /* - * 1 pixel at the top - */ - return height + 1; - } - } - - height = 1; - for (row = 0; row < rows; row++) - height += eti_row_height (eti, row) + 1; - - return height; -} - -static void -eti_compute_height (ETableItem *eti) -{ - int new_height = eti_get_height (eti); - - if (new_height != eti->height){ - double x1, y1, x2, y2; - printf ("Emitting!\n"); - - eti->height = new_height; - eti_update (GNOME_CANVAS_ITEM (eti), NULL, NULL, 0); - - gtk_signal_emit (GTK_OBJECT (eti), eti_signals [HEIGHT_CHANGED]); - } -} - -/* - * Callback routine: invoked when the ETableModel has suffered a change - */ -static void -eti_table_model_changed (ETableModel *table_model, ETableItem *eti) -{ - eti->rows = e_table_model_row_count (eti->table_model); - - if (eti->cell_views) - eti_compute_height (eti); - - eti_update (GNOME_CANVAS_ITEM (eti), NULL, NULL, 0); -} - -static void -eti_item_region_redraw (ETableItem *eti, int x0, int y0, int x1, int y1) -{ - GnomeCanvasItem *item = GNOME_CANVAS_ITEM (eti); - ArtDRect rect; - double i2c [6]; - - rect.x0 = x0; - rect.y0 = y0; - rect.x1 = x1; - rect.y1 = y1; - - gnome_canvas_item_i2c_affine (item, i2c); - art_drect_affine_transform (&rect, &rect, i2c); - - gnome_canvas_request_redraw (item->canvas, rect.x0, rect.y0, rect.x1, rect.y1); -} - -/* - * eti_request_redraw: - * - * Queues a canvas redraw for the entire ETableItem. - */ -static void -eti_request_redraw (ETableItem *eti) -{ - eti_item_region_redraw (eti, eti->x1, eti->y1, eti->x1 + eti->width + 1, eti->y1 + eti->height + 1); -} - -/* - * Computes the distance between @start_row and @end_row in pixels - */ -static int -eti_row_diff (ETableItem *eti, int start_row, int end_row) -{ - int row, total; - - total = 0; - - for (row = start_row; row < end_row; row++) - total += eti_row_height (eti, row) + 1; - - return total; -} - -/* - * eti_request_region_redraw: - * - * Request a canvas redraw on the range (start_col, start_row) to (end_col, end_row). - * This is inclusive (ie, you can use: 0,0-0,0 to redraw the first cell). - * - * The @border argument is a number of pixels around the region that should also be queued - * for redraw. This is typically used by the focus routines to queue a redraw for the - * border as well. - */ -static void -eti_request_region_redraw (ETableItem *eti, - int start_col, int start_row, - int end_col, int end_row, int border) -{ - int x1, y1, width, height; - - x1 = e_table_header_col_diff (eti->header, 0, start_col); - y1 = eti_row_diff (eti, 0, start_row); - width = e_table_header_col_diff (eti->header, start_col, end_col + 1); - height = eti_row_diff (eti, start_row, end_row + 1); - - eti_item_region_redraw (eti, eti->x1 + x1 - border, - eti->y1 + y1 - border, - eti->x1 + x1 + width + 1 + border, - eti->y1 + y1 + height + 1 + border); -} - -static void -eti_table_model_row_changed (ETableModel *table_model, int row, ETableItem *eti) -{ - if (eti->renderers_can_change_size){ - eti_table_model_changed (table_model, eti); - return; - } - - eti_request_region_redraw (eti, 0, row, eti->cols, row, 0); -} - -void -e_table_item_redraw_range (ETableItem *eti, - int start_col, int start_row, - int end_col, int end_row) -{ - int border; - - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - if ((start_col == eti->focused_col) || - (end_col == eti->focused_col) || - (start_row == eti->focused_row) || - (end_row == eti->focused_row)) - border = 2; - else - border = 0; - - eti_request_region_redraw (eti, start_col, start_row, end_col, end_row, border); -} - -static void -eti_add_table_model (ETableItem *eti, ETableModel *table_model) -{ - g_assert (eti->table_model == NULL); - - eti->table_model = table_model; - gtk_object_ref (GTK_OBJECT (eti->table_model)); - - eti->table_model_change_id = gtk_signal_connect ( - GTK_OBJECT (table_model), "model_changed", - GTK_SIGNAL_FUNC (eti_table_model_changed), eti); - - eti->table_model_row_change_id = gtk_signal_connect ( - GTK_OBJECT (table_model), "model_row_changed", - GTK_SIGNAL_FUNC (eti_table_model_row_changed), eti); - - if (eti->header){ - eti_detach_cell_views (eti); - eti_attach_cell_views (eti); - } - - eti_table_model_changed (table_model, eti); -} - -static void -eti_header_dim_changed (ETableHeader *eth, int col, ETableItem *eti) -{ - eti_request_redraw (eti); - - eti->width = e_table_header_total_width (eti->header); - eti_update (GNOME_CANVAS_ITEM (eti), NULL, NULL, 0); - - eti_request_redraw (eti); -} - -static void -eti_header_structure_changed (ETableHeader *eth, ETableItem *eti) -{ - eti_request_redraw (eti); - - eti->cols = e_table_header_count (eti->header); - eti->width = e_table_header_total_width (eti->header); - - if (eti->cell_views){ - eti_unrealize_cell_views (eti); - eti_detach_cell_views (eti); - eti_attach_cell_views (eti); - eti_realize_cell_views (eti); - } else { - if (eti->table_model){ - eti_detach_cell_views (eti); - eti_attach_cell_views (eti); - } - } - - eti_update (GNOME_CANVAS_ITEM (eti), NULL, NULL, 0); - - eti_request_redraw (eti); -} - -static void -eti_add_header_model (ETableItem *eti, ETableHeader *header) -{ - g_assert (eti->header == NULL); - - eti->header = header; - gtk_object_ref (GTK_OBJECT (header)); - - eti_header_structure_changed (header, eti); - - eti->header_dim_change_id = gtk_signal_connect ( - GTK_OBJECT (header), "dimension_change", - GTK_SIGNAL_FUNC (eti_header_dim_changed), eti); - - eti->header_structure_change_id = gtk_signal_connect ( - GTK_OBJECT (header), "structure_change", - GTK_SIGNAL_FUNC (eti_header_structure_changed), eti); -} - -/* - * GtkObject::destroy method - */ -static void -eti_destroy (GtkObject *object) -{ - ETableItem *eti = E_TABLE_ITEM (object); - - eti_remove_header_model (eti); - eti_remove_table_model (eti); - - g_slist_free (eti->selection); - - if (GTK_OBJECT_CLASS (eti_parent_class)->destroy) - (*GTK_OBJECT_CLASS (eti_parent_class)->destroy) (object); -} - -static void -eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) -{ - GnomeCanvasItem *item; - ETableItem *eti; - - item = GNOME_CANVAS_ITEM (o); - eti = E_TABLE_ITEM (o); - - switch (arg_id){ - case ARG_TABLE_HEADER: - eti_remove_header_model (eti); - eti_add_header_model (eti, GTK_VALUE_POINTER (*arg)); - break; - - case ARG_TABLE_MODEL: - eti_remove_table_model (eti); - eti_add_table_model (eti, GTK_VALUE_POINTER (*arg)); - break; - - case ARG_TABLE_X: - eti->x1 = GTK_VALUE_DOUBLE (*arg); - break; - - case ARG_TABLE_Y: - eti->y1 = GTK_VALUE_DOUBLE (*arg); - break; - - case ARG_LENGHT_THRESHOLD: - eti->length_threshold = GTK_VALUE_INT (*arg); - break; - - case ARG_TABLE_DRAW_GRID: - eti->draw_grid = GTK_VALUE_BOOL (*arg); - break; - - case ARG_TABLE_DRAW_FOCUS: - eti->draw_focus = GTK_VALUE_BOOL (*arg); - break; - - case ARG_MODE_SPREADSHEET: - eti->mode_spreadsheet = GTK_VALUE_BOOL (*arg); - break; - } - eti_update (item, NULL, NULL, 0); -} - -static void -eti_init (GnomeCanvasItem *item) -{ - ETableItem *eti = E_TABLE_ITEM (item); - - eti->focused_col = -1; - eti->focused_row = -1; - eti->editing_col = -1; - eti->editing_row = -1; - eti->height = 0; - - eti->length_threshold = -1; - eti->renderers_can_change_size = 0; - - eti->selection_mode = GTK_SELECTION_SINGLE; -} - -#define gray50_width 2 -#define gray50_height 2 -static const char gray50_bits[] = { - 0x02, 0x01, }; - -static void -eti_realize (GnomeCanvasItem *item) -{ - ETableItem *eti = E_TABLE_ITEM (item); - GtkWidget *canvas_widget = GTK_WIDGET (item->canvas); - GdkWindow *window; - - if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize) - (*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize)(item); - - /* - * Gdk Resource allocation - */ - window = canvas_widget->window; - - eti->fill_gc = canvas_widget->style->white_gc; - gdk_gc_ref (canvas_widget->style->white_gc); - - eti->grid_gc = gdk_gc_new (window); -#if 0 - /* This sets it to gray */ -/* gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); */ -#else - gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->black); -#endif - eti->focus_gc = gdk_gc_new (window); - gdk_gc_set_foreground (eti->focus_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); - gdk_gc_set_background (eti->focus_gc, &canvas_widget->style->fg [GTK_STATE_NORMAL]); - eti->stipple = gdk_bitmap_create_from_data (NULL, gray50_bits, gray50_width, gray50_height); - gdk_gc_set_ts_origin (eti->focus_gc, 0, 0); - gdk_gc_set_stipple (eti->focus_gc, eti->stipple); - gdk_gc_set_fill (eti->focus_gc, GDK_OPAQUE_STIPPLED); - - if (eti->cell_views == NULL) - eti_attach_cell_views (eti); - - eti_realize_cell_views (eti); - - eti_compute_height (eti); - - eti_update (item, NULL, NULL, 0); -} - -static void -eti_unrealize (GnomeCanvasItem *item) -{ - ETableItem *eti = E_TABLE_ITEM (item); - - gdk_gc_unref (eti->fill_gc); - eti->fill_gc = NULL; - gdk_gc_unref (eti->grid_gc); - eti->grid_gc = NULL; - gdk_gc_unref (eti->focus_gc); - eti->focus_gc = NULL; - gdk_bitmap_unref (eti->stipple); - eti->stipple = NULL; - - eti_unrealize_cell_views (eti); - - eti->height = 0; - - if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->unrealize) - (*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->unrealize)(item); -} - -static void -eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) -{ - ETableItem *eti = E_TABLE_ITEM (item); - const int rows = eti->rows; - const int cols = eti->cols; - int row, col, y1, y2; - int first_col, last_col, x_offset; - int first_row, last_row, y_offset, yd; - int x1, x2; - int f_x1, f_x2, f_y1, f_y2; - gboolean f_found; - double i2c [6]; - ArtPoint eti_base, eti_base_item; - - /* - * Clear the background - */ -#if 0 - gdk_draw_rectangle ( - drawable, eti->fill_gc, TRUE, - eti->x1 - x, eti->y1 - y, eti->width, eti->height); -#endif - - /* - * Find out our real position after grouping - */ - gnome_canvas_item_i2c_affine (item, i2c); - eti_base_item.x = eti->x1; - eti_base_item.y = eti->y1; - art_affine_point (&eti_base, &eti_base_item, i2c); - - /* - * First column to draw, last column to draw - */ - first_col = -1; - last_col = x_offset = 0; - x1 = x2 = floor (eti_base.x); - for (col = 0; col < cols; col++, x1 = x2){ - ETableCol *ecol = e_table_header_get_column (eti->header, col); - - x2 = x1 + ecol->width; - - if (x1 > (x + width)) - break; - if (x2 < x) - continue; - if (first_col == -1){ - x_offset = x1 - x; - first_col = col; - } - } - last_col = col; - - /* - * Nothing to paint - */ - if (first_col == -1) - return; - - /* - * Compute row span. - */ - first_row = -1; - y_offset = 0; - y1 = y2 = floor (eti_base.y) + 1; - for (row = 0; row < rows; row++, y1 = y2){ - - y2 += eti_row_height (eti, row) + 1; - - if (y1 > y + height) - break; - - if (y2 < y) - continue; - - if (first_row == -1){ - y_offset = y1 - y; - first_row = row; - } - } - last_row = row; - - if (first_row == -1) - return; - - /* - * Draw cells - */ - yd = y_offset; - f_x1 = f_x2 = f_y1 = f_y2 = -1; - f_found = FALSE; - - if (eti->draw_grid && first_row == 0){ - gdk_draw_line ( - drawable, eti->grid_gc, - eti_base.x - x, yd, eti_base.x + eti->width - x, yd); - } - yd++; - - for (row = first_row; row < last_row; row++){ - int xd, height; - gboolean selected; - - height = eti_row_height (eti, row); - - xd = x_offset; -/* printf ("paint: %d %d\n", yd, yd + height); */ - - selected = g_slist_find (eti->selection, GINT_TO_POINTER (row)) != NULL; - - for (col = first_col; col < last_col; col++){ - ETableCol *ecol = e_table_header_get_column (eti->header, col); - ECellView *ecell_view = eti->cell_views [col]; - - e_cell_draw (ecell_view, drawable, ecol->col_idx, col, row, selected, - xd, yd, xd + ecol->width, yd + height); - - if (col == eti->focused_col && row == eti->focused_row){ - f_x1 = xd; - f_x2 = xd + ecol->width; - f_y1 = yd; - f_y2 = yd + height; - f_found = TRUE; - } - - xd += ecol->width; - } - yd += height; - - if (eti->draw_grid) - gdk_draw_line ( - drawable, eti->grid_gc, - eti_base.x - x, yd, eti_base.x + eti->width - x, yd); - yd++; - } - - if (eti->draw_grid){ - int xd = x_offset; - - for (col = first_col; col <= last_col; col++){ - ETableCol *ecol = e_table_header_get_column (eti->header, col); - - gdk_draw_line ( - drawable, eti->grid_gc, - xd, y_offset, xd, yd - 1); - - /* - * This looks wierd, but it is to draw the last line - */ - if (ecol) - xd += ecol->width; - } - } - - /* - * Draw focus - */ - if (f_found && eti->draw_focus){ - - if (!eti_editing (eti)) - gdk_draw_rectangle ( - drawable, eti->focus_gc, FALSE, - f_x1 + 1, f_y1, f_x2 - f_x1 - 2, f_y2 - f_y1 - 1); - } -} - -static double -eti_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, - GnomeCanvasItem **actual_item) -{ - *actual_item = item; - - return 0.0; -} - -static gboolean -find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res, double *x1_res, double *y1_res) -{ - const int cols = eti->cols; - const int rows = eti->rows; - gdouble x1, y1, x2, y2; - int col, row; - - /* FIXME: this routine is inneficient, fix later */ - - x -= eti->x1; - y -= eti->y1; - - x1 = 0; - for (col = 0; col < cols; col++, x1 = x2){ - ETableCol *ecol = e_table_header_get_column (eti->header, col); - - if (x < x1) - return FALSE; - - x2 = x1 + ecol->width; - - if (x > x2) - continue; - - *col_res = col; - if (x1_res) - *x1_res = x - x1; - break; - } - - y1 = y2 = 0; - for (row = 0; row < rows; row++, y1 = y2){ - if (y < y1) - return FALSE; - - y2 += eti_row_height (eti, row) + 1; - - if (y > y2) - continue; - - *row_res = row; - if (y1_res) - *y1_res = y - y1; - break; - } - - return TRUE; -} - -static void -eti_cursor_move_left (ETableItem *eti) -{ - e_table_item_leave_edit (eti); - e_table_item_focus (eti, eti->focused_col - 1, eti->focused_row); -} - -static void -eti_cursor_move_right (ETableItem *eti) -{ - e_table_item_leave_edit (eti); - e_table_item_focus (eti, eti->focused_col + 1, eti->focused_row); -} - -static void -eti_cursor_move_up (ETableItem *eti) -{ - e_table_item_leave_edit (eti); - e_table_item_focus (eti, eti->focused_col, eti->focused_row - 1); -} - -static void -eti_cursor_move_down (ETableItem *eti) -{ - e_table_item_leave_edit (eti); - e_table_item_focus (eti, eti->focused_col, eti->focused_row + 1); -} - -static int -eti_event (GnomeCanvasItem *item, GdkEvent *e) -{ - ETableItem *eti = E_TABLE_ITEM (item); - ECellView *ecell_view; - ETableCol *ecol; - - switch (e->type){ - case GDK_BUTTON_PRESS: - case GDK_BUTTON_RELEASE: - case GDK_2BUTTON_PRESS: { - double x1, y1; - int col, row; - - gnome_canvas_item_w2i (item, &e->button.x, &e->button.y); - - if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) - return TRUE; - - if (eti->focused_row == row && eti->focused_col == col){ - - ecol = e_table_header_get_column (eti->header, col); - ecell_view = eti->cell_views [col]; - - /* - * Adjust the event positions - */ - e->button.x = x1; - e->button.y = y1; - - e_cell_event (ecell_view, e, ecol->col_idx, col, row); - } else { - /* - * Focus the cell, and select the row - */ - e_table_item_leave_edit (eti); - e_table_item_focus (eti, col, row); - e_table_item_select_row (eti, row); - } - break; - } - - case GDK_MOTION_NOTIFY: { - int col, row; - double x1, y1; - - gnome_canvas_item_w2i (item, &e->button.x, &e->button.y); - - if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) - return TRUE; - - if (eti->focused_row == row && eti->focused_col == col){ - ecol = e_table_header_get_column (eti->header, col); - ecell_view = eti->cell_views [col]; - - /* - * Adjust the event positions - */ - e->button.x -= (x1 + eti->x1); - e->button.y -= (y1 + eti->y1); - - e_cell_event (ecell_view, e, ecol->col_idx, col, row); - } - break; - } - - case GDK_KEY_PRESS: - if (eti->focused_col == -1) - return FALSE; - - switch (e->key.keyval){ - case GDK_Left: - if (!eti->mode_spreadsheet && eti_editing (eti)) - break; - - if (eti->focused_col > 0) - eti_cursor_move_left (eti); - - return TRUE; - - case GDK_Right: - if (!eti->mode_spreadsheet && eti_editing (eti)) - break; - - if ((eti->focused_col + 1) < eti->cols) - eti_cursor_move_right (eti); - return TRUE; - - case GDK_Up: - if (eti->focused_row > 0) - eti_cursor_move_up (eti); - return TRUE; - - case GDK_Down: - if ((eti->focused_row + 1) < eti->rows) - eti_cursor_move_down (eti); - - return TRUE; - - case GDK_Tab: - if ((e->key.state & GDK_SHIFT_MASK) != 0){ - /* shift tab */ - if (eti->focused_col > 0) - eti_cursor_move_left (eti); - else if (eti->focused_row > 0){ - e_table_item_leave_edit (eti); - e_table_item_focus (eti, eti->cols - 1, eti->focused_row - 1); - } else { - /* FIXME: request focus leave backward */ - } - } else { - if ((eti->focused_col + 1) < eti->cols) - eti_cursor_move_right (eti); - else if ((eti->focused_row + 1) < eti->rows){ - e_table_item_leave_edit (eti); - e_table_item_focus (eti, 0, eti->rows - 1); - } else { - /* FIXME: request focus leave forward */ - } - } - break; - - default: - if (!eti_editing (eti)){ - if ((e->key.state & (GDK_MOD1_MASK | GDK_CONTROL_MASK)) != 0) - return 0; - - if (!(e->key.keyval >= 0x20 && e->key.keyval <= 0xff)) - return 0; - } - } - - ecol = e_table_header_get_column (eti->header, eti->focused_col); - ecell_view = eti->cell_views [eti->focused_col]; - e_cell_event (ecell_view, e, ecol->col_idx, eti->focused_col, eti->focused_row); - break; - - case GDK_KEY_RELEASE: - if (eti->focused_col == -1) - return FALSE; - - if (eti_editing (eti)){ - ecell_view = eti->cell_views [eti->editing_col]; - ecol = e_table_header_get_column (eti->header, eti->editing_col); - e_cell_event (ecell_view, e, ecol->col_idx, eti->editing_col, eti->editing_row); - } - break; - - default: - return FALSE; - } - return TRUE; -} - -/* - * ETableItem::row_selection method - */ -static void -eti_row_selection (ETableItem *eti, int row, gboolean selected) -{ - eti_request_region_redraw (eti, 0, row, eti->cols - 1, row, 0); - - if (selected) - eti->selection = g_slist_prepend (eti->selection, GINT_TO_POINTER (row)); - else - eti->selection = g_slist_remove (eti->selection, GINT_TO_POINTER (row)); - -} - -static void -eti_class_init (GtkObjectClass *object_class) -{ - GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class; - ETableItemClass *eti_class = (ETableItemClass *) object_class; - - eti_parent_class = gtk_type_class (PARENT_OBJECT_TYPE); - - object_class->destroy = eti_destroy; - object_class->set_arg = eti_set_arg; - - item_class->update = eti_update; - item_class->realize = eti_realize; - item_class->unrealize = eti_unrealize; - item_class->draw = eti_draw; - item_class->point = eti_point; - item_class->event = eti_event; - item_class->bounds = eti_bounds; - - eti_class->row_selection = eti_row_selection; - - gtk_object_add_arg_type ("ETableItem::ETableHeader", GTK_TYPE_POINTER, - GTK_ARG_WRITABLE, ARG_TABLE_HEADER); - gtk_object_add_arg_type ("ETableItem::ETableModel", GTK_TYPE_POINTER, - GTK_ARG_WRITABLE, ARG_TABLE_MODEL); - gtk_object_add_arg_type ("ETableItem::x", GTK_TYPE_DOUBLE, - GTK_ARG_WRITABLE, ARG_TABLE_X); - gtk_object_add_arg_type ("ETableItem::y", GTK_TYPE_DOUBLE, - GTK_ARG_WRITABLE, ARG_TABLE_Y); - gtk_object_add_arg_type ("ETableItem::drawgrid", GTK_TYPE_BOOL, - GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); - gtk_object_add_arg_type ("ETableItem::drawfocus", GTK_TYPE_BOOL, - GTK_ARG_WRITABLE, ARG_TABLE_DRAW_FOCUS); - gtk_object_add_arg_type ("ETableItem::spreadsheet", GTK_TYPE_BOOL, - GTK_ARG_WRITABLE, ARG_MODE_SPREADSHEET); - - eti_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableItemClass, row_selection), - gtk_marshal_NONE__INT_INT, - GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - - eti_signals [HEIGHT_CHANGED] = - gtk_signal_new ("height_changed", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableItemClass, height_changed), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - - gtk_object_class_add_signals (object_class, eti_signals, LAST_SIGNAL); - -} - -GtkType -e_table_item_get_type (void) -{ - static GtkType type = 0; - - if (!type){ - GtkTypeInfo info = { - "ETableItem", - sizeof (ETableItem), - sizeof (ETableItemClass), - (GtkClassInitFunc) eti_class_init, - (GtkObjectInitFunc) eti_init, - NULL, /* reserved 1 */ - NULL, /* reserved 2 */ - (GtkClassInitFunc) NULL - }; - - type = gtk_type_unique (PARENT_OBJECT_TYPE, &info); - } - - return type; -} - -void -e_table_item_focus (ETableItem *eti, int col, int row) -{ - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - if (eti->focused_col != -1) - e_table_item_unfocus (eti); - - eti->focused_col = col; - eti->focused_row = row; - - eti_request_region_redraw (eti, col, row, col, row, FOCUSED_BORDER); - - /* - * make sure we have the Gtk Focus - */ - gnome_canvas_item_grab_focus (GNOME_CANVAS_ITEM (eti)); -} - -void -e_table_item_unfocus (ETableItem *eti) -{ - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - if (eti->focused_row == -1) - return; - - { - const int col = eti->focused_col; - const int row = eti->focused_row; - - eti_request_region_redraw (eti, col, row, col, row, FOCUSED_BORDER); - } - eti->focused_col = -1; - eti->focused_row = -1; -} - -const GSList * -e_table_item_get_selection (ETableItem *eti) -{ - g_return_val_if_fail (eti != NULL, NULL); - g_return_val_if_fail (E_IS_TABLE_ITEM (eti), NULL); - - return eti->selection; -} - -GtkSelectionMode -e_table_item_get_selection_mode (ETableItem *eti) -{ - g_return_val_if_fail (eti != NULL, GTK_SELECTION_SINGLE); - g_return_val_if_fail (E_IS_TABLE_ITEM (eti), GTK_SELECTION_SINGLE); - - return eti->selection_mode; -} - -void -e_table_item_set_selection_mode (ETableItem *eti, GtkSelectionMode selection_mode) -{ - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - if (selection_mode == GTK_SELECTION_BROWSE || - selection_mode == GTK_SELECTION_EXTENDED){ - g_error ("GTK_SELECTION_BROWSE and GTK_SELECTION_EXTENDED are not implemented"); - } - - eti->selection_mode = selection_mode; -} - -gboolean -e_table_item_is_row_selected (ETableItem *eti, int row) -{ - g_return_val_if_fail (eti != NULL, FALSE); - g_return_val_if_fail (E_IS_TABLE_ITEM (eti), FALSE); - - if (g_slist_find (eti->selection, GINT_TO_POINTER (row))) - return TRUE; - else - return FALSE; -} - -void -e_table_item_unselect_row (ETableItem *eti, int row) -{ - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - if (e_table_item_is_row_selected (eti, row)){ - gtk_signal_emit ( - GTK_OBJECT (eti), eti_signals [ROW_SELECTION], - row, 0); - } -} - -void -e_table_item_select_row (ETableItem *eti, int row) -{ - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - switch (eti->selection_mode){ - case GTK_SELECTION_SINGLE: - if (eti->selection){ - gtk_signal_emit ( - GTK_OBJECT (eti), eti_signals [ROW_SELECTION], - GPOINTER_TO_INT (eti->selection->data), 0); - } - g_slist_free (eti->selection); - eti->selection = NULL; - - gtk_signal_emit ( - GTK_OBJECT (eti), eti_signals [ROW_SELECTION], - GINT_TO_POINTER (row), 1); - break; - - case GTK_SELECTION_MULTIPLE: - if (g_slist_find (eti->selection, GINT_TO_POINTER (row))) - return; - gtk_signal_emit ( - GTK_OBJECT (eti), eti_signals [ROW_SELECTION], - GINT_TO_POINTER (row), 1); - break; - - default: - - } -} - -void -e_table_item_enter_edit (ETableItem *eti, int col, int row) -{ - ETableCol *ecol; - - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - eti->editing_col = col; - eti->editing_row = row; - - ecol = e_table_header_get_column (eti->header, col); - eti->edit_ctx = e_cell_enter_edit (eti->cell_views [col], ecol->col_idx, col, row); -} - -void -e_table_item_leave_edit (ETableItem *eti) -{ - ETableCol *ecol; - - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - if (!eti_editing (eti)) - return; - - ecol = e_table_header_get_column (eti->header, eti->editing_col); - e_cell_leave_edit ( - eti->cell_views [eti->editing_col], - ecol->col_idx, eti->editing_col, - eti->editing_row, eti->edit_ctx); - eti->editing_col = -1; - eti->editing_row = -1; - eti->edit_ctx = NULL; -} - diff --git a/widgets/e-table-item.h b/widgets/e-table-item.h deleted file mode 100644 index f19819f2fc..0000000000 --- a/widgets/e-table-item.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef _E_TABLE_ITEM_H_ -#define _E_TABLE_ITEM_H_ - -#include <libgnomeui/gnome-canvas.h> -#include "e-table-model.h" -#include "e-table-header.h" - -#define E_TABLE_ITEM_TYPE (e_table_item_get_type ()) -#define E_TABLE_ITEM(o) (GTK_CHECK_CAST ((o), E_TABLE_ITEM_TYPE, ETableItem)) -#define E_TABLE_ITEM_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TABLE_ITEM_TYPE, ETableItemClass)) -#define E_IS_TABLE_ITEM(o) (GTK_CHECK_TYPE ((o), E_TABLE_ITEM_TYPE)) -#define E_IS_TABLE_ITEM_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_ITEM_TYPE)) - -typedef struct { - GnomeCanvasItem parent; - ETableModel *table_model; - ETableHeader *header; - - int x1, y1; - int width, height; - - int cols, rows; - - /* - * Ids for the signals we connect to - */ - int header_dim_change_id; - int header_structure_change_id; - int table_model_change_id; - int table_model_row_change_id; - - GdkGC *fill_gc; - GdkGC *grid_gc; - GdkGC *focus_gc; - GdkBitmap *stipple; - - unsigned int draw_grid:1; - unsigned int draw_focus:1; - unsigned int mode_spreadsheet:1; - unsigned int renderers_can_change_size:1; - unsigned int cell_views_realized:1; - - int focused_col, focused_row; - - /* - * Realized views, per column - */ - ECellView **cell_views; - int n_cells; - - /* - * Lengh Threshold: above this, we stop computing correctly - * the size - */ - int length_threshold; - - GSList *selection; - GtkSelectionMode selection_mode; - - /* - * During edition - */ - int editing_col, editing_row; - void *edit_ctx; -} ETableItem; - -typedef struct { - GnomeCanvasItemClass parent_class; - - void (*row_selection) (ETableItem *eti, int row, gboolean selected); - void (*height_changed) (ETableItem *eti); -} ETableItemClass; - -GtkType e_table_item_get_type (void); - -/* - * Focus - */ -void e_table_item_focus (ETableItem *eti, int col, int row); -void e_table_item_unfocus (ETableItem *eti); - -/* - * Selection - */ -void e_table_item_select_row (ETableItem *e_table_Item, int row); -void e_table_item_unselect_row (ETableItem *e_table_Item, int row); - -/* - * Handling the selection - */ -const GSList*e_table_item_get_selection (ETableItem *e_table_Item); - -GtkSelectionMode e_table_item_get_selection_mode (ETableItem *e_table_Item); -void e_table_item_set_selection_mode (ETableItem *e_table_Item, - GtkSelectionMode selection_mode); -gboolean e_table_item_is_row_selected (ETableItem *e_table_Item, - int row); - -void e_table_item_leave_edit (ETableItem *eti); -void e_table_item_enter_edit (ETableItem *eti, int col, int row); - -void e_table_item_redraw_range (ETableItem *eti, - int start_col, int start_row, - int end_col, int end_row); - -#endif /* _E_TABLE_ITEM_H_ */ diff --git a/widgets/e-table-model.c b/widgets/e-table-model.c deleted file mode 100644 index 9e397710ef..0000000000 --- a/widgets/e-table-model.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * e-table-model.c: a Table Model - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * (C) 1999 Helix Code, Inc. - */ -#include <config.h> -#include <gtk/gtksignal.h> -#include "e-table-model.h" - -#define ETM_CLASS(e) ((ETableModelClass *)((GtkObject *)e)->klass) - -static GtkObjectClass *e_table_model_parent_class; - -enum { - MODEL_CHANGED, - MODEL_ROW_CHANGED, - MODEL_CELL_CHANGED, - ROW_SELECTION, - LAST_SIGNAL -}; - -static guint e_table_model_signals [LAST_SIGNAL] = { 0, }; - -int -e_table_model_column_count (ETableModel *e_table_model) -{ - g_return_val_if_fail (e_table_model != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), 0); - - return ETM_CLASS (e_table_model)->column_count (e_table_model); -} - - -int -e_table_model_row_count (ETableModel *e_table_model) -{ - g_return_val_if_fail (e_table_model != NULL, 0); - g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), 0); - - return ETM_CLASS (e_table_model)->row_count (e_table_model); -} - -void * -e_table_model_value_at (ETableModel *e_table_model, int col, int row) -{ - g_return_val_if_fail (e_table_model != NULL, NULL); - g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL); - - return ETM_CLASS (e_table_model)->value_at (e_table_model, col, row); -} - -void -e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *data) -{ - g_return_if_fail (e_table_model != NULL); - g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); - - ETM_CLASS (e_table_model)->set_value_at (e_table_model, col, row, data); - - gtk_signal_emit (GTK_OBJECT (e_table_model), - e_table_model_signals [MODEL_ROW_CHANGED], row); - gtk_signal_emit (GTK_OBJECT (e_table_model), - e_table_model_signals [MODEL_CELL_CHANGED], col, row); - - /* - * Notice that "model_changed" is not emitted - */ -} - -gboolean -e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row) -{ - g_return_val_if_fail (e_table_model != NULL, FALSE); - g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), FALSE); - - return ETM_CLASS (e_table_model)->is_cell_editable (e_table_model, col, row); -} - -static void -e_table_model_destroy (GtkObject *object) -{ - if (e_table_model_parent_class->destroy) - (*e_table_model_parent_class->destroy)(object); -} - -static void -e_table_model_class_init (GtkObjectClass *object_class) -{ - e_table_model_parent_class = gtk_type_class (gtk_object_get_type ()); - - object_class->destroy = e_table_model_destroy; - - e_table_model_signals [MODEL_CHANGED] = - gtk_signal_new ("model_changed", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableModelClass, model_changed), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - - e_table_model_signals [MODEL_ROW_CHANGED] = - gtk_signal_new ("model_row_changed", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableModelClass, model_row_changed), - gtk_marshal_NONE__INT, - GTK_TYPE_NONE, 1, GTK_TYPE_INT); - - e_table_model_signals [MODEL_CELL_CHANGED] = - gtk_signal_new ("model_cell_changed", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableModelClass, model_cell_changed), - gtk_marshal_NONE__INT_INT, - GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - - gtk_object_class_add_signals (object_class, e_table_model_signals, LAST_SIGNAL); -} - -GtkType -e_table_model_get_type (void) -{ - static GtkType type = 0; - - if (!type){ - GtkTypeInfo info = { - "ETableModel", - sizeof (ETableModel), - sizeof (ETableModelClass), - (GtkClassInitFunc) e_table_model_class_init, - (GtkObjectInitFunc) NULL, - NULL, /* reserved 1 */ - NULL, /* reserved 2 */ - (GtkClassInitFunc) NULL - }; - - type = gtk_type_unique (gtk_object_get_type (), &info); - } - - return type; -} - -void -e_table_model_changed (ETableModel *e_table_model) -{ - g_return_if_fail (e_table_model != NULL); - g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); - - gtk_signal_emit (GTK_OBJECT (e_table_model), - e_table_model_signals [MODEL_CHANGED]); -} - -void -e_table_model_row_changed (ETableModel *e_table_model, int row) -{ - g_return_if_fail (e_table_model != NULL); - g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); - - gtk_signal_emit (GTK_OBJECT (e_table_model), - e_table_model_signals [MODEL_ROW_CHANGED], row); -} - -void -e_table_model_cell_changed (ETableModel *e_table_model, int col, int row) -{ - g_return_if_fail (e_table_model != NULL); - g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); - - gtk_signal_emit (GTK_OBJECT (e_table_model), - e_table_model_signals [MODEL_CELL_CHANGED], col, row); -} - - diff --git a/widgets/e-table-model.h b/widgets/e-table-model.h deleted file mode 100644 index 2d08f3744e..0000000000 --- a/widgets/e-table-model.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _E_TABLE_MODEL_H_ -#define _E_TABLE_MODEL_H_ - -#include <gtk/gtkobject.h> - -#define E_TABLE_MODEL_TYPE (e_table_model_get_type ()) -#define E_TABLE_MODEL(o) (GTK_CHECK_CAST ((o), E_TABLE_MODEL_TYPE, ETableModel)) -#define E_TABLE_MODEL_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TABLE_MODEL_TYPE, ETableModelClass)) -#define E_IS_TABLE_MODEL(o) (GTK_CHECK_TYPE ((o), E_TABLE_MODEL_TYPE)) -#define E_IS_TABLE_MODEL_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_MODEL_TYPE)) - -typedef struct { - GtkObject base; -} ETableModel; - -typedef struct { - GtkObjectClass parent_class; - - /* - * Virtual methods - */ - int (*column_count) (ETableModel *etm); - int (*row_count) (ETableModel *etm); - void *(*value_at) (ETableModel *etm, int col, int row); - void (*set_value_at) (ETableModel *etm, int col, int row, const void *value); - gboolean (*is_cell_editable) (ETableModel *etm, int col, int row); - - /* - * Signals - */ - - /* - * Major structural changes: model_changed - * Changes only in a row: row_changed - * Only changes in a cell: cell_changed - */ - void (*model_changed) (ETableModel *etm); - void (*model_row_changed) (ETableModel *etm, int row); - void (*model_cell_changed) (ETableModel *etm, int col, int row); -} ETableModelClass; - -GtkType e_table_model_get_type (void); - -int e_table_model_column_count (ETableModel *e_table_model); -const char *e_table_model_column_name (ETableModel *e_table_model, int col); -int e_table_model_row_count (ETableModel *e_table_model); -void *e_table_model_value_at (ETableModel *e_table_model, int col, int row); -void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *data); -gboolean e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row); - -/* - * Routines for emitting signals on the e_table - */ -void e_table_model_changed (ETableModel *e_table_model); -void e_table_model_row_changed (ETableModel *e_table_model, int row); -void e_table_model_cell_changed (ETableModel *e_table_model, int col, int row); - -#endif /* _E_TABLE_MODEL_H_ */ diff --git a/widgets/e-table-render.c b/widgets/e-table-render.c deleted file mode 100644 index 49d742132b..0000000000 --- a/widgets/e-table-render.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * E-table-render.c: Various renderers - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * Copyright 1999, Helix Code, Inc. - */ -#include <config.h> -#include "e-table-header.h" -#include "e-table-header-item.h" -#include "e-table-col.h" -#include "e-table-render.h" - -void -e_table_render_string (ERenderContext *ctxt) -{ - printf ("Rendering string: %s\n", ctxt->render_data); -} - diff --git a/widgets/e-table-render.h b/widgets/e-table-render.h deleted file mode 100644 index ebc65968f0..0000000000 --- a/widgets/e-table-render.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef E_TABLE_RENDER_H -#define E_TABLE_RENDER_H - -#include <libgnomeui/gnome-canvas.h> - -struct ERenderContext { - ETableCol *etc; - int row; - int base_x, base_y; - GnomeCanvasItem *gnome_canvas_item; - GdkDrawable *drawable; - int drawable_width; - int drawable_height; - void *render_data; - void *closure; -}; - -void e_table_render_string (ERenderContext *ctxt); - - -#endif diff --git a/widgets/e-table-simple.c b/widgets/e-table-simple.c deleted file mode 100644 index 943a3291e9..0000000000 --- a/widgets/e-table-simple.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * e-table-model.c: a simple table model implementation that uses function - * pointers to simplify the creation of new, exotic and colorful tables in - * no time. - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * (C) 1999 Helix Code, Inc. - */ - -#include <config.h> -#include "e-table-simple.h" - -#define PARENT_TYPE e_table_model_get_type() - -static int -simple_column_count (ETableModel *etm) -{ - ETableSimple *simple = (ETableSimple *)etm; - - return simple->col_count (etm, simple->data); -} - -static int -simple_row_count (ETableModel *etm) -{ - ETableSimple *simple = (ETableSimple *)etm; - - return simple->row_count (etm, simple->data); -} - -static void * -simple_value_at (ETableModel *etm, int col, int row) -{ - ETableSimple *simple = (ETableSimple *)etm; - - return simple->value_at (etm, col, row, simple->data); -} - -static void -simple_set_value_at (ETableModel *etm, int col, int row, const void *val) -{ - ETableSimple *simple = (ETableSimple *)etm; - - simple->set_value_at (etm, col, row, val, simple->data); -} - -static gboolean -simple_is_cell_editable (ETableModel *etm, int col, int row) -{ - ETableSimple *simple = (ETableSimple *)etm; - - return simple->is_cell_editable (etm, col, row, simple->data); -} - -static void -e_table_simple_class_init (GtkObjectClass *object_class) -{ - ETableModelClass *model_class = (ETableModelClass *) object_class; - - model_class->column_count = simple_column_count; - model_class->row_count = simple_row_count; - model_class->value_at = simple_value_at; - model_class->set_value_at = simple_set_value_at; - model_class->is_cell_editable = simple_is_cell_editable; -} - -GtkType -e_table_simple_get_type (void) -{ - static GtkType type = 0; - - if (!type){ - GtkTypeInfo info = { - "ETableSimple", - sizeof (ETableSimple), - sizeof (ETableSimpleClass), - (GtkClassInitFunc) e_table_simple_class_init, - (GtkObjectInitFunc) NULL, - NULL, /* reserved 1 */ - NULL, /* reserved 2 */ - (GtkClassInitFunc) NULL - }; - - type = gtk_type_unique (PARENT_TYPE, &info); - } - - return type; -} - -ETableModel * -e_table_simple_new (ETableSimpleColumnCountFn col_count, - ETableSimpleRowCountFn row_count, - ETableSimpleValueAtFn value_at, - ETableSimpleSetValueAtFn set_value_at, - ETableSimpleIsCellEditableFn is_cell_editable, - void *data) -{ - ETableSimple *et; - - et = gtk_type_new (e_table_simple_get_type ()); - - et->col_count = col_count; - et->row_count = row_count; - et->value_at = value_at; - et->set_value_at = set_value_at; - et->is_cell_editable = is_cell_editable; - - return (ETableModel *) et; -} diff --git a/widgets/e-table-simple.h b/widgets/e-table-simple.h deleted file mode 100644 index d890245386..0000000000 --- a/widgets/e-table-simple.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _E_TABLE_SIMPLE_H_ -#define _E_TABLE_SIMPLE_H_ - -#include "e-table-model.h" - -typedef int (*ETableSimpleColumnCountFn) (ETableModel *etm, void *data); -typedef int (*ETableSimpleRowCountFn) (ETableModel *etm, void *data); -typedef void *(*ETableSimpleValueAtFn) (ETableModel *etm, int col, int row, void *data); -typedef void (*ETableSimpleSetValueAtFn) (ETableModel *etm, int col, int row, const void *val, void *data); -typedef gboolean (*ETableSimpleIsCellEditableFn) (ETableModel *etm, int col, int row, void *data); - -typedef struct { - ETableModel parent; - - ETableSimpleColumnCountFn col_count; - ETableSimpleRowCountFn row_count; - ETableSimpleValueAtFn value_at; - ETableSimpleSetValueAtFn set_value_at; - ETableSimpleIsCellEditableFn is_cell_editable; - void *data; -} ETableSimple; - -typedef struct { - ETableModelClass parent_class; -} ETableSimpleClass; - -GtkType e_table_simple_get_type (void); - -ETableModel *e_table_simple_new (ETableSimpleColumnCountFn col_count, - ETableSimpleRowCountFn row_count, - ETableSimpleValueAtFn value_at, - ETableSimpleSetValueAtFn set_value_at, - ETableSimpleIsCellEditableFn is_cell_editable, - void *data); - -#endif /* _E_TABLE_SIMPLE_H_ */ - diff --git a/widgets/e-table-sorted.c b/widgets/e-table-sorted.c deleted file mode 100644 index 6bc55ad9dc..0000000000 --- a/widgets/e-table-sorted.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * E-table-sorted.c: Implements a table that sorts another table - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * (C) 1999 Helix Code, Inc. - */ -#include <config.h> -#include <stdlib.h> -#include "e-util.h" -#include "e-table-sorted.h" - -#define PARENT_TYPE E_TABLE_SUBSET_TYPE - -static ETableModelClass *ets_parent_class; - -static void -ets_class_init (GtkObjectClass *klass) -{ - ets_parent_class = gtk_type_class (PARENT_TYPE); -} - -E_MAKE_TYPE(e_table_sorted, "ETableSorted", ETableSorted, ets_class_init, NULL, PARENT_TYPE); - -static ETableSorted *sort_ets; - -static int -my_sort (const void *a, const void *b) -{ - ETableModel *source = E_TABLE_SUBSET (sort_ets)->source; - const int *ia = (const int *) a; - const int *ib = (const int *) b; - void *va, *vb; - - va = e_table_model_value_at (source, sort_ets->sort_col, *ia); - vb = e_table_model_value_at (source, sort_ets->sort_col, *ib); - - return (*sort_ets->compare) (va, vb); -} - -static void -do_sort (ETableSorted *ets) -{ - ETableSubset *etss = E_TABLE_SUBSET (ets); - g_assert (sort_ets == NULL); - - sort_ets = ets; - qsort (etss->map_table, etss->n_map, sizeof (unsigned int), my_sort); - sort_ets = NULL; -} - -ETableModel * -e_table_sorted_new (ETableModel *source, int col, GCompareFunc compare) -{ - ETableSorted *ets = gtk_type_new (E_TABLE_SORTED_TYPE); - ETableSubset *etss = E_TABLE_SUBSET (ets); - const int nvals = e_table_model_row_count (source); - int i; - - if (e_table_subset_construct (etss, source, nvals) == NULL){ - gtk_object_destroy (GTK_OBJECT (ets)); - return NULL; - } - - ets->compare = compare; - ets->sort_col = col; - - /* Init */ - for (i = 0; i < nvals; i++) - etss->map_table [i] = i; - - do_sort (ets); - - return (ETableModel *) ets; -} - -void -e_table_sorted_resort (ETableSorted *ets, int col, GCompareFunc compare) -{ - if (col == -1 || compare == NULL) - do_sort (ets); - else { - ets->sort_col = col; - ets->compare = compare; - do_sort (ets); - } -} - diff --git a/widgets/e-table-sorted.h b/widgets/e-table-sorted.h deleted file mode 100644 index 2ec52df2e7..0000000000 --- a/widgets/e-table-sorted.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _E_TABLE_SORTED_H_ -#define _E_TABLE_SORTED_H_ - -#include <gtk/gtkobject.h> -#include "e-table-model.h" -#include "e-table-subset.h" - -#define E_TABLE_SORTED_TYPE (e_table_sorted_get_type ()) -#define E_TABLE_SORTED(o) (GTK_CHECK_CAST ((o), E_TABLE_SORTED_TYPE, ETableSorted)) -#define E_TABLE_SORTED_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TABLE_SORTED_TYPE, ETableSortedClass)) -#define E_IS_TABLE_SORTED(o) (GTK_CHECK_TYPE ((o), E_TABLE_SORTED_TYPE)) -#define E_IS_TABLE_SORTED_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_SORTED_TYPE)) - -typedef struct { - ETableSubset base; - - short sort_col; - GCompareFunc compare; -} ETableSorted; - -typedef struct { - ETableSubset parent_class; -} ETableSortedClass; - -GtkType e_table_sorted_get_type (void); -ETableModel *e_table_sorted_new (ETableModel *etm, int col, GCompareFunc compare); -void e_table_sorted_resort (ETableSorted *ets, int col, GCompareFunc compare); - -#endif /* _E_TABLE_SORTED_H_ */ diff --git a/widgets/e-table-subset.c b/widgets/e-table-subset.c deleted file mode 100644 index 88f5c18c85..0000000000 --- a/widgets/e-table-subset.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * E-table-subset.c: Implements a table that contains a subset of another table. - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * (C) 1999 Helix Code, Inc. - */ -#include <config.h> -#include <stdlib.h> -#include <gtk/gtksignal.h> -#include "e-util.h" -#include "e-table-subset.h" - -#define PARENT_TYPE E_TABLE_MODEL_TYPE - -static ETableModelClass *etss_parent_class; - -static void -etss_destroy (GtkObject *object) -{ - ETableSubset *etss = E_TABLE_SUBSET (object); - - if (etss->source) - gtk_object_unref (GTK_OBJECT (etss->source)); - - if (etss->map_table) - free (etss->map_table); - - GTK_OBJECT_CLASS (etss_parent_class)->destroy (object); -} - -static int -etss_column_count (ETableModel *etm) -{ - ETableSubset *etss = (ETableSubset *)etm; - - return e_table_model_column_count (etss->source); -} - -static int -etss_row_count (ETableModel *etm) -{ - ETableSubset *etss = (ETableSubset *)etm; - - return etss->n_map; -} - -static void * -etss_value_at (ETableModel *etm, int col, int row) -{ - ETableSubset *etss = (ETableSubset *)etm; - - return e_table_model_value_at (etss->source, col, etss->map_table [row]); -} - -static void -etss_set_value_at (ETableModel *etm, int col, int row, const void *val) -{ - ETableSubset *etss = (ETableSubset *)etm; - - return e_table_model_set_value_at (etss->source, col, etss->map_table [row], val); -} - -static gboolean -etss_is_cell_editable (ETableModel *etm, int col, int row) -{ - ETableSubset *etss = (ETableSubset *)etm; - - return e_table_model_is_cell_editable (etss->source, col, etss->map_table [row]); -} - -static void -etss_class_init (GtkObjectClass *klass) -{ - ETableModelClass *table_class = (ETableModelClass *) klass; - - etss_parent_class = gtk_type_class (PARENT_TYPE); - - klass->destroy = etss_destroy; - - table_class->column_count = etss_column_count; - table_class->row_count = etss_row_count; - table_class->value_at = etss_value_at; - table_class->set_value_at = etss_set_value_at; - table_class->is_cell_editable = etss_is_cell_editable; -} - -E_MAKE_TYPE(e_table_subset, "ETableSubset", ETableSubset, etss_class_init, NULL, PARENT_TYPE); - -static void -etss_proxy_model_changed (ETableModel *etm, ETableSubset *etss) -{ - e_table_model_changed (E_TABLE_MODEL (etss)); -} - -static void -etss_proxy_model_row_changed (ETableModel *etm, int row, ETableSubset *etss) -{ - const int n = etss->n_map; - const int * const map_table = etss->map_table; - int i; - - for (i = 0; i < n; i++){ - if (map_table [i] == row){ - e_table_model_row_changed (E_TABLE_MODEL (etss), i); - return; - } - } -} - -static void -etss_proxy_model_cell_changed (ETableModel *etm, int col, int row, ETableSubset *etss) -{ - const int n = etss->n_map; - const int * const map_table = etss->map_table; - int i; - - for (i = 0; i < n; i++){ - if (map_table [i] == row){ - e_table_model_cell_changed (E_TABLE_MODEL (etss), col, i); - return; - } - } -} - -ETableModel * -e_table_subset_construct (ETableSubset *etss, ETableModel *source, int nvals) -{ - unsigned int *buffer; - int i; - - buffer = (unsigned int *) malloc (sizeof (unsigned int) * nvals); - if (buffer == NULL) - return NULL; - etss->map_table = buffer; - etss->n_map = nvals; - etss->source = source; - gtk_object_ref (GTK_OBJECT (source)); - - /* Init */ - for (i = 0; i < nvals; i++) - etss->map_table [i] = i; - - gtk_signal_connect (GTK_OBJECT (source), "model_changed", - GTK_SIGNAL_FUNC (etss_proxy_model_changed), etss); - gtk_signal_connect (GTK_OBJECT (source), "model_row_changed", - GTK_SIGNAL_FUNC (etss_proxy_model_row_changed), etss); - gtk_signal_connect (GTK_OBJECT (source), "model_cell_changed", - GTK_SIGNAL_FUNC (etss_proxy_model_cell_changed), etss); - - return E_TABLE_MODEL (etss); -} - -ETableModel * -e_table_subset_new (ETableModel *source, const int nvals) -{ - ETableSubset *etss = gtk_type_new (E_TABLE_SUBSET_TYPE); - - if (e_table_subset_construct (etss, source, nvals) == NULL){ - gtk_object_destroy (GTK_OBJECT (etss)); - return NULL; - } - - return (ETableModel *) etss; -} - -ETableModel * -e_table_subset_get_toplevel (ETableSubset *table) -{ - g_return_val_if_fail (table != NULL, NULL); - g_return_val_if_fail (E_IS_TABLE_SUBSET (table), NULL); - - if (E_IS_TABLE_SUBSET (table->source)) - return e_table_subset_get_toplevel (E_TABLE_SUBSET (table->source)); - else - return table->source; -} diff --git a/widgets/e-table-subset.h b/widgets/e-table-subset.h deleted file mode 100644 index 314f28aea6..0000000000 --- a/widgets/e-table-subset.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _E_TABLE_SUBSET_H_ -#define _E_TABLE_SUBSET_H_ - -#include <gtk/gtkobject.h> -#include "e-table-model.h" - -#define E_TABLE_SUBSET_TYPE (e_table_subset_get_type ()) -#define E_TABLE_SUBSET(o) (GTK_CHECK_CAST ((o), E_TABLE_SUBSET_TYPE, ETableSubset)) -#define E_TABLE_SUBSET_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TABLE_SUBSET_TYPE, ETableSubsetClass)) -#define E_IS_TABLE_SUBSET(o) (GTK_CHECK_TYPE ((o), E_TABLE_SUBSET_TYPE)) -#define E_IS_TABLE_SUBSET_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_SUBSET_TYPE)) - -typedef struct { - ETableModel base; - - ETableModel *source; - int n_map; - int *map_table; -} ETableSubset; - -typedef struct { - ETableModelClass parent_class; -} ETableSubsetClass; - -GtkType e_table_subset_get_type (void); -ETableModel *e_table_subset_new (ETableModel *etm, int n_vals); -ETableModel *e_table_subset_construct (ETableSubset *ets, ETableModel *source, int nvals); - -ETableModel *e_table_subset_get_toplevel (ETableSubset *table_model); - -#endif /* _E_TABLE_SUBSET_H_ */ - diff --git a/widgets/e-table-tree.h b/widgets/e-table-tree.h deleted file mode 100644 index e7e125a6af..0000000000 --- a/widgets/e-table-tree.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _E_TABLE_TREE_H_ -#define _E_TABLE_TREE_H_ - -typedef struct { - char *title; - - union { - ETableModel *table; - GList *children; - } u; - - guint expanded :1; - guint is_leaf :1; -} ETableGroup; - -ETableGroup *e_table_group_new (const char *title, ETableModel *table); -ETableGroup *e_table_group_new_leaf (const char *title); - -#endif /* _E_TABLE_TREE_H_ */ diff --git a/widgets/e-table.c b/widgets/e-table.c deleted file mode 100644 index 01389135bf..0000000000 --- a/widgets/e-table.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * E-table-view.c: A graphical view of a Table. - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - * - * Copyright 1999, Helix Code, Inc - */ -#include <config.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <alloca.h> -#include <stdio.h> -#include <libgnomeui/gnome-canvas.h> -#include <gtk/gtksignal.h> -#include "e-table.h" -#include "e-util.h" -#include "e-table-header-item.h" -#include "e-table-subset.h" -#include "e-table-item.h" -#include "e-table-group.h" - -#define COLUMN_HEADER_HEIGHT 16 -#define TITLE_HEIGHT 16 -#define GROUP_INDENT 10 - -#define PARENT_TYPE gtk_table_get_type () - -static GtkObjectClass *e_table_parent_class; - -static void -et_destroy (GtkObject *object) -{ - ETable *et = E_TABLE (object); - - gtk_object_unref (GTK_OBJECT (et->model)); - gtk_object_unref (GTK_OBJECT (et->full_header)); - gtk_object_unref (GTK_OBJECT (et->header)); - - g_free (et->group_spec); - - (*e_table_parent_class->destroy)(object); -} - -static void -e_table_init (GtkObject *object) -{ - ETable *e_table = E_TABLE (object); - - e_table->draw_grid = 1; - e_table->draw_focus = 1; - e_table->spreadsheet = 1; -} - -static ETableHeader * -e_table_make_header (ETable *e_table, ETableHeader *full_header, const char *cols) -{ - ETableHeader *nh; - char *copy = alloca (strlen (cols) + 1); - char *p, *state; - const int max_cols = e_table_header_count (full_header); - - nh = e_table_header_new (); - strcpy (copy, cols); - while ((p = strtok_r (copy, ",", &state)) != NULL){ - int col = atoi (p); - - copy = NULL; - if (col >= max_cols) - continue; - - e_table_header_add_column (nh, e_table_header_get_column (full_header, col), -1); - } - - return nh; -} - -static void -header_canvas_size_alocate (GtkWidget *widget, GtkAllocation *alloc, ETable *e_table) -{ - gnome_canvas_set_scroll_region ( - GNOME_CANVAS (e_table->header_canvas), - 0, 0, alloc->width, COLUMN_HEADER_HEIGHT); -} - -static void -e_table_setup_header (ETable *e_table) -{ - e_table->header_canvas = GNOME_CANVAS (gnome_canvas_new ()); - - gtk_widget_show (GTK_WIDGET (e_table->header_canvas)); - - e_table->header_item = gnome_canvas_item_new ( - gnome_canvas_root (e_table->header_canvas), - e_table_header_item_get_type (), - "ETableHeader", e_table->header, - "x", 0, - "y", 0, - NULL); - - gtk_signal_connect ( - GTK_OBJECT (e_table->header_canvas), "size_allocate", - GTK_SIGNAL_FUNC (header_canvas_size_alocate), e_table); - - gtk_widget_set_usize (GTK_WIDGET (e_table->header_canvas), -1, COLUMN_HEADER_HEIGHT); - - gtk_table_attach ( - GTK_TABLE (e_table), GTK_WIDGET (e_table->header_canvas), - 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); - -} - -typedef struct { - void *value; - GArray *array; -} group_key_t; - -static GArray * -e_table_create_groups (ETableModel *etm, int key_col, GCompareFunc comp) -{ - GArray *groups; - const int rows = e_table_model_row_count (etm); - int row, i; - - groups = g_array_new (FALSE, FALSE, sizeof (group_key_t)); - - for (row = 0; row < rows; row++){ - void *val = e_table_model_value_at (etm, key_col, row); - const int n_groups = groups->len; - - /* - * Should replace this with a bsearch later - */ - for (i = 0; i < n_groups; i++){ - group_key_t *g = &g_array_index (groups, group_key_t, i); - - if ((*comp) (g->value, val)){ - g_array_append_val (g->array, row); - break; - } - } - if (i != n_groups) - continue; - - /* - * We need to create a new group - */ - { - group_key_t gk; - - gk.value = val; - gk.array = g_array_new (FALSE, FALSE, sizeof (int)); - - g_array_append_val (gk.array, row); - g_array_append_val (groups, gk); - } - } - - return groups; -} - -static void -e_table_destroy_groups (GArray *groups) -{ - const int n = groups->len; - int i; - - for (i = 0; i < n; i++){ - group_key_t *g = &g_array_index (groups, group_key_t, i); - - g_array_free (g->array, TRUE); - } - g_array_free (groups, TRUE); -} - -static ETableModel ** -e_table_make_subtables (ETableModel *model, GArray *groups) -{ - const int n_groups = groups->len; - ETableModel **tables; - int i; - - tables = g_new (ETableModel *, n_groups+1); - - for (i = 0; i < n_groups; i++){ - group_key_t *g = &g_array_index (groups, group_key_t, i); - const int sub_size = g->array->len; - ETableSubset *ss; - int j; - - tables [i] = e_table_subset_new (model, sub_size); - ss = E_TABLE_SUBSET (tables [i]); - - for (j = 0; j < sub_size; j++) - ss->map_table [j] = g_array_index (g->array, int, j); - } - tables [i] = NULL; - - return (ETableModel **) tables; -} - -typedef struct _Node Node; - -struct _Node { - Node *parent; - GnomeCanvasItem *item; - ETableModel *table_model; - GSList *children; - - guint is_leaf:1; -}; - -static Node * -leaf_new (GnomeCanvasItem *table_item, ETableModel *table_model, Node *parent) -{ - Node *node = g_new (Node, 1); - - g_assert (table_item != NULL); - g_assert (table_model != NULL); - g_assert (parent != NULL); - - node->item = table_item; - node->parent = parent; - node->table_model = table_model; - node->is_leaf = 1; - - g_assert (!parent->is_leaf); - - parent->children = g_slist_append (parent->children, node); - - e_table_group_add (E_TABLE_GROUP (parent->item), table_item); - - return node; -} - -static Node * -node_new (GnomeCanvasItem *group_item, ETableModel *table_model, Node *parent) -{ - Node *node = g_new (Node, 1); - - g_assert (table_model != NULL); - - node->children = NULL; - node->item = group_item; - node->parent = parent; - node->table_model = table_model; - node->is_leaf = 0; - - if (parent){ - parent->children = g_slist_append (parent->children, node); - - e_table_group_add (E_TABLE_GROUP (parent->item), group_item); - } - - return node; -} - -static Node * -e_table_create_leaf (ETable *e_table, ETableModel *etm, Node *parent) -{ - GnomeCanvasItem *table_item; - static double last_y; - Node *leaf; - - table_item = gnome_canvas_item_new ( - GNOME_CANVAS_GROUP (parent->item), - e_table_item_get_type (), - "ETableHeader", e_table->header, - "ETableModel", etm, - "drawgrid", e_table->draw_grid, - "drawfocus", e_table->draw_focus, - "spreadsheet", e_table->spreadsheet, - NULL); - - leaf = leaf_new (table_item, etm, parent); - - return leaf; -} - -static int -leaf_height (Node *leaf) -{ - const GnomeCanvasItem *item = leaf->item; - - return item->y2 - item->y1; -} - -static int -leaf_event (GnomeCanvasItem *item, GdkEvent *event) -{ - static int last_x = -1; - static int last_y = -1; - - if (event->type == GDK_BUTTON_PRESS){ - last_x = event->button.x; - last_y = event->button.y; - } else if (event->type == GDK_BUTTON_RELEASE){ - last_x = -1; - last_y = -1; - } else if (event->type == GDK_MOTION_NOTIFY){ - if (last_x == -1) - return FALSE; - - gnome_canvas_item_move (item, event->motion.x - last_x, event->motion.y - last_y); - last_x = event->motion.x; - last_y = event->motion.y; - } else - return FALSE; - return TRUE; -} - -static Node * -e_table_create_nodes (ETable *e_table, ETableModel *model, ETableHeader *header, - GnomeCanvasGroup *root, Node *parent, int *groups_list) -{ - GArray *groups; - ETableModel **tables; - ETableCol *ecol; - int key_col, i; - GnomeCanvasItem *group_item; - Node *group; - - key_col = *groups_list; - g_assert (key_col != -1); - - /* - * Create groups - */ - ecol = e_table_header_get_column (header, key_col); - - g_assert (ecol != NULL); - - groups = e_table_create_groups (model, key_col, ecol->compare); - tables = e_table_make_subtables (e_table->model, groups); - e_table_destroy_groups (groups); - - group_item = e_table_group_new (root, ecol, TRUE, parent == NULL); - group = node_new (group_item, model, parent); - - for (i = 0; tables [i] != NULL; i++){ - Node *node; - - /* - * Leafs - */ - if (groups_list [1] == -1){ - GnomeCanvasItem *item_leaf_header; - Node *leaf_header; - - item_leaf_header = e_table_group_new ( - GNOME_CANVAS_GROUP (group_item), ecol, TRUE, FALSE); - leaf_header = node_new (item_leaf_header, tables [i], group); - - e_table_create_leaf (e_table, tables [i], leaf_header); - } else { - e_table_create_nodes ( - e_table, tables [i], header, GNOME_CANVAS_GROUP (group_item), - group, &groups_list [1]); - } - } - - return group; -} - -static int * -group_spec_to_desc (const char *group_spec) -{ - int a_size = 10; - int *elements; - char *p, *copy, *follow; - int n_elements = 0; - - if (group_spec == NULL) - return NULL; - - elements = g_new (int, a_size); - copy = alloca (strlen (group_spec) + 1); - strcpy (copy, group_spec); - - while ((p = strtok_r (copy, ",", &follow)) != NULL){ - elements [n_elements] = atoi (p); - ++n_elements; - if (n_elements+1 == a_size){ - int *new_e; - - n_elements += 10; - new_e = g_renew (int, elements, n_elements); - if (new_e == NULL){ - g_free (elements); - return NULL; - } - elements = new_e; - } - copy = NULL; - } - - /* Tag end */ - elements [n_elements] = -1; - - return elements; -} - -/* - * The ETableCanvas object is just used to enable us to - * hook up to the realize/unrealize phases of the canvas - * initialization (as laying out the subtables requires us to - * know the actual size of the subtables we are inserting - */ - -#define E_TABLE_CANVAS_PARENT_TYPE gnome_canvas_get_type () - -typedef struct { - GnomeCanvas base; - - ETable *e_table; -} ETableCanvas; - -typedef struct { - GnomeCanvasClass base_class; -} ETableCanvasClass; - -static GnomeCanvasClass *e_table_canvas_parent_class; - -static void -e_table_canvas_realize (GtkWidget *widget) -{ - ETableCanvas *e_table_canvas = (ETableCanvas *) widget; - ETable *e_table = e_table_canvas->e_table; - int *groups; - Node *leaf; - - GTK_WIDGET_CLASS (e_table_canvas_parent_class)->realize (widget); - - groups = group_spec_to_desc (e_table->group_spec); - - e_table->root = gnome_canvas_item_new ( - GNOME_CANVAS_GROUP (e_table->table_canvas->root), - gnome_canvas_group_get_type (), - "x", 0.0, - "y", 0.0, - NULL); - - leaf = e_table_create_nodes ( - e_table, e_table->model, - e_table->header, GNOME_CANVAS_GROUP (e_table->root), 0, groups); - - gnome_canvas_set_scroll_region ( - GNOME_CANVAS (e_table_canvas), - 0, 0, - e_table_header_total_width (e_table->header) + 200, - leaf_height (leaf)); - - if (groups) - g_free (groups); -} - -static void -e_table_canvas_unrealize (GtkWidget *widget) -{ - ETableCanvas *e_table_canvas = (ETableCanvas *) widget; - ETable *e_table = e_table_canvas->e_table; - - gtk_object_destroy (GTK_OBJECT (e_table->root)); - e_table->root = NULL; - - GTK_WIDGET_CLASS (e_table_canvas_parent_class)->unrealize (widget); -} - -static void -e_table_canvas_class_init (GtkObjectClass *object_class) -{ - GtkWidgetClass *widget_class = (GtkWidgetClass *) object_class; - - widget_class->realize = e_table_canvas_realize; - widget_class->unrealize = e_table_canvas_unrealize; - - e_table_canvas_parent_class = gtk_type_class (E_TABLE_CANVAS_PARENT_TYPE); -} - -static void -e_table_canvas_init (GtkObject *canvas) -{ - GTK_WIDGET_SET_FLAGS (canvas, GTK_CAN_FOCUS); -} - -GtkType e_table_canvas_get_type (void); - -E_MAKE_TYPE (e_table_canvas, "ETableCanvas", ETableCanvas, e_table_canvas_class_init, - e_table_canvas_init, E_TABLE_CANVAS_PARENT_TYPE); - -static GnomeCanvas * -e_table_canvas_new (ETable *e_table) -{ - ETableCanvas *e_table_canvas; - - e_table_canvas = gtk_type_new (e_table_canvas_get_type ()); - e_table_canvas->e_table = e_table; - - return GNOME_CANVAS (e_table_canvas); -} - -static void -e_table_setup_table (ETable *e_table) -{ - e_table->table_canvas = e_table_canvas_new (e_table); - - gtk_widget_show (GTK_WIDGET (e_table->table_canvas)); - gtk_table_attach ( - GTK_TABLE (e_table), GTK_WIDGET (e_table->table_canvas), - 0, 1, 1, 2, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0); -} - -void -e_table_construct (ETable *e_table, ETableHeader *full_header, ETableModel *etm, - const char *cols_spec, const char *group_spec) -{ - GTK_TABLE (e_table)->homogeneous = FALSE; - - gtk_table_resize (GTK_TABLE (e_table), 1, 2); - - e_table->full_header = full_header; - gtk_object_ref (GTK_OBJECT (full_header)); - - e_table->model = etm; - gtk_object_ref (GTK_OBJECT (etm)); - - e_table->header = e_table_make_header (e_table, full_header, cols_spec); - - e_table_setup_header (e_table); - e_table_setup_table (e_table); - - e_table->group_spec = g_strdup (group_spec); - -} - -GtkWidget * -e_table_new (ETableHeader *full_header, ETableModel *etm, const char *cols_spec, const char *group_spec) -{ - ETable *e_table; - - e_table = gtk_type_new (e_table_get_type ()); - - e_table_construct (e_table, full_header, etm, cols_spec, group_spec); - - return (GtkWidget *) e_table; -} - -static void -e_table_class_init (GtkObjectClass *object_class) -{ - e_table_parent_class = gtk_type_class (PARENT_TYPE); - - object_class->destroy = et_destroy; -} - -E_MAKE_TYPE(e_table, "ETable", ETable, e_table_class_init, e_table_init, PARENT_TYPE); - diff --git a/widgets/e-table.h b/widgets/e-table.h deleted file mode 100644 index 63c131324f..0000000000 --- a/widgets/e-table.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _E_TABLE_H_ -#define _E_TABLE_H_ - -#include <libgnomeui/gnome-canvas.h> -#include <gtk/gtktable.h> -#include "e-table-model.h" -#include "e-table-header.h" - -BEGIN_GNOME_DECLS - -#define E_TABLE_TYPE (e_table_get_type ()) -#define E_TABLE(o) (GTK_CHECK_CAST ((o), E_TABLE_TYPE, ETable)) -#define E_TABLE_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TABLE_TYPE, ETableClass)) -#define E_IS_TABLE(o) (GTK_CHECK_TYPE ((o), E_TABLE_TYPE)) -#define E_IS_TABLE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_TYPE)) - -typedef struct { - GtkTable parent; - - ETableModel *model; - - ETableHeader *full_header, *header; - - GnomeCanvas *header_canvas, *table_canvas; - - GnomeCanvasItem *header_item, *root; - - guint draw_grid:1; - guint draw_focus:1; - guint spreadsheet:1; - - char *group_spec; -} ETable; - -typedef struct { - GtkTableClass parent_class; -} ETableClass; - -GtkType e_table_get_type (void); -void e_table_construct (ETable *e_table, ETableHeader *full_header, ETableModel *etm, - const char *cols_spec, const char *group_spec); -GtkWidget *e_table_new (ETableHeader *full_header, ETableModel *etm, - const char *cols_spec, const char *group_spec); - - -END_GNOME_DECLS - - #endif /* _E_TABLE_H_ */ diff --git a/widgets/e-table/Makefile.am b/widgets/e-table/Makefile.am index 73bd54ee2c..8f81a8076c 100644 --- a/widgets/e-table/Makefile.am +++ b/widgets/e-table/Makefile.am @@ -1,16 +1,11 @@ - -SUBDIRS = - meeting-time-sel - INCLUDES = \ - -I$(top_srcdir)/camel \ - -I$(top_builddir)/camel \ - $(GNOME_INCLUDEDIR) + $(GNOME_INCLUDEDIR) \ + -I$(top_srcdir)/e-util noinst_LIBRARIES = \ - libevolutionwidgets.a + libetable.a -libevolutionwidgets_a_SOURCES = \ +libetable_a_SOURCES = \ e-cell.c \ e-cell.h \ e-cell-checkbox.c \ @@ -19,8 +14,6 @@ libevolutionwidgets_a_SOURCES = \ e-cell-text.h \ e-cell-toggle.c \ e-cell-toggle.h \ - e-cursors.c \ - e-cursors.h \ e-table.c \ e-table.h \ e-table-col.c \ @@ -51,9 +44,10 @@ table_test_SOURCES = \ test-cols.c \ table-test.c -table_test_LDADD = \ - $(EXTRA_GNOME_LIBS) \ - libevolutionwidgets.a +table_test_LDADD = \ + $(EXTRA_GNOME_LIBS) \ + libetable.a \ + $(top_builddir)/e-util/libeutil.a table_test_LDFLAGS = `gnome-config --libs gdk_pixbuf` diff --git a/widgets/e-table/e-cell-checkbox.c b/widgets/e-table/e-cell-checkbox.c index 6e4b597abf..d77e1fa4cd 100644 --- a/widgets/e-table/e-cell-checkbox.c +++ b/widgets/e-table/e-cell-checkbox.c @@ -14,7 +14,7 @@ #include <gdk/gdkkeysyms.h> #include <libgnomeui/gnome-canvas.h> #include "e-cell-checkbox.h" -#include "e-util.h" +#include <e-util/e-util.h> #include "e-table-item.h" #include "check-empty.xpm" diff --git a/widgets/e-table/e-cell-text.c b/widgets/e-table/e-cell-text.c index 1b2205ba51..9ce8190a14 100644 --- a/widgets/e-table/e-cell-text.c +++ b/widgets/e-table/e-cell-text.c @@ -15,7 +15,7 @@ #include <libgnomeui/gnome-canvas.h> #include <stdio.h> #include "e-cell-text.h" -#include "e-util.h" +#include <e-util/e-util.h> #include "e-table-item.h" #define PARENT_TYPE e_cell_get_type() diff --git a/widgets/e-table/e-cell-toggle.c b/widgets/e-table/e-cell-toggle.c index 6ea181ea40..a933a62c49 100644 --- a/widgets/e-table/e-cell-toggle.c +++ b/widgets/e-table/e-cell-toggle.c @@ -14,7 +14,7 @@ #include <gdk/gdkkeysyms.h> #include <libgnomeui/gnome-canvas.h> #include "e-cell-toggle.h" -#include "e-util.h" +#include <e-util/e-util.h> #include "e-table-item.h" #define PARENT_TYPE e_cell_get_type() diff --git a/widgets/e-table/e-cell.c b/widgets/e-table/e-cell.c index 0f9297ecba..b5cbc0e850 100644 --- a/widgets/e-table/e-cell.c +++ b/widgets/e-table/e-cell.c @@ -8,7 +8,7 @@ */ #include <config.h> #include "e-cell.h" -#include "e-util.h" +#include <e-util/e-util.h> #define PARENT_TYPE gtk_object_get_type() diff --git a/widgets/e-table/e-table-col.c b/widgets/e-table/e-table-col.c index 86392a9419..62a451ca4f 100644 --- a/widgets/e-table/e-table-col.c +++ b/widgets/e-table/e-table-col.c @@ -10,7 +10,7 @@ #include <gtk/gtkobject.h> #include <gtk/gtksignal.h> #include "e-table-col.h" -#include "e-util.h" +#include <e-util/e-util.h> #define PARENT_TYPE (gtk_object_get_type ()) diff --git a/widgets/e-table/e-table-group.c b/widgets/e-table/e-table-group.c index 8765c3b83c..14c7a33f79 100644 --- a/widgets/e-table/e-table-group.c +++ b/widgets/e-table/e-table-group.c @@ -12,7 +12,7 @@ #include "e-table-group.h" #include "e-table-item.h" #include <libgnomeui/gnome-canvas-rect-ellipse.h> -#include "e-util.h" +#include <e-util/e-util.h> #define TITLE_HEIGHT 16 #define GROUP_INDENT 10 diff --git a/widgets/e-table/e-table-sorted.c b/widgets/e-table/e-table-sorted.c index 6bc55ad9dc..b559b3d87f 100644 --- a/widgets/e-table/e-table-sorted.c +++ b/widgets/e-table/e-table-sorted.c @@ -8,7 +8,7 @@ */ #include <config.h> #include <stdlib.h> -#include "e-util.h" +#include <e-util/e-util.h> #include "e-table-sorted.h" #define PARENT_TYPE E_TABLE_SUBSET_TYPE diff --git a/widgets/e-table/e-table-subset.c b/widgets/e-table/e-table-subset.c index 88f5c18c85..be4c7ab732 100644 --- a/widgets/e-table/e-table-subset.c +++ b/widgets/e-table/e-table-subset.c @@ -9,7 +9,7 @@ #include <config.h> #include <stdlib.h> #include <gtk/gtksignal.h> -#include "e-util.h" +#include <e-util/e-util.h> #include "e-table-subset.h" #define PARENT_TYPE E_TABLE_MODEL_TYPE diff --git a/widgets/e-table/e-table.c b/widgets/e-table/e-table.c index 01389135bf..730306b374 100644 --- a/widgets/e-table/e-table.c +++ b/widgets/e-table/e-table.c @@ -14,8 +14,8 @@ #include <stdio.h> #include <libgnomeui/gnome-canvas.h> #include <gtk/gtksignal.h> +#include <e-util/e-util.h> #include "e-table.h" -#include "e-util.h" #include "e-table-header-item.h" #include "e-table-subset.h" #include "e-table-item.h" diff --git a/widgets/e-util.h b/widgets/e-util.h deleted file mode 100644 index ad4d754770..0000000000 --- a/widgets/e-util.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _E_UTIL_H_ -#define _E_UTIL_H_ - -#define E_MAKE_TYPE(l,str,t,ci,i,parent) \ -GtkType l##_get_type(void)\ -{\ - static GtkType type = 0;\ - if (!type){\ - GtkTypeInfo info = {\ - str,\ - sizeof (t),\ - sizeof (t##Class),\ - (GtkClassInitFunc) ci,\ - (GtkObjectInitFunc) i,\ - NULL, /* reserved 1 */\ - NULL, /* reserved 2 */\ - (GtkClassInitFunc) NULL\ - };\ - type = gtk_type_unique (parent, &info);\ - }\ - return type;\ -}\ - -#endif /* _E_UTIL_H_ */ diff --git a/widgets/image1.png b/widgets/image1.png Binary files differdeleted file mode 100644 index 8326ac241f..0000000000 --- a/widgets/image1.png +++ /dev/null diff --git a/widgets/image2.png b/widgets/image2.png Binary files differdeleted file mode 100644 index e6a4c75dbe..0000000000 --- a/widgets/image2.png +++ /dev/null diff --git a/widgets/image3.png b/widgets/image3.png Binary files differdeleted file mode 100644 index 50e16e8620..0000000000 --- a/widgets/image3.png +++ /dev/null diff --git a/widgets/remove-col.xpm b/widgets/remove-col.xpm deleted file mode 100644 index ff1024f0c9..0000000000 --- a/widgets/remove-col.xpm +++ /dev/null @@ -1,22 +0,0 @@ -/* XPM */ -static char * remove_col_xpm[] = { -"16 16 3 1", -" c None", -". c #000000", -"+ c #FF0000", -"... ...", -".++. .++.", -".+++. .+++.", -" .+++. .+++. ", -" .+++. .+++. ", -" .+++..+++. ", -" .++++++. ", -" .++++. ", -" .++++. ", -" .++++++. ", -" .+++..+++. ", -" .+++. .+++. ", -" .+++. .+++. ", -".+++. .+++.", -".++. .++.", -"... ..."}; diff --git a/widgets/sample.table b/widgets/sample.table deleted file mode 100644 index 45c8ff0691..0000000000 --- a/widgets/sample.table +++ /dev/null @@ -1,11 +0,0 @@ -Col1 Col2 Address Title Dorks -c1.a c2.a a.a tit-1 DorkA -c1.b c2.b a.b tit-2 DDork -c1.c c2.c a.c tit-1 DorkB -c1.d c2.d a.d tit-2 ADork -c1.e c2.e a.e tit-1 DorkC -c1.f c2.f a.f tit-2 UDork -c1.g c2.g a.g tit-3 Dork--- -j k k tit-1 DorkA - - diff --git a/widgets/shortcut-bar/Makefile.am b/widgets/shortcut-bar/Makefile.am new file mode 100644 index 0000000000..c60c57e872 --- /dev/null +++ b/widgets/shortcut-bar/Makefile.am @@ -0,0 +1,30 @@ + +noinst_LIBRARIES = libshortcut-bar.a +noinst_PROGRAMS = test-shortcut-bar + +INCLUDES = \ + -DEVOLUTION_VERSION=\""$(VERSION)"\" \ + $(EXTRA_GNOME_CFLAGS) + +libshortcut_bar_a_SOURCES = \ + e-clipped-label.c \ + e-clipped-label.h \ + e-group-bar.c \ + e-group-bar.h \ + e-icon-bar-bg-item.c \ + e-icon-bar-bg-item.h \ + e-icon-bar-text-item.c \ + e-icon-bar-text-item.h \ + e-icon-bar.c \ + e-icon-bar.h \ + e-shortcut-bar.c \ + e-shortcut-bar.h \ + e-vscrolled-bar.c \ + e-vscrolled-bar.h + +test_shortcut_bar_SOURCES = \ + test-shortcut-bar.c + +test_shortcut_bar_LDADD = \ + ./libshortcut-bar.a \ + $(EXTRA_GNOME_LIBS) \ diff --git a/widgets/shortcut-bar/e-clipped-label.c b/widgets/shortcut-bar/e-clipped-label.c new file mode 100644 index 0000000000..0b595f6063 --- /dev/null +++ b/widgets/shortcut-bar/e-clipped-label.c @@ -0,0 +1,361 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ + +/* + * This is similar to GtkLabel but clips itself and displays '...' if it + * can't fit inside its allocated area. The intended use is for inside buttons + * that are a fixed size. The GtkLabel would normally display only the middle + * part of the text, which doesn't look very good. This only supports one line + * of text (so no wrapping/justification), without underlined characters. + */ + +#include <math.h> + +#include <gdk/gdki18n.h> +#include <libgnome/gnome-defs.h> +#include <libgnome/gnome-i18n.h> + +#include "e-clipped-label.h" + + +static void e_clipped_label_class_init (EClippedLabelClass *class); +static void e_clipped_label_init (EClippedLabel *label); +static void e_clipped_label_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void e_clipped_label_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint e_clipped_label_expose (GtkWidget *widget, + GdkEventExpose *event); +static void e_clipped_label_recalc_chars_displayed (EClippedLabel *label); + + +static GtkMiscClass *parent_class; + +/* This is the string to draw when the label is clipped, e.g. '...'. */ +static gchar *e_clipped_label_ellipsis; + +/* Flags used in chars_displayed field. Must be negative. */ +#define E_CLIPPED_LABEL_NEED_RECALC -1 +#define E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL -2 + + +GtkType +e_clipped_label_get_type (void) +{ + static GtkType e_clipped_label_type = 0; + + if (!e_clipped_label_type){ + GtkTypeInfo e_clipped_label_info = { + "EClippedLabel", + sizeof (EClippedLabel), + sizeof (EClippedLabelClass), + (GtkClassInitFunc) e_clipped_label_class_init, + (GtkObjectInitFunc) e_clipped_label_init, + NULL, /* reserved 1 */ + NULL, /* reserved 2 */ + (GtkClassInitFunc) NULL + }; + + parent_class = gtk_type_class (GTK_TYPE_MISC); + e_clipped_label_type = gtk_type_unique (GTK_TYPE_MISC, + &e_clipped_label_info); + } + + return e_clipped_label_type; +} + + +static void +e_clipped_label_class_init (EClippedLabelClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass *) class; + widget_class = (GtkWidgetClass *) class; + + /* Method override */ + widget_class->size_request = e_clipped_label_size_request; + widget_class->size_allocate = e_clipped_label_size_allocate; + widget_class->expose_event = e_clipped_label_expose; + + e_clipped_label_ellipsis = _("..."); +} + + +static void +e_clipped_label_init (EClippedLabel *label) +{ + GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW); + + label->label = NULL; + label->label_wc = NULL; + label->chars_displayed = E_CLIPPED_LABEL_NEED_RECALC; +} + + +/** + * e_clipped_label_new: + * + * @text: The label text. + * @Returns: A new #EClippedLabel. + * + * Creates a new #EClippedLabel with the given text. + **/ +GtkWidget * +e_clipped_label_new (const gchar *text) +{ + GtkWidget *label; + + label = GTK_WIDGET (gtk_type_new (e_clipped_label_get_type ())); + + if (text && *text) + e_clipped_label_set_text (E_CLIPPED_LABEL (label), text); + + return label; +} + + +static void +e_clipped_label_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + EClippedLabel *label; + GdkFont *font; + + g_return_if_fail (E_IS_CLIPPED_LABEL (widget)); + g_return_if_fail (requisition != NULL); + + label = E_CLIPPED_LABEL (widget); + font = widget->style->font; + + requisition->width = 0; + requisition->height = font->ascent + font->descent + + 2 * GTK_MISC (widget)->ypad; +} + + +static void +e_clipped_label_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + EClippedLabel *label; + + label = E_CLIPPED_LABEL (widget); + + widget->allocation = *allocation; + + /* Flag that we need to recalculate how many characters to display. */ + label->chars_displayed = E_CLIPPED_LABEL_NEED_RECALC; +} + + +static gint +e_clipped_label_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + EClippedLabel *label; + GtkMisc *misc; + gint x, y; + GdkFont *font; + gchar *tmp_str, tmp_ch; + + g_return_val_if_fail (E_IS_CLIPPED_LABEL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + label = E_CLIPPED_LABEL (widget); + misc = GTK_MISC (widget); + font = widget->style->font; + + /* If the label isn't visible or has no text, just return. */ + if (!GTK_WIDGET_VISIBLE (widget) || !GTK_WIDGET_MAPPED (widget) + || !label->label || (*label->label == '\0')) + return TRUE; + + /* Recalculate the number of characters displayed, if necessary. */ + if (label->chars_displayed == E_CLIPPED_LABEL_NEED_RECALC) + e_clipped_label_recalc_chars_displayed (label); + + /* + * GC Clipping + */ + gdk_gc_set_clip_rectangle (widget->style->white_gc, + &event->area); + gdk_gc_set_clip_rectangle (widget->style->fg_gc[widget->state], + &event->area); + + y = floor (widget->allocation.y + (gint)misc->ypad + + (((gint)widget->allocation.height - 2 * (gint)misc->ypad + - (gint)font->ascent - font->descent) + * misc->yalign) + 0.5) + font->ascent; + + if (label->chars_displayed == E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL) { + x = floor (widget->allocation.x + (gint)misc->xpad + + (((gint)widget->allocation.width - + (gint)label->label_width - 2 * (gint)misc->xpad) + * misc->xalign) + 0.5); + + gtk_paint_string (widget->style, widget->window, widget->state, + &event->area, widget, "label", + x, y, label->label); + } else { + x = widget->allocation.x + (gint)misc->xpad; + + tmp_ch = label->label_wc[label->chars_displayed]; + label->label_wc[label->chars_displayed] = '\0'; + tmp_str = gdk_wcstombs (label->label_wc); + if (tmp_str) { + gtk_paint_string (widget->style, widget->window, + widget->state, &event->area, + widget, "label", + x, y, tmp_str); + g_free (tmp_str); + } + label->label_wc[label->chars_displayed] = tmp_ch; + + x = widget->allocation.x + (gint)misc->xpad + + label->ellipsis_x; + gtk_paint_string (widget->style, widget->window, widget->state, + &event->area, widget, "label", + x, y, e_clipped_label_ellipsis); + } + + gdk_gc_set_clip_mask (widget->style->white_gc, NULL); + gdk_gc_set_clip_mask (widget->style->fg_gc[widget->state], NULL); + + return TRUE; +} + + +/** + * e_clipped_label_get_text: + * + * @label: An #EClippedLabel. + * @Return: The label text. + * + * Returns the label text, or NULL. + **/ +gchar* +e_clipped_label_get_text (EClippedLabel *label) +{ + g_return_val_if_fail (E_IS_CLIPPED_LABEL (label), NULL); + + return label->label; +} + + +/** + * e_clipped_label_set_text: + * + * @label: An #EClippedLabel. + * @text: The new label text. + * + * Sets the label text. + **/ +void +e_clipped_label_set_text (EClippedLabel *label, + const gchar *text) +{ + gint len; + + g_return_if_fail (E_IS_CLIPPED_LABEL (label)); + + if (label->label != text || !label->label || !text + || strcmp (label->label, text)) { + g_free (label->label); + g_free (label->label_wc); + label->label = NULL; + label->label_wc = NULL; + + if (text) { + label->label = g_strdup (text); + len = strlen (text); + label->label_wc = g_new (GdkWChar, len + 1); + label->wc_len = gdk_mbstowcs (label->label_wc, + label->label, len + 1); + label->label_wc[label->wc_len] = '\0'; + } + + /* Reset the number of characters displayed, so it is + recalculated when needed. */ + label->chars_displayed = E_CLIPPED_LABEL_NEED_RECALC; + + /* We don't queue a resize, since the label should not affect + the widget size, but we queue a draw. */ + gtk_widget_queue_draw (GTK_WIDGET (label)); + } +} + + +static void +e_clipped_label_recalc_chars_displayed (EClippedLabel *label) +{ + GdkFont *font; + gint max_width, width, ch, last_width; + + font = GTK_WIDGET (label)->style->font; + + max_width = GTK_WIDGET (label)->allocation.width + - 2 * GTK_MISC (label)->xpad; + + if (!label->label) { + label->chars_displayed = 0; + return; + } + + /* See if the entire label fits in the allocated width. */ + label->label_width = gdk_string_width (font, label->label); + if (label->label_width <= max_width) { + label->chars_displayed = E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL; + return; + } + + /* Calculate the width of the ellipsis string. */ + max_width -= gdk_string_measure (font, e_clipped_label_ellipsis); + + if (max_width <= 0) { + label->chars_displayed = 0; + label->ellipsis_x = 0; + return; + } + + /* Step through the wide-char label, adding on the widths of the + characters, until we can't fit any more in. */ + width = last_width = 0; + for (ch = 0; ch < label->wc_len; ch++) { + width += gdk_char_width_wc (font, label->label_wc[ch]); + + if (width > max_width) { + label->chars_displayed = ch; + label->ellipsis_x = last_width; + return; + } + + last_width = width; + } + + g_warning ("Clipped label width not exceeded as expected"); + label->chars_displayed = E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL; +} + diff --git a/widgets/shortcut-bar/e-clipped-label.h b/widgets/shortcut-bar/e-clipped-label.h new file mode 100644 index 0000000000..b94d261c11 --- /dev/null +++ b/widgets/shortcut-bar/e-clipped-label.h @@ -0,0 +1,90 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ + +/* + * This is similar to GtkLabel but clips itself and displays '...' if it + * can't fit inside its allocated area. The intended use is for inside buttons + * that are a fixed size. The GtkLabel would normally display only the middle + * part of the text, which doesn't look very good. This only supports one line + * of text (so no wrapping/justification), without underlined characters. + */ +#ifndef _E_CLIPPED_LABEL_H_ +#define _E_CLIPPED_LABEL_H_ + +#include <gtk/gtkmisc.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define E_CLIPPED_LABEL(obj) GTK_CHECK_CAST (obj, e_clipped_label_get_type (), EClippedLabel) +#define E_CLIPPED_LABEL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, e_clipped_label_get_type (), EClippedLabelClass) +#define E_IS_CLIPPED_LABEL(obj) GTK_CHECK_TYPE (obj, e_clipped_label_get_type ()) + + +typedef struct _EClippedLabel EClippedLabel; +typedef struct _EClippedLabelClass EClippedLabelClass; + +struct _EClippedLabel +{ + GtkMisc misc; + + gchar *label; + GdkWChar *label_wc; + + /* This is the number of wide characters in the label. */ + gint wc_len; + + /* This is the width of the entire label string, in pixels. */ + gint label_width; + + /* This is the number of characters we can fit in, or + E_CLIPPED_LABEL_NEED_RECALC if it needs to be recalculated, or + E_CLIPPED_LABEL_SHOW_ENTIRE_LABEL to show the entire label. */ + gint chars_displayed; + + /* This is the x position to display the ellipsis string, e.g. '...', + relative to the start of the label. */ + gint ellipsis_x; +}; + +struct _EClippedLabelClass +{ + GtkMiscClass parent_class; +}; + + +GtkType e_clipped_label_get_type (void); +GtkWidget* e_clipped_label_new (const gchar *text); + +gchar* e_clipped_label_get_text (EClippedLabel *label); +void e_clipped_label_set_text (EClippedLabel *label, + const gchar *text); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _E_CLIPPED_LABEL_H_ */ diff --git a/widgets/shortcut-bar/e-group-bar.c b/widgets/shortcut-bar/e-group-bar.c new file mode 100644 index 0000000000..603aa6f78f --- /dev/null +++ b/widgets/shortcut-bar/e-group-bar.c @@ -0,0 +1,1498 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ + +/* + * ShortcutBar displays a vertical bar with a number of Groups, each of which + * contains any number of icons. It is used on the left of the main application + * window so users can easily access items such as folders and files. + */ + +#include <math.h> + +#include <gnome.h> + +#include "e-group-bar.h" + +#define E_GROUP_BAR_SCROLL_TIMEOUT 10 +#define E_GROUP_BAR_MIN_STEP_SIZE 4 + +#define E_GROUP_BAR_AUTO_SHOW_TIMEOUT 300 + + +static void e_group_bar_class_init (EGroupBarClass *class); +static void e_group_bar_init (EGroupBar *group_bar); +static void e_group_bar_destroy (GtkObject *object); +static void e_group_bar_realize (GtkWidget *widget); +static void e_group_bar_unrealize (GtkWidget *widget); +static void e_group_bar_map (GtkWidget *widget); +static void e_group_bar_unmap (GtkWidget *widget); +static void e_group_bar_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void e_group_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint e_group_bar_expose (GtkWidget *widget, + GdkEventExpose *event); +static void e_group_bar_draw (GtkWidget *widget, + GdkRectangle *area); +static void e_group_bar_add (GtkContainer *container, + GtkWidget *widget); +static void e_group_bar_remove (GtkContainer *container, + GtkWidget *widget); +static void e_group_bar_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); + +static void e_group_bar_create_group_button_window (EGroupBar *group_bar, + gint group_num); +static void e_group_bar_create_group_child_window (EGroupBar *group_bar, + gint group_num); +static gint e_group_bar_get_group_button_position (EGroupBar *group_bar, + gint group_num); +static gint e_group_bar_sum_button_heights (EGroupBar *group_bar, + gint first, + gint last); +static gint e_group_bar_get_child_height (EGroupBar *group_bar); +static gint e_group_bar_get_group_child_position (EGroupBar *group_bar, + gint group_num); + +static void e_group_bar_on_button_clicked (GtkWidget *group_button, + EGroupBar *group_bar); +static gint e_group_bar_find_button (EGroupBar *group_bar, + GtkWidget *group_button); +static void e_group_bar_start_animation (EGroupBar *group_bar, + gint group_num); +static gboolean e_group_bar_timeout_handler (gpointer data); +static gint e_group_bar_get_increment (EGroupBar *group_bar, + gint window_y, + gint window_target_y); +static gboolean e_group_bar_on_button_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time, + EGroupBar *group_bar); +static void e_group_bar_on_button_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time, + EGroupBar *group_bar); +static gboolean e_group_bar_auto_show (gpointer data); +static void e_group_bar_stop_all_animation (EGroupBar *group_bar); + + +static GtkContainerClass *parent_class; + + +GtkType +e_group_bar_get_type (void) +{ + static GtkType e_group_bar_type = 0; + + if (!e_group_bar_type){ + GtkTypeInfo e_group_bar_info = { + "EGroupBar", + sizeof (EGroupBar), + sizeof (EGroupBarClass), + (GtkClassInitFunc) e_group_bar_class_init, + (GtkObjectInitFunc) e_group_bar_init, + NULL, /* reserved 1 */ + NULL, /* reserved 2 */ + (GtkClassInitFunc) NULL + }; + + parent_class = gtk_type_class (GTK_TYPE_CONTAINER); + e_group_bar_type = gtk_type_unique (GTK_TYPE_CONTAINER, + &e_group_bar_info); + } + + return e_group_bar_type; +} + + +static void +e_group_bar_class_init (EGroupBarClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass *) class; + widget_class = (GtkWidgetClass *) class; + container_class = (GtkContainerClass *) class; + + /* Method override */ + object_class->destroy = e_group_bar_destroy; + + widget_class->realize = e_group_bar_realize; + widget_class->unrealize = e_group_bar_unrealize; + widget_class->map = e_group_bar_map; + widget_class->unmap = e_group_bar_unmap; + widget_class->size_request = e_group_bar_size_request; + widget_class->size_allocate = e_group_bar_size_allocate; + widget_class->expose_event = e_group_bar_expose; + widget_class->draw = e_group_bar_draw; + + container_class->add = e_group_bar_add; + container_class->remove = e_group_bar_remove; + container_class->forall = e_group_bar_forall; +} + + +static void +e_group_bar_init (EGroupBar *group_bar) +{ + + GTK_WIDGET_UNSET_FLAGS (group_bar, GTK_NO_WINDOW); + + /* We don't want child resizes to propagate up to the parent. */ + gtk_container_set_resize_mode (GTK_CONTAINER (group_bar), + GTK_RESIZE_QUEUE); + + group_bar->children = g_array_new (FALSE, FALSE, + sizeof (EGroupBarChild)); + + group_bar->current_group_num = -1; + group_bar->buttons_homogeneous = TRUE; + group_bar->max_button_height = 0; + group_bar->animation_timeout_id = 0; +} + + +/** + * e_group_bar_new: + * @Returns: a new #EGroupBar. + * + * Creates a new #EGroupBar. + **/ +GtkWidget * +e_group_bar_new (void) +{ + GtkWidget *group_bar; + + group_bar = GTK_WIDGET (gtk_type_new (e_group_bar_get_type ())); + + return group_bar; +} + + +static void +e_group_bar_destroy (GtkObject *object) +{ + EGroupBar *group_bar; + + group_bar = E_GROUP_BAR (object); + + e_group_bar_stop_all_animation (group_bar); + + /* The parent GtkContainer class will automatically destroy all the + child widgets, but it calls gtk_container_foreach() so we must not + destroy our children array until after. */ + GTK_OBJECT_CLASS (parent_class)->destroy (object); + + g_array_free (group_bar->children, TRUE); +} + + +static void +e_group_bar_realize (GtkWidget *widget) +{ + EGroupBar *group_bar; + EGroupBarChild *group; + GdkWindowAttr attributes; + gint attributes_mask; + gint border_width, group_num; + + g_return_if_fail (widget != NULL); + g_return_if_fail (E_IS_GROUP_BAR (widget)); + + group_bar = E_GROUP_BAR (widget); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + border_width = GTK_CONTAINER (group_bar)->border_width; + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x + border_width; + attributes.y = widget->allocation.y + border_width; + attributes.width = widget->allocation.width - 2 * border_width; + attributes.height = widget->allocation.height - 2 * border_width; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y + | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, + GTK_STATE_NORMAL); + + gdk_window_set_back_pixmap (widget->window, NULL, TRUE); + + /* Create windows for all the buttons & group canvases. */ + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + e_group_bar_create_group_button_window (group_bar, group_num); + e_group_bar_create_group_child_window (group_bar, group_num); + } +} + + +static void +e_group_bar_unrealize (GtkWidget *widget) +{ + EGroupBar *group_bar; + EGroupBarChild *group; + gint group_num; + + g_return_if_fail (widget != NULL); + g_return_if_fail (E_IS_GROUP_BAR (widget)); + + group_bar = E_GROUP_BAR (widget); + + /* Destroy the windows for all the buttons & group canvases. */ + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + if (group->button_window) { + gdk_window_set_user_data (group->button_window, NULL); + gdk_window_destroy (group->button_window); + group->button_window = NULL; + } + if (group->child_window) { + gdk_window_set_user_data (group->child_window, NULL); + gdk_window_destroy (group->child_window); + group->child_window = NULL; + } + } + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + + +static void +e_group_bar_map (GtkWidget *widget) +{ + EGroupBar *group_bar; + EGroupBarChild *group; + gint group_num; + + g_return_if_fail (widget != NULL); + g_return_if_fail (E_IS_GROUP_BAR (widget)); + + group_bar = E_GROUP_BAR (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + /* We do this in reverse order, and lower all the child windows, so + the stacking order ends up correct. */ + for (group_num = group_bar->children->len - 1; + group_num >= 0; + group_num--) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + if (group->button_window) { + gdk_window_show (group->button_window); + } + + if (group->button + && GTK_WIDGET_VISIBLE (group->button) + && !GTK_WIDGET_MAPPED (group->button)) { + gtk_widget_map (group->button); + } + + if (group->child_window) { + gdk_window_show (group->child_window); + gdk_window_lower (group->child_window); + } + + if (group->child + && GTK_WIDGET_VISIBLE (group->child) + && !GTK_WIDGET_MAPPED (group->child)) + gtk_widget_map (group->child); + } + + gdk_window_show (widget->window); +} + + +static void +e_group_bar_unmap (GtkWidget *widget) +{ + EGroupBar *group_bar; + EGroupBarChild *group; + gint group_num; + + g_return_if_fail (widget != NULL); + g_return_if_fail (E_IS_GROUP_BAR (widget)); + + group_bar = E_GROUP_BAR (widget); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + if (group->button_window) { + gdk_window_hide (group->button_window); + } + + if (group->button + && GTK_WIDGET_MAPPED (group->button)) + gtk_widget_unmap (group->button); + + if (group->child_window) { + gdk_window_hide (group->child_window); + } + + if (group->child + && GTK_WIDGET_MAPPED (group->child)) + gtk_widget_unmap (group->child); + } + + gdk_window_hide (widget->window); +} + + +static void +e_group_bar_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + EGroupBar *group_bar; + EGroupBarChild *group; + gint group_num, max_child_height; + GtkRequisition child_requisition; + + g_return_if_fail (widget != NULL); + g_return_if_fail (E_IS_GROUP_BAR (widget)); + g_return_if_fail (requisition != NULL); + + group_bar = E_GROUP_BAR (widget); + + /* We set the requisition width to the largest requested width of the + child widgets. The requisition height is set to the sum of all the + button heights plus the height of the largest child. */ + requisition->width = 0; + requisition->height = 0; + + /* We have to call size_request on all children, even though we don't + use the results, since some widgets like GtkLabel depend on it. */ + group_bar->max_button_height = 0; + max_child_height = 0; + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + if (group->button) { + gtk_widget_size_request (group->button, + &child_requisition); + group->button_height = child_requisition.height; + } else { + group->button_height = 0; + } + + group_bar->max_button_height = MAX (group_bar->max_button_height, group->button_height); + requisition->height += child_requisition.height; + + if (group->child) { + gtk_widget_size_request (group->child, + &child_requisition); + max_child_height = MAX (max_child_height, + child_requisition.height); + requisition->width = MAX (requisition->width, + child_requisition.width); + } + } + + requisition->height += max_child_height; + + /* Add on the standard container border widths. */ + requisition->width += GTK_CONTAINER (widget)->border_width * 2; + requisition->height += GTK_CONTAINER (widget)->border_width * 2; +} + + +static void +e_group_bar_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + EGroupBar *group_bar; + EGroupBarChild *group; + gint group_num, border_width, width, height, child_height, y; + GtkAllocation button_allocation, child_allocation; + + group_bar = E_GROUP_BAR (widget); + + /* All child & button windows and widgets use the same width as the + group bar minus the border width. */ + border_width = GTK_CONTAINER (widget)->border_width; + width = allocation->width - border_width * 2; + height = allocation->height - border_width * 2; + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x + border_width, + allocation->y + border_width, + width, height); + + /* All the child widgets use the same height. */ + child_height = e_group_bar_get_child_height (group_bar); + + /* The buttons are always in the top-left of the button windows, and + all have the same width. The height is calculated for each group. */ + button_allocation.x = 0; + button_allocation.y = 0; + button_allocation.width = width; + + /* The child widgets are always in the top-left of the child windows, + and all have the same width and height. */ + child_allocation.x = 0; + child_allocation.y = 0; + child_allocation.width = width; + child_allocation.height = child_height; + + /* Step through the groups, placing the windows as necessary, and + allocating the areas for the child widgets. Note that if a button + or child window is in the middle of an animation, we just resize it + and update the target position, and let the animation continue. */ + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + /* Calculate the y position of the button, which depends on + the currently selected group and the button heights. */ + y = e_group_bar_get_group_button_position (group_bar, group_num); + button_allocation.height = group_bar->buttons_homogeneous ? group_bar->max_button_height : group->button_height; + + if (GTK_WIDGET_REALIZED (group->button)) { + if (group->button_window_in_animation) { + gdk_window_resize (group->button_window, + width, button_allocation.height); + group->button_window_target_y = y; + } else { + gdk_window_move_resize (group->button_window, + 0, y, width, button_allocation.height); + } + } + gtk_widget_size_allocate (group->button, &button_allocation); + + if (GTK_WIDGET_REALIZED (group->child)) { + if (group->child_window_in_animation) { + gdk_window_resize (group->child_window, + width, child_height); + group->child_window_target_y = y + button_allocation.height; + } else { + gdk_window_move_resize (group->child_window, + 0, y + button_allocation.height, + width, child_height); + } + } + gtk_widget_size_allocate (group->child, &child_allocation); + } +} + + +static gint +e_group_bar_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + EGroupBar *group_bar; + EGroupBarChild *group; + GdkEventExpose child_event; + gint group_num; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (E_IS_GROUP_BAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) { + group_bar = E_GROUP_BAR (widget); + + child_event = *event; + + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + if (event->window == group->button_window + && GTK_WIDGET_DRAWABLE (group->button) + && GTK_WIDGET_NO_WINDOW (group->button) + && gtk_widget_intersect (group->button, &event->area, &child_event.area)) + gtk_widget_event (group->button, (GdkEvent*) &child_event); + + if (event->window == group->child_window + && GTK_WIDGET_DRAWABLE (group->child) + && GTK_WIDGET_NO_WINDOW (group->child) + && gtk_widget_intersect (group->child, &event->area, &child_event.area)) + gtk_widget_event (group->child, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + + +static void +e_group_bar_draw (GtkWidget *widget, + GdkRectangle *area) +{ + EGroupBar *group_bar; + EGroupBarChild *group; + gint group_num; +#if 0 + GdkRectangle child_area; +#endif + g_return_if_fail (widget != NULL); + g_return_if_fail (E_IS_GROUP_BAR (widget)); + + g_print ("In e_group_bar_draw %i,%i %ix%i\n", area->x, area->y, + area->width, area->height); + + if (GTK_WIDGET_DRAWABLE (widget)) { + group_bar = E_GROUP_BAR (widget); + + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + /* FIXME */ +#if 0 + if (GTK_WIDGET_DRAWABLE (child->widget) && + gtk_widget_intersect (child->widget, area, &child_area)) + gtk_widget_draw (child->widget, &child_area); +#endif + } + } +} + + +static void +e_group_bar_add (GtkContainer *container, + GtkWidget *widget) +{ + EGroupBar *group_bar; + GtkWidget *button; + gchar buffer[32]; + + g_return_if_fail (container != NULL); + g_return_if_fail (E_IS_GROUP_BAR (container)); + g_return_if_fail (widget != NULL); + + g_snprintf (buffer, sizeof (buffer), _("Group %i"), + group_bar->children->len + 1); + button = gtk_button_new_with_label (buffer); + gtk_widget_show (button); + + e_group_bar_add_group (group_bar, widget, button, -1); +} + + +static void +e_group_bar_remove (GtkContainer *container, + GtkWidget *widget) +{ + EGroupBar *group_bar; + gint group_num; + + g_return_if_fail (container != NULL); + g_return_if_fail (E_IS_GROUP_BAR (container)); + g_return_if_fail (widget != NULL); + + group_bar = E_GROUP_BAR (container); + + group_num = e_group_bar_get_group_num (group_bar, widget); + e_group_bar_remove_group (group_bar, group_num); +} + + +static void +e_group_bar_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + EGroupBar *group_bar; + EGroupBarChild *group; + gint group_num; + GList *tmp_list; + + g_return_if_fail (container != NULL); + g_return_if_fail (E_IS_GROUP_BAR (container)); + g_return_if_fail (callback != NULL); + + group_bar = E_GROUP_BAR (container); + + /* Note that drag-and-drop does not check the Z-order of widgets, so + we have to iterate through them from top to bottom, or it will + not work properly. We also have to use temporary lists so widgets + can be safely destroyed while iterating. */ + + if (include_internals) { + tmp_list = NULL; + for (group_num = group_bar->children->len - 1; + group_num >= 0; + group_num--) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + if (group->button) + tmp_list = g_list_prepend (tmp_list, + group->button); + } + + g_list_foreach (tmp_list, (GFunc) callback, callback_data); + g_list_free (tmp_list); + } + + tmp_list = NULL; + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + if (group->child) + tmp_list = g_list_prepend (tmp_list, group->child); + } + g_list_foreach (tmp_list, (GFunc) callback, callback_data); + g_list_free (tmp_list); +} + + +static void +e_group_bar_create_group_button_window (EGroupBar *group_bar, + gint group_num) +{ + EGroupBarChild *group; + GtkWidget *widget; + GdkWindowAttr attributes; + gint attributes_mask; + gint y, height, border_width; + + widget = GTK_WIDGET (group_bar); + + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + y = e_group_bar_get_group_button_position (group_bar, group_num); + height = group_bar->buttons_homogeneous ? group_bar->max_button_height + : group->button_height; + border_width = GTK_CONTAINER (group_bar)->border_width; + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = 0; + attributes.y = y; + attributes.width = widget->allocation.width - 2 * border_width; + attributes.height = height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y + | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + group->button_window = gdk_window_new (widget->window, &attributes, + attributes_mask); + gdk_window_set_user_data (group->button_window, widget); + + gtk_widget_set_parent_window (group->button, + group->button_window); + gdk_window_set_back_pixmap (group->button_window, NULL, TRUE); +} + + +static void +e_group_bar_create_group_child_window (EGroupBar *group_bar, + gint group_num) +{ + EGroupBarChild *group; + GtkWidget *widget; + GdkWindowAttr attributes; + gint attributes_mask; + gint y, height, border_width; + + widget = GTK_WIDGET (group_bar); + + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + y = e_group_bar_get_group_button_position (group_bar, group_num); + y += group_bar->buttons_homogeneous ? group_bar->max_button_height + : group->button_height; + height = e_group_bar_get_child_height (group_bar); + border_width = GTK_CONTAINER (group_bar)->border_width; + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = 0; + attributes.y = y; + attributes.width = widget->allocation.width - 2 * border_width; + attributes.height = height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y + | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + group->child_window = gdk_window_new (widget->window, &attributes, + attributes_mask); + gdk_window_set_user_data (group->child_window, widget); + + gtk_widget_set_parent_window (GTK_WIDGET (group->child), + group->child_window); + gdk_window_set_back_pixmap (group->child_window, NULL, TRUE); +} + + +/* This returns the y position of a group's button within the EGroupBar window. + */ +static gint +e_group_bar_get_group_button_position (EGroupBar *group_bar, + gint group_num) +{ + gint border_width, window_height, y; + + border_width = GTK_CONTAINER (group_bar)->border_width; + window_height = GTK_WIDGET (group_bar)->allocation.height - 2 * border_width; + + if (group_num <= group_bar->current_group_num) + y = e_group_bar_sum_button_heights (group_bar, 0, group_num - 1); + else + y = window_height - e_group_bar_sum_button_heights (group_bar, group_num, group_bar->children->len - 1); + + return y; +} + + +/* This returns the sum of all the buttons from first to last inclusive. */ +static gint +e_group_bar_sum_button_heights (EGroupBar *group_bar, gint first, gint last) +{ + EGroupBarChild *group; + gint height, group_num; + + height = 0; + + if (group_bar->buttons_homogeneous) + return (last - first + 1) * group_bar->max_button_height; + + for (group_num = first; group_num <= last; group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + height += group->button_height; + } + + return height; +} + + +static gint +e_group_bar_get_group_child_position (EGroupBar *group_bar, + gint group_num) +{ + EGroupBarChild *group; + gint y; + + y = e_group_bar_get_group_button_position (group_bar, group_num); + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + y += group_bar->buttons_homogeneous ? group_bar->max_button_height + : group->button_height; + + return y; +} + + +static gint +e_group_bar_get_child_height (EGroupBar *group_bar) +{ + EGroupBarChild *group; + gint group_num; + + /* Start with the allocated height of the EGroupBar, less the border.*/ + group_bar->child_height = GTK_WIDGET (group_bar)->allocation.height; + group_bar->child_height -= 2 * GTK_CONTAINER (group_bar)->border_width; + + /* Now subtract the heights of all the buttons. */ + if (group_bar->buttons_homogeneous) { + group_bar->child_height -= group_bar->children->len * group_bar->max_button_height; + } else { + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + group_bar->child_height -= group->button_height; + } + } + + return group_bar->child_height; +} + + +/* + * Insertion, reordering and deletion of items. + */ + +/** + * e_group_bar_add_group: + * @group_bar: an #EGroupBar. + * @child: the child widget to add. + * @button: the button used to show the child widget. + * @position: the new group's position, or -1 to place it last. + * @Returns: the position of the new group. + * + * Adds a new group to a #EGroupBar at the given position. + **/ +gint +e_group_bar_add_group (EGroupBar *group_bar, + GtkWidget *child, + GtkWidget *button, + gint position) +{ + EGroupBarChild *group, empty_group, *tmp_group; + gint group_num, tmp_group_num; + + g_return_val_if_fail (group_bar != NULL, -1); + g_return_val_if_fail (E_IS_GROUP_BAR (group_bar), -1); + g_return_val_if_fail (child != NULL, -1); + g_return_val_if_fail (button != NULL, -1); + g_return_val_if_fail (GTK_IS_BUTTON (button), -1); + + /* Append an empty group to the children array and get a pointer to + it, so we can use it like a normal group. */ + group_num = group_bar->children->len; + g_array_append_val (group_bar->children, empty_group); + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + /* Initialize the group. */ + group->button = button; + group->button_window = NULL; + group->child = child; + group->child_window = NULL; + group->button_window_in_animation = FALSE; + group->child_window_in_animation = FALSE; + group->button_window_target_y = 0; + group->child_window_target_y = 0; + + /* If we don't have a current group, set it to the first one. */ + if (group_bar->current_group_num == -1) + group_bar->current_group_num = 0; + + /* If the EGroupBar widget is realize, we need to create the child + windows to put the button & child in. */ + if (GTK_WIDGET_REALIZED (group_bar)) { + e_group_bar_create_group_button_window (group_bar, group_num); + e_group_bar_create_group_child_window (group_bar, group_num); + + /* We need to lower all the child windows of the previous + groups, in reverse order, to keep the stacking order + correct. */ + for (tmp_group_num = group_num - 1; + tmp_group_num >= 0; + tmp_group_num--) { + tmp_group = &g_array_index (group_bar->children, + EGroupBarChild, + tmp_group_num); + gdk_window_lower (group->child_window); + } + } + + gtk_widget_set_parent (group->button, GTK_WIDGET (group_bar)); + gtk_widget_set_parent (group->child, GTK_WIDGET (group_bar)); + + if (GTK_WIDGET_REALIZED (group_bar)) { + gtk_widget_realize (group->button); + gtk_widget_realize (group->child); + } + + if (GTK_WIDGET_VISIBLE (group_bar) + && GTK_WIDGET_MAPPED (group_bar)) { + if (group->button + && GTK_WIDGET_VISIBLE (group->button) + && !GTK_WIDGET_MAPPED (group->button)) { + gtk_widget_map (group->button); + gtk_widget_queue_resize (group->button); + } + if (group->child + && GTK_WIDGET_VISIBLE (group->child) + && !GTK_WIDGET_MAPPED (group->child)) { + gtk_widget_map (group->child); + gtk_widget_queue_resize (group->child); + } + } + + gtk_signal_connect (GTK_OBJECT (group->button), "clicked", + GTK_SIGNAL_FUNC (e_group_bar_on_button_clicked), + group_bar); + + gtk_signal_connect (GTK_OBJECT (group->button), "drag_motion", + GTK_SIGNAL_FUNC (e_group_bar_on_button_drag_motion), + group_bar); + gtk_signal_connect (GTK_OBJECT (group->button), "drag_leave", + GTK_SIGNAL_FUNC (e_group_bar_on_button_drag_leave), + group_bar); + + return group_num; +} + + +/** + * e_group_bar_reorder_group: + * @group_bar: an #EGroupBar. + * @group_num: the index of the group to move. + * @new_position: the new position of the group. + * + * Moves a group to a new position within the #EGroupBar. + **/ +void +e_group_bar_reorder_group (EGroupBar *group_bar, + gint group_num, + gint new_position) +{ + g_return_if_fail (E_IS_GROUP_BAR (group_bar)); + +} + + +/** + * e_group_bar_remove_group: + * @group_bar: an #EGroupBar. + * @group_num: the index of the group to remove. + * + * Removes a group from an #EGroupBar. + **/ +void +e_group_bar_remove_group (EGroupBar *group_bar, + gint group_num) +{ + EGroupBarChild *group; + + g_return_if_fail (E_IS_GROUP_BAR (group_bar)); + g_return_if_fail (group_num >= 0); + g_return_if_fail (group_num < group_bar->children->len); + + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + /* Stop any animation. */ + e_group_bar_stop_all_animation (group_bar); + + gtk_widget_unparent (group->child); + if (group->button) + gtk_widget_unparent (group->button); + + if (group->button_window) { + gdk_window_set_user_data (group->button_window, NULL); + gdk_window_destroy (group->button_window); + } + if (group->child_window) { + gdk_window_set_user_data (group->child_window, NULL); + gdk_window_destroy (group->child_window); + } + + g_array_remove_index (group_bar->children, group_num); + + /* Make sure the current group is valid. */ + if (group_bar->current_group_num >= group_bar->children->len) + group_bar->current_group_num = group_bar->children->len - 1; + + gtk_widget_queue_resize (GTK_WIDGET (group_bar)); +} + + +/* + * Getting & setting the current group. + */ + +/** + * e_group_bar_get_current_group_num: + * @group_bar: an #EGroupBar. + * @Returns: the index of the group currently displayed. + * + * Returns the index of the group currently displayed. + **/ +gint +e_group_bar_get_current_group_num (EGroupBar *group_bar) +{ + g_return_val_if_fail (E_IS_GROUP_BAR (group_bar), -1); + + return group_bar->current_group_num; +} + + +/** + * e_group_bar_set_current_group_num: + * @group_bar: an #EGroupBar. + * @Returns: the index of the group to display. + * + * Sets the group to display. + **/ +/* FIXME: animate option? May want to set group without animation. */ +void +e_group_bar_set_current_group_num (EGroupBar *group_bar, + gint group_num) +{ + g_return_if_fail (E_IS_GROUP_BAR (group_bar)); + + /* If that already is the current group, just return. */ + if (group_bar->current_group_num == group_num) + return; + + /* FIXME: Set the target positions of the old current group and the + new current group, map the new group's child window, and create the + animation timeout, if we haven't already got one. */ + + group_bar->current_group_num = group_num; + +} + + +/* + * Getting groups and group numbers. + */ + +/** + * e_group_bar_get_nth_group: + * @group_bar: an #EGroupBar. + * @group_num: the index of the group to get. + * @Returns: the child widget at the given index. + * + * Returns the child widget at the given index. + **/ +GtkWidget* +e_group_bar_get_nth_group (EGroupBar *group_bar, + gint group_num) +{ + EGroupBarChild *group; + + g_return_val_if_fail (E_IS_GROUP_BAR (group_bar), NULL); + g_return_val_if_fail (group_num >= 0, NULL); + g_return_val_if_fail (group_num < group_bar->children->len, NULL); + + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + return group->child; +} + + +/** + * e_group_bar_get_group_num: + * @group_bar: an #EGroupBar. + * @child: the child widget to find. + * @Returns: the index of the group containing the given widget. + * + * Returns the index of the group containing the given child widget. + **/ +gint +e_group_bar_get_group_num (EGroupBar *group_bar, + GtkWidget *child) +{ + EGroupBarChild *group; + gint group_num; + + g_return_val_if_fail (E_IS_GROUP_BAR (group_bar), -1); + g_return_val_if_fail (child != NULL, -1); + + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + if (group->child == child) + return group_num; + } + + return -1; +} + + +/** + * e_group_bar_set_group_button_label: + * @group_bar: an #EGroupBar. + * @group_num: the index of the group. + * @label: the label widget to place in the group's button. + * + * Sets the label widget for the given group's button, replacing any existing + * widget in the button. + **/ +void +e_group_bar_set_group_button_label (EGroupBar *group_bar, + gint group_num, + GtkWidget *label) +{ + EGroupBarChild *group; + GtkWidget *button_child; + + g_return_if_fail (E_IS_GROUP_BAR (group_bar)); + g_return_if_fail (group_num >= 0); + g_return_if_fail (group_num < group_bar->children->len); + + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + button_child = GTK_BIN (group->button)->child; + if (button_child) { + gtk_container_remove (GTK_CONTAINER (group->button), + button_child); + } + + if (label) + gtk_container_add (GTK_CONTAINER (group->button), label); +} + + +/* + * Getting & setting the EGroupBar options. + */ + +/** + * e_group_bar_get_buttons_homogeneous: + * @group_bar: an #EGroupBar. + * @Returns: TRUE if the buttons are homoegeneous. + * + * Returns TRUE if the buttons are homogeneous (i.e. all have the same height). + **/ +gboolean +e_group_bar_get_buttons_homogeneous (EGroupBar *group_bar) +{ + g_return_val_if_fail (E_IS_GROUP_BAR (group_bar), TRUE); + + return group_bar->buttons_homogeneous; +} + + +/** + * e_group_bar_set_buttons_homogeneous: + * @group_bar: an #EGroupBar. + * @homogeneous: TRUE if the buttons should be homoegeneous. + * + * Specifies whether the buttons should be homogeneous. When set to TRUE all + * the group buttons will be set to the same height (equal to the largest + * requested height). When set to FALSE the buttons will use their own + * individual requested heights. + **/ +void +e_group_bar_set_buttons_homogeneous (EGroupBar *group_bar, + gboolean homogeneous) +{ + g_return_if_fail (E_IS_GROUP_BAR (group_bar)); + + /* Just return if the setting hasn't changed. */ + if (group_bar->buttons_homogeneous == homogeneous) + return; + + group_bar->buttons_homogeneous = homogeneous; + + /* Update the position & sizes of the buttons. */ + gtk_widget_queue_resize (GTK_WIDGET (group_bar)); +} + + +static void +e_group_bar_on_button_clicked (GtkWidget *group_button, + EGroupBar *group_bar) +{ + gint group_num; + + /* Determine which group button was clicked. */ + group_num = e_group_bar_find_button (group_bar, group_button); + + if (group_num != -1) + e_group_bar_start_animation (group_bar, group_num); +} + + +/* This returns the group containing the given button, or -1 if not found. */ +static gint +e_group_bar_find_button (EGroupBar *group_bar, + GtkWidget *group_button) +{ + EGroupBarChild *group; + gint group_num; + + /* Determine which group button was clicked. */ + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + if (group->button == group_button) + return group_num; + } + + return -1; +} + + +static void +e_group_bar_start_animation (EGroupBar *group_bar, + gint group_num) +{ + EGroupBarChild *group, *old_group; + gint old_group_num, step; + + old_group_num = group_bar->current_group_num; + + /* Return if it is already the current group. */ + if (old_group_num == group_num) + return; + + group_bar->current_group_num = group_num; + + /* Calculate the target y position of the new current group button + and child, and map the child. */ + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + group->button_window_target_y = e_group_bar_get_group_button_position (group_bar, group_num); + group->button_window_in_animation = TRUE; + + group->child_window_target_y = e_group_bar_get_group_child_position (group_bar, group_num); + group->child_window_in_animation = TRUE; + + /* Calculate the target y position of the current group button and + child. */ + old_group = &g_array_index (group_bar->children, + EGroupBarChild, old_group_num); + old_group->button_window_target_y = e_group_bar_get_group_button_position (group_bar, old_group_num); + old_group->button_window_in_animation = TRUE; + + old_group->child_window_target_y = e_group_bar_get_group_child_position (group_bar, old_group_num); + old_group->child_window_in_animation = TRUE; + + /* We also need to animate the buttons in between the old group and the + new group. */ + step = (old_group_num < group_num) ? 1 : -1; + old_group_num += step; + while (old_group_num != group_num) { + old_group = &g_array_index (group_bar->children, + EGroupBarChild, old_group_num); + old_group->button_window_target_y = e_group_bar_get_group_button_position (group_bar, old_group_num); + old_group->button_window_in_animation = TRUE; + + old_group->child_window_target_y = e_group_bar_get_group_child_position (group_bar, old_group_num); + old_group->child_window_in_animation = TRUE; + + old_group_num += step; + } + + /* Add a timeout handler if we haven't already got one. */ + if (group_bar->animation_timeout_id == 0) { + group_bar->animation_timeout_id = g_timeout_add (E_GROUP_BAR_SCROLL_TIMEOUT, e_group_bar_timeout_handler, group_bar); + } +} + + +static gboolean +e_group_bar_timeout_handler (gpointer data) +{ + EGroupBar *group_bar; + EGroupBarChild *group; + gint group_num, button_window_y, child_window_y; + gboolean finished = TRUE; + + g_return_val_if_fail (E_IS_GROUP_BAR (data), FALSE); + + group_bar = E_GROUP_BAR (data); + + GDK_THREADS_ENTER (); + + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + + if (group->button_window_in_animation) { + gdk_window_get_position (group->button_window, NULL, + &button_window_y); + button_window_y += e_group_bar_get_increment (group_bar, button_window_y, group->button_window_target_y); + if (button_window_y == group->button_window_target_y) + group->button_window_in_animation = FALSE; + else + finished = FALSE; + gdk_window_move (group->button_window, + 0, button_window_y); + } + if (group->child_window_in_animation) { + gdk_window_get_position (group->child_window, NULL, + &child_window_y); + child_window_y += e_group_bar_get_increment (group_bar, child_window_y, group->child_window_target_y); + if (child_window_y == group->child_window_target_y) + group->child_window_in_animation = FALSE; + else + finished = FALSE; + gdk_window_move (group->child_window, + 0, child_window_y); + } + + } + + if (finished) + group_bar->animation_timeout_id = 0; + + GDK_THREADS_LEAVE (); + + return !finished; +} + + +static gint +e_group_bar_get_increment (EGroupBar *group_bar, + gint window_y, + gint window_target_y) +{ + gdouble percentage; + gint distance, total_distance, step; + + total_distance = group_bar->child_height; + distance = MIN (abs (window_target_y - window_y), total_distance); + + /* Convert the distance into an angle between -PI/2 and PI/2, so we can + then do a cosine of it. */ + percentage = cos (M_PI * ((gdouble)distance / (gdouble)total_distance) - M_PI / 2); + + /* Now multiply by our maximum step size to get the step size. */ + step = percentage * total_distance / 6; + + /* Add it to the minimum step size, but don't go too far. */ + step = step + E_GROUP_BAR_MIN_STEP_SIZE; + step = MIN (step, distance); + + if (window_target_y > window_y) + return step; + else + return -step; +} + + +static gboolean +e_group_bar_on_button_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time, + EGroupBar *group_bar) +{ + gint group_num; + + if (!group_bar->auto_show_timeout_id) { + group_num = e_group_bar_find_button (group_bar, widget); + if (group_num != -1) { + group_bar->auto_show_timeout_id = gtk_timeout_add (E_GROUP_BAR_AUTO_SHOW_TIMEOUT, e_group_bar_auto_show, group_bar); + group_bar->auto_show_group_num = group_num; + } + } + return TRUE; +} + + +static void +e_group_bar_on_button_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time, + EGroupBar *group_bar) +{ + if (group_bar->auto_show_timeout_id) { + gtk_timeout_remove (group_bar->auto_show_timeout_id); + group_bar->auto_show_timeout_id = 0; + } +} + + +static gboolean +e_group_bar_auto_show (gpointer data) +{ + EGroupBar *group_bar; + + g_return_val_if_fail (E_IS_GROUP_BAR (data), FALSE); + + group_bar = E_GROUP_BAR (data); + + GDK_THREADS_ENTER (); + + e_group_bar_start_animation (group_bar, + group_bar->auto_show_group_num); + + group_bar->auto_show_timeout_id = 0; + + GDK_THREADS_LEAVE (); + + return FALSE; +} + + +/* This removes all timeouts and sets all 'in_animation' flags to FALSE. */ +static void +e_group_bar_stop_all_animation (EGroupBar *group_bar) +{ + EGroupBarChild *group; + gint group_num; + + if (group_bar->animation_timeout_id) { + g_source_remove (group_bar->animation_timeout_id); + group_bar->animation_timeout_id = 0; + } + if (group_bar->auto_show_timeout_id) { + g_source_remove (group_bar->auto_show_timeout_id); + group_bar->auto_show_timeout_id = 0; + } + + for (group_num = 0; + group_num < group_bar->children->len; + group_num++) { + group = &g_array_index (group_bar->children, + EGroupBarChild, group_num); + group->button_window_in_animation = FALSE; + group->child_window_in_animation = FALSE; + } +} + diff --git a/widgets/shortcut-bar/e-group-bar.h b/widgets/shortcut-bar/e-group-bar.h new file mode 100644 index 0000000000..9a6f83b461 --- /dev/null +++ b/widgets/shortcut-bar/e-group-bar.h @@ -0,0 +1,171 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ +#ifndef _E_GROUP_BAR_H_ +#define _E_GROUP_BAR_H_ + +#include <gtk/gtkcontainer.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * EGroupBar displays a vertical bar with a number of Groups, which are viewed + * one at a time by selecting the Group's button. When a different Group is + * selected, it slides into view, and the old Group slides out. + * It is typically used on the left of the main application window so users + * can easily access particular features. + * + * It is implemented like GtkNotebook, i.e. the main widgets are the children + * of the EGroupBar and the button widgets are treated specially like the + * GtkNotebook tab labels. + */ + +/* This contains information on one item. */ +typedef struct _EGroupBarChild EGroupBarChild; +struct _EGroupBarChild +{ + /* This is the button used to select the group, and the window we use + to move it around easily. */ + GtkWidget *button; + GdkWindow *button_window; + gint button_height; + + /* This is the child widget, which can be any widget added by the + application, and the window we use to move it around easily. */ + GtkWidget *child; + GdkWindow *child_window; + + /* These are TRUE if we are currently animating the windows. */ + gboolean button_window_in_animation; + gboolean child_window_in_animation; + + /* These are the target y positions that the windows should eventually + move to, used for animation. If we get a size_allocate we just + update these and the animation can continue as normal. + When a child window reaches its target position, it is unmapped if + if it is not the current group (i.e. it has slid off screen). */ + gint button_window_target_y; + gint child_window_target_y; +}; + + +#define E_GROUP_BAR(obj) GTK_CHECK_CAST (obj, e_group_bar_get_type (), EGroupBar) +#define E_GROUP_BAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, e_group_bar_get_type (), EGroupBarClass) +#define E_IS_GROUP_BAR(obj) GTK_CHECK_TYPE (obj, e_group_bar_get_type ()) + + +typedef struct _EGroupBar EGroupBar; +typedef struct _EGroupBarClass EGroupBarClass; + +struct _EGroupBar +{ + GtkContainer container; + + /* This is an array of EGroupBarChild elements. */ + GArray *children; + + /* This is the group currently shown. */ + gint current_group_num; + + /* This is TRUE if all the buttons are allocated the same height. */ + gboolean buttons_homogeneous; + + /* This is the biggest requested height of all the buttons, which we + use for all buttons when buttons_homogeneous is set. */ + gint max_button_height; + + /* This is the height of all the child windows & widgets. */ + gint child_height; + + /* The id of the source function for animation timeouts. If this is + not 0 then we are in the middle of an animation. */ + guint animation_timeout_id; + + /* The id of the source function for automatically showing groups when + the user drags over the group button, and the group to show. */ + guint auto_show_timeout_id; + gint auto_show_group_num; +}; + +struct _EGroupBarClass +{ + GtkContainerClass parent_class; +}; + + +GtkType e_group_bar_get_type (void); +GtkWidget* e_group_bar_new (void); + +/* + * Insertion, reordering and deletion of items. + */ + +/* Adds a new group at the given position. If position is -1 it adds it as + the last group. It returns the group number. */ +gint e_group_bar_add_group (EGroupBar *group_bar, + GtkWidget *child, + GtkWidget *button, + gint position); +void e_group_bar_reorder_group (EGroupBar *group_bar, + gint group_num, + gint new_position); +void e_group_bar_remove_group (EGroupBar *group_bar, + gint group_num); + +/* + * Getting & setting the current group. + */ +gint e_group_bar_get_current_group_num (EGroupBar *group_bar); +void e_group_bar_set_current_group_num (EGroupBar *group_bar, + gint group_num); + +/* + * Getting groups and group numbers. + */ +GtkWidget* e_group_bar_get_nth_group (EGroupBar *group_bar, + gint group_num); +gint e_group_bar_get_group_num (EGroupBar *group_bar, + GtkWidget *child); + +/* + * Setting the group button label. + */ +void e_group_bar_set_group_button_label (EGroupBar *group_bar, + gint group_num, + GtkWidget *label); + +/* + * Getting & setting the EGroupBar options. + */ +gboolean e_group_bar_get_buttons_homogeneous (EGroupBar *group_bar); +void e_group_bar_set_buttons_homogeneous (EGroupBar *group_bar, + gboolean homogeneous); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _E_GROUP_BAR_H_ */ diff --git a/widgets/shortcut-bar/e-icon-bar-bg-item.c b/widgets/shortcut-bar/e-icon-bar-bg-item.c new file mode 100644 index 0000000000..1bdb7a308d --- /dev/null +++ b/widgets/shortcut-bar/e-icon-bar-bg-item.c @@ -0,0 +1,361 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ + +/* + * EIconBarBgItem - A GnomeCanvasItem which covers the entire EIconBar. + * It paints the rectangles around items when the mouse moves over them, and + * the lines between items when dragging. + */ + +#include "e-icon-bar-bg-item.h" +#include "e-icon-bar.h" + +/* This is the size of the border around the icons, for the shadow. */ +#define E_ICON_BAR_LARGE_ICON_SHADOW_BORDER 2 +#define E_ICON_BAR_SMALL_ICON_SHADOW_BORDER 2 + +/* These are for the horzontal bar when dragging. */ +#define E_ICON_BAR_BG_ITEM_BAR_HEIGHT 1 +#define E_ICON_BAR_BG_ITEM_BAR_OFFSET 2 +#define E_ICON_BAR_BG_ITEM_LARGE_ARROW_HEIGHT 8 +#define E_ICON_BAR_BG_ITEM_SMALL_ARROW_HEIGHT 4 + +static void e_icon_bar_bg_item_class_init (EIconBarBgItemClass *class); +static void e_icon_bar_bg_item_init (EIconBarBgItem *ibitem); + +static void e_icon_bar_bg_item_set_arg (GtkObject *o, GtkArg *arg, + guint arg_id); +static void e_icon_bar_bg_item_update (GnomeCanvasItem *item, + double *affine, + ArtSVP *clip_path, int flags); +static void e_icon_bar_bg_item_draw (GnomeCanvasItem *item, + GdkDrawable *drawable, + int x, int y, + int width, int height); +static double e_icon_bar_bg_item_point (GnomeCanvasItem *item, + double x, double y, + int cx, int cy, + GnomeCanvasItem **actual_item); +static gint e_icon_bar_bg_item_event (GnomeCanvasItem *item, + GdkEvent *event); +static gint e_icon_bar_bg_item_button_press (EIconBarBgItem *ibitem, + GdkEvent *event); +static gint e_icon_bar_bg_item_button_release (EIconBarBgItem *ibitem, + GdkEvent *event); +static gint e_icon_bar_bg_item_motion_notify (EIconBarBgItem *ibitem, + GdkEvent *event); + +static GnomeCanvasItemClass *parent_class; + +/* The arguments we take */ +enum { + ARG_0, + ARG_ICON_BAR +}; + + +GtkType +e_icon_bar_bg_item_get_type (void) +{ + static GtkType e_icon_bar_bg_item_type = 0; + + if (!e_icon_bar_bg_item_type) { + GtkTypeInfo e_icon_bar_bg_item_info = { + "EIconBarBgItem", + sizeof (EIconBarBgItem), + sizeof (EIconBarBgItemClass), + (GtkClassInitFunc) e_icon_bar_bg_item_class_init, + (GtkObjectInitFunc) e_icon_bar_bg_item_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + e_icon_bar_bg_item_type = gtk_type_unique (gnome_canvas_item_get_type (), &e_icon_bar_bg_item_info); + } + + return e_icon_bar_bg_item_type; +} + + +static void +e_icon_bar_bg_item_class_init (EIconBarBgItemClass *class) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + parent_class = gtk_type_class (gnome_canvas_item_get_type()); + + object_class = (GtkObjectClass *) class; + item_class = (GnomeCanvasItemClass *) class; + + gtk_object_add_arg_type ("EIconBarBgItem::icon_bar", + GTK_TYPE_POINTER, GTK_ARG_WRITABLE, + ARG_ICON_BAR); + + object_class->set_arg = e_icon_bar_bg_item_set_arg; + + /* GnomeCanvasItem method overrides */ + item_class->update = e_icon_bar_bg_item_update; + item_class->draw = e_icon_bar_bg_item_draw; + item_class->point = e_icon_bar_bg_item_point; + item_class->event = e_icon_bar_bg_item_event; +} + + +static void +e_icon_bar_bg_item_init (EIconBarBgItem *ibitem) +{ + GnomeCanvasItem *item = GNOME_CANVAS_ITEM (ibitem); + + ibitem->icon_bar = NULL; + + item->x1 = 0; + item->y1 = 0; + item->x2 = 0; + item->y2 = 0; +} + + +static void +e_icon_bar_bg_item_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EIconBarBgItem *ibitem; + + item = GNOME_CANVAS_ITEM (o); + ibitem = E_ICON_BAR_BG_ITEM (o); + + switch (arg_id){ + case ARG_ICON_BAR: + ibitem->icon_bar = GTK_VALUE_POINTER (*arg); + break; + } +} + + +static void +e_icon_bar_bg_item_update (GnomeCanvasItem *item, + double *affine, + ArtSVP *clip_path, + int flags) +{ + if (GNOME_CANVAS_ITEM_CLASS (parent_class)->update) + (* GNOME_CANVAS_ITEM_CLASS (parent_class)->update) (item, affine, clip_path, flags); + + /* The grid covers the entire canvas area. */ + item->x1 = 0; + item->y1 = 0; + item->x2 = INT_MAX; + item->y2 = INT_MAX; +} + + +/* + * DRAWING ROUTINES - functions to paint the canvas item. + */ + +static void +e_icon_bar_bg_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable, + int x, int y, int width, int height) +{ + EIconBar *icon_bar; + EIconBarItem *item; + EIconBarBgItem *ibitem; + GtkStyle *style; + GdkGC *gc; + GtkShadowType shadow; + gint item_num, border, bar_x, bar_y, bar_w, i, arrow_height; + + ibitem = E_ICON_BAR_BG_ITEM (canvas_item); + icon_bar = ibitem->icon_bar; + g_return_if_fail (icon_bar != NULL); + style = GTK_WIDGET (icon_bar)->style; + + /* Draw the highlight around the current highlight item. */ + item_num = -1; + if (icon_bar->editing_item_num == -1) { + if (icon_bar->pressed_item_num != -1) { + item_num = icon_bar->pressed_item_num; + if (icon_bar->pressed_item_num == icon_bar->mouse_over_item_num) + shadow = GTK_SHADOW_IN; + else + shadow = GTK_SHADOW_OUT; + } else if (icon_bar->mouse_over_item_num != -1) { + item_num = icon_bar->mouse_over_item_num; + shadow = GTK_SHADOW_OUT; + } + } + + if (item_num != -1) { + item = &g_array_index (icon_bar->items, EIconBarItem, + item_num); + + if (icon_bar->view_type == E_ICON_BAR_LARGE_ICONS) + border = E_ICON_BAR_LARGE_ICON_SHADOW_BORDER; + else + border = E_ICON_BAR_SMALL_ICON_SHADOW_BORDER; + + gtk_draw_shadow (style, drawable, GTK_STATE_NORMAL, shadow, + icon_bar->icon_x - border - x, + item->icon_y - border - y, + icon_bar->icon_w + border * 2 - 1, + icon_bar->icon_h + border * 2 - 1); + } + + /* Draw the bar between items when dragging, if needed. */ + if (icon_bar->in_drag && icon_bar->dragging_before_item_num != -1) { + if (icon_bar->dragging_before_item_num < icon_bar->items->len) { + item = &g_array_index (icon_bar->items, EIconBarItem, + icon_bar->dragging_before_item_num); + bar_y = 0; + } else { + /* We need to draw the bar after the last item. */ + item = &g_array_index (icon_bar->items, EIconBarItem, + icon_bar->items->len - 1); + bar_y = item->item_height + icon_bar->spacing; + } + + if (icon_bar->view_type == E_ICON_BAR_LARGE_ICONS) { + bar_y += item->icon_y; + } else { + bar_y += MIN (item->icon_y, item->text_y); + } + bar_y -= y + icon_bar->spacing / 2; + + bar_x = E_ICON_BAR_BG_ITEM_BAR_OFFSET - x; + bar_w = GTK_WIDGET (icon_bar)->allocation.width - 2 * E_ICON_BAR_BG_ITEM_BAR_OFFSET - 1; + + gc = GTK_WIDGET (icon_bar)->style->fg_gc[GTK_STATE_NORMAL]; + + /* Draw the horizontal bar. */ + gdk_draw_rectangle (drawable, gc, TRUE, + bar_x, bar_y, + bar_w, E_ICON_BAR_BG_ITEM_BAR_HEIGHT); + + if (icon_bar->view_type == E_ICON_BAR_LARGE_ICONS) + arrow_height = E_ICON_BAR_BG_ITEM_LARGE_ARROW_HEIGHT / 2; + else + arrow_height = E_ICON_BAR_BG_ITEM_SMALL_ARROW_HEIGHT / 2; + + /* Draw the arrows at the end of the lines. We use + gdk_draw_line() to draw a series of vertical lines, since + gdk_draw_polygon() produces odd results. */ + i = 0; + while (arrow_height > 0) { + gdk_draw_line (drawable, gc, + bar_x + i, + bar_y - arrow_height, + bar_x + i, + bar_y + arrow_height); + gdk_draw_line (drawable, gc, + bar_x + bar_w - i - 1, + bar_y - arrow_height, + bar_x + bar_w - i - 1, + bar_y + arrow_height); + arrow_height--; + i++; + } + } +} + + +/* This is supposed to return the nearest item the the point and the distance. + Since we are the only item we just return ourself and 0 for the distance. + This is needed so that we get button/motion events. */ +static double +e_icon_bar_bg_item_point (GnomeCanvasItem *item, double x, double y, + int cx, int cy, + GnomeCanvasItem **actual_item) +{ + *actual_item = item; + return 0.0; +} + + +static gint +e_icon_bar_bg_item_event (GnomeCanvasItem *item, GdkEvent *event) +{ + EIconBarBgItem *ibitem; + + ibitem = E_ICON_BAR_BG_ITEM (item); + + switch (event->type) { + case GDK_BUTTON_PRESS: + return e_icon_bar_bg_item_button_press (ibitem, event); + case GDK_BUTTON_RELEASE: + return e_icon_bar_bg_item_button_release (ibitem, event); + case GDK_MOTION_NOTIFY: + return e_icon_bar_bg_item_motion_notify (ibitem, event); + default: + break; + } + + return FALSE; +} + + +static gint +e_icon_bar_bg_item_button_press (EIconBarBgItem *ibitem, + GdkEvent *event) +{ + gint item_num; + + item_num = e_icon_bar_find_item_at_position (ibitem->icon_bar, + event->button.x, + event->button.y, + NULL); + e_icon_bar_item_pressed (ibitem->icon_bar, item_num, event); + return TRUE; +} + + +static gint +e_icon_bar_bg_item_button_release (EIconBarBgItem *ibitem, + GdkEvent *event) +{ + gint item_num; + + item_num = e_icon_bar_find_item_at_position (ibitem->icon_bar, + event->button.x, + event->button.y, + NULL); + e_icon_bar_item_released (ibitem->icon_bar, item_num, event); + return TRUE; +} + + +static gint +e_icon_bar_bg_item_motion_notify (EIconBarBgItem *ibitem, + GdkEvent *event) +{ + gint item_num; + + item_num = e_icon_bar_find_item_at_position (ibitem->icon_bar, + event->motion.x, + event->motion.y, + NULL); + e_icon_bar_item_motion (ibitem->icon_bar, item_num, event); + return TRUE; +} diff --git a/widgets/shortcut-bar/e-icon-bar-bg-item.h b/widgets/shortcut-bar/e-icon-bar-bg-item.h new file mode 100644 index 0000000000..ae25e987d7 --- /dev/null +++ b/widgets/shortcut-bar/e-icon-bar-bg-item.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ + +/* + * EIconBarBgItem - A GnomeCanvasItem which covers the entire EIconBar. + * It paints the rectangles around items when the mouse moves over them, and + * the lines between items when dragging. + */ + +#ifndef _E_ICON_BAR_BG_ITEM_H_ +#define _E_ICON_BAR_BG_ITEM_H_ + +#include <libgnomeui/gnome-canvas.h> + +#include "e-icon-bar.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define E_ICON_BAR_BG_ITEM(obj) (GTK_CHECK_CAST((obj), e_icon_bar_bg_item_get_type (), EIconBarBgItem)) +#define E_ICON_BAR_BG_ITEM_CLASS(k) (GTK_CHECK_CLASS_CAST ((k), e_icon_bar_bg_item_get_type (), EIconBarBgItemClass)) +#define E_IS_ICON_BAR_BG_ITEM(o) (GTK_CHECK_TYPE((o), e_icon_bar_bg_item_get_type ())) + + +typedef struct _EIconBarBgItem EIconBarBgItem; +typedef struct _EIconBarBgItemClass EIconBarBgItemClass; + +struct _EIconBarBgItem +{ + GnomeCanvasItem canvas_item; + + /* The parent EIconBar widget. */ + EIconBar *icon_bar; +}; + + +struct _EIconBarBgItemClass +{ + GnomeCanvasItemClass parent_class; +}; + +GtkType e_icon_bar_bg_item_get_type (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _E_ICON_BAR_BG_ITEM_H_ */ diff --git a/widgets/shortcut-bar/e-icon-bar-text-item.c b/widgets/shortcut-bar/e-icon-bar-text-item.c new file mode 100644 index 0000000000..5548c630b3 --- /dev/null +++ b/widgets/shortcut-bar/e-icon-bar-text-item.c @@ -0,0 +1,1696 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ + +/* + * Based on gnome-icon-text-item: an editable text block with word wrapping + * for the GNOME canvas. + * + * Copyright (C) 1998, 1999 The Free Software Foundation + * + * Authors: Miguel de Icaza <miguel@gnu.org> + * Federico Mena <federico@gimp.org> + */ + +/* + * EIconBarTextItem - An editable canvas text item for the EIconBar. + */ + +#include <math.h> +#include <gdk/gdkkeysyms.h> +#include <gtk/gtkmain.h> +#include <gtk/gtksignal.h> +#include <gtk/gtkwindow.h> +#include <libgnome/gnome-defs.h> +#include <libgnome/gnome-i18n.h> + +#include "e-icon-bar-text-item.h" + + +/* Margins used to display the information */ +#define MARGIN_X 2 +#define MARGIN_Y 2 + +/* Default fontset to be used if the user specified fontset is not found */ +#define DEFAULT_FONT_NAME "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*," \ + "-*-*-medium-r-normal--10-*-*-*-*-*-*-*,*" + +/* Separators for text layout */ +#define DEFAULT_SEPARATORS " \t-.[]#" + +/* This is the string to draw when the text is clipped, e.g. '...'. */ +static gchar *e_icon_bar_text_item_ellipsis; + +/* Aliases to minimize screen use in my laptop */ +#define ITI(x) E_ICON_BAR_TEXT_ITEM (x) +#define ITI_CLASS(x) E_ICON_BAR_TEXT_ITEM_CLASS (x) +#define IS_ITI(x) E_IS_ICON_BAR_TEXT_ITEM (x) + + +typedef EIconBarTextItem Iti; + +/* Private part of the EIconBarTextItem structure */ +typedef struct { + /* Font */ + GdkFont *font; + + /* Hack: create an offscreen window and place an entry inside it */ + GtkEntry *entry; + GtkWidget *entry_top; + + /* Whether the user pressed the mouse while the item was unselected */ + guint unselected_click : 1; + + /* Whether we need to update the position */ + guint need_pos_update : 1; + + /* Whether we need to update the font */ + guint need_font_update : 1; + + /* Whether we need to update the text */ + guint need_text_update : 1; + + /* Whether we need to update because the editing/selected state changed */ + guint need_state_update : 1; +} ItiPrivate; + +typedef struct _EIconBarTextItemInfoRow EIconBarTextItemInfoRow; + +struct _EIconBarTextItemInfoRow { + gchar *text; + gint width; + GdkWChar *text_wc; /* text in wide characters */ + gint text_length; /* number of characters */ +}; + +struct _EIconBarTextItemInfo { + GList *rows; + GdkFont *font; + gint width; + gint height; + gint baseline_skip; +}; + +static GnomeCanvasItemClass *parent_class; + +enum { + ARG_0, + ARG_XALIGN, + ARG_JUSTIFY, + ARG_MAX_LINES, + ARG_SHOW_ELLIPSIS +}; + +enum { + TEXT_CHANGED, + HEIGHT_CHANGED, + WIDTH_CHANGED, + EDITING_STARTED, + EDITING_STOPPED, + SELECTION_STARTED, + SELECTION_STOPPED, + LAST_SIGNAL +}; + +static guint iti_signals [LAST_SIGNAL] = { 0 }; + +static GdkFont *default_font; + +static void e_icon_bar_text_item_free_info (EIconBarTextItemInfo *ti); +static EIconBarTextItemInfo *e_icon_bar_text_item_layout_text (EIconBarTextItem *iti, GdkFont *font, const gchar *text, const gchar *separators, gint max_width, gboolean confine); +static void e_icon_bar_text_item_paint_text (EIconBarTextItem *iti, + EIconBarTextItemInfo *ti, + GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + GtkJustification just); + + +/* Stops the editing state of an icon text item */ +static void +iti_stop_editing (Iti *iti) +{ + ItiPrivate *priv; + + priv = iti->priv; + + iti->editing = FALSE; + + gtk_widget_destroy (priv->entry_top); + priv->entry = NULL; + priv->entry_top = NULL; + + priv->need_state_update = TRUE; + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); + + gtk_signal_emit (GTK_OBJECT (iti), iti_signals[EDITING_STOPPED]); +} + +/* Lays out the text in an icon item */ +static void +layout_text (Iti *iti) +{ + ItiPrivate *priv; + char *text; + int old_width, old_height; + int width, height; + + priv = iti->priv; + + /* Save old size */ + + if (iti->ti) { + old_width = iti->ti->width + 2 * MARGIN_X; + old_height = iti->ti->height + 2 * MARGIN_Y; + + e_icon_bar_text_item_free_info (iti->ti); + } else { + old_width = 2 * MARGIN_X; + old_height = 2 * MARGIN_Y; + } + + /* Change the text layout */ + + if (iti->editing) + text = gtk_entry_get_text (priv->entry); + else + text = iti->text; + + iti->ti = e_icon_bar_text_item_layout_text (iti, priv->font, + text, + DEFAULT_SEPARATORS, + iti->width - 2 * MARGIN_X, + TRUE); + + /* Check the sizes and see if we need to emit any signals */ + + width = iti->ti->width + 2 * MARGIN_X; + height = iti->ti->height + 2 * MARGIN_Y; + + if (width != old_width) + gtk_signal_emit (GTK_OBJECT (iti), iti_signals[WIDTH_CHANGED]); + + if (height != old_height) + gtk_signal_emit (GTK_OBJECT (iti), iti_signals[HEIGHT_CHANGED]); +} + +/* Accepts the text in the off-screen entry of an icon text item */ +static void +iti_edition_accept (Iti *iti) +{ + ItiPrivate *priv; + gboolean accept; + + priv = iti->priv; + accept = TRUE; + + gtk_signal_emit (GTK_OBJECT (iti), iti_signals [TEXT_CHANGED], &accept); + + if (iti->editing){ + if (accept) { + if (iti->is_text_allocated) + g_free (iti->text); + + iti->text = g_strdup (gtk_entry_get_text (priv->entry)); + iti->is_text_allocated = 1; + } + + iti_stop_editing (iti); + } + + priv->need_text_update = TRUE; + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); +} + +/* Callback used when the off-screen entry of an icon text item is activated. + * When this happens, we have to accept edition. + */ +static void +iti_entry_activate (GtkWidget *entry, Iti *iti) +{ + iti_edition_accept (iti); +} + +/* Starts the editing state of an icon text item */ +static void +iti_start_editing (Iti *iti) +{ + ItiPrivate *priv; + + priv = iti->priv; + + if (iti->editing) + return; + + /* Trick: The actual edition of the entry takes place in a GtkEntry + * which is placed offscreen. That way we get all of the advantages + * from GtkEntry without duplicating code. Yes, this is a hack. + */ + priv->entry = (GtkEntry *) gtk_entry_new (); + gtk_entry_set_text (priv->entry, iti->text); + gtk_signal_connect (GTK_OBJECT (priv->entry), "activate", + GTK_SIGNAL_FUNC (iti_entry_activate), iti); + + priv->entry_top = gtk_window_new (GTK_WINDOW_POPUP); + gtk_container_add (GTK_CONTAINER (priv->entry_top), GTK_WIDGET (priv->entry)); + gtk_widget_set_uposition (priv->entry_top, 20000, 20000); + gtk_widget_show_all (priv->entry_top); + + gtk_editable_select_region (GTK_EDITABLE (priv->entry), 0, -1); + + iti->editing = TRUE; + + priv->need_text_update = TRUE; + priv->need_state_update = TRUE; + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); + + gtk_signal_emit (GTK_OBJECT (iti), iti_signals[EDITING_STARTED]); +} + +/* Destroy method handler for the icon text item */ +static void +iti_destroy (GtkObject *object) +{ + Iti *iti; + ItiPrivate *priv; + GnomeCanvasItem *item; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_ITI (object)); + + iti = ITI (object); + priv = iti->priv; + item = GNOME_CANVAS_ITEM (object); + + /* FIXME: stop selection and editing */ + + /* Queue redraw of bounding box */ + + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); + + /* Free everything */ + + if (iti->fontname) + g_free (iti->fontname); + + if (iti->text && iti->is_text_allocated) + g_free (iti->text); + + if (iti->ti) + e_icon_bar_text_item_free_info (iti->ti); + + if (priv->font) + gdk_font_unref (priv->font); + + if (priv->entry_top) + gtk_widget_destroy (priv->entry_top); + + g_free (priv); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +/* set_arg handler for the icon text item */ +static void +iti_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + Iti *iti; + GnomeCanvasItem *item; + ItiPrivate *priv; + gfloat xalign; + gint max_lines; + gboolean show_ellipsis; + GtkJustification justification; + + iti = ITI (object); + item = GNOME_CANVAS_ITEM (object); + priv = iti->priv; + + switch (arg_id) { + case ARG_XALIGN: + xalign = GTK_VALUE_FLOAT (*arg); + if (iti->xalign != xalign) { + iti->xalign = xalign; + priv->need_pos_update = TRUE; + gnome_canvas_item_request_update (item); + } + break; + case ARG_JUSTIFY: + justification = GTK_VALUE_ENUM (*arg); + if (iti->justification != justification) { + iti->justification = justification; + priv->need_text_update = TRUE; + gnome_canvas_item_request_update (item); + } + break; + case ARG_MAX_LINES: + max_lines = GTK_VALUE_INT (*arg); + if (iti->max_lines != max_lines) { + iti->max_lines = max_lines; + priv->need_text_update = TRUE; + gnome_canvas_item_request_update (item); + } + break; + case ARG_SHOW_ELLIPSIS: + show_ellipsis = GTK_VALUE_BOOL (*arg); + if (iti->show_ellipsis != show_ellipsis) { + iti->show_ellipsis = show_ellipsis; + priv->need_text_update = TRUE; + gnome_canvas_item_request_update (item); + } + break; + default: + break; + } +} + +static void +iti_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + Iti *iti; + ItiPrivate *priv; + + iti = ITI (object); + priv = iti->priv; + + switch (arg_id) { + case ARG_XALIGN: + GTK_VALUE_FLOAT (*arg) = iti->xalign; + break; + case ARG_JUSTIFY: + GTK_VALUE_ENUM (*arg) = iti->justification; + break; + case ARG_MAX_LINES: + GTK_VALUE_INT (*arg) = iti->max_lines; + break; + case ARG_SHOW_ELLIPSIS: + GTK_VALUE_BOOL (*arg) = iti->show_ellipsis; + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +/* Loads the default font for icon text items if necessary */ +static GdkFont * +get_default_font (void) +{ + if (!default_font) { + /* FIXME: this is never unref-ed */ + default_font = gdk_fontset_load (DEFAULT_FONT_NAME); + g_assert (default_font != NULL); + } + + return gdk_font_ref (default_font); +} + +/* Recomputes the bounding box of an icon text item */ +static void +recompute_bounding_box (Iti *iti) +{ + GnomeCanvasItem *item; + double affine[6]; + ArtPoint p, q; + int x1, y1, x2, y2; + int width, height; + + item = GNOME_CANVAS_ITEM (iti); + + /* Compute width, height, position */ + + width = iti->ti->width + 2 * MARGIN_X; + height = iti->ti->height + 2 * MARGIN_Y; + + x1 = iti->x + (iti->width - width) * iti->xalign; + y1 = iti->y; + x2 = x1 + width; + y2 = y1 + height; + + /* Translate to world coordinates */ + + gnome_canvas_item_i2w_affine (item, affine); + + p.x = x1; + p.y = y1; + art_affine_point (&q, &p, affine); + item->x1 = q.x; + item->y1 = q.y; + + p.x = x2; + p.y = y2; + art_affine_point (&q, &p, affine); + item->x2 = q.x; + item->y2 = q.y; +} + +/* Update method for the icon text item */ +static void +iti_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) +{ + Iti *iti; + ItiPrivate *priv; + + iti = ITI (item); + priv = iti->priv; + + if (parent_class->update) + (* parent_class->update) (item, affine, clip_path, flags); + + /* If necessary, queue a redraw of the old bounding box */ + + if ((flags & GNOME_CANVAS_UPDATE_VISIBILITY) + || (flags & GNOME_CANVAS_UPDATE_AFFINE) + || priv->need_pos_update + || priv->need_font_update + || priv->need_text_update) + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); + + if (priv->need_text_update) + layout_text (iti); + + /* Compute new bounds */ + + if (priv->need_pos_update + || priv->need_font_update + || priv->need_text_update) + recompute_bounding_box (iti); + + /* Queue redraw */ + + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); + + priv->need_pos_update = FALSE; + priv->need_font_update = FALSE; + priv->need_text_update = FALSE; + priv->need_state_update = FALSE; +} + +/* Draw the icon text item's text when it is being edited */ +static void +iti_paint_text (Iti *iti, GdkDrawable *drawable, int x, int y) +{ + ItiPrivate *priv; + EIconBarTextItemInfoRow *row; + EIconBarTextItemInfo *ti; + GtkStyle *style; + GdkGC *fg_gc, *bg_gc; + GdkGC *gc, *bgc, *sgc, *bsgc; + GList *item; + int xpos, len; + + priv = iti->priv; + style = GTK_WIDGET (GNOME_CANVAS_ITEM (iti)->canvas)->style; + + ti = iti->ti; + len = 0; + y += ti->font->ascent; + + /* + * Pointers to all of the GCs we use + */ + gc = style->black_gc; + bgc = style->white_gc; + sgc = style->fg_gc [GTK_STATE_SELECTED]; + bsgc = style->bg_gc [GTK_STATE_SELECTED]; + + for (item = ti->rows; item; item = item->next, len += (row ? row->text_length : 0)) { + GdkWChar *text_wc; + int text_length; + int cursor, offset, i; + int sel_start, sel_end; + + row = item->data; + + if (!row) { + y += ti->baseline_skip; + continue; + } + + text_wc = row->text_wc; + text_length = row->text_length; + + switch (iti->justification) { + case GTK_JUSTIFY_LEFT: + xpos = 0; + break; + + case GTK_JUSTIFY_RIGHT: + xpos = ti->width - row->width; + break; + + case GTK_JUSTIFY_CENTER: + xpos = (ti->width - row->width) / 2; + break; + + default: + /* Anyone care to implement GTK_JUSTIFY_FILL? */ + g_warning ("Justification type %d not supported. Using left-justification.", + (int) iti->justification); + xpos = 0; + } + + sel_start = GTK_EDITABLE (priv->entry)->selection_start_pos - len; + sel_end = GTK_EDITABLE (priv->entry)->selection_end_pos - len; + offset = 0; + cursor = GTK_EDITABLE (priv->entry)->current_pos - len; + + for (i = 0; *text_wc; text_wc++, i++) { + int size, px; + + size = gdk_text_width_wc (ti->font, text_wc, 1); + + if (i >= sel_start && i < sel_end) { + fg_gc = sgc; + bg_gc = bsgc; + } else { + fg_gc = gc; + bg_gc = bgc; + } + + px = x + xpos + offset; + gdk_draw_rectangle (drawable, + bg_gc, + TRUE, + px, + y - ti->font->ascent, + size, ti->baseline_skip); + + gdk_draw_text_wc (drawable, + ti->font, + fg_gc, + px, y, + text_wc, 1); + + if (cursor == i) + gdk_draw_line (drawable, + gc, + px - 1, + y - ti->font->ascent, + px - 1, + y + ti->font->descent - 1); + + offset += size; + } + + if (cursor == i) { + int px = x + xpos + offset; + + gdk_draw_line (drawable, + gc, + px - 1, + y - ti->font->ascent, + px - 1, + y + ti->font->descent - 1); + } + + y += ti->baseline_skip; + } +} + +/* Draw method handler for the icon text item */ +static void +iti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) +{ + Iti *iti; + GtkStyle *style; + int w, h; + int xofs, yofs; + + iti = ITI (item); + + if (iti->ti) { + w = iti->ti->width + 2 * MARGIN_X; + h = iti->ti->height + 2 * MARGIN_Y; + } else { + w = 2 * MARGIN_X; + h = 2 * MARGIN_Y; + } + + xofs = item->x1 - x; + yofs = item->y1 - y; + + style = GTK_WIDGET (item->canvas)->style; + + if (iti->selected && !iti->editing) + gdk_draw_rectangle (drawable, + style->bg_gc[GTK_STATE_SELECTED], + TRUE, + xofs, yofs, + w, h); + + if (iti->editing) { + gdk_draw_rectangle (drawable, + style->white_gc, + TRUE, + xofs + 1, yofs + 1, + w - 2, h - 2); + gdk_draw_rectangle (drawable, + style->black_gc, + FALSE, + xofs, yofs, + w - 1, h - 1); + + iti_paint_text (iti, drawable, xofs + MARGIN_X, yofs + MARGIN_Y); + } else + e_icon_bar_text_item_paint_text (iti, iti->ti, + drawable, + style->fg_gc[(iti->selected + ? GTK_STATE_SELECTED + : GTK_STATE_NORMAL)], + xofs + MARGIN_X, + yofs + MARGIN_Y, + iti->justification); +} + +/* Point method handler for the icon text item */ +static double +iti_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item) +{ + double dx, dy; + + *actual_item = item; + + if (cx < item->x1) + dx = item->x1 - cx; + else if (cx > item->x2) + dx = cx - item->x2; + else + dx = 0.0; + + if (cy < item->y1) + dy = item->y1 - cy; + else if (cy > item->y2) + dy = cy - item->y2; + else + dy = 0.0; + + return sqrt (dx * dx + dy * dy); +} + +/* Given X, Y, a mouse position, return a valid index inside the edited text */ +static int +iti_idx_from_x_y (Iti *iti, int x, int y) +{ + ItiPrivate *priv; + EIconBarTextItemInfoRow *row; + int lines; + int line, col, i, idx; + GList *l; + + priv = iti->priv; + + if (iti->ti->rows == NULL) + return 0; + + lines = g_list_length (iti->ti->rows); + line = y / iti->ti->baseline_skip; + + if (line < 0) + line = 0; + else if (lines < line + 1) + line = lines - 1; + + /* Compute the base index for this line */ + for (l = iti->ti->rows, idx = i = 0; i < line; l = l->next, i++) { + row = l->data; + idx += row->text_length; + } + + row = g_list_nth (iti->ti->rows, line)->data; + col = 0; + if (row != NULL) { + int first_char; + int last_char; + + first_char = (iti->ti->width - row->width) / 2; + last_char = first_char + row->width; + + if (x < first_char) { + /* nothing */ + } else if (x > last_char) { + col = row->text_length; + } else { + GdkWChar *s = row->text_wc; + int pos = first_char; + + while (pos < last_char) { + pos += gdk_text_width_wc (iti->ti->font, s, 1); + if (pos > x) + break; + col++; + s++; + } + } + } + + idx += col; + + g_assert (idx <= priv->entry->text_size); + + return idx; +} + +/* Starts the selection state in the icon text item */ +static void +iti_start_selecting (Iti *iti, int idx, guint32 event_time) +{ + ItiPrivate *priv; + GtkEditable *e; + GdkCursor *ibeam; + + priv = iti->priv; + e = GTK_EDITABLE (priv->entry); + + gtk_editable_select_region (e, idx, idx); + gtk_editable_set_position (e, idx); + ibeam = gdk_cursor_new (GDK_XTERM); + gnome_canvas_item_grab (GNOME_CANVAS_ITEM (iti), + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK, + ibeam, event_time); + gdk_cursor_destroy (ibeam); + + gtk_editable_select_region (e, idx, idx); + e->current_pos = e->selection_start_pos; + e->has_selection = TRUE; + iti->selecting = TRUE; + + priv->need_state_update = TRUE; + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); + + gtk_signal_emit (GTK_OBJECT (iti), iti_signals[SELECTION_STARTED]); +} + +/* Stops the selection state in the icon text item */ +static void +iti_stop_selecting (Iti *iti, guint32 event_time) +{ + ItiPrivate *priv; + GnomeCanvasItem *item; + GtkEditable *e; + + priv = iti->priv; + item = GNOME_CANVAS_ITEM (iti); + e = GTK_EDITABLE (priv->entry); + + gnome_canvas_item_ungrab (item, event_time); + e->has_selection = FALSE; + iti->selecting = FALSE; + + priv->need_state_update = TRUE; + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); + gtk_signal_emit (GTK_OBJECT (iti), iti_signals[SELECTION_STOPPED]); +} + +/* Handles selection range changes on the icon text item */ +static void +iti_selection_motion (Iti *iti, int idx) +{ + ItiPrivate *priv; + GtkEditable *e; + + priv = iti->priv; + e = GTK_EDITABLE (priv->entry); + + if (idx < e->current_pos) { + e->selection_start_pos = idx; + e->selection_end_pos = e->current_pos; + } else { + e->selection_start_pos = e->current_pos; + e->selection_end_pos = idx; + } + + priv->need_state_update = TRUE; + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); +} + +/* Event handler for icon text items */ +static gint +iti_event (GnomeCanvasItem *item, GdkEvent *event) +{ + Iti *iti; + ItiPrivate *priv; + int idx; + double x, y; + + iti = ITI (item); + priv = iti->priv; + + switch (event->type) { + case GDK_KEY_PRESS: + if (!iti->editing) + break; + + if (event->key.keyval == GDK_Escape) + iti_stop_editing (iti); + else + gtk_widget_event (GTK_WIDGET (priv->entry), event); + + priv->need_text_update = TRUE; + gnome_canvas_item_request_update (item); + return TRUE; + + case GDK_BUTTON_PRESS: + if (!iti->editing) + break; + + if (iti->editing && event->button.button == 1) { + x = event->button.x - (item->x1 + MARGIN_X); + y = event->button.y - (item->y1 + MARGIN_Y); + idx = iti_idx_from_x_y (iti, x, y); + + iti_start_selecting (iti, idx, event->button.time); + } + + return TRUE; + + case GDK_MOTION_NOTIFY: + if (!iti->selecting) + break; + + x = event->motion.x - (item->x1 + MARGIN_X); + y = event->motion.y - (item->y1 + MARGIN_Y); + idx = iti_idx_from_x_y (iti, x, y); + iti_selection_motion (iti, idx); + return TRUE; + + case GDK_BUTTON_RELEASE: + if (iti->selecting && event->button.button == 1) + iti_stop_selecting (iti, event->button.time); + else + break; + + return TRUE; + + default: + break; + } + + return FALSE; +} + +/* Bounds method handler for the icon text item */ +static void +iti_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) +{ + Iti *iti; + ItiPrivate *priv; + int width, height; + + iti = ITI (item); + priv = iti->priv; + + if (priv->need_text_update) { + layout_text (iti); + priv->need_text_update = FALSE; + } + + if (iti->ti) { + width = iti->ti->width + 2 * MARGIN_X; + height = iti->ti->height + 2 * MARGIN_Y; + } else { + width = 2 * MARGIN_X; + height = 2 * MARGIN_Y; + } + + *x1 = iti->x + (iti->width - width) * iti->xalign; + *y1 = iti->y; + *x2 = *x1 + width; + *y2 = *y1 + height; +} + +/* Class initialization function for the icon text item */ +static void +iti_class_init (EIconBarTextItemClass *text_item_class) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass *) text_item_class; + item_class = (GnomeCanvasItemClass *) text_item_class; + + parent_class = gtk_type_class (gnome_canvas_item_get_type ()); + + gtk_object_add_arg_type ("EIconBarTextItem::xalign", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_XALIGN); + gtk_object_add_arg_type ("EIconBarTextItem::justify", GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_JUSTIFY); + gtk_object_add_arg_type ("EIconBarTextItem::max_lines", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_MAX_LINES); + gtk_object_add_arg_type ("EIconBarTextItem::show_ellipsis", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_SHOW_ELLIPSIS); + + iti_signals [TEXT_CHANGED] = + gtk_signal_new ( + "text_changed", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (EIconBarTextItemClass, text_changed), + gtk_marshal_BOOL__NONE, + GTK_TYPE_BOOL, 0); + + iti_signals [HEIGHT_CHANGED] = + gtk_signal_new ( + "height_changed", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (EIconBarTextItemClass, height_changed), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + iti_signals [WIDTH_CHANGED] = + gtk_signal_new ( + "width_changed", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (EIconBarTextItemClass, width_changed), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + iti_signals[EDITING_STARTED] = + gtk_signal_new ( + "editing_started", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (EIconBarTextItemClass, editing_started), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + iti_signals[EDITING_STOPPED] = + gtk_signal_new ( + "editing_stopped", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (EIconBarTextItemClass, editing_stopped), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + iti_signals[SELECTION_STARTED] = + gtk_signal_new ( + "selection_started", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (EIconBarTextItemClass, selection_started), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + iti_signals[SELECTION_STOPPED] = + gtk_signal_new ( + "selection_stopped", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (EIconBarTextItemClass, selection_stopped), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, iti_signals, LAST_SIGNAL); + + object_class->destroy = iti_destroy; + object_class->get_arg = iti_get_arg; + object_class->set_arg = iti_set_arg; + + item_class->update = iti_update; + item_class->draw = iti_draw; + item_class->point = iti_point; + item_class->bounds = iti_bounds; + item_class->event = iti_event; + + e_icon_bar_text_item_ellipsis = _("..."); +} + +/* Object initialization function for the icon text item */ +static void +iti_init (EIconBarTextItem *iti) +{ + ItiPrivate *priv; + + priv = g_new0 (ItiPrivate, 1); + iti->priv = priv; + + iti->xalign = 0.5; + iti->justification = GTK_JUSTIFY_CENTER; + iti->max_lines = -1; + iti->show_ellipsis = TRUE; +} + +/** + * e_icon_bar_text_item_configure: + * @iti: An #EIconBarTextItem. + * @x: X position in which to place the item. + * @y: Y position in which to place the item. + * @width: Maximum width allowed for this item, to be used for word wrapping. + * @fontname: Name of the fontset that should be used to display the text. + * @text: Text that is going to be displayed. + * @is_static: Whether @text points to a static string or not. + * + * This routine is used to configure an #EIconBarTextItem. + * + * @x and @y specify the coordinates where the item is placed in the canvas. + * The @x coordinate should be the leftmost position that the item can + * assume at any one time, that is, the left margin of the column in which the + * icon is to be placed. The @y coordinate specifies the top of the item. + * + * @width is the maximum width allowed for this icon text item. The coordinates + * define the upper-left corner of an item with maximum width; this may + * actually be outside the bounding box of the item if the text is narrower + * than the maximum width. + * + * If @is_static is true, it means that there is no need for the item to + * allocate memory for the string (it is a guarantee that the text is allocated + * by the caller and it will not be deallocated during the lifetime of this + * item). This is an optimization to reduce memory usage for large icon sets. + */ +void +e_icon_bar_text_item_configure (EIconBarTextItem *iti, int x, int y, + int width, const char *fontname, + const char *text, + gboolean is_static) +{ + ItiPrivate *priv; + + g_return_if_fail (iti != NULL); + g_return_if_fail (IS_ITI (iti)); + g_return_if_fail (width > 2 * MARGIN_X); + g_return_if_fail (text != NULL); + + priv = iti->priv; + + iti->x = x; + iti->y = y; + iti->width = width; + + if (iti->text && iti->is_text_allocated) + g_free (iti->text); + + iti->is_text_allocated = !is_static; + + /* This cast is to shut up the compiler */ + if (is_static) + iti->text = (char *) text; + else + iti->text = g_strdup (text); + + if (iti->fontname) + g_free (iti->fontname); + + iti->fontname = g_strdup (fontname ? fontname : DEFAULT_FONT_NAME); + + if (priv->font) + gdk_font_unref (priv->font); + + priv->font = NULL; + if (fontname) + priv->font = gdk_fontset_load (iti->fontname); + if (!priv->font) + priv->font = get_default_font (); + + /* Request update */ + + priv->need_pos_update = TRUE; + priv->need_font_update = TRUE; + priv->need_text_update = TRUE; + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); +} + +/** + * e_icon_bar_text_item_set_width: + * @iti: An #EIconBarTextItem. + * @width: Maximum width allowed for this item, to be used for word wrapping. + * + * This routine is used to set the maximum width of an #EIconBarTextItem. + */ +void +e_icon_bar_text_item_set_width (EIconBarTextItem *iti, int width) +{ + ItiPrivate *priv; + + g_return_if_fail (iti != NULL); + g_return_if_fail (IS_ITI (iti)); + g_return_if_fail (width > 2 * MARGIN_X); + + priv = iti->priv; + + if (iti->width == width) + return; + + iti->width = width; + + /* Request update */ + priv->need_text_update = TRUE; + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); +} + +/** + * e_icon_bar_text_item_setxy: + * @iti: An #EIconBarTextItem. + * @x: X position. + * @y: Y position. + * + * Sets the coordinates at which the #EIconBarTextItem should be placed. + * + * See also: e_icon_bar_text_item_configure(). + */ +void +e_icon_bar_text_item_setxy (EIconBarTextItem *iti, int x, int y) +{ + ItiPrivate *priv; + + g_return_if_fail (iti != NULL); + g_return_if_fail (IS_ITI (iti)); + + priv = iti->priv; + + iti->x = x; + iti->y = y; + + priv->need_pos_update = TRUE; + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); +} + +/** + * e_icon_bar_text_item_select: + * @iti: An #EIconBarTextItem. + * @sel: Whether the item should be displayed as selected. + * + * This function is used to control whether an icon text item is displayed as + * selected or not. Mouse events are ignored by the item when it is unselected; + * when the user clicks on a selected icon text item, it will start the text + * editing process. + */ +void +e_icon_bar_text_item_select (EIconBarTextItem *iti, int sel) +{ + ItiPrivate *priv; + + g_return_if_fail (iti != NULL); + g_return_if_fail (IS_ITI (iti)); + + priv = iti->priv; + + if (!iti->selected == !sel) + return; + + iti->selected = sel ? TRUE : FALSE; + + if (!iti->selected && iti->editing) + iti_edition_accept (iti); + + priv->need_state_update = TRUE; + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); +} + +/** + * e_icon_bar_text_item_get_text: + * @iti: An #EIconBarTextItem. + * + * Returns the current text. The client should not free this string, as it is + * internal to the #EIconBarTextItem. + */ +char * +e_icon_bar_text_item_get_text (EIconBarTextItem *iti) +{ + ItiPrivate *priv; + + g_return_val_if_fail (iti != NULL, NULL); + g_return_val_if_fail (IS_ITI (iti), NULL); + + priv = iti->priv; + + if (iti->editing) + return gtk_entry_get_text (priv->entry); + else + return iti->text; +} + + +/** + * e_icon_bar_text_item_set_text: + * @iti: An #EIconBarTextItem. + * @text: Text that is going to be displayed. + * @is_static: Whether @text points to a static string or not. + * + * If @is_static is true, it means that there is no need for the item to + * allocate memory for the string (it is a guarantee that the text is allocated + * by the caller and it will not be deallocated during the lifetime of this + * item). This is an optimization to reduce memory usage for large icon sets. + */ +void +e_icon_bar_text_item_set_text (EIconBarTextItem *iti, const char *text, + gboolean is_static) +{ + ItiPrivate *priv; + + g_return_if_fail (iti != NULL); + g_return_if_fail (IS_ITI (iti)); + g_return_if_fail (text != NULL); + + priv = iti->priv; + + if (iti->text && iti->is_text_allocated) + g_free (iti->text); + + iti->is_text_allocated = !is_static; + + /* This cast is to shut up the compiler */ + if (is_static) + iti->text = (char *) text; + else + iti->text = g_strdup (text); + + /* Request update */ + + priv->need_text_update = TRUE; + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); +} + + +/** + * e_icon_bar_text_item_start_editing: + * @iti: An #EIconBarTextItem. + * + * Starts the editing state of an #EIconBarTextItem. + **/ +void +e_icon_bar_text_item_start_editing (EIconBarTextItem *iti) +{ + g_return_if_fail (iti != NULL); + g_return_if_fail (IS_ITI (iti)); + + if (iti->editing) + return; + + iti->selected = TRUE; /* Ensure that we are selected */ + gnome_canvas_item_grab_focus (GNOME_CANVAS_ITEM (iti)); + iti_start_editing (iti); +} + +/** + * e_icon_bar_text_item_stop_editing: + * @iti: An #EIconBarTextItem. + * @accept: Whether to accept the current text or to discard it. + * + * Terminates the editing state of an icon text item. The @accept argument + * controls whether the item's current text should be accepted or discarded. + * If it is discarded, then the icon's original text will be restored. + **/ +void +e_icon_bar_text_item_stop_editing (EIconBarTextItem *iti, + gboolean accept) +{ + g_return_if_fail (iti != NULL); + g_return_if_fail (IS_ITI (iti)); + + if (!iti->editing) + return; + + if (accept) + iti_edition_accept (iti); + else + iti_stop_editing (iti); +} + + +/** + * e_icon_bar_text_item_get_type: + * + * Registers the &EIconBarTextItem class if necessary, and returns the type ID + * associated to it. + * + * Return value: the type ID of the #EIconBarTextItem class. + **/ +GtkType +e_icon_bar_text_item_get_type (void) +{ + static GtkType iti_type = 0; + + if (!iti_type) { + static const GtkTypeInfo iti_info = { + "EIconBarTextItem", + sizeof (EIconBarTextItem), + sizeof (EIconBarTextItemClass), + (GtkClassInitFunc) iti_class_init, + (GtkObjectInitFunc) iti_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + iti_type = gtk_type_unique (gnome_canvas_item_get_type (), &iti_info); + } + + return iti_type; +} + + +static void +free_row (gpointer data, gpointer user_data) +{ + EIconBarTextItemInfoRow *row; + + if (data) { + row = data; + g_free (row->text); + g_free (row->text_wc); + g_free (row); + } +} + +/* + * e_icon_bar_text_item_free_info: + * @ti: An icon text info structure. + * + * Frees a &EIconBarTextItemInfo structure. You should call this instead of + * freeing the structure yourself. + */ +static void +e_icon_bar_text_item_free_info (EIconBarTextItemInfo *ti) +{ + g_list_foreach (ti->rows, free_row, NULL); + g_list_free (ti->rows); + g_free (ti); +} + +/* + * e_icon_bar_text_item_layout_text: + * @font: Name of the font that will be used to render the text. + * @text: Text to be formatted. + * @separators: Separators used for word wrapping, can be NULL. + * @max_width: Width in pixels to be used for word wrapping. + * @confine: Whether it is mandatory to wrap at @max_width. + * + * Creates a new &EIconBarTextItemInfo structure by wrapping the specified + * text. If non-NULL, the @separators argument defines a set of characters + * to be used as word delimiters for performing word wrapping. If it is + * NULL, then only spaces will be used as word delimiters. + * + * The @max_width argument is used to specify the width at which word + * wrapping will be performed. If there is a very long word that does not + * fit in a single line, the @confine argument can be used to specify + * whether the word should be unconditionally split to fit or whether + * the maximum width should be increased as necessary. + * + * Return value: A newly-created &EIconBarTextItemInfo structure. + */ +static EIconBarTextItemInfo * +e_icon_bar_text_item_layout_text (EIconBarTextItem *iti, GdkFont *font, + const gchar *text, const gchar *separators, + gint max_width, gboolean confine) +{ + EIconBarTextItemInfo *ti; + EIconBarTextItemInfoRow *row; + GdkWChar *row_end; + GdkWChar *s, *word_start, *word_end, *old_word_end; + GdkWChar *sub_text; + int i, w_len, w; + GdkWChar *text_wc, *text_iter, *separators_wc; + int text_len_wc, separators_len_wc; + gboolean restrict_lines; + int lines; + + g_return_val_if_fail (font != NULL, NULL); + g_return_val_if_fail (text != NULL, NULL); + + if (!separators) + separators = " "; + + text_wc = g_new (GdkWChar, strlen (text) + 1); + text_len_wc = gdk_mbstowcs (text_wc, text, strlen (text)); + if (text_len_wc < 0) text_len_wc = 0; + text_wc[text_len_wc] = 0; + + separators_wc = g_new (GdkWChar, strlen (separators) + 1); + separators_len_wc = gdk_mbstowcs (separators_wc, separators, strlen (separators)); + if (separators_len_wc < 0) separators_len_wc = 0; + separators_wc[separators_len_wc] = 0; + + ti = g_new (EIconBarTextItemInfo, 1); + + ti->rows = NULL; + ti->font = font; + ti->width = 0; + ti->height = 0; + ti->baseline_skip = font->ascent + font->descent; + + word_end = NULL; + + if (!iti->editing && iti->max_lines != -1) + restrict_lines = TRUE; + else + restrict_lines = FALSE; + + text_iter = text_wc; + lines = 0; + while (*text_iter) { + /* If we are restricting the height, and this is the last line, + and we are displaying the ellipsis, then subtract the width + of the ellipsis from our max_width. */ + if (restrict_lines && lines == iti->max_lines - 1 + && iti->show_ellipsis) { + max_width -= gdk_string_measure (font, e_icon_bar_text_item_ellipsis); + } + + for (row_end = text_iter; *row_end != 0 && *row_end != '\n'; row_end++); + + /* Accumulate words from this row until they don't fit in the max_width */ + + s = text_iter; + + while (s < row_end) { + word_start = s; + old_word_end = word_end; + for (word_end = word_start; *word_end; word_end++) { + GdkWChar *p; + for (p = separators_wc; *p; p++) { + if (*word_end == *p) + goto found; + } + } + found: + if (word_end < row_end) + word_end++; + + if (gdk_text_width_wc (font, text_iter, word_end - text_iter) > max_width) { + if (word_start == text_iter + || (restrict_lines + && lines == iti->max_lines - 1)) { + if (confine) { + /* We must force-split the word. Look for a proper + * place to do it. + */ + + w_len = word_end - text_iter; + + for (i = 1; i < w_len; i++) { + w = gdk_text_width_wc (font, text_iter, i); + if (w > max_width) { + if (i == 1) + /* Shit, not even a single character fits */ + max_width = w; + else + break; + } + } + + /* Create sub-row with the chars that fit */ + + sub_text = g_new (GdkWChar, i); + memcpy (sub_text, text_iter, (i - 1) * sizeof (GdkWChar)); + sub_text[i - 1] = 0; + + row = g_new (EIconBarTextItemInfoRow, 1); + row->text_wc = sub_text; + row->text_length = i - 1; + row->width = gdk_text_width_wc (font, sub_text, i - 1); + row->text = gdk_wcstombs(sub_text); + if (row->text == NULL) + row->text = g_strdup(""); + + ti->rows = g_list_append (ti->rows, row); + + if (row->width > ti->width) + ti->width = row->width; + + ti->height += ti->baseline_skip; + + /* Bump the text pointer */ + + text_iter += i - 1; + s = text_iter; + + lines++; + if (restrict_lines + && lines >= iti->max_lines) + break; + + continue; + } else + max_width = gdk_text_width_wc (font, word_start, word_end - word_start); + + continue; /* Retry split */ + } else { + word_end = old_word_end; /* Restore to region that does fit */ + break; /* Stop the loop because we found something that doesn't fit */ + } + } + + s = word_end; + } + + if (restrict_lines && lines >= iti->max_lines) + break; + + /* Append row */ + + if (text_iter == row_end) { + /* We are on a newline, so append an empty row */ + + ti->rows = g_list_append (ti->rows, NULL); + ti->height += ti->baseline_skip; + + /* Next! */ + + text_iter = row_end + 1; + + lines++; + if (restrict_lines && lines >= iti->max_lines) + break; + + } else { + /* Create subrow and append it to the list */ + + int sub_len; + sub_len = word_end - text_iter; + + sub_text = g_new (GdkWChar, sub_len + 1); + memcpy (sub_text, text_iter, sub_len * sizeof (GdkWChar)); + sub_text[sub_len] = 0; + + row = g_new (EIconBarTextItemInfoRow, 1); + row->text_wc = sub_text; + row->text_length = sub_len; + row->width = gdk_text_width_wc (font, sub_text, sub_len); + row->text = gdk_wcstombs(sub_text); + if (row->text == NULL) + row->text = g_strdup(""); + + ti->rows = g_list_append (ti->rows, row); + + if (row->width > ti->width) + ti->width = row->width; + + ti->height += ti->baseline_skip; + + /* Next! */ + + text_iter = word_end; + + lines++; + if (restrict_lines && lines >= iti->max_lines) + break; + } + } + + /* Check if we've had to clip the text. */ + iti->is_clipped = *text_iter ? TRUE : FALSE; + + g_free (text_wc); + g_free (separators_wc); + return ti; +} + +/* + * e_icon_bar_text_item_paint_text: + * @ti: An icon text info structure. + * @drawable: Target drawable. + * @gc: GC used to render the string. + * @x: Left coordinate for text. + * @y: Upper coordinate for text. + * @just: Justification for text. + * + * Paints the formatted text in the icon text info structure onto a drawable. + * This is just a sample implementation; applications can choose to use other + * rendering functions. + */ +static void +e_icon_bar_text_item_paint_text (EIconBarTextItem *iti, + EIconBarTextItemInfo *ti, + GdkDrawable *drawable, GdkGC *gc, + gint x, gint y, GtkJustification just) +{ + GList *item; + EIconBarTextItemInfoRow *row; + int xpos, line, width; + gboolean show_ellipsis; + + g_return_if_fail (ti != NULL); + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + y += ti->font->ascent; + + for (item = ti->rows, line = 1; item; item = item->next, line++) { + + if (item->data) { + row = item->data; + width = row->width; + } + + /* If this is the last line, and the text has been clipped, + and show_ellipsis is TRUE, display '...' */ + if (line == iti->max_lines && iti->is_clipped) { + show_ellipsis = TRUE; + width += gdk_string_measure (ti->font, e_icon_bar_text_item_ellipsis); + } else { + show_ellipsis = FALSE; + } + + switch (just) { + case GTK_JUSTIFY_LEFT: + xpos = 0; + break; + + case GTK_JUSTIFY_RIGHT: + xpos = ti->width - width; + break; + + case GTK_JUSTIFY_CENTER: + xpos = (ti->width - width) / 2; + break; + + default: + /* Anyone care to implement GTK_JUSTIFY_FILL? */ + g_warning ("Justification type %d not supported. Using left-justification.", + (int) just); + xpos = 0; + } + + if (item->data) + gdk_draw_text_wc (drawable, ti->font, gc, x + xpos, y, row->text_wc, row->text_length); + + if (show_ellipsis) + gdk_draw_string (drawable, ti->font, gc, + x + xpos + row->width, y, + e_icon_bar_text_item_ellipsis); + + y += ti->baseline_skip; + } +} diff --git a/widgets/shortcut-bar/e-icon-bar-text-item.h b/widgets/shortcut-bar/e-icon-bar-text-item.h new file mode 100644 index 0000000000..7c0380c87b --- /dev/null +++ b/widgets/shortcut-bar/e-icon-bar-text-item.h @@ -0,0 +1,158 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ + +/* + * Based on gnome-icon-text-item: an editable text block with word wrapping + * for the GNOME canvas. + * + * Copyright (C) 1998, 1999 The Free Software Foundation + * + * Authors: Miguel de Icaza <miguel@gnu.org> + * Federico Mena <federico@gimp.org> + */ + +/* + * EIconBarTextItem - An editable canvas text item for the EIconBar. + */ + +#ifndef _E_ICON_BAR_TEXT_ITEM_H_ +#define _E_ICON_BAR_TEXT_ITEM_H_ + +#include <gtk/gtkentry.h> +#include <libgnomeui/gnome-canvas.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define E_ICON_BAR_TEXT_ITEM(obj) (GTK_CHECK_CAST((obj), \ + e_icon_bar_text_item_get_type (), EIconBarTextItem)) +#define E_ICON_BAR_TEXT_ITEM_CLASS(k) (GTK_CHECK_CLASS_CAST ((k),\ + e_icon_bar_text_item_get_type ())) +#define E_IS_ICON_BAR_TEXT_ITEM(o) (GTK_CHECK_TYPE((o), \ + e_icon_bar_text_item_get_type ())) + +typedef struct _EIconBarTextItemInfo EIconBarTextItemInfo; + +typedef struct { + GnomeCanvasItem canvas_item; + + /* Size and maximum allowed width */ + int x, y; + int width; + + /* Font name */ + char *fontname; + + /* Private data */ + gpointer priv; /* was GtkEntry *entry */ + + /* Actual text */ + char *text; + + /* Text layout information */ + EIconBarTextItemInfo *ti; + + /* Whether the text is being edited */ + unsigned int editing : 1; + + /* Whether the text item is selected */ + unsigned int selected : 1; + + /* Whether the user is select-dragging a block of text */ + unsigned int selecting : 1; + + /* Whether the text is editable */ + unsigned int is_editable : 1; + + /* Whether the text is allocated by us (FALSE if allocated by the client) */ + unsigned int is_text_allocated : 1; + + + /* The horizontal alignment of the text (default 0.5). */ + gfloat xalign; + + /* The justification of the text (default is centered). */ + GtkJustification justification; + + /* The max number of lines of text shown, or -1 for all (default). */ + gint max_lines; + + /* If '...' is displayed if the text doesn't all fit (default TRUE). */ + gboolean show_ellipsis; + + /* This is TRUE if we couldn't fit all the text in. */ + gboolean is_clipped; +} EIconBarTextItem; + +typedef struct { + GnomeCanvasItemClass parent_class; + + /* Signals we emit */ + int (* text_changed) (EIconBarTextItem *iti); + void (* height_changed) (EIconBarTextItem *iti); + void (* width_changed) (EIconBarTextItem *iti); + void (* editing_started) (EIconBarTextItem *iti); + void (* editing_stopped) (EIconBarTextItem *iti); + void (* selection_started) (EIconBarTextItem *iti); + void (* selection_stopped) (EIconBarTextItem *iti); +} EIconBarTextItemClass; + +GtkType e_icon_bar_text_item_get_type (void); + +void e_icon_bar_text_item_configure (EIconBarTextItem *iti, + int x, + int y, + int width, + const char *fontname, + const char *text, + gboolean is_static); + +void e_icon_bar_text_item_set_width (EIconBarTextItem *iti, + int width); + +void e_icon_bar_text_item_setxy (EIconBarTextItem *iti, + int x, + int y); + +void e_icon_bar_text_item_select (EIconBarTextItem *iti, + int sel); + +char* e_icon_bar_text_item_get_text (EIconBarTextItem *iti); +void e_icon_bar_text_item_set_text (EIconBarTextItem *iti, + const char *text, + gboolean is_static); + +void e_icon_bar_text_item_start_editing (EIconBarTextItem *iti); +void e_icon_bar_text_item_stop_editing (EIconBarTextItem *iti, + gboolean accept); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _E_ICON_BAR_TEXT_ITEM_H_ */ + diff --git a/widgets/shortcut-bar/e-icon-bar.c b/widgets/shortcut-bar/e-icon-bar.c new file mode 100644 index 0000000000..6bb32ed2a2 --- /dev/null +++ b/widgets/shortcut-bar/e-icon-bar.c @@ -0,0 +1,1450 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ + +/* + * EIconBar is a subclass of GnomeCanvas for displaying a vertical column of + * icons and descriptions. It provides 2 views - large icons and small icons. + */ + +#include <gtk/gtkmain.h> +#include <gtk/gtksignal.h> +#include <libgnomeui/gnome-canvas-image.h> + +#include "e-icon-bar.h" +#include "e-icon-bar-bg-item.h" +#include "e-icon-bar-text-item.h" + +/* These are the offsets of the icons & text in both views. Note that the + shadow around icons is drawn in the space between items (as is the + horizontal bar when dragging). */ +#define E_ICON_BAR_LARGE_ICON_SPACING 8 /* Spacing between items. */ +#define E_ICON_BAR_LARGE_ICON_WIDTH 48 +#define E_ICON_BAR_LARGE_ICON_HEIGHT 48 +#define E_ICON_BAR_LARGE_ICON_TEXT_X 4 +#define E_ICON_BAR_LARGE_ICON_TEXT_Y (E_ICON_BAR_LARGE_ICON_HEIGHT + 4) + +#define E_ICON_BAR_SMALL_ICON_SPACING 4 /* Spacing between items. */ +#define E_ICON_BAR_SMALL_ICON_WIDTH 24 +#define E_ICON_BAR_SMALL_ICON_HEIGHT 24 +#define E_ICON_BAR_SMALL_ICON_X 4 +#define E_ICON_BAR_SMALL_ICON_TEXT_X (E_ICON_BAR_SMALL_ICON_WIDTH + 4) + +/* The space we leave at the top or bottom of the bar when position an item + while it is being edited. This is used since the EIconBar may be in a + EScrolledBar which may show buttons at the top or bottom. */ +#define E_ICON_BAR_V_SPACE 22 + +/* The number of pixels the mouse has to be moved with the button down before + we start a drag. */ +#define E_ICON_BAR_DRAG_START_OFFSET 4 + +/* This is the area at the top & bottom of the bar where we auto-scroll if the + mouse goes into during a drag-and-drop operation. */ +#define E_ICON_BAR_DRAG_AUTO_SCROLL_OFFSET 16 + +/* This is the time between each auto-scroll, when dragging. */ +#define E_ICON_BAR_SCROLL_TIMEOUT 30 + +/* This is the number of timeouts we skip before we start scrolling. */ +#define E_ICON_BAR_SCROLL_DELAY 12 + + +static void e_icon_bar_class_init (EIconBarClass *class); +static void e_icon_bar_init (EIconBar *icon_bar); +static void e_icon_bar_destroy (GtkObject *object); +static void e_icon_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint e_icon_bar_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event); +static gint e_icon_bar_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint e_icon_bar_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static gint e_icon_bar_key_event (GtkWidget *widget, GdkEventKey *event); + +static gint e_icon_bar_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); +static void e_icon_bar_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time); +static void e_icon_bar_set_dragging_before_item (EIconBar *icon_bar, + gint before_item); +static gboolean e_icon_bar_timeout_handler (gpointer data); + +static void e_icon_bar_recalc_common_positions (EIconBar *icon_bar); +static gint e_icon_bar_recalc_item_positions (EIconBar *icon_bar); +static void e_icon_bar_on_text_height_changed (GnomeCanvasItem *text_item, + EIconBar *icon_bar); +static gint e_icon_bar_find_item (EIconBar *icon_bar, + GnomeCanvasItem *text_item); +static gboolean e_icon_bar_on_item_event (GnomeCanvasItem *item, + GdkEvent *event, + EIconBar *icon_bar); + +static gboolean e_icon_bar_large_icons_intersects (EIconBar *icon_bar, + EIconBarItem *item, + gint x, + gint y); +static gboolean e_icon_bar_large_icons_is_before (EIconBar *icon_bar, + EIconBarItem *item, + gint x, + gint y); +static gboolean e_icon_bar_small_icons_intersects (EIconBar *icon_bar, + EIconBarItem *item, + gint x, + gint y); +static gboolean e_icon_bar_small_icons_is_before (EIconBar *icon_bar, + EIconBarItem *item, + gint x, + gint y); +static void e_icon_bar_on_text_item_editing_started (EIconBarTextItem *text_item, + EIconBar *icon_bar); +static void e_icon_bar_on_text_item_editing_stopped (EIconBarTextItem *text_item, + EIconBar *icon_bar); +static void e_icon_bar_ensure_edited_item_visible (EIconBar *icon_bar); +static void e_icon_bar_update_highlight (EIconBar *icon_bar); + +enum +{ + ITEM_SELECTED, + ITEM_DRAGGED, + LAST_SIGNAL +}; + +static guint e_icon_bar_signals[LAST_SIGNAL] = {0}; + +static GnomeCanvasClass *parent_class; + + +GtkType +e_icon_bar_get_type (void) +{ + static GtkType e_icon_bar_type = 0; + + if (!e_icon_bar_type){ + GtkTypeInfo e_icon_bar_info = { + "EIconBar", + sizeof (EIconBar), + sizeof (EIconBarClass), + (GtkClassInitFunc) e_icon_bar_class_init, + (GtkObjectInitFunc) e_icon_bar_init, + NULL, /* reserved 1 */ + NULL, /* reserved 2 */ + (GtkClassInitFunc) NULL + }; + + parent_class = gtk_type_class (gnome_canvas_get_type ()); + e_icon_bar_type = gtk_type_unique (gnome_canvas_get_type (), + &e_icon_bar_info); + } + + return e_icon_bar_type; +} + + +static void +e_icon_bar_class_init (EIconBarClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass *) class; + widget_class = (GtkWidgetClass *) class; + + e_icon_bar_signals[ITEM_SELECTED] = + gtk_signal_new ("item_selected", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (EIconBarClass, + selected_item), + gtk_marshal_NONE__POINTER_INT, + GTK_TYPE_NONE, 2, GTK_TYPE_GDK_EVENT, + GTK_TYPE_INT); + e_icon_bar_signals[ITEM_DRAGGED] = + gtk_signal_new ("item_dragged", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (EIconBarClass, + dragged_item), + gtk_marshal_NONE__POINTER_INT, + GTK_TYPE_NONE, 2, GTK_TYPE_GDK_EVENT, + GTK_TYPE_INT); + + gtk_object_class_add_signals (object_class, e_icon_bar_signals, + LAST_SIGNAL); + + /* Method override */ + object_class->destroy = e_icon_bar_destroy; + + widget_class->size_allocate = e_icon_bar_size_allocate; + widget_class->leave_notify_event = e_icon_bar_leave_notify_event; + widget_class->focus_in_event = e_icon_bar_focus_in; + widget_class->focus_out_event = e_icon_bar_focus_out; + widget_class->key_press_event = e_icon_bar_key_event; + widget_class->key_release_event = e_icon_bar_key_event; + widget_class->drag_motion = e_icon_bar_drag_motion; + widget_class->drag_leave = e_icon_bar_drag_leave; + + class->selected_item = NULL; +} + + +static void +e_icon_bar_init (EIconBar *icon_bar) +{ + icon_bar->view_type = E_ICON_BAR_LARGE_ICONS; + icon_bar->items = g_array_new (FALSE, FALSE, sizeof (EIconBarItem)); + icon_bar->pressed_item_num = -1; + icon_bar->mouse_over_item_num = -1; + icon_bar->editing_item_num = -1; + icon_bar->in_drag = FALSE; + icon_bar->dragging_before_item_num = -1; + icon_bar->icon_x = 0; + icon_bar->icon_w = 0; + icon_bar->icon_h = 0; + icon_bar->text_x = 0; + icon_bar->text_w = 5; + icon_bar->auto_scroll_timeout_id = 0; + + /* Create the background item in the canvas, which handles selections + and drag-and-drop. */ + gnome_canvas_item_new (GNOME_CANVAS_GROUP (GNOME_CANVAS (icon_bar)->root), + e_icon_bar_bg_item_get_type (), + "EIconBarBgItem::icon_bar", icon_bar, + NULL); +} + + +/** + * e_icon_bar_new: + * @Returns: A new #EIconBar. + * + * Creates a new #EIconBar. + **/ +GtkWidget * +e_icon_bar_new (void) +{ + GtkWidget *icon_bar; + + icon_bar = GTK_WIDGET (gtk_type_new (e_icon_bar_get_type ())); + + return icon_bar; +} + + +static void +e_icon_bar_destroy (GtkObject *object) +{ + EIconBar *icon_bar; + + icon_bar = E_ICON_BAR (object); + + GTK_OBJECT_CLASS (parent_class)->destroy (object); + + g_array_free (icon_bar->items, TRUE); + + if (icon_bar->auto_scroll_timeout_id != 0) { + gtk_timeout_remove (icon_bar->auto_scroll_timeout_id); + icon_bar->auto_scroll_timeout_id = 0; + } +} + + +static void +e_icon_bar_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + EIconBar *icon_bar; + gint canvas_width, canvas_height, height; + + icon_bar = E_ICON_BAR (widget); + + GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation); + + canvas_width = GTK_WIDGET (icon_bar)->allocation.width; + canvas_height = GTK_WIDGET (icon_bar)->allocation.height; + + /* Reset the y position and widths of all the items to the width of + the canvas, and reset the button labels, so they fit. */ + e_icon_bar_recalc_common_positions (icon_bar); + height = e_icon_bar_recalc_item_positions (icon_bar); + + gnome_canvas_set_scroll_region (GNOME_CANVAS (widget), + 0, 0, canvas_width, + MAX (height, canvas_height - 1)); + + /* If we are editing an item, make sure it is visible. */ + e_icon_bar_ensure_edited_item_visible (icon_bar); + + GTK_LAYOUT (widget)->vadjustment->step_increment = 16; + + e_icon_bar_update_highlight (icon_bar); +} + + +/* This sets all the item positions which are the same for all items in the + group. */ +static void +e_icon_bar_recalc_common_positions (EIconBar *icon_bar) +{ + gint canvas_width; + + canvas_width = GTK_WIDGET (icon_bar)->allocation.width; + + if (icon_bar->view_type == E_ICON_BAR_LARGE_ICONS) { + icon_bar->icon_x = (canvas_width - E_ICON_BAR_LARGE_ICON_WIDTH) / 2; + icon_bar->icon_w = E_ICON_BAR_LARGE_ICON_WIDTH; + icon_bar->icon_h = E_ICON_BAR_LARGE_ICON_HEIGHT; + + icon_bar->text_x = E_ICON_BAR_LARGE_ICON_TEXT_X; + icon_bar->text_w = MAX (canvas_width - (E_ICON_BAR_LARGE_ICON_TEXT_X * 2), 5); + + icon_bar->spacing = E_ICON_BAR_LARGE_ICON_SPACING; + } else { + icon_bar->icon_x = E_ICON_BAR_SMALL_ICON_X; + icon_bar->icon_w = E_ICON_BAR_SMALL_ICON_WIDTH; + icon_bar->icon_h = E_ICON_BAR_SMALL_ICON_HEIGHT; + + icon_bar->text_x = E_ICON_BAR_SMALL_ICON_TEXT_X; + icon_bar->text_w = MAX (canvas_width - E_ICON_BAR_SMALL_ICON_TEXT_X, 5); + + icon_bar->spacing = E_ICON_BAR_SMALL_ICON_SPACING; + } +} + + +/* This recalculates the positions of all the items, according to the current + view type and the height of the text items. */ +static gint +e_icon_bar_recalc_item_positions (EIconBar *icon_bar) +{ + EIconBarItem *item; + gint y, item_num; + gdouble x1, y1, x2, y2, xalign; + GtkJustification justify; + gint max_lines; + + if (icon_bar->view_type == E_ICON_BAR_LARGE_ICONS) { + xalign = 0.5; + justify = GTK_JUSTIFY_CENTER; + max_lines = 2; + } else { + xalign = 0.0; + justify = GTK_JUSTIFY_LEFT; + max_lines = 1; + } + + /* Now step through the items, setting the y positions. */ + y = icon_bar->spacing; + for (item_num = 0; item_num < icon_bar->items->len; item_num++) { + item = &g_array_index (icon_bar->items, + EIconBarItem, item_num); + + e_icon_bar_text_item_set_width (E_ICON_BAR_TEXT_ITEM (item->text), + icon_bar->text_w); + + /* Get the text item's height. */ + gnome_canvas_item_get_bounds (item->text, &x1, &y1, &x2, &y2); + item->text_width = x2 - x1; + item->text_height = y2 - y1; + + if (icon_bar->view_type == E_ICON_BAR_LARGE_ICONS) { + item->icon_y = y; + item->text_y = y + E_ICON_BAR_LARGE_ICON_TEXT_Y; + + item->item_height = E_ICON_BAR_LARGE_ICON_TEXT_Y + + item->text_height; + } else { + item->item_height = MAX (item->text_height, E_ICON_BAR_SMALL_ICON_HEIGHT); + item->icon_y = y + (item->item_height - E_ICON_BAR_SMALL_ICON_HEIGHT) / 2; + item->text_y = y + (item->item_height - item->text_height) / 2; + } + + e_icon_bar_text_item_setxy (E_ICON_BAR_TEXT_ITEM (item->text), + icon_bar->text_x, item->text_y); + + /* We need to get the bounds again, in case it has moved. */ + gnome_canvas_item_get_bounds (item->text, &x1, &y1, &x2, &y2); + item->text_x = x1; + + gnome_canvas_item_set (item->text, + "EIconBarTextItem::xalign", xalign, + "EIconBarTextItem::justify", justify, + "EIconBarTextItem::max_lines", max_lines, + NULL); + + gnome_canvas_item_set (item->image, + "GnomeCanvasImage::x", (gdouble)icon_bar->icon_x, + "GnomeCanvasImage::y", (gdouble)item->icon_y, + "GnomeCanvasImage::width", (gdouble)icon_bar->icon_w, + "GnomeCanvasImage::height", (gdouble)icon_bar->icon_h, + NULL); + + y += item->item_height + icon_bar->spacing; + } + + return y; +} + + +static gint +e_icon_bar_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event) +{ + EIconBar *icon_bar; + + icon_bar = E_ICON_BAR (widget); + + GTK_WIDGET_CLASS (parent_class)->leave_notify_event (widget, event); + + /* Make sure no items are highlighted. */ + e_icon_bar_item_motion (icon_bar, -1, NULL); + + return FALSE; +} + + +static gint +e_icon_bar_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (E_IS_ICON_BAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_CLASS (parent_class)->focus_in_event (widget, event); + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + return FALSE; +} + + +static gint +e_icon_bar_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (E_IS_ICON_BAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_CLASS (parent_class)->focus_out_event (widget, event); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + return FALSE; +} + + +/* Key event handler for the canvas. + FIXME: GnomeCanvas bug workaround - I needed to override this to stop the + canvas ignoring key events from other windows. */ +static gint +e_icon_bar_key_event (GtkWidget *widget, GdkEventKey *event) +{ + GnomeCanvas *canvas; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (E_IS_ICON_BAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + canvas = GNOME_CANVAS (widget); + + if (event->window != canvas->layout.bin_window) { + /* We change the window in the event struct so the canvas + doesn't ignore the event. Note that windows are ref-counted + in the event struct. */ + if (event->window) + gdk_window_unref (event->window); + event->window = canvas->layout.bin_window; + gdk_window_ref (event->window); + } + + /* These both call the same function at present, but we'll do it + properly just in case that changes. */ + if (event->type == GDK_KEY_PRESS) + return (*GTK_WIDGET_CLASS (parent_class)->key_press_event)(widget, event); + else + return (*GTK_WIDGET_CLASS (parent_class)->key_release_event)(widget, event); +} + + +/** + * e_icon_bar_set_view_type: + * @icon_bar: An #EIconBar. + * @view_type: The new view type, %E_ICON_BAR_LARGE_ICONS or + * %E_ICON_BAR_SMALL_ICONS. + * + * Sets the view type of the #EIconBar. + **/ +void +e_icon_bar_set_view_type (EIconBar *icon_bar, + EIconBarViewType view_type) +{ + g_return_if_fail (E_IS_ICON_BAR (icon_bar)); + + if (icon_bar->view_type == view_type) + return; + + icon_bar->view_type = view_type; + + /* Queue a resize of the canvas, so everything is put in the right + positions based on the new view type. */ + gtk_widget_queue_resize (GTK_WIDGET (icon_bar)); +} + + +/** + * e_icon_bar_add_item: + * @icon_bar: An #EIconBar. + * @image: the new item's icon. + * @text: the new item's text. + * @position: the position to place the new item, or -1 to place it last. + * + * Adds an item to the #EIconBar at the given position. + **/ +gint +e_icon_bar_add_item (EIconBar *icon_bar, + GdkImlibImage *image, + gchar *text, + gint position) +{ + EIconBarItem item; + gfloat xalign; + GtkJustification justify; + gint max_lines, retval; + + g_return_val_if_fail (E_IS_ICON_BAR (icon_bar), -1); + g_return_val_if_fail (text != NULL, -1); + g_return_val_if_fail (position >= -1, -1); + g_return_val_if_fail (position <= (gint)icon_bar->items->len, -1); + + if (icon_bar->view_type == E_ICON_BAR_LARGE_ICONS) { + xalign = 0.5; + justify = GTK_JUSTIFY_CENTER; + max_lines = 2; + } else { + xalign = 0.0; + justify = GTK_JUSTIFY_LEFT; + max_lines = 1; + } + + item.text = gnome_canvas_item_new (GNOME_CANVAS_GROUP (GNOME_CANVAS (icon_bar)->root), + e_icon_bar_text_item_get_type (), + "EIconBarTextItem::xalign", xalign, + "EIconBarTextItem::justify", justify, + "EIconBarTextItem::max_lines", max_lines, + NULL); + e_icon_bar_text_item_configure (E_ICON_BAR_TEXT_ITEM (item.text), + icon_bar->text_x, 0, + icon_bar->text_w, NULL, + text, FALSE); + gtk_signal_connect (GTK_OBJECT (item.text), "height_changed", + GTK_SIGNAL_FUNC (e_icon_bar_on_text_height_changed), icon_bar); + gtk_signal_connect (GTK_OBJECT (item.text), "event", + GTK_SIGNAL_FUNC (e_icon_bar_on_item_event), + icon_bar); + gtk_signal_connect (GTK_OBJECT (item.text), "editing_started", + GTK_SIGNAL_FUNC (e_icon_bar_on_text_item_editing_started), + icon_bar); + gtk_signal_connect (GTK_OBJECT (item.text), "editing_stopped", + GTK_SIGNAL_FUNC (e_icon_bar_on_text_item_editing_stopped), + icon_bar); + + item.image = gnome_canvas_item_new (GNOME_CANVAS_GROUP (GNOME_CANVAS (icon_bar)->root), + gnome_canvas_image_get_type (), + "GnomeCanvasImage::image", image, + "GnomeCanvasImage::anchor", GTK_ANCHOR_NORTH_WEST, + "GnomeCanvasImage::width", (gdouble) icon_bar->icon_w, + "GnomeCanvasImage::height", (gdouble) icon_bar->icon_h, + NULL); + gtk_signal_connect (GTK_OBJECT (item.image), "event", + GTK_SIGNAL_FUNC (e_icon_bar_on_item_event), + icon_bar); + + item.data = NULL; + item.destroy = NULL; + + if (position == -1) { + g_array_append_val (icon_bar->items, item); + retval = icon_bar->items->len - 1; + } else { + g_array_insert_val (icon_bar->items, position, item); + retval = position; + + /* FIXME: Should possibly update other indices. */ + if (icon_bar->dragged_item_num >= position) + icon_bar->dragged_item_num++; + } + + gtk_widget_queue_resize (GTK_WIDGET (icon_bar)); + + return retval; +} + + +/** + * e_icon_bar_reorder_item: + * @icon_bar: An #EIconBar. + * @item_num: The index of the item to move. + * @new_position: The new position of the item, which is used after the item + * has been removed from its current position. If @new_position is -1, the item + * is placed last. + * + * Moves an item to a new position within the #EIconBar. + **/ +void +e_icon_bar_reorder_item (EIconBar *icon_bar, + gint item_num, + gint new_position) +{ + EIconBarItem tmp_item; + + g_return_if_fail (E_IS_ICON_BAR (icon_bar)); + g_return_if_fail (item_num >= 0); + g_return_if_fail (item_num < icon_bar->items->len); + g_return_if_fail (new_position >= -1); + g_return_if_fail (new_position < icon_bar->items->len); + + tmp_item = g_array_index (icon_bar->items, EIconBarItem, item_num); + g_array_remove_index (icon_bar->items, item_num); + + if (new_position == -1) + g_array_append_val (icon_bar->items, tmp_item); + else + g_array_insert_val (icon_bar->items, new_position, tmp_item); + + gtk_widget_queue_resize (GTK_WIDGET (icon_bar)); +} + + +/** + * e_icon_bar_remove_item: + * @icon_bar: An #EIconBar. + * @item_num: The index of the item to remove. + * + * Removes an item from the #EIconBar. + **/ +void +e_icon_bar_remove_item (EIconBar *icon_bar, + gint item_num) +{ + EIconBarItem *item; + + g_return_if_fail (E_IS_ICON_BAR (icon_bar)); + g_return_if_fail (item_num >= 0); + g_return_if_fail (item_num < icon_bar->items->len); + + item = &g_array_index (icon_bar->items, EIconBarItem, item_num); + + if (item->destroy) + item->destroy (item->data); + + gtk_object_destroy (GTK_OBJECT (item->text)); + gtk_object_destroy (GTK_OBJECT (item->image)); + + g_array_remove_index (icon_bar->items, item_num); + + gtk_widget_queue_resize (GTK_WIDGET (icon_bar)); +} + + +/** + * e_icon_bar_get_item_image: + * @icon_bar: An #EIconBar. + * @item_num: The index of the item. + * @Returns: The icon of the given item. + * + * Returns the icon used for the given item. + **/ +GdkImlibImage* +e_icon_bar_get_item_image (EIconBar *icon_bar, + gint item_num) +{ + EIconBarItem *item; + GdkImlibImage *image; + + g_return_val_if_fail (E_IS_ICON_BAR (icon_bar), NULL); + g_return_val_if_fail (item_num >= 0, NULL); + g_return_val_if_fail (item_num < icon_bar->items->len, NULL); + + item = &g_array_index (icon_bar->items, EIconBarItem, item_num); + gtk_object_get (GTK_OBJECT (item->image), + "GnomeCanvasImage::image", image, + NULL); + return image; +} + + +/** + * e_icon_bar_set_item_image: + * @icon_bar: An #EIconBar. + * @item_num: The index of the item. + * @image: The new icon to use for the given item. + * + * Sets the icon to use for the given item. + **/ +void +e_icon_bar_set_item_image (EIconBar *icon_bar, + gint item_num, + GdkImlibImage *image) +{ + EIconBarItem *item; + + g_return_if_fail (E_IS_ICON_BAR (icon_bar)); + g_return_if_fail (item_num >= 0); + g_return_if_fail (item_num < icon_bar->items->len); + + item = &g_array_index (icon_bar->items, EIconBarItem, item_num); + gnome_canvas_item_set (item->image, + "GnomeCanvasImage::image", image, + NULL); +} + + +/** + * e_icon_bar_get_item_text: + * @icon_bar: An #EIconBar. + * @item_num: The index of the item. + * @Returns: The text of the given item. + * + * Returns the text of the given item. + **/ +gchar* +e_icon_bar_get_item_text (EIconBar *icon_bar, + gint item_num) +{ + EIconBarItem *item; + + g_return_val_if_fail (E_IS_ICON_BAR (icon_bar), NULL); + g_return_val_if_fail (item_num >= 0, NULL); + g_return_val_if_fail (item_num < icon_bar->items->len, NULL); + + item = &g_array_index (icon_bar->items, EIconBarItem, item_num); + return e_icon_bar_text_item_get_text (E_ICON_BAR_TEXT_ITEM (item->text)); +} + + +/** + * e_icon_bar_set_item_text: + * @icon_bar: An #EIconBar. + * @item_num: The index of the item. + * @text: The new text for the given item. + * + * Sets the text of the given item. + **/ +void +e_icon_bar_set_item_text (EIconBar *icon_bar, + gint item_num, + gchar *text) +{ + EIconBarItem *item; + + g_return_if_fail (E_IS_ICON_BAR (icon_bar)); + g_return_if_fail (item_num >= 0); + g_return_if_fail (item_num < icon_bar->items->len); + + item = &g_array_index (icon_bar->items, EIconBarItem, item_num); + e_icon_bar_text_item_set_text (E_ICON_BAR_TEXT_ITEM (item->text), + text, FALSE); +} + + +/** + * e_icon_bar_get_item_data: + * @icon_bar: An #EIconBar. + * @item_num: The index of the item. + * @Returns: The user data associated with the given item. + * + * Returns the user data associated with the given item. + **/ +gpointer +e_icon_bar_get_item_data (EIconBar *icon_bar, + gint item_num) +{ + EIconBarItem *item; + + g_return_val_if_fail (E_IS_ICON_BAR (icon_bar), NULL); + g_return_val_if_fail (item_num >= 0, NULL); + g_return_val_if_fail (item_num < icon_bar->items->len, NULL); + + item = &g_array_index (icon_bar->items, EIconBarItem, item_num); + return item->data; +} + + +/** + * e_icon_bar_set_item_data: + * @icon_bar: An #EIconBar. + * @item_num: The index of the item. + * @data: The user data to set for the given item. + * + * Sets the user data of the given item. + **/ +void +e_icon_bar_set_item_data (EIconBar *icon_bar, + gint item_num, + gpointer data) +{ + e_icon_bar_set_item_data_full (icon_bar, item_num, data, NULL); +} + + +/** + * e_icon_bar_set_item_data_full: + * @icon_bar: An #EIconBar. + * @item_num: The index of the item. + * @data: The user data to set for the given item. + * @destroy: The function to free @data when the item is destroyed. + * + * Sets the user data of the given item, and the function to free the data + * when the item is destroyed. + **/ +void +e_icon_bar_set_item_data_full (EIconBar *icon_bar, + gint item_num, + gpointer data, + GtkDestroyNotify destroy) +{ + EIconBarItem *item; + + g_return_if_fail (E_IS_ICON_BAR (icon_bar)); + g_return_if_fail (item_num >= 0); + g_return_if_fail (item_num < icon_bar->items->len); + + item = &g_array_index (icon_bar->items, EIconBarItem, item_num); + + if (item->destroy) + item->destroy (item->data); + + item->data = data; + item->destroy = destroy; +} + + +static void +e_icon_bar_on_text_height_changed (GnomeCanvasItem *text_item, + EIconBar *icon_bar) +{ + gtk_widget_queue_resize (GTK_WIDGET (icon_bar)); +} + + +/* This returns the index of the given item, or -1 if it isn't found. */ +static gint +e_icon_bar_find_item (EIconBar *icon_bar, + GnomeCanvasItem *canvas_item) +{ + EIconBarItem *item; + gint item_num; + + for (item_num = 0; item_num < icon_bar->items->len; item_num++) { + item = &g_array_index (icon_bar->items, + EIconBarItem, item_num); + + if (item->text == canvas_item || item->image == canvas_item) { + return item_num; + } + } + + return -1; +} + + +/* When an item has a grab, it will get all events, so we need to use the + position to find the real item. */ +static gboolean +e_icon_bar_on_item_event (GnomeCanvasItem *item, + GdkEvent *event, + EIconBar *icon_bar) +{ + gint item_num; + + switch (event->type) { + case GDK_BUTTON_PRESS: + item_num = e_icon_bar_find_item_at_position (icon_bar, + event->button.x, + event->button.y, + NULL); + e_icon_bar_item_pressed (icon_bar, item_num, event); + return TRUE; + case GDK_BUTTON_RELEASE: + item_num = e_icon_bar_find_item_at_position (icon_bar, + event->button.x, + event->button.y, + NULL); + e_icon_bar_item_released (icon_bar, item_num, event); + return TRUE; + case GDK_MOTION_NOTIFY: + item_num = e_icon_bar_find_item_at_position (icon_bar, + event->motion.x, + event->motion.y, + NULL); + e_icon_bar_item_motion (icon_bar, item_num, event); + return TRUE; + default: + break; + } + + return FALSE; +} + + +void +e_icon_bar_item_pressed (EIconBar *icon_bar, + gint item_num, + GdkEvent *event) +{ + EIconBarItem *item; + gint button; + + /* If we are editing an item, and a different item (or anywhere outside + an item) is clicked, stop the edit. If the item being edited is + clicked we just return, since the user may be selecting text. */ + if (icon_bar->editing_item_num != -1) { + if (icon_bar->editing_item_num == item_num) { + item = &g_array_index (icon_bar->items, EIconBarItem, + icon_bar->editing_item_num); + if (!GTK_WIDGET_HAS_FOCUS (item->text->canvas) + || item->text->canvas->focused_item != item->text) + gnome_canvas_item_grab_focus (item->text); + } else { + e_icon_bar_stop_editing_item (icon_bar, TRUE); + } + + return; + } + + button = event->button.button; + + if (button == 1 && item_num != -1) { + icon_bar->pressed_item_num = item_num; + icon_bar->pressed_x = event->button.x; + icon_bar->pressed_y = event->button.y; + gtk_widget_queue_draw (GTK_WIDGET (icon_bar)); + } else if (button == 3) { + gtk_signal_emit (GTK_OBJECT (icon_bar), + e_icon_bar_signals[ITEM_SELECTED], + event, item_num); + } +} + + +void +e_icon_bar_item_released (EIconBar *icon_bar, + gint item_num, + GdkEvent *event) +{ + gint button; + + /* If we are editing an item, just return. */ + if (icon_bar->editing_item_num != -1) + return; + + button = event->button.button; + + if (button == 1) { + if (icon_bar->pressed_item_num == icon_bar->mouse_over_item_num) { + gtk_signal_emit (GTK_OBJECT (icon_bar), + e_icon_bar_signals[ITEM_SELECTED], + event, item_num); + } + + icon_bar->pressed_item_num = -1; + gtk_widget_queue_draw (GTK_WIDGET (icon_bar)); + } +} + + +void +e_icon_bar_item_motion (EIconBar *icon_bar, + gint item_num, + GdkEvent *event) +{ + gboolean need_redraw = TRUE; + + if (event && event->motion.state & GDK_BUTTON1_MASK + && icon_bar->pressed_item_num != -1) { + if (abs (event->motion.x - icon_bar->pressed_x) > E_ICON_BAR_DRAG_START_OFFSET + || abs (event->motion.y - icon_bar->pressed_y) > E_ICON_BAR_DRAG_START_OFFSET) { + icon_bar->dragged_item_num = icon_bar->pressed_item_num; + gtk_signal_emit (GTK_OBJECT (icon_bar), + e_icon_bar_signals[ITEM_DRAGGED], + event, icon_bar->dragged_item_num); + + /* Don't show the button as pressed while dragging. */ + icon_bar->pressed_item_num = -1; + gtk_widget_queue_draw (GTK_WIDGET (icon_bar)); + } + + return; + } + + if (icon_bar->mouse_over_item_num == item_num) + return; + + /* If we are editing an item, items aren't highlighted so we don't + need a redraw. Also if an item is pressed, we only need a redraw if + item_num or the old mouse_over_item_num is the pressed item. */ + if (icon_bar->editing_item_num != -1) { + need_redraw = FALSE; + } else if (icon_bar->pressed_item_num != -1) { + if (icon_bar->pressed_item_num != item_num + && icon_bar->pressed_item_num != icon_bar->mouse_over_item_num) + need_redraw = FALSE; + } + + icon_bar->mouse_over_item_num = item_num; + + if (need_redraw) + gtk_widget_queue_draw (GTK_WIDGET (icon_bar)); +} + + +/* This returns the index of the item at the given position on the EIconBar, + or -1 if no item is found. If before_item is not NULL, it returns the + item which the mouse is before, or -1 (for dragging). */ +gint +e_icon_bar_find_item_at_position (EIconBar *icon_bar, + gint x, + gint y, + gint *before_item) +{ + EIconBarItem *item; + gint item_num; + + if (before_item) + *before_item = -1; + + for (item_num = 0; item_num < icon_bar->items->len; item_num++) { + item = &g_array_index (icon_bar->items, + EIconBarItem, item_num); + + if (icon_bar->view_type == E_ICON_BAR_LARGE_ICONS) { + if (e_icon_bar_large_icons_intersects (icon_bar, item, + x, y)) + return item_num; + + if (before_item + && e_icon_bar_large_icons_is_before (icon_bar, + item, x, y)) { + *before_item = item_num; + return -1; + } + } else { + if (e_icon_bar_small_icons_intersects (icon_bar, item, + x, y)) + return item_num; + + if (before_item + && e_icon_bar_small_icons_is_before (icon_bar, + item, x, y)) { + *before_item = item_num; + return -1; + } + + } + + } + + /* If the mouse is below all the items, but inside the items' width, + and before_item is not NULL, we set it to the number of items, so + the dropped item would be added at the end. Note that this assumes + that the item variable points to the last item in the EIconBar. */ + if (before_item) { + if (icon_bar->view_type == E_ICON_BAR_LARGE_ICONS) { + if (x < icon_bar->text_x + || x >= icon_bar->text_x + icon_bar->text_w) + return -1; + + if (item == NULL + || y > item->icon_y + item->item_height) + *before_item = icon_bar->items->len; + } else { + if (x < icon_bar->icon_x + || x >= icon_bar->text_x + icon_bar->text_w) + return -1; + + if (item == NULL) { + *before_item = icon_bar->items->len; + } else { + gint max_y; + max_y = MAX (item->icon_y + icon_bar->icon_h, + item->text_y + item->text_height); + if (y > max_y) + *before_item = icon_bar->items->len; + } + } + } + + return -1; +} + + +static gboolean +e_icon_bar_large_icons_intersects (EIconBar *icon_bar, + EIconBarItem *item, + gint x, + gint y) +{ + if (y < item->icon_y || y >= item->text_y + item->text_height) + return FALSE; + + if (y < item->icon_y + icon_bar->icon_h) { + if (x < icon_bar->icon_x + || x >= icon_bar->icon_x + icon_bar->icon_w) + return FALSE; + } else { + if (x < item->text_x + || x >= item->text_x + item->text_width) + return FALSE; + } + + return TRUE; +} + + +static gboolean +e_icon_bar_large_icons_is_before (EIconBar *icon_bar, + EIconBarItem *item, + gint x, + gint y) +{ + if (y < item->icon_y - icon_bar->spacing + || y >= item->icon_y) + return FALSE; + + if (x < icon_bar->text_x || x >= icon_bar->text_x + icon_bar->text_w) + return FALSE; + + return TRUE; +} + + +static gboolean +e_icon_bar_small_icons_intersects (EIconBar *icon_bar, + EIconBarItem *item, + gint x, + gint y) +{ + gint min_y, max_y; + + min_y = MIN (item->icon_y, item->text_y); + max_y = MAX (item->icon_y + icon_bar->icon_h, + item->text_y + item->text_height); + + if (y < min_y || y >= max_y) + return FALSE; + + if (x < icon_bar->icon_x || x >= item->text_x + item->text_width) + return FALSE; + + return TRUE; +} + + +static gboolean +e_icon_bar_small_icons_is_before (EIconBar *icon_bar, + EIconBarItem *item, + gint x, + gint y) +{ + gint min_y, max_y; + + max_y = MIN (item->icon_y, item->text_y); + min_y = max_y - icon_bar->spacing; + + if (y < min_y || y >= max_y) + return FALSE; + + if (x < icon_bar->icon_x || x >= icon_bar->text_x + icon_bar->text_w) + return FALSE; + + return TRUE; +} + + +/** + * e_icon_bar_start_editing_item: + * @icon_bar: An #EIconBar. + * @item_num: The index of the item. + * + * Turns the item into an editable text field so the user can rename it. + * Editing is stopped automatically when the user hits 'Return' or clicks + * outside the item. It can also be stopped explicitly by calling + * e_icon_bar_stop_editing_item(). + **/ +void +e_icon_bar_start_editing_item (EIconBar *icon_bar, + gint item_num) +{ + EIconBarItem *item; + + g_return_if_fail (E_IS_ICON_BAR (icon_bar)); + g_return_if_fail (item_num >= 0); + g_return_if_fail (item_num < icon_bar->items->len); + + item = &g_array_index (icon_bar->items, + EIconBarItem, item_num); + + e_icon_bar_text_item_start_editing (E_ICON_BAR_TEXT_ITEM (item->text)); +} + + +/** + * e_icon_bar_stop_editing_item: + * @icon_bar: An #EIconBar. + * @accept: TRUE if the changes should be accepted, FALSE if the text should be + * changed back to its state before the editing started. + * + * Stops the editing of the items, if any were being edited. + **/ +void +e_icon_bar_stop_editing_item (EIconBar *icon_bar, + gboolean accept) +{ + EIconBarItem *item; + + g_return_if_fail (E_IS_ICON_BAR (icon_bar)); + + if (icon_bar->editing_item_num != -1) { + item = &g_array_index (icon_bar->items, EIconBarItem, + icon_bar->editing_item_num); + e_icon_bar_text_item_stop_editing (E_ICON_BAR_TEXT_ITEM (item->text), accept); + } +} + + +static void +e_icon_bar_on_text_item_editing_started (EIconBarTextItem *text_item, + EIconBar *icon_bar) +{ + gint item_num; + + item_num = e_icon_bar_find_item (icon_bar, + GNOME_CANVAS_ITEM (text_item)); + g_return_if_fail (item_num != -1); + + /* Turn off any highlighted item. */ + e_icon_bar_item_motion (icon_bar, -1, NULL); + + icon_bar->editing_item_num = item_num; + + e_icon_bar_ensure_edited_item_visible (icon_bar); +} + + +static void +e_icon_bar_on_text_item_editing_stopped (EIconBarTextItem *text_item, + EIconBar *icon_bar) +{ + gint item_num; + + item_num = e_icon_bar_find_item (icon_bar, + GNOME_CANVAS_ITEM (text_item)); + g_return_if_fail (item_num != -1); + + e_icon_bar_text_item_select (text_item, FALSE); + + icon_bar->editing_item_num = -1; + + e_icon_bar_update_highlight (icon_bar); +} + + +static void +e_icon_bar_ensure_edited_item_visible (EIconBar *icon_bar) +{ + EIconBarItem *item; + gint scroll_x, scroll_y, min_scroll_y, max_scroll_y, new_scroll_y; + + if (icon_bar->editing_item_num == -1) + return; + + item = &g_array_index (icon_bar->items, + EIconBarItem, icon_bar->editing_item_num); + gnome_canvas_get_scroll_offsets (GNOME_CANVAS (icon_bar), + &scroll_x, &scroll_y); + + /* The minimum scroll y position is with the text right on the bottom + of the display. */ + min_scroll_y = item->text_y + item->text_height + E_ICON_BAR_V_SPACE + - GTK_WIDGET (icon_bar)->allocation.height; + /* The maximum scroll y position is with the text at the top. */ + max_scroll_y = item->text_y - E_ICON_BAR_V_SPACE; + + new_scroll_y = MAX (scroll_y, min_scroll_y); + new_scroll_y = MIN (new_scroll_y, max_scroll_y); + + if (new_scroll_y != scroll_y) + gnome_canvas_scroll_to (GNOME_CANVAS (icon_bar), + scroll_x, new_scroll_y); +} + + +/* This gets the mouse position and updates the highlight if necessary. + It is called after items are added/deleted/scrolled/edited. */ +static void +e_icon_bar_update_highlight (EIconBar *icon_bar) +{ + GtkWidget *widget; + gint x, y, item_num; + + widget = GTK_WIDGET (icon_bar); + + if (!widget->window) + return; + + gdk_window_get_pointer (widget->window, &x, &y, NULL); + + if (x < 0 || y < 0 + || x > widget->allocation.width || y > widget->allocation.height) + return; + + item_num = e_icon_bar_find_item_at_position (icon_bar, x, y, NULL); + e_icon_bar_item_motion (icon_bar, item_num, NULL); +} + + +static gint +e_icon_bar_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + EIconBar *icon_bar; + gint item_num, before_item, scroll_x, scroll_y; + + g_return_val_if_fail (E_IS_ICON_BAR (widget), FALSE); + + icon_bar = E_ICON_BAR (widget); + + icon_bar->in_drag = TRUE; + + /* Check if the mouse is over or between items, and if so highlight. */ + gnome_canvas_get_scroll_offsets (GNOME_CANVAS (icon_bar), + &scroll_x, &scroll_y); + item_num = e_icon_bar_find_item_at_position (icon_bar, + x + scroll_x, + y + scroll_y, + &before_item); + e_icon_bar_item_motion (icon_bar, item_num, NULL); + e_icon_bar_set_dragging_before_item (icon_bar, before_item); + + /* Check if the mouse is at the top or bottom of the bar, and if it is + scroll up/down. */ + if (y < E_ICON_BAR_DRAG_AUTO_SCROLL_OFFSET) + icon_bar->scrolling_up = TRUE; + else if (y >= widget->allocation.height - E_ICON_BAR_DRAG_AUTO_SCROLL_OFFSET) + icon_bar->scrolling_up = FALSE; + else { + if (icon_bar->auto_scroll_timeout_id != 0) { + gtk_timeout_remove (icon_bar->auto_scroll_timeout_id); + icon_bar->auto_scroll_timeout_id = 0; + } + return FALSE; + } + + if (icon_bar->auto_scroll_timeout_id == 0) { + icon_bar->auto_scroll_timeout_id = g_timeout_add (E_ICON_BAR_SCROLL_TIMEOUT, e_icon_bar_timeout_handler, icon_bar); + icon_bar->auto_scroll_delay = E_ICON_BAR_SCROLL_DELAY; + } + + return FALSE; +} + + +static void +e_icon_bar_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time) +{ + EIconBar *icon_bar; + + g_return_if_fail (E_IS_ICON_BAR (widget)); + + icon_bar = E_ICON_BAR (widget); + + icon_bar->in_drag = FALSE; + + if (icon_bar->auto_scroll_timeout_id != 0) { + gtk_timeout_remove (icon_bar->auto_scroll_timeout_id); + icon_bar->auto_scroll_timeout_id = 0; + } + + if (icon_bar->mouse_over_item_num != -1) { + icon_bar->mouse_over_item_num = -1; + gtk_widget_queue_draw (GTK_WIDGET (icon_bar)); + } +} + + +static void +e_icon_bar_set_dragging_before_item (EIconBar *icon_bar, + gint before_item) +{ + if (icon_bar->dragging_before_item_num == before_item) + return; + + icon_bar->dragging_before_item_num = before_item; + + gtk_widget_queue_draw (GTK_WIDGET (icon_bar)); +} + + +static gboolean +e_icon_bar_timeout_handler (gpointer data) +{ + EIconBar *icon_bar; + gint scroll_x, scroll_y, new_scroll_y; + GtkAdjustment *adj; + + g_return_val_if_fail (E_IS_ICON_BAR (data), FALSE); + + icon_bar = E_ICON_BAR (data); + + GDK_THREADS_ENTER (); + + if (icon_bar->auto_scroll_delay > 0) { + icon_bar->auto_scroll_delay--; + GDK_THREADS_LEAVE (); + return TRUE; + } + + gnome_canvas_get_scroll_offsets (GNOME_CANVAS (icon_bar), + &scroll_x, &scroll_y); + + adj = GTK_LAYOUT (icon_bar)->vadjustment; + + if (icon_bar->scrolling_up) + new_scroll_y = MAX (scroll_y - adj->step_increment, 0); + else + new_scroll_y = MIN (scroll_y + adj->step_increment, + adj->upper - adj->page_size); + + if (new_scroll_y != scroll_y) + gnome_canvas_scroll_to (GNOME_CANVAS (icon_bar), + scroll_x, new_scroll_y); + + GDK_THREADS_LEAVE (); + return TRUE; +} diff --git a/widgets/shortcut-bar/e-icon-bar.h b/widgets/shortcut-bar/e-icon-bar.h new file mode 100644 index 0000000000..74b7507384 --- /dev/null +++ b/widgets/shortcut-bar/e-icon-bar.h @@ -0,0 +1,221 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ +#ifndef _E_ICON_BAR_H_ +#define _E_ICON_BAR_H_ + +#include <gdk_imlib.h> +#include <libgnomeui/gnome-canvas.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * EIconBar is a subclass of GnomeCanvas for displaying a vertical column of + * icons and descriptions. It provides 2 views - large icons and small icons. + */ + + +/* This contains information on one item. */ +typedef struct _EIconBarItem EIconBarItem; +struct _EIconBarItem +{ + GnomeCanvasItem *text; + GnomeCanvasItem *image; + + /* This is user data attached to the item, e.g. a URL. */ + gpointer data; + GtkDestroyNotify destroy; + + /* This is the height of the item. */ + gint item_height; + + /* This is the actual x, width and height of the text, rather than + the maximum allowed area. */ + gint text_x; + gint text_width; + gint text_height; + + gint icon_y, text_y; +}; + + +/* These are the view types. Defaults to LARGE_ICONS. */ +typedef enum +{ + E_ICON_BAR_LARGE_ICONS, + E_ICON_BAR_SMALL_ICONS +} EIconBarViewType; + + +#define E_ICON_BAR(obj) GTK_CHECK_CAST (obj, e_icon_bar_get_type (), EIconBar) +#define E_ICON_BAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, e_icon_bar_get_type (), EIconBarClass) +#define E_IS_ICON_BAR(obj) GTK_CHECK_TYPE (obj, e_icon_bar_get_type ()) + + +typedef struct _EIconBar EIconBar; +typedef struct _EIconBarClass EIconBarClass; + +struct _EIconBar +{ + GnomeCanvas canvas; + + /* This specifies if we are using large icons or small icons. */ + EIconBarViewType view_type; + + /* This is an array of EIconBarItem elements. */ + GArray *items; + + /* This is the index of the item which has been pressed, or -1. + It will be shown as pressed in while the mouse is over it. */ + gint pressed_item_num; + + /* This is the coordinates of where the button was pressed. If the + mouse moves a certain distance with the button still pressed, we + start a drag. */ + gint pressed_x; + gint pressed_y; + + /* This is the index of the item the mouse is currently over, or -1. + It will be highlighted unless one of the items is pressed. */ + gint mouse_over_item_num; + + /* This is the item that we are currently editing, or -1. */ + gint editing_item_num; + + /* This is the index of the item which is being dragged, or -1. + If the drag results in a move it will be deleted. */ + gint dragged_item_num; + + /* This is TRUE if we are dragging over this EIconBar. */ + gboolean in_drag; + + /* This is used in drag-and-drop to indicate the item which the mouse + is currently before, e.g. if it is 1 then a dropped item would be + inserted between items 0 and 1. It ranges from 0 to the number of + items, or is -1 when the mouse is not dragging between items. */ + gint dragging_before_item_num; + + /* These are the common positions of all the items in the EIconBar. */ + gint icon_x, icon_w, icon_h, text_x, text_w, spacing; + + /* This is the source id of our auto-scroll timeout handler, used when + in the middle of drag-and-drop operations. */ + gint auto_scroll_timeout_id; + gint auto_scroll_delay; + gboolean scrolling_up; +}; + +struct _EIconBarClass +{ + GnomeCanvasClass parent_class; + + void (*selected_item) (EIconBar *icon_bar, + GdkEvent *event, + gint item_num); + void (*dragged_item) (EIconBar *icon_bar, + GdkEvent *event, + gint item_num); +}; + + +GtkType e_icon_bar_get_type (void); +GtkWidget* e_icon_bar_new (void); + +/* Sets the view type. */ +void e_icon_bar_set_view_type (EIconBar *icon_bar, + EIconBarViewType view_type); + +/* Adds a new item to a group at the given position. If position is -1 it is + added at the end. It returns the index of the item. */ +gint e_icon_bar_add_item (EIconBar *icon_bar, + GdkImlibImage *image, + gchar *text, + gint position); + +/* Reorders an item. Note that position refers to the new position to add the + item after removing it from its current position. If position is -1 it is + moved to the end of the bar. */ +void e_icon_bar_reorder_item (EIconBar *icon_bar, + gint item_num, + gint new_position); +void e_icon_bar_remove_item (EIconBar *icon_bar, + gint item_num); + +GdkImlibImage* e_icon_bar_get_item_image (EIconBar *icon_bar, + gint item_num); +void e_icon_bar_set_item_image (EIconBar *icon_bar, + gint item_num, + GdkImlibImage *image); + +gchar* e_icon_bar_get_item_text (EIconBar *icon_bar, + gint item_num); +void e_icon_bar_set_item_text (EIconBar *icon_bar, + gint item_num, + gchar *text); + +gpointer e_icon_bar_get_item_data (EIconBar *icon_bar, + gint item_num); +void e_icon_bar_set_item_data (EIconBar *icon_bar, + gint item_num, + gpointer data); +void e_icon_bar_set_item_data_full (EIconBar *icon_bar, + gint item_num, + gpointer data, + GtkDestroyNotify destroy); + +void e_icon_bar_start_editing_item (EIconBar *icon_bar, + gint item_num); +void e_icon_bar_stop_editing_item (EIconBar *icon_bar, + gboolean accept); + + + +/* + * INTERNAL FUNCTIONS - for use by EIconBarBgItem. + */ + +/* This returns the index of the item at the given position on the EIconBar, + or -1 if no item is found. If before_item is not NULL, it returns the + item which the mouse is before, or -1 (this is used for dragging). */ +gint e_icon_bar_find_item_at_position (EIconBar *icon_bar, + gint x, + gint y, + gint *before_item); + +void e_icon_bar_item_pressed (EIconBar *icon_bar, + gint item_num, + GdkEvent *event); +void e_icon_bar_item_released (EIconBar *icon_bar, + gint item_num, + GdkEvent *event); +void e_icon_bar_item_motion (EIconBar *icon_bar, + gint item_num, + GdkEvent *event); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _E_ICON_BAR_H_ */ diff --git a/widgets/shortcut-bar/e-shortcut-bar.c b/widgets/shortcut-bar/e-shortcut-bar.c new file mode 100644 index 0000000000..7ad00feb78 --- /dev/null +++ b/widgets/shortcut-bar/e-shortcut-bar.c @@ -0,0 +1,563 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ + +/* + * ShortcutBar displays a vertical bar with a number of Groups, each of which + * contains any number of icons. It is used on the left of the main application + * window so users can easily access items such as folders and files. + */ + +#include <string.h> +#include <gnome.h> + +#include "e-shortcut-bar.h" +#include "e-clipped-label.h" +#include "e-vscrolled-bar.h" + +/* Drag and Drop stuff. */ +enum { + TARGET_SHORTCUT +}; +static GtkTargetEntry target_table[] = { + { "E-SHORTCUT", 0, TARGET_SHORTCUT } +}; +static guint n_targets = sizeof(target_table) / sizeof(target_table[0]); + +typedef struct _EShortcutBarBuiltinType EShortcutBarBuiltinType; +struct _EShortcutBarBuiltinType { + gchar *name; + gchar *filename; + GdkImlibImage *image; +}; + +EShortcutBarBuiltinType e_shortcut_bar_builtin_types[] = { + { "folder:", "gnome-word.png", NULL }, + { "calendar:", "gnome-calendar.png", NULL }, + { "todo:", "gnome-cromagnon.png", NULL }, + { "contacts:", "gnome-ccthemes.png", NULL } +}; +static gint e_shortcut_bar_num_builtin_types = sizeof (e_shortcut_bar_builtin_types) / sizeof (EShortcutBarBuiltinType); + +gboolean e_shortcut_bar_default_type_image_loaded = FALSE; +GdkImlibImage *e_shortcut_bar_default_type_image = NULL; +gchar *e_shortcut_bar_default_type_filename = "gnome-balsa2.png"; + +static void e_shortcut_bar_class_init (EShortcutBarClass *class); +static void e_shortcut_bar_init (EShortcutBar *shortcut_bar); +static void e_shortcut_bar_destroy (GtkObject *object); +static void e_shortcut_bar_set_canvas_style (EShortcutBar *shortcut_bar, + GtkWidget *canvas); +static void e_shortcut_bar_item_selected (EIconBar *icon_bar, + GdkEvent *event, + gint item_num, + EShortcutBar *shortcut_bar); +static void e_shortcut_bar_item_dragged (EIconBar *icon_bar, + GdkEvent *event, + gint item_num, + EShortcutBar *shortcut_bar); +static void e_shortcut_bar_on_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + EShortcutBar *shortcut_bar); +static void e_shortcut_bar_on_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *data, + guint info, + guint time, + EShortcutBar *shortcut_bar); +static void e_shortcut_bar_on_drag_data_delete (GtkWidget *widget, + GdkDragContext *context, + EShortcutBar *shortcut_bar); +static void e_shortcut_bar_stop_editing (GtkWidget *button, + EShortcutBar *shortcut_bar); +static GdkImlibImage* e_shortcut_bar_get_image_from_url (EShortcutBar *shortcut_bar, + gchar *item_url); +static GdkImlibImage* e_shortcut_bar_load_image (gchar *filename); + + +enum +{ + ITEM_SELECTED, + LAST_SIGNAL +}; + +static guint e_shortcut_bar_signals[LAST_SIGNAL] = {0}; + +static EGroupBarClass *parent_class; + + +GtkType +e_shortcut_bar_get_type (void) +{ + static GtkType e_shortcut_bar_type = 0; + + if (!e_shortcut_bar_type){ + GtkTypeInfo e_shortcut_bar_info = { + "EShortcutBar", + sizeof (EShortcutBar), + sizeof (EShortcutBarClass), + (GtkClassInitFunc) e_shortcut_bar_class_init, + (GtkObjectInitFunc) e_shortcut_bar_init, + NULL, /* reserved 1 */ + NULL, /* reserved 2 */ + (GtkClassInitFunc) NULL + }; + + parent_class = gtk_type_class (e_group_bar_get_type ()); + e_shortcut_bar_type = gtk_type_unique (e_group_bar_get_type (), + &e_shortcut_bar_info); + } + + return e_shortcut_bar_type; +} + + +static void +e_shortcut_bar_class_init (EShortcutBarClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass *) class; + widget_class = (GtkWidgetClass *) class; + + e_shortcut_bar_signals[ITEM_SELECTED] = + gtk_signal_new ("item_selected", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (EShortcutBarClass, + selected_item), + gtk_marshal_NONE__POINTER_INT_INT, + GTK_TYPE_NONE, 3, GTK_TYPE_GDK_EVENT, + GTK_TYPE_INT, GTK_TYPE_INT); + + gtk_object_class_add_signals (object_class, e_shortcut_bar_signals, + LAST_SIGNAL); + + /* Method override */ + object_class->destroy = e_shortcut_bar_destroy; +} + + +static void +e_shortcut_bar_init (EShortcutBar *shortcut_bar) +{ + shortcut_bar->groups = g_array_new (FALSE, FALSE, + sizeof (EShortcutBarGroup)); +} + + +GtkWidget * +e_shortcut_bar_new (void) +{ + GtkWidget *shortcut_bar; + + shortcut_bar = GTK_WIDGET (gtk_type_new (e_shortcut_bar_get_type ())); + + return shortcut_bar; +} + + +static void +e_shortcut_bar_destroy (GtkObject *object) +{ + EShortcutBar *shortcut_bar; + + shortcut_bar = E_SHORTCUT_BAR (object); + + GTK_OBJECT_CLASS (parent_class)->destroy (object); + + g_array_free (shortcut_bar->groups, TRUE); +} + + +gint +e_shortcut_bar_add_group (EShortcutBar *shortcut_bar, gchar *group_name) +{ + EShortcutBarGroup *group, tmp_group; + gint group_num; + GtkWidget *button, *label; + + g_return_val_if_fail (E_IS_SHORTCUT_BAR (shortcut_bar), -1); + g_return_val_if_fail (group_name != NULL, -1); + + group_num = shortcut_bar->groups->len; + g_array_append_val (shortcut_bar->groups, tmp_group); + + group = &g_array_index (shortcut_bar->groups, + EShortcutBarGroup, group_num); + + group->vscrolled_bar = e_vscrolled_bar_new (NULL); + gtk_widget_show (group->vscrolled_bar); + gtk_signal_connect (GTK_OBJECT (E_VSCROLLED_BAR (group->vscrolled_bar)->up_button), "pressed", GTK_SIGNAL_FUNC (e_shortcut_bar_stop_editing), shortcut_bar); + gtk_signal_connect (GTK_OBJECT (E_VSCROLLED_BAR (group->vscrolled_bar)->down_button), "pressed", GTK_SIGNAL_FUNC (e_shortcut_bar_stop_editing), shortcut_bar); + + group->icon_bar = e_icon_bar_new (); + gtk_widget_show (group->icon_bar); + gtk_container_add (GTK_CONTAINER (group->vscrolled_bar), + group->icon_bar); + gtk_signal_connect (GTK_OBJECT (group->icon_bar), "item_selected", + GTK_SIGNAL_FUNC (e_shortcut_bar_item_selected), + shortcut_bar); + gtk_signal_connect (GTK_OBJECT (group->icon_bar), "item_dragged", + GTK_SIGNAL_FUNC (e_shortcut_bar_item_dragged), + shortcut_bar); + gtk_signal_connect (GTK_OBJECT (group->icon_bar), "drag_data_get", + GTK_SIGNAL_FUNC (e_shortcut_bar_on_drag_data_get), + shortcut_bar); + gtk_signal_connect (GTK_OBJECT (group->icon_bar), "drag_data_received", + GTK_SIGNAL_FUNC (e_shortcut_bar_on_drag_data_received), + shortcut_bar); + gtk_signal_connect (GTK_OBJECT (group->icon_bar), "drag_data_delete", + GTK_SIGNAL_FUNC (e_shortcut_bar_on_drag_data_delete), + shortcut_bar); + + e_shortcut_bar_set_canvas_style (shortcut_bar, group->icon_bar); + + button = gtk_button_new (); + label = e_clipped_label_new (group_name); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (button), label); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (e_shortcut_bar_stop_editing), + shortcut_bar); + + gtk_drag_dest_set (GTK_WIDGET (group->icon_bar), + GTK_DEST_DEFAULT_ALL, + target_table, n_targets, + GDK_ACTION_COPY | GDK_ACTION_MOVE); + gtk_drag_dest_set (GTK_WIDGET (button), + GTK_DEST_DEFAULT_ALL, + target_table, n_targets, + GDK_ACTION_COPY | GDK_ACTION_MOVE); + + e_group_bar_add_group (E_GROUP_BAR (shortcut_bar), + group->vscrolled_bar, button, -1); + + + return group_num; +} + + +void +e_shortcut_bar_remove_group (EShortcutBar *shortcut_bar, + gint group_num) +{ + e_group_bar_remove_group (E_GROUP_BAR (shortcut_bar), group_num); + g_array_remove_index (shortcut_bar->groups, group_num); +} + + +gint +e_shortcut_bar_add_item (EShortcutBar *shortcut_bar, gint group_num, + gchar *item_url, gchar *item_name) +{ + EShortcutBarGroup *group; + GdkImlibImage *image; + gint item_num; + + g_return_val_if_fail (E_IS_SHORTCUT_BAR (shortcut_bar), -1); + g_return_val_if_fail (group_num >= 0, -1); + g_return_val_if_fail (group_num < shortcut_bar->groups->len, -1); + g_return_val_if_fail (item_url != NULL, -1); + g_return_val_if_fail (item_name != NULL, -1); + + image = e_shortcut_bar_get_image_from_url (shortcut_bar, item_url); + + group = &g_array_index (shortcut_bar->groups, + EShortcutBarGroup, group_num); + + item_num = e_icon_bar_add_item (E_ICON_BAR (group->icon_bar), + image, item_name, -1); + e_icon_bar_set_item_data_full (E_ICON_BAR (group->icon_bar), item_num, + g_strdup (item_url), g_free); + return item_num; +} + + +void +e_shortcut_bar_remove_item (EShortcutBar *shortcut_bar, + gint group_num, + gint item_num) +{ + EShortcutBarGroup *group; + + g_return_if_fail (E_IS_SHORTCUT_BAR (shortcut_bar)); + g_return_if_fail (group_num >= 0); + g_return_if_fail (group_num < shortcut_bar->groups->len); + + group = &g_array_index (shortcut_bar->groups, + EShortcutBarGroup, group_num); + + e_icon_bar_remove_item (E_ICON_BAR (group->icon_bar), item_num); +} + + +static void +e_shortcut_bar_set_canvas_style (EShortcutBar *shortcut_bar, + GtkWidget *canvas) +{ + GtkRcStyle *rc_style; + + rc_style = gtk_rc_style_new (); + + rc_style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG | GTK_RC_BG; + rc_style->fg[GTK_STATE_NORMAL].red = 65535; + rc_style->fg[GTK_STATE_NORMAL].green = 65535; + rc_style->fg[GTK_STATE_NORMAL].blue = 65535; + + rc_style->bg[GTK_STATE_NORMAL].red = 32512; + rc_style->bg[GTK_STATE_NORMAL].green = 32512; + rc_style->bg[GTK_STATE_NORMAL].blue = 32512; + + gtk_widget_modify_style (GTK_WIDGET (canvas), rc_style); + gtk_rc_style_unref (rc_style); +} + + +void +e_shortcut_bar_set_view_type (EShortcutBar *shortcut_bar, + gint group_num, + EIconBarViewType view_type) +{ + EShortcutBarGroup *group; + + g_return_if_fail (E_IS_SHORTCUT_BAR (shortcut_bar)); + g_return_if_fail (group_num >= 0); + g_return_if_fail (group_num < shortcut_bar->groups->len); + + group = &g_array_index (shortcut_bar->groups, + EShortcutBarGroup, group_num); + + e_icon_bar_set_view_type (E_ICON_BAR (group->icon_bar), view_type); +} + + +static void +e_shortcut_bar_item_selected (EIconBar *icon_bar, + GdkEvent *event, + gint item_num, + EShortcutBar *shortcut_bar) +{ + gint group_num; + + group_num = e_group_bar_get_group_num (E_GROUP_BAR (shortcut_bar), + GTK_WIDGET (icon_bar)->parent); + + gtk_signal_emit (GTK_OBJECT (shortcut_bar), + e_shortcut_bar_signals[ITEM_SELECTED], + event, group_num, item_num); +} + + +static void +e_shortcut_bar_item_dragged (EIconBar *icon_bar, + GdkEvent *event, + gint item_num, + EShortcutBar *shortcut_bar) +{ + GtkTargetList *target_list; + gint group_num; + + group_num = e_group_bar_get_group_num (E_GROUP_BAR (shortcut_bar), + GTK_WIDGET (icon_bar)->parent); + + /* FIXME: free somewhere - drag_end? */ + shortcut_bar->dragged_url = g_strdup (e_icon_bar_get_item_data (icon_bar, item_num)); + shortcut_bar->dragged_name = g_strdup (e_icon_bar_get_item_text (icon_bar, item_num)); + + target_list = gtk_target_list_new (target_table, n_targets); + gtk_drag_begin (GTK_WIDGET (icon_bar), target_list, + GDK_ACTION_COPY | GDK_ACTION_MOVE, + 1, event); + gtk_target_list_unref (target_list); +} + + +static void +e_shortcut_bar_on_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + EShortcutBar *shortcut_bar) +{ + gchar *data; + + if (info == TARGET_SHORTCUT) { + data = g_strdup_printf ("%s%c%s", shortcut_bar->dragged_name, + '\0', shortcut_bar->dragged_url); + gtk_selection_data_set (selection_data, selection_data->target, + 8, data, + strlen (shortcut_bar->dragged_name) + + strlen (shortcut_bar->dragged_url) + + 2); + g_free (data); + } +} + + +static void +e_shortcut_bar_on_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *data, + guint info, + guint time, + EShortcutBar *shortcut_bar) +{ + EShortcutBarGroup *group; + gchar *item_name, *item_url; + EIconBar *icon_bar; + GdkImlibImage *image; + gint group_num, item_num; + + icon_bar = E_ICON_BAR (widget); + + if ((data->length >= 0) && (data->format == 8) + && icon_bar->dragging_before_item_num != -1) { + item_name = data->data; + item_url = item_name + strlen (item_name) + 1; + + image = e_shortcut_bar_get_image_from_url (shortcut_bar, + item_url); + + group_num = e_group_bar_get_group_num (E_GROUP_BAR (shortcut_bar), + GTK_WIDGET (icon_bar)->parent); + group = &g_array_index (shortcut_bar->groups, + EShortcutBarGroup, group_num); + + item_num = e_icon_bar_add_item (E_ICON_BAR (group->icon_bar), image, item_name, icon_bar->dragging_before_item_num); + e_icon_bar_set_item_data_full (E_ICON_BAR (group->icon_bar), + item_num, g_strdup (item_url), + g_free); + + gtk_drag_finish (context, TRUE, TRUE, time); + return; + } + + gtk_drag_finish (context, FALSE, FALSE, time); +} + + +static void +e_shortcut_bar_on_drag_data_delete (GtkWidget *widget, + GdkDragContext *context, + EShortcutBar *shortcut_bar) +{ + EIconBar *icon_bar; + + icon_bar = E_ICON_BAR (widget); + + e_icon_bar_remove_item (icon_bar, icon_bar->dragged_item_num); +} + + +void +e_shortcut_bar_start_editing_item (EShortcutBar *shortcut_bar, + gint group_num, + gint item_num) +{ + EShortcutBarGroup *group; + + g_return_if_fail (E_IS_SHORTCUT_BAR (shortcut_bar)); + g_return_if_fail (group_num >= 0); + g_return_if_fail (group_num < shortcut_bar->groups->len); + + group = &g_array_index (shortcut_bar->groups, + EShortcutBarGroup, group_num); + + e_icon_bar_start_editing_item (E_ICON_BAR (group->icon_bar), item_num); +} + + +/* We stop editing any item when a scroll button is pressed. */ +static void +e_shortcut_bar_stop_editing (GtkWidget *button, + EShortcutBar *shortcut_bar) +{ + EShortcutBarGroup *group; + gint group_num; + + for (group_num = 0; + group_num < shortcut_bar->groups->len; + group_num++) { + group = &g_array_index (shortcut_bar->groups, + EShortcutBarGroup, group_num); + e_icon_bar_stop_editing_item (E_ICON_BAR (group->icon_bar), + TRUE); + } +} + + +static GdkImlibImage* +e_shortcut_bar_get_image_from_url (EShortcutBar *shortcut_bar, + gchar *item_url) +{ + gchar *method_terminator; + gint method_len, i; + + method_terminator = strchr (item_url, ':'); + if (method_terminator) { + method_len = method_terminator - item_url + 1; + + /* Check if it is a builtin type. */ + for (i = 0; i < e_shortcut_bar_num_builtin_types; i++) { + if (!strncmp (item_url, e_shortcut_bar_builtin_types[i].name, method_len)) { + if (!e_shortcut_bar_builtin_types[i].image) + e_shortcut_bar_builtin_types[i].image = e_shortcut_bar_load_image (e_shortcut_bar_builtin_types[i].filename); + return e_shortcut_bar_builtin_types[i].image; + } + } + } + + if (!e_shortcut_bar_default_type_image_loaded) { + e_shortcut_bar_default_type_image_loaded = TRUE; + e_shortcut_bar_default_type_image = e_shortcut_bar_load_image (e_shortcut_bar_default_type_filename); + } + return e_shortcut_bar_default_type_image; +} + + +static GdkImlibImage* +e_shortcut_bar_load_image (gchar *filename) +{ + gchar *pathname; + GdkImlibImage *image = NULL; + + pathname = gnome_pixmap_file (filename); + if (pathname) + image = gdk_imlib_load_image (pathname); + else + g_warning ("Couldn't find pixmap: %s", filename); + + return image; +} diff --git a/widgets/shortcut-bar/e-shortcut-bar.h b/widgets/shortcut-bar/e-shortcut-bar.h new file mode 100644 index 0000000000..1bbdfb6754 --- /dev/null +++ b/widgets/shortcut-bar/e-shortcut-bar.h @@ -0,0 +1,114 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ +#ifndef _E_SHORTCUT_BAR_H_ +#define _E_SHORTCUT_BAR_H_ + +#include "e-group-bar.h" +#include "e-icon-bar.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * EShortcutBar displays a vertical bar with a number of Groups, each of which + * contains any number of icons. It is used on the left of the main application + * window so users can easily access items such as folders and files. + */ + + +/* This contains information on one group. */ +typedef struct _EShortcutBarGroup EShortcutBarGroup; +struct _EShortcutBarGroup +{ + /* This is the EVScrolledBar which scrolls the group. */ + GtkWidget *vscrolled_bar; + + /* This is the icon bar containing the child items. */ + GtkWidget *icon_bar; +}; + + +#define E_SHORTCUT_BAR(obj) GTK_CHECK_CAST (obj, e_shortcut_bar_get_type (), EShortcutBar) +#define E_SHORTCUT_BAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, e_shortcut_bar_get_type (), EShortcutBarClass) +#define E_IS_SHORTCUT_BAR(obj) GTK_CHECK_TYPE (obj, e_shortcut_bar_get_type ()) + + +typedef struct _EShortcutBar EShortcutBar; +typedef struct _EShortcutBarClass EShortcutBarClass; + +struct _EShortcutBar +{ + EGroupBar group_bar; + + /* This is an array of EShortcutBarGroup elements. */ + GArray *groups; + + gchar *dragged_url; + gchar *dragged_name; +}; + +struct _EShortcutBarClass +{ + EGroupBarClass parent_class; + + void (*selected_item) (EShortcutBar *shortcut_bar, + GdkEvent *event, + gint group_num, + gint item_num); +}; + + +GtkType e_shortcut_bar_get_type (void); +GtkWidget* e_shortcut_bar_new (void); + +/* Adds a new group, returning the index. */ +gint e_shortcut_bar_add_group (EShortcutBar *shortcut_bar, + gchar *group_name); +void e_shortcut_bar_remove_group (EShortcutBar *shortcut_bar, + gint group_num); + +/* Sets the view type for the group. */ +void e_shortcut_bar_set_view_type (EShortcutBar *shortcut_bar, + gint group_num, + EIconBarViewType view_type); + +/* Adds a new item to a group, returning the index within the group. */ +gint e_shortcut_bar_add_item (EShortcutBar *shortcut_bar, + gint group_num, + gchar *item_url, + gchar *item_name); + +void e_shortcut_bar_start_editing_item (EShortcutBar *shortcut_bar, + gint group_num, + gint item_num); +void e_shortcut_bar_remove_item (EShortcutBar *shortcut_bar, + gint group_num, + gint item_num); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _E_SHORTCUT_BAR_H_ */ diff --git a/widgets/shortcut-bar/e-vscrolled-bar.c b/widgets/shortcut-bar/e-vscrolled-bar.c new file mode 100644 index 0000000000..5d5f0ab2e2 --- /dev/null +++ b/widgets/shortcut-bar/e-vscrolled-bar.c @@ -0,0 +1,652 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ + +/* + * EVScrolledBar is like GtkScrolledWindow but only scrolls the child widget + * vertically. It is intended for scrolling narrow vertical bars. + */ + +#include <gtk/gtkarrow.h> +#include <gtk/gtkbutton.h> +#include <gtk/gtksignal.h> + +#include "e-vscrolled-bar.h" + +/* These are the offsets of the up & down buttons from the right and top/bottom + of the widget. */ +#define E_VSCROLLED_BAR_BUTTON_X_OFFSET 2 +#define E_VSCROLLED_BAR_BUTTON_Y_OFFSET 2 + +/* This is the time between scrolls. */ +#define E_VSCROLLED_BAR_SCROLL_TIMEOUT 20 + +static void e_vscrolled_bar_class_init (EVScrolledBarClass *class); +static void e_vscrolled_bar_init (EVScrolledBar *vscrolled_bar); +static void e_vscrolled_bar_destroy (GtkObject *object); +static void e_vscrolled_bar_finalize (GtkObject *object); +static void e_vscrolled_bar_map (GtkWidget *widget); +static void e_vscrolled_bar_unmap (GtkWidget *widget); +static void e_vscrolled_bar_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void e_vscrolled_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void e_vscrolled_bar_draw (GtkWidget *widget, + GdkRectangle *area); +static void e_vscrolled_bar_add (GtkContainer *container, + GtkWidget *child); +static void e_vscrolled_bar_remove (GtkContainer *container, + GtkWidget *child); +static void e_vscrolled_bar_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static void e_vscrolled_bar_adjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void e_vscrolled_bar_button_pressed (GtkWidget *button, + EVScrolledBar *vscrolled_bar); +static void e_vscrolled_bar_button_released (GtkWidget *button, + EVScrolledBar *vscrolled_bar); +static void e_vscrolled_bar_button_clicked (GtkWidget *button, + EVScrolledBar *vscrolled_bar); +static gboolean e_vscrolled_bar_timeout_handler (gpointer data); + + +static GtkBinClass *parent_class; + + +GtkType +e_vscrolled_bar_get_type (void) +{ + static GtkType e_vscrolled_bar_type = 0; + + if (!e_vscrolled_bar_type) { + GtkTypeInfo e_vscrolled_bar_info = { + "EVScrolledBar", + sizeof (EVScrolledBar), + sizeof (EVScrolledBarClass), + (GtkClassInitFunc) e_vscrolled_bar_class_init, + (GtkObjectInitFunc) e_vscrolled_bar_init, + NULL, /* reserved 1 */ + NULL, /* reserved 2 */ + (GtkClassInitFunc) NULL + }; + + parent_class = gtk_type_class (GTK_TYPE_BIN); + e_vscrolled_bar_type = gtk_type_unique (GTK_TYPE_BIN, + &e_vscrolled_bar_info); + } + + return e_vscrolled_bar_type; +} + + +static void +e_vscrolled_bar_class_init (EVScrolledBarClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass *) class; + widget_class = (GtkWidgetClass *) class; + container_class = (GtkContainerClass *) class; + + /* Method override */ + object_class->destroy = e_vscrolled_bar_destroy; + object_class->finalize = e_vscrolled_bar_finalize; + + widget_class->map = e_vscrolled_bar_map; + widget_class->unmap = e_vscrolled_bar_unmap; + widget_class->size_request = e_vscrolled_bar_size_request; + widget_class->size_allocate = e_vscrolled_bar_size_allocate; + widget_class->draw = e_vscrolled_bar_draw; + + container_class->add = e_vscrolled_bar_add; + container_class->remove = e_vscrolled_bar_remove; + container_class->forall = e_vscrolled_bar_forall; +} + + +static void +e_vscrolled_bar_init (EVScrolledBar *vscrolled_bar) +{ + GtkWidget *arrow; + + GTK_WIDGET_SET_FLAGS (vscrolled_bar, GTK_NO_WINDOW); + + gtk_container_set_resize_mode (GTK_CONTAINER (vscrolled_bar), + GTK_RESIZE_QUEUE); + + gtk_widget_push_composite_child (); + + vscrolled_bar->up_button = gtk_button_new (); + gtk_widget_set_composite_name (vscrolled_bar->up_button, + "up_button"); + gtk_widget_set_parent (vscrolled_bar->up_button, + GTK_WIDGET (vscrolled_bar)); + arrow = gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_OUT); + gtk_misc_set_padding (GTK_MISC (arrow), 1, 1); + gtk_widget_show (arrow); + gtk_container_add (GTK_CONTAINER (vscrolled_bar->up_button), arrow); + gtk_signal_connect_after (GTK_OBJECT (vscrolled_bar->up_button), "pressed", GTK_SIGNAL_FUNC (e_vscrolled_bar_button_pressed), vscrolled_bar); + gtk_signal_connect_after (GTK_OBJECT (vscrolled_bar->up_button), "released", GTK_SIGNAL_FUNC (e_vscrolled_bar_button_released), vscrolled_bar); + gtk_signal_connect (GTK_OBJECT (vscrolled_bar->up_button), "clicked", GTK_SIGNAL_FUNC (e_vscrolled_bar_button_clicked), vscrolled_bar); + + vscrolled_bar->down_button = gtk_button_new (); + gtk_widget_set_composite_name (vscrolled_bar->up_button, + "down_button"); + gtk_widget_set_parent (vscrolled_bar->down_button, + GTK_WIDGET (vscrolled_bar)); + arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_misc_set_padding (GTK_MISC (arrow), 1, 1); + gtk_widget_show (arrow); + gtk_container_add (GTK_CONTAINER (vscrolled_bar->down_button), arrow); + gtk_signal_connect_after (GTK_OBJECT (vscrolled_bar->down_button), "pressed", GTK_SIGNAL_FUNC (e_vscrolled_bar_button_pressed), vscrolled_bar); + gtk_signal_connect_after (GTK_OBJECT (vscrolled_bar->down_button), "released", GTK_SIGNAL_FUNC (e_vscrolled_bar_button_released), vscrolled_bar); + gtk_signal_connect (GTK_OBJECT (vscrolled_bar->down_button), "clicked", GTK_SIGNAL_FUNC (e_vscrolled_bar_button_clicked), vscrolled_bar); + + gtk_widget_pop_composite_child (); + + vscrolled_bar->adjustment = NULL; + vscrolled_bar->timeout_id = 0; + vscrolled_bar->scrolling_up = FALSE; + vscrolled_bar->min_distance = -1.0; + vscrolled_bar->button_pressed = FALSE; +} + + +/** + * e_vscrolled_bar_new: + * + * @adjustment: The #GtkAdjustment to use for scrolling, or NULL. + * @Return: A new #EVScrolledBar. + * + * Creates a new #EVScrolledBar with the given adjustment. + **/ +GtkWidget * +e_vscrolled_bar_new (GtkAdjustment *adjustment) +{ + GtkWidget *vscrolled_bar; + + vscrolled_bar = GTK_WIDGET (gtk_type_new (e_vscrolled_bar_get_type ())); + e_vscrolled_bar_set_adjustment (E_VSCROLLED_BAR (vscrolled_bar), + adjustment); + + return vscrolled_bar; +} + + +static void +e_vscrolled_bar_destroy (GtkObject *object) +{ + EVScrolledBar *vscrolled_bar; + + vscrolled_bar = E_VSCROLLED_BAR (object); + + if (vscrolled_bar->timeout_id) { + g_source_remove (vscrolled_bar->timeout_id); + vscrolled_bar->timeout_id = 0; + } + + gtk_widget_unparent (vscrolled_bar->up_button); + gtk_widget_unparent (vscrolled_bar->down_button); + + GTK_OBJECT_CLASS (parent_class)->destroy (object); +} + + +static void +e_vscrolled_bar_finalize (GtkObject *object) +{ + EVScrolledBar *vscrolled_bar; + + vscrolled_bar = E_VSCROLLED_BAR (object); + + gtk_object_unref (GTK_OBJECT (vscrolled_bar->adjustment)); + + GTK_OBJECT_CLASS (parent_class)->finalize (object); +} + + +static void +e_vscrolled_bar_map (GtkWidget *widget) +{ + EVScrolledBar *vscrolled_bar; + + g_return_if_fail (widget != NULL); + g_return_if_fail (E_IS_VSCROLLED_BAR (widget)); + + vscrolled_bar = E_VSCROLLED_BAR (widget); + + /* chain parent class handler to map self and child */ + GTK_WIDGET_CLASS (parent_class)->map (widget); + + if (GTK_WIDGET_VISIBLE (vscrolled_bar->up_button) && + !GTK_WIDGET_MAPPED (vscrolled_bar->up_button)) + gtk_widget_map (vscrolled_bar->up_button); + + if (GTK_WIDGET_VISIBLE (vscrolled_bar->down_button) && + !GTK_WIDGET_MAPPED (vscrolled_bar->down_button)) + gtk_widget_map (vscrolled_bar->down_button); +} + + +static void +e_vscrolled_bar_unmap (GtkWidget *widget) +{ + EVScrolledBar *vscrolled_bar; + + g_return_if_fail (widget != NULL); + g_return_if_fail (E_IS_VSCROLLED_BAR (widget)); + + vscrolled_bar = E_VSCROLLED_BAR (widget); + + /* chain parent class handler to unmap self and child */ + GTK_WIDGET_CLASS (parent_class)->unmap (widget); + + if (GTK_WIDGET_MAPPED (vscrolled_bar->up_button)) + gtk_widget_unmap (vscrolled_bar->up_button); + + if (GTK_WIDGET_MAPPED (vscrolled_bar->down_button)) + gtk_widget_unmap (vscrolled_bar->down_button); +} + + +static void +e_vscrolled_bar_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + EVScrolledBar *vscrolled_bar; + GtkBin *bin; + GtkRequisition child_requisition; + + g_return_if_fail (widget != NULL); + g_return_if_fail (E_IS_VSCROLLED_BAR (widget)); + g_return_if_fail (requisition != NULL); + + vscrolled_bar = E_VSCROLLED_BAR (widget); + bin = GTK_BIN (widget); + + requisition->width = 0; + requisition->height = 0; + + /* We just return the requisition of the child widget, plus the + border width. */ + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) { + gtk_widget_size_request (bin->child, &child_requisition); + *requisition = child_requisition; + } + + /* We remember the requested heights of the up & down buttons. */ + gtk_widget_size_request (vscrolled_bar->up_button, + &child_requisition); + vscrolled_bar->up_button_width = child_requisition.width; + vscrolled_bar->up_button_height = child_requisition.height; + + gtk_widget_size_request (vscrolled_bar->down_button, + &child_requisition); + vscrolled_bar->down_button_width = child_requisition.width; + vscrolled_bar->down_button_height = child_requisition.height; + + /* Add on the standard container border widths. */ + requisition->width += GTK_CONTAINER (widget)->border_width * 2; + requisition->height += GTK_CONTAINER (widget)->border_width * 2; +} + + +static void +e_vscrolled_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + EVScrolledBar *vscrolled_bar; + GtkBin *bin; + GtkAllocation button_allocation, child_allocation; + gint border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (E_IS_VSCROLLED_BAR (widget)); + g_return_if_fail (allocation != NULL); + + vscrolled_bar = E_VSCROLLED_BAR (widget); + bin = GTK_BIN (widget); + + widget->allocation = *allocation; + + border_width = GTK_CONTAINER (widget)->border_width; + + child_allocation.x = border_width; + child_allocation.y = border_width; + child_allocation.width = allocation->width - 2 * border_width; + child_allocation.height = allocation->height - 2 * border_width; + gtk_widget_size_allocate (bin->child, &child_allocation); + + button_allocation.x = allocation->width - border_width + - vscrolled_bar->up_button_width + - E_VSCROLLED_BAR_BUTTON_X_OFFSET; + button_allocation.y = border_width + E_VSCROLLED_BAR_BUTTON_Y_OFFSET; + button_allocation.width = vscrolled_bar->up_button_width; + button_allocation.height = vscrolled_bar->up_button_height; + gtk_widget_size_allocate (vscrolled_bar->up_button, + &button_allocation); + + button_allocation.x = allocation->width - border_width + - vscrolled_bar->down_button_width + - E_VSCROLLED_BAR_BUTTON_X_OFFSET; + button_allocation.y = allocation->height - border_width + - vscrolled_bar->down_button_height + - E_VSCROLLED_BAR_BUTTON_Y_OFFSET; + button_allocation.width = vscrolled_bar->down_button_width; + button_allocation.height = vscrolled_bar->down_button_height; + gtk_widget_size_allocate (vscrolled_bar->down_button, + &button_allocation); +} + + +static void +e_vscrolled_bar_draw (GtkWidget *widget, + GdkRectangle *area) +{ + EVScrolledBar *vscrolled_bar; + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (E_IS_VSCROLLED_BAR (widget)); + g_return_if_fail (area != NULL); + + vscrolled_bar = E_VSCROLLED_BAR (widget); + bin = GTK_BIN (widget); + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child) && + gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + + if (GTK_WIDGET_VISIBLE (vscrolled_bar->up_button) && + gtk_widget_intersect (vscrolled_bar->up_button, area, &child_area)) + gtk_widget_draw (vscrolled_bar->up_button, &child_area); + + if (GTK_WIDGET_VISIBLE (vscrolled_bar->down_button) && + gtk_widget_intersect (vscrolled_bar->down_button, area, &child_area)) + gtk_widget_draw (vscrolled_bar->down_button, &child_area); +} + + +static void +e_vscrolled_bar_add (GtkContainer *container, + GtkWidget *child) +{ + EVScrolledBar *vscrolled_bar; + GtkBin *bin; + + g_return_if_fail (container != NULL); + g_return_if_fail (E_IS_VSCROLLED_BAR (container)); + + vscrolled_bar = E_VSCROLLED_BAR (container); + bin = GTK_BIN (container); + + g_return_if_fail (bin->child == NULL); + + bin->child = child; + gtk_widget_set_parent (child, GTK_WIDGET (bin)); + + gtk_widget_set_scroll_adjustments (child, NULL, + vscrolled_bar->adjustment); + + if (GTK_WIDGET_REALIZED (child->parent)) + gtk_widget_realize (child); + + if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child)) { + if (GTK_WIDGET_MAPPED (child->parent)) + gtk_widget_map (child); + + gtk_widget_queue_resize (child); + } +} + + +static void +e_vscrolled_bar_remove (GtkContainer *container, + GtkWidget *child) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (E_IS_VSCROLLED_BAR (container)); + g_return_if_fail (child != NULL); + g_return_if_fail (GTK_BIN (container)->child == child); + + gtk_widget_set_scroll_adjustments (child, NULL, NULL); + + /* chain parent class handler to remove child */ + GTK_CONTAINER_CLASS (parent_class)->remove (container, child); +} + + +static void +e_vscrolled_bar_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (E_IS_VSCROLLED_BAR (container)); + g_return_if_fail (callback != NULL); + + GTK_CONTAINER_CLASS (parent_class)->forall (container, + include_internals, + callback, + callback_data); + if (include_internals) { + EVScrolledBar *vscrolled_bar; + + vscrolled_bar = E_VSCROLLED_BAR (container); + + if (vscrolled_bar->up_button) + callback (vscrolled_bar->up_button, callback_data); + if (vscrolled_bar->down_button) + callback (vscrolled_bar->down_button, callback_data); + } +} + + +/** + * e_vscrolled_bar_get_adjustment: + * + * @vscrolled_bar: An #EVScrolledBar. + * @Return: The #GtkAdjustment used for scrolling @vscrolled_bar. + * + * Returns the #GtkAdjustment used for scrolling the #EVscrolledBar. + **/ +GtkAdjustment* +e_vscrolled_bar_get_adjustment (EVScrolledBar *vscrolled_bar) +{ + g_return_val_if_fail (vscrolled_bar != NULL, NULL); + g_return_val_if_fail (E_IS_VSCROLLED_BAR (vscrolled_bar), NULL); + + return vscrolled_bar->adjustment; +} + + +/** + * e_vscrolled_bar_set_adjustment: + * + * @vscrolled_bar: An #EVScrolledBar. + * @adjustment: The #GtkAdjustment to use for scrolling @vscrolled_bar. + * + * Sets the #GtkAdjustment to use for scrolling the #EVscrolledBar. + **/ +void +e_vscrolled_bar_set_adjustment (EVScrolledBar *vscrolled_bar, + GtkAdjustment *adjustment) +{ + g_return_if_fail (vscrolled_bar != NULL); + g_return_if_fail (E_IS_VSCROLLED_BAR (vscrolled_bar)); + + if (adjustment) + g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); + else + adjustment = (GtkAdjustment*) gtk_object_new (GTK_TYPE_ADJUSTMENT, NULL); + + if (vscrolled_bar->adjustment == adjustment) + return; + + if (vscrolled_bar->adjustment) { + gtk_signal_disconnect_by_func (GTK_OBJECT (vscrolled_bar->adjustment), + GTK_SIGNAL_FUNC (e_vscrolled_bar_adjustment_changed), + vscrolled_bar); + gtk_object_unref (GTK_OBJECT (vscrolled_bar->adjustment)); + } + + vscrolled_bar->adjustment = adjustment; + gtk_object_ref (GTK_OBJECT (vscrolled_bar->adjustment)); + gtk_object_sink (GTK_OBJECT (vscrolled_bar->adjustment)); + + /* I've used connect_after here to avoid a problem when using a + GnomeCanvas as the child widget. When just using connect it would + leave a blank space when one of the buttons is hidden. We want + the GtkLayout to handle the scrolling before we hide any buttons. */ + gtk_signal_connect_after (GTK_OBJECT (adjustment), "changed", + GTK_SIGNAL_FUNC (e_vscrolled_bar_adjustment_changed), + vscrolled_bar); + gtk_signal_connect_after (GTK_OBJECT (adjustment), "value_changed", + GTK_SIGNAL_FUNC (e_vscrolled_bar_adjustment_changed), + vscrolled_bar); + + e_vscrolled_bar_adjustment_changed (adjustment, vscrolled_bar); + + if (GTK_BIN (vscrolled_bar)->child) + gtk_widget_set_scroll_adjustments (GTK_BIN (vscrolled_bar)->child, NULL, adjustment); +} + + +static void +e_vscrolled_bar_adjustment_changed (GtkAdjustment *adjustment, + gpointer data) +{ + EVScrolledBar *vscrolled_bar; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + vscrolled_bar = E_VSCROLLED_BAR (data); + + /* If the adjustment value is not 0, show the up button. */ + if (adjustment->value != 0) + gtk_widget_show (vscrolled_bar->up_button); + else + gtk_widget_hide (vscrolled_bar->up_button); + + /* If the adjustment value is less than the maximum value, show the + down button. */ + if (adjustment->value < adjustment->upper - adjustment->page_size) + gtk_widget_show (vscrolled_bar->down_button); + else + gtk_widget_hide (vscrolled_bar->down_button); +} + + +static void +e_vscrolled_bar_button_pressed (GtkWidget *button, + EVScrolledBar *vscrolled_bar) +{ + if (vscrolled_bar->timeout_id != 0) + g_source_remove (vscrolled_bar->timeout_id); + + vscrolled_bar->timeout_id = g_timeout_add (E_VSCROLLED_BAR_SCROLL_TIMEOUT, e_vscrolled_bar_timeout_handler, vscrolled_bar); + vscrolled_bar->scrolling_up = (button == vscrolled_bar->up_button) ? TRUE : FALSE; + vscrolled_bar->min_distance = vscrolled_bar->adjustment->page_size / 4; + vscrolled_bar->button_pressed = TRUE; + + e_vscrolled_bar_timeout_handler (vscrolled_bar); +} + + +static void +e_vscrolled_bar_button_released (GtkWidget *button, + EVScrolledBar *vscrolled_bar) +{ + vscrolled_bar->button_pressed = FALSE; +} + + +/* This will be called when the user hits the space key to activate the button. + It will also be called just before button_released() is called, but since + we already handle that we simply return if the button is pressed. */ +static void +e_vscrolled_bar_button_clicked (GtkWidget *button, + EVScrolledBar *vscrolled_bar) +{ + if (vscrolled_bar->button_pressed) + return; + + /* We act as if the button is pressed and released immediately. */ + e_vscrolled_bar_button_pressed (button, vscrolled_bar); + vscrolled_bar->button_pressed = FALSE; +} + + +static gboolean +e_vscrolled_bar_timeout_handler (gpointer data) +{ + EVScrolledBar *vscrolled_bar; + GtkAdjustment *adjustment; + gfloat new_value; + gboolean retval = TRUE; + + vscrolled_bar = E_VSCROLLED_BAR (data); + adjustment = vscrolled_bar->adjustment; + + GDK_THREADS_ENTER (); + + /* Check if the user has released the button and we have already + scrolled the minimum distance. */ + if (vscrolled_bar->button_pressed == FALSE + && vscrolled_bar->min_distance <= 0) { + GDK_THREADS_LEAVE (); + return FALSE; + } + + vscrolled_bar->min_distance -= adjustment->step_increment; + + if (vscrolled_bar->scrolling_up) { + new_value = adjustment->value - adjustment->step_increment; + if (new_value <= adjustment->lower) { + new_value = adjustment->lower; + retval = FALSE; + } + } else { + new_value = adjustment->value + adjustment->step_increment; + if (new_value >= adjustment->upper - adjustment->page_size) { + new_value = adjustment->upper - adjustment->page_size; + retval = FALSE; + } + } + + if (adjustment->value != new_value) { + adjustment->value = new_value; + gtk_signal_emit_by_name (GTK_OBJECT (adjustment), + "value_changed"); + } + + GDK_THREADS_LEAVE (); + return retval; +} diff --git a/widgets/shortcut-bar/e-vscrolled-bar.h b/widgets/shortcut-bar/e-vscrolled-bar.h new file mode 100644 index 0000000000..d3273e6685 --- /dev/null +++ b/widgets/shortcut-bar/e-vscrolled-bar.h @@ -0,0 +1,97 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ +#ifndef _E_VSCROLLED_BAR_H_ +#define _E_VSCROLLED_BAR_H_ + +#include <gtk/gtkbin.h> +#include <gtk/gtkadjustment.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * EVScrolledBar is like GtkScrolledWindow but only scrolls the child widget + * vertically. It is intended for scrolling narrow vertical bars. + */ + + +#define E_VSCROLLED_BAR(obj) GTK_CHECK_CAST (obj, e_vscrolled_bar_get_type (), EVScrolledBar) +#define E_VSCROLLED_BAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, e_vscrolled_bar_get_type (), EVScrolledBarClass) +#define E_IS_VSCROLLED_BAR(obj) GTK_CHECK_TYPE (obj, e_vscrolled_bar_get_type ()) + + +typedef struct _EVScrolledBar EVScrolledBar; +typedef struct _EVScrolledBarClass EVScrolledBarClass; + +struct _EVScrolledBar +{ + GtkBin bin; + + GtkWidget *up_button; + GtkWidget *down_button; + + GtkAdjustment *adjustment; + + gint up_button_width; + gint up_button_height; + gint down_button_width; + gint down_button_height; + + /* The GTK+ event source ID of our timeout handler. */ + gint timeout_id; + + /* TRUE if we are scrolling up, FALSE if scrolling down. */ + gboolean scrolling_up; + + /* The minimum distance left to scroll. If the user just clicks a + button we scroll a minimum amount. This is reduced after each + scroll. */ + gfloat min_distance; + + /* TRUE if the button is still pressed. When the up/down button is + released, this gets set to FALSE, and we scroll until the minimum + distance falls below 0. */ + gboolean button_pressed; +}; + +struct _EVScrolledBarClass +{ + GtkBinClass parent_class; +}; + + +GtkType e_vscrolled_bar_get_type (void); +GtkWidget* e_vscrolled_bar_new (GtkAdjustment *adjustment); + +GtkAdjustment* e_vscrolled_bar_get_adjustment (EVScrolledBar *vscrolled_bar); +void e_vscrolled_bar_set_adjustment (EVScrolledBar *vscrolled_bar, + GtkAdjustment *adjustment); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _E_VSCROLLED_BAR_H_ */ diff --git a/widgets/shortcut-bar/test-shortcut-bar.c b/widgets/shortcut-bar/test-shortcut-bar.c new file mode 100644 index 0000000000..186bf3ed8a --- /dev/null +++ b/widgets/shortcut-bar/test-shortcut-bar.c @@ -0,0 +1,445 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@gtk.org> + * + * Copyright 1999, Helix Code, 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 + */ + +/* + * This tests the ShortcutBar widget. + */ + +#include <gnome.h> + +#include "e-shortcut-bar.h" + +#define NUM_SHORTCUT_TYPES 5 +gchar *shortcut_types[] = { + "folder:", "file:", "calendar:", "todo:", "contacts:" +}; + +GtkWidget *main_label; + +static void quit (GtkWidget *window, GdkEvent *event, gpointer data); +static void add_test_groups (EShortcutBar *shortcut_bar); +static void add_test_group (EShortcutBar *shortcut_bar, gint i, + gchar *group_name); +static gint get_random_int (gint max); + +static void on_shortcut_bar_item_selected (EShortcutBar *shortcut_bar, + GdkEvent *event, + gint group_num, + gint item_num); +static void show_standard_popup (EShortcutBar *shortcut_bar, + GdkEvent *event, + gint group_num); +static void show_context_popup (EShortcutBar *shortcut_bar, + GdkEvent *event, + gint group_num, + gint item_num); + +static void set_large_icons (GtkWidget *menuitem, + EShortcutBar *shortcut_bar); +static void set_small_icons (GtkWidget *menuitem, + EShortcutBar *shortcut_bar); +static void remove_group (GtkWidget *menuitem, + EShortcutBar *shortcut_bar); + +static void rename_item (GtkWidget *menuitem, + EShortcutBar *shortcut_bar); +static void remove_item (GtkWidget *menuitem, + EShortcutBar *shortcut_bar); + +int +main (int argc, char *argv[]) +{ + GtkWidget *window, *hpaned, *shortcut_bar; + + gnome_init ("test-shortcut-bar", "0.1", argc, argv); + + gtk_widget_push_visual (gdk_imlib_get_visual ()); + gtk_widget_push_colormap (gdk_imlib_get_colormap ()); + + window = gnome_app_new ("TestShortcutBar", "TestShortCutBar"); + gtk_window_set_default_size (GTK_WINDOW (window), 600, 400); + gtk_window_set_policy (GTK_WINDOW (window), FALSE, TRUE, FALSE); + + gtk_signal_connect (GTK_OBJECT (window), "delete-event", + GTK_SIGNAL_FUNC (quit), NULL); + + hpaned = gtk_hpaned_new (); + gnome_app_set_contents (GNOME_APP (window), hpaned); + gtk_widget_show (hpaned); + + shortcut_bar = e_shortcut_bar_new (); + gtk_paned_pack1 (GTK_PANED (hpaned), shortcut_bar, FALSE, TRUE); + gtk_widget_show (shortcut_bar); + +#if 0 + gtk_container_set_border_width (GTK_CONTAINER (shortcut_bar), 4); +#endif + + gtk_paned_set_position (GTK_PANED (hpaned), 100); + /*gtk_paned_set_gutter_size (GTK_PANED (hpaned), 12);*/ + + main_label = gtk_label_new ("Main Application Window Goes Here"); + gtk_paned_pack2 (GTK_PANED (hpaned), main_label, TRUE, TRUE); + gtk_widget_show (main_label); + + + gtk_widget_pop_visual (); + gtk_widget_pop_colormap (); + + add_test_groups (E_SHORTCUT_BAR (shortcut_bar)); + + gtk_signal_connect (GTK_OBJECT (shortcut_bar), "item_selected", + GTK_SIGNAL_FUNC (on_shortcut_bar_item_selected), + NULL); + + gtk_widget_show (window); + gtk_main (); + return 0; +} + + +static void +quit (GtkWidget *window, GdkEvent *event, gpointer data) +{ + gtk_widget_destroy (window); + gtk_exit (0); +} + + +static void +add_test_groups (EShortcutBar *shortcut_bar) +{ + add_test_group (shortcut_bar, 1, "Shortcuts"); + add_test_group (shortcut_bar, 2, "My Shortcuts"); + add_test_group (shortcut_bar, 3, "Longer Shortcuts"); + add_test_group (shortcut_bar, 4, "Very Long Shortcuts"); + add_test_group (shortcut_bar, 5, "Incredibly Long Shortcuts"); +} + + +static void +add_test_group (EShortcutBar *shortcut_bar, gint i, gchar *group_name) +{ + gint group_num, item_num, num_items; + gchar buffer[128]; + gint shortcut_type, j; + + group_num = e_shortcut_bar_add_group (E_SHORTCUT_BAR (shortcut_bar), + group_name); + + if (group_num % 2) + e_shortcut_bar_set_view_type (E_SHORTCUT_BAR (shortcut_bar), + group_num, + E_ICON_BAR_SMALL_ICONS); + + num_items = get_random_int (5) + 3; + for (j = 1; j <= num_items; j++) { + if (j == 1) + sprintf (buffer, "A very long shortcut with proper words so I can test the wrapping and ellipsis behaviour"); + else if (j == 2) + sprintf (buffer, "A very long shortcut with averylongworkinthemiddlesoIcantestthewrappingandellipsisbehaviour"); + else + sprintf (buffer, "Item %i:%i\n", i, j); + + shortcut_type = get_random_int (NUM_SHORTCUT_TYPES); + item_num = e_shortcut_bar_add_item (E_SHORTCUT_BAR (shortcut_bar), group_num, shortcut_types[shortcut_type], buffer); + } +} + + +/* Returns a random integer between 0 and max - 1. */ +static gint +get_random_int (gint max) +{ + gint random_num; + + random_num = (int) (max * (rand () / (RAND_MAX + 1.0))); +#if 0 + g_print ("Random num (%i): %i\n", max, random_num); +#endif + return random_num; +} + + +static void +on_shortcut_bar_item_selected (EShortcutBar *shortcut_bar, + GdkEvent *event, gint group_num, gint item_num) +{ + gchar buffer[256]; + + if (event->button.button == 1) { + sprintf (buffer, "Item Selected - %i:%i", + group_num + 1, item_num + 1); + gtk_label_set_text (GTK_LABEL (main_label), buffer); + } else if (event->button.button == 3) { + if (item_num == -1) + show_standard_popup (shortcut_bar, event, group_num); + else + show_context_popup (shortcut_bar, event, group_num, + item_num); + } +} + + +static void +show_standard_popup (EShortcutBar *shortcut_bar, + GdkEvent *event, + gint group_num) +{ + GtkWidget *menu, *menuitem; + + /* We don't have any commands if there aren't any groups yet. */ + if (group_num == -1) + return; + + menu = gtk_menu_new (); + + menuitem = gtk_menu_item_new_with_label ("Large Icons"); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + GTK_SIGNAL_FUNC (set_large_icons), shortcut_bar); + + menuitem = gtk_menu_item_new_with_label ("Small Icons"); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + GTK_SIGNAL_FUNC (set_small_icons), shortcut_bar); + + menuitem = gtk_menu_item_new (); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label ("Add New Group"); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label ("Remove Group"); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + GTK_SIGNAL_FUNC (remove_group), shortcut_bar); + + menuitem = gtk_menu_item_new_with_label ("Rename Group"); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new (); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label ("Add Shortcut..."); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new (); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label ("Hide Shortcut Bar"); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + /* Save the group num so we can get it in the callbacks. */ + gtk_object_set_data (GTK_OBJECT (menu), "group_num", + GINT_TO_POINTER (group_num)); + + /* FIXME: Destroy menu when finished with it somehow? */ + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, + event->button.button, event->button.time); +} + + +static void +set_large_icons (GtkWidget *menuitem, + EShortcutBar *shortcut_bar) +{ + GtkWidget *menu; + gint group_num; + + menu = menuitem->parent; + g_return_if_fail (GTK_IS_MENU (menu)); + + group_num = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menu), + "group_num")); + + e_shortcut_bar_set_view_type (shortcut_bar, group_num, + E_ICON_BAR_LARGE_ICONS); +} + + +static void +set_small_icons (GtkWidget *menuitem, + EShortcutBar *shortcut_bar) +{ + GtkWidget *menu; + gint group_num; + + menu = menuitem->parent; + g_return_if_fail (GTK_IS_MENU (menu)); + + group_num = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menu), + "group_num")); + + e_shortcut_bar_set_view_type (shortcut_bar, group_num, + E_ICON_BAR_SMALL_ICONS); +} + + +static void +remove_group (GtkWidget *menuitem, + EShortcutBar *shortcut_bar) +{ + GtkWidget *menu; + gint group_num; + + menu = menuitem->parent; + g_return_if_fail (GTK_IS_MENU (menu)); + + group_num = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menu), + "group_num")); + + e_shortcut_bar_remove_group (shortcut_bar, group_num); +} + + +static void +show_context_popup (EShortcutBar *shortcut_bar, + GdkEvent *event, + gint group_num, + gint item_num) +{ + GtkWidget *menu, *menuitem, *label, *pixmap; + + menu = gtk_menu_new (); + + menuitem = gtk_pixmap_menu_item_new (); + label = gtk_label_new ("Open Folder"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (menuitem), label); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + pixmap = gnome_stock_pixmap_widget (menu, GNOME_STOCK_MENU_OPEN); + if (pixmap) { + gtk_widget_show(pixmap); + gtk_pixmap_menu_item_set_pixmap (GTK_PIXMAP_MENU_ITEM (menuitem), pixmap); + } + + menuitem = gtk_menu_item_new_with_label ("Open in New Window"); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label ("Advanced Find"); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new (); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label ("Remove from Shortcut Bar"); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + GTK_SIGNAL_FUNC (remove_item), shortcut_bar); + + menuitem = gtk_menu_item_new_with_label ("Rename Shortcut"); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + GTK_SIGNAL_FUNC (rename_item), shortcut_bar); + + menuitem = gtk_menu_item_new (); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label ("Properties"); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + + /* Save the group & item nums so we can get them in the callbacks. */ + gtk_object_set_data (GTK_OBJECT (menu), "group_num", + GINT_TO_POINTER (group_num)); + gtk_object_set_data (GTK_OBJECT (menu), "item_num", + GINT_TO_POINTER (item_num)); + + /* FIXME: Destroy menu when finished with it somehow? */ + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, + event->button.button, event->button.time); +} + + +static void +rename_item (GtkWidget *menuitem, + EShortcutBar *shortcut_bar) +{ + GtkWidget *menu; + gint group_num, item_num; + + menu = menuitem->parent; + g_return_if_fail (GTK_IS_MENU (menu)); + + group_num = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menu), + "group_num")); + item_num = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menu), + "item_num")); + + e_shortcut_bar_start_editing_item (shortcut_bar, group_num, item_num); +} + + +static void +remove_item (GtkWidget *menuitem, + EShortcutBar *shortcut_bar) +{ + GtkWidget *menu; + gint group_num, item_num; + + menu = menuitem->parent; + g_return_if_fail (GTK_IS_MENU (menu)); + + group_num = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menu), + "group_num")); + item_num = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menu), + "item_num")); + + e_shortcut_bar_remove_item (shortcut_bar, group_num, item_num); +} + + diff --git a/widgets/table-test.c b/widgets/table-test.c deleted file mode 100644 index 9de673ede4..0000000000 --- a/widgets/table-test.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Test code for the ETable package - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - */ -#include <config.h> -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <gnome.h> -#include "e-cursors.h" -#include "table-test.h" - -int -main (int argc, char *argv []) -{ - - if (isatty (0)){ - int fd; - - close (0); - fd = open ("sample.table", O_RDONLY); - if (fd == -1){ - fprintf (stderr, "Could not find sample.table, try feeding a table on stdin"); - exit (1); - } - dup2 (fd, 0); - } - - gnome_init ("TableTest", "TableTest", argc, argv); - e_cursors_init (); - - table_browser_test (); - multi_cols_test (); - check_test (); - e_table_test (); - - gtk_main (); - - e_cursors_shutdown (); - return 0; -} diff --git a/widgets/table-test.h b/widgets/table-test.h deleted file mode 100644 index ad8cfcc083..0000000000 --- a/widgets/table-test.h +++ /dev/null @@ -1,4 +0,0 @@ -void table_browser_test (void); -void multi_cols_test (void); -void check_test (void); -void e_table_test (void); diff --git a/widgets/table/e-cell-checkbox.c b/widgets/table/e-cell-checkbox.c index 6e4b597abf..d77e1fa4cd 100644 --- a/widgets/table/e-cell-checkbox.c +++ b/widgets/table/e-cell-checkbox.c @@ -14,7 +14,7 @@ #include <gdk/gdkkeysyms.h> #include <libgnomeui/gnome-canvas.h> #include "e-cell-checkbox.h" -#include "e-util.h" +#include <e-util/e-util.h> #include "e-table-item.h" #include "check-empty.xpm" diff --git a/widgets/table/e-cell-text.c b/widgets/table/e-cell-text.c index 1b2205ba51..9ce8190a14 100644 --- a/widgets/table/e-cell-text.c +++ b/widgets/table/e-cell-text.c @@ -15,7 +15,7 @@ #include <libgnomeui/gnome-canvas.h> #include <stdio.h> #include "e-cell-text.h" -#include "e-util.h" +#include <e-util/e-util.h> #include "e-table-item.h" #define PARENT_TYPE e_cell_get_type() diff --git a/widgets/table/e-cell-toggle.c b/widgets/table/e-cell-toggle.c index 6ea181ea40..a933a62c49 100644 --- a/widgets/table/e-cell-toggle.c +++ b/widgets/table/e-cell-toggle.c @@ -14,7 +14,7 @@ #include <gdk/gdkkeysyms.h> #include <libgnomeui/gnome-canvas.h> #include "e-cell-toggle.h" -#include "e-util.h" +#include <e-util/e-util.h> #include "e-table-item.h" #define PARENT_TYPE e_cell_get_type() diff --git a/widgets/table/e-cell.c b/widgets/table/e-cell.c index 0f9297ecba..b5cbc0e850 100644 --- a/widgets/table/e-cell.c +++ b/widgets/table/e-cell.c @@ -8,7 +8,7 @@ */ #include <config.h> #include "e-cell.h" -#include "e-util.h" +#include <e-util/e-util.h> #define PARENT_TYPE gtk_object_get_type() diff --git a/widgets/table/e-table-col.c b/widgets/table/e-table-col.c index 86392a9419..62a451ca4f 100644 --- a/widgets/table/e-table-col.c +++ b/widgets/table/e-table-col.c @@ -10,7 +10,7 @@ #include <gtk/gtkobject.h> #include <gtk/gtksignal.h> #include "e-table-col.h" -#include "e-util.h" +#include <e-util/e-util.h> #define PARENT_TYPE (gtk_object_get_type ()) diff --git a/widgets/table/e-table-group.c b/widgets/table/e-table-group.c index 8765c3b83c..14c7a33f79 100644 --- a/widgets/table/e-table-group.c +++ b/widgets/table/e-table-group.c @@ -12,7 +12,7 @@ #include "e-table-group.h" #include "e-table-item.h" #include <libgnomeui/gnome-canvas-rect-ellipse.h> -#include "e-util.h" +#include <e-util/e-util.h> #define TITLE_HEIGHT 16 #define GROUP_INDENT 10 diff --git a/widgets/table/e-table-sorted.c b/widgets/table/e-table-sorted.c index 6bc55ad9dc..b559b3d87f 100644 --- a/widgets/table/e-table-sorted.c +++ b/widgets/table/e-table-sorted.c @@ -8,7 +8,7 @@ */ #include <config.h> #include <stdlib.h> -#include "e-util.h" +#include <e-util/e-util.h> #include "e-table-sorted.h" #define PARENT_TYPE E_TABLE_SUBSET_TYPE diff --git a/widgets/table/e-table-subset.c b/widgets/table/e-table-subset.c index 88f5c18c85..be4c7ab732 100644 --- a/widgets/table/e-table-subset.c +++ b/widgets/table/e-table-subset.c @@ -9,7 +9,7 @@ #include <config.h> #include <stdlib.h> #include <gtk/gtksignal.h> -#include "e-util.h" +#include <e-util/e-util.h> #include "e-table-subset.h" #define PARENT_TYPE E_TABLE_MODEL_TYPE diff --git a/widgets/table/e-table.c b/widgets/table/e-table.c index 01389135bf..730306b374 100644 --- a/widgets/table/e-table.c +++ b/widgets/table/e-table.c @@ -14,8 +14,8 @@ #include <stdio.h> #include <libgnomeui/gnome-canvas.h> #include <gtk/gtksignal.h> +#include <e-util/e-util.h> #include "e-table.h" -#include "e-util.h" #include "e-table-header-item.h" #include "e-table-subset.h" #include "e-table-item.h" diff --git a/widgets/test-check.c b/widgets/test-check.c deleted file mode 100644 index b24a7aff64..0000000000 --- a/widgets/test-check.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Test code for the ETable package - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - */ -#include <config.h> -#include <stdio.h> -#include <string.h> -#include <gnome.h> -#include "e-table-simple.h" -#include "e-table-header.h" -#include "e-table-header-item.h" -#include "e-table-item.h" -#include "e-cursors.h" -#include "e-cell-text.h" -#include "e-cell-checkbox.h" - -#include "table-test.h" - -#define LINES 4 - -static struct { - int value; - char *string; -} my_table [LINES] = { - { 0, "Buy food" }, - { 1, "Breathe " }, - { 0, "Cancel gdb session with shrink" }, - { 1, "Make screenshots" }, -}; -/* - * ETableSimple callbacks - */ -static int -col_count (ETableModel *etc, void *data) -{ - return 2; -} - -static int -row_count (ETableModel *etc, void *data) -{ - return LINES; -} - -static void * -value_at (ETableModel *etc, int col, int row, void *data) -{ - g_assert (col < 2); - g_assert (row < LINES); - - if (col == 0) - return GINT_TO_POINTER (my_table [row].value); - else - return my_table [row].string; - -} - -static void -set_value_at (ETableModel *etc, int col, int row, const void *val, void *data) -{ - g_assert (col < 2); - g_assert (row < LINES); - - if (col == 0){ - my_table [row].value = GPOINTER_TO_INT (val); - printf ("Value at %d,%d set to %d\n", col, row, GPOINTER_TO_INT (val)); - } else { - my_table [row].string = g_strdup (val); - printf ("Value at %d,%d set to %s\n", col, row, (char *) val); - } -} - -static gboolean -is_cell_editable (ETableModel *etc, int col, int row, void *data) -{ - return TRUE; -} - -static void -set_canvas_size (GnomeCanvas *canvas, GtkAllocation *alloc) -{ - gnome_canvas_set_scroll_region (canvas, 0, 0, alloc->width, alloc->height); -} - -void -check_test (void) -{ - GtkWidget *canvas, *window; - ETableModel *e_table_model; - ETableHeader *e_table_header; - ETableCol *col_0, *col_1; - ECell *cell_left_just, *cell_image_check; - - gtk_widget_push_visual (gdk_rgb_get_visual ()); - gtk_widget_push_colormap (gdk_rgb_get_cmap ()); - - e_table_model = e_table_simple_new ( - col_count, row_count, value_at, - set_value_at, is_cell_editable, NULL); - - /* - * Header - */ - e_table_header = e_table_header_new (); - - cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT); - - cell_image_check = e_cell_checkbox_new (); - col_0 = e_table_col_new (0, "", 18, 18, cell_image_check, g_int_equal, TRUE); - e_table_header_add_column (e_table_header, col_0, 0); - - col_1 = e_table_col_new (1, "Item Name", 180, 20, cell_left_just, g_str_equal, TRUE); - e_table_header_add_column (e_table_header, col_1, 1); - - /* - * GUI - */ - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - canvas = gnome_canvas_new (); - - gtk_signal_connect (GTK_OBJECT (canvas), "size_allocate", - GTK_SIGNAL_FUNC (set_canvas_size), NULL); - - gtk_container_add (GTK_CONTAINER (window), canvas); - gtk_widget_show_all (window); - gnome_canvas_item_new ( - gnome_canvas_root (GNOME_CANVAS (canvas)), - e_table_header_item_get_type (), - "ETableHeader", e_table_header, - "x", 0, - "y", 0, - NULL); - - gnome_canvas_item_new ( - gnome_canvas_root (GNOME_CANVAS (canvas)), - e_table_item_get_type (), - "ETableHeader", e_table_header, - "ETableModel", e_table_model, - "x", (double) 0, - "y", (double) 30, - "drawgrid", TRUE, - "drawfocus", TRUE, - "spreadsheet", TRUE, - NULL); - -} - - - - - diff --git a/widgets/test-cols.c b/widgets/test-cols.c deleted file mode 100644 index 6342a1739f..0000000000 --- a/widgets/test-cols.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Test code for the ETable package - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - */ -#include <config.h> -#include <stdio.h> -#include <string.h> -#include <gnome.h> -#include "e-table-simple.h" -#include "e-table-header.h" -#include "e-table-header-item.h" -#include "e-table-item.h" -#include "e-cursors.h" -#include "e-cell-text.h" -#include "e-cell-toggle.h" - -#include "table-test.h" - -#define LINES 4 - -static struct { - int value; - char *string; -} my_table [LINES] = { - { 0, "You are not" }, - { 1, "A beautiful and unique " }, - { 0, "Snowflake" }, - { 2, "You are not your wallet" }, -}; -/* - * ETableSimple callbacks - */ -static int -col_count (ETableModel *etc, void *data) -{ - return 2; -} - -static int -row_count (ETableModel *etc, void *data) -{ - return LINES; -} - -static void * -value_at (ETableModel *etc, int col, int row, void *data) -{ - g_assert (col < 2); - g_assert (row < LINES); - - if (col == 0) - return GINT_TO_POINTER (my_table [row].value); - else - return my_table [row].string; - -} - -static void -set_value_at (ETableModel *etc, int col, int row, const void *val, void *data) -{ - g_assert (col < 2); - g_assert (row < LINES); - - if (col == 0){ - my_table [row].value = GPOINTER_TO_INT (val); - printf ("Value at %d,%d set to %d\n", col, row, GPOINTER_TO_INT (val)); - } else { - my_table [row].string = g_strdup (val); - printf ("Value at %d,%d set to %s\n", col, row, (char *) val); - } -} - -static gboolean -is_cell_editable (ETableModel *etc, int col, int row, void *data) -{ - return TRUE; -} - -static void -set_canvas_size (GnomeCanvas *canvas, GtkAllocation *alloc) -{ - gnome_canvas_set_scroll_region (canvas, 0, 0, alloc->width, alloc->height); -} - -void -multi_cols_test (void) -{ - GtkWidget *canvas, *window; - ETableModel *e_table_model; - ETableHeader *e_table_header, *e_table_header_multiple; - ETableCol *col_0, *col_1; - ECell *cell_left_just, *cell_image_toggle; - - gtk_widget_push_visual (gdk_rgb_get_visual ()); - gtk_widget_push_colormap (gdk_rgb_get_cmap ()); - - e_table_model = e_table_simple_new ( - col_count, row_count, value_at, - set_value_at, is_cell_editable, NULL); - - /* - * Header - */ - e_table_header = e_table_header_new (); - - cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT); - - { - GdkPixbuf **images = g_new (GdkPixbuf *, 3); - int i; - - images [0] = gdk_pixbuf_new_from_file ("image1.png"); - images [1] = gdk_pixbuf_new_from_file ("image2.png"); - images [2] = gdk_pixbuf_new_from_file ("image3.png"); - - cell_image_toggle = e_cell_toggle_new (0, 3, images); - - for (i = 0; i < 3; i++) - gdk_pixbuf_unref (images [i]); - - g_free (images); - } - - col_1 = e_table_col_new (1, "Item Name", 180, 20, cell_left_just, g_str_equal, TRUE); - e_table_header_add_column (e_table_header, col_1, 0); - - col_0 = e_table_col_new (0, "A", 48, 48, cell_image_toggle, g_int_equal, TRUE); - e_table_header_add_column (e_table_header, col_0, 1); - - /* - * Second test - */ - e_table_header_multiple = e_table_header_new (); - e_table_header_add_column (e_table_header_multiple, col_0, 0); - e_table_header_add_column (e_table_header_multiple, col_1, 1); - e_table_header_add_column (e_table_header_multiple, col_1, 2); - - /* - * GUI - */ - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - canvas = gnome_canvas_new (); - - gtk_signal_connect (GTK_OBJECT (canvas), "size_allocate", - GTK_SIGNAL_FUNC (set_canvas_size), NULL); - - gtk_container_add (GTK_CONTAINER (window), canvas); - gtk_widget_show_all (window); - - gnome_canvas_item_new ( - gnome_canvas_root (GNOME_CANVAS (canvas)), - e_table_header_item_get_type (), - "ETableHeader", e_table_header, - "x", 0, - "y", 0, - NULL); - - gnome_canvas_item_new ( - gnome_canvas_root (GNOME_CANVAS (canvas)), - e_table_item_get_type (), - "ETableHeader", e_table_header, - "ETableModel", e_table_model, - "x", (double) 0, - "y", (double) 30, - "drawgrid", TRUE, - "drawfocus", TRUE, - "spreadsheet", TRUE, - NULL); - - gnome_canvas_item_new ( - gnome_canvas_root (GNOME_CANVAS (canvas)), - e_table_header_item_get_type (), - "ETableHeader", e_table_header_multiple, - "x", 300, - "y", 0, - NULL); - gnome_canvas_item_new ( - gnome_canvas_root (GNOME_CANVAS (canvas)), - e_table_item_get_type (), - "ETableHeader", e_table_header_multiple, - "ETableModel", e_table_model, - "x", (double) 300, - "y", (double) 30, - "drawgrid", TRUE, - "drawfocus", TRUE, - "spreadsheet", TRUE, - NULL); - -} - - - - - diff --git a/widgets/test-table.c b/widgets/test-table.c deleted file mode 100644 index 2e64826cba..0000000000 --- a/widgets/test-table.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Test code for the ETable package - * - * Author: - * Miguel de Icaza (miguel@gnu.org) - */ -#include <config.h> -#include <stdio.h> -#include <string.h> -#include <gnome.h> -#include "e-table-simple.h" -#include "e-table-header.h" -#include "e-table-header-item.h" -#include "e-table-item.h" -#include "e-cursors.h" -#include "e-cell-text.h" -#include "e-table.h" - -#include "table-test.h" - -char buffer [1024]; -char **column_labels; -char ***table_data; -int cols = 0; -int lines = 0; -int lines_alloc = 0; - -static void -parse_headers () -{ - char *p, *s; - int in_value = 0, i; - - fgets (buffer, sizeof (buffer)-1, stdin); - - for (p = buffer; *p; p++){ - if (*p == ' ' || *p == '\t'){ - if (in_value){ - cols++; - in_value = 0; - } - } else - in_value = 1; - } - if (in_value) - cols++; - - if (!cols){ - fprintf (stderr, "No columns in first row\n"); - exit (1); - } - - column_labels = g_new0 (char *, cols); - - p = buffer; - for (i = 0; (s = strtok (p, " \t")) != NULL; i++){ - column_labels [i] = g_strdup (s); - p = NULL; - } - - printf ("%d headers:\n", cols); - for (i = 0; i < cols; i++){ - printf ("header %d: %s\n", i, column_labels [i]); - } -} - -static char ** -load_line (char *buffer, int cols) -{ - char **line = g_new0 (char *, cols); - char *p; - int i; - - for (i = 0; i < cols; i++){ - p = strtok (buffer, " \t\n"); - if (p == NULL){ - for (; i < cols; i++) - line [i] = g_strdup (""); - return line; - } else - line [i] = g_strdup (p); - buffer = NULL; - } - return line; -} - -static void -append_line (char **line) -{ - if (lines <= lines_alloc){ - lines_alloc = lines + 50; - table_data = g_renew (char **, table_data, lines_alloc); - } - table_data [lines] = line; - lines++; -} - -static void -load_data () -{ - int i; - - { - static int loaded; - - if (loaded) - return; - - loaded = TRUE; - } - - - parse_headers (); - - while (fgets (buffer, sizeof (buffer)-1, stdin) != NULL){ - char **line; - - if (buffer [0] == '\n') - continue; - line = load_line (buffer, cols); - append_line (line); - } - - for (i = 0; i < lines; i++){ - int j; - - printf ("Line %d: ", i); - for (j = 0; j < cols; j++) - printf ("[%s] ", table_data [i][j]); - printf ("\n"); - } -} - -/* - * ETableSimple callbacks - */ -static int -col_count (ETableModel *etc, void *data) -{ - return cols; -} - -static int -row_count (ETableModel *etc, void *data) -{ - return lines; -} - -static void * -value_at (ETableModel *etc, int col, int row, void *data) -{ - g_assert (col < cols); - g_assert (row < lines); - - return (void *) table_data [row][col]; -} - -static void -set_value_at (ETableModel *etc, int col, int row, const void *val, void *data) -{ - g_assert (col < cols); - g_assert (row < lines); - - g_free (table_data [row][col]); - table_data [row][col] = g_strdup (val); - - printf ("Value at %d,%d set to %s\n", col, row, (char *) val); -} - -static gboolean -is_cell_editable (ETableModel *etc, int col, int row, void *data) -{ - return TRUE; -} - -static void -set_canvas_size (GnomeCanvas *canvas, GtkAllocation *alloc) -{ - gnome_canvas_set_scroll_region (canvas, 0, 0, alloc->width, alloc->height); -} - -void -table_browser_test (void) -{ - GtkWidget *canvas, *window; - ETableModel *e_table_model; - ETableHeader *e_table_header; - ECell *cell_left_just; - GnomeCanvasItem *group; - int i; - - load_data (); - - /* - * Data model - */ - e_table_model = e_table_simple_new ( - col_count, row_count, value_at, - set_value_at, is_cell_editable, NULL); - - /* - * Header - */ - e_table_header = e_table_header_new (); - cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT); - - for (i = 0; i < cols; i++){ - ETableCol *ecol = e_table_col_new ( - i, column_labels [i], - 80, 20, cell_left_just, - g_str_equal, TRUE); - - e_table_header_add_column (e_table_header, ecol, i); - } - - /* - * Setup GUI - */ - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - canvas = gnome_canvas_new (); - - gtk_signal_connect (GTK_OBJECT (canvas), "size_allocate", - GTK_SIGNAL_FUNC (set_canvas_size), NULL); - - gtk_container_add (GTK_CONTAINER (window), canvas); - gtk_widget_show_all (window); - gnome_canvas_item_new ( - gnome_canvas_root (GNOME_CANVAS (canvas)), - e_table_header_item_get_type (), - "ETableHeader", e_table_header, - "x", 0, - "y", 0, - NULL); - - group = gnome_canvas_item_new ( - gnome_canvas_root (GNOME_CANVAS (canvas)), - gnome_canvas_group_get_type (), - "x", 30.0, - "y", 30.0, - NULL); - - gnome_canvas_item_new ( - GNOME_CANVAS_GROUP (group), - e_table_item_get_type (), - "ETableHeader", e_table_header, - "ETableModel", e_table_model, - "x", (double) 0, - "y", (double) 0, - "drawgrid", TRUE, - "drawfocus", TRUE, - "spreadsheet", TRUE, - NULL); -} - -static void -do_e_table_demo (const char *col_spec, const char *group_spec) -{ - GtkWidget *e_table, *window; - ETableModel *e_table_model; - ECell *cell_left_just; - ETableHeader *full_header; - int i; - - /* - * Data model - */ - e_table_model = e_table_simple_new ( - col_count, row_count, value_at, - set_value_at, is_cell_editable, NULL); - - full_header = e_table_header_new (); - cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT); - - for (i = 0; i < cols; i++){ - ETableCol *ecol = e_table_col_new ( - i, column_labels [i], - 80, 20, cell_left_just, - g_str_equal, TRUE); - - e_table_header_add_column (full_header, ecol, i); - } - - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - e_table = e_table_new (full_header, e_table_model, col_spec, group_spec); - - gtk_container_add (GTK_CONTAINER (window), e_table); - - gtk_widget_set_usize (window, 200, 200); - gtk_widget_show (e_table); - gtk_widget_show (window); -} - -void -e_table_test (void) -{ - load_data (); - - if (getenv ("DO")){ - do_e_table_demo ("0,1,2,3,4", NULL); - do_e_table_demo ("0,1,2,3,4", "3,4"); - } - do_e_table_demo ("0,1,2,3,4", "3"); -} diff --git a/widgets/test.c b/widgets/test.c deleted file mode 100644 index 0eece34467..0000000000 --- a/widgets/test.c +++ /dev/null @@ -1,17 +0,0 @@ -#include <config.h> -#include "e-table-simple.h" - -struct { - char *str; - int val; -} data [] = { - { "Miguel", 10 }, - { "Nat", 20 }, - { NULL, 0 }, -}; - -main () -{ - -} - |