diff options
Diffstat (limited to 'src/aftereffects/OpenColorIO_AE_UI.cpp')
-rw-r--r-- | src/aftereffects/OpenColorIO_AE_UI.cpp | 1229 |
1 files changed, 1229 insertions, 0 deletions
diff --git a/src/aftereffects/OpenColorIO_AE_UI.cpp b/src/aftereffects/OpenColorIO_AE_UI.cpp new file mode 100644 index 0000000..b5634bf --- /dev/null +++ b/src/aftereffects/OpenColorIO_AE_UI.cpp @@ -0,0 +1,1229 @@ +/* +Copyright (c) 2003-2012 Sony Pictures Imageworks Inc., et al. +All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of Sony Pictures Imageworks nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "OpenColorIO_AE.h" + +#include "OpenColorIO_AE_Context.h" +#include "OpenColorIO_AE_Dialogs.h" + +#include "DrawbotBot.h" + + + +// UI drawing constants + +#define LEFT_MARGIN 5 +#define TOP_MARGIN 5 +#define RIGHT_MARGIN 50 + +#define FILE_LABEL_WIDTH 35 + +#define FIELD_HEIGHT 22 + +#define FIELD_TEXT_INDENT_H 10 +#define FIELD_TEXT_INDENT_V 4 + +#define BUTTONS_INDENT_H (LEFT_MARGIN + 70) + +#define BUTTONS_GAP_V 20 +#define BUTTONS_GAP_H 30 + +#define BUTTON_HEIGHT 20 +#define BUTTON_WIDTH 80 + +#define BUTTON_TEXT_INDENT_V 2 + +#define MENUS_INDENT_H 0 + +#define MENUS_GAP_V 20 + +#define MENU_LABEL_WIDTH 100 +#define MENU_LABEL_SPACE 5 + +#define MENU_WIDTH 150 +#define MENU_HEIGHT 20 + +#define MENU_TEXT_INDENT_H 10 +#define MENU_TEXT_INDENT_V 2 + +#define MENU_ARROW_WIDTH 14 +#define MENU_ARROW_HEIGHT 7 + +#define MENU_ARROW_SPACE_H 8 +#define MENU_ARROW_SPACE_V 7 + +#define MENU_SHADOW_OFFSET 3 + +#define MENU_SPACE_V 20 + +#define TEXT_COLOR PF_App_Color_TEXT_DISABLED + + + +typedef enum { + REGION_NONE=0, + REGION_CONFIG_MENU, + REGION_PATH, + REGION_CONVERT_BUTTON, + REGION_DISPLAY_BUTTON, + REGION_EXPORT_BUTTON, + REGION_MENU1, + REGION_MENU2, + REGION_MENU3 +} UIRegion; + + +static UIRegion WhichRegion(PF_Point ui_point, bool menus, bool third_menu) +{ + int field_top = TOP_MARGIN; + int field_bottom = field_top + FIELD_HEIGHT; + + if(ui_point.v >= field_top && ui_point.v <= field_bottom) + { + int menu_left = LEFT_MARGIN + MENUS_INDENT_H + MENU_LABEL_WIDTH; + int menu_right = menu_left + MENU_WIDTH; + + if(ui_point.h >= menu_left && ui_point.h <= menu_right) + { + return REGION_CONFIG_MENU; + } + else + { + int field_left = MENUS_INDENT_H + MENU_LABEL_WIDTH + MENU_LABEL_SPACE + + MENU_WIDTH + FIELD_TEXT_INDENT_H; + + if(ui_point.h >= field_left) + return REGION_PATH; + } + } + else + { + int buttons_top = field_bottom + BUTTONS_GAP_V; + int buttons_bottom = buttons_top + BUTTON_HEIGHT; + + if(ui_point.v >= buttons_top && ui_point.v <= buttons_bottom) + { + int convert_left = BUTTONS_INDENT_H; + int convert_right = convert_left + BUTTON_WIDTH; + int display_left = convert_right + BUTTONS_GAP_H; + int display_right = display_left + BUTTON_WIDTH; + int export_left = display_right + BUTTONS_GAP_H; + int export_right = export_left + BUTTON_WIDTH; + + if(ui_point.h >= convert_left && ui_point.h <= convert_right) + return REGION_CONVERT_BUTTON; + else if(ui_point.h >= display_left && ui_point.h <= display_right) + return REGION_DISPLAY_BUTTON; + else if(ui_point.h >= export_left && ui_point.h <= export_right) + return REGION_EXPORT_BUTTON; + } + else if(menus) + { + int menu_left = LEFT_MARGIN + MENUS_INDENT_H + MENU_LABEL_WIDTH; + int menu_right = menu_left + MENU_WIDTH; + + if(ui_point.h >= menu_left && ui_point.h <= menu_right) + { + int menu1_top = buttons_bottom + MENUS_GAP_V; + int menu1_bottom = menu1_top + MENU_HEIGHT; + int menu2_top = menu1_bottom + MENU_SPACE_V; + int menu2_bottom = menu2_top + MENU_HEIGHT; + int menu3_top = menu2_bottom + MENU_SPACE_V; + int menu3_bottom = menu3_top + MENU_HEIGHT; + + if(ui_point.v >= menu1_top && ui_point.v <= menu1_bottom) + return REGION_MENU1; + else if(ui_point.v >= menu2_top && ui_point.v <= menu2_bottom) + return REGION_MENU2; + else if(third_menu && ui_point.v >= menu3_top && ui_point.v <= menu3_bottom) + return REGION_MENU3; + } + } + } + + return REGION_NONE; +} + + +static void DrawMenu(DrawbotBot &bot, const char *label, const char *item) +{ + DRAWBOT_PointF32 original = bot.Pos(); + + float text_height = bot.FontSize(); + + bot.Move(MENU_LABEL_WIDTH, MENU_TEXT_INDENT_V + text_height); + + bot.SetColor(TEXT_COLOR); + bot.DrawString(label, kDRAWBOT_TextAlignment_Right); + + bot.Move(MENU_LABEL_SPACE, -(MENU_TEXT_INDENT_V + text_height)); + + DRAWBOT_PointF32 menu_corner = bot.Pos(); + + bot.Move(MENU_SHADOW_OFFSET, MENU_SHADOW_OFFSET); + bot.SetColor(PF_App_Color_BLACK, 0.3f); + bot.PaintRect(MENU_WIDTH, MENU_HEIGHT); + bot.MoveTo(menu_corner); + + bot.SetColor(PF_App_Color_SHADOW); + bot.PaintRect(MENU_WIDTH, MENU_HEIGHT); + + bot.SetColor(PF_App_Color_HILITE); + bot.DrawRect(MENU_WIDTH, MENU_HEIGHT); + + bot.Move(MENU_TEXT_INDENT_H, MENU_TEXT_INDENT_V + text_height); + + bot.SetColor(TEXT_COLOR); + bot.DrawString(item, + kDRAWBOT_TextAlignment_Left, + kDRAWBOT_TextTruncation_EndEllipsis, + MENU_WIDTH - MENU_TEXT_INDENT_H - MENU_TEXT_INDENT_H - + MENU_ARROW_WIDTH - MENU_ARROW_SPACE_H - MENU_ARROW_SPACE_H); + + bot.MoveTo(menu_corner.x + MENU_WIDTH - MENU_ARROW_SPACE_H - MENU_ARROW_WIDTH, + menu_corner.y + MENU_ARROW_SPACE_V); + + bot.SetColor(PF_App_Color_LIGHT_TINGE); + bot.PaintTriangle(MENU_ARROW_WIDTH, MENU_ARROW_HEIGHT); + + bot.MoveTo(original); +} + + +static void DrawButton(DrawbotBot &bot, const char *label, int width, bool pressed) +{ + DRAWBOT_PointF32 original = bot.Pos(); + + float text_height = bot.FontSize(); + + + PF_App_ColorType button_color = (pressed ? PF_App_Color_BUTTON_PRESSED_FILL : PF_App_Color_BUTTON_FILL); + PF_App_ColorType button_hilite = (pressed ? PF_App_Color_BLACK : PF_App_Color_HILITE); + PF_App_ColorType button_lowlite = (pressed ? PF_App_Color_HILITE : PF_App_Color_BLACK); + + + bot.SetColor(button_color); + bot.PaintRect(width, BUTTON_HEIGHT); + + float brush_size = (pressed ? 1.f : 0.5f); + + bot.SetColor(button_hilite); + bot.MoveTo(original.x + 1, original.y + BUTTON_HEIGHT - 1); + + bot.DrawLineTo(original.x + 1, original.y + 1, brush_size); + bot.DrawLineTo(original.x + width - 1, original.y + 1, brush_size); + + bot.MoveTo(original); // annoying corner pixel + bot.SetColor(button_hilite, 0.3f); + bot.PaintRect(1, 1); + + + brush_size = (pressed ? 0.5f : 1.f); + + bot.SetColor(button_lowlite); + bot.MoveTo(original.x + 1, original.y + BUTTON_HEIGHT - 1); + + bot.DrawLineTo(original.x + width - 1, original.y + BUTTON_HEIGHT - 1, brush_size); + bot.DrawLineTo(original.x + width - 1, original.y + 2, brush_size); + + bot.MoveTo(original.x + width - 1, original.y + BUTTON_HEIGHT - 1); // corner + bot.SetColor(button_lowlite, 0.3f); + bot.PaintRect(1, 1); + + + bot.MoveTo(original.x + (width / 2), original.y + text_height + BUTTON_TEXT_INDENT_V); + + if(pressed) + bot.Move(2, 2); + + bot.SetColor(TEXT_COLOR); + bot.DrawString(label, kDRAWBOT_TextAlignment_Center); + + bot.MoveTo(original); +} + + +static PF_Err DrawEvent( + PF_InData *in_data, + PF_OutData *out_data, + PF_ParamDef *params[], + PF_LayerDef *output, + PF_EventExtra *event_extra) +{ + PF_Err err = PF_Err_NONE; + + + if(!(event_extra->evt_in_flags & PF_EI_DONT_DRAW) && + params[OCIO_DATA]->u.arb_d.value != NULL) + { + if(event_extra->effect_win.area == PF_EA_CONTROL) + { + ArbitraryData *arb_data = (ArbitraryData *)PF_LOCK_HANDLE(params[OCIO_DATA]->u.arb_d.value); + SequenceData *seq_data = (SequenceData *)PF_LOCK_HANDLE(in_data->sequence_data); + + DrawbotBot bot(in_data->pica_basicP, event_extra->contextH, in_data->appl_id); + + + int panel_left = event_extra->effect_win.current_frame.left; + int panel_top = event_extra->effect_win.current_frame.top; + int panel_width = event_extra->effect_win.current_frame.right; + int panel_height = event_extra->effect_win.current_frame.bottom; + float text_height = bot.FontSize(); + + if(in_data->appl_id != 'FXTC') + { + // for Premiere we need to paint the background first + bot.SetColor(PF_App_Color_PANEL_BACKGROUND); + bot.MoveTo(panel_left, panel_top); + bot.PaintRect(panel_width, panel_height); + } + + + // configuration menu + bot.MoveTo(panel_left + MENUS_INDENT_H, panel_top + TOP_MARGIN); + + std::string config_menu_text = arb_data->path; + + if(arb_data->source == OCIO_SOURCE_NONE) + { + config_menu_text = "(none)"; + } + if(arb_data->source == OCIO_SOURCE_ENVIRONMENT) + { + config_menu_text = "$OCIO"; + } + else if(arb_data->source == OCIO_SOURCE_CUSTOM) + { + config_menu_text = (arb_data->action == OCIO_ACTION_LUT ? "LUT" : "Custom"); + } + + DrawMenu(bot, "Configuration:", config_menu_text.c_str()); + + + if(arb_data->source == OCIO_SOURCE_CUSTOM || + arb_data->source == OCIO_SOURCE_ENVIRONMENT) + { + // path text field + int field_left = panel_left + MENUS_INDENT_H + MENU_LABEL_WIDTH + + MENU_LABEL_SPACE + MENU_WIDTH + FIELD_TEXT_INDENT_H; + + bot.MoveTo(field_left, panel_top + TOP_MARGIN); + + int field_width = MAX(panel_width - field_left + panel_left - RIGHT_MARGIN, 60); + + bot.SetColor(PF_App_Color_SHADOW); + bot.PaintRect(field_width, FIELD_HEIGHT); + bot.SetColor(PF_App_Color_BLACK); + bot.DrawRect(field_width, FIELD_HEIGHT); + + bot.Move(FIELD_TEXT_INDENT_H, FIELD_TEXT_INDENT_V + text_height); + + bot.SetColor(TEXT_COLOR); + + std::string file_string = "(none)"; + + if(arb_data->source == OCIO_SOURCE_ENVIRONMENT) + { + char *file = std::getenv("OCIO"); + + if(file) + file_string = file; + } + else + { + file_string = (seq_data->status == STATUS_USING_RELATIVE ? + arb_data->relative_path : arb_data->path); + } + + + bot.DrawString(file_string.c_str(), + kDRAWBOT_TextAlignment_Default, + kDRAWBOT_TextTruncation_PathEllipsis, + field_width - (2 * FIELD_TEXT_INDENT_H)); + } + + + if(seq_data->status == STATUS_FILE_MISSING) + { + bot.MoveTo(panel_left + MENU_LABEL_WIDTH + MENU_LABEL_SPACE, + panel_top + MENU_HEIGHT + BUTTONS_GAP_V + BUTTON_HEIGHT + BUTTONS_GAP_V); + + bot.SetColor(PF_App_Color_RED); + bot.PaintRect(200, 50); + + bot.Move(100, 25 + (bot.FontSize() / 2)); + bot.SetColor(PF_App_Color_WHITE); + + if(arb_data->source == OCIO_SOURCE_ENVIRONMENT) + bot.DrawString("$OCIO NOT SET", kDRAWBOT_TextAlignment_Center); + else + bot.DrawString("FILE MISSING", kDRAWBOT_TextAlignment_Center); + } + else + { + // buttons + int field_bottom = panel_top + TOP_MARGIN + FIELD_HEIGHT; + int buttons_top = field_bottom + BUTTONS_GAP_V; + + // GPU alert + if(seq_data->gpu_err != GPU_ERR_NONE) + { + bot.MoveTo(panel_left + MENU_LABEL_WIDTH + MENU_LABEL_SPACE, + field_bottom + bot.FontSize() + BUTTON_TEXT_INDENT_V); + + if(seq_data->gpu_err == GPU_ERR_INSUFFICIENT) + { + bot.DrawString("GPU Insufficient"); + } + else if(seq_data->gpu_err == GPU_ERR_RENDER_ERR) + { + bot.DrawString("GPU Render Error"); + } + } + + #ifndef NDEBUG + // Premiere color space (only for debugging purposes) + if(in_data->appl_id == 'PrMr' && seq_data->prem_status != PREMIERE_UNKNOWN) + { + bot.MoveTo(panel_left + MENU_LABEL_WIDTH + MENU_LABEL_SPACE + 200, + field_bottom + bot.FontSize() + BUTTON_TEXT_INDENT_V); + + bot.SetColor(PF_App_Color_WHITE); + + if(seq_data->prem_status == PREMIERE_LINEAR) + { + bot.DrawString("Linear Float"); + } + else if(seq_data->prem_status == PREMIERE_NON_LINEAR) + { + bot.DrawString("Non-Linear Float"); + } + } + #endif + + // Export button + if(arb_data->action != OCIO_ACTION_NONE) + { + bot.MoveTo(panel_left + BUTTONS_INDENT_H + (2 * (BUTTON_WIDTH + BUTTONS_GAP_H)), buttons_top); + + DrawButton(bot, "Export...", BUTTON_WIDTH, false); + } + + if(arb_data->action == OCIO_ACTION_LUT) + { + // Invert button + bot.MoveTo(panel_left + BUTTONS_INDENT_H, buttons_top); + + DrawButton(bot, "Invert", BUTTON_WIDTH, arb_data->invert); + + // interpolation menu + int buttons_bottom = buttons_top + BUTTON_HEIGHT; + + bot.MoveTo(panel_left + MENUS_INDENT_H, buttons_bottom + MENUS_GAP_V); + + const char *txt = arb_data->interpolation == OCIO_INTERP_NEAREST ? "Nearest Neighbor" : + arb_data->interpolation == OCIO_INTERP_LINEAR ? "Linear" : + arb_data->interpolation == OCIO_INTERP_TETRAHEDRAL ? "Tetrahedral" : + arb_data->interpolation == OCIO_INTERP_BEST ? "Best" : + "Unknown"; + + DrawMenu(bot, "Interpolation:", txt); + } + else if(arb_data->action == OCIO_ACTION_CONVERT || + arb_data->action == OCIO_ACTION_DISPLAY) + { + // Convert/Display buttons + bot.MoveTo(panel_left + BUTTONS_INDENT_H, buttons_top); + + DrawButton(bot, "Convert", BUTTON_WIDTH, + arb_data->action == OCIO_ACTION_CONVERT); + + bot.Move(BUTTON_WIDTH + BUTTONS_GAP_H); + + DrawButton(bot, "Display", BUTTON_WIDTH, + arb_data->action == OCIO_ACTION_DISPLAY); + + + // menus + int buttons_bottom = buttons_top + BUTTON_HEIGHT; + + bot.MoveTo(panel_left + MENUS_INDENT_H, buttons_bottom + MENUS_GAP_V); + + if(arb_data->action == OCIO_ACTION_CONVERT) + { + DrawMenu(bot, "Input Space:", arb_data->input); + + bot.Move(0, MENU_HEIGHT + MENU_SPACE_V); + + DrawMenu(bot, "Output Space:", arb_data->output); + } + else if(arb_data->action == OCIO_ACTION_DISPLAY) + { + // color space transformations + DrawMenu(bot, "Input Space:", arb_data->input); + + bot.Move(0, MENU_HEIGHT + MENU_SPACE_V); + + DrawMenu(bot, "Transform:", arb_data->transform); + + bot.Move(0, MENU_HEIGHT + MENU_SPACE_V); + + DrawMenu(bot, "Device:", arb_data->device); + } + } + } + + + event_extra->evt_out_flags = PF_EO_HANDLED_EVENT; + + PF_UNLOCK_HANDLE(params[OCIO_DATA]->u.arb_d.value); + PF_UNLOCK_HANDLE(in_data->sequence_data); + } + } + + return err; +} + + +std::string GetProjectDir(PF_InData *in_data) +{ + if(in_data->appl_id == 'PrMr') + return std::string(""); + + AEGP_SuiteHandler suites(in_data->pica_basicP); + + AEGP_ProjectH projH = NULL; + suites.ProjSuite5()->AEGP_GetProjectByIndex(0, &projH); + + AEGP_MemHandle pathH = NULL; + suites.ProjSuite5()->AEGP_GetProjectPath(projH, &pathH); + + if(pathH) + { + std::string proj_dir; + + A_UTF16Char *path = NULL; + suites.MemorySuite1()->AEGP_LockMemHandle(pathH, (void **)&path); + + if(path) + { + // poor-man's unicode copy + char c_path[AEGP_MAX_PATH_SIZE]; + + char *c = c_path; + A_UTF16Char *s = path; + + do{ + *c++ = *s; + }while(*s++ != '\0'); + +#ifdef WIN_ENV +#define PATH_DELIMITER '\\' +#else +#define PATH_DELIMITER '/' +#endif + + std::string proj_path(c_path); + + if(proj_path.find_last_of(PATH_DELIMITER) != std::string::npos) + { + proj_dir = proj_path.substr(0, proj_path.find_last_of(PATH_DELIMITER)); + } + } + + suites.MemorySuite1()->AEGP_FreeMemHandle(pathH); + + return proj_dir; + } + + return std::string(""); +} + + +static int FindInVec(const std::vector<std::string> &vec, const std::string val) +{ + for(int i=0; i < vec.size(); i++) + { + if(vec[i] == val) + return i; + } + + return -1; +} + + +static void DoClickPath( + PF_InData *in_data, + PF_OutData *out_data, + PF_ParamDef *params[], + PF_LayerDef *output, + PF_EventExtra *event_extra, + ArbitraryData *arb_data, + SequenceData *seq_data) +{ + ExtensionMap extensions; + + for(int i=0; i < OCIO::FileTransform::getNumFormats(); i++) + { + const char *extension = OCIO::FileTransform::getFormatExtensionByIndex(i); + const char *format = OCIO::FileTransform::getFormatNameByIndex(i); + + extensions[ extension ] = format; + } + + extensions[ "ocio" ] = "OCIO Format"; + + + void *hwndOwner = NULL; + +#ifdef WIN_ENV + PF_GET_PLATFORM_DATA(PF_PlatData_MAIN_WND, &hwndOwner); +#endif + + char c_path[ARB_PATH_LEN + 1] = { '\0' }; + + bool result = OpenFile(c_path, ARB_PATH_LEN, extensions, hwndOwner); + + + if(result) + { + Path path(c_path, GetProjectDir(in_data)); + + OpenColorIO_AE_Context *new_context = new OpenColorIO_AE_Context(path.full_path(), + OCIO_SOURCE_CUSTOM); + + if(new_context == NULL) + throw OCIO::Exception("WTF?"); + + + if(seq_data->context) + { + delete seq_data->context; + } + + seq_data->context = new_context; + + arb_data->source = seq_data->source = OCIO_SOURCE_CUSTOM; + + strncpy(arb_data->path, path.full_path().c_str(), ARB_PATH_LEN); + strncpy(arb_data->relative_path, path.relative_path(false).c_str(), ARB_PATH_LEN); + + strncpy(seq_data->path, arb_data->path, ARB_PATH_LEN); + strncpy(seq_data->relative_path, arb_data->relative_path, ARB_PATH_LEN); + + + // try to retain settings if it looks like the same situation, + // possibly fixing a moved path + if(OCIO_ACTION_NONE == arb_data->action || + (OCIO_ACTION_LUT == new_context->getAction() && OCIO_ACTION_LUT != arb_data->action) || + (OCIO_ACTION_LUT != new_context->getAction() && OCIO_ACTION_LUT == arb_data->action) || + (OCIO_ACTION_LUT != new_context->getAction() && + (-1 == FindInVec(new_context->getInputs(), arb_data->input) || + -1 == FindInVec(new_context->getInputs(), arb_data->output) || + -1 == FindInVec(new_context->getTransforms(), arb_data->transform) || + -1 == FindInVec(new_context->getDevices(), arb_data->device) ) ) ) + { + // Configuration is different, so initialize defaults + arb_data->action = seq_data->context->getAction(); + + if(arb_data->action == OCIO_ACTION_LUT) + { + arb_data->invert = FALSE; + arb_data->interpolation = OCIO_INTERP_LINEAR; + } + else + { + strncpy(arb_data->input, seq_data->context->getInput().c_str(), ARB_SPACE_LEN); + strncpy(arb_data->output, seq_data->context->getOutput().c_str(), ARB_SPACE_LEN); + strncpy(arb_data->transform, seq_data->context->getTransform().c_str(), ARB_SPACE_LEN); + strncpy(arb_data->device, seq_data->context->getDevice().c_str(), ARB_SPACE_LEN); + } + } + else + { + // Configuration is the same, retain current settings + if(arb_data->action == OCIO_ACTION_LUT) + { + seq_data->context->setupLUT(arb_data->invert, arb_data->interpolation); + } + else if(arb_data->action == OCIO_ACTION_CONVERT) + { + seq_data->context->setupConvert(arb_data->input, arb_data->output); + } + else if(arb_data->action == OCIO_ACTION_DISPLAY) + { + seq_data->context->setupDisplay(arb_data->input, arb_data->transform, arb_data->device); + } + } + + params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE; + + seq_data->status = STATUS_USING_ABSOLUTE; + } +} + + +static void DoClickConfig( + PF_InData *in_data, + PF_OutData *out_data, + PF_ParamDef *params[], + PF_LayerDef *output, + PF_EventExtra *event_extra, + ArbitraryData *arb_data, + SequenceData *seq_data) +{ + void *hwndOwner = NULL; + +#ifdef WIN_ENV + PF_GET_PLATFORM_DATA(PF_PlatData_MAIN_WND, &hwndOwner); +#endif + + ConfigVec configs; + GetStdConfigs(configs); + + if(configs.size() == 0) + configs.push_back("(nada)"); // menu makes a gray entry that says "No configs in $PATH" + + + MenuVec menu_items; + int selected = 0; + + menu_items.push_back("$OCIO"); // menu will gray this out if $OCIO is not defined + + menu_items.push_back("(-"); // this tells the menu to make a seperator + + for(ConfigVec::const_iterator i = configs.begin(); i != configs.end(); ++i) + { + menu_items.push_back( *i ); + + if(arb_data->source == OCIO_SOURCE_STANDARD && arb_data->path == *i) + { + selected = menu_items.size() - 1; + } + } + + menu_items.push_back("(-"); + + menu_items.push_back("Custom..."); + + int custom_choice = menu_items.size() - 1; + + if(arb_data->source == OCIO_SOURCE_CUSTOM) + { + selected = -1; + } + + + int choice = PopUpMenu(menu_items, selected, hwndOwner); + + + if(choice == custom_choice) + { + // custom is the same as clicking the path + DoClickPath(in_data, out_data, params, output, event_extra, arb_data, seq_data); + } + else if(choice != selected) + { + OpenColorIO_AE_Context *new_context = NULL; + + if(choice == 0) + { + // $OCIO + char *file = std::getenv("OCIO"); + + if(file) + { + Path path(file, GetProjectDir(in_data)); + + new_context = new OpenColorIO_AE_Context(path.full_path(), + OCIO_SOURCE_ENVIRONMENT); + + arb_data->source = seq_data->source = OCIO_SOURCE_ENVIRONMENT; + + strncpy(arb_data->path, path.full_path().c_str(), ARB_PATH_LEN); + strncpy(arb_data->relative_path, path.relative_path(false).c_str(), ARB_PATH_LEN); + } + else + throw OCIO::Exception("No $OCIO environment variable defined."); + } + else + { + // standard configs + std::string config = configs[choice - 2]; + + std::string path = GetStdConfigPath(config); + + if( !path.empty() ) + { + new_context = new OpenColorIO_AE_Context(config, OCIO_SOURCE_STANDARD); + + arb_data->source = seq_data->source = OCIO_SOURCE_STANDARD; + + strncpy(arb_data->path, config.c_str(), ARB_PATH_LEN); + strncpy(arb_data->relative_path, path.c_str(), ARB_PATH_LEN); + } + else + throw OCIO::Exception("Problem loading OCIO configuration."); + } + + + if(new_context) + { + if(seq_data->context) + { + delete seq_data->context; + } + + seq_data->context = new_context; + + + strncpy(seq_data->path, arb_data->path, ARB_PATH_LEN); + strncpy(seq_data->relative_path, arb_data->relative_path, ARB_PATH_LEN); + + // try to retain settings if it looks like the same situation, + // possibly fixing a moved path + if(OCIO_ACTION_NONE == arb_data->action || + (OCIO_ACTION_LUT == new_context->getAction() && OCIO_ACTION_LUT != arb_data->action) || + (OCIO_ACTION_LUT != new_context->getAction() && OCIO_ACTION_LUT == arb_data->action) || + (OCIO_ACTION_LUT != new_context->getAction() && + (-1 == FindInVec(new_context->getInputs(), arb_data->input) || + -1 == FindInVec(new_context->getInputs(), arb_data->output) || + -1 == FindInVec(new_context->getTransforms(), arb_data->transform) || + -1 == FindInVec(new_context->getDevices(), arb_data->device) ) ) ) + { + // Configuration is different, so initialize defaults + arb_data->action = seq_data->context->getAction(); + + if(arb_data->action == OCIO_ACTION_LUT) + { + arb_data->invert = FALSE; + arb_data->interpolation = OCIO_INTERP_LINEAR; + } + else + { + strncpy(arb_data->input, seq_data->context->getInput().c_str(), ARB_SPACE_LEN); + strncpy(arb_data->output, seq_data->context->getOutput().c_str(), ARB_SPACE_LEN); + strncpy(arb_data->transform, seq_data->context->getTransform().c_str(), ARB_SPACE_LEN); + strncpy(arb_data->device, seq_data->context->getDevice().c_str(), ARB_SPACE_LEN); + } + } + else + { + // Configuration is the same, retain current settings + if(arb_data->action == OCIO_ACTION_LUT) + { + seq_data->context->setupLUT(arb_data->invert, arb_data->interpolation); + } + else if(arb_data->action == OCIO_ACTION_CONVERT) + { + seq_data->context->setupConvert(arb_data->input, arb_data->output); + } + else if(arb_data->action == OCIO_ACTION_DISPLAY) + { + seq_data->context->setupDisplay(arb_data->input, arb_data->transform, arb_data->device); + } + } + + params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE; + + seq_data->status = STATUS_OK; + } + } +} + + +static void DoClickConvertDisplay( + PF_InData *in_data, + PF_OutData *out_data, + PF_ParamDef *params[], + PF_LayerDef *output, + PF_EventExtra *event_extra, + ArbitraryData *arb_data, + SequenceData *seq_data, + UIRegion reg ) +{ + if(arb_data->action == OCIO_ACTION_LUT) + { + if(reg == REGION_CONVERT_BUTTON) // i.e. Invert + { + // doing it this way so that any exceptions thrown by setupLUT + // because the LUT can't be inverted are thrown before + // I actually chenge the ArbData setting + seq_data->context->setupLUT(!arb_data->invert, arb_data->interpolation); + + arb_data->invert = !arb_data->invert; + + params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE; + } + } + else if(arb_data->action == OCIO_ACTION_CONVERT || arb_data->action == OCIO_ACTION_DISPLAY) + { + if(reg == REGION_CONVERT_BUTTON && arb_data->action != OCIO_ACTION_CONVERT) + { + arb_data->action = OCIO_ACTION_CONVERT; + + seq_data->context->setupConvert(arb_data->input, arb_data->output); + + params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE; + } + else if(reg == REGION_DISPLAY_BUTTON && arb_data->action != OCIO_ACTION_DISPLAY) + { + arb_data->action = OCIO_ACTION_DISPLAY; + + seq_data->context->setupDisplay(arb_data->input, arb_data->transform, arb_data->device); + + params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE; + } + } +} + + +static void DoClickExport( + PF_InData *in_data, + PF_OutData *out_data, + PF_ParamDef *params[], + PF_LayerDef *output, + PF_EventExtra *event_extra, + ArbitraryData *arb_data, + SequenceData *seq_data, + UIRegion reg ) +{ + ExtensionMap extensions; + + for(int i=0; i < OCIO::Baker::getNumFormats(); ++i) + { + const char *extension = OCIO::Baker::getFormatExtensionByIndex(i); + const char *format = OCIO::Baker::getFormatNameByIndex(i); + + extensions[ extension ] = format; + } + + extensions[ "icc" ] = "ICC Profile"; + + + void *hwndOwner = NULL; + +#ifdef WIN_ENV + PF_GET_PLATFORM_DATA(PF_PlatData_MAIN_WND, &hwndOwner); +#endif + + char path[256] = { '\0' }; + + bool result = SaveFile(path, 255, extensions, hwndOwner); + + + if(result) + { + std::string the_path(path); + std::string the_extension = the_path.substr( the_path.find_last_of('.') + 1 ); + + bool do_export = true; + + std::string monitor_icc_path; + + if(the_extension == "icc") + { + char monitor_path[256] = {'\0'}; + + do_export = GetMonitorProfile(monitor_path, 255, hwndOwner); + + if(monitor_path[0] != '\0') + monitor_icc_path = monitor_path; + } + + if(do_export) + seq_data->context->ExportLUT(the_path, monitor_icc_path); + } +} + + +static void DoClickMenus( + PF_InData *in_data, + PF_OutData *out_data, + PF_ParamDef *params[], + PF_LayerDef *output, + PF_EventExtra *event_extra, + ArbitraryData *arb_data, + SequenceData *seq_data, + UIRegion reg ) +{ + if(seq_data->context != NULL && arb_data->action == seq_data->context->getAction()) + { + MenuVec menu_items; + int selected_item; + + if(arb_data->action == OCIO_ACTION_LUT) + { + if(reg == REGION_MENU1) + { + menu_items.push_back("Nearest Neighbor"); + menu_items.push_back("Linear"); + menu_items.push_back("Tetrahedral"); + menu_items.push_back("(-"); + menu_items.push_back("Best"); + + selected_item = arb_data->interpolation == OCIO_INTERP_NEAREST ? 0 : + arb_data->interpolation == OCIO_INTERP_LINEAR ? 1 : + arb_data->interpolation == OCIO_INTERP_TETRAHEDRAL ? 2 : + arb_data->interpolation == OCIO_INTERP_BEST ? 4 : + -1; + } + } + else if(arb_data->action == OCIO_ACTION_CONVERT) + { + menu_items = seq_data->context->getInputs(); + + if(reg == REGION_MENU1) + { + selected_item = FindInVec(menu_items, arb_data->input); + } + else + { + selected_item = FindInVec(menu_items, arb_data->output); + } + } + else if(arb_data->action == OCIO_ACTION_DISPLAY) + { + if(reg == REGION_MENU1) + { + menu_items = seq_data->context->getInputs(); + + selected_item = FindInVec(menu_items, arb_data->input); + } + else if(reg == REGION_MENU2) + { + menu_items = seq_data->context->getTransforms(); + + selected_item = FindInVec(menu_items, arb_data->transform); + } + else if(reg == REGION_MENU3) + { + menu_items = seq_data->context->getDevices(); + + selected_item = FindInVec(menu_items, arb_data->device); + } + } + + + + void *hwndOwner = NULL; + + #ifdef WIN_ENV + PF_GET_PLATFORM_DATA(PF_PlatData_MAIN_WND, &hwndOwner); + #endif + + int result = PopUpMenu(menu_items, selected_item, hwndOwner); + + + if(result != selected_item) + { + std::string color_space = menu_items[ result ]; + + if(arb_data->action == OCIO_ACTION_LUT) + { + if(reg == REGION_MENU1) + { + arb_data->interpolation = result == 0 ? OCIO_INTERP_NEAREST : + result == 2 ? OCIO_INTERP_TETRAHEDRAL : + result == 4 ? OCIO_INTERP_BEST : + OCIO_INTERP_LINEAR; + + seq_data->context->setupLUT(arb_data->invert, arb_data->interpolation); + } + } + else if(arb_data->action == OCIO_ACTION_CONVERT) + { + if(reg == REGION_MENU1) + { + strncpy(arb_data->input, color_space.c_str(), ARB_SPACE_LEN); + } + else if(reg == REGION_MENU2) + { + strncpy(arb_data->output, color_space.c_str(), ARB_SPACE_LEN); + } + + seq_data->context->setupConvert(arb_data->input, arb_data->output); + } + else if(arb_data->action == OCIO_ACTION_DISPLAY) + { + if(reg == REGION_MENU1) + { + strncpy(arb_data->input, color_space.c_str(), ARB_SPACE_LEN); + } + else if(reg == REGION_MENU2) + { + strncpy(arb_data->transform, color_space.c_str(), ARB_SPACE_LEN); + } + else if(reg == REGION_MENU3) + { + strncpy(arb_data->device, color_space.c_str(), ARB_SPACE_LEN); + } + + seq_data->context->setupDisplay(arb_data->input, arb_data->transform, arb_data->device); + } + + params[OCIO_DATA]->uu.change_flags = PF_ChangeFlag_CHANGED_VALUE; + } + } +} + + +static PF_Err DoClick( + PF_InData *in_data, + PF_OutData *out_data, + PF_ParamDef *params[], + PF_LayerDef *output, + PF_EventExtra *event_extra ) +{ + PF_Err err = PF_Err_NONE; + + ArbitraryData *arb_data = (ArbitraryData *)PF_LOCK_HANDLE(params[OCIO_DATA]->u.arb_d.value); + SequenceData *seq_data = (SequenceData *)PF_LOCK_HANDLE(in_data->sequence_data); + + + if(event_extra->effect_win.area == PF_EA_CONTROL) + { + bool menus_visible = (arb_data->action != OCIO_ACTION_NONE); + bool third_menu = (arb_data->action == OCIO_ACTION_DISPLAY); + + PF_Point local_point; + + local_point.h = event_extra->u.do_click.screen_point.h - event_extra->effect_win.current_frame.left; + local_point.v = event_extra->u.do_click.screen_point.v - event_extra->effect_win.current_frame.top; + + UIRegion reg = WhichRegion(local_point, menus_visible, third_menu); + + if(reg != REGION_NONE) + { + try + { + if(reg == REGION_CONFIG_MENU) + { + DoClickConfig(in_data, out_data, params, output, + event_extra, arb_data, seq_data); + } + else if(reg == REGION_PATH) + { + if(arb_data->source == OCIO_SOURCE_CUSTOM) + { + DoClickPath(in_data, out_data, params, output, + event_extra, arb_data, seq_data); + } + } + else if(arb_data->action != OCIO_ACTION_NONE && + seq_data->status != STATUS_FILE_MISSING) + { + if(seq_data->context == NULL) + { + seq_data->context = new OpenColorIO_AE_Context(arb_data, + GetProjectDir(in_data) ); + } + + if(reg == REGION_CONVERT_BUTTON || reg == REGION_DISPLAY_BUTTON) + { + DoClickConvertDisplay(in_data, out_data, params, output, + event_extra, arb_data, seq_data, reg); + } + else if(reg == REGION_EXPORT_BUTTON) + { + DoClickExport(in_data, out_data, params, output, + event_extra, arb_data, seq_data, reg); + } + else // must be a menu then + { + DoClickMenus(in_data, out_data, params, output, + event_extra, arb_data, seq_data, reg); + } + } + } + catch(std::exception &e) + { + if(in_data->appl_id == 'FXTC') + { + PF_SPRINTF(out_data->return_msg, e.what()); + + out_data->out_flags |= PF_OutFlag_DISPLAY_ERROR_MESSAGE; + } + else + { + void *hwndOwner = NULL; + + #ifdef WIN_ENV + PF_GET_PLATFORM_DATA(PF_PlatData_MAIN_WND, &hwndOwner); + #endif + + ErrorMessage(e.what(), hwndOwner); + } + } + catch(...) + { + PF_SPRINTF(out_data->return_msg, "Unknown error"); + + out_data->out_flags |= PF_OutFlag_DISPLAY_ERROR_MESSAGE; + } + } + } + + + PF_UNLOCK_HANDLE(params[OCIO_DATA]->u.arb_d.value); + PF_UNLOCK_HANDLE(in_data->sequence_data); + + event_extra->evt_out_flags = PF_EO_HANDLED_EVENT; + + return err; +} + + +PF_Err HandleEvent ( + PF_InData *in_data, + PF_OutData *out_data, + PF_ParamDef *params[], + PF_LayerDef *output, + PF_EventExtra *extra ) +{ + PF_Err err = PF_Err_NONE; + + extra->evt_out_flags = 0; + + if(!err) + { + switch(extra->e_type) + { + case PF_Event_DRAW: + err = DrawEvent(in_data, out_data, params, output, extra); + break; + + case PF_Event_DO_CLICK: + err = DoClick(in_data, out_data, params, output, extra); + break; + } + } + + return err; +} |