本文整理汇总了C++中mygui::Widget类的典型用法代码示例。如果您正苦于以下问题:C++ Widget类的具体用法?C++ Widget怎么用?C++ Widget使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了Widget类的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的C++代码示例。
示例1: getCoordNewWidget
MyGUI::IntCoord WidgetCreatorManager::getCoordNewWidget(const MyGUI::IntPoint& _point)
{
MyGUI::IntPoint point = _point;
if (!MyGUI::InputManager::getInstance().isShiftPressed())
{
point.left += mGridStep / 2;
point.top += mGridStep / 2;
}
MyGUI::Widget* parent = mNewWidget->getParent();
if (parent != nullptr && !mNewWidget->isRootWidget())
point -= parent->getAbsolutePosition();
if (!MyGUI::InputManager::getInstance().isShiftPressed())
{
point.left = toGrid(point.left);
point.top = toGrid(point.top);
}
MyGUI::IntCoord coord = MyGUI::IntCoord(
std::min(mStartPoint.left, point.left),
std::min(mStartPoint.top, point.top),
abs(point.left - mStartPoint.left),
abs(point.top - mStartPoint.top));
return coord;
}
开发者ID:LiberatorUSA,项目名称:GUCEF,代码行数:27,代码来源:WidgetCreatorManager.cpp
示例2: step_change_skin
void step_change_skin()
{
MyGUI::Widget* widget = get_random(all_widgets);
if (!widget) return;
widget->changeWidgetSkin(get_skin());
test_widgets();
}
开发者ID:dayongxie,项目名称:MyGUI,代码行数:7,代码来源:DemoKeeper.cpp
示例3: setValue
void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value)
{
int current = std::max(0, static_cast<int>(value.getCurrent()));
int modified = static_cast<int>(value.getModified());
MyGUI::Widget* w;
std::string valStr = MyGUI::utility::toString(current) + "/" + MyGUI::utility::toString(modified);
if (id == "HBar")
{
mHealth->setProgressRange(modified);
mHealth->setProgressPosition(current);
getWidget(w, "HealthFrame");
w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr);
}
else if (id == "MBar")
{
mMagicka->setProgressRange (modified);
mMagicka->setProgressPosition (current);
getWidget(w, "MagickaFrame");
w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr);
}
else if (id == "FBar")
{
mStamina->setProgressRange (modified);
mStamina->setProgressPosition (current);
getWidget(w, "FatigueFrame");
w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
}
}
开发者ID:AAlderman,项目名称:openmw,代码行数:29,代码来源:hud.cpp
示例4: step_change_type
void step_change_type()
{
MyGUI::Widget* widget = get_random(all_widgets);
if (!widget) return;
widget->setWidgetStyle(get_type());
test_widgets();
}
开发者ID:dayongxie,项目名称:MyGUI,代码行数:7,代码来源:DemoKeeper.cpp
示例5: setValue
void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value)
{
static const char *ids[] =
{
"HBar", "MBar", "FBar", 0
};
for (int i=0; ids[i]; ++i)
if (ids[i]==id)
{
MyGUI::Widget* w;
std::string valStr = boost::lexical_cast<std::string>(value.getCurrent()) + "/" + boost::lexical_cast<std::string>(value.getModified());
switch (i)
{
case 0:
mHealth->setProgressRange (value.getModified());
mHealth->setProgressPosition (value.getCurrent());
getWidget(w, "HealthFrame");
w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr);
break;
case 1:
mMagicka->setProgressRange (value.getModified());
mMagicka->setProgressPosition (value.getCurrent());
getWidget(w, "MagickaFrame");
w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr);
break;
case 2:
mStamina->setProgressRange (value.getModified());
mStamina->setProgressPosition (value.getCurrent());
getWidget(w, "FatigueFrame");
w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
break;
}
}
}
开发者ID:zeidrich,项目名称:openmw,代码行数:35,代码来源:hud.cpp
示例6: step_detach_widget
void step_detach_widget()
{
MyGUI::Widget* widget = get_random(all_widgets);
if (!widget) return;
widget->detachFromWidget(get_layer());
test_widgets();
}
开发者ID:dayongxie,项目名称:MyGUI,代码行数:7,代码来源:DemoKeeper.cpp
示例7: open
void BookWindow::open (MWWorld::Ptr book)
{
mBook = book;
clearPages();
mCurrentPage = 0;
MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0);
MWWorld::LiveCellRef<ESM::Book> *ref = mBook.get<ESM::Book>();
BookTextParser parser;
std::vector<std::string> results = parser.split(ref->mBase->mText, mLeftPage->getSize().width, mLeftPage->getSize().height);
int i=0;
for (std::vector<std::string>::iterator it=results.begin();
it!=results.end(); ++it)
{
MyGUI::Widget* parent;
if (i%2 == 0)
parent = mLeftPage;
else
parent = mRightPage;
MyGUI::Widget* pageWidget = parent->createWidgetReal<MyGUI::Widget>("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast<std::string>(i));
pageWidget->setNeedMouseFocus(false);
parser.parsePage(*it, pageWidget, mLeftPage->getSize().width);
mPages.push_back(pageWidget);
++i;
}
updatePages();
setTakeButtonShow(true);
}
开发者ID:Aozi,项目名称:openmw,代码行数:35,代码来源:bookwindow.cpp
示例8: setHoverSlotsColor
void StashPanel::setHoverSlotsColor(Game::InventorySlot* _slot, Game::InventorySize* _size, MyGUI::Colour color)
{
bool set_all_red = false;
for (int r = _slot->R; r < (_slot->R +_size->Height); r++)
{
for (int c = _slot->C; c < (_slot->C + _size->Width); c++)
{
Game::InventorySlot temp_slot(r,c);
MyGUI::Widget* wg = this->getWidgetSlotByRC(r,c);
if (wg != 0)
wg->setColour(color);
else
set_all_red = true;
}
}
if (set_all_red)
{
for (int r = _slot->R; r < (_slot->R +_size->Height); r++)
{
for (int c = _slot->C; c < (_slot->C + _size->Width); c++)
{
MyGUI::Widget* wg = this->getWidgetSlotByRC(r,c);
if (wg != 0)
wg->setColour(MyGUI::Colour::Red);
}
}
}
}
开发者ID:Alex-G,项目名称:MuOnline,代码行数:29,代码来源:StashPanel.cpp
示例9: createScene
void DemoKeeper::createScene()
{
base::BaseDemoManager::createScene();
MyGUI::ResourceManager::getInstance().load("SplineSkin.xml");
const MyGUI::VectorWidgetPtr& root = MyGUI::LayoutManager::getInstance().loadLayout("HelpPanel.layout");
root.at(0)->findWidget("Text")->castType<MyGUI::TextBox>()->setCaption("PolygonalSkin usage. Drag white rectangles to move points for bezier curve.");
MyGUI::VectorWidgetPtr widgets = MyGUI::LayoutManager::getInstance().loadLayout("SplineWindow.layout");
mQualityText = widgets.at(0)->findWidget("SplineText")->castType<MyGUI::TextBox>();
MyGUI::ScrollBar* qualityScroll = widgets.at(0)->findWidget("SplineQuality")->castType<MyGUI::ScrollBar>();
qualityScroll->eventScrollChangePosition += MyGUI::newDelegate(this, &DemoKeeper::notifyChangeQuality);
mClient = widgets.at(0)->findWidget("SplineClient");
// create widget with skin that contain specific sub skin - PolygonalSkin
MyGUI::Widget* widget = mClient->createWidget<MyGUI::Widget>("PolygonalSkin", MyGUI::IntCoord(MyGUI::IntPoint(), mClient->getSize()), MyGUI::Align::Stretch);
widget->setColour(MyGUI::Colour::Red);
// get main subskin
MyGUI::ISubWidget* main = widget->getSubWidgetMain();
mPolygonalSkin = main->castType<MyGUI::PolygonalSkin>();
// set PolygonalSkin properties and points
mPolygonalSkin->setWidth(8.0f);
for (int i = 0; i < PointsCount; ++i)
{
point[i] = mClient->createWidget<MyGUI::Button>("Button", MyGUI::IntCoord(10 + (i + i % 2 * 3) * 40, 10 + (i + i / 2 * 3) * 40, 16, 16), MyGUI::Align::Default);
point[i]->eventMouseDrag += newDelegate(this, &DemoKeeper::notifyPointMove);
point[i]->eventMouseButtonPressed += newDelegate(this, &DemoKeeper::notifyPointPressed);
}
notifyChangeQuality(qualityScroll, 12);
updateSpline();
}
开发者ID:blunted2night,项目名称:MyGUI,代码行数:34,代码来源:DemoKeeper.cpp
示例10: onFrame
void NoDrop::onFrame(float dt)
{
if (!mWidget)
return;
MyGUI::IntPoint mousePos = MyGUI::InputManager::getInstance().getMousePosition();
if (mDrag->mIsOnDragAndDrop)
{
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getMouseFocusWidget();
while (focus && focus != mWidget)
focus = focus->getParent();
if (focus == mWidget)
mTransparent = true;
}
if (!mWidget->getAbsoluteCoord().inside(mousePos))
mTransparent = false;
if (mTransparent)
{
mWidget->setNeedMouseFocus(false); // Allow click-through
setAlpha(std::max(0.13f, mWidget->getAlpha() - dt*5));
}
else
{
mWidget->setNeedMouseFocus(true);
setAlpha(std::min(1.0f, mWidget->getAlpha() + dt*5));
}
}
开发者ID:yurikrupenin,项目名称:openmw,代码行数:30,代码来源:windowbase.cpp
示例11: initialiseByAttributes
CurveEditor::CurveEditor(MyGUI::Widget* _parent)
{
initialiseByAttributes(this, _parent);
mEditTimeEditBox->setEditReadOnly(true);
mEditValueEditBox->setEditReadOnly(true);
mRangeMinEditBox->eventKeyLostFocus += MyGUI::newDelegate(this, &CurveEditor::NotifyRangeLostFocus);
mRangeMinEditBox->eventEditSelectAccept += MyGUI::newDelegate(this, &CurveEditor::NotifyRangeEditAccept);
mRangeMaxEditBox->eventKeyLostFocus += MyGUI::newDelegate(this, &CurveEditor::NotifyRangeLostFocus);
mRangeMaxEditBox->eventEditSelectAccept += MyGUI::newDelegate(this, &CurveEditor::NotifyRangeEditAccept);
MyGUI::PolygonalSkin::CreateLineSets = false;
MyGUI::Widget* widget = mCurveCanvasWidget->createWidget<MyGUI::Widget>("PolygonalSkin",
MyGUI::IntCoord(MyGUI::IntPoint(), mCurveCanvasWidget->getSize()), MyGUI::Align::Stretch);
widget->setColour(MyGUI::Colour::Red);
MyGUI::ISubWidget* main = widget->getSubWidgetMain();
mCurveLines = main->castType<MyGUI::PolygonalSkin>();
MyGUI::PolygonalSkin::CreateLineSets = true;
widget = mCurveCanvasWidget->createWidget<MyGUI::Widget>("PolygonalSkin",
MyGUI::IntCoord(MyGUI::IntPoint(), mCurveCanvasWidget->getSize()), MyGUI::Align::Stretch);
widget->setColour(MyGUI::Colour::Red);
main = widget->getSubWidgetMain();
mCurveCanvas = main->castType<MyGUI::PolygonalSkin>();
widget->eventMouseButtonPressed += MyGUI::newDelegate(this, &CurveEditor::NotifyMousePressed);
MyGUI::PolygonalSkin::CreateLineSets = false;
mCanvasWidget = widget;
mCurveCanvas->setWidth(5.0f);
std::vector<MyGUI::FloatPoint> mLinePoints;
mLinePoints.push_back(MyGUI::FloatPoint(0, 0));
mLinePoints.push_back(MyGUI::FloatPoint(0, 1));
mCurveCanvas->setPoints(mLinePoints);
mLinePoints.clear();
mCurveCanvas->setPoints(mLinePoints); // todo fix it
mCurveLines->_setColour(MyGUI::Colour(0.2f, 0.2f, 0.2f));
// default range
mValueRange.x = 0;
mValueRange.y = 10;
mRangeMinEditBox->setCaption("0");
mRangeMaxEditBox->setCaption("10");
InitGrid();
RefreshNumbers();
MyGUI::Window* window = mMainWidget->castType<MyGUI::Window>(false);
if (window != nullptr)
window->eventWindowButtonPressed += newDelegate(this, &CurveEditor::NotifyWindowButtonPressed);
mSplineButton = mMainWidget->createWidget<MyGUI::Button>("CheckBox",
MyGUI::IntCoord(15, 10, 95, 25),
MyGUI::Align::Left | MyGUI::Align::Top);
mSplineButton->setCaption("Use Spline");
mSplineButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CurveEditor::NotifySplineChecked);
}
开发者ID:wangyanxing,项目名称:Demi3D,代码行数:59,代码来源:CurveEditor.cpp
示例12: buildNewControl
bool PropertyGridManager::buildNewControl(PropertyGridProperty *const property, int &height)
{
if(nullptr == mContainerWidget)
{
Debug::error(STEEL_METH_INTRO, "no container for controls. Aborting.").endl();
return false;
}
// build the control matching the property value type
Ogre::String const skin = "PanelEmpty";
Ogre::String const controlName = "PropertyGridManager_Control_" + property->id();
// original control size is set here, but the method that build the control can totally resize it.
MyGUI::IntCoord coords(0, height, mContainerWidget->getClientWidget()->getWidth(), 20);
MyGUI::Widget *control = mContainerWidget->createWidget<MyGUI::Widget>(skin, coords, MyGUI::Align::HCenter | MyGUI::Align::Top, controlName);
if(nullptr == control)
{
Debug::error(STEEL_METH_INTRO, "could not build control for property: ", *property, ". Skipping.").endl();
return false;
}
switch(property->valueType())
{
case PropertyGridPropertyValueType::Bool:
buildBoolControl(control, property);
break;
case PropertyGridPropertyValueType::String:
buildStringControl(control, property);
break;
case PropertyGridPropertyValueType::Range:
buildRangeControl(control, property);
break;
case PropertyGridPropertyValueType::StringVectorSelection:
buildStringVectorSelectionControl(control, property);
break;
case PropertyGridPropertyValueType::None:
default:
buildDummyControl(control, property);
}
height = control->getBottom();
mControlsMap.insert(std::make_pair(property->id(), control));
// subscribe to property changes
Signal propertyChanged = property->getSignal(PropertyGridProperty::PublicSignal::changed);
registerSignal(propertyChanged);
mSignals.propertyChanged.insert(propertyChanged);
// update control value
updateControlValue(control, property);
return true;
}
开发者ID:onze,项目名称:Steel,代码行数:58,代码来源:PropertyGridManager.cpp
示例13: setAllSlotsColor
void StashPanel::setAllSlotsColor(MyGUI::Colour color)
{
int slot_count = this->mslot_container_panelWidget->getChildCount();
for (int i = 0; i < slot_count; i++)
{
MyGUI::Widget* widget = this->mslot_container_panelWidget->getChildAt(i);
widget->setColour(color);
}
}
开发者ID:Alex-G,项目名称:MuOnline,代码行数:9,代码来源:StashPanel.cpp
示例14: hitTestSlots
bool InventoryPanel::hitTestSlots(const MyGUI::types::TRect<int>& _value)
{
int slot_count = this->mslot_container_panel_2_Widget->getChildCount();
for (int i = 0; i < slot_count; i++)
{
MyGUI::Widget* widget = this->mslot_container_panel_2_Widget->getChildAt(i);
if (widget->getAbsoluteRect().intersect(_value))
return true;
}
return false;
}
开发者ID:Alex-G,项目名称:MuOnline,代码行数:11,代码来源:InventoryPanel.cpp
示例15: step_attach_layer
void step_attach_layer()
{
MyGUI::Widget* widget = get_random(all_widgets);
if (!widget) return;
if (widget->isRootWidget())
{
std::string layername = get_layer();
if (!layername.empty())
MyGUI::LayerManager::getInstance().attachToLayerNode(layername, widget);
}
test_widgets();
}
开发者ID:dayongxie,项目名称:MyGUI,代码行数:12,代码来源:DemoKeeper.cpp
示例16: moveNewWidget
void WidgetCreatorManager::moveNewWidget(const MyGUI::IntPoint& _point)
{
if (mNewWidget == nullptr)
{
// тип виджета может отсутсвовать
if (!MyGUI::WidgetManager::getInstance().isFactoryExist(mWidgetType))
return;
// выделяем верний виджет
if (!mPopupMode)
WidgetSelectorManager::getInstance().selectWidget(mStartPoint);
MyGUI::Widget* parent = WidgetSelectorManager::getInstance().getSelectedWidget();
// пока не найдем ближайшего над нами способного быть родителем
while (parent != nullptr && !WidgetTypes::getInstance().findWidgetStyle(parent->getTypeName())->parent)
parent = parent->getParent();
if (!WidgetTypes::getInstance().findWidgetStyle(mWidgetType)->child)
parent = nullptr;
if (parent != nullptr)
mNewWidget = parent->createWidgetT(
mPopupMode ? MyGUI::WidgetStyle::Popup : MyGUI::WidgetStyle::Child,
mWidgetType,
EditorWidgets::getInstance().getSkinReplace(mWidgetSkin),
MyGUI::IntCoord(),
MyGUI::Align::Default,
DEFAULT_EDITOR_LAYER);
else
mNewWidget = MyGUI::Gui::getInstance().createWidgetT(
mWidgetType,
EditorWidgets::getInstance().getSkinReplace(mWidgetSkin),
MyGUI::IntCoord(),
MyGUI::Align::Default,
DEFAULT_EDITOR_LAYER);
// переводим старт поинт в координаты отца
if (parent != nullptr && !mNewWidget->isRootWidget())
mStartPoint -= parent->getAbsolutePosition();
if (!MyGUI::InputManager::getInstance().isShiftPressed())
{
mStartPoint.left = toGrid(mStartPoint.left);
mStartPoint.top = toGrid(mStartPoint.top);
}
}
MyGUI::IntCoord coord = getCoordNewWidget(_point);
mNewWidget->setCoord(coord);
eventChangeSelector(true, mNewWidget->getAbsoluteCoord());
}
开发者ID:LiberatorUSA,项目名称:GUCEF,代码行数:53,代码来源:WidgetCreatorManager.cpp
示例17: updateSelectionFromValue
void WorkspaceControl::updateSelectionFromValue()
{
// саму рамку отображаем в глобальных
if (mCurrentWidget != nullptr)
{
MyGUI::Widget* parent = mCurrentWidget->getParent();
if (parent != nullptr && !mCurrentWidget->isRootWidget())
mAreaSelectorControl->setCoord(mCoordValue + parent->getAbsolutePosition());
else
mAreaSelectorControl->setCoord(mCoordValue);
}
}
开发者ID:LiberatorUSA,项目名称:GUCEF,代码行数:12,代码来源:WorkspaceControl.cpp
示例18: injectKeyPress
void HotkeyManager::injectKeyPress(MyGUI::KeyCode _key, MyGUI::Char _text)
{
/*
被翻译成下面的字符串,不区分大小写
Shift+Ctrl+Alt+X,不区分左右Shift和Ctrl,Alt
*/
Game* g = Game::getSingletonPtr();
if( g )
{
string hotkey;
//_key不能是Shift,Ctrl,Alt其中之一
if( _key == MyGUI::KeyCode::Enum(MyGUI::KeyCode::RightShift) ||
_key == MyGUI::KeyCode::Enum(MyGUI::KeyCode::LeftShift) ||
_key == MyGUI::KeyCode::Enum(MyGUI::KeyCode::RightControl) ||
_key == MyGUI::KeyCode::Enum(MyGUI::KeyCode::LeftControl) ||
_key == MyGUI::KeyCode::Enum(MyGUI::KeyCode::RightAlt) ||
_key == MyGUI::KeyCode::Enum(MyGUI::KeyCode::LeftAlt) )
return;
if( g->getKeyState(MyGUI::KeyCode::Enum(MyGUI::KeyCode::RightShift)) ||
g->getKeyState(MyGUI::KeyCode::Enum(MyGUI::KeyCode::LeftShift))
)
{
hotkey += "shift+";
}
if( g->getKeyState(MyGUI::KeyCode::Enum(MyGUI::KeyCode::RightControl)) ||
g->getKeyState(MyGUI::KeyCode::Enum(MyGUI::KeyCode::LeftControl))
)
{
hotkey += "ctrl+";
}
if( g->getKeyState(MyGUI::KeyCode::Enum(MyGUI::KeyCode::RightAlt)) ||
g->getKeyState(MyGUI::KeyCode::Enum(MyGUI::KeyCode::LeftAlt))
)
{
hotkey += "alt+";
}
//注意:正确的话,ScanCodeToText返回小写字传串
hotkey += ScanCodeToText(_key.getValue());
for( HotkeyTable::iterator it = mHotkeys.begin();it!=mHotkeys.end();++it )
{
if( it->mSHotkey == hotkey )
{
MyGUI::Widget* p = MyGUI::Gui::getInstance().findWidget<MyGUI::Widget>(it->mName,false);
if( p )
p->eventMouseButtonClick( p );
}
}
}
}
开发者ID:JohnCrash,项目名称:iRobot,代码行数:52,代码来源:HotkeyManager.cpp
示例19: setWidgetHotkey
void HotkeyManager::setWidgetHotkey( const string name,const string key )
{
MyGUI::Gui& gui = MyGUI::Gui::getInstance();
MyGUI::Widget* p = gui.findWidget<MyGUI::Widget>( name,false );
if( p && (p->isType<MyGUI::Button>() || p->isType<MyGUI::MenuItem>() ) )
{
MyGUI::MenuItem* menuitem = p->castType<MyGUI::MenuItem>(false);
if( menuitem )
menuitem->setUserString( "hotkey",key );
else
p->setUserString( "hotkey",key );
}
}
开发者ID:JohnCrash,项目名称:iRobot,代码行数:13,代码来源:HotkeyManager.cpp
示例20: selectWidget
void WidgetSelectorManager::selectWidget(const MyGUI::IntPoint& _mousePosition)
{
if (mLastClickPoint != _mousePosition)
{
mSelectDepth = 0;
mLastClickPoint = _mousePosition;
}
// здесь кликать вглубь
MyGUI::Widget* item = getTopWidget(_mousePosition);
if (nullptr != item)
{
// find widget registered as container
while ((nullptr == EditorWidgets::getInstance().find(item)) && (nullptr != item))
item = item->getParent();
MyGUI::Widget* oldItem = item;
// try to selectin depth
size_t depth = mSelectDepth;
while (depth && (nullptr != item))
{
item = item->getParent();
while ((nullptr == EditorWidgets::getInstance().find(item)) && (nullptr != item))
item = item->getParent();
MYGUI_ASSERT(depth != 0, "depth != 0");
depth--;
}
if (nullptr == item)
{
item = oldItem;
mSelectDepth = 0;
}
// found widget
if (nullptr != item)
{
depth = mSelectDepth;
WidgetSelectorManager::getInstance().setSelectedWidget(item);
mSelectDepth = depth + 1;
}
else
{
WidgetSelectorManager::getInstance().setSelectedWidget(nullptr);
}
}
else
{
WidgetSelectorManager::getInstance().setSelectedWidget(nullptr);
}
}
开发者ID:LiberatorUSA,项目名称:GUCEF,代码行数:51,代码来源:WidgetSelectorManager.cpp
注:本文中的mygui::Widget类示例由纯净天空整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论