2 #define MUIMASTER_YES_INLINE_STDARG
3 #include <clib/arossupport_protos.h>
6 #define SYSTEM_PRIVATE 1
9 #define AROS_ALMOST_COMPATIBLE
10 #include <proto/muimaster.h>
11 #include <libraries/mui.h>
13 #include <libraries/asl.h>
15 #if !defined(__AROS__)
16 #include <libraries/charsets.h>
19 #include <libraries/locale.h>
20 #include <workbench/workbench.h>
22 #include <proto/exec.h>
23 #include <intuition/intuition.h>
24 #include <graphics/gfx.h>
25 #include <exec/libraries.h>
26 #include <exec/lists.h>
27 #include <proto/graphics.h>
28 #include <proto/intuition.h>
29 #include <proto/icon.h>
31 #include <proto/dos.h>
39 #include <proto/alib.h>
40 #include <proto/utility.h>
42 #include <proto/dtclass.h>
43 #include <datatypes/pictureclass.h>
44 #include <devices/rawkeycodes.h>
46 #include <libraries/gadtools.h>
48 #if defined(__MORPHOS__)
49 #include <emul/emulregs.h>
50 #include <emul/emulinterface.h>
54 #include <private/vapor/vapor.h>
57 #include "pageview_class.h"
58 #include "documentview_class.h"
59 #include "outlineview_class.h"
60 #include "documentlayout_class.h"
61 #include "thumbnaillist_class.h"
62 #include "renderer_class.h"
63 #include "search_class.h"
64 #include "annotation_class.h"
65 #include "toolbar_class.h"
66 #include "clipboard.h"
68 #include "system/chunky.h"
69 #include "system/gentexture.h"
70 #include "../locale.h"
87 struct MinList
**annotationLists
; // annotations are loaded on demand
88 struct MUI_EventHandlerNode eh
;
94 #define ANNOTLIST_INVALID 0
95 #define ANNOTLIST_EMPTY ((void*)-1)
97 #define ANNOTFLAG_ATTACHED 1
99 static char *outlinenames
[] = {"Tree", "Thumbnails", NULL
};
101 static Object
*buildlayoutobject(int layoutmode
, struct Data
*data
)
105 case MUIV_DocumentView_Layout_Single
:
106 return SinglePageLayoutObject
,
107 MUIA_DocumentLayout_PDFDocument
, data
->doc
,
108 MUIA_DocumentLayout_Columns
, 1,
109 MUIA_DocumentLayout_Rotation
, data
->rotation
,
112 case MUIV_DocumentView_Layout_ContinuousSingle
:
113 return ContinuousLayoutObject
,
114 MUIA_DocumentLayout_PDFDocument
, data
->doc
,
115 MUIA_DocumentLayout_Columns
, 1,
116 MUIA_DocumentLayout_Rotation
, data
->rotation
,
119 case MUIV_DocumentView_Layout_Facing
:
120 return SinglePageLayoutObject
,
121 MUIA_DocumentLayout_PDFDocument
, data
->doc
,
122 MUIA_DocumentLayout_Columns
, 2,
123 MUIA_DocumentLayout_Rotation
, data
->rotation
,
126 case MUIV_DocumentView_Layout_ContinuousFacing
:
127 return ContinuousLayoutObject
,
128 MUIA_DocumentLayout_PDFDocument
, data
->doc
,
129 MUIA_DocumentLayout_Columns
, 2,
130 MUIA_DocumentLayout_Rotation
, data
->rotation
,
135 return NULL
; /* let it hit! */
140 Object
*sldPage
, *grpOutlines
, *grpOutlinesTitles
, *grpToolbar
;
141 Object
*grpDisplay
, *grpOutlineTree
, *grpNavigation
, *balBalance
, *grpSearch
, *grpOutlineThumbs
;
143 obj
= DoSuperNew(cl
, obj
,
144 MUIA_Group_Horiz
, FALSE
,
146 Child
, grpDisplay
= VGroup
, End
,
147 Child
, balBalance
= BalanceObject
, End
,
148 Child
, grpOutlines
= VGroup
,
149 MUIA_ShowMe
, GetTagData(MUIA_DocumentView_Outline
, TRUE
, INITTAGS
),
150 MUIA_Group_PageMode
, TRUE
,
151 MUIA_Frame
, MUIV_Frame_Group
,
153 Child
, grpOutlinesTitles
= MUI_NewObject(MUIC_Title
,
158 Child
, grpNavigation
= HGroup
,
159 Child
, sldPage
= SliderObject
,
160 MUIA_Slider_Level
, 1,
161 MUIA_Numeric_Default
, 1,
165 MUIA_Numeric_Format
, LOCSTR( MSG_SLIDER_PAGE
),
166 MUIA_CycleChain
, TRUE
,
169 Child
, grpSearch
= SearchObject
,
173 Child
, grpToolbar
= ToolbarObject
,
174 MUIA_DocumentView_Outline
, GetTagData(MUIA_DocumentView_Outline
, TRUE
, INITTAGS
),
185 data
->dragaction
= MUIV_DocumentView_DragAction_Scroll
;
186 data
->rotation
= MUIV_DocumentLayout_Rotation_None
;
187 data
->filename
= strdup((char*)GetTagData(MUIA_DocumentView_FileName
, NULL
, INITTAGS
));
188 data
->renderer
= (Object
*)GetTagData(MUIA_DocumentView_Renderer
, NULL
, INITTAGS
);
189 data
->doc
= pdfNew(data
->filename
);
190 data
->layoutmode
= GetTagData(MUIA_DocumentView_Layout
, MUIV_DocumentView_Layout_Single
, INITTAGS
);
191 data
->renderpriority
= GetTagData(MUIA_DocumentView_RenderPriority
, MUIV_Renderer_Enqueue_Priority_Normal
, INITTAGS
);
193 data
->sldPage
= sldPage
;
194 data
->grpDisplay
= grpDisplay
;
195 data
->grpToolbar
= grpToolbar
;
197 if (data
->doc
== NULL
)
199 CoerceMethod(cl
, obj
, OM_DISPOSE
);
203 data
->annotationLists
= calloc(pdfGetPagesNum(data
->doc
), sizeof(struct MinList
*));
204 for(i
=pdfGetPagesNum(data
->doc
)-1; i
>=0; i
--)
205 data
->annotationLists
[i
] = ANNOTLIST_INVALID
;
208 /* setup search group */
210 set(grpSearch
, MUIA_Search_DocumentView
, obj
);
212 /* setup pages slider */
214 set(sldPage
, MUIA_Slider_Max
, pdfGetPagesNum(data
->doc
));
215 data
->layoutgroup
= buildlayoutobject(data
->layoutmode
, data
);
216 if (data
->layoutgroup
!= NULL
)
218 int scaling
= GetTagData(MUIA_DocumentLayout_Scaling
, MUIV_DocumentLayout_Scaling_FitPage
, INITTAGS
);
219 if (scaling
== MUIV_DocumentLayout_Scaling_None
)
220 scaling
= MUIV_DocumentLayout_Scaling_Zoom
;
222 set(data
->layoutgroup
, MUIA_DocumentLayout_Scaling
, scaling
);
225 DoMethod(grpDisplay
, OM_ADDMEMBER
, ScrollgroupObject
, MUIA_Scrollgroup_Contents
, data
->layoutgroup
, End
);
228 Object
*outline
= OutlineViewObject
,
229 MUIA_OutlineView_Document
, data
->doc
,
232 if (xget(outline
, MUIA_OutlineView_IsEmpty
) == FALSE
)
234 DoMethod(grpOutlines
, OM_ADDMEMBER
, outline
);
235 DoMethod(grpOutlinesTitles
, OM_ADDMEMBER
, TextObject
, MUIA_Text_Contents
, "Tree", End
);
240 MUI_DisposeObject(outline
);
244 data
->grpOutline
= grpOutlines
;
248 Object
*thumbnails
= ThumbnailListObject
,
249 MUIA_ThumbnailList_PDFDocument
, data
->doc
,
250 MUIA_ThumbnailList_Renderer
, data
->renderer
,
253 DoMethod(grpOutlines
, OM_ADDMEMBER
, thumbnails
);
255 DoMethod(grpOutlinesTitles
, OM_ADDMEMBER
, TextObject
, MUIA_Text_Contents
, "Thumbnails", End
);
262 DoMethod(grpOutlines
, OM_REMMEMBER
, grpOutlinesTitles
);
263 MUI_DisposeObject(grpOutlinesTitles
);
266 /* attach toolbar to the document view */
268 set(grpToolbar
, MUIA_Toolbar_DocumentView
, obj
);
272 DoMethod(grpOutlines
, MUIM_Notify
, MUIA_OutlineView_Page
, MUIV_EveryTime
, sldPage
, 3, MUIM_Set
, MUIA_Slider_Level
, MUIV_TriggerValue
);
274 DoMethod(sldPage
, MUIM_Notify
, MUIA_Slider_Level
, MUIV_EveryTime
, obj
, 3, MUIM_Set
, MUIA_DocumentView_Page
, MUIV_TriggerValue
);
275 DoMethod(data
->layoutgroup
, MUIM_Notify
, MUIA_DocumentLayout_Page
, MUIV_EveryTime
, sldPage
, 3, MUIM_NoNotifySet
, MUIA_Slider_Level
, MUIV_TriggerValue
);
276 DoMethod(data
->layoutgroup
, MUIM_Notify
, MUIA_DocumentLayout_Page
, MUIV_EveryTime
, obj
, 2, MUIM_DocumentView_UpdateAnnotations
, MUIV_TriggerValue
);
278 /* NOTE: this will add notification for all child objects!! todo: rework so no time/memory is wasted! */
279 DoMethod(data
->layoutgroup
, MUIM_Notify
, MUIA_PageView_NeedRefresh
, MUIV_EveryTime
, obj
, 2, MUIM_DocumentView_EnqueueRender
, MUIV_TriggerValue
);
280 DoMethod(data
->layoutgroup
, MUIM_Notify
, MUIA_PageView_RedirectPage
, MUIV_EveryTime
, obj
, 3, MUIM_Set
, MUIA_DocumentView_Page
, MUIV_TriggerValue
);
281 DoMethod(data
->layoutgroup
, MUIM_Notify
, MUIA_PageView_RedirectPage
, MUIV_EveryTime
, data
->sldPage
, 3, MUIM_NoNotifySet
, MUIA_Slider_Level
, MUIV_TriggerValue
);
292 if (data
->doc
!= NULL
)
293 pdfDelete(data
->doc
);
295 if (data
->filename
!= NULL
)
296 free(data
->filename
);
307 case MUIA_DocumentView_Page
:
309 int page
= tag
->ti_Data
;
310 SetAttrs(data
->layoutgroup
, MUIA_Group_Forward
, FALSE
, MUIA_DocumentLayout_Page
, page
, TAG_DONE
);
314 case MUIA_DocumentView_Layout
:
315 DoMethod(obj
, MUIM_DocumentView_Layout
, tag
->ti_Data
); /* this will set layoutmode */
318 case MUIA_DocumentView_Outline
:
319 if (data
->grpOutline
!= NULL
)
320 set(data
->grpOutline
, MUIA_ShowMe
, tag
->ti_Data
);
323 case MUIA_DocumentView_DragAction
:
324 data
->dragaction
= tag
->ti_Data
;
338 switch (msg
->opg_AttrID
)
340 case MUIA_DocumentLayout_Zoom
:
341 *(ULONG
*)msg
->opg_Storage
= xget(data
->layoutgroup
, msg
->opg_AttrID
);
344 case MUIA_DocumentView_PDFDocument
:
345 *(ULONG
*)msg
->opg_Storage
= (ULONG
)data
->doc
;
348 case MUIA_DocumentView_Page
:
349 *(ULONG
*)msg
->opg_Storage
= (ULONG
)xget(data
->sldPage
, MUIA_Slider_Level
);
352 case MUIA_DocumentView_Layout
:
353 *(ULONG
*)msg
->opg_Storage
= (ULONG
)data
->layoutmode
;
356 case MUIA_DocumentView_FileName
:
357 *(ULONG
*)msg
->opg_Storage
= (ULONG
)data
->filename
;
360 case MUIA_DocumentView_DragAction
:
361 *(ULONG
*)msg
->opg_Storage
= (ULONG
)data
->dragaction
;
372 data
->eh
.ehn_Object
= obj
;
373 data
->eh
.ehn_Class
= cl
;
374 data
->eh
.ehn_Events
= IDCMP_RAWKEY
;
375 data
->eh
.ehn_Priority
= 100;
376 data
->eh
.ehn_Flags
= MUI_EHF_GUIMODE
;
377 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, &data
->eh
);
386 /* remove all pending pages from renderer */
387 D(kprintf("cleanup renderer for view %p\n", data
->layoutgroup
));
388 DoMethod(data
->renderer
, MUIM_Renderer_Remove
, MUIV_Renderer_Remove_All
, data
->layoutgroup
);
389 D(kprintf(" ..cleanup done\n"));
391 if (data
->eh
.ehn_Object
!= NULL
)
393 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, &data
->eh
);
394 data
->eh
.ehn_Object
= NULL
;
402 DEFMMETHOD(DocumentView_EnqueueRender
)
405 //kprintf("enqueue with high priority:%d\n", msg->page);
406 DoMethod(data
->renderer
, MUIM_Renderer_Enqueue
, msg
->page
, data
->layoutgroup
, data
->renderpriority
);
408 // rerendered so probably annotations have to be reprocessed. optimize this pass..
409 DoMethod(_app(obj
), MUIM_Application_PushMethod
, obj
,2, MUIM_DocumentView_UpdateAnnotations
, msg
->page
);
415 DEFMMETHOD(DocumentView_Layout
)
418 Object
*grpDisplayChild
;
419 ULONG zoom
= xget(data
->layoutgroup
, MUIA_DocumentLayout_Zoom
);
420 ULONG scaling
= xget(data
->layoutgroup
, MUIA_DocumentLayout_Scaling
);
421 LONG page
= xget(data
->layoutgroup
, MUIA_DocumentLayout_Page
);
424 D(kprintf("cleanup renderer for view %p\n", data
->layoutgroup
));
425 DoMethod(data
->renderer
, MUIM_Renderer_Remove
, MUIV_Renderer_Remove_All
, data
->layoutgroup
);
426 D(kprintf(" ..cleanup done\n"));
428 grpDisplayChild
= (Object
*)DoMethod(data
->grpDisplay
, MUIM_Family_GetChild
, MUIV_Family_GetChild_First
);
429 DoMethod(data
->grpDisplay
, MUIM_Group_InitChange
);
430 DoMethod(data
->grpDisplay
, MUIM_Group_Remove
, grpDisplayChild
);
431 MUI_DisposeObject(grpDisplayChild
);
433 /* disposing layout object disposed all annotation objects which are currently attached to pages. mark them as invalid */
435 for(pagenum
=1; pagenum
<=pdfGetPagesNum(data
->doc
); pagenum
++)
437 struct MinList
*l
= data
->annotationLists
[pagenum
- 1];
438 if (l
!= ANNOTLIST_INVALID
&& l
!= ANNOTLIST_EMPTY
)
440 struct pdfAnnotation
*an
;
448 data
->layoutmode
= msg
->layout
;
449 data
->layoutgroup
= buildlayoutobject(msg
->layout
, data
);
450 SetAttrs(data
->layoutgroup
, MUIA_DocumentLayout_Zoom
, zoom
, MUIA_DocumentLayout_Scaling
, scaling
, TAG_DONE
);
452 DoMethod(data
->grpDisplay
, OM_ADDMEMBER
, ScrollgroupObject
, MUIA_Scrollgroup_Contents
, data
->layoutgroup
, End
);
453 DoMethod(data
->grpDisplay
, MUIM_Group_ExitChange
);
455 /* NOTE: using pushmethod ensures that object will be properly layed out and focusing on page will work properly. investigate in mui! */
456 #warning investigate!
457 DoMethod(_app(obj
), MUIM_Application_PushMethod
, data
->layoutgroup
, 3, MUIM_Set
, MUIA_DocumentLayout_Page
, page
);
458 //set(data->layoutgroup, MUIA_DocumentLayout_Page, page);
460 DoMethod(data
->layoutgroup
, MUIM_Notify
, MUIA_DocumentLayout_Page
, MUIV_EveryTime
, data
->sldPage
, 3, MUIM_NoNotifySet
, MUIA_Slider_Level
, MUIV_TriggerValue
);
461 /* NOTE: this will add notification for all child objects!! todo: rework so no time/memory is wasted! */
462 DoMethod(data
->layoutgroup
, MUIM_Notify
, MUIA_PageView_NeedRefresh
, MUIV_EveryTime
, obj
, 2, MUIM_DocumentView_EnqueueRender
, MUIV_TriggerValue
);
463 DoMethod(data
->layoutgroup
, MUIM_Notify
, MUIA_PageView_RedirectPage
, MUIV_EveryTime
, obj
, 3, MUIM_Set
, MUIA_DocumentView_Page
, MUIV_TriggerValue
);
464 DoMethod(data
->layoutgroup
, MUIM_Notify
, MUIA_PageView_RedirectPage
, MUIV_EveryTime
, data
->sldPage
, 3, MUIM_NoNotifySet
, MUIA_Slider_Level
, MUIV_TriggerValue
);
469 DEFMMETHOD(DocumentView_FindViewForPage
)
472 return DoMethod(data
->layoutgroup
, MUIM_DocumentLayout_FindViewForPage
, msg
->page
);
475 DEFMMETHOD(HandleEvent
)
481 if (msg
->imsg
!= NULL
)
483 switch (msg
->imsg
->Class
)
486 if (msg
->imsg
->Code
== RAWKEY_SPACE
)
488 set(data
->sldPage
, MUIA_Slider_Level
, xget(data
->sldPage
, MUIA_Slider_Level
) + 1);
489 rc
= MUI_EventHandlerRC_Eat
;
491 else if (msg
->imsg
->Code
== RAWKEY_BACKSPACE
)
493 set(data
->sldPage
, MUIA_Slider_Level
, xget(data
->sldPage
, MUIA_Slider_Level
) - 1);
494 rc
= MUI_EventHandlerRC_Eat
;
505 DEFMMETHOD(DocumentView_RotateLeft
)
508 data
->rotation
= data
->rotation
== MUIV_PageView_Rotation_None
? MUIV_PageView_Rotation_270
: data
->rotation
- 1;
509 SetAttrs(data
->layoutgroup
, MUIA_DocumentLayout_Rotation
, data
->rotation
, TAG_DONE
);
513 DEFMMETHOD(DocumentView_RotateRight
)
516 data
->rotation
= data
->rotation
== MUIV_PageView_Rotation_270
? MUIV_PageView_Rotation_None
: data
->rotation
+ 1;
517 SetAttrs(data
->layoutgroup
, MUIA_DocumentLayout_Rotation
, data
->rotation
, TAG_DONE
);
521 DEFMMETHOD(DocumentView_UpdateAnnotations
)
524 int refpagenum
= msg
->page
;
528 int modified
= FALSE
;
530 /* for each visible page around the reference one we display annotations objects */
532 for(first
= refpagenum
; first
> 1 && DoMethod(data
->layoutgroup
, MUIM_DocumentLayout_IsPageVisible
, first
- 1); first
--) {}
533 for(last
= first
; last
< pdfGetPagesNum(data
->doc
) && DoMethod(data
->layoutgroup
, MUIM_DocumentLayout_IsPageVisible
, last
+ 1); last
++) {}
535 //printf("process annotations...:%d:%d-%d\n", refpagenum, first, last);
537 for(pagenum
=first
; pagenum
<=last
; pagenum
++)
539 struct MinList
*l
= data
->annotationLists
[pagenum
- 1];
540 if (l
== ANNOTLIST_INVALID
)
542 struct MinList
*annotList
;
544 //printf("fetch annotations for page %d\n", pagenum);
545 annotList
= pdfGetAnnotations(data
->doc
, pagenum
);
546 if (annotList
== NULL
)
547 annotList
= ANNOTLIST_EMPTY
;
549 data
->annotationLists
[pagenum
- 1] = annotList
;
554 for(pagenum
= pdfGetPagesNum(data
->doc
); pagenum
>= 1; pagenum
--)
556 struct MinList
*l
= data
->annotationLists
[pagenum
-1];
557 if (l
!= ANNOTLIST_EMPTY
&& l
!= ANNOTLIST_INVALID
)
559 struct pdfAnnotation
*an
;
560 Object
*pageview
= (Object
*)DoMethod(data
->layoutgroup
, MUIM_DocumentLayout_FindViewForPage
, pagenum
);
562 if (pagenum
< first
|| pagenum
> last
)
568 //printf(" remove annotation from page %d\n", pagenum);
570 DoMethod(data
->layoutgroup
, MUIM_Group_InitChange
);
573 DoMethod(data
->layoutgroup
, MUIM_Family_Remove
, an
->obj
);
574 DoMethod(pageview
, MUIM_PageView_RemoveAnnotation
, an
->obj
);
575 MUI_DisposeObject(an
->obj
);
587 //printf(" new annotation for page %d\n", pagenum);
589 DoMethod(data
->layoutgroup
, MUIM_Group_InitChange
);
592 an
->obj
= AnnotationObject
,
593 MUIA_Annotation_Contents
, an
->contents
,
594 MUIA_Annotation_RefObject
, pageview
,
596 DoMethod(data
->layoutgroup
, MUIM_Family_AddTail
, an
->obj
);
601 DoMethod(pageview
, MUIM_PageView_AddAnnotation
, an
->obj
, coords
);
609 DoMethod(data
->layoutgroup
, MUIM_Group_ExitChange
);
614 DEFMMETHOD(DocumentView_ClearSelection
)
619 for(pagenum
=1; pagenum
<=pdfGetPagesNum(data
->doc
); pagenum
++)
621 Object
*pageview
= (Object
*)DoMethod(data
->layoutgroup
, MUIM_DocumentLayout_FindViewForPage
, pagenum
);
622 if (pageview
!= NULL
)
624 DoMethod(pageview
, MUIM_PageView_ClearSelection
);
632 DEFMMETHOD(DocumentView_SelectionCopy
)
637 for(pagenum
=1; pagenum
<=pdfGetPagesNum(data
->doc
); pagenum
++)
640 Object
*pageview
= (Object
*)DoMethod(data
->layoutgroup
, MUIM_DocumentLayout_FindViewForPage
, pagenum
);
641 if (pageview
!= NULL
)
643 struct MUIP_PageView_GetSelection msg
;
644 msg
.MethodID
= MUIM_PageView_GetSelection
;
645 if (DoMethodA(pageview
, &msg
))
647 struct pdfSelectionText
*selection
= pdfBuildTextForSelection(data
->doc
, pagenum
, msg
.region
.x1
, msg
.region
.y1
, msg
.region
.x2
, msg
.region
.y2
);
648 if (selection
!= NULL
)
650 clipboard_write_text(selection
->utf8
, CODESET_UTF8
);
651 pdfDisposeTextForSelection(data
->doc
, selection
);
669 DECMMETHOD(HandleEvent
)
670 DECMMETHOD(DocumentView_EnqueueRender
)
671 DECMMETHOD(DocumentView_Layout
)
672 DECMMETHOD(DocumentView_FindViewForPage
)
673 DECMMETHOD(DocumentView_RotateRight
)
674 DECMMETHOD(DocumentView_RotateLeft
)
675 DECMMETHOD(DocumentView_UpdateAnnotations
)
676 DECMMETHOD(DocumentView_ClearSelection
)
677 DECMMETHOD(DocumentView_SelectionCopy
)
681 DECSUBCLASS_NC(MUIC_Group
, DocumentViewClass
)