1 /*
2   DF-SHOW: An interactive directory/file browser written for Unix-like systems.
3   Based on the applications from the PC-DOS DF-EDIT suite by Larry Kroeker.
4   Copyright (C) 2018-2021  Robert Ian Hawdon
5 
6   This program is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10 
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #define _GNU_SOURCE
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <ncurses.h>
24 #include <string.h>
25 #include <wchar.h>
26 #include "colors.h"
27 #include "menu.h"
28 
cmp_menu_ref(const void * lhs,const void * rhs)29 int cmp_menu_ref(const void *lhs, const void *rhs)
30 {
31 
32   menuDef *dforderA = (menuDef *)lhs;
33   menuDef *dforderB = (menuDef *)rhs;
34 
35   return strcoll(dforderA->refLabel, dforderB->refLabel);
36 
37 }
38 
updateMenuItem(menuDef ** dfMenu,int * menuSize,char * refLabel,wchar_t * displayLabel)39 void updateMenuItem(menuDef **dfMenu, int *menuSize, char* refLabel, wchar_t* displayLabel){
40   // To Do
41   int i;
42   for(i = 0; i < *menuSize; i++){
43     if (!strcmp(((*dfMenu)[i].refLabel), refLabel)){
44       swprintf((*dfMenu)[i].displayLabel, 32, L"%ls", displayLabel);
45       break;
46     }
47   }
48   return;
49 }
50 
addMenuItem(menuDef ** dfMenu,int * pos,char * refLabel,wchar_t * displayLabel,int hotKey)51 void addMenuItem(menuDef **dfMenu, int *pos, char* refLabel, wchar_t* displayLabel, int hotKey){
52 
53   int menuPos = *pos;
54   int charCount = 0;
55   int i;
56   menuDef *tmp;
57 
58   if (menuPos == 0){
59     tmp = malloc(sizeof(menuDef) * 2);
60   } else {
61     tmp = realloc(*dfMenu, (menuPos + 1) * (sizeof(menuDef) + 1) );
62   }
63   if (tmp){
64     *dfMenu = tmp;
65   }
66 
67   sprintf((*dfMenu)[menuPos].refLabel, "%s", refLabel);
68   swprintf((*dfMenu)[menuPos].displayLabel, 32, L"%ls", displayLabel);
69   (*dfMenu)[menuPos].hotKey = hotKey;
70 
71   for (i = 0; i < wcslen(displayLabel); i++)
72     {
73       if ( displayLabel[i] == '!' || displayLabel[i] == '<' || displayLabel[i] == '>' || displayLabel[i] == '\\') {
74         i++;
75         charCount++;
76       } else {
77         charCount++;
78       }
79     }
80   (*dfMenu)[menuPos].displayLabelSize = charCount;
81 
82   qsort((*dfMenu), menuPos + 1, sizeof(menuDef), cmp_menu_ref);
83 
84   ++*pos;
85 
86 }
87 
genMenuDisplayLabel(wchar_t * preMenu,menuDef * dfMenu,int size,wchar_t * postMenu,int comma)88 wchar_t * genMenuDisplayLabel(wchar_t* preMenu, menuDef* dfMenu, int size, wchar_t* postMenu, int comma){
89   wchar_t * output;
90   int gapSize;
91   int currentLen = 0;
92   int i;
93 
94   output = malloc(sizeof(wchar_t) * ( wcslen(preMenu) + 2));
95   if (wcscmp(preMenu, L"")){
96     wcscpy(output, preMenu);
97     wcscat(output, L" ");
98   } else {
99     wcscpy(output, L"\0");
100   }
101   for (i = 0; i < size ; i++){
102     output = realloc(output, ((i + 1) * sizeof(dfMenu[i].displayLabel) + wcslen(output) + 1) * sizeof(wchar_t) );
103    if ( i == 0 ){
104      currentLen = currentLen + dfMenu[i].displayLabelSize;
105      if ( currentLen - 1 < COLS){
106        wcscat(output, dfMenu[i].displayLabel);
107      } else if ( currentLen +1 > COLS && i == 0){
108        wcscat(output, L"");
109      }
110    } else {
111      if (comma == 1){
112        gapSize = 2;
113      } else if (comma == -1) {
114        gapSize = 0;
115      } else {
116        gapSize = 1;
117      }
118      currentLen = currentLen + dfMenu[i].displayLabelSize + gapSize;
119      if (currentLen - 1 < COLS){
120        if (comma == 1){
121          wcscat(output, L", ");
122        } else if (comma == 0) {
123          wcscat(output, L" ");
124        }
125        wcscat(output, dfMenu[i].displayLabel);
126      }
127    }
128   }
129   output = realloc(output, (sizeof(wchar_t) * (wcslen(output) + wcslen(postMenu) + 2) ));
130   if (wcscmp(postMenu, L"")){
131     wcscat(output, L" ");
132     wcscat(output, postMenu);
133   } else {
134     wcscat(output, L"\0");
135   }
136   return output;
137 }
138 
menuHotkeyLookup(menuDef * dfMenu,char * refLabel,int size)139 int menuHotkeyLookup(menuDef* dfMenu, char* refLabel, int size){
140   int i;
141   int r = -1;
142   for (i = 0; i < size; i++){
143     if (!strcmp(dfMenu[i].refLabel, refLabel)){
144       r = dfMenu[i].hotKey;
145     }
146   }
147   return r;
148 }
149 
altHotkey(int key)150 int altHotkey(int key)
151 {
152   int alt;
153   if ((key < 123) && (key > 96)){
154     alt = key - 32;
155   } else if ((key < 91) && (key > 64)){
156     alt = key + 32;
157   } else {
158     alt = -1;
159   }
160   return(alt);
161 }
162 
wPrintMenu(int line,int col,wchar_t * menustring)163 void wPrintMenu(int line, int col, wchar_t *menustring)
164 {
165   int i, len, charcount, pad;
166   charcount = 0;
167   move(line, col);
168   clrtoeol();
169   len = wcslen(menustring);
170   setColors(COMMAND_PAIR);
171   for (i = 0; i < len; i++)
172     {
173       if ( menustring[i] == '!' ) {
174         setColors(HILITE_PAIR);
175         i++;
176         mvprintw(line, col + charcount, "%lc", menustring[i]);
177         setColors(COMMAND_PAIR);
178         charcount++;
179       } else if ( menustring[i] == '<' ) {
180         setColors(HILITE_PAIR);
181         i++;
182         mvprintw(line, col + charcount, "%lc", menustring[i]);
183         charcount++;
184       } else if ( menustring[i] == '>' ) {
185         setColors(COMMAND_PAIR);
186         if (i < (len - 1)){
187           i++;
188           mvprintw(line, col + charcount, "%lc", menustring[i]);
189           charcount++;
190         }
191       } else if ( menustring[i] == '\\' ) {
192         i++;
193         mvprintw(line, col + charcount, "%lc", menustring[i]);
194         charcount++;
195       } else {
196         mvprintw(line, col + charcount, "%lc", menustring[i]);
197         charcount++;
198       }
199     }
200   pad = COLS - charcount;
201   for (i = 0; i < pad; i++)
202     {
203       mvprintw(line, col + charcount, " ");
204       charcount++;
205     }
206 }
207 
printMenu(int line,int col,char * menustring)208 void printMenu(int line, int col, char *menustring)
209 {
210   // Small wrapper to seemlessly forward calls to the wide char version
211   wchar_t *wMenuString;
212   wMenuString = malloc(sizeof(wchar_t) * (strlen(menustring) + 1));
213   swprintf(wMenuString, strlen(menustring) + 1, L"%s", menustring);
214   wPrintMenu(line, col, wMenuString);
215   free(wMenuString);
216 }
217