Subversion Repositories Filer-Free

Rev

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