Code

screen: moved screen_interface externs to each screen header
[ncmpc.git] / src / screen_keydef.c
1 /* ncmpc (Ncurses MPD Client)
2  * (c) 2004-2009 The Music Player Daemon Project
3  * Project homepage: http://musicpd.org
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
20 #include "screen_keydef.h"
21 #include "screen_interface.h"
22 #include "i18n.h"
23 #include "conf.h"
24 #include "screen.h"
25 #include "screen_utils.h"
27 #include <errno.h>
28 #include <string.h>
29 #include <glib.h>
31 #define STATIC_ITEMS      0
32 #define STATIC_SUB_ITEMS  1
33 #define BUFSIZE 256
35 #define LIST_ITEM_APPLY()   ((unsigned)command_list_length)
36 #define LIST_ITEM_SAVE()    (LIST_ITEM_APPLY()+1)
37 #define LIST_LENGTH()       (LIST_ITEM_SAVE()+1)
39 #define LIST_ITEM_SAVE_LABEL  _("===> Apply & Save key bindings  ")
40 #define LIST_ITEM_APPLY_LABEL _("===> Apply key bindings ")
43 static list_window_t *lw = NULL;
44 static unsigned command_list_length = 0;
45 static command_definition_t *cmds = NULL;
47 static int subcmd = -1;
48 static unsigned subcmd_length = 0;
49 static unsigned subcmd_addpos = 0;
51 static int
52 keybindings_changed(void)
53 {
54         command_definition_t *orginal_cmds = get_command_definitions();
55         size_t size = command_list_length * sizeof(command_definition_t);
57         return memcmp(orginal_cmds, cmds, size);
58 }
60 static void
61 apply_keys(void)
62 {
63         if (keybindings_changed()) {
64                 command_definition_t *orginal_cmds = get_command_definitions();
65                 size_t size = command_list_length * sizeof(command_definition_t);
67                 memcpy(orginal_cmds, cmds, size);
68                 screen_status_printf(_("You have new key bindings"));
69         } else
70                 screen_status_printf(_("Keybindings unchanged."));
71 }
73 static int
74 save_keys(void)
75 {
76         FILE *f;
77         char *filename;
79         if (check_user_conf_dir()) {
80                 screen_status_printf(_("Error: Unable to create directory ~/.ncmpc - %s"),
81                                      strerror(errno));
82                 screen_bell();
83                 return -1;
84         }
86         filename = get_user_key_binding_filename();
88         if ((f = fopen(filename,"w")) == NULL) {
89                 screen_status_printf(_("Error: %s - %s"), filename, strerror(errno));
90                 screen_bell();
91                 g_free(filename);
92                 return -1;
93         }
95         if (write_key_bindings(f, KEYDEF_WRITE_HEADER))
96                 screen_status_printf(_("Error: %s - %s"), filename, strerror(errno));
97         else
98                 screen_status_printf(_("Wrote %s"), filename);
100         g_free(filename);
101         return fclose(f);
104 static void
105 check_subcmd_length(void)
107         subcmd_length = 0;
108         while (subcmd_length < MAX_COMMAND_KEYS &&
109                cmds[subcmd].keys[subcmd_length] > 0)
110                 ++subcmd_length;
112         if (subcmd_length < MAX_COMMAND_KEYS) {
113                 subcmd_addpos = subcmd_length;
114                 subcmd_length++;
115         } else
116                 subcmd_addpos = 0;
117         subcmd_length += STATIC_SUB_ITEMS;
120 static void
121 keydef_paint(void);
123 static void
124 keydef_repaint(void)
126         keydef_paint();
127         wrefresh(lw->w);
130 static void
131 delete_key(int cmd_index, int key_index)
133         int i = key_index+1;
135         screen_status_printf(_("Deleted"));
136         while (i < MAX_COMMAND_KEYS && cmds[cmd_index].keys[i])
137                 cmds[cmd_index].keys[key_index++] = cmds[cmd_index].keys[i++];
138         cmds[cmd_index].keys[key_index] = 0;
139         cmds[cmd_index].flags |= COMMAND_KEY_MODIFIED;
140         check_subcmd_length();
142         /* repaint */
143         keydef_repaint();
145         /* update key conflict flags */
146         check_key_bindings(cmds, NULL, 0);
149 static void
150 assign_new_key(int cmd_index, int key_index)
152         int key;
153         char *buf;
154         command_t cmd;
156         buf = g_strdup_printf(_("Enter new key for %s: "), cmds[cmd_index].name);
157         key = screen_getch(buf);
158         g_free(buf);
160         if (key==ERR) {
161                 screen_status_printf(_("Aborted"));
162                 return;
163         }
165         cmd = find_key_command(key, cmds);
166         if (cmd != CMD_NONE && cmd != cmds[cmd_index].command) {
167                 screen_status_printf(_("Error: key %s is already used for %s"),
168                                      key2str(key),
169                                      get_key_command_name(cmd));
170                 screen_bell();
171                 return;
172         }
174         cmds[cmd_index].keys[key_index] = key;
175         cmds[cmd_index].flags |= COMMAND_KEY_MODIFIED;
177         screen_status_printf(_("Assigned %s to %s"),
178                              key2str(key),cmds[cmd_index].name);
179         check_subcmd_length();
181         /* repaint */
182         keydef_repaint();
184         /* update key conflict flags */
185         check_key_bindings(cmds, NULL, 0);
188 static const char *
189 list_callback(unsigned idx, bool *highlight, G_GNUC_UNUSED char** sc, G_GNUC_UNUSED void *data)
191         static char buf[BUFSIZE];
193         if (subcmd < 0) {
194                 if (idx < (unsigned)command_list_length) {
195                         if (cmds[idx].flags & COMMAND_KEY_CONFLICT)
196                                 *highlight = true;
197                         return cmds[idx].name;
198                 } else if (idx == LIST_ITEM_APPLY())
199                         return LIST_ITEM_APPLY_LABEL;
200                 else if (idx == LIST_ITEM_SAVE())
201                         return LIST_ITEM_SAVE_LABEL;
202         } else {
203                 if (idx == 0)
204                         return "[..]";
205                 idx--;
206                 if (idx < MAX_COMMAND_KEYS && cmds[subcmd].keys[idx] > 0) {
207                         g_snprintf(buf,
208                                    BUFSIZE, "%d. %-20s   (%d) ",
209                                    idx + 1,
210                                    key2str(cmds[subcmd].keys[idx]),
211                                    cmds[subcmd].keys[idx]);
212                         return buf;
213                 } else if (idx == subcmd_addpos) {
214                         g_snprintf(buf, BUFSIZE, "%d. %s",
215                                    idx + 1, _("Add new key"));
216                         return buf;
217                 }
218         }
220         return NULL;
223 static void
224 keydef_init(WINDOW *w, int cols, int rows)
226         lw = list_window_init(w, cols, rows);
229 static void
230 keydef_resize(int cols, int rows)
232         lw->cols = cols;
233         lw->rows = rows;
236 static void
237 keydef_exit(void)
239         list_window_free(lw);
240         if (cmds)
241                 g_free(cmds);
242         cmds = NULL;
243         lw = NULL;
246 static void
247 keydef_open(G_GNUC_UNUSED struct mpdclient *c)
249         if (cmds == NULL) {
250                 command_definition_t *current_cmds = get_command_definitions();
251                 size_t cmds_size;
253                 command_list_length = 0;
254                 while (current_cmds[command_list_length].name)
255                         command_list_length++;
257                 cmds_size = (command_list_length+1) * sizeof(command_definition_t);
258                 cmds = g_malloc0(cmds_size);
259                 memcpy(cmds, current_cmds, cmds_size);
260                 command_list_length += STATIC_ITEMS;
261         }
263         subcmd = -1;
264         list_window_check_selected(lw, LIST_LENGTH());
267 static void
268 keydef_close(void)
270         if (cmds && !keybindings_changed()) {
271                 g_free(cmds);
272                 cmds = NULL;
273         } else
274                 screen_status_printf(_("Note: Did you forget to \'Apply\' your changes?"));
277 static const char *
278 keydef_title(char *str, size_t size)
280         if (subcmd < 0)
281                 return _("Edit key bindings");
283         g_snprintf(str, size, _("Edit keys for %s"), cmds[subcmd].name);
284         return str;
287 static void
288 keydef_paint(void)
290         list_window_paint(lw, list_callback, NULL);
293 static bool
294 keydef_cmd(G_GNUC_UNUSED struct mpdclient *c, command_t cmd)
296         int length = LIST_LENGTH();
298         if (subcmd >= 0)
299                 length = subcmd_length;
301         if (cmd == CMD_LIST_RANGE_SELECT)
302                 return false;
304         if (list_window_cmd(lw, length, cmd)) {
305                 keydef_repaint();
306                 return true;
307         }
309         switch(cmd) {
310         case CMD_PLAY:
311                 if (subcmd < 0) {
312                         if (lw->selected == LIST_ITEM_APPLY())
313                                 apply_keys();
314                         else if (lw->selected == LIST_ITEM_SAVE()) {
315                                 apply_keys();
316                                 save_keys();
317                         } else {
318                                 subcmd = lw->selected;
319                                 lw->selected=0;
320                                 lw->selected_start = lw->selected;
321                                 lw->selected_end = lw->selected;
322                                 check_subcmd_length();
324                                 keydef_repaint();
325                         }
326                 } else {
327                         if (lw->selected == 0) { /* up */
328                                 lw->selected = subcmd;
329                                 lw->selected_start = lw->selected;
330                                 lw->selected_end = lw->selected;
331                                 subcmd = -1;
333                                 keydef_repaint();
334                         } else
335                                 assign_new_key(subcmd,
336                                                lw->selected - STATIC_SUB_ITEMS);
337                 }
338                 return true;
339         case CMD_GO_PARENT_DIRECTORY:
340                 if (subcmd >=0) {
341                         lw->selected = subcmd;
342                         lw->selected_start = lw->selected;
343                         lw->selected_end = lw->selected;
344                         subcmd = -1;
346                         keydef_repaint();
347                 }
348                 break;
349         case CMD_DELETE:
350                 if (subcmd >= 0 && lw->selected >= STATIC_SUB_ITEMS)
351                         delete_key(subcmd, lw->selected - STATIC_SUB_ITEMS);
352                 return true;
353                 break;
354         case CMD_SAVE_PLAYLIST:
355                 apply_keys();
356                 save_keys();
357                 break;
358         case CMD_LIST_FIND:
359         case CMD_LIST_RFIND:
360         case CMD_LIST_FIND_NEXT:
361         case CMD_LIST_RFIND_NEXT:
362                 screen_find(lw, length,
363                             cmd, list_callback, NULL);
364                 keydef_repaint();
365                 return true;
367         default:
368                 break;
369         }
371         return false;
374 const struct screen_functions screen_keydef = {
375         .init = keydef_init,
376         .exit = keydef_exit,
377         .open = keydef_open,
378         .close = keydef_close,
379         .resize = keydef_resize,
380         .paint = keydef_paint,
381         .cmd = keydef_cmd,
382         .get_title = keydef_title,
383 };