diff --git a/bigpicture.c b/bigpicture.c index fe6b997a127d7c95418afb58a41e4a4f0d6ff4c3..1ca6295e75053669dac64701bd57c82ea3afb1d2 100644 --- a/bigpicture.c +++ b/bigpicture.c @@ -27,6 +27,9 @@ #define GRID_SCALE_MIN_ID_PER_CELL 0.1 /* minimum %ID per grid cell */ #define GRID_SCALE_MIN 0 /* minimum possible value for grid scale */ #define GRID_SCALE_MAX 100 /* maximum possible value for grid scale */ +#define BIG_PICTURE_GRID_HEADER_NAME "BigPictureGridHeader" +#define BIG_PICTURE_WIDGET_NAME "BigPictureWidget" /* name of the direct parent of the grids etc. */ +#define MAX_BIG_PICTURE_HEIGHT_RATIO 0.4 /* max height of the big picture wrt the whole window size */ /* Local function declarations */ static GridHeaderProperties* gridHeaderGetProperties(GtkWidget *gridHeader); @@ -325,27 +328,28 @@ void refreshGridOrder(GtkWidget *bigPicture) g_object_ref(fwdExonView); g_object_ref(revExonView); - /* Remove them */ - gtk_container_remove(GTK_CONTAINER(bigPicture), fwdStrandGrid); - gtk_container_remove(GTK_CONTAINER(bigPicture), revStrandGrid); - gtk_container_remove(GTK_CONTAINER(bigPicture), fwdExonView); - gtk_container_remove(GTK_CONTAINER(bigPicture), revExonView); + /* Find the direct container of the grids etc and remove them */ + GtkWidget *bpContainer = getNamedChildWidget(bigPicture, BIG_PICTURE_WIDGET_NAME); + gtk_container_remove(GTK_CONTAINER(bpContainer), fwdStrandGrid); + gtk_container_remove(GTK_CONTAINER(bpContainer), revStrandGrid); + gtk_container_remove(GTK_CONTAINER(bpContainer), fwdExonView); + gtk_container_remove(GTK_CONTAINER(bpContainer), revExonView); /* Add them back, with the forward-strand grid at the top and the reverse-strand grid * at the bottom, or vice versa if the strands are toggled. */ if (bigPictureGetDisplayRev(bigPicture)) { - addChildToBigPicture(bigPicture, revStrandGrid, FALSE); - addChildToBigPicture(bigPicture, revExonView, FALSE); - addChildToBigPicture(bigPicture, fwdExonView, FALSE); - addChildToBigPicture(bigPicture, fwdStrandGrid, TRUE); + addChildToBigPicture(bpContainer, revStrandGrid, FALSE); + addChildToBigPicture(bpContainer, revExonView, FALSE); + addChildToBigPicture(bpContainer, fwdExonView, FALSE); + addChildToBigPicture(bpContainer, fwdStrandGrid, FALSE); } else { - addChildToBigPicture(bigPicture, fwdStrandGrid, FALSE); - addChildToBigPicture(bigPicture, fwdExonView, FALSE); - addChildToBigPicture(bigPicture, revExonView, FALSE); - addChildToBigPicture(bigPicture, revStrandGrid, TRUE); + addChildToBigPicture(bpContainer, fwdStrandGrid, FALSE); + addChildToBigPicture(bpContainer, fwdExonView, FALSE); + addChildToBigPicture(bpContainer, revExonView, FALSE); + addChildToBigPicture(bpContainer, revStrandGrid, FALSE); } /* Decrease the ref count again */ @@ -744,6 +748,63 @@ void acceptAndClearPreviewBox(GtkWidget *bigPicture, const int xCentre, GdkRecta } +/* Recursively loop through the children of the given widget and sum the heights of any + * that are grid or exon-view widgets. */ +static int getBigPictureChildrenHeights(GtkWidget *widget, const int heightIn) +{ + GList *child = gtk_container_get_children(GTK_CONTAINER(widget)); + int height = heightIn; + + for ( ; child; child = child->next) + { + GtkWidget *childWidget = GTK_WIDGET(child->data); + + if (GTK_WIDGET_VISIBLE(childWidget)) + { + const gchar *name = gtk_widget_get_name(childWidget); + + if (stringsEqual(name, BIG_PICTURE_GRID_NAME, TRUE) || + stringsEqual(name, BIG_PICTURE_EXON_VIEW_NAME, TRUE) || + stringsEqual(name, BIG_PICTURE_GRID_HEADER_NAME, TRUE)) + { + height += childWidget->allocation.height; + } + else if (GTK_IS_CONTAINER(childWidget)) + { + height += getBigPictureChildrenHeights(childWidget, height); + } + } + } + + return height; +} + + +/* Calculate the size of the big picture's children and set its size request to fit them in + * but don't go greater than the maximum. This is called when the exon view or grids change size + * etc. to make sure we only use as much space as necessary. Note that because the big picture + * is in a paned window this does not have an effect if the user has changed (i.e. specifically + * set) the pane size, which makes sense but it would be nice to have some way to be able to + * revert to the original behaviour */ +static void bigPictureRecalculateSize(GtkWidget *bigPicture) +{ + int height = getBigPictureChildrenHeights(bigPicture, 0); + height += 4; /* not sure where this extra space comes from (padding or something?) */ + + GtkWidget *blxWindow = bigPictureGetBlxWindow(bigPicture); + int maxHeight = blxWindow->allocation.height * MAX_BIG_PICTURE_HEIGHT_RATIO; + + height = min(height, maxHeight); + gtk_widget_set_size_request(bigPicture, -1, height); +} + + +static void onSizeAllocateBigPicture(GtkWidget *bigPicture, GtkAllocation *allocation, gpointer data) +{ + bigPictureRecalculateSize(bigPicture); +} + + /*********************************************************** * Properties * ***********************************************************/ @@ -1107,6 +1168,7 @@ static GtkWidget* createButton(GtkWidget *container, char *label, char *tooltip, static GtkWidget *createBigPictureGridHeader(GtkWidget *bigPicture) { GtkWidget *header = gtk_layout_new(NULL, NULL); + gtk_widget_set_name(header, BIG_PICTURE_GRID_HEADER_NAME); /* Create the header buttons. Put them in an hbox */ GtkWidget *hbox = gtk_hbox_new(FALSE, 0); @@ -1129,16 +1191,21 @@ static GtkWidget *createBigPictureGridHeader(GtkWidget *bigPicture) GtkWidget* createBigPicture(GtkWidget *blxWindow, - GtkWidget *container, + GtkContainer *parent, GtkWidget **fwdStrandGrid, GtkWidget **revStrandGrid, const int initialZoom, const gdouble lowestId) { /* Create the main big picture widget, which will contain all of the - * individual big-picture grids, plus a header. */ - GtkWidget *bigPicture = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(container), bigPicture, FALSE, TRUE, 0); + * individual big-picture grids, plus a header, in a scrollable vbox. */ + GtkWidget *bigPicture = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(bigPicture), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add(parent, bigPicture); + + GtkWidget *vbox = gtk_vbox_new(FALSE, 0); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(bigPicture), vbox); + gtk_widget_set_name(vbox, BIG_PICTURE_WIDGET_NAME); /* Our big picture needs to have a header plus 3 panes: * 1. the top grid (fwd strand); @@ -1146,7 +1213,7 @@ GtkWidget* createBigPicture(GtkWidget *blxWindow, * 3. bottom grid (reverse strand) */ GtkWidget *header = createBigPictureGridHeader(bigPicture); - addChildToBigPicture(bigPicture, header, FALSE); + addChildToBigPicture(vbox, header, FALSE); *fwdStrandGrid = createBigPictureGrid(bigPicture, BLXSTRAND_FORWARD); *revStrandGrid = createBigPictureGrid(bigPicture, BLXSTRAND_REVERSE); @@ -1155,10 +1222,12 @@ GtkWidget* createBigPicture(GtkWidget *blxWindow, GtkWidget *revExonView = createExonView(bigPicture, BLXSTRAND_REVERSE); /* By default, make the forward strand the top grid */ - addChildToBigPicture(bigPicture, *fwdStrandGrid, FALSE); - addChildToBigPicture(bigPicture, fwdExonView, FALSE); - addChildToBigPicture(bigPicture, revExonView, FALSE); - addChildToBigPicture(bigPicture, *revStrandGrid, TRUE); + addChildToBigPicture(vbox, *fwdStrandGrid, FALSE); + addChildToBigPicture(vbox, fwdExonView, FALSE); + addChildToBigPicture(vbox, revExonView, FALSE); + addChildToBigPicture(vbox, *revStrandGrid, FALSE); + + g_signal_connect(G_OBJECT(bigPicture), "size-allocate", G_CALLBACK(onSizeAllocateBigPicture), NULL); /* Set the big picture properties */ bigPictureCreateProperties(bigPicture, diff --git a/bigpicture.h b/bigpicture.h index f3ffea1b7dfe8a68279c198a0688264b0b210477..e3ccb5f808394b6e4d7d1097416ffa88883b31eb 100644 --- a/bigpicture.h +++ b/bigpicture.h @@ -124,7 +124,7 @@ int getRightCoordFromCentre(const int centreCoord, void refreshGridOrder(GtkWidget *bigPicture); GtkWidget* createBigPicture(GtkWidget *blxWindow, - GtkWidget *container, + GtkContainer *parent, GtkWidget **fwdStrandGrid, GtkWidget **revStrandGrid, const int bigPictZoom, diff --git a/blxwindow.c b/blxwindow.c index 17b59d8068cbddf844beab9c99a1028b60a0bea6..6b0c9180db352b5bb4a3286f1deeb2ac2f3a533e 100755 --- a/blxwindow.c +++ b/blxwindow.c @@ -937,6 +937,10 @@ static void toggleGridVisibility(GtkWidget *blxWindow, const int number) GtkWidget *grid = useFwdGrid ? bigPictureGetFwdGrid(bigPicture) : bigPictureGetRevGrid(bigPicture); widgetSetHidden(grid, !widgetGetHidden(grid)); + + /* It's probably overkill to call refreshGridOrder here but I can't seem to find another way + * to force the paned window to shrink to take into account newly-hidden widgets */ + refreshGridOrder(bigPicture); } } @@ -951,6 +955,10 @@ static void toggleExonViewVisibility(GtkWidget *blxWindow, const int number) GtkWidget *exonView = useFwdExonView ? bigPictureGetFwdExonView(bigPicture) : bigPictureGetRevExonView(bigPicture); widgetSetHidden(exonView, !widgetGetHidden(exonView)); + + /* It's probably overkill to call refreshGridOrder here but I can't seem to find another way + * to force the paned window to shrink to take into account newly-hidden widgets */ + refreshGridOrder(bigPicture); } } @@ -3959,6 +3967,36 @@ static gboolean onButtonPressBlxWindow(GtkWidget *window, GdkEventButton *event, } +/* Mouse button handler for the paned window containing the big picture and detail view */ +static gboolean onButtonPressPanedWin(GtkWidget *panedWin, GdkEventButton *event, gpointer data) +{ + gboolean handled = FALSE; + + switch (event->button) + { + case 1: /* left button */ + { + if (event->type == GDK_2BUTTON_PRESS) /* double-click */ + { + /* When the user double-clicks the paned window separator, reset the splitter position + * (i.e. so that gets automatically positioned based on the child widgets' size) + * to do: This makes the splitter jump temporarily to the desired position but then it + * immediately jumps back, so I'm leaving it out for now */ + /* gtk_paned_set_position(GTK_PANED(panedWin), 100); */ + handled = TRUE; + } + + break; + } + + default: + break; + }; + + return handled; +} + + /* Handlers for specific key presses */ static gboolean onKeyPressEscape(GtkWidget *window, const gboolean ctrlModifier, const gboolean shiftModifier) { @@ -5344,15 +5382,19 @@ GtkWidget* createBlxWindow(CommandLineOptions *options, GtkWidget *fwdStrandGrid = NULL, *revStrandGrid = NULL; + /* Create the two main sections - the big picture and detail view - in a paned window */ + GtkWidget *panedWin = gtk_vpaned_new(); + gtk_box_pack_start(GTK_BOX(vbox), panedWin, TRUE, TRUE, 0); + GtkWidget *bigPicture = createBigPicture(window, - vbox, + GTK_CONTAINER(panedWin), &fwdStrandGrid, &revStrandGrid, options->bigPictZoom, lowestId); GtkWidget *detailView = createDetailView(window, - vbox, + GTK_CONTAINER(panedWin), detailAdjustment, fwdStrandGrid, revStrandGrid, @@ -5385,6 +5427,7 @@ GtkWidget* createBlxWindow(CommandLineOptions *options, paddingSeq); /* Connect signals */ + g_signal_connect(G_OBJECT(panedWin), "button-press-event", G_CALLBACK(onButtonPressPanedWin), window); g_signal_connect(G_OBJECT(window), "button-press-event", G_CALLBACK(onButtonPressBlxWindow), mainmenu); g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(onKeyPressBlxWindow), NULL); diff --git a/detailview.c b/detailview.c index 8917f6017d28679575aae20399056e414fd83298..aa9c04ec5474f089ebad189566b7ae0184e429b0 100755 --- a/detailview.c +++ b/detailview.c @@ -18,6 +18,7 @@ #include <math.h> #define DETAIL_VIEW_TOOLBAR_NAME "DetailViewToolbarName" +#define DETAIL_VIEW_WIDGET_NAME "DetailViewWidget" #define SORT_BY_NAME_STRING "Name" #define SORT_BY_SCORE_STRING "Score" #define SORT_BY_ID_STRING "Identity" @@ -369,86 +370,59 @@ static GtkWidget *findNestedPanedWidget(GtkContainer *parentWidget) * actual trees, it may contain their containers (e.g. if they live in scrolled windows). 'first' * indicates that this is the first (set of) tree(s) added. This information is used to determine * which pane to put the tree in and/or whether the first tree in the list should have headers. */ -static void addTreesToDetailView(GtkContainer *detailView, - GList *treeList, - const gboolean first) +static void addTreesToDetailViewPane(GtkPaned *panedWin, + GList *treeList, + const gboolean first) { - /* Currently we expect the detail view to be a paned widget */ - if (GTK_IS_PANED(detailView)) + int numTrees = g_list_length(treeList); + + if (numTrees == 1) { - int numTrees = g_list_length(treeList); + /* Two panes, one tree. Use 'first' flags to decide which pane to put it in */ + GtkWidget *tree1 = GTK_WIDGET(treeList->data); - if (numTrees == 1) + if (first) { - /* Two panes, one tree. Use 'first' flags to decide which pane to put it in */ - GtkWidget *tree1 = GTK_WIDGET(treeList->data); - - if (first) - { - gtk_paned_pack1(GTK_PANED(detailView), tree1, TRUE, TRUE); - } - else - { - gtk_paned_pack2(GTK_PANED(detailView), tree1, TRUE, TRUE); - } + gtk_paned_pack1(panedWin, tree1, TRUE, TRUE); } - else if (numTrees == 2) + else { - /* Two panes, two trees. Easy - put one in each. */ - GtkWidget *tree1 = GTK_WIDGET(treeList->data); - GtkWidget *tree2 = GTK_WIDGET(treeList->next->data); - - gtk_paned_pack1(GTK_PANED(detailView), tree1, TRUE, TRUE); - gtk_paned_pack2(GTK_PANED(detailView), tree2, TRUE, TRUE); - } - else if (numTrees > 2) - { - /* Two panes, three trees. Put one tree in pane 1. There should be a - * nested widget in pane 2 that we can put the remaining trees in. */ - GtkWidget *tree1 = GTK_WIDGET(treeList->data); - gtk_paned_pack1(GTK_PANED(detailView), tree1, TRUE, TRUE); - - GtkWidget *nestedPanedWidget = findNestedPanedWidget(detailView); - - if (nestedPanedWidget) - { - /* Create a new list containing the remaining trees and call this - * function again on the nested paned widget. */ - GList *remainingTrees = NULL; - GList *nextTree = treeList->next; - while (nextTree) - { - remainingTrees = g_list_append(remainingTrees, nextTree->data); - nextTree = nextTree->next; - } - - /* Pass 'first' as false to make sure we don't add any more headers */ - addTreesToDetailView(GTK_CONTAINER(nestedPanedWidget), remainingTrees, FALSE); - } + gtk_paned_pack2(panedWin, tree1, TRUE, TRUE); } } - else + else if (numTrees == 2) { - g_error("Unexpected detail view type: expected a paned widget. Could not add child trees.\n"); - } -} - - -/* Remove the given widget from the detail view. Does NOT remove nested paned - * widgets, but does remove THEIR children. */ -static void removeFromDetailView(GtkWidget *widget, gpointer data) -{ - GtkContainer *parent = GTK_CONTAINER(data); - - if (!GTK_IS_PANED(widget)) - { - gtk_container_remove(parent, widget); + /* Two panes, two trees. Easy - put one in each. */ + GtkWidget *tree1 = GTK_WIDGET(treeList->data); + GtkWidget *tree2 = GTK_WIDGET(treeList->next->data); + + gtk_paned_pack1(panedWin, tree1, TRUE, TRUE); + gtk_paned_pack2(panedWin, tree2, TRUE, TRUE); } - else + else if (numTrees > 2) { - /* This widget is a nested paned widget. Leave it in the heirarchy, but - * recurse to remove all its child widgets. */ - gtk_container_foreach(GTK_CONTAINER(widget), removeFromDetailView, widget); + /* Two panes, three trees. Put one tree in pane 1. There should be a + * nested widget in pane 2 that we can put the remaining trees in. */ + GtkWidget *tree1 = GTK_WIDGET(treeList->data); + gtk_paned_pack1(panedWin, tree1, TRUE, TRUE); + + GtkWidget *nestedPanedWidget = findNestedPanedWidget(GTK_CONTAINER(panedWin)); + + if (nestedPanedWidget) + { + /* Create a new list containing the remaining trees and call this + * function again on the nested paned widget. */ + GList *remainingTrees = NULL; + GList *nextTree = treeList->next; + while (nextTree) + { + remainingTrees = g_list_append(remainingTrees, nextTree->data); + nextTree = nextTree->next; + } + + /* Pass 'first' as false to make sure we don't add any more headers */ + addTreesToDetailViewPane(GTK_PANED(nestedPanedWidget), remainingTrees, FALSE); + } } } @@ -529,19 +503,31 @@ static void refreshTreeOrder(GtkWidget *detailView) BlxViewContext *bc = detailViewGetContext(detailView); gboolean toggled = detailViewGetDisplayRev(detailView); - gtk_container_foreach(GTK_CONTAINER(detailView), removeAllTreesFromContainer, detailView); + /* Get the direct parent of the trees */ + GtkWidget *detailViewContainer = getNamedChildWidget(detailView, DETAIL_VIEW_WIDGET_NAME); + + gtk_container_foreach(GTK_CONTAINER(detailView), removeAllTreesFromContainer, detailViewContainer); + + /* Extract the named detail-view widget, which is the direct parent of the trees. This + * should be a paned window. */ + GtkWidget *panedWin = getNamedChildWidget(detailView, DETAIL_VIEW_WIDGET_NAME); + + if (!GTK_IS_PANED(panedWin)) + { + g_error("Unexpected detail view type: expected a paned widget. Could not add child trees.\n"); + } if (bc->seqType == BLXSEQ_DNA) { /* Add both trees - the order they're added will depend on whether the display is toggled or not. */ - addTreesToDetailView(GTK_CONTAINER(detailView), properties->fwdStrandTrees, !toggled); - addTreesToDetailView(GTK_CONTAINER(detailView), properties->revStrandTrees, toggled); + addTreesToDetailViewPane(GTK_PANED(panedWin), properties->fwdStrandTrees, !toggled); + addTreesToDetailViewPane(GTK_PANED(panedWin), properties->revStrandTrees, toggled); } else if (bc->seqType == BLXSEQ_PEPTIDE) { /* Only add one set of trees - the reverse strand if toggled, the forward strand if not. */ GList *treeList = toggled ? properties->revStrandTrees : properties->fwdStrandTrees; - addTreesToDetailView(GTK_CONTAINER(detailView), treeList, TRUE); + addTreesToDetailViewPane(GTK_PANED(panedWin), treeList, TRUE); } /* Must show all child widgets because some of them may not have been in this parent before. @@ -3760,7 +3746,7 @@ static void buttonDetach(GtkHandleBox *handlebox, GtkWidget *toolbar, gpointer d * pointer to the actual toolbar and returns a pointer to the container of * the toolbar, if different (i.e. the widget that will be packed into the * parent container). */ -static GtkWidget* createEmptyButtonBar(GtkWidget *parent, GtkToolbar **toolbar) +static GtkWidget* createEmptyButtonBar(GtkToolbar **toolbar) { /* Create a handle box for the toolbar and add it to the window */ GtkWidget *handleBox = gtk_handle_box_new(); @@ -3952,7 +3938,7 @@ static GtkWidget* createDetailViewButtonBar(GtkWidget *detailView, GtkWidget **statusBar) { GtkToolbar *toolbar = NULL; - GtkWidget *toolbarContainer = createEmptyButtonBar(detailView, &toolbar); + GtkWidget *toolbarContainer = createEmptyButtonBar(&toolbar); /* Help */ makeToolbarButton(toolbar, "Help", GTK_STOCK_HELP, "Help (Ctrl-H)", (GtkSignalFunc)GHelp, detailView); @@ -4002,7 +3988,7 @@ static GtkWidget* createDetailViewButtonBar(GtkWidget *detailView, * given). The first tree gets associated with grid1 and appended to list1, and the second * with grid2 and list2. If hasHeaders is true, the first tree will have visible headers. */ static void createTwoPanedTrees(GtkWidget *detailView, - GtkWidget *container, + GtkPaned *panedWin, GtkCellRenderer *renderer, GtkWidget *grid1, GtkWidget *grid2, @@ -4018,10 +4004,10 @@ static void createTwoPanedTrees(GtkWidget *detailView, GtkWidget *tree1 = createDetailViewTree(grid1, detailView, renderer, list1, columnList, seqType, refSeqName, frame1, includeSnpTrack); GtkWidget *tree2 = createDetailViewTree(grid2, detailView, renderer, list2, columnList, seqType, refSeqName, frame2, includeSnpTrack); - if (container) + if (panedWin) { - gtk_paned_pack1(GTK_PANED(container), tree1, TRUE, TRUE); - gtk_paned_pack2(GTK_PANED(container), tree2, TRUE, TRUE); + gtk_paned_pack1(GTK_PANED(panedWin), tree1, TRUE, TRUE); + gtk_paned_pack2(GTK_PANED(panedWin), tree2, TRUE, TRUE); } } @@ -4030,6 +4016,7 @@ static void createTwoPanedTrees(GtkWidget *detailView, * two panes in the widget, so two of the trees will be placed in a second, nested * paned widget. */ static void createThreePanedTrees(GtkWidget *detailView, + GtkPaned *panedWin, GtkCellRenderer *renderer, GtkWidget *grid, GList **list, @@ -4045,14 +4032,14 @@ static void createThreePanedTrees(GtkWidget *detailView, * The first tree has headers. */ GtkWidget *tree1 = createDetailViewTree(grid, detailView, renderer, list, columnList, seqType, refSeqName, frame1, includeSnpTrack); - GtkWidget *nestedPanedWidget = NULL; + GtkPaned *nestedPanedWidget = NULL; if (addToDetailView) { - gtk_paned_pack1(GTK_PANED(detailView), tree1, TRUE, TRUE); + gtk_paned_pack1(GTK_PANED(panedWin), tree1, TRUE, TRUE); /* Create another paned widget and place it in pane 2 */ - nestedPanedWidget = gtk_vpaned_new(); - gtk_paned_pack2(GTK_PANED(detailView), nestedPanedWidget, TRUE, TRUE); + nestedPanedWidget = GTK_PANED(gtk_vpaned_new()); + gtk_paned_pack2(panedWin, GTK_WIDGET(nestedPanedWidget), TRUE, TRUE); } /* Create two more trees (and place them in the nested paned widget, if it is not null). @@ -4064,6 +4051,7 @@ static void createThreePanedTrees(GtkWidget *detailView, /* Create the trees for the detail view, creating sub-panes if necessary depending * on how many trees we need */ static void createDetailViewPanes(GtkWidget *detailView, + GtkPaned *panedWin, GtkCellRenderer *renderer, GtkWidget *fwdStrandGrid, GtkWidget *revStrandGrid, @@ -4079,7 +4067,7 @@ static void createDetailViewPanes(GtkWidget *detailView, { /* DNA matches: we need 2 trees, one for the forward strand and one for the reverse. */ createTwoPanedTrees(detailView, - detailView, + panedWin, renderer, fwdStrandGrid, revStrandGrid, @@ -4096,8 +4084,8 @@ static void createDetailViewPanes(GtkWidget *detailView, { /* Protein matches: we need 3 trees for the 3 reading frames for EACH strand (although only * one set of trees will be displayed at a time). */ - createThreePanedTrees(detailView, renderer, fwdStrandGrid, fwdStrandTrees, seqType, TRUE, columnList, refSeqName, includeSnpTrack); - createThreePanedTrees(detailView, renderer, revStrandGrid, revStrandTrees, seqType, FALSE, columnList, refSeqName, includeSnpTrack); + createThreePanedTrees(detailView, panedWin, renderer, fwdStrandGrid, fwdStrandTrees, seqType, TRUE, columnList, refSeqName, includeSnpTrack); + createThreePanedTrees(detailView, panedWin, renderer, revStrandGrid, revStrandTrees, seqType, FALSE, columnList, refSeqName, includeSnpTrack); } } @@ -4177,7 +4165,7 @@ static const char* findDetailViewFont(GtkWidget *detailView) GtkWidget* createDetailView(GtkWidget *blxWindow, - GtkWidget *container, + GtkContainer *parent, GtkAdjustment *adjustment, GtkWidget *fwdStrandGrid, GtkWidget *revStrandGrid, @@ -4196,7 +4184,11 @@ GtkWidget* createDetailView(GtkWidget *blxWindow, * trees might be a direct child of this or a grandchild/grand-grandchild, so we will need * to look at all children recursively and check if they're the correct type. (We'll give * all of our detail-view trees the same name so that we can identify them.) */ - GtkWidget *detailView = gtk_vpaned_new(); + GtkWidget *detailView = gtk_vbox_new(FALSE, 0); + gtk_container_add(parent, detailView); + + GtkWidget *panedWin = gtk_vpaned_new(); + gtk_widget_set_name(panedWin, DETAIL_VIEW_WIDGET_NAME); /* Create a custom cell renderer to render the sequences in the detail view */ GtkCellRenderer *renderer = sequence_cell_renderer_new(); @@ -4217,6 +4209,7 @@ GtkWidget* createDetailView(GtkWidget *blxWindow, /* Create the trees. */ GList *fwdStrandTrees = NULL, *revStrandTrees = NULL; createDetailViewPanes(detailView, + GTK_PANED(panedWin), renderer, fwdStrandGrid, revStrandGrid, @@ -4228,14 +4221,10 @@ GtkWidget* createDetailView(GtkWidget *blxWindow, refSeqName, !singleSnpTrack); - /* Put everything in a vbox, and pack it into the blixem window. */ - GtkWidget *vbox = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), buttonBar, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), header, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), detailView, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(detailView), buttonBar, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(detailView), header, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(detailView), panedWin, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(container), vbox, TRUE, TRUE, 0); - /* Connect signals */ gtk_widget_add_events(detailView, GDK_BUTTON_PRESS_MASK); g_signal_connect(G_OBJECT(detailView), "size-allocate", G_CALLBACK(onSizeAllocateDetailView), NULL); diff --git a/detailview.h b/detailview.h index 7abb778e29ced83e946dcbbd3dc4118c94c41963..4c0b7698f990f0235c8a39615ad25e339ac1d533 100644 --- a/detailview.h +++ b/detailview.h @@ -201,7 +201,7 @@ void drawHeaderChar(BlxViewContext *bc, GHashTable *intronBases); GtkWidget* createDetailView(GtkWidget *blxWindow, - GtkWidget *container, + GtkContainer *parent, GtkAdjustment *adjustment, GtkWidget *fwdStrandGrid, GtkWidget *revStrandGrid, diff --git a/exonview.c b/exonview.c index 198955b74530cab5de8357681e7ff1d5d7be8864..37a07e4cab9e8ad5ea903ee7ab23542423874948 100644 --- a/exonview.c +++ b/exonview.c @@ -444,6 +444,11 @@ void exonViewSetExpanded(GtkWidget *exonView, const gboolean expanded) } calculateExonViewHeight(exonView); + + /* It's probably overkill to call refreshGridOrder here but I can't seem to find another way + * to force the big picture pane to shrink to take into account newly-hidden exons */ + refreshGridOrder(properties->bigPicture); + bigPictureRedrawAll(properties->bigPicture); } diff --git a/utilities.c b/utilities.c index 0344ef1069925e7b1423a12d3413baea81b93cf5..dbf35c41cfbad90773fb7df21dcbe42afa8477d6 100644 --- a/utilities.c +++ b/utilities.c @@ -1846,6 +1846,32 @@ gboolean isWhitespaceChar(const char curChar) } +/* Get the child of the given widget that has the given name (which could be the given + * widget itself.) Assumes there is only one, so returns the first one found. */ +GtkWidget* getNamedChildWidget(GtkWidget *widget, const gchar *searchName) +{ + GtkWidget *result = NULL; + const gchar *widgetName = gtk_widget_get_name(widget); + + if (stringsEqual(widgetName, searchName, TRUE)) + { + result = widget; + } + else if (GTK_IS_CONTAINER(widget)) + { + /* recurse over children until we find the detail view (assumes there is only one!) */ + GList *child = gtk_container_get_children(GTK_CONTAINER(widget)); + + for ( ; child && !result; child = child->next) + { + GtkWidget *childWidget = GTK_WIDGET(child->data); + result = getNamedChildWidget(childWidget, searchName); + } + } + + return result; +} + /*********************************************************** * Dialogs * ***********************************************************/ diff --git a/utilities.h b/utilities.h index ea0a84b3e3d48060093c8c4b1101fbc952b62936..529af30c0e29832e14af9d4a44070a567a917e54 100644 --- a/utilities.h +++ b/utilities.h @@ -330,6 +330,8 @@ int parseMatchLine(const char *inputText, GList* parseMatchList(const char *inputText); +GtkWidget* getNamedChildWidget(GtkWidget *widget, const gchar *searchName); + gint runConfirmationBox(GtkWidget *blxWindow, char *title, char *messageText); const char* getSeqVariantName(const char *longName);