📄 programming
字号:
/* The dialog is ready: map the dialog */ CMapDialog ("mail");/* Don't forget to focus on the widget we would like entry to go to */ CFocus (CIdent ("mail.to"));/* Now run the dialog */ for (;;) { CNextEvent (NULL, &cwevent);/* Window was killed by some unknown means (like the window manager) - this won't actually happen here */ if (!CIdent ("mail")) break;/* Pressed the 'Esc' key: */ if (!strcmp (cwevent.ident, "mail.cancel") || cwevent.command == CK_Cancel) break;/* Pressed the 'Enter' key: */ if (!strcmp (cwevent.ident, "mail.send") || cwevent.command == CK_Enter) {/* We want an hour glass in case this takes a few seconds: */ CHourGlass (win);/* The function pipe_mail() does not come with the library: */ pipe_mail ((CIdent ("mail.to"))->text, (CIdent ("mail.subject"))->text, (CIdent ("mail.cc"))->text);/* Turn off hourglass: */ CUnHourGlass (win); break; } }/* Destroys children widgets also: */ CDestroyWidget ("mail"); CRestoreState (&s);}*******************************************************************************Event Handling--------------There are two ways to 'run' a dialog using the library. The first way is the 'object orientated' way used with the X toolkits. Using this method, routines are hooked onto the widgets, using the CAddCallback() function. The dialog main loop is just: for (;;) { CNextEvent (NULL, NULL);/* Dialog no long exists */ if (!CIdent ("mail")) break; } }Although object orientated method is more modular, it often has the problem that many little subroutines have to created, some of which would be much more appropriate as a simple if statement in the body of the code.The second method is the 'basic C' approach, used in the mail example above.No callbacks are used, instead, 'if' conditions in the main loop do the operations. This way, simple dialogs can be created in one function. You must choose to what extent you use either technique, to make your code as succinct as possible.*******************************************************************************Details of Dialog Creation--------------------------One of the problems with creating dialogs is the spacing of widgets. It is tedious to calculate the positions of widgets for a typographically correct dialog box.The technique used above is to draw the widget, and the look to see how much space it has taken up. Then draw the next widget with this information. The library records a 'hint' position which points to the position where the next widget may be drawn. This position is reset when you draw a window. The command void CGetHintPos (int *x, int *y);returns the x and y pixel coordinates of this position.In the above dialog, after calling CDrawHeadedWindow(), we issue: CGetHintPos (&x, &y);Which gets a point close to the top left hand corner of the dialog.Then we draw a label at this position while setting a letter to be underlined: (CDrawText ("mail.tto", win, x, y, "To: "))->hotkey = 'T';We want to now draw directly under this widget, so we get the hint of the y coordinate: CGetHintPos (0, &y);Then we draw a text-input widget, while setting its hotkey to 'T': (CDrawTextInput ("mail.to", win, x, y, (FONT_MEAN_WIDTH) * 50, AUTO_HEIGHT, 1024, CLastInput ("mail.to")))->hotkey = 'T';Finally we get the hint position for the next widget below the text-input widget: CGetHintPos (0, &y);And so on...Having done the text-input widgets, we now want to draw an 'Ok' and 'Cancel' button. These will be drawn to the very right of everything drawn so far. The function void get_hint_limits (int *x, int *y);get the maximum position thus far reached.*******************************************************************************Disabling Widgets-----------------Because CNextEvent() runs all the widget's you have ever created, other dialogs will continue to operate in parallel with the currently created dialog. This behaviour would be confusing to the user, so thefunctions CDisable (const char *ident); CEnable (const char *ident);are provided to stop user input to those widgets. CDisable() and CEnable(), take shell patterns as arguments, so you can disable groups of widgets with a single command. You should hence name widgets with this in mind using dotted notation eg: call your menu buttons "menu.file", "menu.options", "menu.help" etc., so that you can use CDisable("menu.*") to disable them all at once.The commands CBackupState() and CRestoreState() record the state of "enablement" of all the widgets in the library. So you can restore your application at the end of a dialog. Note that I personally have never thus far found use for anything but CDisable("*"). But I can imagine circumstances where this would be very useful.*******************************************************************************Resizable Dialogs-----------------Resizing of dialogs is trickey. Coolwidgets does not support widgets moving all over to make space for other widgets. After the dialog is created, the command void CSetWindowResizable (const char *ident, int min_width, int min_height, int max_width, int max_height);will make the dialog resizable. The position member of all the children widgets will then have to set to reflect the way the widget is to beresized or moved when its parent window is resized. At this stage, all the widgets would be spaced correctly (though the dialog would not be mapped) and hence all resizing would do would be to track changes in the dialog size. The various options are - POSITION_RIGHT: the widget moves to keep its distance to the right border constant - POSITION_WIDTH: the widget resizes to keep its distance to the right border constant - POSITION_BOTTOM: the widget moves to keep its distance to the bottom border constant - POSITION_HEIGHT: the widget resizes to keep its distance to the bottom border constant - POSITION_CENTRE: the widget moves to keep in the centre - POSITION_FILL: the resizes to be justified on the right border.These values must be OR'd with the ->position member of the CWidget structure, or otherwise, just call void CSetMovement (const char *ident, unsigned long position)This creates a very dynamic effect when resizing subwindows, see cooledit and open a file; try resizing the 'Load' dialog box to see what happens. If these options don't have enough functionality for you, then set the resize member of the CWidget structure to a function of your own. Also, don't make dialogs resizable when they don't need to be: like error dialogs etc. They should be resizable only when the user may liketo see more of something: like text boxes.Here is how I create the filebrowser dialog:(This just draws the dialog, it does not run it. It is the most complicated dialog in the whole library.)Window draw_file_browser (const char *identifier, Window parent, int x, int y, const char *dir, const char *file, const char *label){ char *filelist = 0; char *directorylist = 0; char *resolved_path, *p; int y2, x2, x3, y3; Window win; if (parent == CRoot) win = CDrawMainWindow (identifier, label); else win = CDrawHeadedDialog (identifier, parent, x, y, label); (CIdent (identifier))->options |= WINDOW_ALWAYS_RAISED; CHourGlass (CFirstWindow); filelist = get_file_list (dir, 'f', CLastInput (catstrs (identifier, ".filt", 0))); CUnHourGlass (CFirstWindow); if (!filelist || !(directorylist = get_file_list (dir, '/', ""))) { CErrorDialog (parent, 20, 20, " File browser ", " Unable to read directory "); CDestroyWidget (identifier); goto error; } CGetHintPos (&x, &y); resolved_path = canonicalize_pathname (dir); p = resolved_path + strlen (resolved_path) - 1; if (*p != '/') { *++p = '/'; *++p = '\0'; } (CDrawText (catstrs (identifier, ".dir", 0), win, x, y, resolved_path))->position |= POSITION_FILL; free (resolved_path); CGetHintPos (0, &y); y3 = y;/* draws two widgets: text box with a scrollbar */ (CDrawTextbox (catstrs (identifier, ".fbox", 0), win, x, y, FONT_MEAN_WIDTH * 24 + 7, FONT_PIX_PER_LINE * 14 + 6, 0, 0, filelist, TEXT_FILES))->position |= POSITION_WIDTH | POSITION_HEIGHT; (CIdent (catstrs (identifier, ".fbox", 0)))->options |= TEXT_MARK_WHOLE_LINES;/* the vertical scroll bar is named the same as the text box, with a ".vsc" at the end: */ CSetMovement (catstrs (identifier, ".fbox.vsc", 0), POSITION_HEIGHT | POSITION_RIGHT); CGetHintPos (&x2, &y2); x3 = x2;/* draws two widgets: text box with a scrollbar */ (CDrawTextbox (catstrs (identifier, ".dbox", 0), win, x2, y + TICK_BUTTON_WIDTH + WIDGET_SPACING, FONT_MEAN_WIDTH * 20 + 7, y2 - WIDGET_SPACING * 2 - y - TICK_BUTTON_WIDTH, 0, 0, directorylist, TEXT_FILES))->position |= POSITION_HEIGHT | POSITION_RIGHT; (CIdent (catstrs (identifier, ".dbox", 0)))->options |= TEXT_MARK_WHOLE_LINES;/* the vertical scroll bar is named the same as the text box, with a ".vsc" at the end: */ CSetMovement (catstrs (identifier, ".dbox.vsc", 0), POSITION_HEIGHT | POSITION_RIGHT); CGetHintPos (&x2, &y2); (CDrawTextInput (catstrs (identifier, ".finp", 0), win, x, y2, WIDGET_SPACING * 2 - 2, AUTO_HEIGHT, 256, file))->position |= POSITION_FILL | POSITION_BOTTOM; CGetHintPos (0, &y2); (CDrawText (catstrs (identifier, ".filx", 0), win, x, y2, "Filter : "))->position |= POSITION_BOTTOM; CGetHintPos (&x, 0); (CDrawTextInput (catstrs (identifier, ".filt", 0), win, x, y2, WIDGET_SPACING * 2 - 2, AUTO_HEIGHT, 256, TEXTINPUT_LAST_INPUT))->position |= POSITION_FILL | POSITION_BOTTOM; (CDrawPixmapButton (catstrs (identifier, ".ok", 0), win, x3, y3, PIXMAP_BUTTON_TICK))->position |= POSITION_RIGHT; (CDrawPixmapButton (catstrs (identifier, ".cancel", 0), win, x2 - WIDGET_SPACING * 2 - TICK_BUTTON_WIDTH - 20, y3, PIXMAP_BUTTON_CROSS))->position |= POSITION_RIGHT; CSetSizeHintPos (identifier); CMapDialog (identifier); y = (CIdent (identifier))->height; CSetWindowResizable (identifier, FONT_MEAN_WIDTH * 40, min (FONT_PIX_PER_LINE * 4 + 210, y), 1600, 1200); /* minimum and maximum sizes */ error: if (directorylist) free (directorylist); if (filelist) free (filelist); return win;}*************************DOCUMENT NOT YET COMPLETE*************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -