Subversion Repositories Filer-Free

Rev

Rev 55 | Rev 57 | 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
        }
31 gdshaw@RISCPKG.ORG 261
        else if (block.buttons&(wimp_SINGLE_SELECT|wimp_SINGLE_ADJUST))
262
        {
30 gdshaw@RISCPKG.ORG 263
                // If single select click then first de-select everything.
264
                if (block.buttons&wimp_SINGLE_SELECT) select_all(0);
265
 
266
                // If click within a cell then select that cell.
267
                if (index!=directory::npos)
268
                {
269
                        _directory[index].selected(!_directory[index].selected());
270
                        force_redraw_cell(index);
271
                }
272
        }
35 gdshaw@RISCPKG.ORG 273
 
274
        // If this window has closed as a result of the mouse event
275
        // then delete it.
276
        if (close) delete this;
30 gdshaw@RISCPKG.ORG 277
}
278
 
55 gdshaw@RISCPKG.ORG 279
void filer_window::handle_user_drag_box(wimp_dragged& block)
280
{
281
        // Read pointer state.
282
        wimp_pointer pointer;
283
        xwimp_get_pointer_info(&pointer);
284
 
285
        // Read shift state.
286
        int shift_state=0;
287
        xosbyte1(osbyte_VAR_KEYBOARD_STATE,0,0xff,&shift_state);
288
        int shift=(shift_state&0x08)!=0;
289
 
290
        if (application* app=parent_application())
291
        {
292
                if (pointer.w==handle())
293
                {
294
                        // Object has been dropped back onto this window: no action.
295
                }
296
                else if (filer_window* w=
297
                        dynamic_cast<filer_window*>(app->find_window(pointer.w)))
298
                {
299
                        // Object has been dropped onto another filer window.
300
                        wimp_t filer_action_handle=begin_filer_action();
301
 
302
                        // Copy or move according to shift state.
303
                        const char* dst_pathname=w->pathname();
304
                        fileraction_flags flags=options().flags()|fileraction_RECURSE;
305
                        if (shift)
306
                        {
307
                                fileractionsendstartoperation_move(filer_action_handle,flags,
308
                                        dst_pathname,strlen(dst_pathname)+1);
309
                        }
310
                        else
311
                        {
312
                                fileractionsendstartoperation_copy(filer_action_handle,flags,
313
                                        dst_pathname,strlen(dst_pathname)+1);
314
                        }
315
                }
316
                else
317
                {
318
                        // Object has been dropped onto some other type of window.
319
                        // Construct Message_DataLoad.
320
                        wimp_message block2;
321
                        block2.your_ref=0;
322
                        block2.action=message_DATA_LOAD;
323
                        block2.data.data_xfer.w=pointer.w;
324
                        block2.data.data_xfer.i=pointer.i;
325
                        block2.data.data_xfer.pos=pointer.pos;
326
                        block2.data.data_xfer.est_size=-1; /* can do better than this */
327
                        block2.data.data_xfer.file_type=0xfff; /* can better this too */
328
 
329
                        // Send a Message_DataLoad for each object in the selection.
330
                        int count=0;
331
                        for (unsigned int i=0,i_end=_directory.size();i!=i_end;++i)
332
                        {
333
                                if (_directory[i].selected())
334
                                {
335
                                        ++count;
336
 
337
                                        sprintf(block2.data.data_xfer.file_name,"%s.%s",_pathname,
338
                                                _directory[i]->name);
339
                                        block2.size=(44+strlen(block2.data.data_xfer.file_name)+4)&~3;
340
 
341
                                        wimp_send_message_to_window(wimp_USER_MESSAGE,&block2,
342
                                                pointer.w,pointer.i);
343
                                }
344
                        }
345
                }
346
        }
347
}
348
 
56 gdshaw@RISCPKG.ORG 349
void filer_window::handle_data_xfer(wimp_message& block)
350
{
351
        // A buffer to temporarily hold the leafname.
352
        static char leafname[212];
353
 
354
        switch (block.action)
355
        {
356
        case message_DATA_SAVE:
357
                {
358
                        // Extract leafname.
359
                        char* p=std::strrchr(block.data.data_xfer.file_name,'.');
360
                        if (p) ++p;
361
                        else p=block.data.data_xfer.file_name;
362
                        std::strcpy(leafname,p);
363
 
364
                        // Construct and send acknowledgement.
365
                        block.your_ref=block.my_ref;
366
                        block.action=message_DATA_SAVE_ACK;
367
                        std::sprintf(block.data.data_xfer.file_name,"%s.%s",
368
                                _pathname,leafname);
369
                        block.size=(44+std::strlen(block.data.data_xfer.file_name)+4)&~3;
370
                        xwimp_send_message(wimp_USER_MESSAGE,&block,block.sender);
371
                }
372
                break;
373
        case message_DATA_LOAD:
374
                {
375
                        // Construct and send acknowledgement.
376
                        block.your_ref=block.my_ref;
377
                        block.action=message_DATA_LOAD_ACK;
378
                        xwimp_send_message(wimp_USER_MESSAGE,&block,block.sender);
379
                }
380
                break;
381
        }
382
}
383
 
31 gdshaw@RISCPKG.ORG 384
void filer_window::handle_menus_deleted()
385
{
386
        if (_temp_selection!=directory::npos)
387
        {
388
                _directory[_temp_selection].selected(0);
389
                force_redraw_cell(_temp_selection);
390
                _temp_selection=directory::npos;
391
        }
392
}
393
 
36 gdshaw@RISCPKG.ORG 394
void filer_window::options(const filer_options& options)
395
{
396
        // Keep track of whether window needs to be reformatted, restored
397
        // and redrawn.
398
        int need_reformat=0;
399
        int need_resort=0;
400
        int need_redraw=0;
401
 
402
        // Check whether layout method has changed.
403
        if (&options.layout()!=&_options.layout())
404
        {
405
                need_reformat=1;
406
                need_redraw=1;
407
        }
408
 
409
        // Check whether sorting method has changed.
410
        if (&options.sort()!=&_options.sort())
411
        {
412
                need_resort=1;
413
                need_redraw=1;
414
        }
415
 
416
        // Update options.
417
        _options=options;
418
 
419
        // Reformat, resort and redraw window as required.
420
        if (need_resort) _directory.sort(_options.sort());
421
        if (need_redraw) force_redraw();
422
        if (need_reformat)
423
        {
424
                reformat();
425
                if (need_redraw) force_redraw();
426
        }
427
}
428
 
31 gdshaw@RISCPKG.ORG 429
filer_menu& filer_window::shared_menu() const
430
{
431
        static filer_menu* _shared_menu=0;
432
        if (!_shared_menu)
433
        {
38 gdshaw@RISCPKG.ORG 434
                wimp_open_template(template_pathname);
31 gdshaw@RISCPKG.ORG 435
                _shared_menu=new filer_menu(parent_application());
38 gdshaw@RISCPKG.ORG 436
                wimp_close_template();
31 gdshaw@RISCPKG.ORG 437
        }
438
        return *_shared_menu;
439
}
440
 
21 gdshaw@RISCPKG.ORG 441
void filer_window::reload()
442
{
443
        static int buffer[256];
444
        _directory.load(_pathname,buffer,sizeof(buffer));
445
}
25 gdshaw@RISCPKG.ORG 446
 
447
void filer_window::reformat()
448
{
449
        wimp_window_state wstate;
450
        get_window_state(wstate);
451
        reformat(wstate.visible.x1-wstate.visible.x0);
452
}
453
 
454
void filer_window::reformat(int xsize)
455
{
456
        // Fetch layout.
457
        layout_method& layout=options().layout();
458
        int xgap=layout.xgap();
459
        int ygap=layout.ygap();
460
 
53 gdshaw@RISCPKG.ORG 461
        // Window will automatically resize if visible area matches extent.
462
        wimp_window_info winfo;
463
        get_window_info_header(winfo);
464
        int xauto=(winfo.xscroll==0)&&
465
                (winfo.visible.x1-winfo.visible.x0==winfo.extent.x1-winfo.extent.x0);
466
        int yauto=(winfo.yscroll==0)&&
467
                (winfo.visible.y1-winfo.visible.y0==winfo.extent.y1-winfo.extent.y0);
468
 
25 gdshaw@RISCPKG.ORG 469
        // Calculate cell size.  This must be able to accommodate
470
        // - the minimum cell size for the chosen layout, and
471
        // - the actual size occupied by each file to be listed.
472
        os_coord csize=layout.min_size(_options);
473
        for (unsigned int i=0;i!=_directory.size();++i)
474
        {
475
                os_coord size=layout.size(*_directory[i],_options);
476
                if (size.x>csize.x) csize.x=size.x;
477
                if (size.y>csize.y) csize.y=size.y;
478
        }
479
 
480
        // Apply the calculated cell size.
481
        _xcsize=csize.x;
482
        _ycsize=csize.y;
483
 
484
        // Determine number of rows and columns.
53 gdshaw@RISCPKG.ORG 485
        if (xauto&&(_yccount<2))
486
        {
487
                _xccount=(_directory.size()<4)?_directory.size():4;
488
        }
489
        else
490
        {
491
                _xccount=xsize/(_xcsize+xgap);
492
        }
25 gdshaw@RISCPKG.ORG 493
        if (_xccount<1) _xccount=1;
494
        _yccount=(_directory.size()+_xccount-1)/_xccount;
495
        if (_yccount<1) _yccount=1;
496
 
497
        // Calculate new extent.
498
        int extent_xsize=_xccount*(_xcsize+xgap)+xgap;
499
        int extent_ysize=_yccount*(_ycsize+ygap)+ygap;
500
 
28 gdshaw@RISCPKG.ORG 501
        // Do not force the window to become narrower than the width requested,
25 gdshaw@RISCPKG.ORG 502
        // unless there are too few directory entries to justify that width.
503
        if (extent_xsize<xsize)
504
        {
505
                extent_xsize=xsize;
506
                if (((extent_xsize+_xcsize-1)/(_xcsize+xgap))>
507
                        static_cast<int>(_directory.size()))
508
                {
509
                        extent_xsize=_directory.size()*(_xcsize+xgap)+xgap;
510
                }
511
        }
512
 
513
        // Apply the calculated extent.
514
        os_box extent;
515
        extent.x0=0;
516
        extent.y0=-extent_ysize;
517
        extent.x1=extent_xsize;
518
        extent.y1=0;
519
        set_extent(extent);
520
}
29 gdshaw@RISCPKG.ORG 521
 
53 gdshaw@RISCPKG.ORG 522
void filer_window::set_extent(const os_box& extent)
523
{
524
        // Window will automatically resize if visible area matches extent.
525
        wimp_window_info winfo;
526
        get_window_info_header(winfo);
527
        int xauto=(winfo.xscroll==0)&&
528
                (winfo.visible.x1-winfo.visible.x0==winfo.extent.x1-winfo.extent.x0);
529
        int yauto=(winfo.yscroll==0)&&
530
                (winfo.visible.y1-winfo.visible.y0==winfo.extent.y1-winfo.extent.y0);
531
 
532
        // Set the new extent.
533
        window::set_extent(extent);
534
 
535
        // Open the window.
536
        wimp_open open;
537
        open.visible=winfo.visible;
538
        open.xscroll=winfo.xscroll;
539
        open.yscroll=winfo.yscroll;
540
        open.next=winfo.next;
541
 
542
        // If automatically resizing then adjust visible area to match extent.
543
        int reopen=0;
544
        if (xauto&&(winfo.visible.x1-winfo.visible.x0!=extent.x1-extent.x0))
545
        {
546
                open.visible.x1=open.visible.x0+(extent.x1-extent.x0);
547
                reopen=1;
548
        }
549
        if (yauto&&(open.visible.y1-open.visible.y0!=extent.y1-extent.y0))
550
        {
551
                open.visible.y0=open.visible.y1-(extent.y1-extent.y0);
552
                reopen=1;
553
        }
554
        if (reopen) open_window(open);
555
}
556
 
30 gdshaw@RISCPKG.ORG 557
unsigned int filer_window::find_cell(const os_coord& p)
558
{
559
        layout_method& layout=options().layout();
560
        int xgap=layout.xgap();
561
        int ygap=layout.ygap();
562
 
563
        wimp_window_state state;
564
        get_window_state(state);
565
        int x=p.x-state.visible.x0+state.xscroll-xgap;
566
        int y=p.y-state.visible.y1+state.yscroll+ygap;
567
 
568
        int xc=x/(_xcsize+xgap);
569
        int yc=(-y)/(_ycsize+ygap);
570
        unsigned int index=xc+yc*_xccount;
571
 
572
        x-=xc*(_xcsize+xgap);
573
        y+=yc*(_ycsize+ygap);
574
 
575
        int found=(x>=0)&&(y>=-_ycsize)&&(x<_xcsize)&&(y<0)&&
576
                (xc>=0)&&(yc>=0)&&(xc<_xccount)&&(yc<_yccount)&&
577
                (index<_directory.size());
578
 
579
        return (found)?index:directory::npos;
580
}
581
 
582
void filer_window::force_redraw_cell(unsigned int index)
583
{
584
        layout_method& layout=options().layout();
585
        int xgap=layout.xgap();
586
        int ygap=layout.ygap();
587
 
588
        int xc=index%_xccount;
589
        int yc=index/_xccount;
590
 
591
        os_box box;
592
        box.x0=xgap+xc*(_xcsize+xgap);
593
        box.y0=-(yc+1)*(_ycsize+ygap);
594
        box.x1=box.x0+_xcsize;
595
        box.y1=box.y0+_ycsize;
596
        force_redraw(box);
597
}
598
 
34 gdshaw@RISCPKG.ORG 599
void filer_window::refresh()
600
{
601
        reload();
602
        reformat();
603
        force_redraw();
604
}
605
 
30 gdshaw@RISCPKG.ORG 606
void filer_window::select_all(int selected)
607
{
608
        layout_method& layout=options().layout();
609
        int xgap=layout.xgap();
610
        int ygap=layout.ygap();
611
 
612
        int xc_min=_xccount;
613
        int yc_min=_yccount;
614
        int xc_max=0;
615
        int yc_max=0;
616
 
617
        for (unsigned int i=0;i!=_directory.size();++i)
618
        {
619
                if (_directory[i].selected()!=selected)
620
                {
621
                        _directory[i].selected(selected);
622
 
623
                        int xc=i%_xccount;
624
                        int yc=i/_xccount;
625
                        if (xc<xc_min) xc_min=xc;
626
                        if (yc<yc_min) yc_min=yc;
627
                        if (xc+1>xc_max) xc_max=xc+1;
628
                        if (yc+1>yc_max) yc_max=yc+1;
629
                }
630
        }
631
 
632
        if ((xc_max>xc_min)&&(yc_max>yc_min))
633
        {
634
                os_box box;
635
                box.x0=xgap+xc_min*(_xcsize+xgap);
636
                box.y0=-yc_max*(_ycsize+ygap);
637
                box.x1=xc_max*(_xcsize+xgap);
638
                box.y1=-ygap-yc_min*(_ycsize+ygap);
639
                force_redraw(box);
640
        }
31 gdshaw@RISCPKG.ORG 641
 
642
        _temp_selection=directory::npos;
30 gdshaw@RISCPKG.ORG 643
}
644
 
29 gdshaw@RISCPKG.ORG 645
void filer_window::open_parent(const os_coord& offset) const
646
{
647
        // Determine whether there is a parent directory.
648
        char* lastdot=strrchr(_pathname,'.');
649
        if (lastdot&&strcmp(lastdot+1,"$"))
650
        {
651
                // Find top-left corner of this window.
652
                wimp_window_state state;
653
                get_window_state(state);
654
 
655
                // Add offset to give top-left corner of new window.
656
                os_box box;
657
                box.x0=state.visible.x0+offset.x;
658
                box.y1=state.visible.y1+offset.y;
659
                box.x1=box.x0;
660
                box.y0=box.y1;
661
 
662
                // Open new window.
663
                *lastdot=0;
664
                new filer_window((filer_application*)parent_application(),
665
                        _pathname,box,_options);
666
                *lastdot='.';
667
        }
668
}
35 gdshaw@RISCPKG.ORG 669
 
42 gdshaw@RISCPKG.ORG 670
void filer_window::set_work_directory() const
671
{
672
        osfscontrol_dir(_pathname);
673
}
674
 
45 gdshaw@RISCPKG.ORG 675
wimp_t filer_window::begin_filer_action()
676
{
677
        // Start a FilerAction task.
678
        wimp_t handle=wimp_start_task("Filer_Action");
679
 
680
        // Send it the pathname of the directory on which it is to act.
681
        fileraction_send_selected_directory(handle,pathname());
682
 
683
        // Send it the list of leafnames on which it is to act.
684
        for (unsigned int i=0,i_end=_directory.size();i!=i_end;++i)
685
        {
686
                if (_directory[i].selected())
687
                {
688
                        const char* leafname=_directory[i]->name;
689
                        fileraction_send_selected_file(handle,leafname);
690
                }
691
        }
692
 
693
        // Return the task handle of the FilerAction task.
694
        return handle;
695
}
696
 
35 gdshaw@RISCPKG.ORG 697
void filer_window::run(osgbpb_info& info,int close,int shift)
698
{
699
        // Need to at least partially handle shift key here, because
700
        // Filer_Run does not allow coordinates to be specified when
701
        // shift-clicking an application directory.
702
        // (... unless there is an alternative way to invoke Filer_Run?)
703
 
704
        static char buffer[12+max_name_length];
705
        if ((info.obj_type&fileswitch_IS_DIR)&&((info.name[0]!='!')||shift))
706
        {
707
                // Get dimensions of this window.
708
                wimp_window_state state;
709
                get_window_state(state);
710
 
711
                // Choose coordinates for new window.
712
                // If closing this window then open in same position,
713
                // otherwise open below and to the right.
714
                os_coord offset=_auto_pos();
715
                os_box box;
716
                box.x0=state.visible.x0+((close)?0:offset.x);
717
                box.y1=state.visible.y1+((close)?0:offset.y);
718
                box.x1=box.x0;
719
                box.y0=box.y1;
720
 
721
                // Open new window.
722
                if (std::strlen(_pathname)+std::strlen(info.name)+1<max_name_length)
723
                {
724
                        std::sprintf(buffer,"%s.%s",_pathname,info.name);
725
                        window* w=new filer_window(
726
                                (filer_application*)parent_application(),
727
                                buffer,box,_options);
728
                }
729
        }
730
        else
731
        {
732
                // Run object.
733
                if (std::strlen(_pathname)+std::strlen(info.name)+1<max_name_length)
734
                {
735
                        std::sprintf(buffer,"Run %s.%s",_pathname,info.name);
736
                        wimp_start_task(buffer);
737
                }
738
        }
739
}