3DCoat  3D-COAT 4.9.xx
3DCoat is the one application that has all the tools you need to take your 3D idea from a block of digital clay all the way to a production ready, fully textured organic or hard surface model.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Ответы на вопросы по работе с UI

Как что-то найти в 3DCoat глядя на его UI

Например, надо посмотреть, как работает меню "Define Measurement Units" в комнате "Sculpt". Для этого нам необходим идентификатор. Два способа его найти:

  1. Открываем файл "text.xml" в папке "Документы/3D-Coat" и ищем строку "Define Measurement Units". В XML-блоке лежит идентификатор.
  2. Жмём MClick+RClick и получаем идентификатор в буфер обмена.

В нашем случае обнаруживаем идентификатор DefineScaleCorrespondance. Находим его в коде проекта и видим с какой функцией он связан. Ставим точки останова и отслеживаем работу меню.

See Also
Поиск в коде
Видео от Шпагина 2:10

Как добавить пункт меню

В коде C++

Много примеров можем найти в коде проекта. Общий синтаксис:

TextMenu* menu = new TextMenu( 0, 0, "FolderMyMenuID" );
TextWidget* open = menu->AddLine( "MyOpenID", "MyOpenID_HINT" );
pi_callback( WM_PRESS_BTN, open, myCallbackFunction );

Чтобы меню стало доступным из скриптов, его необходимо зарегистрировать *до показа* UI. Для регистрации используем макрос ui_reg_pitem.

See Also
Видео от Шпагина 15:33

С помощью скрипта

Помещаем в папку Scripts/ui файл с именем mainmenu.cpp. Пример кода в файле:

void main(){
FileMenu();
EditMenu();
}
void FileMenu(){
start_main_menu( "FILE" );
menu_item( "CLEARSCENE" );
menu_item( "OPEN_FILE" );
menu_hotkey( 'O', 0, 1, 0 );
menu_item( "RecentFiles" );
menu_item( "Autosave" );
if ( !is_new_scene() ){
menu_item( "SAVE_FILEFAST" );
menu_hotkey( 'S', 0, 1, 0 );
menu_item( "SAVE_FILE" );
menu_hotkey( 'S', 0, 1, 1 );
}
menu_item( "EXIT" );
}
void EditMenu(){
start_main_menu( "COMMANDS" );
menu_item( "UNDO" );
menu_hotkey( 'Z', 0, 1, 0 );
menu_item( "REDO" );
menu_hotkey( 'Y', 0, 1, 0 );
menu_item( "OPTIONS" );
}
See Also
Видео от Шпагина 26:00

Как добавить меню, которое появляется по R-Click

Когда появлятся необходимость вызвать окно свойств по R-Click, можем использовать BaseWidget::AssignPropPanel():

const char* const name = "SomeWidgetName";
BaseWidget* widget = PenInterface::Root->Find( name, true );
if ( widget ) {
widget->Destroy();
}
widget = PenInterface::Root->AssignPropPanel();
widget->Name = name;
// element of BaseClass for popup menu
BaseClass* item = ...
item->CreateRmbMenu( widget );
AutoShift2( widget );

К сожалению, для "простыни" это плохой способ, т.к. формирование большого меню блокирует 3DCoat. С тяжёлыми меню лучше работать так.

See Also
Видео от Шпагина 36:50

Как научить виджет получать перетаскиваемый в него виджет

Мы просто ловим событие WM_ONDROP в виджете, которого хотим научить ловить другие виджеты.

See Also
Как сделать виджет перетаскиваемым
Видео от Шпагина 44:04

Как зарегистрировать свой виджет

Для персонализации виджета пользуемся полем BaseWidget::UserInt.

See Also
Как пользоваться классом `Widgets`
Видео от Шпагина 54:07

Как сделать виджет перетаскиваемым

Любой виджет, у которого свойство BaseWidget::Moveable = true, можно перемещать.

See Also
Как научить виджет получать перетаскиваемый в него виджет

Где живут графические контролы

Большинство графических контролов обитают в файле SimpleWidgets.h.

Как пользоваться классом `Widgets`

Этот класс хранит все виджеты 3DCoat в Widgets::ActiveWidgets.

Также здесь находится набор свойств для определения положения мыши (Widgets::MouseX), размеров рабочей области (Widgets::WorkArea), где был сделан последний клик (Widgets::LastRmbX) и множество других характеристик, касающихся расположения элементов UI на экране (см. комментарии в коде).

Warning
Не рекомендуется работать напрямую с Widgets::ActiveWidgets. Для этой цели аккуратно используем PenInterface::Root.
See Also
Как зарегистрировать свой виджет
Как найти виджет
Видео от Шпагина 8:45
Todo:
Перенести все глобальные переменные в Widgets.

Как найти виджет

Все виджеты 3DCoat лежат в PenInterface::Root.

Для поиска виджета по имени пользуемся функцией Find() или одним из методов:

  • BaseWidget::Find() Для поиска по ID и возврата *первого* подходящего виджета.
  • BaseWidget::Look() Для получения *подборки* виджетов по любым свойствам.
See Also
Элементы интерфейса (виджеты)
Видео от Шпагина 54:45

Как разрешить художнику добавить горячие кнопки (хоткеи) к вашему виджету

Для этой цели необходимо дать виджету имя, заполнив поле Name. Причём имя должно начинаться с символа $. В коде, по завершении инициализации своего виджета, вызываем RefreshHotkeysAssignment().

Если хотим назначить хоткей прямо в коде, воспользуемся макросом def_hotkey().

See Also
Видео от Шпагина 53:14

Как устроены все элементы UI

В методе Init() инициализируем свойства виджета и цепляем некоторые события:

  • WM_PAINT - для рисования виджета
  • WM_BUTTONDOWN - реакция виджета на прикосновение
  • WM_PRESS_BTN - реакция виджета на клик
See Also
Элементы интерфейса (виджеты)
В качестве примера TextWidget::Init().

На какие события и каким образом реагируют UI-элементы

Реакции виджета на события реализованы с помощью коллбэков.

Названия событий начинаются с префикса WM_ и размещены они в файле SimpleWidgets.

Todo:
Добавить группу для событий виджета и ссылку на неё из документации.
See Also
Видео от Шпагина 16:18

Как использовать callback'и

В качестве коллбэков для виджета может быть использована любая функция без параметров или принимающая в качестве параметров от 1 до 5 типов cPtrDiff.

Параметры для коллбэков всегда передаются через cPtrDiff.

Пример регистрации коллбэка WM_PRESS_BTN:

TextWidget* widget = ...
pi_callback( WM_PRESS_BTN, widget, myCallbackFunction );
See Also
Макросы для виджетов
Видео от Шпагина 23:40

Работаем с окнами 3DCoat

Для показа модального окна с некоторым набором кнопок используем ShowModalMessageBox().

Для не модального окна (управление сразу возвращается коду) находим ShowNormalMessageBox(). Но если нам необходимо просто окно, в котором каждый тик будем что-то перерисовывать, лучше перегрузить BaseClass::ProcessInEditor().

Когда нам необходимо надоедливое окно, появление которого художник захочет отменить, работаем с DontShowAgainDialog().

Магические окна для выполнения цепочки действий вызываем по ShowWizardBox(). Магическое окно - не модальное.

Warning
Сообщения пишем в файле English.xml, в коде указываем только уникальные ID.
До первого вызова рендера информационных окон создать нельзя.
Todo:
Добавить отсылку к документации списков OkCancel + Ko в Utils.cpp.
See Also
Как правильно работать с выводом информации
Видео от Шпагина 59:23