Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add command palette #1160

Merged
merged 38 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
231853c
Command palette - part 1
yohannd1 Jun 15, 2023
224577c
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Jun 17, 2023
56874dd
command palette: recent file support
yohannd1 Jun 19, 2023
91e7b90
command palette: reducing code repetition
yohannd1 Jun 19, 2023
66fbc1f
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Jun 20, 2023
869e5d7
command palette: get rid of "extra actions" enum
yohannd1 Jul 1, 2023
55d791f
command palette: improve checks on item selection
yohannd1 Jul 1, 2023
e454433
command palette: replace some to-dos with errors
yohannd1 Jul 1, 2023
60de8b0
command palette: (breaking) attempt to center the window
yohannd1 Jul 3, 2023
b19f7cf
command palette: now a modal + proper sizing&centering
yohannd1 Jul 3, 2023
d45827f
command palette: not a modal anymore, but a working popup
yohannd1 Jul 3, 2023
81fd5a2
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Jul 12, 2023
30c1a69
command palette: scroll to the beginning when the palette opens
yohannd1 Jul 12, 2023
f3902e1
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Jul 25, 2023
8b8f908
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Jul 31, 2023
00ee722
command palette: fixed recent files history bug
yohannd1 Jul 31, 2023
51148a7
command palette: instrument and sample menus
yohannd1 Jul 31, 2023
b203c39
command palette: improved consistency
yohannd1 Jul 31, 2023
74bb1b1
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Aug 15, 2023
0060ea5
command palette: support for changing (selection's) instrument
yohannd1 Aug 15, 2023
aff6996
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Aug 20, 2023
4f83fc2
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Aug 27, 2023
7e9edb5
command palette: "add chip" menu
yohannd1 Aug 27, 2023
5a5090f
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Sep 4, 2023
163d1b2
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Oct 29, 2023
a495817
command palette: change instrument menu: better naming
yohannd1 Oct 29, 2023
0d17280
changes to GUI action names
yohannd1 Nov 23, 2023
b1dd947
command palette: small fix to instrument search
yohannd1 Dec 18, 2023
c8975ea
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Dec 19, 2023
34e18ff
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Dec 27, 2023
b9c51c5
whoops
yohannd1 Dec 28, 2023
8ab1c41
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Jan 18, 2024
c9d57d4
Merge branch 'master' of https://github.com/tildearrow/furnace into c…
yohannd1 Feb 3, 2024
a2e20ff
update extern/fmt
yohannd1 Feb 4, 2024
aba64d2
command palette: update copyright year to 2024
yohannd1 Feb 4, 2024
477b331
command palette: minor style changes
yohannd1 Feb 5, 2024
f08ef30
command palette: instrument number should be in hex
yohannd1 Feb 5, 2024
266a35f
command palette: whoops!! (hex instrument numbers)
yohannd1 Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,7 @@ src/gui/log.cpp
src/gui/mixer.cpp
src/gui/midiMap.cpp
src/gui/newSong.cpp
src/gui/commandPalette.cpp
src/gui/orders.cpp
src/gui/osc.cpp
src/gui/patManager.cpp
Expand Down
253 changes: 253 additions & 0 deletions src/gui/commandPalette.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "gui.h"
#include "guiConst.h"
#include "commandPalette.h"
#include "misc/cpp/imgui_stdlib.h"
#include <fmt/printf.h>
#include <algorithm>
#include <ctype.h>
#include "../ta-log.h"

static inline bool matchFuzzy(const char* haystack, const char* needle) {
size_t h_i=0; // haystack idx
size_t n_i=0; // needle idx
while (needle[n_i]!='\0') {
for (; std::tolower(haystack[h_i])!=std::tolower(needle[n_i]); h_i++) {
if (haystack[h_i]=='\0')
return false;
}
n_i+=1;
}
return true;
}

void FurnaceGUI::drawPalette() {
bool accepted=false;

if (paletteFirstFrame)
ImGui::SetKeyboardFocusHere();

int width=ImGui::GetContentRegionAvail().x;
ImGui::SetNextItemWidth(width);

const char* hint="Search...";
switch (curPaletteType) {
case CMDPAL_TYPE_RECENT:
hint="Search recent files...";
break;
case CMDPAL_TYPE_INSTRUMENTS:
hint="Search instruments...";
break;
case CMDPAL_TYPE_SAMPLES:
hint="Search samples...";
break;
case CMDPAL_TYPE_INSTRUMENT_CHANGE:
hint="Search instruments (to change to)...";
break;
case CMDPAL_TYPE_ADD_CHIP:
hint="Search chip (to add)...";
break;
}

if (ImGui::InputTextWithHint("##CommandPaletteSearch",hint,&paletteQuery) || paletteFirstFrame) {
paletteSearchResults.clear();

switch (curPaletteType) {
case CMDPAL_TYPE_MAIN:
for (int i=0; i<GUI_ACTION_MAX; i++) {
if (guiActions[i].defaultBind==-1) continue;
if (matchFuzzy(guiActions[i].friendlyName,paletteQuery.c_str())) {
paletteSearchResults.push_back(i);
}
}
break;

case CMDPAL_TYPE_RECENT:
for (int i=0; i<(int)recentFile.size(); i++) {
if (matchFuzzy(recentFile[i].c_str(),paletteQuery.c_str())) {
paletteSearchResults.push_back(i);
}
}
break;

case CMDPAL_TYPE_INSTRUMENTS:
case CMDPAL_TYPE_INSTRUMENT_CHANGE:
if (matchFuzzy("- None -",paletteQuery.c_str())) {
paletteSearchResults.push_back(0);
}
for (int i=0; i<e->song.insLen; i++) {
String s=fmt::sprintf("%02X: %s", i, e->song.ins[i]->name.c_str());
if (matchFuzzy(s.c_str(),paletteQuery.c_str())) {
paletteSearchResults.push_back(i+1); // because over here ins=0 is 'None'
}
}
break;

case CMDPAL_TYPE_SAMPLES:
for (int i=0; i<e->song.sampleLen; i++) {
if (matchFuzzy(e->song.sample[i]->name.c_str(),paletteQuery.c_str())) {
paletteSearchResults.push_back(i);
}
}
break;

case CMDPAL_TYPE_ADD_CHIP:
for (int i=0; availableSystems[i]; i++) {
int ds=availableSystems[i];
const char* sysname=getSystemName((DivSystem)ds);
if (matchFuzzy(sysname,paletteQuery.c_str())) {
paletteSearchResults.push_back(ds);
}
}
break;

default:
logE("invalid command palette type");
ImGui::CloseCurrentPopup();
break;
};
}

ImVec2 avail=ImGui::GetContentRegionAvail();
avail.y-=ImGui::GetFrameHeightWithSpacing();

if (ImGui::BeginChild("CommandPaletteList",avail,false,0)) {
bool navigated=false;
if (ImGui::IsKeyPressed(ImGuiKey_UpArrow) && curPaletteChoice>0) {
curPaletteChoice-=1;
navigated=true;
}
if (ImGui::IsKeyPressed(ImGuiKey_DownArrow)) {
curPaletteChoice+=1;
navigated=true;
}

if (paletteSearchResults.size()>0 && curPaletteChoice<0) {
curPaletteChoice=0;
navigated=true;
}
if (curPaletteChoice>=(int)paletteSearchResults.size()) {
curPaletteChoice=paletteSearchResults.size()-1;
navigated=true;
}

for (int i=0; i<(int)paletteSearchResults.size(); i++) {
bool current=(i==curPaletteChoice);
int id=paletteSearchResults[i];

String s="???";
switch (curPaletteType) {
case CMDPAL_TYPE_MAIN:
s=guiActions[id].friendlyName;
break;
case CMDPAL_TYPE_RECENT:
s=recentFile[id].c_str();
break;
case CMDPAL_TYPE_INSTRUMENTS:
case CMDPAL_TYPE_INSTRUMENT_CHANGE:
if (id==0) {
s="- None -";
} else {
s=fmt::sprintf("%02X: %s", id-1, e->song.ins[id-1]->name.c_str());
}
break;
case CMDPAL_TYPE_SAMPLES:
s=e->song.sample[id]->name.c_str();
break;
case CMDPAL_TYPE_ADD_CHIP:
s=getSystemName((DivSystem)id);
break;
default:
logE("invalid command palette type");
break;
};

if (ImGui::Selectable(s.c_str(),current)) {
curPaletteChoice=i;
accepted=true;
}
if ((navigated || paletteFirstFrame) && current) ImGui::SetScrollHereY();
}
}
ImGui::EndChild();

if (!accepted) {
if (curPaletteChoice>=(int)paletteSearchResults.size()) {
curPaletteChoice=paletteSearchResults.size()-1;
}
accepted=ImGui::IsKeyPressed(ImGuiKey_Enter);
}

if (ImGui::Button("Cancel") || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
ImGui::CloseCurrentPopup();
}

// do not move this to after the resetPalette() calls!
// if they are called before and we're jumping from one palette to the next, the paletteFirstFrame won't be true at the start and the setup will not happen.
paletteFirstFrame=false;

if (accepted) {
if (paletteSearchResults.size()>0) {
int i=paletteSearchResults[curPaletteChoice];
switch (curPaletteType) {
case CMDPAL_TYPE_MAIN:
doAction(i);
break;

case CMDPAL_TYPE_RECENT:
openRecentFile(recentFile[i]);
break;

case CMDPAL_TYPE_INSTRUMENTS:
curIns=i-1;
break;

case CMDPAL_TYPE_SAMPLES:
curSample=i;
break;

case CMDPAL_TYPE_INSTRUMENT_CHANGE:
doChangeIns(i-1);
break;

case CMDPAL_TYPE_ADD_CHIP:
if (i!=DIV_SYSTEM_NULL) {
if (!e->addSystem((DivSystem)i)) {
showError("cannot add chip! ("+e->getLastError()+")");
} else {
MARK_MODIFIED;
}
ImGui::CloseCurrentPopup();
if (e->song.autoSystem) {
autoDetectSystem();
}
updateWindowTitle();
}
break;

default:
logE("invalid command palette type");
break;
};
}
ImGui::CloseCurrentPopup();
}
}
31 changes: 31 additions & 0 deletions src/gui/commandPalette.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

enum CommandPaletteType {
CMDPAL_TYPE_MAIN = 0,
CMDPAL_TYPE_RECENT,
CMDPAL_TYPE_INSTRUMENTS,
CMDPAL_TYPE_SAMPLES,
CMDPAL_TYPE_INSTRUMENT_CHANGE,
CMDPAL_TYPE_ADD_CHIP,
// a menu to select wavetables is beyond scope (they can't be put as strings)
// TODO: are there more?

CMDPAL_TYPE_MAX,
};
26 changes: 25 additions & 1 deletion src/gui/doAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

#include "gui.h"
#include "commandPalette.h"
#include "../ta-log.h"
#include <fmt/printf.h>
#include <imgui.h>
Expand Down Expand Up @@ -192,7 +193,30 @@ void FurnaceGUI::doAction(int what) {
case GUI_ACTION_CLEAR:
showWarning("Select an option: (cannot be undone!)",GUI_WARN_CLEAR);
break;

case GUI_ACTION_COMMAND_PALETTE:
displayPalette=true;
curPaletteType=CMDPAL_TYPE_MAIN;
break;
case GUI_ACTION_CMDPAL_RECENT:
displayPalette=true;
curPaletteType=CMDPAL_TYPE_RECENT;
break;
case GUI_ACTION_CMDPAL_INSTRUMENTS:
displayPalette=true;
curPaletteType=CMDPAL_TYPE_INSTRUMENTS;
break;
case GUI_ACTION_CMDPAL_SAMPLES:
displayPalette=true;
curPaletteType=CMDPAL_TYPE_SAMPLES;
break;
case GUI_ACTION_CMDPAL_INSTRUMENT_CHANGE:
displayPalette=true;
curPaletteType=CMDPAL_TYPE_INSTRUMENT_CHANGE;
break;
case GUI_ACTION_CMDPAL_ADD_CHIP:
displayPalette=true;
curPaletteType=CMDPAL_TYPE_ADD_CHIP;
break;
case GUI_ACTION_WINDOW_EDIT_CONTROLS:
nextWindow=GUI_WINDOW_EDIT_CONTROLS;
break;
Expand Down
Loading