1
////////////////////////////////////////////////////////////////////////////////
3
// This file is part of Toolkit for Conceptual Modeling (TCM).
4
// (c) copyright 1995, Vrije Universiteit Amsterdam.
5
// Author: Frank Dehne (frank@cs.vu.nl).
7
// TCM is free software; you can redistribute it and/or modify
8
// it under the terms of the GNU General Public License as published by
9
// the Free Software Foundation; either version 2 of the License, or
10
// (at your option) any later version.
12
// TCM is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
// GNU General Public License for more details.
17
// You should have received a copy of the GNU General Public License
18
// along with TCM; if not, write to the Free Software
19
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21
////////////////////////////////////////////////////////////////////////////////
22
#include "drawingarea.h"
24
#include "xgrafport.h"
25
#include "messagedialog.h"
33
#include <X11/keysym.h>
35
// the standard translations don't work, actually.
36
// These are borrowed from an example program in the Motif distribution.
37
char DrawingArea::drawTranslations[] = "#replace\n\
38
~s ~m ~a <Key>Return:DrawingAreaInput() ManagerParentActivate()\n\
39
<Key>Return:DrawingAreaInput() ManagerGadgetSelect()\n\
40
<Key>osfActivate:DrawingAreaInput() ManagerParentActivate()\n\
41
<Key>osfCancel:DrawingAreaInput() ManagerParentCancel()\n\
42
<Key>osfHelp:DrawingAreaInput() ManagerGadgetHelp()\n\
43
<Key>space:DrawingAreaInput() ManagerGadgetSelect()\n\
44
<Key>osfSelect:DrawingAreaInput() ManagerGadgetSelect()\n\
45
<Key>osfBeginLine:DrawingAreaInput()\n\
46
<Key>osfEndLine:DrawingAreaInput()\n\
47
<KeyDown>:DrawingAreaInput() ManagerGadgetKeyInput()\n\
48
<KeyUp>:DrawingAreaInput()\n\
49
<Enter>:DrawingAreaInput()\n\
50
<Leave>:DrawingAreaInput()\n\
51
<BtnMotion>:DrawingAreaInput() ManagerGadgetButtonMotion()\n\
52
<Motion>:DrawingAreaInput() ManagerGadgetButtonMotion()\n\
53
<Btn1Down>:DrawingAreaInput() ManagerGadgetArm()\n\
54
<Btn1Up>:DrawingAreaInput() ManagerGadgetActivate()\n\
55
<Btn2Down>:DrawingAreaInput() ManagerGadgetDrag()\n\
56
<BtnDown>:DrawingAreaInput()\n\
57
<BtnUp>:DrawingAreaInput()";
59
DrawingArea::DrawingArea(Config *config, Widget parent, const char *n,
60
DrawWindow *w): MWidget(n) {
66
width = min(drawwindow->initDrawingWidth, drawwindow->maxDrawingWidth);
67
height = min(drawwindow->initDrawingHeight,
68
drawwindow->maxDrawingHeight);
69
maxWidth = drawwindow->maxDrawingWidth;
70
maxHeight = drawwindow->maxDrawingHeight;
71
// create a drawing area widget
72
SetWidget(XtVaCreateWidget(
73
GetName()->getstr(), xmDrawingAreaWidgetClass, parent,
74
XmNtranslations, XtParseTranslationTable(drawTranslations),
77
XmNresizePolicy, XmNONE, // remain this a fixed size
79
// set up destruction handler.
80
InstallDestroyHandler();
81
// convert drawing area back to pixels to get its width and height
82
XtVaSetValues(GetWidget(), XmNunitType, XmPIXELS, 0);
83
XtAddCallback(GetWidget(), XmNexposeCallback, DrawCB, this);
84
XtAddCallback(GetWidget(), XmNresizeCallback, DrawCB, this);
85
XtAddCallback(GetWidget(), XmNinputCallback, DrawCB, this);
87
CreatePopupMenu(drawwindow->GetTool());
88
XtManageChild(GetWidget());
89
Display *display = GetDisplay();
90
Window window = GetWindow();
91
if (!check(display) || !check(window))
93
// create new x grafport object.
95
grafport = new XGrafport(display, window, width, height);
96
grafport->SetBackgroundColor(config->GetDrawingBackground());
97
grafport->SetForegroundColor(config->GetDrawingForeground());
98
grafport->ClearArea(0,0,width,height);
102
void DrawingArea::SetViewer(Viewer *v) {
105
grafport->SetFont(viewer->GetDefaultFont());
108
Pixel DrawingArea::GetBackgroundColor() {
110
XtVaGetValues(GetWidget(), XmNbackground, &p, 0);
114
Pixel DrawingArea::GetForegroundColor() {
116
XtVaGetValues(GetWidget(), XmNforeground, &p, 0);
120
void DrawingArea::UpdateSize(int w, int h) {
121
w = min(w, maxWidth);
122
h = min(h, maxHeight);
123
XtVaSetValues(GetWidget(), XmNheight, h, XmNwidth, w, 0);
128
void DrawingArea::FitDocument(int wd, int ht) {
129
if (wd > maxWidth || ht > maxHeight) {
130
(new MessageDialog(GetWidget(), MessageDialog::WARNING))->
132
"The drawing area has reached its maximum size\n"
133
"Can not display the entire document");
135
wd = min(wd, maxWidth);
136
ht = min(ht, maxHeight);
137
if (ht > height || wd > width) {
139
ht = max(ht, height);
141
grafport->UpdateSize(wd, ht);
148
void DrawingArea::FitDocument() {
152
viewer->CalcSizeElements(p1, p2);
153
int wd = int(0.5 + 10.0 + grafport->Zoom(p2.x));
154
int ht = int(0.5 + 10.0 + grafport->Zoom(p2.y));
158
void DrawingArea::CreatePopupMenu(int tool) {
159
popupMenu = new Menu(GetWidget(), Menu::POPUP, "Edit", 0,
160
drawwindow->GetPopupEditItems());
161
// if (Toolkit::EditorWithoutDuplicates(tool)) {
162
// // make "Duplicate" command insensitive.
163
// Widget w1 = popupMenu->GetMenuItem("Duplicate");
165
// XtVaSetValues(w1, XmNsensitive, False, 0);
169
void DrawingArea::DrawCB(Widget, XtPointer clientData, XtPointer callData) {
170
DrawingArea *da = (DrawingArea *)clientData;
171
da->Dispatch(callData);
174
void DrawingArea::Dispatch (XtPointer callData) {
175
XmDrawingAreaCallbackStruct *dacs =
176
(XmDrawingAreaCallbackStruct *)callData;
177
static int dragButton = 0;
178
switch (dacs->reason) {
186
bool pasting = viewer->IsPasting();
187
bool zigZag = viewer->IsZigZag();
188
switch (dacs->event->type) {
190
XButtonEvent *event = (XButtonEvent *)dacs->event;
193
if (event->button == Button3 &&
194
!(zigZag || pasting || beenDragging))
195
PopupMenu(dacs->event);
196
beenDragging = False;
199
case ButtonRelease: {
200
XButtonEvent *event = (XButtonEvent *)dacs->event;
201
Command *lastcmd = viewer->GetLastCmd();
204
if (zigZag || pasting) {
207
if ((zigZag && (event->button != Button2) &&
208
!(event->state & ShiftMask)) ||
209
pasting && (event->button != Button1)) {
210
lastcmd->SayAborted();
214
lastcmd->TrackMouse(Command::TRACK_UP,
215
&anchorPoint, &previousPoint,
217
anchorPoint = nextPoint;
220
else if (beenDragging) {
222
beenDragging = False;
226
lastcmd->TrackMouse(Command::TRACK_RELEASE,
227
&anchorPoint, &previousPoint,
229
if ((int)event->button == dragButton)
230
viewer->ExecuteCommand();
232
else if (dragButton == 0) {
233
if (event->button == Button1) {
234
if (event->state & ShiftMask)
235
viewer->Adjust(x, y);
237
viewer->Select(x, y);
239
else if (event->button == Button2)
240
viewer->Adjust(x, y);
242
else if (dragButton > 0) {
244
beenDragging = False;
249
lastcmd->TrackMouse(Command::TRACK_RELEASE,
250
&anchorPoint, &previousPoint,
252
lastcmd->SayAborted();
256
beenDragging = False;
261
XMotionEvent *event = (XMotionEvent *)dacs->event;
263
(Button1MotionMask | Button2MotionMask)) {
266
if (!beenDragging && abs(xx-x) < 5 &&
267
abs(yy-y) < 5 && !zigZag)
269
if (!beenDragging && !zigZag) {
273
anchorPoint.Set(x,y);
274
previousPoint = anchorPoint;
275
nextPoint = anchorPoint;
277
if (event->state & Button1MotionMask) {
278
if (event->state & ShiftMask)
279
newCmd = viewer->Connect(x,y);
281
newCmd = viewer->Drag(x,y);
282
dragButton = Button1;
285
newCmd = viewer->Connect(x,y);
286
dragButton = Button2;
288
viewer->NewCommand(newCmd);
292
Command::TRACK_PRESS,
293
&anchorPoint, &previousPoint,
297
nextPoint.Set(event->x, event->y);
298
Command *lastcmd = viewer->GetLastCmd();
303
&anchorPoint, &previousPoint,
305
previousPoint = nextPoint;
309
else if (zigZag || pasting) {
310
nextPoint.Set(event->x, event->y);
311
Command *lastcmd = viewer->GetLastCmd();
313
lastcmd->TrackMouse(Command::TRACK_DRAG,
314
&anchorPoint, &previousPoint,
316
previousPoint = nextPoint;
320
viewer->MovingPointer(event->x, event->y);
324
XKeyEvent *event = (XKeyEvent *)dacs->event;
325
XComposeStatus status;
327
int n = XLookupString(event, buf, 5, &keysym, &status);
329
// normal ascii character.
330
viewer->KeyTyped(event->x, event->y, buf[0]);
333
// special character.
334
int code = MapKeySym(keysym);
336
viewer->KeyTyped(event->x, event->y,
341
// next two don't work ??
343
error("ENTERING !!!\n");
348
error("LEAVING !!!\n");
349
viewer->Deactivate();
359
void DrawingArea::Redraw(XEvent *e) {
362
XExposeEvent *event = (XExposeEvent *)e;
364
grafport->Redraw(event->x, event->y,
365
event->width, event->height, event->x, event->y);
368
void DrawingArea::PopupMenu(XEvent *e) {
369
Widget w = popupMenu->GetWidget();
370
XmMenuPosition(w, (XButtonEvent *)e);
374
void DrawingArea::EnableUndo(bool flag) {
375
Widget undoMenuItem = popupMenu->GetMenuItem("Undo");
377
XtVaSetValues(undoMenuItem, XmNsensitive, flag, 0);
380
void DrawingArea::EnableRedo(bool flag) {
381
Widget redoMenuItem = popupMenu->GetMenuItem("Redo");
383
XtVaSetValues(redoMenuItem, XmNsensitive, flag, 0);
386
void DrawingArea::Enable(const char *label, bool flag) {
387
Widget menuItem = popupMenu->GetMenuItem(label);
389
XtVaSetValues(menuItem, XmNsensitive, flag, 0);
392
void DrawingArea::SetUndoName(const char *undoname) {
393
XmString s = CreateXmString(undoname);
394
Widget undoMenuItem = popupMenu->GetMenuItem("Undo");
396
XtVaSetValues(undoMenuItem, XmNlabelString, s, 0);
400
void DrawingArea::SetRedoName(const char *redoname) {
401
XmString s = CreateXmString(redoname);
402
Widget redoMenuItem = popupMenu->GetMenuItem("Redo");
404
XtVaSetValues(redoMenuItem, XmNlabelString, s, 0);
408
int DrawingArea::MapKeySym(KeySym keysym) {
411
case XK_Home: return Key::HOME;
414
case XK_Left: return Key::LEFT;
417
case XK_Up: return Key::UP;
420
case XK_Right: return Key::RIGHT;
423
case XK_Down: return Key::DOWN;
426
case XK_Page_Up: return Key::PAGE_UP;
429
case XK_Page_Down: return Key::PAGE_DOWN;
432
case XK_End: return Key::END;
435
case XK_Insert: return Key::INSERT;