1 /* browse.c: tape browser dialog box
2    Copyright (c) 2002-2008 Philip Kendall, Marek Januszewski
3    Copyright (c) 2015 Sergio Baldoví
4 
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.
9 
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.
14 
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 
19    Author contact information:
20 
21    E-mail: philip-fuse@shadowmagic.org.uk
22 
23 */
24 
25 #include <config.h>
26 
27 #include <libspectrum.h>
28 #include <tchar.h>
29 #include <windows.h>
30 
31 #include "fuse.h"
32 #include "tape.h"
33 #include "ui/ui.h"
34 #include "win32internals.h"
35 
36 #include "browse.h"
37 
38 static INT_PTR CALLBACK dialog_proc( HWND hwndDlg, UINT uMsg,
39                                      WPARAM wParam, LPARAM lParam );
40 static void add_block_details( libspectrum_tape_block *block, void *user_data );
41 static void select_row( LPNMITEMACTIVATE lpnmitem );
42 
43 static HWND dialog;             /* The dialog box itself */
44 
45 static int dialog_created;	/* Have we created the dialog box yet? */
46 
47 void
menu_media_tape_browse(int action)48 menu_media_tape_browse( int action )
49 {
50   /* Firstly, stop emulation */
51   fuse_emulation_pause();
52 
53   if( !dialog_created ) {
54     dialog = CreateDialog( fuse_hInstance, MAKEINTRESOURCE( IDD_BROWSE ),
55                            fuse_hWnd, dialog_proc );
56     if( dialog == NULL ) { fuse_emulation_unpause(); return; }
57   }
58 
59   if( ui_tape_browser_update( UI_TAPE_BROWSER_NEW_TAPE, NULL ) ) {
60     fuse_emulation_unpause();
61     return;
62   }
63 
64   ShowWindow( dialog, SW_SHOW );
65 
66   /* Carry on with emulation */
67   fuse_emulation_unpause();
68 }
69 
70 static void
dialog_init(HWND hwndDlg)71 dialog_init( HWND hwndDlg )
72 {
73   size_t i;
74   LPCTSTR titles[3] = { _T( "" ), _T( "Block type" ), _T( "Data" ) };
75   int titles_widths[3] = { 16, 115, 150 };
76 
77   /* set extended listview style to select full row, when an item is selected */
78   DWORD lv_ext_style;
79   lv_ext_style = SendDlgItemMessage( hwndDlg, IDC_BROWSE_LV,
80                                      LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0 );
81   lv_ext_style |= LVS_EX_FULLROWSELECT;
82   SendDlgItemMessage( hwndDlg, IDC_BROWSE_LV,
83                       LVM_SETEXTENDEDLISTVIEWSTYLE, 0, lv_ext_style );
84 
85   /* Create columns in the listview */
86   LVCOLUMN lvc;
87   lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT ;
88   lvc.fmt = LVCFMT_LEFT;
89 
90   for( i = 0; i < 3; i++ ) {
91     if( i != 0 )
92       lvc.mask |= LVCF_SUBITEM;
93     lvc.cx = titles_widths[i];
94     lvc.pszText = (LPTSTR)titles[i];
95     SendDlgItemMessage( hwndDlg, IDC_BROWSE_LV, LVM_INSERTCOLUMN, i,
96                         ( LPARAM ) &lvc );
97   }
98 
99   /* create image list for the listview */
100   HBITMAP icon_tape_marker, icon_tape_marker_mask;
101   BITMAP bmp;
102   HIMAGELIST himl;
103 
104   /* FIXME: need to destroy those objects later */
105   icon_tape_marker = LoadImage( fuse_hInstance, "win32bmp_tape_marker",
106                                 IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
107   icon_tape_marker_mask = LoadImage( fuse_hInstance, "win32bmp_tape_marker_mask",
108                                      IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
109   GetObject( icon_tape_marker, sizeof( bmp ), &bmp );
110 
111   /* FIXME: destroy the list later */
112   himl = ImageList_Create( bmp.bmWidth, bmp.bmHeight,
113                            ILC_COLOR | ILC_MASK, 1, 0 );
114 
115   ImageList_Add( himl, icon_tape_marker, icon_tape_marker_mask );
116 
117   SendDlgItemMessage( hwndDlg, IDC_BROWSE_LV, LVM_SETIMAGELIST,
118                       LVSIL_SMALL, ( LPARAM ) himl );
119 
120   dialog_created = 1;
121 }
122 
123 static INT_PTR CALLBACK
dialog_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)124 dialog_proc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
125 {
126 /* FIXME: implement resizing the dialog */
127   switch( uMsg ) {
128 
129     case WM_INITDIALOG:
130       dialog_init( hwndDlg );
131       return FALSE;
132 
133     case WM_NOTIFY:
134       if( ( ( LPNMHDR ) lParam )->code == NM_DBLCLK ) {
135         if( ( ( LPNMHDR ) lParam )->idFrom == IDC_BROWSE_LV ) {
136           select_row( ( LPNMITEMACTIVATE ) lParam );
137           return 0;
138         }
139       }
140       break;
141 
142     case WM_COMMAND:
143       if( LOWORD( wParam ) == IDCLOSE ) {
144         ShowWindow( dialog, SW_HIDE );
145         return 0;
146       }
147       break;
148 
149     case WM_CLOSE:
150       /* Catch attempts to delete the window and just hide it instead */
151       ShowWindow( dialog, SW_HIDE );
152       return 0;
153   }
154   return FALSE;
155 }
156 
157 int
ui_tape_browser_update(ui_tape_browser_update_type change GCC_UNUSED,libspectrum_tape_block * block GCC_UNUSED)158 ui_tape_browser_update( ui_tape_browser_update_type change GCC_UNUSED,
159                         libspectrum_tape_block *block GCC_UNUSED )
160 {
161   int error, current_block;
162 
163   if( !dialog_created ) return 0;
164 
165   fuse_emulation_pause();
166 
167   SendDlgItemMessage( dialog, IDC_BROWSE_LV, LVM_DELETEALLITEMS, 0, 0 );
168 
169   error = tape_foreach( add_block_details, NULL );
170   if( error ) {
171     fuse_emulation_unpause();
172     return 1;
173   }
174 
175   current_block = tape_get_current_block();
176   if( current_block != -1 ) {
177     LVITEM li;
178     li.mask = LVIF_IMAGE;
179     li.iItem = current_block;
180     li.iSubItem = 0;
181     li.iImage = 0;
182     SendDlgItemMessage( dialog, IDC_BROWSE_LV, LVM_SETITEM, 0, ( LPARAM ) &li );
183   }
184 
185   if( tape_modified ) {
186     SendDlgItemMessage( dialog, IDC_BROWSE_MODIFIED, WM_SETTEXT,
187                         0, ( LPARAM ) TEXT( "Tape modified" ) );
188   } else {
189     SendDlgItemMessage( dialog, IDC_BROWSE_MODIFIED, WM_SETTEXT,
190                         0, ( LPARAM ) TEXT( "Tape not modified" ) );
191  }
192 
193   fuse_emulation_unpause();
194 
195   return 0;
196 }
197 
198 static void
add_block_details(libspectrum_tape_block * block,void * user_data)199 add_block_details( libspectrum_tape_block *block, void *user_data )
200 {
201   TCHAR buffer[256];
202   TCHAR *details[3] = { &buffer[0], &buffer[80], &buffer[160] };
203   LV_ITEM lvi;
204   size_t i;
205 
206   _tcscpy( details[0], "" );
207   libspectrum_tape_block_description( details[1], 80, block );
208   /* FIXME: why does it give such a big number of bytes? */
209   tape_block_details( details[2], 80, block );
210 
211   lvi.mask = LVIF_TEXT | LVIF_IMAGE;
212   lvi.iImage = -1;
213   lvi.iItem = SendDlgItemMessage( dialog, IDC_BROWSE_LV,
214                                   LVM_GETITEMCOUNT, 0, 0 );
215   for( i = 0; i < 3; i++ ) {
216     lvi.iSubItem = i;
217     lvi.pszText = details[i];
218     if( i == 0 )
219       SendDlgItemMessage( dialog, IDC_BROWSE_LV, LVM_INSERTITEM, 0,
220                           ( LPARAM ) &lvi );
221     else
222       SendDlgItemMessage( dialog, IDC_BROWSE_LV, LVM_SETITEM, 0,
223                           ( LPARAM ) &lvi );
224   }
225 }
226 
227 /* Called when a row is selected */
228 static void
select_row(LPNMITEMACTIVATE lpnmitem)229 select_row( LPNMITEMACTIVATE lpnmitem )
230 {
231   int current_block, row;
232 
233   row = lpnmitem->iItem;
234 
235   /* Don't do anything if the current block was clicked on */
236   current_block = tape_get_current_block();
237   if( row == current_block ) return;
238 
239   /* Otherwise, select the new block */
240   tape_select_block_no_update( row );
241 
242   /* set the marker at the current item, clear others */
243   size_t i, count;
244   count = SendDlgItemMessage( dialog, IDC_BROWSE_LV,
245                               LVM_GETITEMCOUNT, 0, 0 );
246   LVITEM li;
247   li.mask = LVIF_IMAGE;
248   li.iSubItem = 0;
249 
250   for( i=0; i<count; i++ ) {
251     li.iImage = ( i==row ? 0 : -1 );
252     li.iItem = i;
253     SendDlgItemMessage( dialog, IDC_BROWSE_LV, LVM_SETITEM, 0, ( LPARAM ) &li );
254   }
255 }
256