def popupWindow(title, lines): """ Simple popup window with title & closebuttons, and multiple lines displayed Window is _sized_to_fit_ all lines, without scrolling. So do not use this if a line is going to be wider than the screen, or if there are so many lines it won't fit vertically. I do not error check. """ fontID = xp.Font_Proportional _w, strHeight, _ignore = xp.getFontDimensions(fontID) left = 100 bottom = 400 top = bottom + 25 widest = 10 for line in lines: top += strHeight + 4 widest = max(widest, xp.measureString(fontID, line.strip())) main = xp.createWidget(left, top, int(left + widest + 10), bottom, 1, title, 1, 0, xp.WidgetClass_MainWindow) xp.setWidgetProperty(main, xp.Property_MainWindowHasCloseBoxes, 1) xp.addWidgetCallback(main, popupCallback) left += 4 top -= 20 for line in lines: bottom = top - strHeight right = int(left + xp.measureString(fontID, line.strip())) xp.createWidget(left, top, right, bottom, 1, line.strip(), 0, main, xp.WidgetClass_Caption) top -= strHeight + 4
def createPipWindow(self): widgetWindow = {'widgetID': None, 'widgets': {}} box_left = 100 box_right = 500 top = 300 widgetWindow['widgetID'] = xp.createWidget(box_left, top, box_right, top - 125, 1, "PIP Package Installer", 1, 0, xp.WidgetClass_MainWindow) xp.setWidgetProperty(widgetWindow['widgetID'], xp.Property_MainWindowHasCloseBoxes, 1) fontID = xp.Font_Proportional _w, strHeight, _ignore = xp.getFontDimensions(fontID) xp.addWidgetCallback(widgetWindow['widgetID'], self.pipWidgetCallback) left = box_left + 10 top -= 30 bottom = int(top - strHeight) # Instructions.... s = "Enter one or more python packages below, then press 'Install'." strWidth = xp.measureString(fontID, s) right = int(left + strWidth) xp.createWidget(left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Caption) top -= strHeight + 4 bottom = int(top - strHeight) # text field bottom = int(top - (strHeight + 4)) right = int(left + strWidth) widgetWindow['widgets']['packages'] = xp.createWidget( left, top, right, bottom, 1, '', 0, widgetWindow['widgetID'], xp.WidgetClass_TextField) top -= strHeight + 8 bottom = int(top - strHeight) # Hints.... s = "Common packages: requests, pyopengl, cryptography, urllib3, six" strWidth = xp.measureString(fontID, s) right = int(left + strWidth) xp.createWidget(left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Caption) top = bottom - 4 bottom = int(top - strHeight) # (add a bit extra vertical buffer) top = bottom - 4 bottom = int(top - strHeight) # button s = " Install " strWidth = xp.measureString(fontID, s) right = int(left + strWidth) middle = int((box_left + box_right) / 2) widgetWindow['widgets']['button'] = xp.createWidget( int(middle - strWidth / 2.0), top, int(middle + strWidth / 2.0), bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Button) top = bottom - 10 bottom = int(top - strHeight) right = left + 400 widgetWindow['widgets']['error'] = xp.createWidget( left, top, right, bottom, 1, '', 0, widgetWindow['widgetID'], xp.WidgetClass_Caption) return widgetWindow
def createAboutWindow(self): widgetWindow = {'widgetID': None, 'widgets': {}} left = 100 top = 300 width = 525 height = 170 widgetWindow['widgetID'] = xp.createWidget(left, top, left + width, top - height, 1, "About XPPython3", 1, 0, xp.WidgetClass_MainWindow) xp.setWidgetProperty(widgetWindow['widgetID'], xp.Property_MainWindowHasCloseBoxes, 1) fontID = xp.Font_Proportional _w, strHeight, _ignore = xp.getFontDimensions(fontID) xp.addWidgetCallback(widgetWindow['widgetID'], self.aboutWidgetCallback) left += 10 top -= 30 bottom = int(top - strHeight) s = "X-Plane Plugin to support Python3 plugins" strWidth = xp.measureString(fontID, s) right = int(left + strWidth) xp.createWidget(left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Caption) top = bottom - 8 bottom = int(top - strHeight) s = 'This is Version {}'.format(XPPython.VERSION) strWidth = xp.measureString(fontID, s) right = int(left + strWidth) xp.createWidget(left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Caption) beta_left = left + width - 150 right = int(beta_left + 10) widgetWindow['widgets']['beta'] = xp.createWidget( beta_left, top, right, bottom, 1, '', 0, widgetWindow['widgetID'], xp.WidgetClass_Button) xp.setWidgetProperty(widgetWindow['widgets']['beta'], xp.Property_ButtonType, xp.RadioButton) xp.setWidgetProperty(widgetWindow['widgets']['beta'], xp.Property_ButtonBehavior, xp.ButtonBehaviorCheckBox) xp.setWidgetProperty(widgetWindow['widgets']['beta'], xp.Property_ButtonState, 1 if self.config['beta'] else 0) beta_left = right + 5 s = "Include Betas " strWidth = xp.measureString(fontID, s) right = int(beta_left + strWidth) xp.createWidget(beta_left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Caption) top = bottom - 10 bottom = int(top - strHeight) s = self.get_currency() strWidth = xp.measureString(fontID, s) right = int(left + 20 + strWidth) widgetWindow['widgets']['currency'] = xp.createWidget( left + 20, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Caption) top = bottom - 10 bottom = int(top - strHeight) s = "Based off of Sandy Barbour's Python2 plugin, this plugin is updated for X-Plane 11.50+," strWidth = xp.measureString(fontID, s) right = int(left + strWidth) xp.createWidget(left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Caption) top = bottom - 4 bottom = int(top - strHeight) s = "and python3 language. " strWidth = xp.measureString(fontID, s) right = int(left + strWidth) xp.createWidget(left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Caption) top = bottom - 8 bottom = int(top - strHeight) s = "See documentation at xppython3.rtfd.io." strWidth = xp.measureString(fontID, s) right = int(left + strWidth) xp.createWidget(left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Caption) top = bottom - 15 bottom = int(top - strHeight) left += 10 s = " User Documentation " strWidth = xp.measureString(fontID, s) right = int(left + strWidth) widgetWindow['widgets']['documentation'] = xp.createWidget( left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Button) left = right + 10 s = " Plugin Development " strWidth = xp.measureString(fontID, s) right = int(left + strWidth) widgetWindow['widgets']['plugin'] = xp.createWidget( left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Button) left = right + 10 s = " Support " strWidth = xp.measureString(fontID, s) right = int(left + strWidth) widgetWindow['widgets']['support'] = xp.createWidget( left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Button) left = right + 10 s = " Donate " strWidth = xp.measureString(fontID, s) right = int(left + strWidth) widgetWindow['widgets']['donate'] = xp.createWidget( left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Button) left = right + 30 s = " Changelog " strWidth = xp.measureString(fontID, s) right = int(left + strWidth) widgetWindow['widgets']['changelog'] = xp.createWidget( left, top, right, bottom, 1, s, 0, widgetWindow['widgetID'], xp.WidgetClass_Button) return widgetWindow
def add(self, s): xp.setWidgetDescriptor(self.widgetID, s) xp.setWidgetProperty(self.widgetID, Prop.ListBoxAddItem, 1)
def clear(self): xp.setWidgetProperty(self.widgetID, Prop.ListBoxClear, 1)
def listBoxProc(self, message, widget, param1, param2): currentItem = 0 scrollbarMax = 0 sliderPosition = 0 try: if xp.selectIfNeeded(message, widget, param1, param2, 0): return 1 except SystemError: print( "Failure in selectIfNeeded for message: {}, {}, {}, {}".format( message, widget, param1, param2)) raise left, top, right, bottom = xp.getWidgetGeometry(widget) sliderPosition = xp.getWidgetProperty( widget, Prop.ListBoxScrollBarSliderPosition, None) scrollbarMin = xp.getWidgetProperty(widget, Prop.ListBoxScrollBarMin, None) scrollbarMax = xp.getWidgetProperty(widget, Prop.ListBoxScrollBarMax, None) scrollBarPageAmount = xp.getWidgetProperty( widget, Prop.ListBoxScrollBarPageAmount, None) currentItem = xp.getWidgetProperty(widget, Prop.ListBoxCurrentItem, None) maxListBoxItems = xp.getWidgetProperty(widget, Prop.ListBoxMaxListBoxItems, None) highlighted = xp.getWidgetProperty(widget, Prop.ListBoxHighlighted, None) listBoxDataObj = xp.getWidgetProperty(widget, Prop.ListBoxData, None) scrollBarSlop = xp.getWidgetProperty(widget, Prop.ListBoxScrollBarSlop, None) fontWidth, fontHeight, _other = xp.getFontDimensions(xp.Font_Basic) listbox_item_height = int(fontHeight * 1.2) if message == xp.Msg_Create: listBoxDataObj = {'Items': [], 'Lefts': [], 'Rights': []} descriptor = xp.getWidgetDescriptor(widget) self.listBoxFillWithData(listBoxDataObj, descriptor, (right - left - 20)) xp.setWidgetProperty(widget, Prop.ListBoxData, listBoxDataObj) xp.setWidgetProperty(widget, Prop.ListBoxCurrentItem, currentItem) scrollbarMin = 0 scrollbarMax = len(listBoxDataObj['Items']) scrollBarSlop = 0 highlighted = False sliderPosition = scrollbarMax maxListBoxItems = int((top - bottom) / listbox_item_height) scrollBarPageAmount = maxListBoxItems xp.setWidgetProperty(widget, Prop.ListBoxScrollBarMin, scrollbarMin) xp.setWidgetProperty(widget, Prop.ListBoxScrollBarMax, scrollbarMax) xp.setWidgetProperty(widget, Prop.ListBoxScrollBarSlop, scrollBarSlop) xp.setWidgetProperty(widget, Prop.ListBoxHighlighted, highlighted) xp.setWidgetProperty(widget, Prop.ListBoxScrollBarSliderPosition, sliderPosition) xp.setWidgetProperty(widget, Prop.ListBoxMaxListBoxItems, maxListBoxItems) xp.setWidgetProperty(widget, Prop.ListBoxScrollBarPageAmount, scrollBarPageAmount) return 1 if message == xp.Msg_DescriptorChanged: return 1 if message == xp.Msg_PropertyChanged: if xp.getWidgetProperty(widget, Prop.ListBoxAddItem, None): wasViewingBottom = maxListBoxItems - sliderPosition > 0 xp.setWidgetProperty(widget, Prop.ListBoxAddItem, 0) # unset it descriptor = xp.getWidgetDescriptor(widget) if xp.measureString(xp.Font_Basic, descriptor) > (right - left - 20): charsPer = int((right - left - 20) / fontWidth) for x in range(0, len(descriptor), charsPer): self.listBoxAddItem(listBoxDataObj, descriptor[x:x + charsPer], (right - left - 20)) else: self.listBoxAddItem(listBoxDataObj, descriptor, (right - left - 20)) scrollbarMax = len(listBoxDataObj['Items']) sliderPosition = scrollbarMax xp.setWidgetProperty(widget, Prop.ListBoxScrollBarMax, scrollbarMax) if self.autoScroll: if wasViewingBottom and not ( maxListBoxItems - sliderPosition > 0): # print('was, but no more, setting to {}'.format(maxListBoxItems - 1)) xp.setWidgetProperty( widget, Prop.ListBoxScrollBarSliderPosition, maxListBoxItems - 1) elif wasViewingBottom: # print('was, and still is, setting to: {}'.format(sliderPosition)) xp.setWidgetProperty( widget, Prop.ListBoxScrollBarSliderPosition, sliderPosition) else: # print("wasn't, still isn't, set backwards: {}".format(sliderPosition - 1)) xp.setWidgetProperty( widget, Prop.ListBoxScrollBarSliderPosition, sliderPosition - 1) else: xp.setWidgetProperty(widget, Prop.ListBoxScrollBarSliderPosition, sliderPosition) if xp.getWidgetProperty(widget, Prop.ListBoxAddItemsWithClear, None): xp.setWidgetProperty(widget, Prop.ListBoxAddItemsWithClear, 0) # unset it descriptor = xp.getWidgetDescriptor(widget) self.listBoxClear(listBoxDataObj) self.listBoxFillWithData(listBoxDataObj, descriptor, (right - left - 20)) scrollbarMax = len(listBoxDataObj['Items']) sliderPosition = scrollbarMax xp.setWidgetProperty(widget, Prop.ListBoxScrollBarSliderPosition, sliderPosition) xp.setWidgetProperty(widget, Prop.ListBoxScrollBarMax, scrollbarMax) if xp.getWidgetProperty(widget, Prop.ListBoxClear, None): xp.setWidgetProperty(widget, Prop.ListBoxClear, 0) xp.setWidgetProperty(widget, Prop.ListBoxCurrentItem, 0) self.listBoxClear(listBoxDataObj) scrollbarMax = len(listBoxDataObj['Items']) sliderPosition = scrollbarMax xp.setWidgetProperty(widget, Prop.ListBoxScrollBarSliderPosition, sliderPosition) xp.setWidgetProperty(widget, Prop.ListBoxScrollBarMax, scrollbarMax) if xp.getWidgetProperty(widget, Prop.ListBoxInsertItem, None): xp.setWidgetProperty(widget, Prop.ListBoxInsertItem, 0) descriptor = xp.getWidgetDescriptor(widget) self.listBoxInsertItem(listBoxDataObj, descriptor, (right - left - 20), currentItem) if xp.getWidgetProperty(widget, Prop.ListBoxDeleteItem, None): xp.setWidgetProperty(widget, Prop.ListBoxDeleteItem, 0) if listBoxDataObj['Items'] and len( listBoxDataObj['Items']) > currentItem: self.listBoxDeleteItem(listBoxDataObj, currentItem) return 1 if message == xp.Msg_Draw: _x, y = xp.getMouseLocationGlobal() xp.drawWindow(left, bottom, right - 20, top, xp.Window_ListView) xp.drawTrack(right - 20, bottom, right, top, scrollbarMin, scrollbarMax, sliderPosition, xp.Track_ScrollBar, highlighted) xp.setGraphicsState(0, 1, 0, 0, 1, 0, 0) GL.glColor4f(1.0, 1.0, 1.0, 1.0) xp.setGraphicsState(0, 0, 0, 0, 0, 0, 0) # Now draw each item. listBoxIndex = scrollbarMax - sliderPosition itemNumber = 0 # print("numItems is {}, maxListBoxItems: {}, sliderPosition = {}, lbIndex= {}: {}".format( # scrollbarMax, # maxListBoxItems, # sliderPosition, # listBoxIndex, # listBoxIndex + maxListBoxItems > scrollbarMax # )) while itemNumber < maxListBoxItems: if listBoxIndex < len(listBoxDataObj['Items']): # Calculate the item rect in global coordinates. itemTop = int(top - (itemNumber * listbox_item_height)) itemBottom = int(top - ((itemNumber * listbox_item_height) + listbox_item_height)) # If we are hilited, draw the hilite bkgnd. if currentItem == listBoxIndex: SetAlphaLevels(0.25) xp.setGraphicsState(0, 0, 0, 0, 1, 0, 0) SetupAmbientColor(XP_Color.MenuHilite, True) SetAlphaLevels(1.0) GL.glBegin(GL.GL_QUADS) GL.glVertex2i(left, itemTop) GL.glVertex2i(right - 20, itemTop) GL.glVertex2i(right - 20, itemBottom) GL.glVertex2i(left, itemBottom) GL.glEnd() text = SetupAmbientColor(XP_Color.ListText) listBoxWidth = (right - 20) - left fontWidth, fontHeight, _other = xp.getFontDimensions( xp.Font_Basic) maxChars = int(listBoxWidth / fontWidth) buffer = listBoxDataObj['Items'][listBoxIndex][0:maxChars] listBoxIndex += 1 xp.drawString(text, left, itemBottom + 2, buffer, None, xp.Font_Basic) itemNumber += 1 return 1 if message == xp.Msg_MouseUp: if IN_RECT(MOUSE_X(param1), MOUSE_Y(param1), right - 20, top, right, bottom): highlighted = False xp.setWidgetProperty(widget, Prop.ListBoxHighlighted, highlighted) if IN_RECT(MOUSE_X(param1), MOUSE_Y(param1), left, top, right - 20, bottom): if listBoxDataObj['Items']: if currentItem != -1: xp.setWidgetDescriptor( widget, listBoxDataObj['Items'][currentItem]) else: xp.setWidgetDescriptor(widget, "") xp.sendMessageToWidget(widget, xpMessage_ListBoxItemSelected, xp.Mode_UpChain, widget, currentItem) return 1 if message == xp.Msg_MouseDown: if IN_RECT(MOUSE_X(param1), MOUSE_Y(param1), left, top, right - 20, bottom): if listBoxDataObj['Items']: x, y = xp.getMouseLocationGlobal() listBoxDataOffset = self.listBoxGetItemNumber( listBoxDataObj, listbox_item_height, x - left, top - y) if listBoxDataOffset != -1: listBoxDataOffset += scrollbarMax - sliderPosition if listBoxDataOffset < len(listBoxDataObj['Items']): xp.setWidgetProperty(widget, Prop.ListBoxCurrentItem, listBoxDataOffset) if IN_RECT(MOUSE_X(param1), MOUSE_Y(param1), right - 20, top, right, bottom): tm = xp.getTrackMetrics(right - 20, bottom, right, top, scrollbarMin, scrollbarMax, sliderPosition, xp.Track_ScrollBar) scrollbarMin = xp.getWidgetProperty(widget, Prop.ListBoxScrollBarMin, None) scrollbarMax = xp.getWidgetProperty(widget, Prop.ListBoxScrollBarMax, None) if tm.isVertical: upBtnSelected = IN_RECT(MOUSE_X(param1), MOUSE_Y(param1), right - 20, top, right, top - tm.upBtnSize) downBtnSelected = IN_RECT(MOUSE_X(param1), MOUSE_Y(param1), right - 20, bottom + tm.downBtnSize, right, bottom) upPageSelected = IN_RECT(MOUSE_X(param1), MOUSE_Y(param1), right - 20, (top - tm.upBtnSize), right, (bottom + tm.downBtnSize + tm.downPageSize + tm.thumbSize)) downPageSelected = IN_RECT( MOUSE_X(param1), MOUSE_Y(param1), right - 20, (top - tm.upBtnSize - tm.upPageSize - tm.thumbSize), right, (bottom + tm.downBtnSize)) thumbSelected = IN_RECT( MOUSE_X(param1), MOUSE_Y(param1), right - 20, (top - tm.upBtnSize - tm.upPageSize), right, (bottom + tm.downBtnSize + tm.downPageSize)) else: downBtnSelected = IN_RECT(MOUSE_X(param1), MOUSE_Y(param1), right - 20, top, right - 20 + tm.upBtnSize, bottom) upBtnSelected = IN_RECT(MOUSE_X(param1), MOUSE_Y(param1), right - 20 - tm.downBtnSize, top, right, bottom) downPageSelected = IN_RECT( MOUSE_X(param1), MOUSE_Y(param1), right - 20 + tm.downBtnSize, top, right - tm.upBtnSize - tm.upPageSize - tm.thumbSize, bottom) upPageSelected = IN_RECT( MOUSE_X(param1), MOUSE_Y(param1), right - 20 + tm.downBtnSize + tm.downPageSize + tm.thumbSize, top, right - tm.upBtnSize, bottom) thumbSelected = IN_RECT( MOUSE_X(param1), MOUSE_Y(param1), right - 20 + tm.downBtnSize + tm.downPageSize, top, right - tm.upBtnSize - tm.upPageSize, bottom) if upPageSelected: sliderPosition += scrollBarPageAmount if sliderPosition > scrollbarMax: sliderPosition = scrollbarMax xp.setWidgetProperty(widget, Prop.ListBoxScrollBarSliderPosition, sliderPosition) elif downPageSelected: sliderPosition -= scrollBarPageAmount if sliderPosition < scrollbarMin: sliderPosition = scrollbarMin xp.setWidgetProperty(widget, Prop.ListBoxScrollBarSliderPosition, sliderPosition) elif upBtnSelected: sliderPosition += 1 if sliderPosition > scrollbarMax: sliderPosition = scrollbarMax xp.setWidgetProperty(widget, Prop.ListBoxScrollBarSliderPosition, sliderPosition) elif downBtnSelected: sliderPosition -= 1 if sliderPosition < scrollbarMin: sliderPosition = scrollbarMin xp.setWidgetProperty(widget, Prop.ListBoxScrollBarSliderPosition, sliderPosition) elif thumbSelected: if tm.isVertical: scrollBarSlop = int(bottom + tm.downBtnSize + tm.downPageSize + (tm.thumbSize / 2) - MOUSE_Y(param1)) else: scrollBarSlop = int(right - 20 + tm.downBtnSize + tm.downPageSize + (tm.thumbSize / 2) - MOUSE_X(param1)) highlighted = True xp.setWidgetProperty(widget, Prop.ListBoxScrollBarSlop, scrollBarSlop) xp.setWidgetProperty(widget, Prop.ListBoxHighlighted, highlighted) else: highlighted = False xp.setWidgetProperty(widget, Prop.ListBoxHighlighted, highlighted) return 1 if message == xp.Msg_MouseDrag: if IN_RECT(MOUSE_X(param1), MOUSE_Y(param1), right - 20, top, right, bottom): tm = xp.getTrackMetrics(right - 20, bottom, right, top, scrollbarMin, scrollbarMax, sliderPosition, xp.Track_ScrollBar) scrollbarMin = xp.getWidgetProperty(widget, Prop.ListBoxScrollBarMin, None) scrollbarMax = xp.getWidgetProperty(widget, Prop.ListBoxScrollBarMax, None) thumbSelected = highlighted if thumbSelected: if param1 != 0: if tm.isVertical: y = MOUSE_Y(param1) + scrollBarSlop sliderPosition = round( float( float(y - (bottom + tm.downBtnSize + tm.thumbSize / 2)) / float((top - tm.upBtnSize - tm.thumbSize / 2) - (bottom + tm.downBtnSize + tm.thumbSize / 2))) * scrollbarMax) else: x = MOUSE_X(param1) + scrollBarSlop sliderPosition = round((float)( (float)(x - (right - 20 + tm.downBtnSize + tm.thumbSize / 2)) / (float)( (right - tm.upBtnSize - tm.thumbSize / 2) - (right - 20 + tm.downBtnSize + tm.thumbSize / 2))) * scrollbarMax) else: sliderPosition = 0 if sliderPosition < scrollbarMin: sliderPosition = scrollbarMin if sliderPosition > scrollbarMax: sliderPosition = scrollbarMax xp.setWidgetProperty(widget, Prop.ListBoxScrollBarSliderPosition, sliderPosition) return 1 return 0