Subversion Repositories Filer-Free

Rev

Rev 57 | Rev 63 | 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);
58 gdshaw@RISCPKG.ORG 207
        bool alt=(shift_state&0x01)!=0;
208
        bool shift=(shift_state&0x08)!=0;
35 gdshaw@RISCPKG.ORG 209
 
30 gdshaw@RISCPKG.ORG 210
        // Find cell under pointer.
211
        unsigned int index=find_cell(block.pos);
212
 
35 gdshaw@RISCPKG.ORG 213
        bool close=false;
31 gdshaw@RISCPKG.ORG 214
        if (block.buttons==wimp_CLICK_MENU)
30 gdshaw@RISCPKG.ORG 215
        {
31 gdshaw@RISCPKG.ORG 216
                // Any existing menu will be deleted by this action.
217
                handle_menus_deleted();
218
 
219
                // Count number of cells selected.
220
                int count=0;
221
                for (unsigned int i=0,i_end=_directory.size();i!=i_end;++i)
222
                {
223
                        if (_directory[i].selected()) ++count;
224
                }
225
 
226
                // If pointer is over a cell and nothing has yet been selected
227
                // then temporarily select the cell under the pointer.
228
                if (index!=directory::npos&&!_directory[index].selected()&&!count)
229
                {
230
                        _directory[index].selected(true);
231
                        _temp_selection=index;
232
                        force_redraw_cell(index);
233
                }
234
 
235
                // Update then open the menu.
236
                shared_menu().update(this);
237
                shared_menu().show(block);
238
        }
35 gdshaw@RISCPKG.ORG 239
        else if (block.buttons&(wimp_DOUBLE_ADJUST|wimp_DOUBLE_SELECT))
240
        {
241
                // If double click within a cell then run that object.
242
                if (index!=directory::npos)
243
                {
244
                        select_all(0);
245
                        close=(block.buttons&wimp_DOUBLE_ADJUST)!=0;
246
                        if (close) close_window();
247
                        run(*_directory[index],close,shift);
248
                }
249
        }
55 gdshaw@RISCPKG.ORG 250
        else if (block.buttons&(wimp_DRAG_SELECT|wimp_DRAG_ADJUST))
251
        {
252
                // No action unless the pointer is over a cell.
253
                if (index!=directory::npos)
254
                {
58 gdshaw@RISCPKG.ORG 255
                        // No action if select drag with alt.
256
                        if ((block.buttons&wimp_DRAG_ADJUST)||!alt)
257
                        {
258
                                // Choose sprite to be dragged.
259
                                filer_sprite sprite(*_directory[index]);
55 gdshaw@RISCPKG.ORG 260
 
58 gdshaw@RISCPKG.ORG 261
                                // Begin the drag with this sprite.
262
                                begin_drag(block,sprite.name());
263
                        }
55 gdshaw@RISCPKG.ORG 264
                }
265
        }
57 gdshaw@RISCPKG.ORG 266
        else if (block.buttons&wimp_SINGLE_ADJUST)
31 gdshaw@RISCPKG.ORG 267
        {
58 gdshaw@RISCPKG.ORG 268
                // Cancel rename if one is in progress.
269
                if (filer_application* app=
270
                        dynamic_cast<filer_application*>(parent_application()))
271
                {
272
                        app->cancel_rename();
273
                }
274
 
57 gdshaw@RISCPKG.ORG 275
                // Invert selection state of cell under pointer.
30 gdshaw@RISCPKG.ORG 276
                if (index!=directory::npos)
277
                {
278
                        _directory[index].selected(!_directory[index].selected());
279
                        force_redraw_cell(index);
280
                }
281
        }
57 gdshaw@RISCPKG.ORG 282
        else if (block.buttons&wimp_SINGLE_SELECT)
283
        {
58 gdshaw@RISCPKG.ORG 284
                // Cancel rename if one is in progress.
285
                if (filer_application* app=
286
                        dynamic_cast<filer_application*>(parent_application()))
57 gdshaw@RISCPKG.ORG 287
                {
58 gdshaw@RISCPKG.ORG 288
                        app->cancel_rename();
289
                }
290
 
291
                if (alt&&index!=directory::npos)
292
                {
293
                        if (filer_application* app=dynamic_cast<filer_application*>(
294
                                parent_application()))
295
                        {
296
                                app->begin_rename(*this,index,block.pos);
297
                        }
298
                }
299
                else if (index==directory::npos||!_directory[index].selected())
300
                {
301
                        // Select click over a cell which is not already selected.
57 gdshaw@RISCPKG.ORG 302
                        // De-select everything.
303
                        select_all(0);
35 gdshaw@RISCPKG.ORG 304
 
57 gdshaw@RISCPKG.ORG 305
                        // Select cell under pointer.
306
                        if (index!=directory::npos)
307
                        {
308
                                _directory[index].selected(true);
309
                                force_redraw_cell(index);
310
                        }
311
                }
312
        }
313
 
35 gdshaw@RISCPKG.ORG 314
        // If this window has closed as a result of the mouse event
315
        // then delete it.
316
        if (close) delete this;
30 gdshaw@RISCPKG.ORG 317
}
318
 
55 gdshaw@RISCPKG.ORG 319
void filer_window::handle_user_drag_box(wimp_dragged& block)
320
{
321
        // Read pointer state.
322
        wimp_pointer pointer;
323
        xwimp_get_pointer_info(&pointer);
324
 
325
        // Read shift state.
326
        int shift_state=0;
327
        xosbyte1(osbyte_VAR_KEYBOARD_STATE,0,0xff,&shift_state);
328
        int shift=(shift_state&0x08)!=0;
329
 
330
        if (application* app=parent_application())
331
        {
332
                if (pointer.w==handle())
333
                {
334
                        // Object has been dropped back onto this window: no action.
335
                }
336
                else if (filer_window* w=
337
                        dynamic_cast<filer_window*>(app->find_window(pointer.w)))
338
                {
339
                        // Object has been dropped onto another filer window.
340
                        wimp_t filer_action_handle=begin_filer_action();
341
 
342
                        // Copy or move according to shift state.
343
                        const char* dst_pathname=w->pathname();
344
                        fileraction_flags flags=options().flags()|fileraction_RECURSE;
345
                        if (shift)
346
                        {
347
                                fileractionsendstartoperation_move(filer_action_handle,flags,
348
                                        dst_pathname,strlen(dst_pathname)+1);
349
                        }
350
                        else
351
                        {
352
                                fileractionsendstartoperation_copy(filer_action_handle,flags,
353
                                        dst_pathname,strlen(dst_pathname)+1);
354
                        }
355
                }
356
                else
357
                {
358
                        // Object has been dropped onto some other type of window.
359
                        // Construct Message_DataLoad.
360
                        wimp_message block2;
361
                        block2.your_ref=0;
362
                        block2.action=message_DATA_LOAD;
363
                        block2.data.data_xfer.w=pointer.w;
364
                        block2.data.data_xfer.i=pointer.i;
365
                        block2.data.data_xfer.pos=pointer.pos;
366
                        block2.data.data_xfer.est_size=-1; /* can do better than this */
367
                        block2.data.data_xfer.file_type=0xfff; /* can better this too */
368
 
369
                        // Send a Message_DataLoad for each object in the selection.
370
                        int count=0;
371
                        for (unsigned int i=0,i_end=_directory.size();i!=i_end;++i)
372
                        {
373
                                if (_directory[i].selected())
374
                                {
375
                                        ++count;
376
 
377
                                        sprintf(block2.data.data_xfer.file_name,"%s.%s",_pathname,
378
                                                _directory[i]->name);
379
                                        block2.size=(44+strlen(block2.data.data_xfer.file_name)+4)&~3;
380
 
381
                                        wimp_send_message_to_window(wimp_USER_MESSAGE,&block2,
382
                                                pointer.w,pointer.i);
383
                                }
384
                        }
385
                }
386
        }
387
}
388
 
58 gdshaw@RISCPKG.ORG 389
void filer_window::handle_key_pressed(wimp_key& block)
390
{
391
        parent_application()->handle_key_pressed(block);
392
}
393
 
56 gdshaw@RISCPKG.ORG 394
void filer_window::handle_data_xfer(wimp_message& block)
395
{
396
        // A buffer to temporarily hold the leafname.
397
        static char leafname[212];
398
 
399
        switch (block.action)
400
        {
401
        case message_DATA_SAVE:
402
                {
403
                        // Extract leafname.
404
                        char* p=std::strrchr(block.data.data_xfer.file_name,'.');
405
                        if (p) ++p;
406
                        else p=block.data.data_xfer.file_name;
407
                        std::strcpy(leafname,p);
408
 
409
                        // Construct and send acknowledgement.
410
                        block.your_ref=block.my_ref;
411
                        block.action=message_DATA_SAVE_ACK;
412
                        std::sprintf(block.data.data_xfer.file_name,"%s.%s",
413
                                _pathname,leafname);
414
                        block.size=(44+std::strlen(block.data.data_xfer.file_name)+4)&~3;
415
                        xwimp_send_message(wimp_USER_MESSAGE,&block,block.sender);
416
                }
417
                break;
418
        case message_DATA_LOAD:
419
                {
420
                        // Construct and send acknowledgement.
421
                        block.your_ref=block.my_ref;
422
                        block.action=message_DATA_LOAD_ACK;
423
                        xwimp_send_message(wimp_USER_MESSAGE,&block,block.sender);
424
                }
425
                break;
426
        }
427
}
428
 
31 gdshaw@RISCPKG.ORG 429
void filer_window::handle_menus_deleted()
430
{
431
        if (_temp_selection!=directory::npos)
432
        {
433
                _directory[_temp_selection].selected(0);
434
                force_redraw_cell(_temp_selection);
435
                _temp_selection=directory::npos;
436
        }
437
}
438
 
36 gdshaw@RISCPKG.ORG 439
void filer_window::options(const filer_options& options)
440
{
441
        // Keep track of whether window needs to be reformatted, restored
442
        // and redrawn.
443
        int need_reformat=0;
444
        int need_resort=0;
445
        int need_redraw=0;
446
 
447
        // Check whether layout method has changed.
448
        if (&options.layout()!=&_options.layout())
449
        {
450
                need_reformat=1;
451
                need_redraw=1;
452
        }
453
 
454
        // Check whether sorting method has changed.
455
        if (&options.sort()!=&_options.sort())
456
        {
457
                need_resort=1;
458
                need_redraw=1;
459
        }
460
 
461
        // Update options.
462
        _options=options;
463
 
464
        // Reformat, resort and redraw window as required.
465
        if (need_resort) _directory.sort(_options.sort());
466
        if (need_redraw) force_redraw();
467
        if (need_reformat)
468
        {
469
                reformat();
470
                if (need_redraw) force_redraw();
471
        }
472
}
473
 
31 gdshaw@RISCPKG.ORG 474
filer_menu& filer_window::shared_menu() const
475
{
476
        static filer_menu* _shared_menu=0;
477
        if (!_shared_menu)
478
        {
38 gdshaw@RISCPKG.ORG 479
                wimp_open_template(template_pathname);
31 gdshaw@RISCPKG.ORG 480
                _shared_menu=new filer_menu(parent_application());
38 gdshaw@RISCPKG.ORG 481
                wimp_close_template();
31 gdshaw@RISCPKG.ORG 482
        }
483
        return *_shared_menu;
484
}
485
 
21 gdshaw@RISCPKG.ORG 486
void filer_window::reload()
487
{
488
        static int buffer[256];
489
        _directory.load(_pathname,buffer,sizeof(buffer));
490
}
25 gdshaw@RISCPKG.ORG 491
 
492
void filer_window::reformat()
493
{
494
        wimp_window_state wstate;
495
        get_window_state(wstate);
496
        reformat(wstate.visible.x1-wstate.visible.x0);
497
}
498
 
499
void filer_window::reformat(int xsize)
500
{
501
        // Fetch layout.
502
        layout_method& layout=options().layout();
503
        int xgap=layout.xgap();
504
        int ygap=layout.ygap();
505
 
53 gdshaw@RISCPKG.ORG 506
        // Window will automatically resize if visible area matches extent.
507
        wimp_window_info winfo;
508
        get_window_info_header(winfo);
509
        int xauto=(winfo.xscroll==0)&&
510
                (winfo.visible.x1-winfo.visible.x0==winfo.extent.x1-winfo.extent.x0);
511
        int yauto=(winfo.yscroll==0)&&
512
                (winfo.visible.y1-winfo.visible.y0==winfo.extent.y1-winfo.extent.y0);
513
 
25 gdshaw@RISCPKG.ORG 514
        // Calculate cell size.  This must be able to accommodate
515
        // - the minimum cell size for the chosen layout, and
516
        // - the actual size occupied by each file to be listed.
517
        os_coord csize=layout.min_size(_options);
518
        for (unsigned int i=0;i!=_directory.size();++i)
519
        {
520
                os_coord size=layout.size(*_directory[i],_options);
521
                if (size.x>csize.x) csize.x=size.x;
522
                if (size.y>csize.y) csize.y=size.y;
523
        }
524
 
525
        // Apply the calculated cell size.
526
        _xcsize=csize.x;
527
        _ycsize=csize.y;
528
 
529
        // Determine number of rows and columns.
53 gdshaw@RISCPKG.ORG 530
        if (xauto&&(_yccount<2))
531
        {
532
                _xccount=(_directory.size()<4)?_directory.size():4;
533
        }
534
        else
535
        {
536
                _xccount=xsize/(_xcsize+xgap);
537
        }
25 gdshaw@RISCPKG.ORG 538
        if (_xccount<1) _xccount=1;
539
        _yccount=(_directory.size()+_xccount-1)/_xccount;
540
        if (_yccount<1) _yccount=1;
541
 
542
        // Calculate new extent.
543
        int extent_xsize=_xccount*(_xcsize+xgap)+xgap;
544
        int extent_ysize=_yccount*(_ycsize+ygap)+ygap;
545
 
28 gdshaw@RISCPKG.ORG 546
        // Do not force the window to become narrower than the width requested,
25 gdshaw@RISCPKG.ORG 547
        // unless there are too few directory entries to justify that width.
548
        if (extent_xsize<xsize)
549
        {
550
                extent_xsize=xsize;
551
                if (((extent_xsize+_xcsize-1)/(_xcsize+xgap))>
552
                        static_cast<int>(_directory.size()))
553
                {
554
                        extent_xsize=_directory.size()*(_xcsize+xgap)+xgap;
555
                }
556
        }
557
 
558
        // Apply the calculated extent.
559
        os_box extent;
560
        extent.x0=0;
561
        extent.y0=-extent_ysize;
562
        extent.x1=extent_xsize;
563
        extent.y1=0;
564
        set_extent(extent);
565
}
29 gdshaw@RISCPKG.ORG 566
 
53 gdshaw@RISCPKG.ORG 567
void filer_window::set_extent(const os_box& extent)
568
{
569
        // Window will automatically resize if visible area matches extent.
570
        wimp_window_info winfo;
571
        get_window_info_header(winfo);
572
        int xauto=(winfo.xscroll==0)&&
573
                (winfo.visible.x1-winfo.visible.x0==winfo.extent.x1-winfo.extent.x0);
574
        int yauto=(winfo.yscroll==0)&&
575
                (winfo.visible.y1-winfo.visible.y0==winfo.extent.y1-winfo.extent.y0);
576
 
577
        // Set the new extent.
578
        window::set_extent(extent);
579
 
580
        // Open the window.
581
        wimp_open open;
582
        open.visible=winfo.visible;
583
        open.xscroll=winfo.xscroll;
584
        open.yscroll=winfo.yscroll;
585
        open.next=winfo.next;
586
 
587
        // If automatically resizing then adjust visible area to match extent.
588
        int reopen=0;
589
        if (xauto&&(winfo.visible.x1-winfo.visible.x0!=extent.x1-extent.x0))
590
        {
591
                open.visible.x1=open.visible.x0+(extent.x1-extent.x0);
592
                reopen=1;
593
        }
594
        if (yauto&&(open.visible.y1-open.visible.y0!=extent.y1-extent.y0))
595
        {
596
                open.visible.y0=open.visible.y1-(extent.y1-extent.y0);
597
                reopen=1;
598
        }
599
        if (reopen) open_window(open);
600
}
601
 
30 gdshaw@RISCPKG.ORG 602
unsigned int filer_window::find_cell(const os_coord& p)
603
{
604
        layout_method& layout=options().layout();
605
        int xgap=layout.xgap();
606
        int ygap=layout.ygap();
607
 
608
        wimp_window_state state;
609
        get_window_state(state);
610
        int x=p.x-state.visible.x0+state.xscroll-xgap;
611
        int y=p.y-state.visible.y1+state.yscroll+ygap;
612
 
613
        int xc=x/(_xcsize+xgap);
614
        int yc=(-y)/(_ycsize+ygap);
615
        unsigned int index=xc+yc*_xccount;
616
 
617
        x-=xc*(_xcsize+xgap);
618
        y+=yc*(_ycsize+ygap);
619
 
620
        int found=(x>=0)&&(y>=-_ycsize)&&(x<_xcsize)&&(y<0)&&
621
                (xc>=0)&&(yc>=0)&&(xc<_xccount)&&(yc<_yccount)&&
622
                (index<_directory.size());
623
 
624
        return (found)?index:directory::npos;
625
}
626
 
627
void filer_window::force_redraw_cell(unsigned int index)
628
{
629
        layout_method& layout=options().layout();
630
        int xgap=layout.xgap();
631
        int ygap=layout.ygap();
632
 
633
        int xc=index%_xccount;
634
        int yc=index/_xccount;
635
 
636
        os_box box;
637
        box.x0=xgap+xc*(_xcsize+xgap);
58 gdshaw@RISCPKG.ORG 638
        box.y0=-(yc+1)*(_ycsize+ygap)-ygap;
30 gdshaw@RISCPKG.ORG 639
        box.x1=box.x0+_xcsize;
58 gdshaw@RISCPKG.ORG 640
        box.y1=box.y0+_ycsize+ygap;
30 gdshaw@RISCPKG.ORG 641
        force_redraw(box);
642
}
643
 
34 gdshaw@RISCPKG.ORG 644
void filer_window::refresh()
645
{
646
        reload();
647
        reformat();
648
        force_redraw();
649
}
650
 
30 gdshaw@RISCPKG.ORG 651
void filer_window::select_all(int selected)
652
{
653
        layout_method& layout=options().layout();
654
        int xgap=layout.xgap();
655
        int ygap=layout.ygap();
656
 
657
        int xc_min=_xccount;
658
        int yc_min=_yccount;
659
        int xc_max=0;
660
        int yc_max=0;
661
 
662
        for (unsigned int i=0;i!=_directory.size();++i)
663
        {
664
                if (_directory[i].selected()!=selected)
665
                {
666
                        _directory[i].selected(selected);
667
 
668
                        int xc=i%_xccount;
669
                        int yc=i/_xccount;
670
                        if (xc<xc_min) xc_min=xc;
671
                        if (yc<yc_min) yc_min=yc;
672
                        if (xc+1>xc_max) xc_max=xc+1;
673
                        if (yc+1>yc_max) yc_max=yc+1;
674
                }
675
        }
676
 
677
        if ((xc_max>xc_min)&&(yc_max>yc_min))
678
        {
679
                os_box box;
680
                box.x0=xgap+xc_min*(_xcsize+xgap);
681
                box.y0=-yc_max*(_ycsize+ygap);
682
                box.x1=xc_max*(_xcsize+xgap);
683
                box.y1=-ygap-yc_min*(_ycsize+ygap);
684
                force_redraw(box);
685
        }
31 gdshaw@RISCPKG.ORG 686
 
687
        _temp_selection=directory::npos;
30 gdshaw@RISCPKG.ORG 688
}
689
 
58 gdshaw@RISCPKG.ORG 690
wimp_i filer_window::open_rename(directory::size_type index,os_coord pos,
691
        char* buffer)
692
{
693
        // Fetch layout.
694
        layout_method& layout=_options.layout();
695
        int xgap=layout.xgap();
696
        int ygap=layout.ygap();
697
 
698
        // Calculate cell coordinates from cell index.
699
        int xc=index%_xccount;
700
        int yc=index/_xccount;
701
        os_box box;
702
        box.x0=xc*(_xcsize+xgap)+xgap;
703
        box.y0=-yc*(_ycsize+ygap)-_ycsize-ygap;
704
        box.x1=box.x0+_xcsize;
705
        box.y1=box.y0+_ycsize;
706
 
707
        // Construct icon block for name field.
708
        wimp_icon_create icon_c;
709
        icon_c.w=handle();
710
        icon_c.icon=*layout.icon_data(layout_method::icon_name,box,
711
                *_directory[index],false,_options);
712
 
713
        // Extend field upwards and downwards by 4 OS units,
714
        // and sideways to fill cell.
715
        icon_c.icon.extent.x0=box.x0;
716
        icon_c.icon.extent.y0-=4;
717
        icon_c.icon.extent.x1=box.x1;
718
        icon_c.icon.extent.y1+=4;
719
 
720
        // Modify icon flags to make it a writable field.
721
        icon_c.icon.flags&=~(wimp_ICON_BUTTON_TYPE|wimp_ICON_BG_COLOUR);
722
        icon_c.icon.flags|=wimp_ICON_BORDER|wimp_ICON_FILLED;
723
        icon_c.icon.flags|=wimp_BUTTON_WRITABLE<<wimp_ICON_BUTTON_TYPE_SHIFT;
724
        icon_c.icon.flags|=wimp_COLOUR_WHITE<<wimp_ICON_BG_COLOUR_SHIFT;
725
 
726
        // Switch to using dedicated buffer.
727
        // (The one returned by the layout class is neither large enough
728
        // nor sufficiently persistant.)
729
        std::strcpy(buffer,icon_c.icon.data.indirected_text.text);
730
        icon_c.icon.data.indirected_text.text=buffer;
731
        icon_c.icon.data.indirected_text.size=256;
732
 
733
        // Make pointer coordinates relative to work area.
734
        wimp_window_state wstate;
735
        wstate.w=handle();
736
        wimp_get_window_state(&wstate);
737
        os_coord rel_pos;
738
        rel_pos.x=pos.x-wstate.visible.x0+wstate.xscroll;
739
        rel_pos.y=pos.y-wstate.visible.y1+wstate.yscroll;
740
 
741
        // Create the icon, claiming the caret.
742
        wimp_i ic=wimp_create_icon(&icon_c);
743
        force_redraw_cell(index);
744
        wimp_set_caret_position(handle(),ic,rel_pos.x,rel_pos.y,-1,-1);
745
 
746
        // Return the icon handle.
747
        return ic;
748
}
749
 
750
void filer_window::close_rename(wimp_i ic,directory::size_type index)
751
{
752
        wimp_delete_icon(handle(),ic);
753
        force_redraw_cell(index);
754
}
755
 
756
void filer_window::rename(directory::size_type index,const char* leafname)
757
{
758
        osgbpb_info* object=_directory[index];
759
        if (object&&std::strlen(leafname))
760
        {
761
                const size_t max_pathname=255;
762
                size_t max_leafname=
763
                        max_pathname-std::strlen(pathname())-1;
764
                if (max_leafname>max_pathname) max_leafname=0;
765
                if ((std::strlen(object->name)<=max_leafname)&&
766
                        (std::strlen(leafname)<=max_leafname))
767
                {
768
                        static char src_pathname[max_pathname+1];
769
                        static char dst_pathname[max_pathname+1];
770
                        std::sprintf(src_pathname,"%s.%s",pathname(),object->name);
771
                        std::sprintf(dst_pathname,"%s.%s",pathname(),leafname);
772
                        osfscontrol_rename(src_pathname,dst_pathname);
773
                }
774
        }
775
}
776
 
29 gdshaw@RISCPKG.ORG 777
void filer_window::open_parent(const os_coord& offset) const
778
{
779
        // Determine whether there is a parent directory.
780
        char* lastdot=strrchr(_pathname,'.');
781
        if (lastdot&&strcmp(lastdot+1,"$"))
782
        {
783
                // Find top-left corner of this window.
784
                wimp_window_state state;
785
                get_window_state(state);
786
 
787
                // Add offset to give top-left corner of new window.
788
                os_box box;
789
                box.x0=state.visible.x0+offset.x;
790
                box.y1=state.visible.y1+offset.y;
791
                box.x1=box.x0;
792
                box.y0=box.y1;
793
 
794
                // Open new window.
795
                *lastdot=0;
796
                new filer_window((filer_application*)parent_application(),
797
                        _pathname,box,_options);
798
                *lastdot='.';
799
        }
800
}
35 gdshaw@RISCPKG.ORG 801
 
42 gdshaw@RISCPKG.ORG 802
void filer_window::set_work_directory() const
803
{
804
        osfscontrol_dir(_pathname);
805
}
806
 
45 gdshaw@RISCPKG.ORG 807
wimp_t filer_window::begin_filer_action()
808
{
809
        // Start a FilerAction task.
810
        wimp_t handle=wimp_start_task("Filer_Action");
811
 
812
        // Send it the pathname of the directory on which it is to act.
813
        fileraction_send_selected_directory(handle,pathname());
814
 
815
        // Send it the list of leafnames on which it is to act.
816
        for (unsigned int i=0,i_end=_directory.size();i!=i_end;++i)
817
        {
818
                if (_directory[i].selected())
819
                {
820
                        const char* leafname=_directory[i]->name;
821
                        fileraction_send_selected_file(handle,leafname);
822
                }
823
        }
824
 
825
        // Return the task handle of the FilerAction task.
826
        return handle;
827
}
828
 
35 gdshaw@RISCPKG.ORG 829
void filer_window::run(osgbpb_info& info,int close,int shift)
830
{
831
        // Need to at least partially handle shift key here, because
832
        // Filer_Run does not allow coordinates to be specified when
833
        // shift-clicking an application directory.
834
        // (... unless there is an alternative way to invoke Filer_Run?)
835
 
836
        static char buffer[12+max_name_length];
837
        if ((info.obj_type&fileswitch_IS_DIR)&&((info.name[0]!='!')||shift))
838
        {
839
                // Get dimensions of this window.
840
                wimp_window_state state;
841
                get_window_state(state);
842
 
843
                // Choose coordinates for new window.
844
                // If closing this window then open in same position,
845
                // otherwise open below and to the right.
846
                os_coord offset=_auto_pos();
847
                os_box box;
848
                box.x0=state.visible.x0+((close)?0:offset.x);
849
                box.y1=state.visible.y1+((close)?0:offset.y);
850
                box.x1=box.x0;
851
                box.y0=box.y1;
852
 
853
                // Open new window.
854
                if (std::strlen(_pathname)+std::strlen(info.name)+1<max_name_length)
855
                {
856
                        std::sprintf(buffer,"%s.%s",_pathname,info.name);
857
                        window* w=new filer_window(
858
                                (filer_application*)parent_application(),
859
                                buffer,box,_options);
860
                }
861
        }
862
        else
863
        {
864
                // Run object.
865
                if (std::strlen(_pathname)+std::strlen(info.name)+1<max_name_length)
866
                {
867
                        std::sprintf(buffer,"Run %s.%s",_pathname,info.name);
868
                        wimp_start_task(buffer);
869
                }
870
        }
871
}