~alextee/zrythm-devel

popover track creation menu for "add" button v1 APPLIED

Robert Panovics: 1
 popover track creation menu for "add" button

 10 files changed, 321 insertions(+), 64 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~alextee/zrythm-devel/patches/31322/mbox | git am -3
Learn more about email & git

[PATCH] popover track creation menu for "add" button Export this patch

A common popover menu is added to tracklist and mixer add button.

Signed-off-by: Robert Panovics <robert.panovics@gmail.com>
---
 inc/gui/widgets/add_track_menu_button.h |  89 ++++++++++++++++
 inc/gui/widgets/mixer.h                 |   6 +-
 inc/gui/widgets/tracklist.h             |  10 ++
 resources/ui/mixer.ui                   |  14 +--
 src/gui/widgets/add_track_menu_button.c | 129 ++++++++++++++++++++++++
 src/gui/widgets/bot_dock_edge.c         |   4 -
 src/gui/widgets/drag_dest_box.c         |  45 +--------
 src/gui/widgets/meson.build             |   1 +
 src/gui/widgets/mixer.c                 |  12 ++-
 src/gui/widgets/tracklist.c             |  75 ++++++++++++++
 10 files changed, 321 insertions(+), 64 deletions(-)
 create mode 100644 inc/gui/widgets/add_track_menu_button.h
 create mode 100644 src/gui/widgets/add_track_menu_button.c

diff --git a/inc/gui/widgets/add_track_menu_button.h b/inc/gui/widgets/add_track_menu_button.h
new file mode 100644
index 000000000..89ea83c2e
--- /dev/null
+++ b/inc/gui/widgets/add_track_menu_button.h
@@ -0,0 +1,89 @@
/*
 * Copyright (C) 2022 Robert Panovics <robert dot panovics at gmail dot com>
 *
 * This file is part of Zrythm
 *
 * Zrythm is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Zrythm 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Zrythm.  If not, see <https://www.gnu.org/licenses/>.
 */

/**
 * \file
 *
 * Button with a popover menu to add new tracks
 */

#ifndef __GUI_WIDGETS_ADD_TRACK_MENU_BUTTON_H__
#define __GUI_WIDGETS_ADD_TRACK_MENU_BUTTON_H__

#include <stdbool.h>

#include <gtk/gtk.h>

#define ADD_TRACK_MENU_BUTTON_WIDGET_TYPE \
  (add_track_menu_button_widget_get_type ())
G_DECLARE_FINAL_TYPE (
  AddTrackMenuButtonWidget,
  add_track_menu_button_widget,
  Z,
  ADD_TRACK_MENU_BUTTON_WIDGET,
  GtkWidget)

/**
 * @addtogroup widgets
 *
 * @{
 */

/**
 * Button with a popover menu.
 */
typedef struct _AddTrackMenuButtonWidget
{
  GtkWidget parent_instance;

  GtkMenuButton * menu_btn;

} AddTrackMenuButtonWidget;

void
add_track_menu_button_widget_set_menu_model (
  AddTrackMenuButtonWidget * self,
  GMenuModel *               gmenu_model);

/**
 * Set a custom popover instead of a menu model.
 */
void
add_track_menu_button_widget_set_popover (
  AddTrackMenuButtonWidget * self,
  GtkPopover *               popover);

/**
 * This must only be called once to set up the
 * widget.
 */
void
add_track_menu_button_widget_setup (
  AddTrackMenuButtonWidget * self,
  int                        height,
  const char *               menu_tooltip_text);

AddTrackMenuButtonWidget *
add_track_menu_button_widget_new (void);

/**
 * @}
 */

#endif
diff --git a/inc/gui/widgets/mixer.h b/inc/gui/widgets/mixer.h
index fd682da5c..0117d4709 100644
--- a/inc/gui/widgets/mixer.h
+++ b/inc/gui/widgets/mixer.h
@@ -34,6 +34,8 @@ typedef struct _DragDestBoxWidget DragDestBoxWidget;
typedef struct Channel            Channel;
typedef struct _ChannelSlotWidget ChannelSlotWidget;
typedef struct Track              Track;
typedef struct _AddTrackMenuButtonWidget
  AddTrackMenuButtonWidget;

/**
 * @addtogroup widgets
@@ -72,8 +74,8 @@ typedef struct _MixerWidget
   */
  Track * start_drag_track;

  GtkButton * channels_add;
  GtkBox *    master_box;
  AddTrackMenuButtonWidget * channels_add;
  GtkBox *                   master_box;

  /**
   * Selected slot to paste selections (when
diff --git a/inc/gui/widgets/tracklist.h b/inc/gui/widgets/tracklist.h
index a6f90e74f..4ee307e92 100644
--- a/inc/gui/widgets/tracklist.h
+++ b/inc/gui/widgets/tracklist.h
@@ -46,6 +46,8 @@ typedef struct _DragDestBoxWidget DragDestBoxWidget;
typedef struct _ChordTrackWidget  ChordTrackWidget;
typedef struct Track              InstrumentTrack;
typedef struct Tracklist          Tracklist;
typedef struct _AddTrackMenuButtonWidget
  AddTrackMenuButtonWidget;

/**
 * The TracklistWidget holds all the Track's
@@ -79,6 +81,8 @@ typedef struct _TracklistWidget
   */
  Tracklist * tracklist;

  AddTrackMenuButtonWidget * channel_add;

  /** Size group to set the pinned track box and
   * the pinned timeline to the same height. */
  GtkSizeGroup * pinned_size_group;
@@ -114,6 +118,12 @@ void
tracklist_widget_update_track_visibility (
  TracklistWidget * self);

/**
 * Generates a menu for adding tracks to the tracklist.
 */
GMenu *
tracklist_widget_generate_add_track_menu ();

/**
 * Gets hit TrackWidget and the given coordinates.
 */
diff --git a/resources/ui/mixer.ui b/resources/ui/mixer.ui
index c5dfadd99..90582fcd7 100644
--- a/resources/ui/mixer.ui
+++ b/resources/ui/mixer.ui
@@ -10,19 +10,7 @@
        <property name="child">
          <object class="GtkViewport">
            <property name="child">
              <object class="GtkBox" id="channels_box">
                <child>
                  <object class="GtkButton" id="channels_add">
                    <property name="focusable">1</property>
                    <property name="receives_default">1</property>
                    <child>
                      <object class="GtkImage">
                        <property name="icon_name">plus</property>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
              <object class="GtkBox" id="channels_box"/>
            </property>
          </object>
        </property>
diff --git a/src/gui/widgets/add_track_menu_button.c b/src/gui/widgets/add_track_menu_button.c
new file mode 100644
index 000000000..4592105a6
--- /dev/null
+++ b/src/gui/widgets/add_track_menu_button.c
@@ -0,0 +1,129 @@
// SPDX-FileCopyrightText: © 2022 Robert Panovics <robert dot panovics at gmail dot com>
// SPDX-License-Identifier: LicenseRef-ZrythmLicense

#include "gui/widgets/add_track_menu_button.h"

#include <gtk/gtk.h>

G_DEFINE_TYPE (
  AddTrackMenuButtonWidget,
  add_track_menu_button_widget,
  GTK_TYPE_WIDGET)

void
add_track_menu_button_widget_set_menu_model (
  AddTrackMenuButtonWidget * self,
  GMenuModel *               gmenu_model)
{
  GMenuModel * existing_model =
    gtk_menu_button_get_menu_model (self->menu_btn);
  if (existing_model != gmenu_model)
    {
      gtk_menu_button_set_menu_model (
        self->menu_btn, gmenu_model);
      gtk_popover_set_position (
        gtk_menu_button_get_popover (self->menu_btn),
        GTK_POS_RIGHT);
    }
}

/**
 * Set a custom popover instead of a menu model.
 */
void
add_track_menu_button_widget_set_popover (
  AddTrackMenuButtonWidget * self,
  GtkPopover *               popover)
{
  gtk_menu_button_set_popover (
    self->menu_btn, GTK_WIDGET (popover));
}

/**
 * This must only be called once to set up the
 * widget.
 *
 * @param menu Optional GMenuModel to set for the
 *   arrow button.
 */
void
add_track_menu_button_widget_setup (
  AddTrackMenuButtonWidget * self,
  int                        height,
  const char *               menu_tooltip_text)
{
  self->menu_btn =
    GTK_MENU_BUTTON (gtk_menu_button_new ());

  gtk_widget_add_css_class (
    GTK_WIDGET (self), "linked");
  gtk_widget_add_css_class (
    GTK_WIDGET (self), "add_track_menu_button");

  /* int width;
  gtk_widget_get_size_request (
    GTK_WIDGET (btn), &width, NULL);
  gtk_widget_set_size_request (
    GTK_WIDGET (btn), width, height);
  gtk_widget_set_size_request (
    GTK_WIDGET (self->menu_btn), -1, height);
    */

  gtk_widget_set_tooltip_text (
    GTK_WIDGET (self->menu_btn), menu_tooltip_text);
}

AddTrackMenuButtonWidget *
add_track_menu_button_widget_new (void)
{
  return g_object_new (
    ADD_TRACK_MENU_BUTTON_WIDGET_TYPE, NULL);
}

static void
dispose (AddTrackMenuButtonWidget * self)
{
  gtk_widget_unparent (GTK_WIDGET (self->menu_btn));

  G_OBJECT_CLASS (
    add_track_menu_button_widget_parent_class)
    ->dispose (G_OBJECT (self));
}

static void
finalize (AddTrackMenuButtonWidget * self)
{
  G_OBJECT_CLASS (
    add_track_menu_button_widget_parent_class)
    ->finalize (G_OBJECT (self));
}

static void
add_track_menu_button_widget_init (
  AddTrackMenuButtonWidget * self)
{
  gtk_widget_set_focusable (
    GTK_WIDGET (self), true);

  self->menu_btn =
    GTK_MENU_BUTTON (gtk_menu_button_new ());
  gtk_menu_button_set_icon_name (
    self->menu_btn, "add");
  gtk_widget_set_parent (
    GTK_WIDGET (self->menu_btn), GTK_WIDGET (self));
}

static void
add_track_menu_button_widget_class_init (
  AddTrackMenuButtonWidgetClass * _klass)
{
  GObjectClass *   klass = G_OBJECT_CLASS (_klass);
  GtkWidgetClass * wklass =
    GTK_WIDGET_CLASS (_klass);

  gtk_widget_class_set_layout_manager_type (
    wklass, GTK_TYPE_BIN_LAYOUT);

  klass->dispose = (GObjectFinalizeFunc) dispose;
  klass->finalize = (GObjectFinalizeFunc) finalize;
}
diff --git a/src/gui/widgets/bot_dock_edge.c b/src/gui/widgets/bot_dock_edge.c
index 6fc81987d..2df1c7896 100644
--- a/src/gui/widgets/bot_dock_edge.c
+++ b/src/gui/widgets/bot_dock_edge.c
@@ -318,10 +318,6 @@ bot_dock_edge_widget_init (BotDockEdgeWidget * self)
    GTK_ORIENTATION_VERTICAL);

  generate_bot_notebook (self);

  /* set icons */
  gtk_button_set_icon_name (
    GTK_BUTTON (self->mixer->channels_add), "add");
}

static void
diff --git a/src/gui/widgets/drag_dest_box.c b/src/gui/widgets/drag_dest_box.c
index cd094ca50..c186ff941 100644
--- a/src/gui/widgets/drag_dest_box.c
+++ b/src/gui/widgets/drag_dest_box.c
@@ -437,50 +437,7 @@ show_context_menu (
  double              x,
  double              y)
{
  GMenu *     menu = g_menu_new ();
  GMenuItem * menuitem;

  menuitem = z_gtk_create_menu_item (
    _ ("Add _MIDI Track"), NULL,
    "app.create-midi-track");
  g_menu_append_item (menu, menuitem);

  menuitem = z_gtk_create_menu_item (
    _ ("Add Audio Track"), NULL,
    "app.create-audio-track");
  g_menu_append_item (menu, menuitem);

  GMenu * bus_submenu = g_menu_new ();
  menuitem = z_gtk_create_menu_item (
    _ (track_type_to_string (TRACK_TYPE_AUDIO_BUS)),
    NULL, "app.create-audio-bus-track");
  g_menu_append_item (bus_submenu, menuitem);
  menuitem = z_gtk_create_menu_item (
    _ (track_type_to_string (TRACK_TYPE_MIDI_BUS)),
    NULL, "app.create-midi-bus-track");
  g_menu_append_item (bus_submenu, menuitem);
  g_menu_append_section (
    menu, _ ("Add FX Track"),
    G_MENU_MODEL (bus_submenu));

  GMenu * group_submenu = g_menu_new ();
  menuitem = z_gtk_create_menu_item (
    _ (track_type_to_string (
      TRACK_TYPE_AUDIO_GROUP)),
    NULL, "app.create-audio-group-track");
  g_menu_append_item (group_submenu, menuitem);
  menuitem = z_gtk_create_menu_item (
    _ (track_type_to_string (TRACK_TYPE_MIDI_GROUP)),
    NULL, "app.create-midi-group-track");
  g_menu_append_item (group_submenu, menuitem);
  g_menu_append_section (
    menu, _ ("Add Group Track"),
    G_MENU_MODEL (group_submenu));

  menuitem = z_gtk_create_menu_item (
    _ ("Add Folder Track"), NULL,
    "app.create-folder-track");
  g_menu_append_item (menu, menuitem);
  GMenu *     menu = tracklist_widget_generate_add_track_menu();

  z_gtk_show_context_menu_from_g_menu (
    self->popover_menu, x, y, menu);
diff --git a/src/gui/widgets/meson.build b/src/gui/widgets/meson.build
index fe5283def..a75fc1b88 100644
--- a/src/gui/widgets/meson.build
+++ b/src/gui/widgets/meson.build
@@ -4,6 +4,7 @@
widget_srcs = files([
  'active_hardware_mb.c',
  'active_hardware_popover.c',
  'add_track_menu_button.c',
  'arranger.c',
  'arranger_draw.c',
  'arranger_object.c',
diff --git a/src/gui/widgets/mixer.c b/src/gui/widgets/mixer.c
index b3abb607b..8b3bddb2e 100644
--- a/src/gui/widgets/mixer.c
+++ b/src/gui/widgets/mixer.c
@@ -19,6 +19,7 @@

#include "audio/channel.h"
#include "audio/track.h"
#include "gui/widgets/add_track_menu_button.h"
#include "gui/widgets/bot_dock_edge.h"
#include "gui/widgets/center_dock.h"
#include "gui/widgets/channel.h"
@@ -217,7 +218,6 @@ mixer_widget_class_init (MixerWidgetClass * _klass)
    klass, MixerWidget, x)

  BIND_CHILD (channels_box);
  BIND_CHILD (channels_add);
  BIND_CHILD (master_box);

#undef BIND_CHILD
@@ -230,6 +230,16 @@ mixer_widget_init (MixerWidget * self)

  gtk_widget_init_template (GTK_WIDGET (self));

  self->channels_add =
    add_track_menu_button_widget_new ();
  gtk_widget_set_name (
    GTK_WIDGET (self->channels_add),
    "mixer-add-channel");
  add_track_menu_button_widget_set_menu_model (
    self->channels_add,
    G_MENU_MODEL (
      tracklist_widget_generate_add_track_menu ()));

  /* add dummy box for dnd */
  self->ddbox = drag_dest_box_widget_new (
    GTK_ORIENTATION_HORIZONTAL, 0,
diff --git a/src/gui/widgets/tracklist.c b/src/gui/widgets/tracklist.c
index 362439b03..375e8ace5 100644
--- a/src/gui/widgets/tracklist.c
+++ b/src/gui/widgets/tracklist.c
@@ -28,6 +28,7 @@
#include "gui/backend/event.h"
#include "gui/backend/event_manager.h"
#include "gui/backend/wrapped_object_with_change_signal.h"
#include "gui/widgets/add_track_menu_button.h"
#include "gui/widgets/bot_dock_edge.h"
#include "gui/widgets/center_dock.h"
#include "gui/widgets/channel.h"
@@ -46,11 +47,64 @@
#include "utils/ui.h"
#include "zrythm_app.h"

#include <glib/gi18n.h>

G_DEFINE_TYPE (
  TracklistWidget,
  tracklist_widget,
  GTK_TYPE_BOX)

GMenu *
tracklist_widget_generate_add_track_menu ()
{
  GMenu *     menu = g_menu_new ();
  GMenuItem * menuitem;

  menuitem = z_gtk_create_menu_item (
    _ ("Add _MIDI Track"), NULL,
    "app.create-midi-track");
  g_menu_append_item (menu, menuitem);

  menuitem = z_gtk_create_menu_item (
    _ ("Add Audio Track"), NULL,
    "app.create-audio-track");
  g_menu_append_item (menu, menuitem);

  GMenu * bus_submenu = g_menu_new ();
  menuitem = z_gtk_create_menu_item (
    _ (track_type_to_string (TRACK_TYPE_AUDIO_BUS)),
    NULL, "app.create-audio-bus-track");
  g_menu_append_item (bus_submenu, menuitem);
  menuitem = z_gtk_create_menu_item (
    _ (track_type_to_string (TRACK_TYPE_MIDI_BUS)),
    NULL, "app.create-midi-bus-track");
  g_menu_append_item (bus_submenu, menuitem);
  g_menu_append_section (
    menu, _ ("Add FX Track"),
    G_MENU_MODEL (bus_submenu));

  GMenu * group_submenu = g_menu_new ();
  menuitem = z_gtk_create_menu_item (
    _ (track_type_to_string (
      TRACK_TYPE_AUDIO_GROUP)),
    NULL, "app.create-audio-group-track");
  g_menu_append_item (group_submenu, menuitem);
  menuitem = z_gtk_create_menu_item (
    _ (track_type_to_string (TRACK_TYPE_MIDI_GROUP)),
    NULL, "app.create-midi-group-track");
  g_menu_append_item (group_submenu, menuitem);
  g_menu_append_section (
    menu, _ ("Add Group Track"),
    G_MENU_MODEL (group_submenu));

  menuitem = z_gtk_create_menu_item (
    _ ("Add Folder Track"), NULL,
    "app.create-folder-track");
  g_menu_append_item (menu, menuitem);

  return menu;
}

static void
on_dnd_leave (
  GtkDropTarget *   drop_target,
@@ -394,6 +448,7 @@ tracklist_widget_hard_refresh (
{
  g_debug ("hard refreshing tracklist");

  g_object_ref (self->channel_add);
  g_object_ref (self->ddbox);

  /* remove all children */
@@ -421,6 +476,15 @@ tracklist_widget_hard_refresh (
          GTK_WIDGET (track->widget));
    }

  /* re-add chanel_add */
  g_return_if_fail (
    gtk_widget_get_parent (
      GTK_WIDGET (self->channel_add))
    == NULL);
  gtk_box_append (
    GTK_BOX (self->unpinned_box),
    GTK_WIDGET (self->channel_add));

  /* re-add ddbox */
  g_return_if_fail (
    gtk_widget_get_parent (GTK_WIDGET (self->ddbox))
@@ -429,6 +493,7 @@ tracklist_widget_hard_refresh (
    GTK_BOX (self->unpinned_box),
    GTK_WIDGET (self->ddbox));

  g_object_unref (self->channel_add);
  g_object_unref (self->ddbox);

  g_debug ("done hard refreshing tracklist");
@@ -561,6 +626,16 @@ tracklist_widget_init (TracklistWidget * self)
  gtk_widget_set_name (
    GTK_WIDGET (self->ddbox), "tracklist-ddbox");

  self->channel_add =
    add_track_menu_button_widget_new ();
  gtk_widget_set_name (
    GTK_WIDGET (self->channel_add),
    "tracklist-add-channel");
  add_track_menu_button_widget_set_menu_model (
    self->channel_add,
    G_MENU_MODEL (
      tracklist_widget_generate_add_track_menu ()));

  gtk_orientable_set_orientation (
    GTK_ORIENTABLE (self),
    GTK_ORIENTATION_VERTICAL);
-- 
2.35.1
Thanks! Applied with the following changes:

diff --git a/inc/gui/widgets/add_track_menu_button.h
b/inc/gui/widgets/add_track_menu_button.h
index 89ea83c2e..d7832611f 100644
--- a/inc/gui/widgets/add_track_menu_button.h
+++ b/inc/gui/widgets/add_track_menu_button.h
@@ -1,21 +1,5 @@
-/*
- * Copyright (C) 2022 Robert Panovics <robert dot panovics at gmail
dot com>
- *
- * This file is part of Zrythm
- *
- * Zrythm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Zrythm 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
License
- * along with Zrythm.  If not, see <https://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: © 2022 Robert Panovics <robert dot panovics
at gmail dot com>
+// SPDX-License-Identifier: LicenseRef-ZrythmLicense
 
 /**
  * \file
@@ -56,29 +40,6 @@ typedef struct _AddTrackMenuButtonWidget
 
 } AddTrackMenuButtonWidget;
 
-void
-add_track_menu_button_widget_set_menu_model (
-  AddTrackMenuButtonWidget * self,
-  GMenuModel *               gmenu_model);
-
-/**
- * Set a custom popover instead of a menu model.
- */
-void
-add_track_menu_button_widget_set_popover (
-  AddTrackMenuButtonWidget * self,
-  GtkPopover *               popover);
-
-/**
- * This must only be called once to set up the
- * widget.
- */
-void
-add_track_menu_button_widget_setup (
-  AddTrackMenuButtonWidget * self,
-  int                        height,
-  const char *               menu_tooltip_text);
-
 AddTrackMenuButtonWidget *
 add_track_menu_button_widget_new (void);
 
diff --git a/inc/gui/widgets/tracklist.h b/inc/gui/widgets/tracklist.h
index 4ee307e92..3c05f1513 100644
--- a/inc/gui/widgets/tracklist.h
+++ b/inc/gui/widgets/tracklist.h
@@ -1,21 +1,5 @@
-/*
- * Copyright (C) 2019-2021 Alexandros Theodotou <alex at zrythm dot
org>
- *
- * This file is part of Zrythm
- *
- * Zrythm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Zrythm 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
License
- * along with Zrythm.  If not, see <https://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: © 2019-2021 Alexandros Theodotou
<alex@zrythm.org>
+// SPDX-License-Identifier: LicenseRef-ZrythmLicense
 
 #ifndef __GUI_WIDGETS_TRACKLIST_H__
 #define __GUI_WIDGETS_TRACKLIST_H__
@@ -122,7 +106,7 @@ tracklist_widget_update_track_visibility (
  * Generates a menu for adding tracks to the tracklist.
  */
 GMenu *
-tracklist_widget_generate_add_track_menu ();
+tracklist_widget_generate_add_track_menu (void);
 
 /**
  * Gets hit TrackWidget and the given coordinates.
diff --git a/resources/ui/mixer.ui b/resources/ui/mixer.ui
index 90582fcd7..6d55b30f3 100644
--- a/resources/ui/mixer.ui
+++ b/resources/ui/mixer.ui
@@ -10,7 +10,12 @@
         <property name="child">
           <object class="GtkViewport">
             <property name="child">
-              <object class="GtkBox" id="channels_box"/>
+              <object class="GtkBox" id="channels_box">
+                <child>
+                  <object class="AddTrackMenuButtonWidget"
id="channels_add">
+                  </object>
+                </child>
+              </object>
             </property>
           </object>
         </property>
diff --git a/src/gui/widgets/add_track_menu_button.c
b/src/gui/widgets/add_track_menu_button.c
index 4592105a6..7dc27dce7 100644
--- a/src/gui/widgets/add_track_menu_button.c
+++ b/src/gui/widgets/add_track_menu_button.c
@@ -1,8 +1,11 @@
+// SPDX-FileCopyrightText: © 2022 Alexandros Theodotou
<alex@zrythm.org>
 // SPDX-FileCopyrightText: © 2022 Robert Panovics <robert dot panovics
at gmail dot com>
 // SPDX-License-Identifier: LicenseRef-ZrythmLicense
 
 #include "gui/widgets/add_track_menu_button.h"
+#include "gui/widgets/tracklist.h"
 
+#include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
 G_DEFINE_TYPE (
@@ -10,67 +13,16 @@ G_DEFINE_TYPE (
   add_track_menu_button_widget,
   GTK_TYPE_WIDGET)
 
-void
-add_track_menu_button_widget_set_menu_model (
-  AddTrackMenuButtonWidget * self,
-  GMenuModel *               gmenu_model)
-{
-  GMenuModel * existing_model =
-    gtk_menu_button_get_menu_model (self->menu_btn);
-  if (existing_model != gmenu_model)
-    {
-      gtk_menu_button_set_menu_model (
-        self->menu_btn, gmenu_model);
-      gtk_popover_set_position (
-        gtk_menu_button_get_popover (self->menu_btn),
-        GTK_POS_RIGHT);
-    }
-}
-
-/**
- * Set a custom popover instead of a menu model.
- */
-void
-add_track_menu_button_widget_set_popover (
-  AddTrackMenuButtonWidget * self,
-  GtkPopover *               popover)
+static void
+set_menu_model (GtkMenuButton * menu_btn)
 {
-  gtk_menu_button_set_popover (
-    self->menu_btn, GTK_WIDGET (popover));
-}
-
-/**
- * This must only be called once to set up the
- * widget.
- *
- * @param menu Optional GMenuModel to set for the
- *   arrow button.
- */
-void
-add_track_menu_button_widget_setup (
-  AddTrackMenuButtonWidget * self,
-  int                        height,
-  const char *               menu_tooltip_text)
-{
-  self->menu_btn =
-    GTK_MENU_BUTTON (gtk_menu_button_new ());
-
-  gtk_widget_add_css_class (
-    GTK_WIDGET (self), "linked");
-  gtk_widget_add_css_class (
-    GTK_WIDGET (self), "add_track_menu_button");
-
-  /* int width;
-  gtk_widget_get_size_request (
-    GTK_WIDGET (btn), &width, NULL);
-  gtk_widget_set_size_request (
-    GTK_WIDGET (btn), width, height);
-  gtk_widget_set_size_request (
-    GTK_WIDGET (self->menu_btn), -1, height);
-    */
-
-  gtk_widget_set_tooltip_text (
-    GTK_WIDGET (self->menu_btn), menu_tooltip_text);
+  GMenuModel * menu_model = G_MENU_MODEL (
+    tracklist_widget_generate_add_track_menu ());
+  gtk_menu_button_set_menu_model (
+    menu_btn, menu_model);
+  gtk_popover_set_position (
+    gtk_menu_button_get_popover (menu_btn),
+    GTK_POS_RIGHT);
 }
 
 AddTrackMenuButtonWidget *
@@ -107,6 +59,11 @@ add_track_menu_button_widget_init (
 
   self->menu_btn =
     GTK_MENU_BUTTON (gtk_menu_button_new ());
+  set_menu_model (self->menu_btn);
+  gtk_widget_add_css_class (
+    GTK_WIDGET (self), "add-track-menu-button");
+  gtk_widget_set_tooltip_text (
+    GTK_WIDGET (self->menu_btn), _ ("Add track"));
   gtk_menu_button_set_icon_name (
     self->menu_btn, "add");
   gtk_widget_set_parent (
diff --git a/src/gui/widgets/drag_dest_box.c
b/src/gui/widgets/drag_dest_box.c
index c186ff941..2565d314c 100644
--- a/src/gui/widgets/drag_dest_box.c
+++ b/src/gui/widgets/drag_dest_box.c
@@ -437,7 +437,8 @@ show_context_menu (
   double              x,
   double              y)
 {
-  GMenu *     menu = tracklist_widget_generate_add_track_menu();
+  GMenu * menu =
+    tracklist_widget_generate_add_track_menu ();
 
   z_gtk_show_context_menu_from_g_menu (
     self->popover_menu, x, y, menu);
diff --git a/src/gui/widgets/mixer.c b/src/gui/widgets/mixer.c
index 8b3bddb2e..2d8cb1816 100644
--- a/src/gui/widgets/mixer.c
+++ b/src/gui/widgets/mixer.c
@@ -218,6 +218,7 @@ mixer_widget_class_init (MixerWidgetClass * _klass)
     klass, MixerWidget, x)
 
   BIND_CHILD (channels_box);
+  BIND_CHILD (channels_add);
   BIND_CHILD (master_box);
 
 #undef BIND_CHILD
@@ -227,18 +228,13 @@ static void
 mixer_widget_init (MixerWidget * self)
 {
   g_type_ensure (DRAG_DEST_BOX_WIDGET_TYPE);
+  g_type_ensure (ADD_TRACK_MENU_BUTTON_WIDGET_TYPE);
 
   gtk_widget_init_template (GTK_WIDGET (self));
 
-  self->channels_add =
-    add_track_menu_button_widget_new ();
   gtk_widget_set_name (
     GTK_WIDGET (self->channels_add),
     "mixer-add-channel");
-  add_track_menu_button_widget_set_menu_model (
-    self->channels_add,
-    G_MENU_MODEL (
-      tracklist_widget_generate_add_track_menu ()));
 
   /* add dummy box for dnd */
   self->ddbox = drag_dest_box_widget_new (
diff --git a/src/gui/widgets/tracklist.c b/src/gui/widgets/tracklist.c
index 375e8ace5..6acaf6967 100644
--- a/src/gui/widgets/tracklist.c
+++ b/src/gui/widgets/tracklist.c
@@ -631,10 +631,6 @@ tracklist_widget_init (TracklistWidget * self)
   gtk_widget_set_name (
     GTK_WIDGET (self->channel_add),
     "tracklist-add-channel");
-  add_track_menu_button_widget_set_menu_model (
-    self->channel_add,
-    G_MENU_MODEL (
-      tracklist_widget_generate_add_track_menu ()));
 
   gtk_orientable_set_orientation (
     GTK_ORIENTABLE (self),