Subversion Repositories Filer-Free

Rev

Rev 56 | Rev 58 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
21 gdshaw@RISCPKG.ORG 1
// This file is part of the free Filer module for RISC OS.
2
// Copyright  2007 Graham Shaw.
3
// Redistribution and modification are permitted under the terms of the
4
// GNU General Public License (version 2 or any later version).
5
 
6
#include <cstring>
35 gdshaw@RISCPKG.ORG 7
#include <cstdio>
21 gdshaw@RISCPKG.ORG 8
 
35 gdshaw@RISCPKG.ORG 9
#include "oslib/osbyte.h"
42 gdshaw@RISCPKG.ORG 10
#include "oslib/osfscontrol.h"
35 gdshaw@RISCPKG.ORG 11
#include "oslib/wimp.h"
12
 
21 gdshaw@RISCPKG.ORG 13
#include "template_loader.h"
55 gdshaw@RISCPKG.ORG 14
#include "filer_sprite.h"
25 gdshaw@RISCPKG.ORG 15
#include "layout_method.h"
31 gdshaw@RISCPKG.ORG 16
#include "filer_menu.h"
21 gdshaw@RISCPKG.ORG 17
#include "filer_window.h"
18
#include "filer_application.h"
19
 
35 gdshaw@RISCPKG.ORG 20
namespace {
21
 
22
/** The maximum length of a leafname. */
23
const size_t max_name_length=256;
24
 
25
/** The initial horizontal offset for opening a subdirectory. */
26
const int open_xstart=20;
27
 
28
/** The initial vertical offset for opening a subdirectory. */
29
const int open_ystart=-32;
30
 
31
/** The horizontal offset between subdirectories. */
32
const int open_xstep=20;
33
 
34
/** The vertical offset between subdirectories. */
35
const int open_ystep=0;
36
 
37
/** The number of distinct subdirectory offsets. */
38
const unsigned int open_count=8;
39
 
38 gdshaw@RISCPKG.ORG 40
/** The pathname for the template file. */
41
const char* template_pathname="Resources:$.Resources.Filer.Templates";
42
 
35 gdshaw@RISCPKG.ORG 43
}; /* anonymous namespace */
44
 
21 gdshaw@RISCPKG.ORG 45
filer_window::filer_window(filer_application* app,const char* pathname,
25 gdshaw@RISCPKG.ORG 46
        const os_box& box,const filer_options& options):
21 gdshaw@RISCPKG.ORG 47
        window(app),
48
        _pathname(new char[std::strlen(pathname)+1]),
25 gdshaw@RISCPKG.ORG 49
        _options(options),
50
        _directory(options.sort()),
51
        _xcsize(68),
52
        _ycsize(68),
53
        _xccount(1),
31 gdshaw@RISCPKG.ORG 54
        _yccount(1),
35 gdshaw@RISCPKG.ORG 55
        _temp_selection(directory::npos),
56
        _auto_pos(open_xstart,open_ystart,open_xstep,open_ystep,open_count)
21 gdshaw@RISCPKG.ORG 57
{
58
        // Copy pathname into buffer owned by this object.
59
        std::strcpy(_pathname,pathname);
60
 
61
        // Load directory listing.
62
        reload();
63
 
64
        // Create window from template.
38 gdshaw@RISCPKG.ORG 65
        template_loader loader("directory",template_pathname);
21 gdshaw@RISCPKG.ORG 66
        wimp_window& wblock=loader;
67
        wblock.title_flags|=wimp_ICON_INDIRECTED;
68
        wblock.title_data.indirected_text.text=_pathname;
69
        wblock.title_data.indirected_text.validation="";
70
        wblock.title_data.indirected_text.size=strlen(_pathname);
71
        wblock.visible=box;
72
        wblock.extent.x0=0;
73
        wblock.extent.y0=-(box.y1-box.y0);
74
        wblock.extent.x1=box.x1-box.x0;
75
        wblock.extent.y1=0;
28 gdshaw@RISCPKG.ORG 76
        wblock.flags|=wimp_WINDOW_IGNORE_XEXTENT;
21 gdshaw@RISCPKG.ORG 77
        wblock.icon_count=0;
78
        create_window(wblock);
79
 
80
        // Resize extent to match actual visible area.
81
        wimp_window_state wstate;
82
        get_window_state(wstate);
83
        os_box extent;
84
        extent.x0=0;
85
        extent.y0=-(wstate.visible.y1-wstate.visible.y0);
86
        extent.x1=wstate.visible.x1-wstate.visible.x0;
87
        extent.y1=0;
88
        window::set_extent(extent);
89
 
25 gdshaw@RISCPKG.ORG 90
        // Open window, but keep it hidden from view.
21 gdshaw@RISCPKG.ORG 91
        wimp_window_info winfo;
92
        get_window_info_header(winfo);
93
        wimp_open open;
94
        open.visible.x0=winfo.visible.x0;
95
        open.visible.y0=winfo.visible.y1-(winfo.extent.y1-winfo.extent.y0);
96
        open.visible.x1=winfo.visible.x0+(winfo.extent.x1-winfo.extent.x0);
97
        open.visible.y1=winfo.visible.y1;
98
        open.visible=winfo.visible;
99
        open.xscroll=0;
100
        open.yscroll=0;
25 gdshaw@RISCPKG.ORG 101
        open.next=wimp_HIDDEN;
102
        open_window(open);
103
 
104
        // Reformat content of window.
105
        reformat();
106
 
107
        // Reopen window, now making it visible.
108
        get_window_state(wstate);
109
        open.visible=wstate.visible;
110
        open.xscroll=wstate.xscroll;
111
        open.yscroll=wstate.yscroll;
21 gdshaw@RISCPKG.ORG 112
        open.next=wimp_TOP;
113
        open_window(open);
114
}
115
 
116
filer_window::~filer_window()
117
{
118
        // Delete pathname buffer.
119
        delete[] _pathname;
120
}
121
 
122
void filer_window::handle_redraw_request(wimp_draw& block)
123
{
25 gdshaw@RISCPKG.ORG 124
        // Fetch layout.
125
        layout_method& layout=_options.layout();
126
        int xgap=layout.xgap();
127
        int ygap=layout.ygap();
128
 
21 gdshaw@RISCPKG.ORG 129
        int more=0;
130
        xwimp_redraw_window(&block,&more);
131
        while (more)
132
        {
25 gdshaw@RISCPKG.ORG 133
                // Get clipping coordinates with respect to this window.
134
                int xmin=block.clip.x0-block.box.x0+block.xscroll-xgap;
135
                int ymin=block.clip.y0-block.box.y1+block.yscroll+ygap;
136
                int xmax=block.clip.x1-block.box.x0+block.xscroll-xgap;
137
                int ymax=block.clip.y1-block.box.y1+block.yscroll+ygap;
138
 
139
                // Determine which cells are within clipping box.
140
                int xcmin=(xmin)/(_xcsize+xgap);
141
                int ycmin=(-ymax)/(_ycsize+ygap);
142
                int xcmax=(xmax-1)/(_xcsize+xgap)+1;
143
                int ycmax=(-ymin-1)/(_ycsize+ygap)+1;
144
                if (xcmin<0) xcmin=0;
145
                if (ycmin<0) ycmin=0;
146
                if (xcmax>_xccount) xcmax=_xccount;
147
                if (ycmax>_yccount) ycmax=_yccount;
148
 
149
                // Iterate over cells to be redrawn.
150
                for (int yc=ycmin;yc<ycmax;++yc)
151
                {
152
                        for (int xc=xcmin;xc<xcmax;++xc)
153
                        {
154
                                // Determine whether cell is occupied.
30 gdshaw@RISCPKG.ORG 155
                                unsigned int i=xc+yc*_xccount;
156
                                if (i<_directory.size())
25 gdshaw@RISCPKG.ORG 157
                                {
158
                                        // Redraw cell.
159
                                        os_box box;
160
                                        box.x0=xc*(_xcsize+xgap)+xgap;
161
                                        box.y0=-yc*(_ycsize+ygap)-_ycsize-ygap;
162
                                        box.x1=box.x0+_xcsize;
163
                                        box.y1=box.y0+_ycsize;
164
                                        layout.plot(box,*_directory[i],
165
                                                _directory[i].selected(),_options);
166
                                }
167
                        }
168
                }
169
 
21 gdshaw@RISCPKG.ORG 170
                xwimp_get_rectangle(&block,&more);
171
        }
172
}
173
 
28 gdshaw@RISCPKG.ORG 174
void filer_window::handle_open_request(wimp_open& block)
175
{
176
        int xccount=_xccount;
177
        int yccount=_yccount;
178
        reformat(block.visible.x1-block.visible.x0);
179
        xwimp_open_window(&block);
180
        if (_xccount!=xccount||_yccount!=yccount) force_redraw();
181
}
182
 
29 gdshaw@RISCPKG.ORG 183
void filer_window::handle_close_request(wimp_close& block)
184
{
185
        wimp_pointer pointer;
186
        xwimp_get_pointer_info(&pointer);
187
 
188
        if (pointer.buttons&wimp_CLICK_ADJUST)
189
        {
190
                os_coord offset;
191
                offset.x=0;
192
                offset.y=0;
193
                open_parent(offset);
194
        }
195
 
196
        delete this;
197
}
198
 
30 gdshaw@RISCPKG.ORG 199
void filer_window::handle_mouse_click(wimp_pointer& block)
200
{
201
        // Fetch layout.
202
        layout_method& layout=options().layout();
203
 
35 gdshaw@RISCPKG.ORG 204
        // Read shift state.
205
        int shift_state=0;
206
        xosbyte1(osbyte_VAR_KEYBOARD_STATE,0,0xff,&shift_state);
207
        int shift=(shift_state&0x08)!=0;
208
 
30 gdshaw@RISCPKG.ORG 209
        // Find cell under pointer.
210
        unsigned int index=find_cell(block.pos);
211
 
35 gdshaw@RISCPKG.ORG 212
        bool close=false;
31 gdshaw@RISCPKG.ORG 213
        if (block.buttons==wimp_CLICK_MENU)
30 gdshaw@RISCPKG.ORG 214
        {
31 gdshaw@RISCPKG.ORG 215
                // Any existing menu will be deleted by this action.
216
                handle_menus_deleted();
217
 
218
                // Count number of cells selected.
219
                int count=0;
220
                for (unsigned int i=0,i_end=_directory.size();i!=i_end;++i)
221
                {
222
                        if (_directory[i].selected()) ++count;
223
                }
224
 
225
                // If pointer is over a cell and nothing has yet been selected
226
                // then temporarily select the cell under the pointer.
227
                if (index!=directory::npos&&!_directory[index].selected()&&!count)
228
                {
229
                        _directory[index].selected(true);
230
                        _temp_selection=index;
231
                        force_redraw_cell(index);
232
                }
233
 
234
                // Update then open the menu.
235
                shared_menu().update(this);
236
                shared_menu().show(block);
237
        }
35 gdshaw@RISCPKG.ORG 238
        else if (block.buttons&(wimp_DOUBLE_ADJUST|wimp_DOUBLE_SELECT))
239
        {
240
                // If double click within a cell then run that object.
241
                if (index!=directory::npos)
242
                {
243
                        select_all(0);
244
                        close=(block.buttons&wimp_DOUBLE_ADJUST)!=0;
245
                        if (close) close_window();
246
                        run(*_directory[index],close,shift);
247
                }
248
        }
55 gdshaw@RISCPKG.ORG 249
        else if (block.buttons&(wimp_DRAG_SELECT|wimp_DRAG_ADJUST))
250
        {
251
                // No action unless the pointer is over a cell.
252
                if (index!=directory::npos)
253
                {
254
                        // Choose sprite to be dragged.
255
                        filer_sprite sprite(*_directory[index]);
256
 
257
                        // Begin the drag with this sprite.
258
                        begin_drag(block,sprite.name());
259
                }
260
        }
57 gdshaw@RISCPKG.ORG 261
        else if (block.buttons&wimp_SINGLE_ADJUST)
31 gdshaw@RISCPKG.ORG 262
        {
57 gdshaw@RISCPKG.ORG 263
                // Invert selection state of cell under pointer.
30 gdshaw@RISCPKG.ORG 264
                if (index!=directory::npos)
265
                {
266
                        _directory[index].selected(!_directory[index].selected());
267
                        force_redraw_cell(index);
268
                }
269
        }
57 gdshaw@RISCPKG.ORG 270
        else if (block.buttons&wimp_SINGLE_SELECT)
271
        {
272
                // No action if over a cell which is already selected.
273
                if (index==directory::npos||!_directory[index].selected())
274
                {
275
                        // De-select everything.
276
                        select_all(0);
35 gdshaw@RISCPKG.ORG 277
 
57 gdshaw@RISCPKG.ORG 278
                        // Select cell under pointer.
279
                        if (index!=directory::npos)
280
                        {
281
                                _directory[index].selected(true);
282
                                force_redraw_cell(index);
283
                        }
284
                }
285
        }
286
 
35 gdshaw@RISCPKG.ORG 287
        // If this window has closed as a result of the mouse event
288
        // then delete it.
289
        if (close) delete this;
30 gdshaw@RISCPKG.ORG 290
}
291
 
55 gdshaw@RISCPKG.ORG 292
void filer_window::handle_user_drag_box(wimp_dragged& block)
293
{
294
        // Read pointer state.
295
        wimp_pointer pointer;
296
        xwimp_get_pointer_info(&pointer);
297
 
298
        // Read shift state.
299
        int shift_state=0;
300
        xosbyte1(osbyte_VAR_KEYBOARD_STATE,0,0xff,&shift_state);
301
        int shift=(shift_state&0x08)!=0;
302
 
303
        if (application* app=parent_application())
304
        {
305
                if (pointer.w==handle())
306
                {
307
                        // Object has been dropped back onto this window: no action.
308
                }
309
                else if (filer_window* w=
310
                        dynamic_cast<filer_window*>(app->find_window(pointer.w)))
311
                {
312
                        // Object has been dropped onto another filer window.
313
                        wimp_t filer_action_handle=begin_filer_action();
314
 
315
                        // Copy or move according to shift state.
316
                        const char* dst_pathname=w->pathname();
317
                        fileraction_flags flags=options().flags()|fileraction_RECURSE;
318
                        if (shift)
319
                        {
320
                                fileractionsendstartoperation_move(filer_action_handle,flags,
321
                                        dst_pathname,strlen(dst_pathname)+1);
322
                        }
323
                        else
324
                        {
325
                                fileractionsendstartoperation_copy(filer_action_handle,flags,
326
                                        dst_pathname,strlen(dst_pathname)+1);
327
                        }
328
                }
329
                else
330
                {
331
                        // Object has been dropped onto some other type of window.
332
                        // Construct Message_DataLoad.
333
                        wimp_message block2;
334
                        block2.your_ref=0;
335
                        block2.action=message_DATA_LOAD;
336
                        block2.data.data_xfer.w=pointer.w;
337
                        block2.data.data_xfer.i=pointer.i;
338
                        block2.data.data_xfer.pos=pointer.pos;
339
                        block2.data.data_xfer.est_size=-1; /* can do better than this */
340
                        block2.data.data_xfer.file_type=0xfff; /* can better this too */
341
 
342
                        // Send a Message_DataLoad for each object in the selection.
343
                        int count=0;
344
                        for (unsigned int i=0,i_end=_directory.size();i!=i_end;++i)
345
                        {
346
                                if (_directory[i].selected())
347
                                {
348
                                        ++count;
349
 
350
                                        sprintf(block2.data.data_xfer.file_name,"%s.%s",_pathname,
351
                                                _directory[i]->name);
352
                                        block2.size=(44+strlen(block2.data.data_xfer.file_name)+4)&~3;
353
 
354
                                        wimp_send_message_to_window(wimp_USER_MESSAGE,&block2,
355
                                                pointer.w,pointer.i);
356
                                }
357
                        }
358
                }
359
        }
360
}
361
 
56 gdshaw@RISCPKG.ORG 362
void filer_window::handle_data_xfer(wimp_message& block)
363
{
364
        // A buffer to temporarily hold the leafname.
365
        static char leafname[212];
366
 
367
        switch (block.action)
368
        {
369
        case message_DATA_SAVE:
370
                {
371
                        // Extract leafname.
372
                        char* p=std::strrchr(block.data.data_xfer.file_name,'.');
373
                        if (p) ++p;
374
                        else p=block.data.data_xfer.file_name;
375
                        std::strcpy(leafname,p);
376
 
377
                        // Construct and send acknowledgement.
378
                        block.your_ref=block.my_ref;
379
                        block.action=message_DATA_SAVE_ACK;
380
                        std::sprintf(block.data.data_xfer.file_name,"%s.%s",
381
                                _pathname,leafname);
382
                        block.size=(44+std::strlen(block.data.data_xfer.file_name)+4)&~3;
383
                        xwimp_send_message(wimp_USER_MESSAGE,&block,block.sender);
384
                }
385
                break;
386
        case message_DATA_LOAD:
387
                {
388
                        // Construct and send acknowledgement.
389
                        block.your_ref=block.my_ref;
390
                        block.action=message_DATA_LOAD_ACK;
391
                        xwimp_send_message(wimp_USER_MESSAGE,&block,block.sender);
392
                }
393
                break;
394
        }
395
}
396
 
31 gdshaw@RISCPKG.ORG 397
void filer_window::handle_menus_deleted()
398
{
399
        if (_temp_selection!=directory::npos)
400
        {
401
                _directory[_temp_selection].selected(0);
402
                force_redraw_cell(_temp_selection);
403
                _temp_selection=directory::npos;
404
        }
405
}
406
 
36 gdshaw@RISCPKG.ORG 407
void filer_window::options(const filer_options& options)
408
{
409
        // Keep track of whether window needs to be reformatted, restored
410
        // and redrawn.
411
        int need_reformat=0;
412
        int need_resort=0;
413
        int need_redraw=0;
414
 
415
        // Check whether layout method has changed.
416
        if (&options.layout()!=&_options.layout())
417
        {
418
                need_reformat=1;
419
                need_redraw=1;
420
        }
421
 
422
        // Check whether sorting method has changed.
423
        if (&options.sort()!=&_options.sort())
424
        {
425
                need_resort=1;
426
                need_redraw=1;
427
        }
428
 
429
        // Update options.
430
        _options=options;
431
 
432
        // Reformat, resort and redraw window as required.
433
        if (need_resort) _directory.sort(_options.sort());
434
        if (need_redraw) force_redraw();
435
        if (need_reformat)
436
        {
437
                reformat();
438
                if (need_redraw) force_redraw();
439
        }
440
}
441
 
31 gdshaw@RISCPKG.ORG 442
filer_menu& filer_window::shared_menu() const
443
{
444
        static filer_menu* _shared_menu=0;
445
        if (!_shared_menu)
446
        {
38 gdshaw@RISCPKG.ORG 447
                wimp_open_template(template_pathname);
31 gdshaw@RISCPKG.ORG 448
                _shared_menu=new filer_menu(parent_application());
38 gdshaw@RISCPKG.ORG 449
                wimp_close_template();
31 gdshaw@RISCPKG.ORG 450
        }
451
        return *_shared_menu;
452
}
453
 
21 gdshaw@RISCPKG.ORG 454
void filer_window::reload()
455
{
456
        static int buffer[256];
457
        _directory.load(_pathname,buffer,sizeof(buffer));
458
}
25 gdshaw@RISCPKG.ORG 459
 
460
void filer_window::reformat()
461
{
462
        wimp_window_state wstate;
463
        get_window_state(wstate);
464
        reformat(wstate.visible.x1-wstate.visible.x0);
465
}
466
 
467
void filer_window::reformat(int xsize)
468
{
469
        // Fetch layout.
470
        layout_method& layout=options().layout();
471
        int xgap=layout.xgap();
472
        int ygap=layout.ygap();
473
 
53 gdshaw@RISCPKG.ORG 474
        // Window will automatically resize if visible area matches extent.
475
        wimp_window_info winfo;
476
        get_window_info_header(winfo);
477
        int xauto=(winfo.xscroll==0)&&
478
                (winfo.visible.x1-winfo.visible.x0==winfo.extent.x1-winfo.extent.x0);
479
        int yauto=(winfo.yscroll==0)&&
480
                (winfo.visible.y1-winfo.visible.y0==winfo.extent.y1-winfo.extent.y0);
481
 
25 gdshaw@RISCPKG.ORG 482
        // Calculate cell size.  This must be able to accommodate
483
        // - the minimum cell size for the chosen layout, and
484
        // - the actual size occupied by each file to be listed.
485
        os_coord csize=layout.min_size(_options);
486
        for (unsigned int i=0;i!=_directory.size();++i)
487
        {
488
                os_coord size=layout.size(*_directory[i],_options);
489
                if (size.x>csize.x) csize.x=size.x;
490
                if (size.y>csize.y) csize.y=size.y;
491
        }
492
 
493
        // Apply the calculated cell size.
494
        _xcsize=csize.x;
495
        _ycsize=csize.y;
496
 
497
        // Determine number of rows and columns.
53 gdshaw@RISCPKG.ORG 498
        if (xauto&&(_yccount<2))
499
        {
500
                _xccount=(_directory.size()<4)?_directory.size():4;
501
        }
502
        else
503
        {
504
                _xccount=xsize/(_xcsize+xgap);
505
        }
25 gdshaw@RISCPKG.ORG 506
        if (_xccount<1) _xccount=1;
507
        _yccount=(_directory.size()+_xccount-1)/_xccount;
508
        if (_yccount<1) _yccount=1;
509
 
510
        // Calculate new extent.
511
        int extent_xsize=_xccount*(_xcsize+xgap)+xgap;
512
        int extent_ysize=_yccount*(_ycsize+ygap)+ygap;
513
 
28 gdshaw@RISCPKG.ORG 514
        // Do not force the window to become narrower than the width requested,
25 gdshaw@RISCPKG.ORG 515
        // unless there are too few directory entries to justify that width.
516
        if (extent_xsize<xsize)
517
        {
518
                extent_xsize=xsize;
519
                if (((extent_xsize+_xcsize-1)/(_xcsize+xgap))>
520
                        static_cast<int>(_directory.size()))
521
                {
522
                        extent_xsize=_directory.size()*(_xcsize+xgap)+xgap;
523
                }
524
        }
525
 
526
        // Apply the calculated extent.
527
        os_box extent;
528
        extent.x0=0;
529
        extent.y0=-extent_ysize;
530
        extent.x1=extent_xsize;
531
        extent.y1=0;
532
        set_extent(extent);
533
}
29 gdshaw@RISCPKG.ORG 534
 
53 gdshaw@RISCPKG.ORG 535
void filer_window::set_extent(const os_box& extent)
536
{
537
        // Window will automatically resize if visible area matches extent.
538
        wimp_window_info winfo;
539
        get_window_info_header(winfo);
540
        int xauto=(winfo.xscroll==0)&&
541
                (winfo.visible.x1-winfo.visible.x0==winfo.extent.x1-winfo.extent.x0);
542
        int yauto=(winfo.yscroll==0)&&
543
                (winfo.visible.y1-winfo.visible.y0==winfo.extent.y1-winfo.extent.y0);
544
 
545
        // Set the new extent.
546
        window::set_extent(extent);
547
 
548
        // Open the window.
549
        wimp_open open;
550
        open.visible=winfo.visible;
551
        open.xscroll=winfo.xscroll;
552
        open.yscroll=winfo.yscroll;
553
        open.next=winfo.next;
554
 
555
        // If automatically resizing then adjust visible area to match extent.
556
        int reopen=0;
557
        if (xauto&&(winfo.visible.x1-winfo.visible.x0!=extent.x1-extent.x0))
558
        {
559
                open.visible.x1=open.visible.x0+(extent.x1-extent.x0);
560
                reopen=1;
561
        }
562
        if (yauto&&(open.visible.y1-open.visible.y0!=extent.y1-extent.y0))
563
        {
564
                open.visible.y0=open.visible.y1-(extent.y1-extent.y0);
565
                reopen=1;
566
        }
567
        if (reopen) open_window(open);
568
}
569
 
30 gdshaw@RISCPKG.ORG 570
unsigned int filer_window::find_cell(const os_coord& p)
571
{
572
        layout_method& layout=options().layout();
573
        int xgap=layout.xgap();
574
        int ygap=layout.ygap();
575
 
576
        wimp_window_state state;
577
        get_window_state(state);
578
        int x=p.x-state.visible.x0+state.xscroll-xgap;
579
        int y=p.y-state.visible.y1+state.yscroll+ygap;
580
 
581
        int xc=x/(_xcsize+xgap);
582
        int yc=(-y)/(_ycsize+ygap);
583
        unsigned int index=xc+yc*_xccount;
584
 
585
        x-=xc*(_xcsize+xgap);
586
        y+=yc*(_ycsize+ygap);
587
 
588
        int found=(x>=0)&&(y>=-_ycsize)&&(x<_xcsize)&&(y<0)&&
589
                (xc>=0)&&(yc>=0)&&(xc<_xccount)&&(yc<_yccount)&&
590
                (index<_directory.size());
591
 
592
        return (found)?index:directory::npos;
593
}
594
 
595
void filer_window::force_redraw_cell(unsigned int index)
596
{
597
        layout_method& layout=options().layout();
598
        int xgap=layout.xgap();
599
        int ygap=layout.ygap();
600
 
601
        int xc=index%_xccount;
602
        int yc=index/_xccount;
603
 
604
        os_box box;
605
        box.x0=xgap+xc*(_xcsize+xgap);
606
        box.y0=-(yc+1)*(_ycsize+ygap);
607
        box.x1=box.x0+_xcsize;
608
        box.y1=box.y0+_ycsize;
609
        force_redraw(box);
610
}
611
 
34 gdshaw@RISCPKG.ORG 612
void filer_window::refresh()
613
{
614
        reload();
615
        reformat();
616
        force_redraw();
617
}
618
 
30 gdshaw@RISCPKG.ORG 619
void filer_window::select_all(int selected)
620
{
621
        layout_method& layout=options().layout();
622
        int xgap=layout.xgap();
623
        int ygap=layout.ygap();
624
 
625
        int xc_min=_xccount;
626
        int yc_min=_yccount;
627
        int xc_max=0;
628
        int yc_max=0;
629
 
630
        for (unsigned int i=0;i!=_directory.size();++i)
631
        {
632
                if (_directory[i].selected()!=selected)
633
                {
634
                        _directory[i].selected(selected);
635
 
636
                        int xc=i%_xccount;
637
                        int yc=i/_xccount;
638
                        if (xc<xc_min) xc_min=xc;
639
                        if (yc<yc_min) yc_min=yc;
640
                        if (xc+1>xc_max) xc_max=xc+1;
641
                        if (yc+1>yc_max) yc_max=yc+1;
642
                }
643
        }
644
 
645
        if ((xc_max>xc_min)&&(yc_max>yc_min))
646
        {
647
                os_box box;
648
                box.x0=xgap+xc_min*(_xcsize+xgap);
649
                box.y0=-yc_max*(_ycsize+ygap);
650
                box.x1=xc_max*(_xcsize+xgap);
651
                box.y1=-ygap-yc_min*(_ycsize+ygap);
652
                force_redraw(box);
653
        }
31 gdshaw@RISCPKG.ORG 654
 
655
        _temp_selection=directory::npos;
30 gdshaw@RISCPKG.ORG 656
}
657
 
29 gdshaw@RISCPKG.ORG 658
void filer_window::open_parent(const os_coord& offset) const
659
{
660
        // Determine whether there is a parent directory.
661
        char* lastdot=strrchr(_pathname,'.');
662
        if (lastdot&&strcmp(lastdot+1,"$"))
663
        {
664
                // Find top-left corner of this window.
665
                wimp_window_state state;
666
                get_window_state(state);
667
 
668
                // Add offset to give top-left corner of new window.
669
                os_box box;
670
                box.x0=state.visible.x0+offset.x;
671
                box.y1=state.visible.y1+offset.y;
672
                box.x1=box.x0;
673
                box.y0=box.y1;
674
 
675
                // Open new window.
676
                *lastdot=0;
677
                new filer_window((filer_application*)parent_application(),
678
                        _pathname,box,_options);
679
                *lastdot='.';
680
        }
681
}
35 gdshaw@RISCPKG.ORG 682
 
42 gdshaw@RISCPKG.ORG 683
void filer_window::set_work_directory() const
684
{
685
        osfscontrol_dir(_pathname);
686
}
687
 
45 gdshaw@RISCPKG.ORG 688
wimp_t filer_window::begin_filer_action()
689
{
690
        // Start a FilerAction task.
691
        wimp_t handle=wimp_start_task("Filer_Action");
692
 
693
        // Send it the pathname of the directory on which it is to act.
694
        fileraction_send_selected_directory(handle,pathname());
695
 
696
        // Send it the list of leafnames on which it is to act.
697
        for (unsigned int i=0,i_end=_directory.size();i!=i_end;++i)
698
        {
699
                if (_directory[i].selected())
700
                {
701
                        const char* leafname=_directory[i]->name;
702
                        fileraction_send_selected_file(handle,leafname);
703
                }
704
        }
705
 
706
        // Return the task handle of the FilerAction task.
707
        return handle;
708
}
709
 
35 gdshaw@RISCPKG.ORG 710
void filer_window::run(osgbpb_info& info,int close,int shift)
711
{
712
        // Need to at least partially handle shift key here, because
713
        // Filer_Run does not allow coordinates to be specified when
714
        // shift-clicking an application directory.
715
        // (... unless there is an alternative way to invoke Filer_Run?)
716
 
717
        static char buffer[12+max_name_length];
718
        if ((info.obj_type&fileswitch_IS_DIR)&&((info.name[0]!='!')||shift))
719
        {
720
                // Get dimensions of this window.
721
                wimp_window_state state;
722
                get_window_state(state);
723
 
724
                // Choose coordinates for new window.
725
                // If closing this window then open in same position,
726
                // otherwise open below and to the right.
727
                os_coord offset=_auto_pos();
728
                os_box box;
729
                box.x0=state.visible.x0+((close)?0:offset.x);
730
                box.y1=state.visible.y1+((close)?0:offset.y);
731
                box.x1=box.x0;
732
                box.y0=box.y1;
733
 
734
                // Open new window.
735
                if (std::strlen(_pathname)+std::strlen(info.name)+1<max_name_length)
736
                {
737
                        std::sprintf(buffer,"%s.%s",_pathname,info.name);
738
                        window* w=new filer_window(
739
                                (filer_application*)parent_application(),
740
                                buffer,box,_options);
741
                }
742
        }
743
        else
744
        {
745
                // Run object.
746
                if (std::strlen(_pathname)+std::strlen(info.name)+1<max_name_length)
747
                {
748
                        std::sprintf(buffer,"Run %s.%s",_pathname,info.name);
749
                        wimp_start_task(buffer);
750
                }
751
        }
752
}