void QTextOdfWriter::writeFrameFormat(QXmlStreamWriter &writer, QTextFrameFormat format, int formatIndex) const { writer.writeStartElement(styleNS, QString::fromLatin1("style")); writer.writeAttribute(styleNS, QString::fromLatin1("name"), QString::fromLatin1("s%1").arg(formatIndex)); writer.writeAttribute(styleNS, QString::fromLatin1("family"), QString::fromLatin1("section")); writer.writeEmptyElement(styleNS, QString::fromLatin1("section-properties")); if (format.hasProperty(QTextFormat::FrameTopMargin)) writer.writeAttribute(foNS, QString::fromLatin1("margin-top"), pixelToPoint(qMax(qreal(0.), format.topMargin())) ); if (format.hasProperty(QTextFormat::FrameBottomMargin)) writer.writeAttribute(foNS, QString::fromLatin1("margin-bottom"), pixelToPoint(qMax(qreal(0.), format.bottomMargin())) ); if (format.hasProperty(QTextFormat::FrameLeftMargin)) writer.writeAttribute(foNS, QString::fromLatin1("margin-left"), pixelToPoint(qMax(qreal(0.), format.leftMargin())) ); if (format.hasProperty(QTextFormat::FrameRightMargin)) writer.writeAttribute(foNS, QString::fromLatin1("margin-right"), pixelToPoint(qMax(qreal(0.), format.rightMargin())) ); writer.writeEndElement(); // style // TODO consider putting the following properties in a qt-namespace. // Position position () const // qreal border () const // QBrush borderBrush () const // BorderStyle borderStyle () const // qreal padding () const // QTextLength width () const // QTextLength height () const // PageBreakFlags pageBreakPolicy () const }
void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextFragment &fragment) const { writer.writeStartElement(drawNS, QString::fromLatin1("frame")); if (m_strategy == 0) { // don't do anything. } else if (fragment.charFormat().isImageFormat()) { QTextImageFormat imageFormat = fragment.charFormat().toImageFormat(); writer.writeAttribute(drawNS, QString::fromLatin1("name"), imageFormat.name()); // vvv Copy pasted mostly from Qt ================= QImage image; QString name = imageFormat.name(); if (name.startsWith(QLatin1String(":/"))) // auto-detect resources name.prepend(QLatin1String("qrc")); QUrl url = QUrl::fromEncoded(name.toUtf8()); const QVariant data = m_document->resource(QTextDocument::ImageResource, url); if (data.type() == QVariant::Image) { image = qvariant_cast<QImage>(data); } else if (data.type() == QVariant::ByteArray) { image.loadFromData(data.toByteArray()); } if (image.isNull()) { QString context; if (QTextImageHandler::externalLoader) image = QTextImageHandler::externalLoader(name, context); if (image.isNull()) { // try direct loading name = imageFormat.name(); // remove qrc:/ prefix again image.load(name); } } // ^^^ Copy pasted mostly from Qt ================= if (! image.isNull()) { QBuffer imageBytes; QImageWriter imageWriter(&imageBytes, "png"); imageWriter.write(image); QString filename = m_strategy->createUniqueImageName(); m_strategy->addFile(filename, QString::fromLatin1("image/png"), imageBytes.data()); // get the width/height from the format. qreal width = (imageFormat.hasProperty(QTextFormat::ImageWidth)) ? imageFormat.width() : image.width(); writer.writeAttribute(svgNS, QString::fromLatin1("width"), pixelToPoint(width)); qreal height = (imageFormat.hasProperty(QTextFormat::ImageHeight)) ? imageFormat.height() : image.height(); writer.writeAttribute(svgNS, QString::fromLatin1("height"), pixelToPoint(height)); writer.writeStartElement(drawNS, QString::fromLatin1("image")); writer.writeAttribute(xlinkNS, QString::fromLatin1("href"), filename); writer.writeEndElement(); // image } } writer.writeEndElement(); // frame }
void QTextOdfWriter::writeTableCellFormat(QXmlStreamWriter &writer, QTextTableCellFormat format, int formatIndex) const { writer.writeStartElement(styleNS, QString::fromLatin1("style")); writer.writeAttribute(styleNS, QString::fromLatin1("name"), QString::fromLatin1("T%1").arg(formatIndex)); writer.writeAttribute(styleNS, QString::fromLatin1("family"), QString::fromLatin1("table")); writer.writeEmptyElement(styleNS, QString::fromLatin1("table-properties")); qreal padding = format.topPadding(); if (padding > 0 && padding == format.bottomPadding() && padding == format.leftPadding() && padding == format.rightPadding()) { writer.writeAttribute(foNS, QString::fromLatin1("padding"), pixelToPoint(padding)); } else { if (padding > 0) writer.writeAttribute(foNS, QString::fromLatin1("padding-top"), pixelToPoint(padding)); if (format.bottomPadding() > 0) writer.writeAttribute(foNS, QString::fromLatin1("padding-bottom"), pixelToPoint(format.bottomPadding())); if (format.leftPadding() > 0) writer.writeAttribute(foNS, QString::fromLatin1("padding-left"), pixelToPoint(format.leftPadding())); if (format.rightPadding() > 0) writer.writeAttribute(foNS, QString::fromLatin1("padding-right"), pixelToPoint(format.rightPadding())); } if (format.hasProperty(QTextFormat::TextVerticalAlignment)) { QString pos; switch (format.verticalAlignment()) { case QTextCharFormat::AlignMiddle: pos = QString::fromLatin1("middle"); break; case QTextCharFormat::AlignTop: pos = QString::fromLatin1("top"); break; case QTextCharFormat::AlignBottom: pos = QString::fromLatin1("bottom"); break; default: pos = QString::fromLatin1("automatic"); break; } writer.writeAttribute(styleNS, QString::fromLatin1("vertical-align"), pos); } // TODO // ODF just search for style-table-cell-properties-attlist) // QTextFormat::BackgroundImageUrl // format.background // QTextFormat::FrameBorder writer.writeEndElement(); // style }
void QTextOdfWriter::writeCharacterFormat(QXmlStreamWriter &writer, QTextCharFormat format, int formatIndex) const { writer.writeStartElement(styleNS, QString::fromLatin1("style")); writer.writeAttribute(styleNS, QString::fromLatin1("name"), QString::fromLatin1("c%1").arg(formatIndex)); writer.writeAttribute(styleNS, QString::fromLatin1("family"), QString::fromLatin1("text")); writer.writeEmptyElement(styleNS, QString::fromLatin1("text-properties")); if (format.fontItalic()) writer.writeAttribute(foNS, QString::fromLatin1("font-style"), QString::fromLatin1("italic")); if (format.hasProperty(QTextFormat::FontWeight) && format.fontWeight() != QFont::Normal) { QString value; if (format.fontWeight() == QFont::Bold) value = QString::fromLatin1("bold"); else value = QString::number(format.fontWeight() * 10); writer.writeAttribute(foNS, QString::fromLatin1("font-weight"), value); } if (format.hasProperty(QTextFormat::FontFamily)) writer.writeAttribute(foNS, QString::fromLatin1("font-family"), format.fontFamily()); else writer.writeAttribute(foNS, QString::fromLatin1("font-family"), QString::fromLatin1("Sans")); // Qt default if (format.hasProperty(QTextFormat::FontPointSize)) writer.writeAttribute(foNS, QString::fromLatin1("font-size"), QString::fromLatin1("%1pt").arg(format.fontPointSize())); if (format.hasProperty(QTextFormat::FontCapitalization)) { switch(format.fontCapitalization()) { case QFont::MixedCase: writer.writeAttribute(foNS, QString::fromLatin1("text-transform"), QString::fromLatin1("none")); break; case QFont::AllUppercase: writer.writeAttribute(foNS, QString::fromLatin1("text-transform"), QString::fromLatin1("uppercase")); break; case QFont::AllLowercase: writer.writeAttribute(foNS, QString::fromLatin1("text-transform"), QString::fromLatin1("lowercase")); break; case QFont::Capitalize: writer.writeAttribute(foNS, QString::fromLatin1("text-transform"), QString::fromLatin1("capitalize")); break; case QFont::SmallCaps: writer.writeAttribute(foNS, QString::fromLatin1("font-variant"), QString::fromLatin1("small-caps")); break; } } if (format.hasProperty(QTextFormat::FontLetterSpacing)) writer.writeAttribute(foNS, QString::fromLatin1("letter-spacing"), pixelToPoint(format.fontLetterSpacing())); if (format.hasProperty(QTextFormat::FontWordSpacing) && format.fontWordSpacing() != 0) writer.writeAttribute(foNS, QString::fromLatin1("word-spacing"), pixelToPoint(format.fontWordSpacing())); if (format.hasProperty(QTextFormat::FontUnderline)) writer.writeAttribute(styleNS, QString::fromLatin1("text-underline-type"), format.fontUnderline() ? QString::fromLatin1("single") : QString::fromLatin1("none")); if (format.hasProperty(QTextFormat::FontOverline)) { // bool fontOverline () const TODO } if (format.hasProperty(QTextFormat::FontStrikeOut)) writer.writeAttribute(styleNS,QString::fromLatin1( "text-line-through-type"), format.fontStrikeOut() ? QString::fromLatin1("single") : QString::fromLatin1("none")); if (format.hasProperty(QTextFormat::TextUnderlineColor)) writer.writeAttribute(styleNS, QString::fromLatin1("text-underline-color"), format.underlineColor().name()); if (format.hasProperty(QTextFormat::FontFixedPitch)) { // bool fontFixedPitch () const TODO } if (format.hasProperty(QTextFormat::TextUnderlineStyle)) { QString value; switch (format.underlineStyle()) { case QTextCharFormat::NoUnderline: value = QString::fromLatin1("none"); break; case QTextCharFormat::SingleUnderline: value = QString::fromLatin1("solid"); break; case QTextCharFormat::DashUnderline: value = QString::fromLatin1("dash"); break; case QTextCharFormat::DotLine: value = QString::fromLatin1("dotted"); break; case QTextCharFormat::DashDotLine: value = QString::fromLatin1("dash-dot"); break; case QTextCharFormat::DashDotDotLine: value = QString::fromLatin1("dot-dot-dash"); break; case QTextCharFormat::WaveUnderline: value = QString::fromLatin1("wave"); break; case QTextCharFormat::SpellCheckUnderline: value = QString::fromLatin1("none"); break; } writer.writeAttribute(styleNS, QString::fromLatin1("text-underline-style"), value); } if (format.hasProperty(QTextFormat::TextVerticalAlignment)) { QString value; switch (format.verticalAlignment()) { case QTextCharFormat::AlignMiddle: case QTextCharFormat::AlignNormal: value = QString::fromLatin1("0%"); break; case QTextCharFormat::AlignSuperScript: value = QString::fromLatin1("super"); break; case QTextCharFormat::AlignSubScript: value = QString::fromLatin1("sub"); break; case QTextCharFormat::AlignTop: value = QString::fromLatin1("100%"); break; case QTextCharFormat::AlignBottom : value = QString::fromLatin1("-100%"); break; case QTextCharFormat::AlignBaseline: break; } writer.writeAttribute(styleNS, QString::fromLatin1("text-position"), value); } if (format.hasProperty(QTextFormat::TextOutline)) writer.writeAttribute(styleNS, QString::fromLatin1("text-outline"), QString::fromLatin1("true")); if (format.hasProperty(QTextFormat::TextToolTip)) { // QString toolTip () const TODO } if (format.hasProperty(QTextFormat::IsAnchor)) { // bool isAnchor () const TODO } if (format.hasProperty(QTextFormat::AnchorHref)) { // QString anchorHref () const TODO } if (format.hasProperty(QTextFormat::AnchorName)) { // QString anchorName () const TODO } if (format.hasProperty(QTextFormat::ForegroundBrush)) { QBrush brush = format.foreground(); writer.writeAttribute(foNS, QString::fromLatin1("color"), brush.color().name()); } if (format.hasProperty(QTextFormat::BackgroundBrush)) { QBrush brush = format.background(); writer.writeAttribute(foNS, QString::fromLatin1("background-color"), brush.color().name()); } writer.writeEndElement(); // style }
void QTextOdfWriter::writeBlockFormat(QXmlStreamWriter &writer, QTextBlockFormat format, int formatIndex) const { writer.writeStartElement(styleNS, QString::fromLatin1("style")); writer.writeAttribute(styleNS, QString::fromLatin1("name"), QString::fromLatin1("p%1").arg(formatIndex)); writer.writeAttribute(styleNS, QString::fromLatin1("family"), QString::fromLatin1("paragraph")); writer.writeStartElement(styleNS, QString::fromLatin1("paragraph-properties")); if (format.hasProperty(QTextFormat::BlockAlignment)) { const Qt::Alignment alignment = format.alignment() & Qt::AlignHorizontal_Mask; QString value; if (alignment == Qt::AlignLeading) value = QString::fromLatin1("start"); else if (alignment == Qt::AlignTrailing) value = QString::fromLatin1("end"); else if (alignment == (Qt::AlignLeft | Qt::AlignAbsolute)) value = QString::fromLatin1("left"); else if (alignment == (Qt::AlignRight | Qt::AlignAbsolute)) value = QString::fromLatin1("right"); else if (alignment == Qt::AlignHCenter) value = QString::fromLatin1("center"); else if (alignment == Qt::AlignJustify) value = QString::fromLatin1("justify"); else qWarning() << "QTextOdfWriter: unsupported paragraph alignment; " << format.alignment(); if (! value.isNull()) writer.writeAttribute(foNS, QString::fromLatin1("text-align"), value); } if (format.hasProperty(QTextFormat::BlockTopMargin)) writer.writeAttribute(foNS, QString::fromLatin1("margin-top"), pixelToPoint(qMax(qreal(0.), format.topMargin())) ); if (format.hasProperty(QTextFormat::BlockBottomMargin)) writer.writeAttribute(foNS, QString::fromLatin1("margin-bottom"), pixelToPoint(qMax(qreal(0.), format.bottomMargin())) ); if (format.hasProperty(QTextFormat::BlockLeftMargin) || format.hasProperty(QTextFormat::BlockIndent)) writer.writeAttribute(foNS, QString::fromLatin1("margin-left"), pixelToPoint(qMax(qreal(0.), format.leftMargin() + format.indent()))); if (format.hasProperty(QTextFormat::BlockRightMargin)) writer.writeAttribute(foNS, QString::fromLatin1("margin-right"), pixelToPoint(qMax(qreal(0.), format.rightMargin())) ); if (format.hasProperty(QTextFormat::TextIndent)) writer.writeAttribute(foNS, QString::fromLatin1("text-indent"), pixelToPoint(format.textIndent())); if (format.hasProperty(QTextFormat::PageBreakPolicy)) { if (format.pageBreakPolicy() & QTextFormat::PageBreak_AlwaysBefore) writer.writeAttribute(foNS, QString::fromLatin1("break-before"), QString::fromLatin1("page")); if (format.pageBreakPolicy() & QTextFormat::PageBreak_AlwaysAfter) writer.writeAttribute(foNS, QString::fromLatin1("break-after"), QString::fromLatin1("page")); } if (format.hasProperty(QTextFormat::BackgroundBrush)) { QBrush brush = format.background(); writer.writeAttribute(foNS, QString::fromLatin1("background-color"), brush.color().name()); } if (format.hasProperty(QTextFormat::BlockNonBreakableLines)) writer.writeAttribute(foNS, QString::fromLatin1("keep-together"), format.nonBreakableLines() ? QString::fromLatin1("true") : QString::fromLatin1("false")); if (format.hasProperty(QTextFormat::TabPositions)) { QList<QTextOption::Tab> tabs = format.tabPositions(); writer.writeStartElement(styleNS, QString::fromLatin1("tab-stops")); QList<QTextOption::Tab>::Iterator iterator = tabs.begin(); while(iterator != tabs.end()) { writer.writeEmptyElement(styleNS, QString::fromLatin1("tab-stop")); writer.writeAttribute(styleNS, QString::fromLatin1("position"), pixelToPoint(iterator->position) ); QString type; switch(iterator->type) { case QTextOption::DelimiterTab: type = QString::fromLatin1("char"); break; case QTextOption::LeftTab: type = QString::fromLatin1("left"); break; case QTextOption::RightTab: type = QString::fromLatin1("right"); break; case QTextOption::CenterTab: type = QString::fromLatin1("center"); break; } writer.writeAttribute(styleNS, QString::fromLatin1("type"), type); if (iterator->delimiter != 0) writer.writeAttribute(styleNS, QString::fromLatin1("char"), iterator->delimiter); ++iterator; } writer.writeEndElement(); // tab-stops } writer.writeEndElement(); // paragraph-properties writer.writeEndElement(); // style }
float rowPointSize(ROW *row,int resolution) { float ptsize = pixelToPoint(rowPixelSize(row), resolution); return ptsize; }
void updateEditor(SDL_Event event, EditorData* data) { GUI_sendEventToGUI(data->gui, &event); const unsigned char* keyboardState = SDL_GetKeyboardState(NULL); int2 mousePixel; SDL_GetMouseState(&mousePixel.x, &mousePixel.y); float2 mousePos = pixelToPoint(&data->view, mousePixel); updateBones(data); switch (event.type) { case SDL_KEYDOWN: { switch (event.key.keysym.scancode) { case SDL_SCANCODE_S: if (event.key.keysym.mod == KMOD_LCTRL) { SDL_Event lastEvent = data->lowEventStack.Top(); if (lastEvent.key.keysym.scancode == SDL_SCANCODE_S && lastEvent.key.keysym.mod == KMOD_LCTRL) { // save skeleton GUI_WidgetID widget = GUI_addContainer(data->gui, GUI_MAIN_WIDGET, { 400 - 100, 300 - 25, 200, 50}, GUI_Container::Orientation::HORIZONTAL); auto callbackSave = [](GUI* gui, GUI_WidgetID widgetID, void* editorData) { EditorData* data = (EditorData*)editorData; GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); const char* filename = GUI_getTextfield(gui, GUI_getChildWidget(gui, widget, 0)).text; saveSkeleton(filename, &data->skeleton[0], &data->names[0], data->skeleton.size()); GUI_removeWidget(gui, widget); }; auto callbackCancel = [](GUI* gui, GUI_WidgetID widgetID, void*) { GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); GUI_removeWidget(gui, widget); }; GUI_addTextfield(data->gui, widget, { 0, 0, -1, -1 }, "filename"); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Save", data, callbackSave); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Cancel", 0, callbackCancel); break; } else if (lastEvent.key.keysym.scancode == SDL_SCANCODE_O && lastEvent.key.keysym.mod == KMOD_LCTRL) { // load skeleton GUI_WidgetID widget = GUI_addContainer(data->gui, GUI_MAIN_WIDGET, { 400 - 100, 300 - 15, 200, 30 }, GUI_Container::Orientation::HORIZONTAL); auto callbackLoad = [](GUI* gui, GUI_WidgetID widgetID, void* editorData) { EditorData* data = (EditorData*)editorData; GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); const char* filename = GUI_getTextfield(gui, GUI_getChildWidget(gui, widget, 0)).text; strcpy(data->skeletonName, filename); const SkeletonSave* save = loadSkeleton(filename); if (save != 0) { data->bones.clear(); data->skeleton.clear(); data->constraints.clear(); data->names.clear(); const char* name = save->names; for (int i = 0; i < save->numBones; ++i) { Bone newBone; newBone.jointAngle = { 1, 0 }; newBone.jointPos = save->jointPos[i]; newBone.parentJoint = save->parentJoints[i]; newBone.name = data->names.push({ { 0 } }); memcpy(data->names[newBone.name].string, name, save->nameLen[i] * sizeof(char)); name += save->nameLen[i]; Constraint constraint; constraint.minAngle = -PI; constraint.maxAngle = 3 * PI; data->skeleton.push(newBone); data->constraints.push(constraint); } updateBones(data); } GUI_removeWidget(gui, widget); }; auto callbackCancel = [](GUI* gui, GUI_WidgetID widgetID, void*) { GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); GUI_removeWidget(gui, widget); }; GUI_addTextfield(data->gui, widget, { 0, 0, -1, -1 }, "filename"); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Load", data, callbackLoad); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Cancel", 0, callbackCancel); break; } data->lowEventStack.Push(event); } break; case SDL_SCANCODE_K: if (event.key.keysym.mod == KMOD_LCTRL) { SDL_Event lastEvent = data->lowEventStack.Top(); if (lastEvent.key.keysym.scancode == SDL_SCANCODE_S && lastEvent.key.keysym.mod == KMOD_LCTRL) { // save keyFrame GUI_WidgetID widget = GUI_addContainer(data->gui, GUI_MAIN_WIDGET, { 400 - 100, 300 - 15, 200, 30 }, GUI_Container::Orientation::HORIZONTAL); auto callbackSave = [](GUI* gui, GUI_WidgetID widgetID, void* editorData) { EditorData* data = (EditorData*)editorData; GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); const char* filename = GUI_getTextfield(gui, GUI_getChildWidget(gui, widget, 0)).text; saveKeyFrame(filename, &data->skeleton[0], &data->names[0], data->skeleton.size()); GUI_removeWidget(gui, widget); }; auto callbackCancel = [](GUI* gui, GUI_WidgetID widgetID, void*) { GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); GUI_removeWidget(gui, widget); }; GUI_addTextfield(data->gui, widget, { 0, 0, -1, -1 }, "filename"); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Save", data, callbackSave); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Cancel", 0, callbackCancel); break; } else if (lastEvent.key.keysym.scancode == SDL_SCANCODE_O && lastEvent.key.keysym.mod == KMOD_LCTRL) { // load keyframe GUI_WidgetID widget = GUI_addContainer(data->gui, GUI_MAIN_WIDGET, { 400 - 100, 300 - 15, 200, 30 }, GUI_Container::Orientation::HORIZONTAL); auto callbackLoad = [](GUI* gui, GUI_WidgetID widgetID, void* editorData) { EditorData* data = (EditorData*)editorData; GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); const char* filename = GUI_getTextfield(gui, GUI_getChildWidget(gui, widget, 0)).text; strcpy(data->frameName, filename); const KeyFrameSave* save = loadKeyFrame(filename); if (save != 0) { const char* name = save->names; for (int i = 0; i < save->numBones; ++i) { int nameID = -1; for (int j = 0; j < data->names.size(); ++j) { if (strncmp(name, data->names[j].string, save->nameLen[i]) == 0) { nameID = j; break; } } if (nameID != -1) { if (data->skeleton[nameID].name == nameID) { data->skeleton[nameID].jointAngle = save->jointAngles[i]; } else { for (int j = 0; j < data->skeleton.size(); j++) { if (data->skeleton[j].name = nameID) data->skeleton[j].jointAngle = save->jointAngles[i]; } } } name += save->nameLen[i]; } updateBones(data); } GUI_removeWidget(gui, widget); }; auto callbackCancel = [](GUI* gui, GUI_WidgetID widgetID, void*) { GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); GUI_removeWidget(gui, widget); }; GUI_addTextfield(data->gui, widget, { 0, 0, -1, -1 }, "filename"); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Load", data, callbackLoad); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Cancel", 0, callbackCancel); break; } data->lowEventStack.Push(event); } break; default: data->lowEventStack.Push(event); break; } break; } case SDL_MOUSEBUTTONDOWN: { data->newBone = -1; if (keyboardState[SDL_SCANCODE_A]) { for (int i = 0; i < data->bones.size(); ++i) { if (pointInRect(mousePos, data->bones[i].rect)) { int name = data->names.push({ "test" }); Bone newBone; newBone.jointAngle = { 1, 0 }; newBone.jointPos = { 0, 0 }; newBone.parentJoint = i; newBone.name = name; Constraint constraint; constraint.minAngle = -PI; constraint.maxAngle = 3 * PI; int newBoneID = data->skeleton.push(newBone); data->constraints.push(constraint); int* ids = new int[data->skeleton.size()]; sortSkeleton(&data->skeleton[0], data->skeleton.size(), ids); Constraint* tempConstraints = new Constraint[data->constraints.size()]; memcpy(tempConstraints, &data->constraints[0], sizeof(Constraint) * data->constraints.size()); for (int i = 0; i < data->constraints.size(); ++i) { data->constraints[i] = tempConstraints[ids[i]]; } delete[] tempConstraints; //find bone again data->newBone = ids[newBoneID]; // rebuild bone selection updateBones(data); delete[]ids; break; } } } else if (keyboardState[SDL_SCANCODE_N]) { for (int i = 0; i < data->bones.size(); ++i) { if (pointInRect(mousePos, data->bones[i].rect)) { int2 pos = pointToPixel(&data->view, float2{ data->bones[i].rect.x + 10, data->bones[i].rect.y }); GUI_WidgetID widget = GUI_addContainer(data->gui, GUI_MAIN_WIDGET, intRect{ pos.x, pos.y, 100, 30 }, GUI_Container::HORIZONTAL); struct Args { EditorData* data; int boneId; }*args = new Args{ data, i }; auto callbackOk = [](GUI* gui, GUI_WidgetID widgetID, void* args) { EditorData* data = ((Args*)args)->data; int boneID = ((Args*)args)->boneId; GUI_WidgetID parentID = GUI_getParentWidget(gui, widgetID); const char* newName = GUI_getTextfield(gui, GUI_getChildWidget(gui, parentID, 0)).text; strcpy(data->names[data->skeleton[boneID].name].string, newName); GUI_removeWidget(gui, parentID); delete args; }; GUI_addTextfield(data->gui, widget, intRect{ 0, 0, -1, -1 }, data->names[data->skeleton[i].name].string); GUI_addButton(data->gui, widget, intRect{ 0, 0, 30, -1 }, "OK", args, callbackOk); break; } } } else { for (int i = 0; i < data->bones.size(); i++) { if (pointInRect(mousePos, data->bones[i].rect)) { data->selectedBones.push(i); data->grabbedBone = i; } } if (data->grabbedBone == -1 && !keyboardState[SDL_SCANCODE_LCTRL]) data->selectedBones.clear(); } break; } case SDL_MOUSEBUTTONUP: { data->grabbedBone = -1; break; } case SDL_MOUSEMOTION: { if (SDL_GetMouseState(0, 0) == SDL_BUTTON_MIDDLE) { data->view.position.x -= (event.motion.xrel / data->view.scale.x); data->view.position.y -= (event.motion.yrel / data->view.scale.y); } else { float2 motion = rotate({ (float)event.motion.xrel, (float)event.motion.yrel }, data->view.angle) * float2{ 1 / data->view.scale.x, 1 / data->view.scale.y }; if (data->newBone != -1) { float2 angle = getBoneWorldTransform(&data->skeleton[0], data->skeleton.size(), data->newBone).angle; float2 rel = rotate(float2{ motion.x, motion.y }, negateRotation(angle)); data->skeleton[data->newBone].jointPos += rel; } if (data->grabbedBone != -1) { if (keyboardState[SDL_SCANCODE_LCTRL]) { float2 angle = getBoneWorldTransform(&data->skeleton[0], data->skeleton.size(), data->skeleton[data->grabbedBone].parentJoint).angle; float2 rel = rotate(float2{ motion.x, motion.y }, negateRotation(angle)); data->skeleton[data->grabbedBone].jointPos += rel; } else { animateCCDIKSelection(&data->skeleton[0], &data->constraints[0], data->skeleton.size(), &data->selectedBones[0], data->selectedBones.size(), data->grabbedBone, mousePos - float2{ 400, 300 }); } } } break; } case SDL_MOUSEWHEEL: { data->view.scale.x += event.wheel.y*0.1f; data->view.scale.y += event.wheel.y*0.1f; break; } } }